+++ /dev/null
-From 4c8a49854130da0117a0fdb858551824919a2389 Mon Sep 17 00:00:00 2001
-Date: Tue, 27 Feb 2024 09:58:15 +0100
-Subject: [PATCH] smp: Avoid 'setup_max_cpus' namespace collision/shadowing
-
-bringup_nonboot_cpus() gets passed the 'setup_max_cpus'
-variable in init/main.c - which is also the name of the parameter,
-shadowing the name.
-
-To reduce confusion and to allow the 'setup_max_cpus' value
-to be #defined in the <linux/smp.h> header, use the 'max_cpus'
-name for the function parameter name.
-
----
- include/linux/cpu.h | 2 +-
- kernel/cpu.c | 6 +++---
- 2 files changed, 4 insertions(+), 4 deletions(-)
-
---- a/include/linux/cpu.h
-+++ b/include/linux/cpu.h
-@@ -113,7 +113,7 @@ void notify_cpu_starting(unsigned int cp
- extern void cpu_maps_update_begin(void);
- extern void cpu_maps_update_done(void);
- int bringup_hibernate_cpu(unsigned int sleep_cpu);
--void bringup_nonboot_cpus(unsigned int setup_max_cpus);
-+void bringup_nonboot_cpus(unsigned int max_cpus);
-
- #else /* CONFIG_SMP */
- #define cpuhp_tasks_frozen 0
---- a/kernel/cpu.c
-+++ b/kernel/cpu.c
-@@ -1905,17 +1905,17 @@ static bool __init cpuhp_bringup_cpus_pa
- static inline bool cpuhp_bringup_cpus_parallel(unsigned int ncpus) { return false; }
- #endif /* CONFIG_HOTPLUG_PARALLEL */
-
--void __init bringup_nonboot_cpus(unsigned int setup_max_cpus)
-+void __init bringup_nonboot_cpus(unsigned int max_cpus)
- {
-- if (!setup_max_cpus)
-+ if (!max_cpus)
- return;
-
- /* Try parallel bringup optimization if enabled */
-- if (cpuhp_bringup_cpus_parallel(setup_max_cpus))
-+ if (cpuhp_bringup_cpus_parallel(max_cpus))
- return;
-
- /* Full per CPU serialized bringup */
-- cpuhp_bringup_mask(cpu_present_mask, setup_max_cpus, CPUHP_ONLINE);
-+ cpuhp_bringup_mask(cpu_present_mask, max_cpus, CPUHP_ONLINE);
- }
-
- #ifdef CONFIG_PM_SLEEP_SMP
+++ /dev/null
-From 443df175be581618d6ff781dc3af3aa1a9ba789d Mon Sep 17 00:00:00 2001
-Date: Fri, 31 May 2024 23:55:55 -0700
-Subject: [PATCH 1/2] compiler_types.h: Define __retain for
- __attribute__((__retain__))
-
-Some code includes the __used macro to prevent functions and data from
-being optimized out. This macro implements __attribute__((__used__)), which
-operates at the compiler and IR-level, and so still allows a linker to
-remove objects intended to be kept.
-
-Compilers supporting __attribute__((__retain__)) can address this gap by
-setting the flag SHF_GNU_RETAIN on the section of a function/variable,
-indicating to the linker the object should be retained. This attribute is
-available since gcc 11, clang 13, and binutils 2.36.
-
-Provide a __retain macro implementing __attribute__((__retain__)), whose
-first user will be the '__bpf_kfunc' tag.
-
-Link: https://lore.kernel.org/bpf/ZlmGoT9KiYLZd91S@krava/T/
----
- include/linux/compiler_types.h | 23 +++++++++++++++++++++++
- 1 file changed, 23 insertions(+)
-
---- a/include/linux/compiler_types.h
-+++ b/include/linux/compiler_types.h
-@@ -145,6 +145,29 @@ static inline void __chk_io_ptr(const vo
- #define __has_builtin(x) (0)
- #endif
-
-+/*
-+ * Annotating a function/variable with __retain tells the compiler to place
-+ * the object in its own section and set the flag SHF_GNU_RETAIN. This flag
-+ * instructs the linker to retain the object during garbage-cleanup or LTO
-+ * phases.
-+ *
-+ * Note that the __used macro is also used to prevent functions or data
-+ * being optimized out, but operates at the compiler/IR-level and may still
-+ * allow unintended removal of objects during linking.
-+ *
-+ * Optional: only supported since gcc >= 11, clang >= 13
-+ *
-+ * gcc: https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-retain-function-attribute
-+ * clang: https://clang.llvm.org/docs/AttributeReference.html#retain
-+ */
-+#if __has_attribute(__retain__) && \
-+ (defined(CONFIG_LD_DEAD_CODE_DATA_ELIMINATION) || \
-+ defined(CONFIG_LTO_CLANG))
-+# define __retain __attribute__((__retain__))
-+#else
-+# define __retain
-+#endif
-+
- /* Compiler specific macros. */
- #ifdef __clang__
- #include <linux/compiler-clang.h>
+++ /dev/null
-From ac507ed9882fd91a94657d68fe9ceac04b957103 Mon Sep 17 00:00:00 2001
-Date: Sat, 1 Jun 2024 00:00:21 -0700
-Subject: [PATCH 2/2] bpf: Harden __bpf_kfunc tag against linker kfunc removal
-
-BPF kfuncs are often not directly referenced and may be inadvertently
-removed by optimization steps during kernel builds, thus the __bpf_kfunc
-tag mitigates against this removal by including the __used macro. However,
-this macro alone does not prevent removal during linking, and may still
-yield build warnings (e.g. on mips64el):
-
- LD vmlinux
- BTFIDS vmlinux
- WARN: resolve_btfids: unresolved symbol bpf_verify_pkcs7_signature
- WARN: resolve_btfids: unresolved symbol bpf_lookup_user_key
- WARN: resolve_btfids: unresolved symbol bpf_lookup_system_key
- WARN: resolve_btfids: unresolved symbol bpf_key_put
- WARN: resolve_btfids: unresolved symbol bpf_iter_task_next
- WARN: resolve_btfids: unresolved symbol bpf_iter_css_task_new
- WARN: resolve_btfids: unresolved symbol bpf_get_file_xattr
- WARN: resolve_btfids: unresolved symbol bpf_ct_insert_entry
- WARN: resolve_btfids: unresolved symbol bpf_cgroup_release
- WARN: resolve_btfids: unresolved symbol bpf_cgroup_from_id
- WARN: resolve_btfids: unresolved symbol bpf_cgroup_acquire
- WARN: resolve_btfids: unresolved symbol bpf_arena_free_pages
- NM System.map
- SORTTAB vmlinux
- OBJCOPY vmlinux.32
-
-Update the __bpf_kfunc tag to better guard against linker optimization by
-including the new __retain compiler macro, which fixes the warnings above.
-
-Verify the __retain macro with readelf by checking object flags for 'R':
-
- $ readelf -Wa kernel/trace/bpf_trace.o
- Section Headers:
- [Nr] Name Type Address Off Size ES Flg Lk Inf Al
- ...
- [178] .text.bpf_key_put PROGBITS 00000000 6420 0050 00 AXR 0 0 8
- ...
- Key to Flags:
- ...
- R (retain), D (mbind), p (processor specific)
-
-Link: https://lore.kernel.org/bpf/ZlmGoT9KiYLZd91S@krava/T/
-Fixes: 57e7c169cd6a ("bpf: Add __bpf_kfunc tag for marking kernel functions as kfuncs")
----
- include/linux/btf.h | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/include/linux/btf.h
-+++ b/include/linux/btf.h
-@@ -81,7 +81,7 @@
- * as to avoid issues such as the compiler inlining or eliding either a static
- * kfunc, or a global kfunc in an LTO build.
- */
--#define __bpf_kfunc __used noinline
-+#define __bpf_kfunc __used __retain noinline
-
- /*
- * Return the name of the passed struct, if exists, or halt the build if for
+++ /dev/null
-From fab45b962749184e1a1a57c7c583782b78fad539 Mon Sep 17 00:00:00 2001
-Date: Tue, 13 Aug 2024 20:49:06 +0100
-Subject: [PATCH] libbpf: Workaround -Wmaybe-uninitialized false positive
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-In `elf_close`, we get this with GCC 15 -O3 (at least):
-```
-In function ‘elf_close’,
- inlined from ‘elf_close’ at elf.c:53:6,
- inlined from ‘elf_find_func_offset_from_file’ at elf.c:384:2:
-elf.c:57:9: warning: ‘elf_fd.elf’ may be used uninitialized [-Wmaybe-uninitialized]
- 57 | elf_end(elf_fd->elf);
- | ^~~~~~~~~~~~~~~~~~~~
-elf.c: In function ‘elf_find_func_offset_from_file’:
-elf.c:377:23: note: ‘elf_fd.elf’ was declared here
- 377 | struct elf_fd elf_fd;
- | ^~~~~~
-In function ‘elf_close’,
- inlined from ‘elf_close’ at elf.c:53:6,
- inlined from ‘elf_find_func_offset_from_file’ at elf.c:384:2:
-elf.c:58:9: warning: ‘elf_fd.fd’ may be used uninitialized [-Wmaybe-uninitialized]
- 58 | close(elf_fd->fd);
- | ^~~~~~~~~~~~~~~~~
-elf.c: In function ‘elf_find_func_offset_from_file’:
-elf.c:377:23: note: ‘elf_fd.fd’ was declared here
- 377 | struct elf_fd elf_fd;
- | ^~~~~~
-```
-
-In reality, our use is fine, it's just that GCC doesn't model errno
-here (see linked GCC bug). Suppress -Wmaybe-uninitialized accordingly
-by initializing elf_fd.fd to -1 and elf_fd.elf to NULL.
-
-I've done this in two other functions as well given it could easily
-occur there too (same access/use pattern).
-
-Link: https://gcc.gnu.org/PR114952
-Link: https://lore.kernel.org/bpf/14ec488a1cac02794c2fa2b83ae0cef1bce2cb36.1723578546.git.sam@gentoo.org
----
- tools/lib/bpf/elf.c | 3 +++
- 1 file changed, 3 insertions(+)
-
---- a/tools/lib/bpf/elf.c
-+++ b/tools/lib/bpf/elf.c
-@@ -16,6 +16,9 @@ int elf_open(const char *binary_path, st
- int fd, ret;
- Elf *elf;
-
-+ elf_fd->elf = NULL;
-+ elf_fd->fd = -1;
-+
- if (elf_version(EV_CURRENT) == EV_NONE) {
- pr_warn("elf: failed to init libelf for %s\n", binary_path);
- return -LIBBPF_ERRNO__LIBELF;
+++ /dev/null
-From ed0f941022515ff40473ea5335769a5dc2524a3f Mon Sep 17 00:00:00 2001
-Date: Mon, 3 Jun 2024 16:37:50 +0100
-Subject: [PATCH] ARM: 9404/1: arm32: enable HAVE_LD_DEAD_CODE_DATA_ELIMINATION
-
-The current arm32 architecture does not yet support the
-HAVE_LD_DEAD_CODE_DATA_ELIMINATION feature. arm32 is widely used in
-embedded scenarios, and enabling this feature would be beneficial for
-reducing the size of the kernel image.
-
-In order to make this work, we keep the necessary tables by annotating
-them with KEEP, also it requires further changes to linker script to KEEP
-some tables and wildcard compiler generated sections into the right place.
-When using ld.lld for linking, KEEP is not recognized within the OVERLAY
-command, and Ard proposed a concise method to solve this problem.
-
-It boots normally with defconfig, vexpress_defconfig and tinyconfig.
-
-The size comparison of zImage is as follows:
-defconfig vexpress_defconfig tinyconfig
-5137712 5138024 424192 no dce
-5032560 4997824 298384 dce
-2.0% 2.7% 29.7% shrink
-
-When using smaller config file, there is a significant reduction in the
-size of the zImage.
-
-We also tested this patch on a commercially available single-board
-computer, and the comparison is as follows:
-a15eb_config
-2161384 no dce
-2092240 dce
-3.2% shrink
-
-The zImage size has been reduced by approximately 3.2%, which is 70KB on
-2.1M.
-
----
- arch/arm/Kconfig | 1 +
- arch/arm/boot/compressed/vmlinux.lds.S | 2 +-
- arch/arm/include/asm/vmlinux.lds.h | 2 +-
- arch/arm/kernel/entry-armv.S | 3 +++
- arch/arm/kernel/vmlinux-xip.lds.S | 4 ++--
- arch/arm/kernel/vmlinux.lds.S | 6 +++---
- drivers/firmware/efi/libstub/Makefile | 4 ++++
- 7 files changed, 15 insertions(+), 7 deletions(-)
-
---- a/arch/arm/Kconfig
-+++ b/arch/arm/Kconfig
-@@ -111,6 +111,7 @@ config ARM
- select HAVE_KERNEL_XZ
- select HAVE_KPROBES if !XIP_KERNEL && !CPU_ENDIAN_BE32 && !CPU_V7M
- select HAVE_KRETPROBES if HAVE_KPROBES
-+ select HAVE_LD_DEAD_CODE_DATA_ELIMINATION
- select HAVE_MOD_ARCH_SPECIFIC
- select HAVE_NMI
- select HAVE_OPTPROBES if !THUMB2_KERNEL
---- a/arch/arm/boot/compressed/vmlinux.lds.S
-+++ b/arch/arm/boot/compressed/vmlinux.lds.S
-@@ -125,7 +125,7 @@ SECTIONS
-
- . = BSS_START;
- __bss_start = .;
-- .bss : { *(.bss) }
-+ .bss : { *(.bss .bss.*) }
- _end = .;
-
- . = ALIGN(8); /* the stack must be 64-bit aligned */
---- a/arch/arm/include/asm/vmlinux.lds.h
-+++ b/arch/arm/include/asm/vmlinux.lds.h
-@@ -42,7 +42,7 @@
- #define PROC_INFO \
- . = ALIGN(4); \
- __proc_info_begin = .; \
-- *(.proc.info.init) \
-+ KEEP(*(.proc.info.init)) \
- __proc_info_end = .;
-
- #define IDMAP_TEXT \
---- a/arch/arm/kernel/entry-armv.S
-+++ b/arch/arm/kernel/entry-armv.S
-@@ -1073,6 +1073,7 @@ vector_addrexcptn:
- .globl vector_fiq
-
- .section .vectors, "ax", %progbits
-+ .reloc .text, R_ARM_NONE, .
- W(b) vector_rst
- W(b) vector_und
- ARM( .reloc ., R_ARM_LDR_PC_G0, .L__vector_swi )
-@@ -1086,6 +1087,7 @@ THUMB( .reloc ., R_ARM_THM_PC12, .L__vec
-
- #ifdef CONFIG_HARDEN_BRANCH_HISTORY
- .section .vectors.bhb.loop8, "ax", %progbits
-+ .reloc .text, R_ARM_NONE, .
- W(b) vector_rst
- W(b) vector_bhb_loop8_und
- ARM( .reloc ., R_ARM_LDR_PC_G0, .L__vector_bhb_loop8_swi )
-@@ -1098,6 +1100,7 @@ THUMB( .reloc ., R_ARM_THM_PC12, .L__vec
- W(b) vector_bhb_loop8_fiq
-
- .section .vectors.bhb.bpiall, "ax", %progbits
-+ .reloc .text, R_ARM_NONE, .
- W(b) vector_rst
- W(b) vector_bhb_bpiall_und
- ARM( .reloc ., R_ARM_LDR_PC_G0, .L__vector_bhb_bpiall_swi )
---- a/arch/arm/kernel/vmlinux-xip.lds.S
-+++ b/arch/arm/kernel/vmlinux-xip.lds.S
-@@ -63,7 +63,7 @@ SECTIONS
- . = ALIGN(4);
- __ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) {
- __start___ex_table = .;
-- ARM_MMU_KEEP(*(__ex_table))
-+ ARM_MMU_KEEP(KEEP(*(__ex_table)))
- __stop___ex_table = .;
- }
-
-@@ -83,7 +83,7 @@ SECTIONS
- }
- .init.arch.info : {
- __arch_info_begin = .;
-- *(.arch.info.init)
-+ KEEP(*(.arch.info.init))
- __arch_info_end = .;
- }
- .init.tagtable : {
---- a/arch/arm/kernel/vmlinux.lds.S
-+++ b/arch/arm/kernel/vmlinux.lds.S
-@@ -74,7 +74,7 @@ SECTIONS
- . = ALIGN(4);
- __ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) {
- __start___ex_table = .;
-- ARM_MMU_KEEP(*(__ex_table))
-+ ARM_MMU_KEEP(KEEP(*(__ex_table)))
- __stop___ex_table = .;
- }
-
-@@ -99,7 +99,7 @@ SECTIONS
- }
- .init.arch.info : {
- __arch_info_begin = .;
-- *(.arch.info.init)
-+ KEEP(*(.arch.info.init))
- __arch_info_end = .;
- }
- .init.tagtable : {
-@@ -116,7 +116,7 @@ SECTIONS
- #endif
- .init.pv_table : {
- __pv_table_begin = .;
-- *(.pv_table)
-+ KEEP(*(.pv_table))
- __pv_table_end = .;
- }
-
---- a/drivers/firmware/efi/libstub/Makefile
-+++ b/drivers/firmware/efi/libstub/Makefile
-@@ -67,6 +67,10 @@ OBJECT_FILES_NON_STANDARD := y
- # Prevents link failures: __sanitizer_cov_trace_pc() is not linked in.
- KCOV_INSTRUMENT := n
-
-+# The .data section would be renamed to .data.efistub, therefore, remove
-+# `-fdata-sections` flag from KBUILD_CFLAGS_KERNEL
-+KBUILD_CFLAGS_KERNEL := $(filter-out -fdata-sections, $(KBUILD_CFLAGS_KERNEL))
-+
- lib-y := efi-stub-helper.o gop.o secureboot.o tpm.o \
- file.o mem.o random.o randomalloc.o pci.o \
- skip_spaces.o lib-cmdline.o lib-ctype.o \
+++ /dev/null
-From 65033574ade97afccba074d837fd269903a83a9a Mon Sep 17 00:00:00 2001
-Date: Thu, 5 Oct 2023 16:40:30 +0100
-Subject: [PATCH] arm64: swiotlb: Reduce the default size if no ZONE_DMA
- bouncing needed
-
-With CONFIG_DMA_BOUNCE_UNALIGNED_KMALLOC enabled, the arm64 kernel still
-allocates the default SWIOTLB buffer (64MB) even if ZONE_DMA is disabled
-or all the RAM fits into this zone. However, this potentially wastes a
-non-negligible amount of memory on platforms with little RAM.
-
-Reduce the SWIOTLB size to 1MB per 1GB of RAM if only needed for
-kmalloc() buffer bouncing.
-
----
- arch/arm64/mm/init.c | 11 ++++++++++-
- 1 file changed, 10 insertions(+), 1 deletion(-)
-
---- a/arch/arm64/mm/init.c
-+++ b/arch/arm64/mm/init.c
-@@ -16,6 +16,7 @@
- #include <linux/nodemask.h>
- #include <linux/initrd.h>
- #include <linux/gfp.h>
-+#include <linux/math.h>
- #include <linux/memblock.h>
- #include <linux/sort.h>
- #include <linux/of.h>
-@@ -493,8 +494,16 @@ void __init mem_init(void)
- {
- bool swiotlb = max_pfn > PFN_DOWN(arm64_dma_phys_limit);
-
-- if (IS_ENABLED(CONFIG_DMA_BOUNCE_UNALIGNED_KMALLOC))
-+ if (IS_ENABLED(CONFIG_DMA_BOUNCE_UNALIGNED_KMALLOC) && !swiotlb) {
-+ /*
-+ * If no bouncing needed for ZONE_DMA, reduce the swiotlb
-+ * buffer for kmalloc() bouncing to 1MB per 1GB of RAM.
-+ */
-+ unsigned long size =
-+ DIV_ROUND_UP(memblock_phys_mem_size(), 1024);
-+ swiotlb_adjust_size(min(swiotlb_size_or_default(), size));
- swiotlb = true;
-+ }
-
- swiotlb_init(swiotlb, SWIOTLB_VERBOSE);
-
+++ /dev/null
-From 66a5c40f60f5d88ad8d47ba6a4ba05892853fa1f Mon Sep 17 00:00:00 2001
-Date: Tue, 26 Dec 2023 18:00:00 +0000
-Subject: [PATCH] kernel.h: removed REPEAT_BYTE from kernel.h
-
-This patch creates wordpart.h and includes it in asm/word-at-a-time.h
-for all architectures. WORD_AT_A_TIME_CONSTANTS depends on kernel.h
-because of REPEAT_BYTE. Moving this to another header and including it
-where necessary allows us to not include the bloated kernel.h. Making
-this implicit dependency on REPEAT_BYTE explicit allows for later
-improvements in the lib/string.c inclusion list.
-
----
- arch/arm/include/asm/word-at-a-time.h | 3 ++-
- arch/arm64/include/asm/word-at-a-time.h | 3 ++-
- arch/powerpc/include/asm/word-at-a-time.h | 4 ++--
- arch/riscv/include/asm/word-at-a-time.h | 3 ++-
- arch/s390/include/asm/word-at-a-time.h | 3 ++-
- arch/sh/include/asm/word-at-a-time.h | 2 ++
- arch/x86/include/asm/word-at-a-time.h | 3 ++-
- arch/x86/kvm/mmu/mmu.c | 1 +
- fs/namei.c | 2 +-
- include/asm-generic/word-at-a-time.h | 3 ++-
- include/linux/kernel.h | 8 --------
- include/linux/wordpart.h | 13 +++++++++++++
- 12 files changed, 31 insertions(+), 17 deletions(-)
- create mode 100644 include/linux/wordpart.h
-
---- a/arch/arm/include/asm/word-at-a-time.h
-+++ b/arch/arm/include/asm/word-at-a-time.h
-@@ -8,7 +8,8 @@
- * Little-endian word-at-a-time zero byte handling.
- * Heavily based on the x86 algorithm.
- */
--#include <linux/kernel.h>
-+#include <linux/bitops.h>
-+#include <linux/wordpart.h>
-
- struct word_at_a_time {
- const unsigned long one_bits, high_bits;
---- a/arch/arm64/include/asm/word-at-a-time.h
-+++ b/arch/arm64/include/asm/word-at-a-time.h
-@@ -9,7 +9,8 @@
-
- #ifndef __AARCH64EB__
-
--#include <linux/kernel.h>
-+#include <linux/bitops.h>
-+#include <linux/wordpart.h>
-
- struct word_at_a_time {
- const unsigned long one_bits, high_bits;
---- a/arch/powerpc/include/asm/word-at-a-time.h
-+++ b/arch/powerpc/include/asm/word-at-a-time.h
-@@ -4,8 +4,8 @@
- /*
- * Word-at-a-time interfaces for PowerPC.
- */
--
--#include <linux/kernel.h>
-+#include <linux/bitops.h>
-+#include <linux/wordpart.h>
- #include <asm/asm-compat.h>
- #include <asm/extable.h>
-
---- a/arch/sh/include/asm/word-at-a-time.h
-+++ b/arch/sh/include/asm/word-at-a-time.h
-@@ -5,6 +5,8 @@
- #ifdef CONFIG_CPU_BIG_ENDIAN
- # include <asm-generic/word-at-a-time.h>
- #else
-+#include <linux/bitops.h>
-+#include <linux/wordpart.h>
- /*
- * Little-endian version cribbed from x86.
- */
---- a/arch/x86/include/asm/word-at-a-time.h
-+++ b/arch/x86/include/asm/word-at-a-time.h
-@@ -2,7 +2,8 @@
- #ifndef _ASM_WORD_AT_A_TIME_H
- #define _ASM_WORD_AT_A_TIME_H
-
--#include <linux/kernel.h>
-+#include <linux/bitops.h>
-+#include <linux/wordpart.h>
-
- /*
- * This is largely generic for little-endian machines, but the
---- a/arch/x86/kvm/mmu/mmu.c
-+++ b/arch/x86/kvm/mmu/mmu.c
-@@ -47,6 +47,7 @@
- #include <linux/kern_levels.h>
- #include <linux/kstrtox.h>
- #include <linux/kthread.h>
-+#include <linux/wordpart.h>
-
- #include <asm/page.h>
- #include <asm/memtype.h>
---- a/fs/namei.c
-+++ b/fs/namei.c
-@@ -17,8 +17,8 @@
-
- #include <linux/init.h>
- #include <linux/export.h>
--#include <linux/kernel.h>
- #include <linux/slab.h>
-+#include <linux/wordpart.h>
- #include <linux/fs.h>
- #include <linux/filelock.h>
- #include <linux/namei.h>
---- a/include/asm-generic/word-at-a-time.h
-+++ b/include/asm-generic/word-at-a-time.h
-@@ -2,7 +2,8 @@
- #ifndef _ASM_WORD_AT_A_TIME_H
- #define _ASM_WORD_AT_A_TIME_H
-
--#include <linux/kernel.h>
-+#include <linux/bitops.h>
-+#include <linux/wordpart.h>
- #include <asm/byteorder.h>
-
- #ifdef __BIG_ENDIAN
---- a/include/linux/kernel.h
-+++ b/include/linux/kernel.h
-@@ -38,14 +38,6 @@
-
- #define STACK_MAGIC 0xdeadbeef
-
--/**
-- * REPEAT_BYTE - repeat the value @x multiple times as an unsigned long value
-- * @x: value to repeat
-- *
-- * NOTE: @x is not checked for > 0xff; larger values produce odd results.
-- */
--#define REPEAT_BYTE(x) ((~0ul / 0xff) * (x))
--
- /* generic data direction definitions */
- #define READ 0
- #define WRITE 1
---- /dev/null
-+++ b/include/linux/wordpart.h
-@@ -0,0 +1,13 @@
-+/* SPDX-License-Identifier: GPL-2.0 */
-+
-+#ifndef _LINUX_WORDPART_H
-+#define _LINUX_WORDPART_H
-+/**
-+ * REPEAT_BYTE - repeat the value @x multiple times as an unsigned long value
-+ * @x: value to repeat
-+ *
-+ * NOTE: @x is not checked for > 0xff; larger values produce odd results.
-+ */
-+#define REPEAT_BYTE(x) ((~0ul / 0xff) * (x))
-+
-+#endif // _LINUX_WORDPART_H
+++ /dev/null
-From adeb04362d74188c1e22ccb824b15a0a7b3de2f4 Mon Sep 17 00:00:00 2001
-Date: Wed, 14 Feb 2024 19:26:32 +0200
-Subject: [PATCH] kernel.h: Move upper_*_bits() and lower_*_bits() to
- wordpart.h
-
-The wordpart.h header is collecting APIs related to the handling
-parts of the word (usually in byte granularity). The upper_*_bits()
-and lower_*_bits() are good candidates to be moved to there.
-
-This helps to clean up header dependency hell with regard to kernel.h
-as the latter gathers completely unrelated stuff together and slows
-down compilation (especially when it's included into other header).
-
----
- include/linux/kernel.h | 30 ++----------------------------
- include/linux/wordpart.h | 29 +++++++++++++++++++++++++++++
- 2 files changed, 31 insertions(+), 28 deletions(-)
-
---- a/include/linux/kernel.h
-+++ b/include/linux/kernel.h
-@@ -32,6 +32,8 @@
- #include <linux/sprintf.h>
- #include <linux/static_call_types.h>
- #include <linux/instruction_pointer.h>
-+#include <linux/wordpart.h>
-+
- #include <asm/byteorder.h>
-
- #include <uapi/linux/kernel.h>
-@@ -57,34 +59,6 @@
- } \
- )
-
--/**
-- * upper_32_bits - return bits 32-63 of a number
-- * @n: the number we're accessing
-- *
-- * A basic shift-right of a 64- or 32-bit quantity. Use this to suppress
-- * the "right shift count >= width of type" warning when that quantity is
-- * 32-bits.
-- */
--#define upper_32_bits(n) ((u32)(((n) >> 16) >> 16))
--
--/**
-- * lower_32_bits - return bits 0-31 of a number
-- * @n: the number we're accessing
-- */
--#define lower_32_bits(n) ((u32)((n) & 0xffffffff))
--
--/**
-- * upper_16_bits - return bits 16-31 of a number
-- * @n: the number we're accessing
-- */
--#define upper_16_bits(n) ((u16)((n) >> 16))
--
--/**
-- * lower_16_bits - return bits 0-15 of a number
-- * @n: the number we're accessing
-- */
--#define lower_16_bits(n) ((u16)((n) & 0xffff))
--
- struct completion;
- struct user;
-
---- a/include/linux/wordpart.h
-+++ b/include/linux/wordpart.h
-@@ -2,6 +2,35 @@
-
- #ifndef _LINUX_WORDPART_H
- #define _LINUX_WORDPART_H
-+
-+/**
-+ * upper_32_bits - return bits 32-63 of a number
-+ * @n: the number we're accessing
-+ *
-+ * A basic shift-right of a 64- or 32-bit quantity. Use this to suppress
-+ * the "right shift count >= width of type" warning when that quantity is
-+ * 32-bits.
-+ */
-+#define upper_32_bits(n) ((u32)(((n) >> 16) >> 16))
-+
-+/**
-+ * lower_32_bits - return bits 0-31 of a number
-+ * @n: the number we're accessing
-+ */
-+#define lower_32_bits(n) ((u32)((n) & 0xffffffff))
-+
-+/**
-+ * upper_16_bits - return bits 16-31 of a number
-+ * @n: the number we're accessing
-+ */
-+#define upper_16_bits(n) ((u16)((n) >> 16))
-+
-+/**
-+ * lower_16_bits - return bits 0-15 of a number
-+ * @n: the number we're accessing
-+ */
-+#define lower_16_bits(n) ((u16)((n) & 0xffff))
-+
- /**
- * REPEAT_BYTE - repeat the value @x multiple times as an unsigned long value
- * @x: value to repeat
+++ /dev/null
-From 8cd2accb71f5eb8e92d775fc1978d3779875c2e5 Mon Sep 17 00:00:00 2001
-Date: Fri, 8 Dec 2023 15:30:34 +0800
-Subject: [PATCH] mips, kexec: fix the incorrect ifdeffery and dependency of
- CONFIG_KEXEC
-
-The select of KEXEC for CRASH_DUMP in kernel/Kconfig.kexec will be
-dropped, then compiling errors will be triggered if below config items are
-set:
-
-===
-CONFIG_CRASH_CORE=y
-CONFIG_KEXEC_CORE=y
-CONFIG_CRASH_DUMP=y
-===
-
---------------------------------------------------------------------
-mipsel-linux-ld: kernel/kexec_core.o: in function `kimage_free':
-kernel/kexec_core.c:(.text+0x2200): undefined reference to `machine_kexec_cleanup'
-mipsel-linux-ld: kernel/kexec_core.o: in function `__crash_kexec':
-kernel/kexec_core.c:(.text+0x2480): undefined reference to `machine_crash_shutdown'
-mipsel-linux-ld: kernel/kexec_core.c:(.text+0x2488): undefined reference to `machine_kexec'
-mipsel-linux-ld: kernel/kexec_core.o: in function `kernel_kexec':
-kernel/kexec_core.c:(.text+0x29b8): undefined reference to `machine_shutdown'
-mipsel-linux-ld: kernel/kexec_core.c:(.text+0x29c0): undefined reference to `machine_kexec'
---------------------------------------------------------------------
-
-Here, change the dependency of building kexec_core related object files,
-and the ifdeffery in mips from CONFIG_KEXEC to CONFIG_KEXEC_CORE.
-
----
- arch/mips/cavium-octeon/smp.c | 4 ++--
- arch/mips/include/asm/kexec.h | 2 +-
- arch/mips/include/asm/smp-ops.h | 2 +-
- arch/mips/include/asm/smp.h | 2 +-
- arch/mips/kernel/Makefile | 2 +-
- arch/mips/kernel/smp-bmips.c | 4 ++--
- arch/mips/kernel/smp-cps.c | 10 +++++-----
- arch/mips/loongson64/reset.c | 4 ++--
- arch/mips/loongson64/smp.c | 2 +-
- 9 files changed, 16 insertions(+), 16 deletions(-)
-
---- a/arch/mips/cavium-octeon/smp.c
-+++ b/arch/mips/cavium-octeon/smp.c
-@@ -422,7 +422,7 @@ static const struct plat_smp_ops octeon_
- .cpu_disable = octeon_cpu_disable,
- .cpu_die = octeon_cpu_die,
- #endif
--#ifdef CONFIG_KEXEC
-+#ifdef CONFIG_KEXEC_CORE
- .kexec_nonboot_cpu = kexec_nonboot_cpu_jump,
- #endif
- };
-@@ -502,7 +502,7 @@ static const struct plat_smp_ops octeon_
- .cpu_disable = octeon_cpu_disable,
- .cpu_die = octeon_cpu_die,
- #endif
--#ifdef CONFIG_KEXEC
-+#ifdef CONFIG_KEXEC_CORE
- .kexec_nonboot_cpu = kexec_nonboot_cpu_jump,
- #endif
- };
---- a/arch/mips/include/asm/kexec.h
-+++ b/arch/mips/include/asm/kexec.h
-@@ -31,7 +31,7 @@ static inline void crash_setup_regs(stru
- prepare_frametrace(newregs);
- }
-
--#ifdef CONFIG_KEXEC
-+#ifdef CONFIG_KEXEC_CORE
- struct kimage;
- extern unsigned long kexec_args[4];
- extern int (*_machine_kexec_prepare)(struct kimage *);
---- a/arch/mips/include/asm/smp-ops.h
-+++ b/arch/mips/include/asm/smp-ops.h
-@@ -35,7 +35,7 @@ struct plat_smp_ops {
- void (*cpu_die)(unsigned int cpu);
- void (*cleanup_dead_cpu)(unsigned cpu);
- #endif
--#ifdef CONFIG_KEXEC
-+#ifdef CONFIG_KEXEC_CORE
- void (*kexec_nonboot_cpu)(void);
- #endif
- };
---- a/arch/mips/include/asm/smp.h
-+++ b/arch/mips/include/asm/smp.h
-@@ -93,7 +93,7 @@ static inline void __cpu_die(unsigned in
- extern void __noreturn play_dead(void);
- #endif
-
--#ifdef CONFIG_KEXEC
-+#ifdef CONFIG_KEXEC_CORE
- static inline void kexec_nonboot_cpu(void)
- {
- extern const struct plat_smp_ops *mp_ops; /* private */
---- a/arch/mips/kernel/Makefile
-+++ b/arch/mips/kernel/Makefile
-@@ -90,7 +90,7 @@ obj-$(CONFIG_GPIO_TXX9) += gpio_txx9.o
-
- obj-$(CONFIG_RELOCATABLE) += relocate.o
-
--obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o crash.o
-+obj-$(CONFIG_KEXEC_CORE) += machine_kexec.o relocate_kernel.o crash.o
- obj-$(CONFIG_CRASH_DUMP) += crash_dump.o
- obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
- obj-$(CONFIG_EARLY_PRINTK_8250) += early_printk_8250.o
---- a/arch/mips/kernel/smp-bmips.c
-+++ b/arch/mips/kernel/smp-bmips.c
-@@ -434,7 +434,7 @@ const struct plat_smp_ops bmips43xx_smp_
- .cpu_disable = bmips_cpu_disable,
- .cpu_die = bmips_cpu_die,
- #endif
--#ifdef CONFIG_KEXEC
-+#ifdef CONFIG_KEXEC_CORE
- .kexec_nonboot_cpu = kexec_nonboot_cpu_jump,
- #endif
- };
-@@ -451,7 +451,7 @@ const struct plat_smp_ops bmips5000_smp_
- .cpu_disable = bmips_cpu_disable,
- .cpu_die = bmips_cpu_die,
- #endif
--#ifdef CONFIG_KEXEC
-+#ifdef CONFIG_KEXEC_CORE
- .kexec_nonboot_cpu = kexec_nonboot_cpu_jump,
- #endif
- };
---- a/arch/mips/kernel/smp-cps.c
-+++ b/arch/mips/kernel/smp-cps.c
-@@ -395,7 +395,7 @@ static void cps_smp_finish(void)
- local_irq_enable();
- }
-
--#if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_KEXEC)
-+#if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_KEXEC_CORE)
-
- enum cpu_death {
- CPU_DEATH_HALT,
-@@ -432,7 +432,7 @@ static void cps_shutdown_this_cpu(enum c
- }
- }
-
--#ifdef CONFIG_KEXEC
-+#ifdef CONFIG_KEXEC_CORE
-
- static void cps_kexec_nonboot_cpu(void)
- {
-@@ -442,9 +442,9 @@ static void cps_kexec_nonboot_cpu(void)
- cps_shutdown_this_cpu(CPU_DEATH_POWER);
- }
-
--#endif /* CONFIG_KEXEC */
-+#endif /* CONFIG_KEXEC_CORE */
-
--#endif /* CONFIG_HOTPLUG_CPU || CONFIG_KEXEC */
-+#endif /* CONFIG_HOTPLUG_CPU || CONFIG_KEXEC_CORE */
-
- #ifdef CONFIG_HOTPLUG_CPU
-
-@@ -613,7 +613,7 @@ static const struct plat_smp_ops cps_smp
- .cpu_die = cps_cpu_die,
- .cleanup_dead_cpu = cps_cleanup_dead_cpu,
- #endif
--#ifdef CONFIG_KEXEC
-+#ifdef CONFIG_KEXEC_CORE
- .kexec_nonboot_cpu = cps_kexec_nonboot_cpu,
- #endif
- };
---- a/arch/mips/loongson64/reset.c
-+++ b/arch/mips/loongson64/reset.c
-@@ -39,7 +39,7 @@ static int firmware_poweroff(struct sys_
- return NOTIFY_DONE;
- }
-
--#ifdef CONFIG_KEXEC
-+#ifdef CONFIG_KEXEC_CORE
-
- /* 0X80000000~0X80200000 is safe */
- #define MAX_ARGS 64
-@@ -152,7 +152,7 @@ static int __init mips_reboot_setup(void
- firmware_poweroff, NULL);
- }
-
--#ifdef CONFIG_KEXEC
-+#ifdef CONFIG_KEXEC_CORE
- kexec_argv = kmalloc(KEXEC_ARGV_SIZE, GFP_KERNEL);
- if (WARN_ON(!kexec_argv))
- return -ENOMEM;
---- a/arch/mips/loongson64/smp.c
-+++ b/arch/mips/loongson64/smp.c
-@@ -883,7 +883,7 @@ const struct plat_smp_ops loongson3_smp_
- .cpu_disable = loongson3_cpu_disable,
- .cpu_die = loongson3_cpu_die,
- #endif
--#ifdef CONFIG_KEXEC
-+#ifdef CONFIG_KEXEC_CORE
- .kexec_nonboot_cpu = kexec_nonboot_cpu_jump,
- #endif
- };
+++ /dev/null
-From a5c05453a13ab324ad8719e8a23dfb6af01f3652 Mon Sep 17 00:00:00 2001
-Date: Thu, 20 Jun 2024 17:26:42 +0200
-Subject: [PATCH 1/4] mips: bmips: rework and cache CBR addr handling
-
-Rework the handling of the CBR address and cache it. This address
-doesn't change and can be cached instead of reading the register every
-time.
-
-This is in preparation of permitting to tweak the CBR address in DT with
-broken SoC or bootloader.
-
-bmips_cbr_addr is defined in setup.c for each arch to keep compatibility
-with legacy brcm47xx/brcm63xx and generic BMIPS target.
-
----
- arch/mips/bcm47xx/prom.c | 3 +++
- arch/mips/bcm47xx/setup.c | 4 ++++
- arch/mips/bcm63xx/prom.c | 3 +++
- arch/mips/bcm63xx/setup.c | 4 ++++
- arch/mips/bmips/dma.c | 2 +-
- arch/mips/bmips/setup.c | 7 ++++++-
- arch/mips/include/asm/bmips.h | 1 +
- arch/mips/kernel/smp-bmips.c | 4 ++--
- 8 files changed, 24 insertions(+), 4 deletions(-)
-
---- a/arch/mips/bcm47xx/prom.c
-+++ b/arch/mips/bcm47xx/prom.c
-@@ -32,6 +32,7 @@
- #include <linux/ssb/ssb_driver_chipcommon.h>
- #include <linux/ssb/ssb_regs.h>
- #include <linux/smp.h>
-+#include <asm/bmips.h>
- #include <asm/bootinfo.h>
- #include <bcm47xx.h>
- #include <bcm47xx_board.h>
-@@ -109,6 +110,8 @@ static __init void prom_init_mem(void)
-
- void __init prom_init(void)
- {
-+ /* Cache CBR addr before CPU/DMA setup */
-+ bmips_cbr_addr = BMIPS_GET_CBR();
- prom_init_mem();
- setup_8250_early_printk_port(CKSEG1ADDR(BCM47XX_SERIAL_ADDR), 0, 0);
- }
---- a/arch/mips/bcm47xx/setup.c
-+++ b/arch/mips/bcm47xx/setup.c
-@@ -37,6 +37,7 @@
- #include <linux/ssb/ssb.h>
- #include <linux/ssb/ssb_embedded.h>
- #include <linux/bcma/bcma_soc.h>
-+#include <asm/bmips.h>
- #include <asm/bootinfo.h>
- #include <asm/idle.h>
- #include <asm/prom.h>
-@@ -45,6 +46,9 @@
- #include <bcm47xx.h>
- #include <bcm47xx_board.h>
-
-+/* CBR addr doesn't change and we can cache it */
-+void __iomem *bmips_cbr_addr __read_mostly;
-+
- union bcm47xx_bus bcm47xx_bus;
- EXPORT_SYMBOL(bcm47xx_bus);
-
---- a/arch/mips/bcm63xx/prom.c
-+++ b/arch/mips/bcm63xx/prom.c
-@@ -22,6 +22,9 @@ void __init prom_init(void)
- {
- u32 reg, mask;
-
-+ /* Cache CBR addr before CPU/DMA setup */
-+ bmips_cbr_addr = BMIPS_GET_CBR();
-+
- bcm63xx_cpu_init();
-
- /* stop any running watchdog */
---- a/arch/mips/bcm63xx/setup.c
-+++ b/arch/mips/bcm63xx/setup.c
-@@ -12,6 +12,7 @@
- #include <linux/memblock.h>
- #include <linux/ioport.h>
- #include <linux/pm.h>
-+#include <asm/bmips.h>
- #include <asm/bootinfo.h>
- #include <asm/time.h>
- #include <asm/reboot.h>
-@@ -22,6 +23,9 @@
- #include <bcm63xx_io.h>
- #include <bcm63xx_gpio.h>
-
-+/* CBR addr doesn't change and we can cache it */
-+void __iomem *bmips_cbr_addr __read_mostly;
-+
- void bcm63xx_machine_halt(void)
- {
- pr_info("System halted\n");
---- a/arch/mips/bmips/dma.c
-+++ b/arch/mips/bmips/dma.c
-@@ -9,7 +9,7 @@ bool bmips_rac_flush_disable;
-
- void arch_sync_dma_for_cpu_all(void)
- {
-- void __iomem *cbr = BMIPS_GET_CBR();
-+ void __iomem *cbr = bmips_cbr_addr;
- u32 cfg;
-
- if (boot_cpu_type() != CPU_BMIPS3300 &&
---- a/arch/mips/bmips/setup.c
-+++ b/arch/mips/bmips/setup.c
-@@ -34,6 +34,9 @@
- #define REG_BCM6328_OTP ((void __iomem *)CKSEG1ADDR(0x1000062c))
- #define BCM6328_TP1_DISABLED BIT(9)
-
-+/* CBR addr doesn't change and we can cache it */
-+void __iomem *bmips_cbr_addr __read_mostly;
-+
- extern bool bmips_rac_flush_disable;
-
- static const unsigned long kbase = VMLINUX_LOAD_ADDRESS & 0xfff00000;
-@@ -111,7 +114,7 @@ static void bcm6358_quirks(void)
- * because the bootloader is not initializing it properly.
- */
- bmips_rac_flush_disable = !!(read_c0_brcm_cmt_local() & (1 << 31)) ||
-- !!BMIPS_GET_CBR();
-+ !!bmips_cbr_addr;
- }
-
- static void bcm6368_quirks(void)
-@@ -144,6 +147,8 @@ static void __init bmips_init_cfe(void)
-
- void __init prom_init(void)
- {
-+ /* Cache CBR addr before CPU/DMA setup */
-+ bmips_cbr_addr = BMIPS_GET_CBR();
- bmips_init_cfe();
- bmips_cpu_setup();
- register_bmips_smp_ops();
---- a/arch/mips/include/asm/bmips.h
-+++ b/arch/mips/include/asm/bmips.h
-@@ -81,6 +81,7 @@ extern char bmips_smp_movevec[];
- extern char bmips_smp_int_vec[];
- extern char bmips_smp_int_vec_end[];
-
-+extern void __iomem *bmips_cbr_addr;
- extern int bmips_smp_enabled;
- extern int bmips_cpu_offset;
- extern cpumask_t bmips_booted_mask;
---- a/arch/mips/kernel/smp-bmips.c
-+++ b/arch/mips/kernel/smp-bmips.c
-@@ -518,7 +518,7 @@ static void bmips_set_reset_vec(int cpu,
- info.val = val;
- bmips_set_reset_vec_remote(&info);
- } else {
-- void __iomem *cbr = BMIPS_GET_CBR();
-+ void __iomem *cbr = bmips_cbr_addr;
-
- if (cpu == 0)
- __raw_writel(val, cbr + BMIPS_RELO_VECTOR_CONTROL_0);
-@@ -591,7 +591,7 @@ asmlinkage void __weak plat_wired_tlb_se
-
- void bmips_cpu_setup(void)
- {
-- void __iomem __maybe_unused *cbr = BMIPS_GET_CBR();
-+ void __iomem __maybe_unused *cbr = bmips_cbr_addr;
- u32 __maybe_unused cfg;
-
- switch (current_cpu_type()) {
+++ /dev/null
-From b95b30e50aed225d26e20737873ae2404941901c Mon Sep 17 00:00:00 2001
-Date: Thu, 20 Jun 2024 17:26:44 +0200
-Subject: [PATCH 3/4] mips: bmips: setup: make CBR address configurable
-
-Add support to provide CBR address from DT to handle broken
-SoC/Bootloader that doesn't correctly init it. This permits to use the
-RAC flush even in these condition.
-
-To provide a CBR address from DT, the property "brcm,bmips-cbr-reg"
-needs to be set in the "cpus" node. On DT init, this property presence
-will be checked and will set the bmips_cbr_addr value accordingly. Also
-bmips_rac_flush_disable will be set to false as RAC flush can be
-correctly supported.
-
-The CBR address from DT will overwrite the cached one and the
-one set in the CBR register will be ignored.
-
-Also the DT CBR address is validated on being outside DRAM window.
-
----
- arch/mips/bcm47xx/setup.c | 6 +++++-
- arch/mips/bcm63xx/setup.c | 6 +++++-
- arch/mips/bmips/setup.c | 30 ++++++++++++++++++++++++++++--
- 3 files changed, 38 insertions(+), 4 deletions(-)
-
---- a/arch/mips/bcm47xx/setup.c
-+++ b/arch/mips/bcm47xx/setup.c
-@@ -46,7 +46,11 @@
- #include <bcm47xx.h>
- #include <bcm47xx_board.h>
-
--/* CBR addr doesn't change and we can cache it */
-+/*
-+ * CBR addr doesn't change and we can cache it.
-+ * For broken SoC/Bootloader CBR addr might also be provided via DT
-+ * with "brcm,bmips-cbr-reg" in the "cpus" node.
-+ */
- void __iomem *bmips_cbr_addr __read_mostly;
-
- union bcm47xx_bus bcm47xx_bus;
---- a/arch/mips/bcm63xx/setup.c
-+++ b/arch/mips/bcm63xx/setup.c
-@@ -23,7 +23,11 @@
- #include <bcm63xx_io.h>
- #include <bcm63xx_gpio.h>
-
--/* CBR addr doesn't change and we can cache it */
-+/*
-+ * CBR addr doesn't change and we can cache it.
-+ * For broken SoC/Bootloader CBR addr might also be provided via DT
-+ * with "brcm,bmips-cbr-reg" in the "cpus" node.
-+ */
- void __iomem *bmips_cbr_addr __read_mostly;
-
- void bcm63xx_machine_halt(void)
---- a/arch/mips/bmips/setup.c
-+++ b/arch/mips/bmips/setup.c
-@@ -34,7 +34,11 @@
- #define REG_BCM6328_OTP ((void __iomem *)CKSEG1ADDR(0x1000062c))
- #define BCM6328_TP1_DISABLED BIT(9)
-
--/* CBR addr doesn't change and we can cache it */
-+/*
-+ * CBR addr doesn't change and we can cache it.
-+ * For broken SoC/Bootloader CBR addr might also be provided via DT
-+ * with "brcm,bmips-cbr-reg" in the "cpus" node.
-+ */
- void __iomem *bmips_cbr_addr __read_mostly;
-
- extern bool bmips_rac_flush_disable;
-@@ -208,13 +212,35 @@ void __init plat_mem_setup(void)
- void __init device_tree_init(void)
- {
- struct device_node *np;
-+ u32 addr;
-
- unflatten_and_copy_device_tree();
-
- /* Disable SMP boot unless both CPUs are listed in DT and !disabled */
- np = of_find_node_by_name(NULL, "cpus");
-- if (np && of_get_available_child_count(np) <= 1)
-+ if (!np)
-+ return;
-+
-+ if (of_get_available_child_count(np) <= 1)
- bmips_smp_enabled = 0;
-+
-+ /* Check if DT provide a CBR address */
-+ if (of_property_read_u32(np, "brcm,bmips-cbr-reg", &addr))
-+ goto exit;
-+
-+ /* Make sure CBR address is outside DRAM window */
-+ if (addr >= (u32)memblock_start_of_DRAM() &&
-+ addr < (u32)memblock_end_of_DRAM()) {
-+ WARN(1, "DT CBR %x inside DRAM window. Ignoring DT CBR.\n",
-+ addr);
-+ goto exit;
-+ }
-+
-+ bmips_cbr_addr = (void __iomem *)addr;
-+ /* Since CBR is provided by DT, enable RAC flush */
-+ bmips_rac_flush_disable = false;
-+
-+exit:
- of_node_put(np);
- }
-
+++ /dev/null
-From 04f38d1a4db017f17e82442727b91ce03dd72759 Mon Sep 17 00:00:00 2001
-Date: Thu, 20 Jun 2024 17:26:45 +0200
-Subject: [PATCH 4/4] mips: bmips: enable RAC on BMIPS4350
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-The data RAC is left disabled by the bootloader in some SoCs, at least in
-the core it boots from.
-Enabling this feature increases the performance up to +30% depending on the
-task.
-
-[ rework code and reduce code duplication ]
----
- arch/mips/kernel/smp-bmips.c | 18 ++++++++++++++++++
- 1 file changed, 18 insertions(+)
-
---- a/arch/mips/kernel/smp-bmips.c
-+++ b/arch/mips/kernel/smp-bmips.c
-@@ -592,6 +592,7 @@ asmlinkage void __weak plat_wired_tlb_se
- void bmips_cpu_setup(void)
- {
- void __iomem __maybe_unused *cbr = bmips_cbr_addr;
-+ u32 __maybe_unused rac_addr;
- u32 __maybe_unused cfg;
-
- switch (current_cpu_type()) {
-@@ -620,6 +621,23 @@ void bmips_cpu_setup(void)
- __raw_readl(cbr + BMIPS_RAC_ADDRESS_RANGE);
- break;
-
-+ case CPU_BMIPS4350:
-+ rac_addr = BMIPS_RAC_CONFIG_1;
-+
-+ if (!(read_c0_brcm_cmt_local() & (1 << 31)))
-+ rac_addr = BMIPS_RAC_CONFIG;
-+
-+ /* Enable data RAC */
-+ cfg = __raw_readl(cbr + rac_addr);
-+ __raw_writel(cfg | 0xf, cbr + rac_addr);
-+ __raw_readl(cbr + rac_addr);
-+
-+ /* Flush stale data out of the readahead cache */
-+ cfg = __raw_readl(cbr + BMIPS_RAC_CONFIG);
-+ __raw_writel(cfg | 0x100, cbr + BMIPS_RAC_CONFIG);
-+ __raw_readl(cbr + BMIPS_RAC_CONFIG);
-+ break;
-+
- case CPU_BMIPS4380:
- /* CBG workaround for early BMIPS4380 CPUs */
- switch (read_c0_prid()) {
+++ /dev/null
-From b35108a51cf7bab58d7eace1267d7965978bcdb8 Mon Sep 17 00:00:00 2001
-Date: Wed, 30 Oct 2024 17:47:35 +0000
-Subject: [PATCH] jiffies: Define secs_to_jiffies()
-
-secs_to_jiffies() is defined in hci_event.c and cannot be reused by
-other call sites. Hoist it into the core code to allow conversion of the
-~1150 usages of msecs_to_jiffies() that either:
-
- - use a multiplier value of 1000 or equivalently MSEC_PER_SEC, or
- - have timeouts that are denominated in seconds (i.e. end in 000)
-
-It's implemented as a macro to allow usage in static initializers.
-
-This will also allow conversion of yet more sites that use (sec * HZ)
-directly, and improve their readability.
-
-Link: https://lore.kernel.org/all/20241030-open-coded-timeouts-v3-1-9ba123facf88@linux.microsoft.com
----
- include/linux/jiffies.h | 13 +++++++++++++
- net/bluetooth/hci_event.c | 2 --
- 2 files changed, 13 insertions(+), 2 deletions(-)
-
---- a/include/linux/jiffies.h
-+++ b/include/linux/jiffies.h
-@@ -523,6 +523,19 @@ static __always_inline unsigned long mse
- }
- }
-
-+/**
-+ * secs_to_jiffies: - convert seconds to jiffies
-+ * @_secs: time in seconds
-+ *
-+ * Conversion is done by simple multiplication with HZ
-+ *
-+ * secs_to_jiffies() is defined as a macro rather than a static inline
-+ * function so it can be used in static initializers.
-+ *
-+ * Return: jiffies value
-+ */
-+#define secs_to_jiffies(_secs) ((_secs) * HZ)
-+
- extern unsigned long __usecs_to_jiffies(const unsigned int u);
- #if !(USEC_PER_SEC % HZ)
- static inline unsigned long _usecs_to_jiffies(const unsigned int u)
---- a/net/bluetooth/hci_event.c
-+++ b/net/bluetooth/hci_event.c
-@@ -43,8 +43,6 @@
- #define ZERO_KEY "\x00\x00\x00\x00\x00\x00\x00\x00" \
- "\x00\x00\x00\x00\x00\x00\x00\x00"
-
--#define secs_to_jiffies(_secs) msecs_to_jiffies((_secs) * 1000)
--
- /* Handle HCI Event packets */
-
- static void *hci_ev_skb_pull(struct hci_dev *hdev, struct sk_buff *skb,
+++ /dev/null
-From bb2784d9ab49587ba4fbff37a319fff2924db289 Mon Sep 17 00:00:00 2001
-Date: Thu, 30 Jan 2025 19:26:58 +0000
-Subject: [PATCH] jiffies: Cast to unsigned long in secs_to_jiffies()
- conversion
-
-While converting users of msecs_to_jiffies(), lkp reported that some range
-checks would always be true because of the mismatch between the implied int
-value of secs_to_jiffies() vs the unsigned long return value of the
-msecs_to_jiffies() calls it was replacing.
-
-Fix this by casting the secs_to_jiffies() input value to unsigned long.
-
-Fixes: b35108a51cf7ba ("jiffies: Define secs_to_jiffies()")
----
- include/linux/jiffies.h | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/include/linux/jiffies.h
-+++ b/include/linux/jiffies.h
-@@ -534,7 +534,7 @@ static __always_inline unsigned long mse
- *
- * Return: jiffies value
- */
--#define secs_to_jiffies(_secs) ((_secs) * HZ)
-+#define secs_to_jiffies(_secs) (unsigned long)((_secs) * HZ)
-
- extern unsigned long __usecs_to_jiffies(const unsigned int u);
- #if !(USEC_PER_SEC % HZ)
+++ /dev/null
-From 8e7daa85641c9559c113f6b217bdc923397de77c Mon Sep 17 00:00:00 2001
-Date: Thu, 22 Feb 2024 19:47:58 -0800
-Subject: [PATCH] mtd: rawnand: brcmnand: Support write protection setting from
- dts
-
-The write protection feature is controlled by the module parameter wp_on
-with default set to enabled. But not all the board use this feature
-especially in BCMBCA broadband board. And module parameter is not
-sufficient as different board can have different option. Add a device
-tree property and allow this feature to be configured through the board
-dts on per board basis.
-
----
- drivers/mtd/nand/raw/brcmnand/brcmnand.c | 4 ++++
- 1 file changed, 4 insertions(+)
-
---- a/drivers/mtd/nand/raw/brcmnand/brcmnand.c
-+++ b/drivers/mtd/nand/raw/brcmnand/brcmnand.c
-@@ -3194,6 +3194,10 @@ int brcmnand_probe(struct platform_devic
- /* Disable XOR addressing */
- brcmnand_rmw_reg(ctrl, BRCMNAND_CS_XOR, 0xff, 0, 0);
-
-+ /* Check if the board connects the WP pin */
-+ if (of_property_read_bool(dn, "brcm,wp-not-connected"))
-+ wp_on = 0;
-+
- if (ctrl->features & BRCMNAND_HAS_WP) {
- /* Permanently disable write protection */
- if (wp_on == 2)
+++ /dev/null
-From 25d88bfd35bac3196eafa666e3b05033b46ffa21 Mon Sep 17 00:00:00 2001
-Date: Tue, 19 Dec 2023 02:32:00 +0000
-Subject: [PATCH 1/8] dt-bindings: mtd: add basic bindings for UBI
-
-Add basic bindings for UBI devices and volumes.
-
----
- .../bindings/mtd/partitions/linux,ubi.yaml | 65 +++++++++++++++++++
- .../bindings/mtd/partitions/ubi-volume.yaml | 35 ++++++++++
- 2 files changed, 100 insertions(+)
- create mode 100644 Documentation/devicetree/bindings/mtd/partitions/linux,ubi.yaml
- create mode 100644 Documentation/devicetree/bindings/mtd/partitions/ubi-volume.yaml
-
---- /dev/null
-+++ b/Documentation/devicetree/bindings/mtd/partitions/linux,ubi.yaml
-@@ -0,0 +1,65 @@
-+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
-+%YAML 1.2
-+---
-+$id: http://devicetree.org/schemas/mtd/partitions/linux,ubi.yaml#
-+$schema: http://devicetree.org/meta-schemas/core.yaml#
-+
-+title: Unsorted Block Images
-+
-+description: |
-+ UBI ("Unsorted Block Images") is a volume management system for raw
-+ flash devices which manages multiple logical volumes on a single
-+ physical flash device and spreads the I/O load (i.e wear-leveling)
-+ across the whole flash chip.
-+
-+maintainers:
-+
-+allOf:
-+ - $ref: partition.yaml#
-+
-+properties:
-+ compatible:
-+ const: linux,ubi
-+
-+ volumes:
-+ type: object
-+ description: UBI Volumes
-+
-+ patternProperties:
-+ "^ubi-volume-.*$":
-+ $ref: /schemas/mtd/partitions/ubi-volume.yaml#
-+
-+ unevaluatedProperties: false
-+
-+required:
-+ - compatible
-+
-+unevaluatedProperties: false
-+
-+examples:
-+ - |
-+ partitions {
-+ compatible = "fixed-partitions";
-+ #address-cells = <1>;
-+ #size-cells = <1>;
-+
-+ partition@0 {
-+ reg = <0x0 0x100000>;
-+ label = "bootloader";
-+ read-only;
-+ };
-+
-+ partition@100000 {
-+ reg = <0x100000 0x1ff00000>;
-+ label = "ubi";
-+ compatible = "linux,ubi";
-+
-+ volumes {
-+ ubi-volume-caldata {
-+ volid = <2>;
-+ volname = "rf";
-+ };
-+ };
-+ };
-+ };
---- /dev/null
-+++ b/Documentation/devicetree/bindings/mtd/partitions/ubi-volume.yaml
-@@ -0,0 +1,35 @@
-+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
-+%YAML 1.2
-+---
-+$id: http://devicetree.org/schemas/mtd/partitions/ubi-volume.yaml#
-+$schema: http://devicetree.org/meta-schemas/core.yaml#
-+
-+title: UBI volume
-+
-+description: |
-+ This binding describes a single UBI volume. Volumes can be matches either
-+ by their ID or their name, or both.
-+
-+maintainers:
-+
-+properties:
-+ volid:
-+ $ref: /schemas/types.yaml#/definitions/uint32
-+ description:
-+ Match UBI volume ID
-+
-+ volname:
-+ $ref: /schemas/types.yaml#/definitions/string
-+ description:
-+ Match UBI volume ID
-+
-+anyOf:
-+ - required:
-+ - volid
-+
-+ - required:
-+ - volname
-+
-+# This is a generic file other binding inherit from and extend
-+additionalProperties: true
+++ /dev/null
-From 95b113222b5164ac0887eb5c514ff3970a0136f0 Mon Sep 17 00:00:00 2001
-Date: Tue, 19 Dec 2023 02:32:11 +0000
-Subject: [PATCH 2/8] dt-bindings: mtd: ubi-volume: allow UBI volumes to
- provide NVMEM
-
-UBI volumes may be used to contain NVMEM bits, typically device MAC
-addresses or wireless radio calibration data.
-
----
- .../devicetree/bindings/mtd/partitions/linux,ubi.yaml | 10 ++++++++++
- .../devicetree/bindings/mtd/partitions/ubi-volume.yaml | 5 +++++
- 2 files changed, 15 insertions(+)
-
---- a/Documentation/devicetree/bindings/mtd/partitions/linux,ubi.yaml
-+++ b/Documentation/devicetree/bindings/mtd/partitions/linux,ubi.yaml
-@@ -59,6 +59,16 @@ examples:
- ubi-volume-caldata {
- volid = <2>;
- volname = "rf";
-+
-+ nvmem-layout {
-+ compatible = "fixed-layout";
-+ #address-cells = <1>;
-+ #size-cells = <1>;
-+
-+ eeprom@0 {
-+ reg = <0x0 0x1000>;
-+ };
-+ };
- };
- };
- };
---- a/Documentation/devicetree/bindings/mtd/partitions/ubi-volume.yaml
-+++ b/Documentation/devicetree/bindings/mtd/partitions/ubi-volume.yaml
-@@ -24,6 +24,11 @@ properties:
- description:
- Match UBI volume ID
-
-+ nvmem-layout:
-+ $ref: /schemas/nvmem/layouts/nvmem-layout.yaml#
-+ description:
-+ This container may reference an NVMEM layout parser.
-+
- anyOf:
- - required:
- - volid
+++ /dev/null
-From 2bba1cdcfcd2907d0696cc0139f1bd078d36ee81 Mon Sep 17 00:00:00 2001
-Date: Tue, 19 Dec 2023 02:32:35 +0000
-Subject: [PATCH 3/8] mtd: ubi: block: use notifier to create ubiblock from
- parameter
-
-Use UBI_VOLUME_ADDED notification to create ubiblock device specified
-on kernel cmdline or module parameter.
-This makes thing more simple and has the advantage that ubiblock devices
-on volumes which are not present at the time the ubi module is probed
-will still be created.
-
----
- drivers/mtd/ubi/block.c | 136 ++++++++++++++++++++--------------------
- drivers/mtd/ubi/kapi.c | 54 +++++++++++-----
- drivers/mtd/ubi/ubi.h | 1 +
- 3 files changed, 106 insertions(+), 85 deletions(-)
-
---- a/drivers/mtd/ubi/block.c
-+++ b/drivers/mtd/ubi/block.c
-@@ -65,10 +65,10 @@ struct ubiblock_pdu {
- };
-
- /* Numbers of elements set in the @ubiblock_param array */
--static int ubiblock_devs __initdata;
-+static int ubiblock_devs;
-
- /* MTD devices specification parameters */
--static struct ubiblock_param ubiblock_param[UBIBLOCK_MAX_DEVICES] __initdata;
-+static struct ubiblock_param ubiblock_param[UBIBLOCK_MAX_DEVICES];
-
- struct ubiblock {
- struct ubi_volume_desc *desc;
-@@ -532,6 +532,70 @@ static int ubiblock_resize(struct ubi_vo
- return 0;
- }
-
-+static bool
-+match_volume_desc(struct ubi_volume_info *vi, const char *name, int ubi_num, int vol_id)
-+{
-+ int err, len, cur_ubi_num, cur_vol_id;
-+
-+ if (ubi_num == -1) {
-+ /* No ubi num, name must be a vol device path */
-+ err = ubi_get_num_by_path(name, &cur_ubi_num, &cur_vol_id);
-+ if (err || vi->ubi_num != cur_ubi_num || vi->vol_id != cur_vol_id)
-+ return false;
-+
-+ return true;
-+ }
-+
-+ if (vol_id == -1) {
-+ /* Got ubi_num, but no vol_id, name must be volume name */
-+ if (vi->ubi_num != ubi_num)
-+ return false;
-+
-+ len = strnlen(name, UBI_VOL_NAME_MAX + 1);
-+ if (len < 1 || vi->name_len != len)
-+ return false;
-+
-+ if (strcmp(name, vi->name))
-+ return false;
-+
-+ return true;
-+ }
-+
-+ if (vi->ubi_num != ubi_num)
-+ return false;
-+
-+ if (vi->vol_id != vol_id)
-+ return false;
-+
-+ return true;
-+}
-+
-+static void
-+ubiblock_create_from_param(struct ubi_volume_info *vi)
-+{
-+ int i, ret = 0;
-+ struct ubiblock_param *p;
-+
-+ /*
-+ * Iterate over ubiblock cmdline parameters. If a parameter matches the
-+ * newly added volume create the ubiblock device for it.
-+ */
-+ for (i = 0; i < ubiblock_devs; i++) {
-+ p = &ubiblock_param[i];
-+
-+ if (!match_volume_desc(vi, p->name, p->ubi_num, p->vol_id))
-+ continue;
-+
-+ ret = ubiblock_create(vi);
-+ if (ret) {
-+ pr_err(
-+ "UBI: block: can't add '%s' volume on ubi%d_%d, err=%d\n",
-+ vi->name, p->ubi_num, p->vol_id, ret);
-+ }
-+ break;
-+ }
-+}
-+
- static int ubiblock_notify(struct notifier_block *nb,
- unsigned long notification_type, void *ns_ptr)
- {
-@@ -539,10 +603,7 @@ static int ubiblock_notify(struct notifi
-
- switch (notification_type) {
- case UBI_VOLUME_ADDED:
-- /*
-- * We want to enforce explicit block device creation for
-- * volumes, so when a volume is added we do nothing.
-- */
-+ ubiblock_create_from_param(&nt->vi);
- break;
- case UBI_VOLUME_REMOVED:
- ubiblock_remove(&nt->vi);
-@@ -568,56 +629,6 @@ static struct notifier_block ubiblock_no
- .notifier_call = ubiblock_notify,
- };
-
--static struct ubi_volume_desc * __init
--open_volume_desc(const char *name, int ubi_num, int vol_id)
--{
-- if (ubi_num == -1)
-- /* No ubi num, name must be a vol device path */
-- return ubi_open_volume_path(name, UBI_READONLY);
-- else if (vol_id == -1)
-- /* No vol_id, must be vol_name */
-- return ubi_open_volume_nm(ubi_num, name, UBI_READONLY);
-- else
-- return ubi_open_volume(ubi_num, vol_id, UBI_READONLY);
--}
--
--static void __init ubiblock_create_from_param(void)
--{
-- int i, ret = 0;
-- struct ubiblock_param *p;
-- struct ubi_volume_desc *desc;
-- struct ubi_volume_info vi;
--
-- /*
-- * If there is an error creating one of the ubiblocks, continue on to
-- * create the following ubiblocks. This helps in a circumstance where
-- * the kernel command-line specifies multiple block devices and some
-- * may be broken, but we still want the working ones to come up.
-- */
-- for (i = 0; i < ubiblock_devs; i++) {
-- p = &ubiblock_param[i];
--
-- desc = open_volume_desc(p->name, p->ubi_num, p->vol_id);
-- if (IS_ERR(desc)) {
-- pr_err(
-- "UBI: block: can't open volume on ubi%d_%d, err=%ld\n",
-- p->ubi_num, p->vol_id, PTR_ERR(desc));
-- continue;
-- }
--
-- ubi_get_volume_info(desc, &vi);
-- ubi_close_volume(desc);
--
-- ret = ubiblock_create(&vi);
-- if (ret) {
-- pr_err(
-- "UBI: block: can't add '%s' volume on ubi%d_%d, err=%d\n",
-- vi.name, p->ubi_num, p->vol_id, ret);
-- continue;
-- }
-- }
--}
--
- static void ubiblock_remove_all(void)
- {
- struct ubiblock *next;
-@@ -643,18 +654,7 @@ int __init ubiblock_init(void)
- if (ubiblock_major < 0)
- return ubiblock_major;
-
-- /*
-- * Attach block devices from 'block=' module param.
-- * Even if one block device in the param list fails to come up,
-- * still allow the module to load and leave any others up.
-- */
-- ubiblock_create_from_param();
--
-- /*
-- * Block devices are only created upon user requests, so we ignore
-- * existing volumes.
-- */
-- ret = ubi_register_volume_notifier(&ubiblock_notifier, 1);
-+ ret = ubi_register_volume_notifier(&ubiblock_notifier, 0);
- if (ret)
- goto err_unreg;
- return 0;
---- a/drivers/mtd/ubi/kapi.c
-+++ b/drivers/mtd/ubi/kapi.c
-@@ -280,6 +280,41 @@ struct ubi_volume_desc *ubi_open_volume_
- EXPORT_SYMBOL_GPL(ubi_open_volume_nm);
-
- /**
-+ * ubi_get_num_by_path - get UBI device and volume number from device path
-+ * @pathname: volume character device node path
-+ * @ubi_num: pointer to UBI device number to be set
-+ * @vol_id: pointer to UBI volume ID to be set
-+ *
-+ * Returns 0 on success and sets ubi_num and vol_id, returns error otherwise.
-+ */
-+int ubi_get_num_by_path(const char *pathname, int *ubi_num, int *vol_id)
-+{
-+ int error;
-+ struct path path;
-+ struct kstat stat;
-+
-+ error = kern_path(pathname, LOOKUP_FOLLOW, &path);
-+ if (error)
-+ return error;
-+
-+ error = vfs_getattr(&path, &stat, STATX_TYPE, AT_STATX_SYNC_AS_STAT);
-+ path_put(&path);
-+ if (error)
-+ return error;
-+
-+ if (!S_ISCHR(stat.mode))
-+ return -EINVAL;
-+
-+ *ubi_num = ubi_major2num(MAJOR(stat.rdev));
-+ *vol_id = MINOR(stat.rdev) - 1;
-+
-+ if (*vol_id < 0 || *ubi_num < 0)
-+ return -ENODEV;
-+
-+ return 0;
-+}
-+
-+/**
- * ubi_open_volume_path - open UBI volume by its character device node path.
- * @pathname: volume character device node path
- * @mode: open mode
-@@ -290,32 +325,17 @@ EXPORT_SYMBOL_GPL(ubi_open_volume_nm);
- struct ubi_volume_desc *ubi_open_volume_path(const char *pathname, int mode)
- {
- int error, ubi_num, vol_id;
-- struct path path;
-- struct kstat stat;
-
- dbg_gen("open volume %s, mode %d", pathname, mode);
-
- if (!pathname || !*pathname)
- return ERR_PTR(-EINVAL);
-
-- error = kern_path(pathname, LOOKUP_FOLLOW, &path);
-- if (error)
-- return ERR_PTR(error);
--
-- error = vfs_getattr(&path, &stat, STATX_TYPE, AT_STATX_SYNC_AS_STAT);
-- path_put(&path);
-+ error = ubi_get_num_by_path(pathname, &ubi_num, &vol_id);
- if (error)
- return ERR_PTR(error);
-
-- if (!S_ISCHR(stat.mode))
-- return ERR_PTR(-EINVAL);
--
-- ubi_num = ubi_major2num(MAJOR(stat.rdev));
-- vol_id = MINOR(stat.rdev) - 1;
--
-- if (vol_id >= 0 && ubi_num >= 0)
-- return ubi_open_volume(ubi_num, vol_id, mode);
-- return ERR_PTR(-ENODEV);
-+ return ubi_open_volume(ubi_num, vol_id, mode);
- }
- EXPORT_SYMBOL_GPL(ubi_open_volume_path);
-
---- a/drivers/mtd/ubi/ubi.h
-+++ b/drivers/mtd/ubi/ubi.h
-@@ -956,6 +956,7 @@ void ubi_free_internal_volumes(struct ub
- void ubi_do_get_device_info(struct ubi_device *ubi, struct ubi_device_info *di);
- void ubi_do_get_volume_info(struct ubi_device *ubi, struct ubi_volume *vol,
- struct ubi_volume_info *vi);
-+int ubi_get_num_by_path(const char *pathname, int *ubi_num, int *vol_id);
- /* scan.c */
- int ubi_compare_lebs(struct ubi_device *ubi, const struct ubi_ainf_peb *aeb,
- int pnum, const struct ubi_vid_hdr *vid_hdr);
+++ /dev/null
-From 6e331888643887ce85657527bc03f97d46235e71 Mon Sep 17 00:00:00 2001
-Date: Tue, 19 Dec 2023 02:33:14 +0000
-Subject: [PATCH 4/8] mtd: ubi: attach from device tree
-
-Introduce device tree compatible 'linux,ubi' and attach compatible MTD
-devices using the MTD add notifier. This is needed for a UBI device to
-be available early at boot (and not only after late_initcall), so
-volumes on them can be used eg. as NVMEM providers for other drivers.
-
----
- drivers/mtd/ubi/build.c | 135 ++++++++++++++++++++++++++++------------
- 1 file changed, 96 insertions(+), 39 deletions(-)
-
---- a/drivers/mtd/ubi/build.c
-+++ b/drivers/mtd/ubi/build.c
-@@ -27,6 +27,7 @@
- #include <linux/log2.h>
- #include <linux/kthread.h>
- #include <linux/kernel.h>
-+#include <linux/of.h>
- #include <linux/slab.h>
- #include <linux/major.h>
- #include "ubi.h"
-@@ -1214,43 +1215,43 @@ static struct mtd_info * __init open_mtd
- return mtd;
- }
-
--static int __init ubi_init(void)
-+static void ubi_notify_add(struct mtd_info *mtd)
- {
-- int err, i, k;
-+ struct device_node *np = mtd_get_of_node(mtd);
-+ int err;
-
-- /* Ensure that EC and VID headers have correct size */
-- BUILD_BUG_ON(sizeof(struct ubi_ec_hdr) != 64);
-- BUILD_BUG_ON(sizeof(struct ubi_vid_hdr) != 64);
-+ if (!of_device_is_compatible(np, "linux,ubi"))
-+ return;
-
-- if (mtd_devs > UBI_MAX_DEVICES) {
-- pr_err("UBI error: too many MTD devices, maximum is %d\n",
-- UBI_MAX_DEVICES);
-- return -EINVAL;
-- }
-+ /*
-+ * we are already holding &mtd_table_mutex, but still need
-+ * to bump refcount
-+ */
-+ err = __get_mtd_device(mtd);
-+ if (err)
-+ return;
-
-- /* Create base sysfs directory and sysfs files */
-- err = class_register(&ubi_class);
-+ /* called while holding mtd_table_mutex */
-+ mutex_lock_nested(&ubi_devices_mutex, SINGLE_DEPTH_NESTING);
-+ err = ubi_attach_mtd_dev(mtd, UBI_DEV_NUM_AUTO, 0, 0, false);
-+ mutex_unlock(&ubi_devices_mutex);
- if (err < 0)
-- return err;
--
-- err = misc_register(&ubi_ctrl_cdev);
-- if (err) {
-- pr_err("UBI error: cannot register device\n");
-- goto out;
-- }
-+ __put_mtd_device(mtd);
-+}
-
-- ubi_wl_entry_slab = kmem_cache_create("ubi_wl_entry_slab",
-- sizeof(struct ubi_wl_entry),
-- 0, 0, NULL);
-- if (!ubi_wl_entry_slab) {
-- err = -ENOMEM;
-- goto out_dev_unreg;
-- }
-+static void ubi_notify_remove(struct mtd_info *mtd)
-+{
-+ /* do nothing for now */
-+}
-
-- err = ubi_debugfs_init();
-- if (err)
-- goto out_slab;
-+static struct mtd_notifier ubi_mtd_notifier = {
-+ .add = ubi_notify_add,
-+ .remove = ubi_notify_remove,
-+};
-
-+static int __init ubi_init_attach(void)
-+{
-+ int err, i, k;
-
- /* Attach MTD devices */
- for (i = 0; i < mtd_devs; i++) {
-@@ -1298,25 +1299,79 @@ static int __init ubi_init(void)
- }
- }
-
-+ return 0;
-+
-+out_detach:
-+ for (k = 0; k < i; k++)
-+ if (ubi_devices[k]) {
-+ mutex_lock(&ubi_devices_mutex);
-+ ubi_detach_mtd_dev(ubi_devices[k]->ubi_num, 1);
-+ mutex_unlock(&ubi_devices_mutex);
-+ }
-+ return err;
-+}
-+#ifndef CONFIG_MTD_UBI_MODULE
-+late_initcall(ubi_init_attach);
-+#endif
-+
-+static int __init ubi_init(void)
-+{
-+ int err;
-+
-+ /* Ensure that EC and VID headers have correct size */
-+ BUILD_BUG_ON(sizeof(struct ubi_ec_hdr) != 64);
-+ BUILD_BUG_ON(sizeof(struct ubi_vid_hdr) != 64);
-+
-+ if (mtd_devs > UBI_MAX_DEVICES) {
-+ pr_err("UBI error: too many MTD devices, maximum is %d\n",
-+ UBI_MAX_DEVICES);
-+ return -EINVAL;
-+ }
-+
-+ /* Create base sysfs directory and sysfs files */
-+ err = class_register(&ubi_class);
-+ if (err < 0)
-+ return err;
-+
-+ err = misc_register(&ubi_ctrl_cdev);
-+ if (err) {
-+ pr_err("UBI error: cannot register device\n");
-+ goto out;
-+ }
-+
-+ ubi_wl_entry_slab = kmem_cache_create("ubi_wl_entry_slab",
-+ sizeof(struct ubi_wl_entry),
-+ 0, 0, NULL);
-+ if (!ubi_wl_entry_slab) {
-+ err = -ENOMEM;
-+ goto out_dev_unreg;
-+ }
-+
-+ err = ubi_debugfs_init();
-+ if (err)
-+ goto out_slab;
-+
- err = ubiblock_init();
- if (err) {
- pr_err("UBI error: block: cannot initialize, error %d\n", err);
-
- /* See comment above re-ubi_is_module(). */
- if (ubi_is_module())
-- goto out_detach;
-+ goto out_slab;
-+ }
-+
-+ register_mtd_user(&ubi_mtd_notifier);
-+
-+ if (ubi_is_module()) {
-+ err = ubi_init_attach();
-+ if (err)
-+ goto out_mtd_notifier;
- }
-
- return 0;
-
--out_detach:
-- for (k = 0; k < i; k++)
-- if (ubi_devices[k]) {
-- mutex_lock(&ubi_devices_mutex);
-- ubi_detach_mtd_dev(ubi_devices[k]->ubi_num, 1);
-- mutex_unlock(&ubi_devices_mutex);
-- }
-- ubi_debugfs_exit();
-+out_mtd_notifier:
-+ unregister_mtd_user(&ubi_mtd_notifier);
- out_slab:
- kmem_cache_destroy(ubi_wl_entry_slab);
- out_dev_unreg:
-@@ -1326,13 +1381,15 @@ out:
- pr_err("UBI error: cannot initialize UBI, error %d\n", err);
- return err;
- }
--late_initcall(ubi_init);
-+device_initcall(ubi_init);
-+
-
- static void __exit ubi_exit(void)
- {
- int i;
-
- ubiblock_exit();
-+ unregister_mtd_user(&ubi_mtd_notifier);
-
- for (i = 0; i < UBI_MAX_DEVICES; i++)
- if (ubi_devices[i]) {
+++ /dev/null
-From 924731fbed3247e3b82b8ab17db587ee28c2e781 Mon Sep 17 00:00:00 2001
-Date: Tue, 19 Dec 2023 02:33:24 +0000
-Subject: [PATCH 5/8] mtd: ubi: introduce pre-removal notification for UBI
- volumes
-
-Introduce a new notification type UBI_VOLUME_SHUTDOWN to inform users
-that a volume is just about to be removed.
-This is needed because users (such as the NVMEM subsystem) expect that
-at the time their removal function is called, the parenting device is
-still available (for removal of sysfs nodes, for example, in case of
-NVMEM which otherwise WARNs on volume removal).
-
----
- drivers/mtd/ubi/build.c | 19 ++++++++++++++-----
- drivers/mtd/ubi/kapi.c | 2 +-
- drivers/mtd/ubi/ubi.h | 2 ++
- drivers/mtd/ubi/vmt.c | 17 +++++++++++++++--
- include/linux/mtd/ubi.h | 2 ++
- 5 files changed, 34 insertions(+), 8 deletions(-)
-
---- a/drivers/mtd/ubi/build.c
-+++ b/drivers/mtd/ubi/build.c
-@@ -91,7 +91,7 @@ static struct ubi_device *ubi_devices[UB
- /* Serializes UBI devices creations and removals */
- DEFINE_MUTEX(ubi_devices_mutex);
-
--/* Protects @ubi_devices and @ubi->ref_count */
-+/* Protects @ubi_devices, @ubi->ref_count and @ubi->is_dead */
- static DEFINE_SPINLOCK(ubi_devices_lock);
-
- /* "Show" method for files in '/<sysfs>/class/ubi/' */
-@@ -259,6 +259,9 @@ struct ubi_device *ubi_get_device(int ub
-
- spin_lock(&ubi_devices_lock);
- ubi = ubi_devices[ubi_num];
-+ if (ubi && ubi->is_dead)
-+ ubi = NULL;
-+
- if (ubi) {
- ubi_assert(ubi->ref_count >= 0);
- ubi->ref_count += 1;
-@@ -296,7 +299,7 @@ struct ubi_device *ubi_get_by_major(int
- spin_lock(&ubi_devices_lock);
- for (i = 0; i < UBI_MAX_DEVICES; i++) {
- ubi = ubi_devices[i];
-- if (ubi && MAJOR(ubi->cdev.dev) == major) {
-+ if (ubi && !ubi->is_dead && MAJOR(ubi->cdev.dev) == major) {
- ubi_assert(ubi->ref_count >= 0);
- ubi->ref_count += 1;
- get_device(&ubi->dev);
-@@ -325,7 +328,7 @@ int ubi_major2num(int major)
- for (i = 0; i < UBI_MAX_DEVICES; i++) {
- struct ubi_device *ubi = ubi_devices[i];
-
-- if (ubi && MAJOR(ubi->cdev.dev) == major) {
-+ if (ubi && !ubi->is_dead && MAJOR(ubi->cdev.dev) == major) {
- ubi_num = ubi->ubi_num;
- break;
- }
-@@ -512,7 +515,7 @@ static void ubi_free_volumes_from(struct
- int i;
-
- for (i = from; i < ubi->vtbl_slots + UBI_INT_VOL_COUNT; i++) {
-- if (!ubi->volumes[i])
-+ if (!ubi->volumes[i] || ubi->volumes[i]->is_dead)
- continue;
- ubi_eba_replace_table(ubi->volumes[i], NULL);
- ubi_fastmap_destroy_checkmap(ubi->volumes[i]);
-@@ -1094,7 +1097,6 @@ int ubi_detach_mtd_dev(int ubi_num, int
- return -EINVAL;
-
- spin_lock(&ubi_devices_lock);
-- put_device(&ubi->dev);
- ubi->ref_count -= 1;
- if (ubi->ref_count) {
- if (!anyway) {
-@@ -1105,6 +1107,13 @@ int ubi_detach_mtd_dev(int ubi_num, int
- ubi_err(ubi, "%s reference count %d, destroy anyway",
- ubi->ubi_name, ubi->ref_count);
- }
-+ ubi->is_dead = true;
-+ spin_unlock(&ubi_devices_lock);
-+
-+ ubi_notify_all(ubi, UBI_VOLUME_SHUTDOWN, NULL);
-+
-+ spin_lock(&ubi_devices_lock);
-+ put_device(&ubi->dev);
- ubi_devices[ubi_num] = NULL;
- spin_unlock(&ubi_devices_lock);
-
---- a/drivers/mtd/ubi/kapi.c
-+++ b/drivers/mtd/ubi/kapi.c
-@@ -152,7 +152,7 @@ struct ubi_volume_desc *ubi_open_volume(
-
- spin_lock(&ubi->volumes_lock);
- vol = ubi->volumes[vol_id];
-- if (!vol)
-+ if (!vol || vol->is_dead)
- goto out_unlock;
-
- err = -EBUSY;
---- a/drivers/mtd/ubi/ubi.h
-+++ b/drivers/mtd/ubi/ubi.h
-@@ -345,6 +345,7 @@ struct ubi_volume {
- int writers;
- int exclusive;
- int metaonly;
-+ bool is_dead;
-
- int reserved_pebs;
- int vol_type;
-@@ -564,6 +565,7 @@ struct ubi_device {
- spinlock_t volumes_lock;
- int ref_count;
- int image_seq;
-+ bool is_dead;
-
- int rsvd_pebs;
- int avail_pebs;
---- a/drivers/mtd/ubi/vmt.c
-+++ b/drivers/mtd/ubi/vmt.c
-@@ -59,7 +59,7 @@ static ssize_t vol_attribute_show(struct
- struct ubi_device *ubi = vol->ubi;
-
- spin_lock(&ubi->volumes_lock);
-- if (!ubi->volumes[vol->vol_id]) {
-+ if (!ubi->volumes[vol->vol_id] || ubi->volumes[vol->vol_id]->is_dead) {
- spin_unlock(&ubi->volumes_lock);
- return -ENODEV;
- }
-@@ -189,7 +189,7 @@ int ubi_create_volume(struct ubi_device
-
- /* Ensure that the name is unique */
- for (i = 0; i < ubi->vtbl_slots; i++)
-- if (ubi->volumes[i] &&
-+ if (ubi->volumes[i] && !ubi->volumes[i]->is_dead &&
- ubi->volumes[i]->name_len == req->name_len &&
- !strcmp(ubi->volumes[i]->name, req->name)) {
- ubi_err(ubi, "volume \"%s\" exists (ID %d)",
-@@ -352,6 +352,19 @@ int ubi_remove_volume(struct ubi_volume_
- err = -EBUSY;
- goto out_unlock;
- }
-+
-+ /*
-+ * Mark volume as dead at this point to prevent that anyone
-+ * can take a reference to the volume from now on.
-+ * This is necessary as we have to release the spinlock before
-+ * calling ubi_volume_notify.
-+ */
-+ vol->is_dead = true;
-+ spin_unlock(&ubi->volumes_lock);
-+
-+ ubi_volume_notify(ubi, vol, UBI_VOLUME_SHUTDOWN);
-+
-+ spin_lock(&ubi->volumes_lock);
- ubi->volumes[vol_id] = NULL;
- spin_unlock(&ubi->volumes_lock);
-
---- a/include/linux/mtd/ubi.h
-+++ b/include/linux/mtd/ubi.h
-@@ -192,6 +192,7 @@ struct ubi_device_info {
- * or a volume was removed)
- * @UBI_VOLUME_RESIZED: a volume has been re-sized
- * @UBI_VOLUME_RENAMED: a volume has been re-named
-+ * @UBI_VOLUME_SHUTDOWN: a volume is going to removed, shutdown users
- * @UBI_VOLUME_UPDATED: data has been written to a volume
- *
- * These constants define which type of event has happened when a volume
-@@ -202,6 +203,7 @@ enum {
- UBI_VOLUME_REMOVED,
- UBI_VOLUME_RESIZED,
- UBI_VOLUME_RENAMED,
-+ UBI_VOLUME_SHUTDOWN,
- UBI_VOLUME_UPDATED,
- };
-
+++ /dev/null
-From 1c54542170819e36baa43c17ca55bb3d7da89a53 Mon Sep 17 00:00:00 2001
-Date: Tue, 19 Dec 2023 02:33:38 +0000
-Subject: [PATCH 6/8] mtd: ubi: populate ubi volume fwnode
-
-Look for the 'volumes' subnode of an MTD partition attached to a UBI
-device and attach matching child nodes to UBI volumes.
-This allows UBI volumes to be referenced in device tree, e.g. for use
-as NVMEM providers.
-
----
- drivers/mtd/ubi/vmt.c | 27 +++++++++++++++++++++++++++
- 1 file changed, 27 insertions(+)
-
---- a/drivers/mtd/ubi/vmt.c
-+++ b/drivers/mtd/ubi/vmt.c
-@@ -124,6 +124,31 @@ static void vol_release(struct device *d
- kfree(vol);
- }
-
-+static struct fwnode_handle *find_volume_fwnode(struct ubi_volume *vol)
-+{
-+ struct fwnode_handle *fw_vols, *fw_vol;
-+ const char *volname;
-+ u32 volid;
-+
-+ fw_vols = device_get_named_child_node(vol->dev.parent->parent, "volumes");
-+ if (!fw_vols)
-+ return NULL;
-+
-+ fwnode_for_each_child_node(fw_vols, fw_vol) {
-+ if (!fwnode_property_read_string(fw_vol, "volname", &volname) &&
-+ strncmp(volname, vol->name, vol->name_len))
-+ continue;
-+
-+ if (!fwnode_property_read_u32(fw_vol, "volid", &volid) &&
-+ vol->vol_id != volid)
-+ continue;
-+
-+ return fw_vol;
-+ }
-+
-+ return NULL;
-+}
-+
- /**
- * ubi_create_volume - create volume.
- * @ubi: UBI device description object
-@@ -223,6 +248,7 @@ int ubi_create_volume(struct ubi_device
- vol->name_len = req->name_len;
- memcpy(vol->name, req->name, vol->name_len);
- vol->ubi = ubi;
-+ device_set_node(&vol->dev, find_volume_fwnode(vol));
-
- /*
- * Finish all pending erases because there may be some LEBs belonging
-@@ -605,6 +631,7 @@ int ubi_add_volume(struct ubi_device *ub
- vol->dev.class = &ubi_class;
- vol->dev.groups = volume_dev_groups;
- dev_set_name(&vol->dev, "%s_%d", ubi->ubi_name, vol->vol_id);
-+ device_set_node(&vol->dev, find_volume_fwnode(vol));
- err = device_register(&vol->dev);
- if (err) {
- cdev_del(&vol->cdev);
+++ /dev/null
-From 15fc7dc926c91c871f6c0305b2938dbdeb14203b Mon Sep 17 00:00:00 2001
-Date: Tue, 19 Dec 2023 02:33:48 +0000
-Subject: [PATCH 7/8] mtd: ubi: provide NVMEM layer over UBI volumes
-
-In an ideal world we would like UBI to be used where ever possible on a
-NAND chip. And with UBI support in ARM Trusted Firmware and U-Boot it
-is possible to achieve an (almost-)all-UBI flash layout. Hence the need
-for a way to also use UBI volumes to store board-level constants, such
-as MAC addresses and calibration data of wireless interfaces.
-
-Add UBI volume NVMEM driver module exposing UBI volumes as NVMEM
-providers. Allow UBI devices to have a "volumes" firmware subnode with
-volumes which may be compatible with "nvmem-cells".
-Access to UBI volumes via the NVMEM interface at this point is
-read-only, and it is slow, opening and closing the UBI volume for each
-access due to limitations of the NVMEM provider API.
-
----
- drivers/mtd/ubi/Kconfig | 12 +++
- drivers/mtd/ubi/Makefile | 1 +
- drivers/mtd/ubi/nvmem.c | 188 +++++++++++++++++++++++++++++++++++++++
- 3 files changed, 201 insertions(+)
- create mode 100644 drivers/mtd/ubi/nvmem.c
-
---- a/drivers/mtd/ubi/Kconfig
-+++ b/drivers/mtd/ubi/Kconfig
-@@ -104,4 +104,16 @@ config MTD_UBI_BLOCK
-
- If in doubt, say "N".
-
-+config MTD_UBI_NVMEM
-+ tristate "UBI virtual NVMEM"
-+ default n
-+ depends on NVMEM
-+ help
-+ This option enabled an additional driver exposing UBI volumes as NVMEM
-+ providers, intended for platforms where UBI is part of the firmware
-+ specification and used to store also e.g. MAC addresses or board-
-+ specific Wi-Fi calibration data.
-+
-+ If in doubt, say "N".
-+
- endif # MTD_UBI
---- a/drivers/mtd/ubi/Makefile
-+++ b/drivers/mtd/ubi/Makefile
-@@ -7,3 +7,4 @@ ubi-$(CONFIG_MTD_UBI_FASTMAP) += fastmap
- ubi-$(CONFIG_MTD_UBI_BLOCK) += block.o
-
- obj-$(CONFIG_MTD_UBI_GLUEBI) += gluebi.o
-+obj-$(CONFIG_MTD_UBI_NVMEM) += nvmem.o
---- /dev/null
-+++ b/drivers/mtd/ubi/nvmem.c
-@@ -0,0 +1,188 @@
-+// SPDX-License-Identifier: GPL-2.0-or-later
-+/*
-+ */
-+
-+/* UBI NVMEM provider */
-+#include "ubi.h"
-+#include <linux/nvmem-provider.h>
-+#include <asm/div64.h>
-+
-+/* List of all NVMEM devices */
-+static LIST_HEAD(nvmem_devices);
-+static DEFINE_MUTEX(devices_mutex);
-+
-+struct ubi_nvmem {
-+ struct nvmem_device *nvmem;
-+ int ubi_num;
-+ int vol_id;
-+ int usable_leb_size;
-+ struct list_head list;
-+};
-+
-+static int ubi_nvmem_reg_read(void *priv, unsigned int from,
-+ void *val, size_t bytes)
-+{
-+ int err = 0, lnum = from, offs, bytes_left = bytes, to_read;
-+ struct ubi_nvmem *unv = priv;
-+ struct ubi_volume_desc *desc;
-+
-+ desc = ubi_open_volume(unv->ubi_num, unv->vol_id, UBI_READONLY);
-+ if (IS_ERR(desc))
-+ return PTR_ERR(desc);
-+
-+ offs = do_div(lnum, unv->usable_leb_size);
-+ while (bytes_left) {
-+ to_read = unv->usable_leb_size - offs;
-+
-+ if (to_read > bytes_left)
-+ to_read = bytes_left;
-+
-+ err = ubi_read(desc, lnum, val, offs, to_read);
-+ if (err)
-+ break;
-+
-+ lnum += 1;
-+ offs = 0;
-+ bytes_left -= to_read;
-+ val += to_read;
-+ }
-+ ubi_close_volume(desc);
-+
-+ if (err)
-+ return err;
-+
-+ return bytes_left == 0 ? 0 : -EIO;
-+}
-+
-+static int ubi_nvmem_add(struct ubi_volume_info *vi)
-+{
-+ struct device_node *np = dev_of_node(vi->dev);
-+ struct nvmem_config config = {};
-+ struct ubi_nvmem *unv;
-+ int ret;
-+
-+ if (!np)
-+ return 0;
-+
-+ if (!of_get_child_by_name(np, "nvmem-layout"))
-+ return 0;
-+
-+ if (WARN_ON_ONCE(vi->usable_leb_size <= 0) ||
-+ WARN_ON_ONCE(vi->size <= 0))
-+ return -EINVAL;
-+
-+ unv = kzalloc(sizeof(struct ubi_nvmem), GFP_KERNEL);
-+ if (!unv)
-+ return -ENOMEM;
-+
-+ config.id = NVMEM_DEVID_NONE;
-+ config.dev = vi->dev;
-+ config.name = dev_name(vi->dev);
-+ config.owner = THIS_MODULE;
-+ config.priv = unv;
-+ config.reg_read = ubi_nvmem_reg_read;
-+ config.size = vi->usable_leb_size * vi->size;
-+ config.word_size = 1;
-+ config.stride = 1;
-+ config.read_only = true;
-+ config.root_only = true;
-+ config.ignore_wp = true;
-+ config.of_node = np;
-+
-+ unv->ubi_num = vi->ubi_num;
-+ unv->vol_id = vi->vol_id;
-+ unv->usable_leb_size = vi->usable_leb_size;
-+ unv->nvmem = nvmem_register(&config);
-+ if (IS_ERR(unv->nvmem)) {
-+ ret = dev_err_probe(vi->dev, PTR_ERR(unv->nvmem),
-+ "Failed to register NVMEM device\n");
-+ kfree(unv);
-+ return ret;
-+ }
-+
-+ mutex_lock(&devices_mutex);
-+ list_add_tail(&unv->list, &nvmem_devices);
-+ mutex_unlock(&devices_mutex);
-+
-+ return 0;
-+}
-+
-+static void ubi_nvmem_remove(struct ubi_volume_info *vi)
-+{
-+ struct ubi_nvmem *unv_c, *unv = NULL;
-+
-+ mutex_lock(&devices_mutex);
-+ list_for_each_entry(unv_c, &nvmem_devices, list)
-+ if (unv_c->ubi_num == vi->ubi_num && unv_c->vol_id == vi->vol_id) {
-+ unv = unv_c;
-+ break;
-+ }
-+
-+ if (!unv) {
-+ mutex_unlock(&devices_mutex);
-+ return;
-+ }
-+
-+ list_del(&unv->list);
-+ mutex_unlock(&devices_mutex);
-+ nvmem_unregister(unv->nvmem);
-+ kfree(unv);
-+}
-+
-+/**
-+ * nvmem_notify - UBI notification handler.
-+ * @nb: registered notifier block
-+ * @l: notification type
-+ * @ns_ptr: pointer to the &struct ubi_notification object
-+ */
-+static int nvmem_notify(struct notifier_block *nb, unsigned long l,
-+ void *ns_ptr)
-+{
-+ struct ubi_notification *nt = ns_ptr;
-+
-+ switch (l) {
-+ case UBI_VOLUME_RESIZED:
-+ ubi_nvmem_remove(&nt->vi);
-+ fallthrough;
-+ case UBI_VOLUME_ADDED:
-+ ubi_nvmem_add(&nt->vi);
-+ break;
-+ case UBI_VOLUME_SHUTDOWN:
-+ ubi_nvmem_remove(&nt->vi);
-+ break;
-+ default:
-+ break;
-+ }
-+ return NOTIFY_OK;
-+}
-+
-+static struct notifier_block nvmem_notifier = {
-+ .notifier_call = nvmem_notify,
-+};
-+
-+static int __init ubi_nvmem_init(void)
-+{
-+ return ubi_register_volume_notifier(&nvmem_notifier, 0);
-+}
-+
-+static void __exit ubi_nvmem_exit(void)
-+{
-+ struct ubi_nvmem *unv, *tmp;
-+
-+ mutex_lock(&devices_mutex);
-+ list_for_each_entry_safe(unv, tmp, &nvmem_devices, list) {
-+ nvmem_unregister(unv->nvmem);
-+ list_del(&unv->list);
-+ kfree(unv);
-+ }
-+ mutex_unlock(&devices_mutex);
-+
-+ ubi_unregister_volume_notifier(&nvmem_notifier);
-+}
-+
-+module_init(ubi_nvmem_init);
-+module_exit(ubi_nvmem_exit);
-+MODULE_DESCRIPTION("NVMEM layer over UBI volumes");
-+MODULE_AUTHOR("Daniel Golle");
-+MODULE_LICENSE("GPL");
+++ /dev/null
-From 04231c61dcd51db0f12061e49bb761b197109f2f Mon Sep 17 00:00:00 2001
-Date: Thu, 29 Feb 2024 03:47:24 +0000
-Subject: [PATCH 8/8] mtd: ubi: fix NVMEM over UBI volumes on 32-bit systems
-
-A compiler warning related to sizeof(int) != 8 when calling do_div()
-is triggered when building on 32-bit platforms.
-Address this by using integer types having a well-defined size.
-
-Fixes: 3ce485803da1 ("mtd: ubi: provide NVMEM layer over UBI volumes")
----
- drivers/mtd/ubi/nvmem.c | 5 ++++-
- 1 file changed, 4 insertions(+), 1 deletion(-)
-
---- a/drivers/mtd/ubi/nvmem.c
-+++ b/drivers/mtd/ubi/nvmem.c
-@@ -23,9 +23,12 @@ struct ubi_nvmem {
- static int ubi_nvmem_reg_read(void *priv, unsigned int from,
- void *val, size_t bytes)
- {
-- int err = 0, lnum = from, offs, bytes_left = bytes, to_read;
-+ size_t to_read, bytes_left = bytes;
- struct ubi_nvmem *unv = priv;
- struct ubi_volume_desc *desc;
-+ uint32_t offs;
-+ uint64_t lnum = from;
-+ int err = 0;
-
- desc = ubi_open_volume(unv->ubi_num, unv->vol_id, UBI_READONLY);
- if (IS_ERR(desc))
+++ /dev/null
-From 03cb793b26834ddca170ba87057c8f883772dd45 Mon Sep 17 00:00:00 2001
-Date: Thu, 3 Oct 2024 00:11:41 +0200
-Subject: [PATCH 1/5] block: add support for defining read-only partitions
-
-Add support for defining read-only partitions and complete support for
-it in the cmdline partition parser as the additional "ro" after a
-partition is scanned but never actually applied.
-
----
- block/blk.h | 1 +
- block/partitions/cmdline.c | 3 +++
- block/partitions/core.c | 3 +++
- 3 files changed, 7 insertions(+)
-
---- a/block/blk.h
-+++ b/block/blk.h
-@@ -424,6 +424,7 @@ void blk_free_ext_minor(unsigned int min
- #define ADDPART_FLAG_NONE 0
- #define ADDPART_FLAG_RAID 1
- #define ADDPART_FLAG_WHOLEDISK 2
-+#define ADDPART_FLAG_READONLY 4
- int bdev_add_partition(struct gendisk *disk, int partno, sector_t start,
- sector_t length);
- int bdev_del_partition(struct gendisk *disk, int partno);
---- a/block/partitions/cmdline.c
-+++ b/block/partitions/cmdline.c
-@@ -237,6 +237,9 @@ static int add_part(int slot, struct cmd
- put_partition(state, slot, subpart->from >> 9,
- subpart->size >> 9);
-
-+ if (subpart->flags & PF_RDONLY)
-+ state->parts[slot].flags |= ADDPART_FLAG_READONLY;
-+
- info = &state->parts[slot].info;
-
- strscpy(info->volname, subpart->name, sizeof(info->volname));
---- a/block/partitions/core.c
-+++ b/block/partitions/core.c
-@@ -392,6 +392,9 @@ static struct block_device *add_partitio
- goto out_del;
- }
-
-+ if (flags & ADDPART_FLAG_READONLY)
-+ bdev->bd_read_only = true;
-+
- /* everything is up and running, commence */
- err = xa_insert(&disk->part_tbl, partno, bdev, GFP_KERNEL);
- if (err)
+++ /dev/null
-From e5f587242b6072ffab4f4a084a459a59f3035873 Mon Sep 17 00:00:00 2001
-Date: Thu, 3 Oct 2024 00:11:43 +0200
-Subject: [PATCH 3/5] block: introduce add_disk_fwnode()
-
-Introduce add_disk_fwnode() as a replacement of device_add_disk() that
-permits to pass and attach a fwnode to disk dev.
-
-This variant can be useful for eMMC that might have the partition table
-for the disk defined in DT. A parser can later make use of the attached
-fwnode to parse the related table and init the hardcoded partition for
-the disk.
-
-device_add_disk() is converted to a simple wrapper of add_disk_fwnode()
-with the fwnode entry set as NULL.
-
----
- block/genhd.c | 28 ++++++++++++++++++++++++----
- include/linux/blkdev.h | 3 +++
- 2 files changed, 27 insertions(+), 4 deletions(-)
-
---- a/block/genhd.c
-+++ b/block/genhd.c
-@@ -383,16 +383,18 @@ int disk_scan_partitions(struct gendisk
- }
-
- /**
-- * device_add_disk - add disk information to kernel list
-+ * add_disk_fwnode - add disk information to kernel list with fwnode
- * @parent: parent device for the disk
- * @disk: per-device partitioning information
- * @groups: Additional per-device sysfs groups
-+ * @fwnode: attached disk fwnode
- *
- * This function registers the partitioning information in @disk
-- * with the kernel.
-+ * with the kernel. Also attach a fwnode to the disk device.
- */
--int __must_check device_add_disk(struct device *parent, struct gendisk *disk,
-- const struct attribute_group **groups)
-+int __must_check add_disk_fwnode(struct device *parent, struct gendisk *disk,
-+ const struct attribute_group **groups,
-+ struct fwnode_handle *fwnode)
-
- {
- struct device *ddev = disk_to_dev(disk);
-@@ -451,6 +453,8 @@ int __must_check device_add_disk(struct
- ddev->parent = parent;
- ddev->groups = groups;
- dev_set_name(ddev, "%s", disk->disk_name);
-+ if (fwnode)
-+ device_set_node(ddev, fwnode);
- if (!(disk->flags & GENHD_FL_HIDDEN))
- ddev->devt = MKDEV(disk->major, disk->first_minor);
- ret = device_add(ddev);
-@@ -552,6 +556,22 @@ out_exit_elevator:
- elevator_exit(disk->queue);
- return ret;
- }
-+EXPORT_SYMBOL_GPL(add_disk_fwnode);
-+
-+/**
-+ * device_add_disk - add disk information to kernel list
-+ * @parent: parent device for the disk
-+ * @disk: per-device partitioning information
-+ * @groups: Additional per-device sysfs groups
-+ *
-+ * This function registers the partitioning information in @disk
-+ * with the kernel.
-+ */
-+int __must_check device_add_disk(struct device *parent, struct gendisk *disk,
-+ const struct attribute_group **groups)
-+{
-+ return add_disk_fwnode(parent, disk, groups, NULL);
-+}
- EXPORT_SYMBOL(device_add_disk);
-
- static void blk_report_disk_dead(struct gendisk *disk, bool surprise)
---- a/include/linux/blkdev.h
-+++ b/include/linux/blkdev.h
-@@ -741,6 +741,9 @@ static inline unsigned int blk_queue_dep
- #define for_each_bio(_bio) \
- for (; _bio; _bio = _bio->bi_next)
-
-+int __must_check add_disk_fwnode(struct device *parent, struct gendisk *disk,
-+ const struct attribute_group **groups,
-+ struct fwnode_handle *fwnode);
- int __must_check device_add_disk(struct device *parent, struct gendisk *disk,
- const struct attribute_group **groups);
- static inline int __must_check add_disk(struct gendisk *disk)
+++ /dev/null
-From 45ff6c340ddfc2dade74d5b7a8962c778ab7042c Mon Sep 17 00:00:00 2001
-Date: Thu, 3 Oct 2024 00:11:44 +0200
-Subject: [PATCH 4/5] mmc: block: attach partitions fwnode if found in mmc-card
-
-Attach partitions fwnode if found in mmc-card and register disk with it.
-
-This permits block partition to reference the node and register a
-partition table defined in DT for the special case for embedded device
-that doesn't have a partition table flashed but have an hardcoded
-partition table passed from the system.
-
-JEDEC BOOT partition boot0/boot1 are supported but in DT we refer with
-the JEDEC name of boot1 and boot2 to better adhere to documentation.
-
-Also JEDEC GP partition gp0/1/2/3 are supported but in DT we refer with
-the JEDEC name of gp1/2/3/4 to better adhere to documentration.
-
----
- drivers/mmc/core/block.c | 55 +++++++++++++++++++++++++++++++++++++++-
- 1 file changed, 54 insertions(+), 1 deletion(-)
-
---- a/drivers/mmc/core/block.c
-+++ b/drivers/mmc/core/block.c
-@@ -2455,6 +2455,56 @@ static inline int mmc_blk_readonly(struc
- !(card->csd.cmdclass & CCC_BLOCK_WRITE);
- }
-
-+/*
-+ * Search for a declared partitions node for the disk in mmc-card related node.
-+ *
-+ * This is to permit support for partition table defined in DT in special case
-+ * where a partition table is not written in the disk and is expected to be
-+ * passed from the running system.
-+ *
-+ * For the user disk, "partitions" node is searched.
-+ * For the special HW disk, "partitions-" node with the appended name is used
-+ * following this conversion table (to adhere to JEDEC naming)
-+ * - boot0 -> partitions-boot1
-+ * - boot1 -> partitions-boot2
-+ * - gp0 -> partitions-gp1
-+ * - gp1 -> partitions-gp2
-+ * - gp2 -> partitions-gp3
-+ * - gp3 -> partitions-gp4
-+ */
-+static struct fwnode_handle *mmc_blk_get_partitions_node(struct device *mmc_dev,
-+ const char *subname)
-+{
-+ const char *node_name = "partitions";
-+
-+ if (subname) {
-+ mmc_dev = mmc_dev->parent;
-+
-+ /*
-+ * Check if we are allocating a BOOT disk boot0/1 disk.
-+ * In DT we use the JEDEC naming boot1/2.
-+ */
-+ if (!strcmp(subname, "boot0"))
-+ node_name = "partitions-boot1";
-+ if (!strcmp(subname, "boot1"))
-+ node_name = "partitions-boot2";
-+ /*
-+ * Check if we are allocating a GP disk gp0/1/2/3 disk.
-+ * In DT we use the JEDEC naming gp1/2/3/4.
-+ */
-+ if (!strcmp(subname, "gp0"))
-+ node_name = "partitions-gp1";
-+ if (!strcmp(subname, "gp1"))
-+ node_name = "partitions-gp2";
-+ if (!strcmp(subname, "gp2"))
-+ node_name = "partitions-gp3";
-+ if (!strcmp(subname, "gp3"))
-+ node_name = "partitions-gp4";
-+ }
-+
-+ return device_get_named_child_node(mmc_dev, node_name);
-+}
-+
- static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,
- struct device *parent,
- sector_t size,
-@@ -2463,6 +2513,7 @@ static struct mmc_blk_data *mmc_blk_allo
- int area_type,
- unsigned int part_type)
- {
-+ struct fwnode_handle *disk_fwnode;
- struct mmc_blk_data *md;
- int devidx, ret;
- char cap_str[10];
-@@ -2568,7 +2619,9 @@ static struct mmc_blk_data *mmc_blk_allo
- /* used in ->open, must be set before add_disk: */
- if (area_type == MMC_BLK_DATA_AREA_MAIN)
- dev_set_drvdata(&card->dev, md);
-- ret = device_add_disk(md->parent, md->disk, mmc_disk_attr_groups);
-+ disk_fwnode = mmc_blk_get_partitions_node(parent, subname);
-+ ret = add_disk_fwnode(md->parent, md->disk, mmc_disk_attr_groups,
-+ disk_fwnode);
- if (ret)
- goto err_put_disk;
- return md;
+++ /dev/null
-From 884555b557e5e6d41c866e2cd8d7b32f50ec974b Mon Sep 17 00:00:00 2001
-Date: Thu, 3 Oct 2024 00:11:45 +0200
-Subject: [PATCH 5/5] block: add support for partition table defined in OF
-
-Add support for partition table defined in Device Tree. Similar to how
-it's done with MTD, add support for defining a fixed partition table in
-device tree.
-
-A common scenario for this is fixed block (eMMC) embedded devices that
-have no MBR or GPT partition table to save storage space. Bootloader
-access the block device with absolute address of data.
-
-This is to complete the functionality with an equivalent implementation
-with providing partition table with bootargs, for case where the booargs
-can't be modified and tweaking the Device Tree is the only solution to
-have an usabe partition table.
-
-The implementation follow the fixed-partitions parser used on MTD
-devices where a "partitions" node is expected to be declared with
-"fixed-partitions" compatible in the OF node of the disk device
-(mmc-card for eMMC for example) and each child node declare a label
-and a reg with offset and size. If label is not declared, the node name
-is used as fallback. Eventually is also possible to declare the read-only
-property to flag the partition as read-only.
-
----
- block/partitions/Kconfig | 9 ++++
- block/partitions/Makefile | 1 +
- block/partitions/check.h | 1 +
- block/partitions/core.c | 3 ++
- block/partitions/of.c | 110 ++++++++++++++++++++++++++++++++++++++
- 5 files changed, 124 insertions(+)
- create mode 100644 block/partitions/of.c
-
---- a/block/partitions/Kconfig
-+++ b/block/partitions/Kconfig
-@@ -270,4 +270,13 @@ config CMDLINE_PARTITION
- Say Y here if you want to read the partition table from bootargs.
- The format for the command line is just like mtdparts.
-
-+config OF_PARTITION
-+ bool "Device Tree partition support" if PARTITION_ADVANCED
-+ depends on OF
-+ help
-+ Say Y here if you want to enable support for partition table
-+ defined in Device Tree. (mainly for eMMC)
-+ The format for the device tree node is just like MTD fixed-partition
-+ schema.
-+
- endmenu
---- a/block/partitions/Makefile
-+++ b/block/partitions/Makefile
-@@ -12,6 +12,7 @@ obj-$(CONFIG_CMDLINE_PARTITION) += cmdli
- obj-$(CONFIG_MAC_PARTITION) += mac.o
- obj-$(CONFIG_LDM_PARTITION) += ldm.o
- obj-$(CONFIG_MSDOS_PARTITION) += msdos.o
-+obj-$(CONFIG_OF_PARTITION) += of.o
- obj-$(CONFIG_OSF_PARTITION) += osf.o
- obj-$(CONFIG_SGI_PARTITION) += sgi.o
- obj-$(CONFIG_SUN_PARTITION) += sun.o
---- a/block/partitions/check.h
-+++ b/block/partitions/check.h
-@@ -62,6 +62,7 @@ int karma_partition(struct parsed_partit
- int ldm_partition(struct parsed_partitions *state);
- int mac_partition(struct parsed_partitions *state);
- int msdos_partition(struct parsed_partitions *state);
-+int of_partition(struct parsed_partitions *state);
- int osf_partition(struct parsed_partitions *state);
- int sgi_partition(struct parsed_partitions *state);
- int sun_partition(struct parsed_partitions *state);
---- a/block/partitions/core.c
-+++ b/block/partitions/core.c
-@@ -43,6 +43,9 @@ static int (*const check_part[])(struct
- #ifdef CONFIG_CMDLINE_PARTITION
- cmdline_partition,
- #endif
-+#ifdef CONFIG_OF_PARTITION
-+ of_partition, /* cmdline have priority to OF */
-+#endif
- #ifdef CONFIG_EFI_PARTITION
- efi_partition, /* this must come before msdos */
- #endif
---- /dev/null
-+++ b/block/partitions/of.c
-@@ -0,0 +1,110 @@
-+// SPDX-License-Identifier: GPL-2.0
-+
-+#include <linux/blkdev.h>
-+#include <linux/major.h>
-+#include <linux/of.h>
-+#include <linux/string.h>
-+#include "check.h"
-+
-+static int validate_of_partition(struct device_node *np, int slot)
-+{
-+ u64 offset, size;
-+ int len;
-+
-+ const __be32 *reg = of_get_property(np, "reg", &len);
-+ int a_cells = of_n_addr_cells(np);
-+ int s_cells = of_n_size_cells(np);
-+
-+ /* Make sure reg len match the expected addr and size cells */
-+ if (len / sizeof(*reg) != a_cells + s_cells)
-+ return -EINVAL;
-+
-+ /* Validate offset conversion from bytes to sectors */
-+ offset = of_read_number(reg, a_cells);
-+ if (offset % SECTOR_SIZE)
-+ return -EINVAL;
-+
-+ /* Validate size conversion from bytes to sectors */
-+ size = of_read_number(reg + a_cells, s_cells);
-+ if (!size || size % SECTOR_SIZE)
-+ return -EINVAL;
-+
-+ return 0;
-+}
-+
-+static void add_of_partition(struct parsed_partitions *state, int slot,
-+ struct device_node *np)
-+{
-+ struct partition_meta_info *info;
-+ char tmp[sizeof(info->volname) + 4];
-+ const char *partname;
-+ int len;
-+
-+ const __be32 *reg = of_get_property(np, "reg", &len);
-+ int a_cells = of_n_addr_cells(np);
-+ int s_cells = of_n_size_cells(np);
-+
-+ /* Convert bytes to sector size */
-+ u64 offset = of_read_number(reg, a_cells) / SECTOR_SIZE;
-+ u64 size = of_read_number(reg + a_cells, s_cells) / SECTOR_SIZE;
-+
-+ put_partition(state, slot, offset, size);
-+
-+ if (of_property_read_bool(np, "read-only"))
-+ state->parts[slot].flags |= ADDPART_FLAG_READONLY;
-+
-+ /*
-+ * Follow MTD label logic, search for label property,
-+ * fallback to node name if not found.
-+ */
-+ info = &state->parts[slot].info;
-+ partname = of_get_property(np, "label", &len);
-+ if (!partname)
-+ partname = of_get_property(np, "name", &len);
-+ strscpy(info->volname, partname, sizeof(info->volname));
-+
-+ snprintf(tmp, sizeof(tmp), "(%s)", info->volname);
-+ strlcat(state->pp_buf, tmp, PAGE_SIZE);
-+}
-+
-+int of_partition(struct parsed_partitions *state)
-+{
-+ struct device *ddev = disk_to_dev(state->disk);
-+ struct device_node *np;
-+ int slot;
-+
-+ struct device_node *partitions_np = of_node_get(ddev->of_node);
-+
-+ if (!partitions_np ||
-+ !of_device_is_compatible(partitions_np, "fixed-partitions"))
-+ return 0;
-+
-+ slot = 1;
-+ /* Validate parition offset and size */
-+ for_each_child_of_node(partitions_np, np) {
-+ if (validate_of_partition(np, slot)) {
-+ of_node_put(np);
-+ of_node_put(partitions_np);
-+
-+ return -1;
-+ }
-+
-+ slot++;
-+ }
-+
-+ slot = 1;
-+ for_each_child_of_node(partitions_np, np) {
-+ if (slot >= state->limit) {
-+ of_node_put(np);
-+ break;
-+ }
-+
-+ add_of_partition(state, slot, np);
-+
-+ slot++;
-+ }
-+
-+ strlcat(state->pp_buf, "\n", PAGE_SIZE);
-+
-+ return 1;
-+}
+++ /dev/null
-From 49c8e854869d673df8452f24dfa8989cd0f615a8 Mon Sep 17 00:00:00 2001
-Date: Mon, 2 Oct 2023 17:04:58 +0300
-Subject: [PATCH] mtd: spinand: add support for FORESEE F35SQA002G
-
-Add support for FORESEE F35SQA002G SPI NAND.
-Datasheet:
- https://www.longsys.com/uploads/LM-00006FORESEEF35SQA002GDatasheet_1650183701.pdf
-
----
- drivers/mtd/nand/spi/Makefile | 2 +-
- drivers/mtd/nand/spi/core.c | 1 +
- drivers/mtd/nand/spi/foresee.c | 95 ++++++++++++++++++++++++++++++++++
- include/linux/mtd/spinand.h | 1 +
- 4 files changed, 98 insertions(+), 1 deletion(-)
- create mode 100644 drivers/mtd/nand/spi/foresee.c
-
---- a/drivers/mtd/nand/spi/Makefile
-+++ b/drivers/mtd/nand/spi/Makefile
-@@ -1,4 +1,4 @@
- # SPDX-License-Identifier: GPL-2.0
--spinand-objs := core.o alliancememory.o ato.o esmt.o gigadevice.o macronix.o
-+spinand-objs := core.o alliancememory.o ato.o esmt.o foresee.o gigadevice.o macronix.o
- spinand-objs += micron.o paragon.o toshiba.o winbond.o xtx.o
- obj-$(CONFIG_MTD_SPI_NAND) += spinand.o
---- a/drivers/mtd/nand/spi/core.c
-+++ b/drivers/mtd/nand/spi/core.c
-@@ -943,6 +943,7 @@ static const struct spinand_manufacturer
- &alliancememory_spinand_manufacturer,
- &ato_spinand_manufacturer,
- &esmt_c8_spinand_manufacturer,
-+ &foresee_spinand_manufacturer,
- &gigadevice_spinand_manufacturer,
- ¯onix_spinand_manufacturer,
- µn_spinand_manufacturer,
---- /dev/null
-+++ b/drivers/mtd/nand/spi/foresee.c
-@@ -0,0 +1,95 @@
-+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
-+/*
-+ * Copyright (c) 2023, SberDevices. All Rights Reserved.
-+ *
-+ */
-+
-+#include <linux/device.h>
-+#include <linux/kernel.h>
-+#include <linux/mtd/spinand.h>
-+
-+#define SPINAND_MFR_FORESEE 0xCD
-+
-+static SPINAND_OP_VARIANTS(read_cache_variants,
-+ SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
-+ SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
-+ SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
-+ SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
-+
-+static SPINAND_OP_VARIANTS(write_cache_variants,
-+ SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
-+ SPINAND_PROG_LOAD(true, 0, NULL, 0));
-+
-+static SPINAND_OP_VARIANTS(update_cache_variants,
-+ SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
-+ SPINAND_PROG_LOAD(false, 0, NULL, 0));
-+
-+static int f35sqa002g_ooblayout_ecc(struct mtd_info *mtd, int section,
-+ struct mtd_oob_region *region)
-+{
-+ return -ERANGE;
-+}
-+
-+static int f35sqa002g_ooblayout_free(struct mtd_info *mtd, int section,
-+ struct mtd_oob_region *region)
-+{
-+ if (section)
-+ return -ERANGE;
-+
-+ /* Reserve 2 bytes for the BBM. */
-+ region->offset = 2;
-+ region->length = 62;
-+
-+ return 0;
-+}
-+
-+static const struct mtd_ooblayout_ops f35sqa002g_ooblayout = {
-+ .ecc = f35sqa002g_ooblayout_ecc,
-+ .free = f35sqa002g_ooblayout_free,
-+};
-+
-+static int f35sqa002g_ecc_get_status(struct spinand_device *spinand, u8 status)
-+{
-+ struct nand_device *nand = spinand_to_nand(spinand);
-+
-+ switch (status & STATUS_ECC_MASK) {
-+ case STATUS_ECC_NO_BITFLIPS:
-+ return 0;
-+
-+ case STATUS_ECC_HAS_BITFLIPS:
-+ return nanddev_get_ecc_conf(nand)->strength;
-+
-+ default:
-+ break;
-+ }
-+
-+ /* More than 1-bit error was detected in one or more sectors and
-+ * cannot be corrected.
-+ */
-+ return -EBADMSG;
-+}
-+
-+static const struct spinand_info foresee_spinand_table[] = {
-+ SPINAND_INFO("F35SQA002G",
-+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x72, 0x72),
-+ NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 1, 1, 1),
-+ NAND_ECCREQ(1, 512),
-+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
-+ &write_cache_variants,
-+ &update_cache_variants),
-+ SPINAND_HAS_QE_BIT,
-+ SPINAND_ECCINFO(&f35sqa002g_ooblayout,
-+ f35sqa002g_ecc_get_status)),
-+};
-+
-+static const struct spinand_manufacturer_ops foresee_spinand_manuf_ops = {
-+};
-+
-+const struct spinand_manufacturer foresee_spinand_manufacturer = {
-+ .id = SPINAND_MFR_FORESEE,
-+ .name = "FORESEE",
-+ .chips = foresee_spinand_table,
-+ .nchips = ARRAY_SIZE(foresee_spinand_table),
-+ .ops = &foresee_spinand_manuf_ops,
-+};
---- a/include/linux/mtd/spinand.h
-+++ b/include/linux/mtd/spinand.h
-@@ -263,6 +263,7 @@ struct spinand_manufacturer {
- extern const struct spinand_manufacturer alliancememory_spinand_manufacturer;
- extern const struct spinand_manufacturer ato_spinand_manufacturer;
- extern const struct spinand_manufacturer esmt_c8_spinand_manufacturer;
-+extern const struct spinand_manufacturer foresee_spinand_manufacturer;
- extern const struct spinand_manufacturer gigadevice_spinand_manufacturer;
- extern const struct spinand_manufacturer macronix_spinand_manufacturer;
- extern const struct spinand_manufacturer micron_spinand_manufacturer;
+++ /dev/null
-From ae461cde5c559675fc4c0ba351c7c31ace705f56 Mon Sep 17 00:00:00 2001
-Date: Sun, 10 Nov 2024 22:50:47 +0200
-Subject: [PATCH] mtd: spinand: add support for FORESEE F35SQA001G
-
-Add support for FORESEE F35SQA001G SPI NAND.
-
-Similar to F35SQA002G, but differs in capacity.
-Datasheet:
- - https://cdn.ozdisan.com/ETicaret_Dosya/704795_871495.pdf
-
-Tested on Xiaomi AX3000T flashed with OpenWRT.
-
----
- drivers/mtd/nand/spi/foresee.c | 10 ++++++++++
- 1 file changed, 10 insertions(+)
-
---- a/drivers/mtd/nand/spi/foresee.c
-+++ b/drivers/mtd/nand/spi/foresee.c
-@@ -81,6 +81,16 @@ static const struct spinand_info foresee
- SPINAND_HAS_QE_BIT,
- SPINAND_ECCINFO(&f35sqa002g_ooblayout,
- f35sqa002g_ecc_get_status)),
-+ SPINAND_INFO("F35SQA001G",
-+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x71, 0x71),
-+ NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
-+ NAND_ECCREQ(1, 512),
-+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
-+ &write_cache_variants,
-+ &update_cache_variants),
-+ SPINAND_HAS_QE_BIT,
-+ SPINAND_ECCINFO(&f35sqa002g_ooblayout,
-+ f35sqa002g_ecc_get_status)),
- };
-
- static const struct spinand_manufacturer_ops foresee_spinand_manuf_ops = {
+++ /dev/null
-From 8c52932da5e6756fa66f52f0720da283fba13aa6 Mon Sep 17 00:00:00 2001
-Date: Wed, 20 Nov 2024 14:45:00 +0530
-Subject: [PATCH 1/4] mtd: rawnand: qcom: cleanup qcom_nandc driver
-
-Perform a global cleanup of the Qualcomm NAND
-controller driver with the following improvements:
-
-- Remove register value indirection API
-
-- Remove set_reg() API
-
-- Convert read_loc_first & read_loc_last macro to functions
-
-- Rename multiple variables
-
----
- drivers/mtd/nand/raw/qcom_nandc.c | 516 ++++++++++++++----------------
- 1 file changed, 234 insertions(+), 282 deletions(-)
-
---- a/drivers/mtd/nand/raw/qcom_nandc.c
-+++ b/drivers/mtd/nand/raw/qcom_nandc.c
-@@ -189,17 +189,6 @@
- #define ECC_BCH_4BIT BIT(2)
- #define ECC_BCH_8BIT BIT(3)
-
--#define nandc_set_read_loc_first(chip, reg, cw_offset, read_size, is_last_read_loc) \
--nandc_set_reg(chip, reg, \
-- ((cw_offset) << READ_LOCATION_OFFSET) | \
-- ((read_size) << READ_LOCATION_SIZE) | \
-- ((is_last_read_loc) << READ_LOCATION_LAST))
--
--#define nandc_set_read_loc_last(chip, reg, cw_offset, read_size, is_last_read_loc) \
--nandc_set_reg(chip, reg, \
-- ((cw_offset) << READ_LOCATION_OFFSET) | \
-- ((read_size) << READ_LOCATION_SIZE) | \
-- ((is_last_read_loc) << READ_LOCATION_LAST))
- /*
- * Returns the actual register address for all NAND_DEV_ registers
- * (i.e. NAND_DEV_CMD0, NAND_DEV_CMD1, NAND_DEV_CMD2 and NAND_DEV_CMD_VLD)
-@@ -257,8 +246,6 @@ nandc_set_reg(chip, reg, \
- * @tx_sgl_start - start index in data sgl for tx.
- * @rx_sgl_pos - current index in data sgl for rx.
- * @rx_sgl_start - start index in data sgl for rx.
-- * @wait_second_completion - wait for second DMA desc completion before making
-- * the NAND transfer completion.
- */
- struct bam_transaction {
- struct bam_cmd_element *bam_ce;
-@@ -275,7 +262,6 @@ struct bam_transaction {
- u32 tx_sgl_start;
- u32 rx_sgl_pos;
- u32 rx_sgl_start;
-- bool wait_second_completion;
- };
-
- /*
-@@ -471,9 +457,9 @@ struct qcom_op {
- unsigned int data_instr_idx;
- unsigned int rdy_timeout_ms;
- unsigned int rdy_delay_ns;
-- u32 addr1_reg;
-- u32 addr2_reg;
-- u32 cmd_reg;
-+ __le32 addr1_reg;
-+ __le32 addr2_reg;
-+ __le32 cmd_reg;
- u8 flag;
- };
-
-@@ -549,17 +535,17 @@ struct qcom_nand_host {
- * among different NAND controllers.
- * @ecc_modes - ecc mode for NAND
- * @dev_cmd_reg_start - NAND_DEV_CMD_* registers starting offset
-- * @is_bam - whether NAND controller is using BAM
-- * @is_qpic - whether NAND CTRL is part of qpic IP
-- * @qpic_v2 - flag to indicate QPIC IP version 2
-+ * @supports_bam - whether NAND controller is using Bus Access Manager (BAM)
-+ * @nandc_part_of_qpic - whether NAND controller is part of qpic IP
-+ * @qpic_version2 - flag to indicate QPIC IP version 2
- * @use_codeword_fixup - whether NAND has different layout for boot partitions
- */
- struct qcom_nandc_props {
- u32 ecc_modes;
- u32 dev_cmd_reg_start;
-- bool is_bam;
-- bool is_qpic;
-- bool qpic_v2;
-+ bool supports_bam;
-+ bool nandc_part_of_qpic;
-+ bool qpic_version2;
- bool use_codeword_fixup;
- };
-
-@@ -613,19 +599,11 @@ static void clear_bam_transaction(struct
- {
- struct bam_transaction *bam_txn = nandc->bam_txn;
-
-- if (!nandc->props->is_bam)
-+ if (!nandc->props->supports_bam)
- return;
-
-- bam_txn->bam_ce_pos = 0;
-- bam_txn->bam_ce_start = 0;
-- bam_txn->cmd_sgl_pos = 0;
-- bam_txn->cmd_sgl_start = 0;
-- bam_txn->tx_sgl_pos = 0;
-- bam_txn->tx_sgl_start = 0;
-- bam_txn->rx_sgl_pos = 0;
-- bam_txn->rx_sgl_start = 0;
-+ memset(&bam_txn->bam_ce_pos, 0, sizeof(u32) * 8);
- bam_txn->last_data_desc = NULL;
-- bam_txn->wait_second_completion = false;
-
- sg_init_table(bam_txn->cmd_sgl, nandc->max_cwperpage *
- QPIC_PER_CW_CMD_SGL);
-@@ -640,46 +618,35 @@ static void qpic_bam_dma_done(void *data
- {
- struct bam_transaction *bam_txn = data;
-
-- /*
-- * In case of data transfer with NAND, 2 callbacks will be generated.
-- * One for command channel and another one for data channel.
-- * If current transaction has data descriptors
-- * (i.e. wait_second_completion is true), then set this to false
-- * and wait for second DMA descriptor completion.
-- */
-- if (bam_txn->wait_second_completion)
-- bam_txn->wait_second_completion = false;
-- else
-- complete(&bam_txn->txn_done);
-+ complete(&bam_txn->txn_done);
- }
-
--static inline struct qcom_nand_host *to_qcom_nand_host(struct nand_chip *chip)
-+static struct qcom_nand_host *to_qcom_nand_host(struct nand_chip *chip)
- {
- return container_of(chip, struct qcom_nand_host, chip);
- }
-
--static inline struct qcom_nand_controller *
-+static struct qcom_nand_controller *
- get_qcom_nand_controller(struct nand_chip *chip)
- {
- return container_of(chip->controller, struct qcom_nand_controller,
- controller);
- }
-
--static inline u32 nandc_read(struct qcom_nand_controller *nandc, int offset)
-+static u32 nandc_read(struct qcom_nand_controller *nandc, int offset)
- {
- return ioread32(nandc->base + offset);
- }
-
--static inline void nandc_write(struct qcom_nand_controller *nandc, int offset,
-- u32 val)
-+static void nandc_write(struct qcom_nand_controller *nandc, int offset,
-+ u32 val)
- {
- iowrite32(val, nandc->base + offset);
- }
-
--static inline void nandc_read_buffer_sync(struct qcom_nand_controller *nandc,
-- bool is_cpu)
-+static void nandc_dev_to_mem(struct qcom_nand_controller *nandc, bool is_cpu)
- {
-- if (!nandc->props->is_bam)
-+ if (!nandc->props->supports_bam)
- return;
-
- if (is_cpu)
-@@ -694,93 +661,90 @@ static inline void nandc_read_buffer_syn
- DMA_FROM_DEVICE);
- }
-
--static __le32 *offset_to_nandc_reg(struct nandc_regs *regs, int offset)
--{
-- switch (offset) {
-- case NAND_FLASH_CMD:
-- return ®s->cmd;
-- case NAND_ADDR0:
-- return ®s->addr0;
-- case NAND_ADDR1:
-- return ®s->addr1;
-- case NAND_FLASH_CHIP_SELECT:
-- return ®s->chip_sel;
-- case NAND_EXEC_CMD:
-- return ®s->exec;
-- case NAND_FLASH_STATUS:
-- return ®s->clrflashstatus;
-- case NAND_DEV0_CFG0:
-- return ®s->cfg0;
-- case NAND_DEV0_CFG1:
-- return ®s->cfg1;
-- case NAND_DEV0_ECC_CFG:
-- return ®s->ecc_bch_cfg;
-- case NAND_READ_STATUS:
-- return ®s->clrreadstatus;
-- case NAND_DEV_CMD1:
-- return ®s->cmd1;
-- case NAND_DEV_CMD1_RESTORE:
-- return ®s->orig_cmd1;
-- case NAND_DEV_CMD_VLD:
-- return ®s->vld;
-- case NAND_DEV_CMD_VLD_RESTORE:
-- return ®s->orig_vld;
-- case NAND_EBI2_ECC_BUF_CFG:
-- return ®s->ecc_buf_cfg;
-- case NAND_READ_LOCATION_0:
-- return ®s->read_location0;
-- case NAND_READ_LOCATION_1:
-- return ®s->read_location1;
-- case NAND_READ_LOCATION_2:
-- return ®s->read_location2;
-- case NAND_READ_LOCATION_3:
-- return ®s->read_location3;
-- case NAND_READ_LOCATION_LAST_CW_0:
-- return ®s->read_location_last0;
-- case NAND_READ_LOCATION_LAST_CW_1:
-- return ®s->read_location_last1;
-- case NAND_READ_LOCATION_LAST_CW_2:
-- return ®s->read_location_last2;
-- case NAND_READ_LOCATION_LAST_CW_3:
-- return ®s->read_location_last3;
-- default:
-- return NULL;
-- }
--}
--
--static void nandc_set_reg(struct nand_chip *chip, int offset,
-- u32 val)
--{
-- struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
-- struct nandc_regs *regs = nandc->regs;
-- __le32 *reg;
--
-- reg = offset_to_nandc_reg(regs, offset);
--
-- if (reg)
-- *reg = cpu_to_le32(val);
--}
--
--/* Helper to check the code word, whether it is last cw or not */
-+/* Helper to check whether this is the last CW or not */
- static bool qcom_nandc_is_last_cw(struct nand_ecc_ctrl *ecc, int cw)
- {
- return cw == (ecc->steps - 1);
- }
-
-+/**
-+ * nandc_set_read_loc_first() - to set read location first register
-+ * @chip: NAND Private Flash Chip Data
-+ * @reg_base: location register base
-+ * @cw_offset: code word offset
-+ * @read_size: code word read length
-+ * @is_last_read_loc: is this the last read location
-+ *
-+ * This function will set location register value
-+ */
-+static void nandc_set_read_loc_first(struct nand_chip *chip,
-+ int reg_base, u32 cw_offset,
-+ u32 read_size, u32 is_last_read_loc)
-+{
-+ struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
-+ __le32 locreg_val;
-+ u32 val = (((cw_offset) << READ_LOCATION_OFFSET) |
-+ ((read_size) << READ_LOCATION_SIZE) |
-+ ((is_last_read_loc) << READ_LOCATION_LAST));
-+
-+ locreg_val = cpu_to_le32(val);
-+
-+ if (reg_base == NAND_READ_LOCATION_0)
-+ nandc->regs->read_location0 = locreg_val;
-+ else if (reg_base == NAND_READ_LOCATION_1)
-+ nandc->regs->read_location1 = locreg_val;
-+ else if (reg_base == NAND_READ_LOCATION_2)
-+ nandc->regs->read_location2 = locreg_val;
-+ else if (reg_base == NAND_READ_LOCATION_3)
-+ nandc->regs->read_location3 = locreg_val;
-+}
-+
-+/**
-+ * nandc_set_read_loc_last - to set read location last register
-+ * @chip: NAND Private Flash Chip Data
-+ * @reg_base: location register base
-+ * @cw_offset: code word offset
-+ * @read_size: code word read length
-+ * @is_last_read_loc: is this the last read location
-+ *
-+ * This function will set location last register value
-+ */
-+static void nandc_set_read_loc_last(struct nand_chip *chip,
-+ int reg_base, u32 cw_offset,
-+ u32 read_size, u32 is_last_read_loc)
-+{
-+ struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
-+ __le32 locreg_val;
-+ u32 val = (((cw_offset) << READ_LOCATION_OFFSET) |
-+ ((read_size) << READ_LOCATION_SIZE) |
-+ ((is_last_read_loc) << READ_LOCATION_LAST));
-+
-+ locreg_val = cpu_to_le32(val);
-+
-+ if (reg_base == NAND_READ_LOCATION_LAST_CW_0)
-+ nandc->regs->read_location_last0 = locreg_val;
-+ else if (reg_base == NAND_READ_LOCATION_LAST_CW_1)
-+ nandc->regs->read_location_last1 = locreg_val;
-+ else if (reg_base == NAND_READ_LOCATION_LAST_CW_2)
-+ nandc->regs->read_location_last2 = locreg_val;
-+ else if (reg_base == NAND_READ_LOCATION_LAST_CW_3)
-+ nandc->regs->read_location_last3 = locreg_val;
-+}
-+
- /* helper to configure location register values */
- static void nandc_set_read_loc(struct nand_chip *chip, int cw, int reg,
-- int cw_offset, int read_size, int is_last_read_loc)
-+ u32 cw_offset, u32 read_size, u32 is_last_read_loc)
- {
- struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
- struct nand_ecc_ctrl *ecc = &chip->ecc;
- int reg_base = NAND_READ_LOCATION_0;
-
-- if (nandc->props->qpic_v2 && qcom_nandc_is_last_cw(ecc, cw))
-+ if (nandc->props->qpic_version2 && qcom_nandc_is_last_cw(ecc, cw))
- reg_base = NAND_READ_LOCATION_LAST_CW_0;
-
- reg_base += reg * 4;
-
-- if (nandc->props->qpic_v2 && qcom_nandc_is_last_cw(ecc, cw))
-+ if (nandc->props->qpic_version2 && qcom_nandc_is_last_cw(ecc, cw))
- return nandc_set_read_loc_last(chip, reg_base, cw_offset,
- read_size, is_last_read_loc);
- else
-@@ -792,12 +756,13 @@ static void nandc_set_read_loc(struct na
- static void set_address(struct qcom_nand_host *host, u16 column, int page)
- {
- struct nand_chip *chip = &host->chip;
-+ struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
-
- if (chip->options & NAND_BUSWIDTH_16)
- column >>= 1;
-
-- nandc_set_reg(chip, NAND_ADDR0, page << 16 | column);
-- nandc_set_reg(chip, NAND_ADDR1, page >> 16 & 0xff);
-+ nandc->regs->addr0 = cpu_to_le32(page << 16 | column);
-+ nandc->regs->addr1 = cpu_to_le32(page >> 16 & 0xff);
- }
-
- /*
-@@ -811,41 +776,43 @@ static void set_address(struct qcom_nand
- static void update_rw_regs(struct qcom_nand_host *host, int num_cw, bool read, int cw)
- {
- struct nand_chip *chip = &host->chip;
-- u32 cmd, cfg0, cfg1, ecc_bch_cfg;
-+ __le32 cmd, cfg0, cfg1, ecc_bch_cfg;
- struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
-
- if (read) {
- if (host->use_ecc)
-- cmd = OP_PAGE_READ_WITH_ECC | PAGE_ACC | LAST_PAGE;
-+ cmd = cpu_to_le32(OP_PAGE_READ_WITH_ECC | PAGE_ACC | LAST_PAGE);
- else
-- cmd = OP_PAGE_READ | PAGE_ACC | LAST_PAGE;
-+ cmd = cpu_to_le32(OP_PAGE_READ | PAGE_ACC | LAST_PAGE);
- } else {
-- cmd = OP_PROGRAM_PAGE | PAGE_ACC | LAST_PAGE;
-+ cmd = cpu_to_le32(OP_PROGRAM_PAGE | PAGE_ACC | LAST_PAGE);
- }
-
- if (host->use_ecc) {
-- cfg0 = (host->cfg0 & ~(7U << CW_PER_PAGE)) |
-- (num_cw - 1) << CW_PER_PAGE;
-+ cfg0 = cpu_to_le32((host->cfg0 & ~(7U << CW_PER_PAGE)) |
-+ (num_cw - 1) << CW_PER_PAGE);
-
-- cfg1 = host->cfg1;
-- ecc_bch_cfg = host->ecc_bch_cfg;
-+ cfg1 = cpu_to_le32(host->cfg1);
-+ ecc_bch_cfg = cpu_to_le32(host->ecc_bch_cfg);
- } else {
-- cfg0 = (host->cfg0_raw & ~(7U << CW_PER_PAGE)) |
-- (num_cw - 1) << CW_PER_PAGE;
-+ cfg0 = cpu_to_le32((host->cfg0_raw & ~(7U << CW_PER_PAGE)) |
-+ (num_cw - 1) << CW_PER_PAGE);
-
-- cfg1 = host->cfg1_raw;
-- ecc_bch_cfg = 1 << ECC_CFG_ECC_DISABLE;
-+ cfg1 = cpu_to_le32(host->cfg1_raw);
-+ ecc_bch_cfg = cpu_to_le32(1 << ECC_CFG_ECC_DISABLE);
- }
-
-- nandc_set_reg(chip, NAND_FLASH_CMD, cmd);
-- nandc_set_reg(chip, NAND_DEV0_CFG0, cfg0);
-- nandc_set_reg(chip, NAND_DEV0_CFG1, cfg1);
-- nandc_set_reg(chip, NAND_DEV0_ECC_CFG, ecc_bch_cfg);
-- if (!nandc->props->qpic_v2)
-- nandc_set_reg(chip, NAND_EBI2_ECC_BUF_CFG, host->ecc_buf_cfg);
-- nandc_set_reg(chip, NAND_FLASH_STATUS, host->clrflashstatus);
-- nandc_set_reg(chip, NAND_READ_STATUS, host->clrreadstatus);
-- nandc_set_reg(chip, NAND_EXEC_CMD, 1);
-+ nandc->regs->cmd = cmd;
-+ nandc->regs->cfg0 = cfg0;
-+ nandc->regs->cfg1 = cfg1;
-+ nandc->regs->ecc_bch_cfg = ecc_bch_cfg;
-+
-+ if (!nandc->props->qpic_version2)
-+ nandc->regs->ecc_buf_cfg = cpu_to_le32(host->ecc_buf_cfg);
-+
-+ nandc->regs->clrflashstatus = cpu_to_le32(host->clrflashstatus);
-+ nandc->regs->clrreadstatus = cpu_to_le32(host->clrreadstatus);
-+ nandc->regs->exec = cpu_to_le32(1);
-
- if (read)
- nandc_set_read_loc(chip, cw, 0, 0, host->use_ecc ?
-@@ -1121,7 +1088,7 @@ static int read_reg_dma(struct qcom_nand
- if (first == NAND_DEV_CMD_VLD || first == NAND_DEV_CMD1)
- first = dev_cmd_reg_addr(nandc, first);
-
-- if (nandc->props->is_bam)
-+ if (nandc->props->supports_bam)
- return prep_bam_dma_desc_cmd(nandc, true, first, vaddr,
- num_regs, flags);
-
-@@ -1136,25 +1103,16 @@ static int read_reg_dma(struct qcom_nand
- * write_reg_dma: prepares a descriptor to write a given number of
- * contiguous registers
- *
-+ * @vaddr: contiguous memory from where register value will
-+ * be written
- * @first: offset of the first register in the contiguous block
- * @num_regs: number of registers to write
- * @flags: flags to control DMA descriptor preparation
- */
--static int write_reg_dma(struct qcom_nand_controller *nandc, int first,
-- int num_regs, unsigned int flags)
-+static int write_reg_dma(struct qcom_nand_controller *nandc, __le32 *vaddr,
-+ int first, int num_regs, unsigned int flags)
- {
- bool flow_control = false;
-- struct nandc_regs *regs = nandc->regs;
-- void *vaddr;
--
-- vaddr = offset_to_nandc_reg(regs, first);
--
-- if (first == NAND_ERASED_CW_DETECT_CFG) {
-- if (flags & NAND_ERASED_CW_SET)
-- vaddr = ®s->erased_cw_detect_cfg_set;
-- else
-- vaddr = ®s->erased_cw_detect_cfg_clr;
-- }
-
- if (first == NAND_EXEC_CMD)
- flags |= NAND_BAM_NWD;
-@@ -1165,7 +1123,7 @@ static int write_reg_dma(struct qcom_nan
- if (first == NAND_DEV_CMD_VLD_RESTORE || first == NAND_DEV_CMD_VLD)
- first = dev_cmd_reg_addr(nandc, NAND_DEV_CMD_VLD);
-
-- if (nandc->props->is_bam)
-+ if (nandc->props->supports_bam)
- return prep_bam_dma_desc_cmd(nandc, false, first, vaddr,
- num_regs, flags);
-
-@@ -1188,7 +1146,7 @@ static int write_reg_dma(struct qcom_nan
- static int read_data_dma(struct qcom_nand_controller *nandc, int reg_off,
- const u8 *vaddr, int size, unsigned int flags)
- {
-- if (nandc->props->is_bam)
-+ if (nandc->props->supports_bam)
- return prep_bam_dma_desc_data(nandc, true, vaddr, size, flags);
-
- return prep_adm_dma_desc(nandc, true, reg_off, vaddr, size, false);
-@@ -1206,7 +1164,7 @@ static int read_data_dma(struct qcom_nan
- static int write_data_dma(struct qcom_nand_controller *nandc, int reg_off,
- const u8 *vaddr, int size, unsigned int flags)
- {
-- if (nandc->props->is_bam)
-+ if (nandc->props->supports_bam)
- return prep_bam_dma_desc_data(nandc, false, vaddr, size, flags);
-
- return prep_adm_dma_desc(nandc, false, reg_off, vaddr, size, false);
-@@ -1220,13 +1178,14 @@ static void config_nand_page_read(struct
- {
- struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
-
-- write_reg_dma(nandc, NAND_ADDR0, 2, 0);
-- write_reg_dma(nandc, NAND_DEV0_CFG0, 3, 0);
-- if (!nandc->props->qpic_v2)
-- write_reg_dma(nandc, NAND_EBI2_ECC_BUF_CFG, 1, 0);
-- write_reg_dma(nandc, NAND_ERASED_CW_DETECT_CFG, 1, 0);
-- write_reg_dma(nandc, NAND_ERASED_CW_DETECT_CFG, 1,
-- NAND_ERASED_CW_SET | NAND_BAM_NEXT_SGL);
-+ write_reg_dma(nandc, &nandc->regs->addr0, NAND_ADDR0, 2, 0);
-+ write_reg_dma(nandc, &nandc->regs->cfg0, NAND_DEV0_CFG0, 3, 0);
-+ if (!nandc->props->qpic_version2)
-+ write_reg_dma(nandc, &nandc->regs->ecc_buf_cfg, NAND_EBI2_ECC_BUF_CFG, 1, 0);
-+ write_reg_dma(nandc, &nandc->regs->erased_cw_detect_cfg_clr,
-+ NAND_ERASED_CW_DETECT_CFG, 1, 0);
-+ write_reg_dma(nandc, &nandc->regs->erased_cw_detect_cfg_set,
-+ NAND_ERASED_CW_DETECT_CFG, 1, NAND_ERASED_CW_SET | NAND_BAM_NEXT_SGL);
- }
-
- /*
-@@ -1239,16 +1198,16 @@ config_nand_cw_read(struct nand_chip *ch
- struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
- struct nand_ecc_ctrl *ecc = &chip->ecc;
-
-- int reg = NAND_READ_LOCATION_0;
-+ __le32 *reg = &nandc->regs->read_location0;
-
-- if (nandc->props->qpic_v2 && qcom_nandc_is_last_cw(ecc, cw))
-- reg = NAND_READ_LOCATION_LAST_CW_0;
-+ if (nandc->props->qpic_version2 && qcom_nandc_is_last_cw(ecc, cw))
-+ reg = &nandc->regs->read_location_last0;
-
-- if (nandc->props->is_bam)
-- write_reg_dma(nandc, reg, 4, NAND_BAM_NEXT_SGL);
-+ if (nandc->props->supports_bam)
-+ write_reg_dma(nandc, reg, NAND_READ_LOCATION_0, 4, NAND_BAM_NEXT_SGL);
-
-- write_reg_dma(nandc, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
-- write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
-+ write_reg_dma(nandc, &nandc->regs->cmd, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
-+ write_reg_dma(nandc, &nandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
-
- if (use_ecc) {
- read_reg_dma(nandc, NAND_FLASH_STATUS, 2, 0);
-@@ -1279,10 +1238,10 @@ static void config_nand_page_write(struc
- {
- struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
-
-- write_reg_dma(nandc, NAND_ADDR0, 2, 0);
-- write_reg_dma(nandc, NAND_DEV0_CFG0, 3, 0);
-- if (!nandc->props->qpic_v2)
-- write_reg_dma(nandc, NAND_EBI2_ECC_BUF_CFG, 1,
-+ write_reg_dma(nandc, &nandc->regs->addr0, NAND_ADDR0, 2, 0);
-+ write_reg_dma(nandc, &nandc->regs->cfg0, NAND_DEV0_CFG0, 3, 0);
-+ if (!nandc->props->qpic_version2)
-+ write_reg_dma(nandc, &nandc->regs->ecc_buf_cfg, NAND_EBI2_ECC_BUF_CFG, 1,
- NAND_BAM_NEXT_SGL);
- }
-
-@@ -1294,13 +1253,13 @@ static void config_nand_cw_write(struct
- {
- struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
-
-- write_reg_dma(nandc, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
-- write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
-+ write_reg_dma(nandc, &nandc->regs->cmd, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
-+ write_reg_dma(nandc, &nandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
-
- read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL);
-
-- write_reg_dma(nandc, NAND_FLASH_STATUS, 1, 0);
-- write_reg_dma(nandc, NAND_READ_STATUS, 1, NAND_BAM_NEXT_SGL);
-+ write_reg_dma(nandc, &nandc->regs->clrflashstatus, NAND_FLASH_STATUS, 1, 0);
-+ write_reg_dma(nandc, &nandc->regs->clrreadstatus, NAND_READ_STATUS, 1, NAND_BAM_NEXT_SGL);
- }
-
- /* helpers to submit/free our list of dma descriptors */
-@@ -1311,7 +1270,7 @@ static int submit_descs(struct qcom_nand
- struct bam_transaction *bam_txn = nandc->bam_txn;
- int ret = 0;
-
-- if (nandc->props->is_bam) {
-+ if (nandc->props->supports_bam) {
- if (bam_txn->rx_sgl_pos > bam_txn->rx_sgl_start) {
- ret = prepare_bam_async_desc(nandc, nandc->rx_chan, 0);
- if (ret)
-@@ -1336,14 +1295,9 @@ static int submit_descs(struct qcom_nand
- list_for_each_entry(desc, &nandc->desc_list, node)
- cookie = dmaengine_submit(desc->dma_desc);
-
-- if (nandc->props->is_bam) {
-+ if (nandc->props->supports_bam) {
- bam_txn->last_cmd_desc->callback = qpic_bam_dma_done;
- bam_txn->last_cmd_desc->callback_param = bam_txn;
-- if (bam_txn->last_data_desc) {
-- bam_txn->last_data_desc->callback = qpic_bam_dma_done;
-- bam_txn->last_data_desc->callback_param = bam_txn;
-- bam_txn->wait_second_completion = true;
-- }
-
- dma_async_issue_pending(nandc->tx_chan);
- dma_async_issue_pending(nandc->rx_chan);
-@@ -1365,7 +1319,7 @@ err_unmap_free_desc:
- list_for_each_entry_safe(desc, n, &nandc->desc_list, node) {
- list_del(&desc->node);
-
-- if (nandc->props->is_bam)
-+ if (nandc->props->supports_bam)
- dma_unmap_sg(nandc->dev, desc->bam_sgl,
- desc->sgl_cnt, desc->dir);
- else
-@@ -1382,7 +1336,7 @@ err_unmap_free_desc:
- static void clear_read_regs(struct qcom_nand_controller *nandc)
- {
- nandc->reg_read_pos = 0;
-- nandc_read_buffer_sync(nandc, false);
-+ nandc_dev_to_mem(nandc, false);
- }
-
- /*
-@@ -1446,7 +1400,7 @@ static int check_flash_errors(struct qco
- struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
- int i;
-
-- nandc_read_buffer_sync(nandc, true);
-+ nandc_dev_to_mem(nandc, true);
-
- for (i = 0; i < cw_cnt; i++) {
- u32 flash = le32_to_cpu(nandc->reg_read_buf[i]);
-@@ -1476,7 +1430,7 @@ qcom_nandc_read_cw_raw(struct mtd_info *
- clear_read_regs(nandc);
- host->use_ecc = false;
-
-- if (nandc->props->qpic_v2)
-+ if (nandc->props->qpic_version2)
- raw_cw = ecc->steps - 1;
-
- clear_bam_transaction(nandc);
-@@ -1497,7 +1451,7 @@ qcom_nandc_read_cw_raw(struct mtd_info *
- oob_size2 = host->ecc_bytes_hw + host->spare_bytes;
- }
-
-- if (nandc->props->is_bam) {
-+ if (nandc->props->supports_bam) {
- nandc_set_read_loc(chip, cw, 0, read_loc, data_size1, 0);
- read_loc += data_size1;
-
-@@ -1621,7 +1575,7 @@ static int parse_read_errors(struct qcom
- u8 *data_buf_start = data_buf, *oob_buf_start = oob_buf;
-
- buf = (struct read_stats *)nandc->reg_read_buf;
-- nandc_read_buffer_sync(nandc, true);
-+ nandc_dev_to_mem(nandc, true);
-
- for (i = 0; i < ecc->steps; i++, buf++) {
- u32 flash, buffer, erased_cw;
-@@ -1734,7 +1688,7 @@ static int read_page_ecc(struct qcom_nan
- oob_size = host->ecc_bytes_hw + host->spare_bytes;
- }
-
-- if (nandc->props->is_bam) {
-+ if (nandc->props->supports_bam) {
- if (data_buf && oob_buf) {
- nandc_set_read_loc(chip, i, 0, 0, data_size, 0);
- nandc_set_read_loc(chip, i, 1, data_size,
-@@ -2455,14 +2409,14 @@ static int qcom_nand_attach_chip(struct
-
- mtd_set_ooblayout(mtd, &qcom_nand_ooblayout_ops);
- /* Free the initially allocated BAM transaction for reading the ONFI params */
-- if (nandc->props->is_bam)
-+ if (nandc->props->supports_bam)
- free_bam_transaction(nandc);
-
- nandc->max_cwperpage = max_t(unsigned int, nandc->max_cwperpage,
- cwperpage);
-
- /* Now allocate the BAM transaction based on updated max_cwperpage */
-- if (nandc->props->is_bam) {
-+ if (nandc->props->supports_bam) {
- nandc->bam_txn = alloc_bam_transaction(nandc);
- if (!nandc->bam_txn) {
- dev_err(nandc->dev,
-@@ -2522,7 +2476,7 @@ static int qcom_nand_attach_chip(struct
- | ecc_mode << ECC_MODE
- | host->ecc_bytes_hw << ECC_PARITY_SIZE_BYTES_BCH;
-
-- if (!nandc->props->qpic_v2)
-+ if (!nandc->props->qpic_version2)
- host->ecc_buf_cfg = 0x203 << NUM_STEPS;
-
- host->clrflashstatus = FS_READY_BSY_N;
-@@ -2556,7 +2510,7 @@ static int qcom_op_cmd_mapping(struct na
- cmd = OP_FETCH_ID;
- break;
- case NAND_CMD_PARAM:
-- if (nandc->props->qpic_v2)
-+ if (nandc->props->qpic_version2)
- cmd = OP_PAGE_READ_ONFI_READ;
- else
- cmd = OP_PAGE_READ;
-@@ -2609,7 +2563,7 @@ static int qcom_parse_instructions(struc
- if (ret < 0)
- return ret;
-
-- q_op->cmd_reg = ret;
-+ q_op->cmd_reg = cpu_to_le32(ret);
- q_op->rdy_delay_ns = instr->delay_ns;
- break;
-
-@@ -2619,10 +2573,10 @@ static int qcom_parse_instructions(struc
- addrs = &instr->ctx.addr.addrs[offset];
-
- for (i = 0; i < min_t(unsigned int, 4, naddrs); i++)
-- q_op->addr1_reg |= addrs[i] << (i * 8);
-+ q_op->addr1_reg |= cpu_to_le32(addrs[i] << (i * 8));
-
- if (naddrs > 4)
-- q_op->addr2_reg |= addrs[4];
-+ q_op->addr2_reg |= cpu_to_le32(addrs[4]);
-
- q_op->rdy_delay_ns = instr->delay_ns;
- break;
-@@ -2663,7 +2617,7 @@ static int qcom_wait_rdy_poll(struct nan
- unsigned long start = jiffies + msecs_to_jiffies(time_ms);
- u32 flash;
-
-- nandc_read_buffer_sync(nandc, true);
-+ nandc_dev_to_mem(nandc, true);
-
- do {
- flash = le32_to_cpu(nandc->reg_read_buf[0]);
-@@ -2706,11 +2660,11 @@ static int qcom_read_status_exec(struct
- clear_read_regs(nandc);
- clear_bam_transaction(nandc);
-
-- nandc_set_reg(chip, NAND_FLASH_CMD, q_op.cmd_reg);
-- nandc_set_reg(chip, NAND_EXEC_CMD, 1);
-+ nandc->regs->cmd = q_op.cmd_reg;
-+ nandc->regs->exec = cpu_to_le32(1);
-
-- write_reg_dma(nandc, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
-- write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
-+ write_reg_dma(nandc, &nandc->regs->cmd, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
-+ write_reg_dma(nandc, &nandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
- read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL);
-
- ret = submit_descs(nandc);
-@@ -2719,7 +2673,7 @@ static int qcom_read_status_exec(struct
- goto err_out;
- }
-
-- nandc_read_buffer_sync(nandc, true);
-+ nandc_dev_to_mem(nandc, true);
-
- for (i = 0; i < num_cw; i++) {
- flash_status = le32_to_cpu(nandc->reg_read_buf[i]);
-@@ -2763,16 +2717,14 @@ static int qcom_read_id_type_exec(struct
- clear_read_regs(nandc);
- clear_bam_transaction(nandc);
-
-- nandc_set_reg(chip, NAND_FLASH_CMD, q_op.cmd_reg);
-- nandc_set_reg(chip, NAND_ADDR0, q_op.addr1_reg);
-- nandc_set_reg(chip, NAND_ADDR1, q_op.addr2_reg);
-- nandc_set_reg(chip, NAND_FLASH_CHIP_SELECT,
-- nandc->props->is_bam ? 0 : DM_EN);
-+ nandc->regs->cmd = q_op.cmd_reg;
-+ nandc->regs->addr0 = q_op.addr1_reg;
-+ nandc->regs->addr1 = q_op.addr2_reg;
-+ nandc->regs->chip_sel = cpu_to_le32(nandc->props->supports_bam ? 0 : DM_EN);
-+ nandc->regs->exec = cpu_to_le32(1);
-
-- nandc_set_reg(chip, NAND_EXEC_CMD, 1);
--
-- write_reg_dma(nandc, NAND_FLASH_CMD, 4, NAND_BAM_NEXT_SGL);
-- write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
-+ write_reg_dma(nandc, &nandc->regs->cmd, NAND_FLASH_CMD, 4, NAND_BAM_NEXT_SGL);
-+ write_reg_dma(nandc, &nandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
-
- read_reg_dma(nandc, NAND_READ_ID, 1, NAND_BAM_NEXT_SGL);
-
-@@ -2786,7 +2738,7 @@ static int qcom_read_id_type_exec(struct
- op_id = q_op.data_instr_idx;
- len = nand_subop_get_data_len(subop, op_id);
-
-- nandc_read_buffer_sync(nandc, true);
-+ nandc_dev_to_mem(nandc, true);
- memcpy(instr->ctx.data.buf.in, nandc->reg_read_buf, len);
-
- err_out:
-@@ -2807,15 +2759,14 @@ static int qcom_misc_cmd_type_exec(struc
-
- if (q_op.flag == OP_PROGRAM_PAGE) {
- goto wait_rdy;
-- } else if (q_op.cmd_reg == OP_BLOCK_ERASE) {
-- q_op.cmd_reg |= PAGE_ACC | LAST_PAGE;
-- nandc_set_reg(chip, NAND_ADDR0, q_op.addr1_reg);
-- nandc_set_reg(chip, NAND_ADDR1, q_op.addr2_reg);
-- nandc_set_reg(chip, NAND_DEV0_CFG0,
-- host->cfg0_raw & ~(7 << CW_PER_PAGE));
-- nandc_set_reg(chip, NAND_DEV0_CFG1, host->cfg1_raw);
-+ } else if (q_op.cmd_reg == cpu_to_le32(OP_BLOCK_ERASE)) {
-+ q_op.cmd_reg |= cpu_to_le32(PAGE_ACC | LAST_PAGE);
-+ nandc->regs->addr0 = q_op.addr1_reg;
-+ nandc->regs->addr1 = q_op.addr2_reg;
-+ nandc->regs->cfg0 = cpu_to_le32(host->cfg0_raw & ~(7 << CW_PER_PAGE));
-+ nandc->regs->cfg1 = cpu_to_le32(host->cfg1_raw);
- instrs = 3;
-- } else if (q_op.cmd_reg != OP_RESET_DEVICE) {
-+ } else if (q_op.cmd_reg != cpu_to_le32(OP_RESET_DEVICE)) {
- return 0;
- }
-
-@@ -2826,14 +2777,14 @@ static int qcom_misc_cmd_type_exec(struc
- clear_read_regs(nandc);
- clear_bam_transaction(nandc);
-
-- nandc_set_reg(chip, NAND_FLASH_CMD, q_op.cmd_reg);
-- nandc_set_reg(chip, NAND_EXEC_CMD, 1);
-+ nandc->regs->cmd = q_op.cmd_reg;
-+ nandc->regs->exec = cpu_to_le32(1);
-
-- write_reg_dma(nandc, NAND_FLASH_CMD, instrs, NAND_BAM_NEXT_SGL);
-- if (q_op.cmd_reg == OP_BLOCK_ERASE)
-- write_reg_dma(nandc, NAND_DEV0_CFG0, 2, NAND_BAM_NEXT_SGL);
-+ write_reg_dma(nandc, &nandc->regs->cmd, NAND_FLASH_CMD, instrs, NAND_BAM_NEXT_SGL);
-+ if (q_op.cmd_reg == cpu_to_le32(OP_BLOCK_ERASE))
-+ write_reg_dma(nandc, &nandc->regs->cfg0, NAND_DEV0_CFG0, 2, NAND_BAM_NEXT_SGL);
-
-- write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
-+ write_reg_dma(nandc, &nandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
- read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL);
-
- ret = submit_descs(nandc);
-@@ -2862,14 +2813,14 @@ static int qcom_param_page_type_exec(str
-
- reg_base = NAND_READ_LOCATION_0;
-
-- if (nandc->props->qpic_v2)
-+ if (nandc->props->qpic_version2)
- reg_base = NAND_READ_LOCATION_LAST_CW_0;
-
- ret = qcom_parse_instructions(chip, subop, &q_op);
- if (ret)
- return ret;
-
-- q_op.cmd_reg |= PAGE_ACC | LAST_PAGE;
-+ q_op.cmd_reg |= cpu_to_le32(PAGE_ACC | LAST_PAGE);
-
- nandc->buf_count = 0;
- nandc->buf_start = 0;
-@@ -2877,52 +2828,52 @@ static int qcom_param_page_type_exec(str
- clear_read_regs(nandc);
- clear_bam_transaction(nandc);
-
-- nandc_set_reg(chip, NAND_FLASH_CMD, q_op.cmd_reg);
-+ nandc->regs->cmd = q_op.cmd_reg;
-+ nandc->regs->addr0 = 0;
-+ nandc->regs->addr1 = 0;
-+
-+ nandc->regs->cfg0 = cpu_to_le32(0 << CW_PER_PAGE |
-+ 512 << UD_SIZE_BYTES |
-+ 5 << NUM_ADDR_CYCLES |
-+ 0 << SPARE_SIZE_BYTES);
-+
-+ nandc->regs->cfg1 = cpu_to_le32(7 << NAND_RECOVERY_CYCLES |
-+ 0 << CS_ACTIVE_BSY |
-+ 17 << BAD_BLOCK_BYTE_NUM |
-+ 1 << BAD_BLOCK_IN_SPARE_AREA |
-+ 2 << WR_RD_BSY_GAP |
-+ 0 << WIDE_FLASH |
-+ 1 << DEV0_CFG1_ECC_DISABLE);
-
-- nandc_set_reg(chip, NAND_ADDR0, 0);
-- nandc_set_reg(chip, NAND_ADDR1, 0);
-- nandc_set_reg(chip, NAND_DEV0_CFG0, 0 << CW_PER_PAGE
-- | 512 << UD_SIZE_BYTES
-- | 5 << NUM_ADDR_CYCLES
-- | 0 << SPARE_SIZE_BYTES);
-- nandc_set_reg(chip, NAND_DEV0_CFG1, 7 << NAND_RECOVERY_CYCLES
-- | 0 << CS_ACTIVE_BSY
-- | 17 << BAD_BLOCK_BYTE_NUM
-- | 1 << BAD_BLOCK_IN_SPARE_AREA
-- | 2 << WR_RD_BSY_GAP
-- | 0 << WIDE_FLASH
-- | 1 << DEV0_CFG1_ECC_DISABLE);
-- if (!nandc->props->qpic_v2)
-- nandc_set_reg(chip, NAND_EBI2_ECC_BUF_CFG, 1 << ECC_CFG_ECC_DISABLE);
-+ if (!nandc->props->qpic_version2)
-+ nandc->regs->ecc_buf_cfg = cpu_to_le32(1 << ECC_CFG_ECC_DISABLE);
-
- /* configure CMD1 and VLD for ONFI param probing in QPIC v1 */
-- if (!nandc->props->qpic_v2) {
-- nandc_set_reg(chip, NAND_DEV_CMD_VLD,
-- (nandc->vld & ~READ_START_VLD));
-- nandc_set_reg(chip, NAND_DEV_CMD1,
-- (nandc->cmd1 & ~(0xFF << READ_ADDR))
-- | NAND_CMD_PARAM << READ_ADDR);
-+ if (!nandc->props->qpic_version2) {
-+ nandc->regs->vld = cpu_to_le32((nandc->vld & ~READ_START_VLD));
-+ nandc->regs->cmd1 = cpu_to_le32((nandc->cmd1 & ~(0xFF << READ_ADDR))
-+ | NAND_CMD_PARAM << READ_ADDR);
- }
-
-- nandc_set_reg(chip, NAND_EXEC_CMD, 1);
--
-- if (!nandc->props->qpic_v2) {
-- nandc_set_reg(chip, NAND_DEV_CMD1_RESTORE, nandc->cmd1);
-- nandc_set_reg(chip, NAND_DEV_CMD_VLD_RESTORE, nandc->vld);
-+ nandc->regs->exec = cpu_to_le32(1);
-+
-+ if (!nandc->props->qpic_version2) {
-+ nandc->regs->orig_cmd1 = cpu_to_le32(nandc->cmd1);
-+ nandc->regs->orig_vld = cpu_to_le32(nandc->vld);
- }
-
- instr = q_op.data_instr;
- op_id = q_op.data_instr_idx;
- len = nand_subop_get_data_len(subop, op_id);
-
-- if (nandc->props->qpic_v2)
-+ if (nandc->props->qpic_version2)
- nandc_set_read_loc_last(chip, reg_base, 0, len, 1);
- else
- nandc_set_read_loc_first(chip, reg_base, 0, len, 1);
-
-- if (!nandc->props->qpic_v2) {
-- write_reg_dma(nandc, NAND_DEV_CMD_VLD, 1, 0);
-- write_reg_dma(nandc, NAND_DEV_CMD1, 1, NAND_BAM_NEXT_SGL);
-+ if (!nandc->props->qpic_version2) {
-+ write_reg_dma(nandc, &nandc->regs->vld, NAND_DEV_CMD_VLD, 1, 0);
-+ write_reg_dma(nandc, &nandc->regs->cmd1, NAND_DEV_CMD1, 1, NAND_BAM_NEXT_SGL);
- }
-
- nandc->buf_count = 512;
-@@ -2934,9 +2885,10 @@ static int qcom_param_page_type_exec(str
- nandc->buf_count, 0);
-
- /* restore CMD1 and VLD regs */
-- if (!nandc->props->qpic_v2) {
-- write_reg_dma(nandc, NAND_DEV_CMD1_RESTORE, 1, 0);
-- write_reg_dma(nandc, NAND_DEV_CMD_VLD_RESTORE, 1, NAND_BAM_NEXT_SGL);
-+ if (!nandc->props->qpic_version2) {
-+ write_reg_dma(nandc, &nandc->regs->orig_cmd1, NAND_DEV_CMD1_RESTORE, 1, 0);
-+ write_reg_dma(nandc, &nandc->regs->orig_vld, NAND_DEV_CMD_VLD_RESTORE, 1,
-+ NAND_BAM_NEXT_SGL);
- }
-
- ret = submit_descs(nandc);
-@@ -3025,7 +2977,7 @@ static const struct nand_controller_ops
-
- static void qcom_nandc_unalloc(struct qcom_nand_controller *nandc)
- {
-- if (nandc->props->is_bam) {
-+ if (nandc->props->supports_bam) {
- if (!dma_mapping_error(nandc->dev, nandc->reg_read_dma))
- dma_unmap_single(nandc->dev, nandc->reg_read_dma,
- MAX_REG_RD *
-@@ -3078,7 +3030,7 @@ static int qcom_nandc_alloc(struct qcom_
- if (!nandc->reg_read_buf)
- return -ENOMEM;
-
-- if (nandc->props->is_bam) {
-+ if (nandc->props->supports_bam) {
- nandc->reg_read_dma =
- dma_map_single(nandc->dev, nandc->reg_read_buf,
- MAX_REG_RD *
-@@ -3159,15 +3111,15 @@ static int qcom_nandc_setup(struct qcom_
- u32 nand_ctrl;
-
- /* kill onenand */
-- if (!nandc->props->is_qpic)
-+ if (!nandc->props->nandc_part_of_qpic)
- nandc_write(nandc, SFLASHC_BURST_CFG, 0);
-
-- if (!nandc->props->qpic_v2)
-+ if (!nandc->props->qpic_version2)
- nandc_write(nandc, dev_cmd_reg_addr(nandc, NAND_DEV_CMD_VLD),
- NAND_DEV_CMD_VLD_VAL);
-
- /* enable ADM or BAM DMA */
-- if (nandc->props->is_bam) {
-+ if (nandc->props->supports_bam) {
- nand_ctrl = nandc_read(nandc, NAND_CTRL);
-
- /*
-@@ -3184,7 +3136,7 @@ static int qcom_nandc_setup(struct qcom_
- }
-
- /* save the original values of these registers */
-- if (!nandc->props->qpic_v2) {
-+ if (!nandc->props->qpic_version2) {
- nandc->cmd1 = nandc_read(nandc, dev_cmd_reg_addr(nandc, NAND_DEV_CMD1));
- nandc->vld = NAND_DEV_CMD_VLD_VAL;
- }
-@@ -3357,7 +3309,7 @@ static int qcom_nandc_parse_dt(struct pl
- struct device_node *np = nandc->dev->of_node;
- int ret;
-
-- if (!nandc->props->is_bam) {
-+ if (!nandc->props->supports_bam) {
- ret = of_property_read_u32(np, "qcom,cmd-crci",
- &nandc->cmd_crci);
- if (ret) {
-@@ -3482,30 +3434,30 @@ static void qcom_nandc_remove(struct pla
-
- static const struct qcom_nandc_props ipq806x_nandc_props = {
- .ecc_modes = (ECC_RS_4BIT | ECC_BCH_8BIT),
-- .is_bam = false,
-+ .supports_bam = false,
- .use_codeword_fixup = true,
- .dev_cmd_reg_start = 0x0,
- };
-
- static const struct qcom_nandc_props ipq4019_nandc_props = {
- .ecc_modes = (ECC_BCH_4BIT | ECC_BCH_8BIT),
-- .is_bam = true,
-- .is_qpic = true,
-+ .supports_bam = true,
-+ .nandc_part_of_qpic = true,
- .dev_cmd_reg_start = 0x0,
- };
-
- static const struct qcom_nandc_props ipq8074_nandc_props = {
- .ecc_modes = (ECC_BCH_4BIT | ECC_BCH_8BIT),
-- .is_bam = true,
-- .is_qpic = true,
-+ .supports_bam = true,
-+ .nandc_part_of_qpic = true,
- .dev_cmd_reg_start = 0x7000,
- };
-
- static const struct qcom_nandc_props sdx55_nandc_props = {
- .ecc_modes = (ECC_BCH_4BIT | ECC_BCH_8BIT),
-- .is_bam = true,
-- .is_qpic = true,
-- .qpic_v2 = true,
-+ .supports_bam = true,
-+ .nandc_part_of_qpic = true,
-+ .qpic_version2 = true,
- .dev_cmd_reg_start = 0x7000,
- };
-
+++ /dev/null
-From 1d479f5b345e0c3650fec4dddeef9fc6fab30c8b Mon Sep 17 00:00:00 2001
-Date: Wed, 20 Nov 2024 14:45:01 +0530
-Subject: [PATCH 2/4] mtd: rawnand: qcom: Add qcom prefix to common api
-
-Add qcom prefix to all the api which will be commonly
-used by spi nand driver and raw nand driver.
-
----
- drivers/mtd/nand/raw/qcom_nandc.c | 320 +++++++++++++++---------------
- 1 file changed, 160 insertions(+), 160 deletions(-)
-
---- a/drivers/mtd/nand/raw/qcom_nandc.c
-+++ b/drivers/mtd/nand/raw/qcom_nandc.c
-@@ -53,7 +53,7 @@
- #define NAND_READ_LOCATION_LAST_CW_2 0xf48
- #define NAND_READ_LOCATION_LAST_CW_3 0xf4c
-
--/* dummy register offsets, used by write_reg_dma */
-+/* dummy register offsets, used by qcom_write_reg_dma */
- #define NAND_DEV_CMD1_RESTORE 0xdead
- #define NAND_DEV_CMD_VLD_RESTORE 0xbeef
-
-@@ -211,7 +211,7 @@
-
- /*
- * Flags used in DMA descriptor preparation helper functions
-- * (i.e. read_reg_dma/write_reg_dma/read_data_dma/write_data_dma)
-+ * (i.e. qcom_read_reg_dma/qcom_write_reg_dma/qcom_read_data_dma/qcom_write_data_dma)
- */
- /* Don't set the EOT in current tx BAM sgl */
- #define NAND_BAM_NO_EOT BIT(0)
-@@ -550,7 +550,7 @@ struct qcom_nandc_props {
- };
-
- /* Frees the BAM transaction memory */
--static void free_bam_transaction(struct qcom_nand_controller *nandc)
-+static void qcom_free_bam_transaction(struct qcom_nand_controller *nandc)
- {
- struct bam_transaction *bam_txn = nandc->bam_txn;
-
-@@ -559,7 +559,7 @@ static void free_bam_transaction(struct
-
- /* Allocates and Initializes the BAM transaction */
- static struct bam_transaction *
--alloc_bam_transaction(struct qcom_nand_controller *nandc)
-+qcom_alloc_bam_transaction(struct qcom_nand_controller *nandc)
- {
- struct bam_transaction *bam_txn;
- size_t bam_txn_size;
-@@ -595,7 +595,7 @@ alloc_bam_transaction(struct qcom_nand_c
- }
-
- /* Clears the BAM transaction indexes */
--static void clear_bam_transaction(struct qcom_nand_controller *nandc)
-+static void qcom_clear_bam_transaction(struct qcom_nand_controller *nandc)
- {
- struct bam_transaction *bam_txn = nandc->bam_txn;
-
-@@ -614,7 +614,7 @@ static void clear_bam_transaction(struct
- }
-
- /* Callback for DMA descriptor completion */
--static void qpic_bam_dma_done(void *data)
-+static void qcom_qpic_bam_dma_done(void *data)
- {
- struct bam_transaction *bam_txn = data;
-
-@@ -644,7 +644,7 @@ static void nandc_write(struct qcom_nand
- iowrite32(val, nandc->base + offset);
- }
-
--static void nandc_dev_to_mem(struct qcom_nand_controller *nandc, bool is_cpu)
-+static void qcom_nandc_dev_to_mem(struct qcom_nand_controller *nandc, bool is_cpu)
- {
- if (!nandc->props->supports_bam)
- return;
-@@ -824,9 +824,9 @@ static void update_rw_regs(struct qcom_n
- * for BAM. This descriptor will be added in the NAND DMA descriptor queue
- * which will be submitted to DMA engine.
- */
--static int prepare_bam_async_desc(struct qcom_nand_controller *nandc,
-- struct dma_chan *chan,
-- unsigned long flags)
-+static int qcom_prepare_bam_async_desc(struct qcom_nand_controller *nandc,
-+ struct dma_chan *chan,
-+ unsigned long flags)
- {
- struct desc_info *desc;
- struct scatterlist *sgl;
-@@ -903,9 +903,9 @@ static int prepare_bam_async_desc(struct
- * NAND_BAM_NEXT_SGL will be used for starting the separate SGL
- * after the current command element.
- */
--static int prep_bam_dma_desc_cmd(struct qcom_nand_controller *nandc, bool read,
-- int reg_off, const void *vaddr,
-- int size, unsigned int flags)
-+static int qcom_prep_bam_dma_desc_cmd(struct qcom_nand_controller *nandc, bool read,
-+ int reg_off, const void *vaddr,
-+ int size, unsigned int flags)
- {
- int bam_ce_size;
- int i, ret;
-@@ -943,9 +943,9 @@ static int prep_bam_dma_desc_cmd(struct
- bam_txn->bam_ce_start = bam_txn->bam_ce_pos;
-
- if (flags & NAND_BAM_NWD) {
-- ret = prepare_bam_async_desc(nandc, nandc->cmd_chan,
-- DMA_PREP_FENCE |
-- DMA_PREP_CMD);
-+ ret = qcom_prepare_bam_async_desc(nandc, nandc->cmd_chan,
-+ DMA_PREP_FENCE |
-+ DMA_PREP_CMD);
- if (ret)
- return ret;
- }
-@@ -958,9 +958,8 @@ static int prep_bam_dma_desc_cmd(struct
- * Prepares the data descriptor for BAM DMA which will be used for NAND
- * data reads and writes.
- */
--static int prep_bam_dma_desc_data(struct qcom_nand_controller *nandc, bool read,
-- const void *vaddr,
-- int size, unsigned int flags)
-+static int qcom_prep_bam_dma_desc_data(struct qcom_nand_controller *nandc, bool read,
-+ const void *vaddr, int size, unsigned int flags)
- {
- int ret;
- struct bam_transaction *bam_txn = nandc->bam_txn;
-@@ -979,8 +978,8 @@ static int prep_bam_dma_desc_data(struct
- * is not set, form the DMA descriptor
- */
- if (!(flags & NAND_BAM_NO_EOT)) {
-- ret = prepare_bam_async_desc(nandc, nandc->tx_chan,
-- DMA_PREP_INTERRUPT);
-+ ret = qcom_prepare_bam_async_desc(nandc, nandc->tx_chan,
-+ DMA_PREP_INTERRUPT);
- if (ret)
- return ret;
- }
-@@ -989,9 +988,9 @@ static int prep_bam_dma_desc_data(struct
- return 0;
- }
-
--static int prep_adm_dma_desc(struct qcom_nand_controller *nandc, bool read,
-- int reg_off, const void *vaddr, int size,
-- bool flow_control)
-+static int qcom_prep_adm_dma_desc(struct qcom_nand_controller *nandc, bool read,
-+ int reg_off, const void *vaddr, int size,
-+ bool flow_control)
- {
- struct desc_info *desc;
- struct dma_async_tx_descriptor *dma_desc;
-@@ -1069,15 +1068,15 @@ err:
- }
-
- /*
-- * read_reg_dma: prepares a descriptor to read a given number of
-+ * qcom_read_reg_dma: prepares a descriptor to read a given number of
- * contiguous registers to the reg_read_buf pointer
- *
- * @first: offset of the first register in the contiguous block
- * @num_regs: number of registers to read
- * @flags: flags to control DMA descriptor preparation
- */
--static int read_reg_dma(struct qcom_nand_controller *nandc, int first,
-- int num_regs, unsigned int flags)
-+static int qcom_read_reg_dma(struct qcom_nand_controller *nandc, int first,
-+ int num_regs, unsigned int flags)
- {
- bool flow_control = false;
- void *vaddr;
-@@ -1089,18 +1088,18 @@ static int read_reg_dma(struct qcom_nand
- first = dev_cmd_reg_addr(nandc, first);
-
- if (nandc->props->supports_bam)
-- return prep_bam_dma_desc_cmd(nandc, true, first, vaddr,
-+ return qcom_prep_bam_dma_desc_cmd(nandc, true, first, vaddr,
- num_regs, flags);
-
- if (first == NAND_READ_ID || first == NAND_FLASH_STATUS)
- flow_control = true;
-
-- return prep_adm_dma_desc(nandc, true, first, vaddr,
-+ return qcom_prep_adm_dma_desc(nandc, true, first, vaddr,
- num_regs * sizeof(u32), flow_control);
- }
-
- /*
-- * write_reg_dma: prepares a descriptor to write a given number of
-+ * qcom_write_reg_dma: prepares a descriptor to write a given number of
- * contiguous registers
- *
- * @vaddr: contiguous memory from where register value will
-@@ -1109,8 +1108,8 @@ static int read_reg_dma(struct qcom_nand
- * @num_regs: number of registers to write
- * @flags: flags to control DMA descriptor preparation
- */
--static int write_reg_dma(struct qcom_nand_controller *nandc, __le32 *vaddr,
-- int first, int num_regs, unsigned int flags)
-+static int qcom_write_reg_dma(struct qcom_nand_controller *nandc, __le32 *vaddr,
-+ int first, int num_regs, unsigned int flags)
- {
- bool flow_control = false;
-
-@@ -1124,18 +1123,18 @@ static int write_reg_dma(struct qcom_nan
- first = dev_cmd_reg_addr(nandc, NAND_DEV_CMD_VLD);
-
- if (nandc->props->supports_bam)
-- return prep_bam_dma_desc_cmd(nandc, false, first, vaddr,
-+ return qcom_prep_bam_dma_desc_cmd(nandc, false, first, vaddr,
- num_regs, flags);
-
- if (first == NAND_FLASH_CMD)
- flow_control = true;
-
-- return prep_adm_dma_desc(nandc, false, first, vaddr,
-+ return qcom_prep_adm_dma_desc(nandc, false, first, vaddr,
- num_regs * sizeof(u32), flow_control);
- }
-
- /*
-- * read_data_dma: prepares a DMA descriptor to transfer data from the
-+ * qcom_read_data_dma: prepares a DMA descriptor to transfer data from the
- * controller's internal buffer to the buffer 'vaddr'
- *
- * @reg_off: offset within the controller's data buffer
-@@ -1143,17 +1142,17 @@ static int write_reg_dma(struct qcom_nan
- * @size: DMA transaction size in bytes
- * @flags: flags to control DMA descriptor preparation
- */
--static int read_data_dma(struct qcom_nand_controller *nandc, int reg_off,
-- const u8 *vaddr, int size, unsigned int flags)
-+static int qcom_read_data_dma(struct qcom_nand_controller *nandc, int reg_off,
-+ const u8 *vaddr, int size, unsigned int flags)
- {
- if (nandc->props->supports_bam)
-- return prep_bam_dma_desc_data(nandc, true, vaddr, size, flags);
-+ return qcom_prep_bam_dma_desc_data(nandc, true, vaddr, size, flags);
-
-- return prep_adm_dma_desc(nandc, true, reg_off, vaddr, size, false);
-+ return qcom_prep_adm_dma_desc(nandc, true, reg_off, vaddr, size, false);
- }
-
- /*
-- * write_data_dma: prepares a DMA descriptor to transfer data from
-+ * qcom_write_data_dma: prepares a DMA descriptor to transfer data from
- * 'vaddr' to the controller's internal buffer
- *
- * @reg_off: offset within the controller's data buffer
-@@ -1161,13 +1160,13 @@ static int read_data_dma(struct qcom_nan
- * @size: DMA transaction size in bytes
- * @flags: flags to control DMA descriptor preparation
- */
--static int write_data_dma(struct qcom_nand_controller *nandc, int reg_off,
-- const u8 *vaddr, int size, unsigned int flags)
-+static int qcom_write_data_dma(struct qcom_nand_controller *nandc, int reg_off,
-+ const u8 *vaddr, int size, unsigned int flags)
- {
- if (nandc->props->supports_bam)
-- return prep_bam_dma_desc_data(nandc, false, vaddr, size, flags);
-+ return qcom_prep_bam_dma_desc_data(nandc, false, vaddr, size, flags);
-
-- return prep_adm_dma_desc(nandc, false, reg_off, vaddr, size, false);
-+ return qcom_prep_adm_dma_desc(nandc, false, reg_off, vaddr, size, false);
- }
-
- /*
-@@ -1178,14 +1177,14 @@ static void config_nand_page_read(struct
- {
- struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
-
-- write_reg_dma(nandc, &nandc->regs->addr0, NAND_ADDR0, 2, 0);
-- write_reg_dma(nandc, &nandc->regs->cfg0, NAND_DEV0_CFG0, 3, 0);
-+ qcom_write_reg_dma(nandc, &nandc->regs->addr0, NAND_ADDR0, 2, 0);
-+ qcom_write_reg_dma(nandc, &nandc->regs->cfg0, NAND_DEV0_CFG0, 3, 0);
- if (!nandc->props->qpic_version2)
-- write_reg_dma(nandc, &nandc->regs->ecc_buf_cfg, NAND_EBI2_ECC_BUF_CFG, 1, 0);
-- write_reg_dma(nandc, &nandc->regs->erased_cw_detect_cfg_clr,
-- NAND_ERASED_CW_DETECT_CFG, 1, 0);
-- write_reg_dma(nandc, &nandc->regs->erased_cw_detect_cfg_set,
-- NAND_ERASED_CW_DETECT_CFG, 1, NAND_ERASED_CW_SET | NAND_BAM_NEXT_SGL);
-+ qcom_write_reg_dma(nandc, &nandc->regs->ecc_buf_cfg, NAND_EBI2_ECC_BUF_CFG, 1, 0);
-+ qcom_write_reg_dma(nandc, &nandc->regs->erased_cw_detect_cfg_clr,
-+ NAND_ERASED_CW_DETECT_CFG, 1, 0);
-+ qcom_write_reg_dma(nandc, &nandc->regs->erased_cw_detect_cfg_set,
-+ NAND_ERASED_CW_DETECT_CFG, 1, NAND_ERASED_CW_SET | NAND_BAM_NEXT_SGL);
- }
-
- /*
-@@ -1204,17 +1203,17 @@ config_nand_cw_read(struct nand_chip *ch
- reg = &nandc->regs->read_location_last0;
-
- if (nandc->props->supports_bam)
-- write_reg_dma(nandc, reg, NAND_READ_LOCATION_0, 4, NAND_BAM_NEXT_SGL);
-+ qcom_write_reg_dma(nandc, reg, NAND_READ_LOCATION_0, 4, NAND_BAM_NEXT_SGL);
-
-- write_reg_dma(nandc, &nandc->regs->cmd, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
-- write_reg_dma(nandc, &nandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
-+ qcom_write_reg_dma(nandc, &nandc->regs->cmd, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
-+ qcom_write_reg_dma(nandc, &nandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
-
- if (use_ecc) {
-- read_reg_dma(nandc, NAND_FLASH_STATUS, 2, 0);
-- read_reg_dma(nandc, NAND_ERASED_CW_DETECT_STATUS, 1,
-- NAND_BAM_NEXT_SGL);
-+ qcom_read_reg_dma(nandc, NAND_FLASH_STATUS, 2, 0);
-+ qcom_read_reg_dma(nandc, NAND_ERASED_CW_DETECT_STATUS, 1,
-+ NAND_BAM_NEXT_SGL);
- } else {
-- read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL);
-+ qcom_read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL);
- }
- }
-
-@@ -1238,11 +1237,11 @@ static void config_nand_page_write(struc
- {
- struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
-
-- write_reg_dma(nandc, &nandc->regs->addr0, NAND_ADDR0, 2, 0);
-- write_reg_dma(nandc, &nandc->regs->cfg0, NAND_DEV0_CFG0, 3, 0);
-+ qcom_write_reg_dma(nandc, &nandc->regs->addr0, NAND_ADDR0, 2, 0);
-+ qcom_write_reg_dma(nandc, &nandc->regs->cfg0, NAND_DEV0_CFG0, 3, 0);
- if (!nandc->props->qpic_version2)
-- write_reg_dma(nandc, &nandc->regs->ecc_buf_cfg, NAND_EBI2_ECC_BUF_CFG, 1,
-- NAND_BAM_NEXT_SGL);
-+ qcom_write_reg_dma(nandc, &nandc->regs->ecc_buf_cfg, NAND_EBI2_ECC_BUF_CFG, 1,
-+ NAND_BAM_NEXT_SGL);
- }
-
- /*
-@@ -1253,17 +1252,18 @@ static void config_nand_cw_write(struct
- {
- struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
-
-- write_reg_dma(nandc, &nandc->regs->cmd, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
-- write_reg_dma(nandc, &nandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
-+ qcom_write_reg_dma(nandc, &nandc->regs->cmd, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
-+ qcom_write_reg_dma(nandc, &nandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
-
-- read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL);
-+ qcom_read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL);
-
-- write_reg_dma(nandc, &nandc->regs->clrflashstatus, NAND_FLASH_STATUS, 1, 0);
-- write_reg_dma(nandc, &nandc->regs->clrreadstatus, NAND_READ_STATUS, 1, NAND_BAM_NEXT_SGL);
-+ qcom_write_reg_dma(nandc, &nandc->regs->clrflashstatus, NAND_FLASH_STATUS, 1, 0);
-+ qcom_write_reg_dma(nandc, &nandc->regs->clrreadstatus, NAND_READ_STATUS, 1,
-+ NAND_BAM_NEXT_SGL);
- }
-
- /* helpers to submit/free our list of dma descriptors */
--static int submit_descs(struct qcom_nand_controller *nandc)
-+static int qcom_submit_descs(struct qcom_nand_controller *nandc)
- {
- struct desc_info *desc, *n;
- dma_cookie_t cookie = 0;
-@@ -1272,21 +1272,21 @@ static int submit_descs(struct qcom_nand
-
- if (nandc->props->supports_bam) {
- if (bam_txn->rx_sgl_pos > bam_txn->rx_sgl_start) {
-- ret = prepare_bam_async_desc(nandc, nandc->rx_chan, 0);
-+ ret = qcom_prepare_bam_async_desc(nandc, nandc->rx_chan, 0);
- if (ret)
- goto err_unmap_free_desc;
- }
-
- if (bam_txn->tx_sgl_pos > bam_txn->tx_sgl_start) {
-- ret = prepare_bam_async_desc(nandc, nandc->tx_chan,
-- DMA_PREP_INTERRUPT);
-+ ret = qcom_prepare_bam_async_desc(nandc, nandc->tx_chan,
-+ DMA_PREP_INTERRUPT);
- if (ret)
- goto err_unmap_free_desc;
- }
-
- if (bam_txn->cmd_sgl_pos > bam_txn->cmd_sgl_start) {
-- ret = prepare_bam_async_desc(nandc, nandc->cmd_chan,
-- DMA_PREP_CMD);
-+ ret = qcom_prepare_bam_async_desc(nandc, nandc->cmd_chan,
-+ DMA_PREP_CMD);
- if (ret)
- goto err_unmap_free_desc;
- }
-@@ -1296,7 +1296,7 @@ static int submit_descs(struct qcom_nand
- cookie = dmaengine_submit(desc->dma_desc);
-
- if (nandc->props->supports_bam) {
-- bam_txn->last_cmd_desc->callback = qpic_bam_dma_done;
-+ bam_txn->last_cmd_desc->callback = qcom_qpic_bam_dma_done;
- bam_txn->last_cmd_desc->callback_param = bam_txn;
-
- dma_async_issue_pending(nandc->tx_chan);
-@@ -1314,7 +1314,7 @@ static int submit_descs(struct qcom_nand
- err_unmap_free_desc:
- /*
- * Unmap the dma sg_list and free the desc allocated by both
-- * prepare_bam_async_desc() and prep_adm_dma_desc() functions.
-+ * qcom_prepare_bam_async_desc() and qcom_prep_adm_dma_desc() functions.
- */
- list_for_each_entry_safe(desc, n, &nandc->desc_list, node) {
- list_del(&desc->node);
-@@ -1333,10 +1333,10 @@ err_unmap_free_desc:
- }
-
- /* reset the register read buffer for next NAND operation */
--static void clear_read_regs(struct qcom_nand_controller *nandc)
-+static void qcom_clear_read_regs(struct qcom_nand_controller *nandc)
- {
- nandc->reg_read_pos = 0;
-- nandc_dev_to_mem(nandc, false);
-+ qcom_nandc_dev_to_mem(nandc, false);
- }
-
- /*
-@@ -1400,7 +1400,7 @@ static int check_flash_errors(struct qco
- struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
- int i;
-
-- nandc_dev_to_mem(nandc, true);
-+ qcom_nandc_dev_to_mem(nandc, true);
-
- for (i = 0; i < cw_cnt; i++) {
- u32 flash = le32_to_cpu(nandc->reg_read_buf[i]);
-@@ -1427,13 +1427,13 @@ qcom_nandc_read_cw_raw(struct mtd_info *
- nand_read_page_op(chip, page, 0, NULL, 0);
- nandc->buf_count = 0;
- nandc->buf_start = 0;
-- clear_read_regs(nandc);
-+ qcom_clear_read_regs(nandc);
- host->use_ecc = false;
-
- if (nandc->props->qpic_version2)
- raw_cw = ecc->steps - 1;
-
-- clear_bam_transaction(nandc);
-+ qcom_clear_bam_transaction(nandc);
- set_address(host, host->cw_size * cw, page);
- update_rw_regs(host, 1, true, raw_cw);
- config_nand_page_read(chip);
-@@ -1466,18 +1466,18 @@ qcom_nandc_read_cw_raw(struct mtd_info *
-
- config_nand_cw_read(chip, false, raw_cw);
-
-- read_data_dma(nandc, reg_off, data_buf, data_size1, 0);
-+ qcom_read_data_dma(nandc, reg_off, data_buf, data_size1, 0);
- reg_off += data_size1;
-
-- read_data_dma(nandc, reg_off, oob_buf, oob_size1, 0);
-+ qcom_read_data_dma(nandc, reg_off, oob_buf, oob_size1, 0);
- reg_off += oob_size1;
-
-- read_data_dma(nandc, reg_off, data_buf + data_size1, data_size2, 0);
-+ qcom_read_data_dma(nandc, reg_off, data_buf + data_size1, data_size2, 0);
- reg_off += data_size2;
-
-- read_data_dma(nandc, reg_off, oob_buf + oob_size1, oob_size2, 0);
-+ qcom_read_data_dma(nandc, reg_off, oob_buf + oob_size1, oob_size2, 0);
-
-- ret = submit_descs(nandc);
-+ ret = qcom_submit_descs(nandc);
- if (ret) {
- dev_err(nandc->dev, "failure to read raw cw %d\n", cw);
- return ret;
-@@ -1575,7 +1575,7 @@ static int parse_read_errors(struct qcom
- u8 *data_buf_start = data_buf, *oob_buf_start = oob_buf;
-
- buf = (struct read_stats *)nandc->reg_read_buf;
-- nandc_dev_to_mem(nandc, true);
-+ qcom_nandc_dev_to_mem(nandc, true);
-
- for (i = 0; i < ecc->steps; i++, buf++) {
- u32 flash, buffer, erased_cw;
-@@ -1704,8 +1704,8 @@ static int read_page_ecc(struct qcom_nan
- config_nand_cw_read(chip, true, i);
-
- if (data_buf)
-- read_data_dma(nandc, FLASH_BUF_ACC, data_buf,
-- data_size, 0);
-+ qcom_read_data_dma(nandc, FLASH_BUF_ACC, data_buf,
-+ data_size, 0);
-
- /*
- * when ecc is enabled, the controller doesn't read the real
-@@ -1720,8 +1720,8 @@ static int read_page_ecc(struct qcom_nan
- for (j = 0; j < host->bbm_size; j++)
- *oob_buf++ = 0xff;
-
-- read_data_dma(nandc, FLASH_BUF_ACC + data_size,
-- oob_buf, oob_size, 0);
-+ qcom_read_data_dma(nandc, FLASH_BUF_ACC + data_size,
-+ oob_buf, oob_size, 0);
- }
-
- if (data_buf)
-@@ -1730,7 +1730,7 @@ static int read_page_ecc(struct qcom_nan
- oob_buf += oob_size;
- }
-
-- ret = submit_descs(nandc);
-+ ret = qcom_submit_descs(nandc);
- if (ret) {
- dev_err(nandc->dev, "failure to read page/oob\n");
- return ret;
-@@ -1751,7 +1751,7 @@ static int copy_last_cw(struct qcom_nand
- int size;
- int ret;
-
-- clear_read_regs(nandc);
-+ qcom_clear_read_regs(nandc);
-
- size = host->use_ecc ? host->cw_data : host->cw_size;
-
-@@ -1763,9 +1763,9 @@ static int copy_last_cw(struct qcom_nand
-
- config_nand_single_cw_page_read(chip, host->use_ecc, ecc->steps - 1);
-
-- read_data_dma(nandc, FLASH_BUF_ACC, nandc->data_buffer, size, 0);
-+ qcom_read_data_dma(nandc, FLASH_BUF_ACC, nandc->data_buffer, size, 0);
-
-- ret = submit_descs(nandc);
-+ ret = qcom_submit_descs(nandc);
- if (ret)
- dev_err(nandc->dev, "failed to copy last codeword\n");
-
-@@ -1851,14 +1851,14 @@ static int qcom_nandc_read_page(struct n
- nandc->buf_count = 0;
- nandc->buf_start = 0;
- host->use_ecc = true;
-- clear_read_regs(nandc);
-+ qcom_clear_read_regs(nandc);
- set_address(host, 0, page);
- update_rw_regs(host, ecc->steps, true, 0);
-
- data_buf = buf;
- oob_buf = oob_required ? chip->oob_poi : NULL;
-
-- clear_bam_transaction(nandc);
-+ qcom_clear_bam_transaction(nandc);
-
- return read_page_ecc(host, data_buf, oob_buf, page);
- }
-@@ -1899,8 +1899,8 @@ static int qcom_nandc_read_oob(struct na
- if (host->nr_boot_partitions)
- qcom_nandc_codeword_fixup(host, page);
-
-- clear_read_regs(nandc);
-- clear_bam_transaction(nandc);
-+ qcom_clear_read_regs(nandc);
-+ qcom_clear_bam_transaction(nandc);
-
- host->use_ecc = true;
- set_address(host, 0, page);
-@@ -1927,8 +1927,8 @@ static int qcom_nandc_write_page(struct
- set_address(host, 0, page);
- nandc->buf_count = 0;
- nandc->buf_start = 0;
-- clear_read_regs(nandc);
-- clear_bam_transaction(nandc);
-+ qcom_clear_read_regs(nandc);
-+ qcom_clear_bam_transaction(nandc);
-
- data_buf = (u8 *)buf;
- oob_buf = chip->oob_poi;
-@@ -1949,8 +1949,8 @@ static int qcom_nandc_write_page(struct
- oob_size = ecc->bytes;
- }
-
-- write_data_dma(nandc, FLASH_BUF_ACC, data_buf, data_size,
-- i == (ecc->steps - 1) ? NAND_BAM_NO_EOT : 0);
-+ qcom_write_data_dma(nandc, FLASH_BUF_ACC, data_buf, data_size,
-+ i == (ecc->steps - 1) ? NAND_BAM_NO_EOT : 0);
-
- /*
- * when ECC is enabled, we don't really need to write anything
-@@ -1962,8 +1962,8 @@ static int qcom_nandc_write_page(struct
- if (qcom_nandc_is_last_cw(ecc, i)) {
- oob_buf += host->bbm_size;
-
-- write_data_dma(nandc, FLASH_BUF_ACC + data_size,
-- oob_buf, oob_size, 0);
-+ qcom_write_data_dma(nandc, FLASH_BUF_ACC + data_size,
-+ oob_buf, oob_size, 0);
- }
-
- config_nand_cw_write(chip);
-@@ -1972,7 +1972,7 @@ static int qcom_nandc_write_page(struct
- oob_buf += oob_size;
- }
-
-- ret = submit_descs(nandc);
-+ ret = qcom_submit_descs(nandc);
- if (ret) {
- dev_err(nandc->dev, "failure to write page\n");
- return ret;
-@@ -1997,8 +1997,8 @@ static int qcom_nandc_write_page_raw(str
- qcom_nandc_codeword_fixup(host, page);
-
- nand_prog_page_begin_op(chip, page, 0, NULL, 0);
-- clear_read_regs(nandc);
-- clear_bam_transaction(nandc);
-+ qcom_clear_read_regs(nandc);
-+ qcom_clear_bam_transaction(nandc);
-
- data_buf = (u8 *)buf;
- oob_buf = chip->oob_poi;
-@@ -2024,28 +2024,28 @@ static int qcom_nandc_write_page_raw(str
- oob_size2 = host->ecc_bytes_hw + host->spare_bytes;
- }
-
-- write_data_dma(nandc, reg_off, data_buf, data_size1,
-- NAND_BAM_NO_EOT);
-+ qcom_write_data_dma(nandc, reg_off, data_buf, data_size1,
-+ NAND_BAM_NO_EOT);
- reg_off += data_size1;
- data_buf += data_size1;
-
-- write_data_dma(nandc, reg_off, oob_buf, oob_size1,
-- NAND_BAM_NO_EOT);
-+ qcom_write_data_dma(nandc, reg_off, oob_buf, oob_size1,
-+ NAND_BAM_NO_EOT);
- reg_off += oob_size1;
- oob_buf += oob_size1;
-
-- write_data_dma(nandc, reg_off, data_buf, data_size2,
-- NAND_BAM_NO_EOT);
-+ qcom_write_data_dma(nandc, reg_off, data_buf, data_size2,
-+ NAND_BAM_NO_EOT);
- reg_off += data_size2;
- data_buf += data_size2;
-
-- write_data_dma(nandc, reg_off, oob_buf, oob_size2, 0);
-+ qcom_write_data_dma(nandc, reg_off, oob_buf, oob_size2, 0);
- oob_buf += oob_size2;
-
- config_nand_cw_write(chip);
- }
-
-- ret = submit_descs(nandc);
-+ ret = qcom_submit_descs(nandc);
- if (ret) {
- dev_err(nandc->dev, "failure to write raw page\n");
- return ret;
-@@ -2075,7 +2075,7 @@ static int qcom_nandc_write_oob(struct n
- qcom_nandc_codeword_fixup(host, page);
-
- host->use_ecc = true;
-- clear_bam_transaction(nandc);
-+ qcom_clear_bam_transaction(nandc);
-
- /* calculate the data and oob size for the last codeword/step */
- data_size = ecc->size - ((ecc->steps - 1) << 2);
-@@ -2090,11 +2090,11 @@ static int qcom_nandc_write_oob(struct n
- update_rw_regs(host, 1, false, 0);
-
- config_nand_page_write(chip);
-- write_data_dma(nandc, FLASH_BUF_ACC,
-- nandc->data_buffer, data_size + oob_size, 0);
-+ qcom_write_data_dma(nandc, FLASH_BUF_ACC,
-+ nandc->data_buffer, data_size + oob_size, 0);
- config_nand_cw_write(chip);
-
-- ret = submit_descs(nandc);
-+ ret = qcom_submit_descs(nandc);
- if (ret) {
- dev_err(nandc->dev, "failure to write oob\n");
- return ret;
-@@ -2121,7 +2121,7 @@ static int qcom_nandc_block_bad(struct n
- */
- host->use_ecc = false;
-
-- clear_bam_transaction(nandc);
-+ qcom_clear_bam_transaction(nandc);
- ret = copy_last_cw(host, page);
- if (ret)
- goto err;
-@@ -2148,8 +2148,8 @@ static int qcom_nandc_block_markbad(stru
- struct nand_ecc_ctrl *ecc = &chip->ecc;
- int page, ret;
-
-- clear_read_regs(nandc);
-- clear_bam_transaction(nandc);
-+ qcom_clear_read_regs(nandc);
-+ qcom_clear_bam_transaction(nandc);
-
- /*
- * to mark the BBM as bad, we flash the entire last codeword with 0s.
-@@ -2166,11 +2166,11 @@ static int qcom_nandc_block_markbad(stru
- update_rw_regs(host, 1, false, ecc->steps - 1);
-
- config_nand_page_write(chip);
-- write_data_dma(nandc, FLASH_BUF_ACC,
-- nandc->data_buffer, host->cw_size, 0);
-+ qcom_write_data_dma(nandc, FLASH_BUF_ACC,
-+ nandc->data_buffer, host->cw_size, 0);
- config_nand_cw_write(chip);
-
-- ret = submit_descs(nandc);
-+ ret = qcom_submit_descs(nandc);
- if (ret) {
- dev_err(nandc->dev, "failure to update BBM\n");
- return ret;
-@@ -2410,14 +2410,14 @@ static int qcom_nand_attach_chip(struct
- mtd_set_ooblayout(mtd, &qcom_nand_ooblayout_ops);
- /* Free the initially allocated BAM transaction for reading the ONFI params */
- if (nandc->props->supports_bam)
-- free_bam_transaction(nandc);
-+ qcom_free_bam_transaction(nandc);
-
- nandc->max_cwperpage = max_t(unsigned int, nandc->max_cwperpage,
- cwperpage);
-
- /* Now allocate the BAM transaction based on updated max_cwperpage */
- if (nandc->props->supports_bam) {
-- nandc->bam_txn = alloc_bam_transaction(nandc);
-+ nandc->bam_txn = qcom_alloc_bam_transaction(nandc);
- if (!nandc->bam_txn) {
- dev_err(nandc->dev,
- "failed to allocate bam transaction\n");
-@@ -2617,7 +2617,7 @@ static int qcom_wait_rdy_poll(struct nan
- unsigned long start = jiffies + msecs_to_jiffies(time_ms);
- u32 flash;
-
-- nandc_dev_to_mem(nandc, true);
-+ qcom_nandc_dev_to_mem(nandc, true);
-
- do {
- flash = le32_to_cpu(nandc->reg_read_buf[0]);
-@@ -2657,23 +2657,23 @@ static int qcom_read_status_exec(struct
- nandc->buf_start = 0;
- host->use_ecc = false;
-
-- clear_read_regs(nandc);
-- clear_bam_transaction(nandc);
-+ qcom_clear_read_regs(nandc);
-+ qcom_clear_bam_transaction(nandc);
-
- nandc->regs->cmd = q_op.cmd_reg;
- nandc->regs->exec = cpu_to_le32(1);
-
-- write_reg_dma(nandc, &nandc->regs->cmd, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
-- write_reg_dma(nandc, &nandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
-- read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL);
-+ qcom_write_reg_dma(nandc, &nandc->regs->cmd, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
-+ qcom_write_reg_dma(nandc, &nandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
-+ qcom_read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL);
-
-- ret = submit_descs(nandc);
-+ ret = qcom_submit_descs(nandc);
- if (ret) {
- dev_err(nandc->dev, "failure in submitting status descriptor\n");
- goto err_out;
- }
-
-- nandc_dev_to_mem(nandc, true);
-+ qcom_nandc_dev_to_mem(nandc, true);
-
- for (i = 0; i < num_cw; i++) {
- flash_status = le32_to_cpu(nandc->reg_read_buf[i]);
-@@ -2714,8 +2714,8 @@ static int qcom_read_id_type_exec(struct
- nandc->buf_start = 0;
- host->use_ecc = false;
-
-- clear_read_regs(nandc);
-- clear_bam_transaction(nandc);
-+ qcom_clear_read_regs(nandc);
-+ qcom_clear_bam_transaction(nandc);
-
- nandc->regs->cmd = q_op.cmd_reg;
- nandc->regs->addr0 = q_op.addr1_reg;
-@@ -2723,12 +2723,12 @@ static int qcom_read_id_type_exec(struct
- nandc->regs->chip_sel = cpu_to_le32(nandc->props->supports_bam ? 0 : DM_EN);
- nandc->regs->exec = cpu_to_le32(1);
-
-- write_reg_dma(nandc, &nandc->regs->cmd, NAND_FLASH_CMD, 4, NAND_BAM_NEXT_SGL);
-- write_reg_dma(nandc, &nandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
-+ qcom_write_reg_dma(nandc, &nandc->regs->cmd, NAND_FLASH_CMD, 4, NAND_BAM_NEXT_SGL);
-+ qcom_write_reg_dma(nandc, &nandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
-
-- read_reg_dma(nandc, NAND_READ_ID, 1, NAND_BAM_NEXT_SGL);
-+ qcom_read_reg_dma(nandc, NAND_READ_ID, 1, NAND_BAM_NEXT_SGL);
-
-- ret = submit_descs(nandc);
-+ ret = qcom_submit_descs(nandc);
- if (ret) {
- dev_err(nandc->dev, "failure in submitting read id descriptor\n");
- goto err_out;
-@@ -2738,7 +2738,7 @@ static int qcom_read_id_type_exec(struct
- op_id = q_op.data_instr_idx;
- len = nand_subop_get_data_len(subop, op_id);
-
-- nandc_dev_to_mem(nandc, true);
-+ qcom_nandc_dev_to_mem(nandc, true);
- memcpy(instr->ctx.data.buf.in, nandc->reg_read_buf, len);
-
- err_out:
-@@ -2774,20 +2774,20 @@ static int qcom_misc_cmd_type_exec(struc
- nandc->buf_start = 0;
- host->use_ecc = false;
-
-- clear_read_regs(nandc);
-- clear_bam_transaction(nandc);
-+ qcom_clear_read_regs(nandc);
-+ qcom_clear_bam_transaction(nandc);
-
- nandc->regs->cmd = q_op.cmd_reg;
- nandc->regs->exec = cpu_to_le32(1);
-
-- write_reg_dma(nandc, &nandc->regs->cmd, NAND_FLASH_CMD, instrs, NAND_BAM_NEXT_SGL);
-+ qcom_write_reg_dma(nandc, &nandc->regs->cmd, NAND_FLASH_CMD, instrs, NAND_BAM_NEXT_SGL);
- if (q_op.cmd_reg == cpu_to_le32(OP_BLOCK_ERASE))
-- write_reg_dma(nandc, &nandc->regs->cfg0, NAND_DEV0_CFG0, 2, NAND_BAM_NEXT_SGL);
-+ qcom_write_reg_dma(nandc, &nandc->regs->cfg0, NAND_DEV0_CFG0, 2, NAND_BAM_NEXT_SGL);
-
-- write_reg_dma(nandc, &nandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
-- read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL);
-+ qcom_write_reg_dma(nandc, &nandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
-+ qcom_read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL);
-
-- ret = submit_descs(nandc);
-+ ret = qcom_submit_descs(nandc);
- if (ret) {
- dev_err(nandc->dev, "failure in submitting misc descriptor\n");
- goto err_out;
-@@ -2825,8 +2825,8 @@ static int qcom_param_page_type_exec(str
- nandc->buf_count = 0;
- nandc->buf_start = 0;
- host->use_ecc = false;
-- clear_read_regs(nandc);
-- clear_bam_transaction(nandc);
-+ qcom_clear_read_regs(nandc);
-+ qcom_clear_bam_transaction(nandc);
-
- nandc->regs->cmd = q_op.cmd_reg;
- nandc->regs->addr0 = 0;
-@@ -2872,8 +2872,8 @@ static int qcom_param_page_type_exec(str
- nandc_set_read_loc_first(chip, reg_base, 0, len, 1);
-
- if (!nandc->props->qpic_version2) {
-- write_reg_dma(nandc, &nandc->regs->vld, NAND_DEV_CMD_VLD, 1, 0);
-- write_reg_dma(nandc, &nandc->regs->cmd1, NAND_DEV_CMD1, 1, NAND_BAM_NEXT_SGL);
-+ qcom_write_reg_dma(nandc, &nandc->regs->vld, NAND_DEV_CMD_VLD, 1, 0);
-+ qcom_write_reg_dma(nandc, &nandc->regs->cmd1, NAND_DEV_CMD1, 1, NAND_BAM_NEXT_SGL);
- }
-
- nandc->buf_count = 512;
-@@ -2881,17 +2881,17 @@ static int qcom_param_page_type_exec(str
-
- config_nand_single_cw_page_read(chip, false, 0);
-
-- read_data_dma(nandc, FLASH_BUF_ACC, nandc->data_buffer,
-- nandc->buf_count, 0);
-+ qcom_read_data_dma(nandc, FLASH_BUF_ACC, nandc->data_buffer,
-+ nandc->buf_count, 0);
-
- /* restore CMD1 and VLD regs */
- if (!nandc->props->qpic_version2) {
-- write_reg_dma(nandc, &nandc->regs->orig_cmd1, NAND_DEV_CMD1_RESTORE, 1, 0);
-- write_reg_dma(nandc, &nandc->regs->orig_vld, NAND_DEV_CMD_VLD_RESTORE, 1,
-- NAND_BAM_NEXT_SGL);
-+ qcom_write_reg_dma(nandc, &nandc->regs->orig_cmd1, NAND_DEV_CMD1_RESTORE, 1, 0);
-+ qcom_write_reg_dma(nandc, &nandc->regs->orig_vld, NAND_DEV_CMD_VLD_RESTORE, 1,
-+ NAND_BAM_NEXT_SGL);
- }
-
-- ret = submit_descs(nandc);
-+ ret = qcom_submit_descs(nandc);
- if (ret) {
- dev_err(nandc->dev, "failure in submitting param page descriptor\n");
- goto err_out;
-@@ -3075,7 +3075,7 @@ static int qcom_nandc_alloc(struct qcom_
- * maximum codeword size
- */
- nandc->max_cwperpage = 1;
-- nandc->bam_txn = alloc_bam_transaction(nandc);
-+ nandc->bam_txn = qcom_alloc_bam_transaction(nandc);
- if (!nandc->bam_txn) {
- dev_err(nandc->dev,
- "failed to allocate bam transaction\n");
+++ /dev/null
-From fdf3ee5c6e5278dab4f60b998b47ed2d510bf80f Mon Sep 17 00:00:00 2001
-Date: Wed, 20 Nov 2024 14:45:02 +0530
-Subject: [PATCH 3/4] mtd: nand: Add qpic_common API file
-
-Add qpic_common.c file which hold all the common
-qpic APIs which will be used by both qpic raw nand
-driver and qpic spi nand driver.
-
----
- drivers/mtd/nand/Makefile | 2 +-
- drivers/mtd/nand/qpic_common.c | 759 ++++++++++++++++++
- drivers/mtd/nand/raw/qcom_nandc.c | 1092 +-------------------------
- include/linux/mtd/nand-qpic-common.h | 468 +++++++++++
- 4 files changed, 1240 insertions(+), 1081 deletions(-)
- create mode 100644 drivers/mtd/nand/qpic_common.c
- create mode 100644 include/linux/mtd/nand-qpic-common.h
-
---- a/drivers/mtd/nand/Makefile
-+++ b/drivers/mtd/nand/Makefile
-@@ -3,7 +3,7 @@
- nandcore-objs := core.o bbt.o
- obj-$(CONFIG_MTD_NAND_CORE) += nandcore.o
- obj-$(CONFIG_MTD_NAND_ECC_MEDIATEK) += ecc-mtk.o
--
-+obj-$(CONFIG_MTD_NAND_QCOM) += qpic_common.o
- obj-y += onenand/
- obj-y += raw/
- obj-y += spi/
---- /dev/null
-+++ b/drivers/mtd/nand/qpic_common.c
-@@ -0,0 +1,759 @@
-+// SPDX-License-Identifier: GPL-2.0-only
-+/*
-+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
-+ * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved
-+ */
-+#include <linux/clk.h>
-+#include <linux/delay.h>
-+#include <linux/dmaengine.h>
-+#include <linux/dma-mapping.h>
-+#include <linux/dma/qcom_adm.h>
-+#include <linux/dma/qcom_bam_dma.h>
-+#include <linux/module.h>
-+#include <linux/of.h>
-+#include <linux/platform_device.h>
-+#include <linux/slab.h>
-+#include <linux/mtd/nand-qpic-common.h>
-+
-+/**
-+ * qcom_free_bam_transaction() - Frees the BAM transaction memory
-+ * @nandc: qpic nand controller
-+ *
-+ * This function frees the bam transaction memory
-+ */
-+void qcom_free_bam_transaction(struct qcom_nand_controller *nandc)
-+{
-+ struct bam_transaction *bam_txn = nandc->bam_txn;
-+
-+ kfree(bam_txn);
-+}
-+EXPORT_SYMBOL(qcom_free_bam_transaction);
-+
-+/**
-+ * qcom_alloc_bam_transaction() - allocate BAM transaction
-+ * @nandc: qpic nand controller
-+ *
-+ * This function will allocate and initialize the BAM transaction structure
-+ */
-+struct bam_transaction *
-+qcom_alloc_bam_transaction(struct qcom_nand_controller *nandc)
-+{
-+ struct bam_transaction *bam_txn;
-+ size_t bam_txn_size;
-+ unsigned int num_cw = nandc->max_cwperpage;
-+ void *bam_txn_buf;
-+
-+ bam_txn_size =
-+ sizeof(*bam_txn) + num_cw *
-+ ((sizeof(*bam_txn->bam_ce) * QPIC_PER_CW_CMD_ELEMENTS) +
-+ (sizeof(*bam_txn->cmd_sgl) * QPIC_PER_CW_CMD_SGL) +
-+ (sizeof(*bam_txn->data_sgl) * QPIC_PER_CW_DATA_SGL));
-+
-+ bam_txn_buf = kzalloc(bam_txn_size, GFP_KERNEL);
-+ if (!bam_txn_buf)
-+ return NULL;
-+
-+ bam_txn = bam_txn_buf;
-+ bam_txn_buf += sizeof(*bam_txn);
-+
-+ bam_txn->bam_ce = bam_txn_buf;
-+ bam_txn_buf +=
-+ sizeof(*bam_txn->bam_ce) * QPIC_PER_CW_CMD_ELEMENTS * num_cw;
-+
-+ bam_txn->cmd_sgl = bam_txn_buf;
-+ bam_txn_buf +=
-+ sizeof(*bam_txn->cmd_sgl) * QPIC_PER_CW_CMD_SGL * num_cw;
-+
-+ bam_txn->data_sgl = bam_txn_buf;
-+
-+ init_completion(&bam_txn->txn_done);
-+
-+ return bam_txn;
-+}
-+EXPORT_SYMBOL(qcom_alloc_bam_transaction);
-+
-+/**
-+ * qcom_clear_bam_transaction() - Clears the BAM transaction
-+ * @nandc: qpic nand controller
-+ *
-+ * This function will clear the BAM transaction indexes.
-+ */
-+void qcom_clear_bam_transaction(struct qcom_nand_controller *nandc)
-+{
-+ struct bam_transaction *bam_txn = nandc->bam_txn;
-+
-+ if (!nandc->props->supports_bam)
-+ return;
-+
-+ memset(&bam_txn->bam_ce_pos, 0, sizeof(u32) * 8);
-+ bam_txn->last_data_desc = NULL;
-+
-+ sg_init_table(bam_txn->cmd_sgl, nandc->max_cwperpage *
-+ QPIC_PER_CW_CMD_SGL);
-+ sg_init_table(bam_txn->data_sgl, nandc->max_cwperpage *
-+ QPIC_PER_CW_DATA_SGL);
-+
-+ reinit_completion(&bam_txn->txn_done);
-+}
-+EXPORT_SYMBOL(qcom_clear_bam_transaction);
-+
-+/**
-+ * qcom_qpic_bam_dma_done() - Callback for DMA descriptor completion
-+ * @data: data pointer
-+ *
-+ * This function is a callback for DMA descriptor completion
-+ */
-+void qcom_qpic_bam_dma_done(void *data)
-+{
-+ struct bam_transaction *bam_txn = data;
-+
-+ complete(&bam_txn->txn_done);
-+}
-+EXPORT_SYMBOL(qcom_qpic_bam_dma_done);
-+
-+/**
-+ * qcom_nandc_dev_to_mem() - Check for dma sync for cpu or device
-+ * @nandc: qpic nand controller
-+ * @is_cpu: cpu or Device
-+ *
-+ * This function will check for dma sync for cpu or device
-+ */
-+inline void qcom_nandc_dev_to_mem(struct qcom_nand_controller *nandc, bool is_cpu)
-+{
-+ if (!nandc->props->supports_bam)
-+ return;
-+
-+ if (is_cpu)
-+ dma_sync_single_for_cpu(nandc->dev, nandc->reg_read_dma,
-+ MAX_REG_RD *
-+ sizeof(*nandc->reg_read_buf),
-+ DMA_FROM_DEVICE);
-+ else
-+ dma_sync_single_for_device(nandc->dev, nandc->reg_read_dma,
-+ MAX_REG_RD *
-+ sizeof(*nandc->reg_read_buf),
-+ DMA_FROM_DEVICE);
-+}
-+EXPORT_SYMBOL(qcom_nandc_dev_to_mem);
-+
-+/**
-+ * qcom_prepare_bam_async_desc() - Prepare DMA descriptor
-+ * @nandc: qpic nand controller
-+ * @chan: dma channel
-+ * @flags: flags to control DMA descriptor preparation
-+ *
-+ * This function maps the scatter gather list for DMA transfer and forms the
-+ * DMA descriptor for BAM.This descriptor will be added in the NAND DMA
-+ * descriptor queue which will be submitted to DMA engine.
-+ */
-+int qcom_prepare_bam_async_desc(struct qcom_nand_controller *nandc,
-+ struct dma_chan *chan, unsigned long flags)
-+{
-+ struct desc_info *desc;
-+ struct scatterlist *sgl;
-+ unsigned int sgl_cnt;
-+ int ret;
-+ struct bam_transaction *bam_txn = nandc->bam_txn;
-+ enum dma_transfer_direction dir_eng;
-+ struct dma_async_tx_descriptor *dma_desc;
-+
-+ desc = kzalloc(sizeof(*desc), GFP_KERNEL);
-+ if (!desc)
-+ return -ENOMEM;
-+
-+ if (chan == nandc->cmd_chan) {
-+ sgl = &bam_txn->cmd_sgl[bam_txn->cmd_sgl_start];
-+ sgl_cnt = bam_txn->cmd_sgl_pos - bam_txn->cmd_sgl_start;
-+ bam_txn->cmd_sgl_start = bam_txn->cmd_sgl_pos;
-+ dir_eng = DMA_MEM_TO_DEV;
-+ desc->dir = DMA_TO_DEVICE;
-+ } else if (chan == nandc->tx_chan) {
-+ sgl = &bam_txn->data_sgl[bam_txn->tx_sgl_start];
-+ sgl_cnt = bam_txn->tx_sgl_pos - bam_txn->tx_sgl_start;
-+ bam_txn->tx_sgl_start = bam_txn->tx_sgl_pos;
-+ dir_eng = DMA_MEM_TO_DEV;
-+ desc->dir = DMA_TO_DEVICE;
-+ } else {
-+ sgl = &bam_txn->data_sgl[bam_txn->rx_sgl_start];
-+ sgl_cnt = bam_txn->rx_sgl_pos - bam_txn->rx_sgl_start;
-+ bam_txn->rx_sgl_start = bam_txn->rx_sgl_pos;
-+ dir_eng = DMA_DEV_TO_MEM;
-+ desc->dir = DMA_FROM_DEVICE;
-+ }
-+
-+ sg_mark_end(sgl + sgl_cnt - 1);
-+ ret = dma_map_sg(nandc->dev, sgl, sgl_cnt, desc->dir);
-+ if (ret == 0) {
-+ dev_err(nandc->dev, "failure in mapping desc\n");
-+ kfree(desc);
-+ return -ENOMEM;
-+ }
-+
-+ desc->sgl_cnt = sgl_cnt;
-+ desc->bam_sgl = sgl;
-+
-+ dma_desc = dmaengine_prep_slave_sg(chan, sgl, sgl_cnt, dir_eng,
-+ flags);
-+
-+ if (!dma_desc) {
-+ dev_err(nandc->dev, "failure in prep desc\n");
-+ dma_unmap_sg(nandc->dev, sgl, sgl_cnt, desc->dir);
-+ kfree(desc);
-+ return -EINVAL;
-+ }
-+
-+ desc->dma_desc = dma_desc;
-+
-+ /* update last data/command descriptor */
-+ if (chan == nandc->cmd_chan)
-+ bam_txn->last_cmd_desc = dma_desc;
-+ else
-+ bam_txn->last_data_desc = dma_desc;
-+
-+ list_add_tail(&desc->node, &nandc->desc_list);
-+
-+ return 0;
-+}
-+EXPORT_SYMBOL(qcom_prepare_bam_async_desc);
-+
-+/**
-+ * qcom_prep_bam_dma_desc_cmd() - Prepares the command descriptor for BAM DMA
-+ * @nandc: qpic nand controller
-+ * @read: read or write type
-+ * @reg_off: offset within the controller's data buffer
-+ * @vaddr: virtual address of the buffer we want to write to
-+ * @size: DMA transaction size in bytes
-+ * @flags: flags to control DMA descriptor preparation
-+ *
-+ * This function will prepares the command descriptor for BAM DMA
-+ * which will be used for NAND register reads and writes.
-+ */
-+int qcom_prep_bam_dma_desc_cmd(struct qcom_nand_controller *nandc, bool read,
-+ int reg_off, const void *vaddr,
-+ int size, unsigned int flags)
-+{
-+ int bam_ce_size;
-+ int i, ret;
-+ struct bam_cmd_element *bam_ce_buffer;
-+ struct bam_transaction *bam_txn = nandc->bam_txn;
-+
-+ bam_ce_buffer = &bam_txn->bam_ce[bam_txn->bam_ce_pos];
-+
-+ /* fill the command desc */
-+ for (i = 0; i < size; i++) {
-+ if (read)
-+ bam_prep_ce(&bam_ce_buffer[i],
-+ nandc_reg_phys(nandc, reg_off + 4 * i),
-+ BAM_READ_COMMAND,
-+ reg_buf_dma_addr(nandc,
-+ (__le32 *)vaddr + i));
-+ else
-+ bam_prep_ce_le32(&bam_ce_buffer[i],
-+ nandc_reg_phys(nandc, reg_off + 4 * i),
-+ BAM_WRITE_COMMAND,
-+ *((__le32 *)vaddr + i));
-+ }
-+
-+ bam_txn->bam_ce_pos += size;
-+
-+ /* use the separate sgl after this command */
-+ if (flags & NAND_BAM_NEXT_SGL) {
-+ bam_ce_buffer = &bam_txn->bam_ce[bam_txn->bam_ce_start];
-+ bam_ce_size = (bam_txn->bam_ce_pos -
-+ bam_txn->bam_ce_start) *
-+ sizeof(struct bam_cmd_element);
-+ sg_set_buf(&bam_txn->cmd_sgl[bam_txn->cmd_sgl_pos],
-+ bam_ce_buffer, bam_ce_size);
-+ bam_txn->cmd_sgl_pos++;
-+ bam_txn->bam_ce_start = bam_txn->bam_ce_pos;
-+
-+ if (flags & NAND_BAM_NWD) {
-+ ret = qcom_prepare_bam_async_desc(nandc, nandc->cmd_chan,
-+ DMA_PREP_FENCE | DMA_PREP_CMD);
-+ if (ret)
-+ return ret;
-+ }
-+ }
-+
-+ return 0;
-+}
-+EXPORT_SYMBOL(qcom_prep_bam_dma_desc_cmd);
-+
-+/**
-+ * qcom_prep_bam_dma_desc_data() - Prepares the data descriptor for BAM DMA
-+ * @nandc: qpic nand controller
-+ * @read: read or write type
-+ * @vaddr: virtual address of the buffer we want to write to
-+ * @size: DMA transaction size in bytes
-+ * @flags: flags to control DMA descriptor preparation
-+ *
-+ * This function will prepares the data descriptor for BAM DMA which
-+ * will be used for NAND data reads and writes.
-+ */
-+int qcom_prep_bam_dma_desc_data(struct qcom_nand_controller *nandc, bool read,
-+ const void *vaddr, int size, unsigned int flags)
-+{
-+ int ret;
-+ struct bam_transaction *bam_txn = nandc->bam_txn;
-+
-+ if (read) {
-+ sg_set_buf(&bam_txn->data_sgl[bam_txn->rx_sgl_pos],
-+ vaddr, size);
-+ bam_txn->rx_sgl_pos++;
-+ } else {
-+ sg_set_buf(&bam_txn->data_sgl[bam_txn->tx_sgl_pos],
-+ vaddr, size);
-+ bam_txn->tx_sgl_pos++;
-+
-+ /*
-+ * BAM will only set EOT for DMA_PREP_INTERRUPT so if this flag
-+ * is not set, form the DMA descriptor
-+ */
-+ if (!(flags & NAND_BAM_NO_EOT)) {
-+ ret = qcom_prepare_bam_async_desc(nandc, nandc->tx_chan,
-+ DMA_PREP_INTERRUPT);
-+ if (ret)
-+ return ret;
-+ }
-+ }
-+
-+ return 0;
-+}
-+EXPORT_SYMBOL(qcom_prep_bam_dma_desc_data);
-+
-+/**
-+ * qcom_prep_adm_dma_desc() - Prepare descriptor for adma
-+ * @nandc: qpic nand controller
-+ * @read: read or write type
-+ * @reg_off: offset within the controller's data buffer
-+ * @vaddr: virtual address of the buffer we want to write to
-+ * @size: adm dma transaction size in bytes
-+ * @flow_control: flow controller
-+ *
-+ * This function will prepare descriptor for adma
-+ */
-+int qcom_prep_adm_dma_desc(struct qcom_nand_controller *nandc, bool read,
-+ int reg_off, const void *vaddr, int size,
-+ bool flow_control)
-+{
-+ struct qcom_adm_peripheral_config periph_conf = {};
-+ struct dma_async_tx_descriptor *dma_desc;
-+ struct dma_slave_config slave_conf = {0};
-+ enum dma_transfer_direction dir_eng;
-+ struct desc_info *desc;
-+ struct scatterlist *sgl;
-+ int ret;
-+
-+ desc = kzalloc(sizeof(*desc), GFP_KERNEL);
-+ if (!desc)
-+ return -ENOMEM;
-+
-+ sgl = &desc->adm_sgl;
-+
-+ sg_init_one(sgl, vaddr, size);
-+
-+ if (read) {
-+ dir_eng = DMA_DEV_TO_MEM;
-+ desc->dir = DMA_FROM_DEVICE;
-+ } else {
-+ dir_eng = DMA_MEM_TO_DEV;
-+ desc->dir = DMA_TO_DEVICE;
-+ }
-+
-+ ret = dma_map_sg(nandc->dev, sgl, 1, desc->dir);
-+ if (!ret) {
-+ ret = -ENOMEM;
-+ goto err;
-+ }
-+
-+ slave_conf.device_fc = flow_control;
-+ if (read) {
-+ slave_conf.src_maxburst = 16;
-+ slave_conf.src_addr = nandc->base_dma + reg_off;
-+ if (nandc->data_crci) {
-+ periph_conf.crci = nandc->data_crci;
-+ slave_conf.peripheral_config = &periph_conf;
-+ slave_conf.peripheral_size = sizeof(periph_conf);
-+ }
-+ } else {
-+ slave_conf.dst_maxburst = 16;
-+ slave_conf.dst_addr = nandc->base_dma + reg_off;
-+ if (nandc->cmd_crci) {
-+ periph_conf.crci = nandc->cmd_crci;
-+ slave_conf.peripheral_config = &periph_conf;
-+ slave_conf.peripheral_size = sizeof(periph_conf);
-+ }
-+ }
-+
-+ ret = dmaengine_slave_config(nandc->chan, &slave_conf);
-+ if (ret) {
-+ dev_err(nandc->dev, "failed to configure dma channel\n");
-+ goto err;
-+ }
-+
-+ dma_desc = dmaengine_prep_slave_sg(nandc->chan, sgl, 1, dir_eng, 0);
-+ if (!dma_desc) {
-+ dev_err(nandc->dev, "failed to prepare desc\n");
-+ ret = -EINVAL;
-+ goto err;
-+ }
-+
-+ desc->dma_desc = dma_desc;
-+
-+ list_add_tail(&desc->node, &nandc->desc_list);
-+
-+ return 0;
-+err:
-+ kfree(desc);
-+
-+ return ret;
-+}
-+EXPORT_SYMBOL(qcom_prep_adm_dma_desc);
-+
-+/**
-+ * qcom_read_reg_dma() - read a given number of registers to the reg_read_buf pointer
-+ * @nandc: qpic nand controller
-+ * @first: offset of the first register in the contiguous block
-+ * @num_regs: number of registers to read
-+ * @flags: flags to control DMA descriptor preparation
-+ *
-+ * This function will prepares a descriptor to read a given number of
-+ * contiguous registers to the reg_read_buf pointer.
-+ */
-+int qcom_read_reg_dma(struct qcom_nand_controller *nandc, int first,
-+ int num_regs, unsigned int flags)
-+{
-+ bool flow_control = false;
-+ void *vaddr;
-+
-+ vaddr = nandc->reg_read_buf + nandc->reg_read_pos;
-+ nandc->reg_read_pos += num_regs;
-+
-+ if (first == NAND_DEV_CMD_VLD || first == NAND_DEV_CMD1)
-+ first = dev_cmd_reg_addr(nandc, first);
-+
-+ if (nandc->props->supports_bam)
-+ return qcom_prep_bam_dma_desc_cmd(nandc, true, first, vaddr,
-+ num_regs, flags);
-+
-+ if (first == NAND_READ_ID || first == NAND_FLASH_STATUS)
-+ flow_control = true;
-+
-+ return qcom_prep_adm_dma_desc(nandc, true, first, vaddr,
-+ num_regs * sizeof(u32), flow_control);
-+}
-+EXPORT_SYMBOL(qcom_read_reg_dma);
-+
-+/**
-+ * qcom_write_reg_dma() - write a given number of registers
-+ * @nandc: qpic nand controller
-+ * @vaddr: contiguous memory from where register value will
-+ * be written
-+ * @first: offset of the first register in the contiguous block
-+ * @num_regs: number of registers to write
-+ * @flags: flags to control DMA descriptor preparation
-+ *
-+ * This function will prepares a descriptor to write a given number of
-+ * contiguous registers
-+ */
-+int qcom_write_reg_dma(struct qcom_nand_controller *nandc, __le32 *vaddr,
-+ int first, int num_regs, unsigned int flags)
-+{
-+ bool flow_control = false;
-+
-+ if (first == NAND_EXEC_CMD)
-+ flags |= NAND_BAM_NWD;
-+
-+ if (first == NAND_DEV_CMD1_RESTORE || first == NAND_DEV_CMD1)
-+ first = dev_cmd_reg_addr(nandc, NAND_DEV_CMD1);
-+
-+ if (first == NAND_DEV_CMD_VLD_RESTORE || first == NAND_DEV_CMD_VLD)
-+ first = dev_cmd_reg_addr(nandc, NAND_DEV_CMD_VLD);
-+
-+ if (nandc->props->supports_bam)
-+ return qcom_prep_bam_dma_desc_cmd(nandc, false, first, vaddr,
-+ num_regs, flags);
-+
-+ if (first == NAND_FLASH_CMD)
-+ flow_control = true;
-+
-+ return qcom_prep_adm_dma_desc(nandc, false, first, vaddr,
-+ num_regs * sizeof(u32), flow_control);
-+}
-+EXPORT_SYMBOL(qcom_write_reg_dma);
-+
-+/**
-+ * qcom_read_data_dma() - transfer data
-+ * @nandc: qpic nand controller
-+ * @reg_off: offset within the controller's data buffer
-+ * @vaddr: virtual address of the buffer we want to write to
-+ * @size: DMA transaction size in bytes
-+ * @flags: flags to control DMA descriptor preparation
-+ *
-+ * This function will prepares a DMA descriptor to transfer data from the
-+ * controller's internal buffer to the buffer 'vaddr'
-+ */
-+int qcom_read_data_dma(struct qcom_nand_controller *nandc, int reg_off,
-+ const u8 *vaddr, int size, unsigned int flags)
-+{
-+ if (nandc->props->supports_bam)
-+ return qcom_prep_bam_dma_desc_data(nandc, true, vaddr, size, flags);
-+
-+ return qcom_prep_adm_dma_desc(nandc, true, reg_off, vaddr, size, false);
-+}
-+EXPORT_SYMBOL(qcom_read_data_dma);
-+
-+/**
-+ * qcom_write_data_dma() - transfer data
-+ * @nandc: qpic nand controller
-+ * @reg_off: offset within the controller's data buffer
-+ * @vaddr: virtual address of the buffer we want to read from
-+ * @size: DMA transaction size in bytes
-+ * @flags: flags to control DMA descriptor preparation
-+ *
-+ * This function will prepares a DMA descriptor to transfer data from
-+ * 'vaddr' to the controller's internal buffer
-+ */
-+int qcom_write_data_dma(struct qcom_nand_controller *nandc, int reg_off,
-+ const u8 *vaddr, int size, unsigned int flags)
-+{
-+ if (nandc->props->supports_bam)
-+ return qcom_prep_bam_dma_desc_data(nandc, false, vaddr, size, flags);
-+
-+ return qcom_prep_adm_dma_desc(nandc, false, reg_off, vaddr, size, false);
-+}
-+EXPORT_SYMBOL(qcom_write_data_dma);
-+
-+/**
-+ * qcom_submit_descs() - submit dma descriptor
-+ * @nandc: qpic nand controller
-+ *
-+ * This function will submit all the prepared dma descriptor
-+ * cmd or data descriptor
-+ */
-+int qcom_submit_descs(struct qcom_nand_controller *nandc)
-+{
-+ struct desc_info *desc, *n;
-+ dma_cookie_t cookie = 0;
-+ struct bam_transaction *bam_txn = nandc->bam_txn;
-+ int ret = 0;
-+
-+ if (nandc->props->supports_bam) {
-+ if (bam_txn->rx_sgl_pos > bam_txn->rx_sgl_start) {
-+ ret = qcom_prepare_bam_async_desc(nandc, nandc->rx_chan, 0);
-+ if (ret)
-+ goto err_unmap_free_desc;
-+ }
-+
-+ if (bam_txn->tx_sgl_pos > bam_txn->tx_sgl_start) {
-+ ret = qcom_prepare_bam_async_desc(nandc, nandc->tx_chan,
-+ DMA_PREP_INTERRUPT);
-+ if (ret)
-+ goto err_unmap_free_desc;
-+ }
-+
-+ if (bam_txn->cmd_sgl_pos > bam_txn->cmd_sgl_start) {
-+ ret = qcom_prepare_bam_async_desc(nandc, nandc->cmd_chan,
-+ DMA_PREP_CMD);
-+ if (ret)
-+ goto err_unmap_free_desc;
-+ }
-+ }
-+
-+ list_for_each_entry(desc, &nandc->desc_list, node)
-+ cookie = dmaengine_submit(desc->dma_desc);
-+
-+ if (nandc->props->supports_bam) {
-+ bam_txn->last_cmd_desc->callback = qcom_qpic_bam_dma_done;
-+ bam_txn->last_cmd_desc->callback_param = bam_txn;
-+
-+ dma_async_issue_pending(nandc->tx_chan);
-+ dma_async_issue_pending(nandc->rx_chan);
-+ dma_async_issue_pending(nandc->cmd_chan);
-+
-+ if (!wait_for_completion_timeout(&bam_txn->txn_done,
-+ QPIC_NAND_COMPLETION_TIMEOUT))
-+ ret = -ETIMEDOUT;
-+ } else {
-+ if (dma_sync_wait(nandc->chan, cookie) != DMA_COMPLETE)
-+ ret = -ETIMEDOUT;
-+ }
-+
-+err_unmap_free_desc:
-+ /*
-+ * Unmap the dma sg_list and free the desc allocated by both
-+ * qcom_prepare_bam_async_desc() and qcom_prep_adm_dma_desc() functions.
-+ */
-+ list_for_each_entry_safe(desc, n, &nandc->desc_list, node) {
-+ list_del(&desc->node);
-+
-+ if (nandc->props->supports_bam)
-+ dma_unmap_sg(nandc->dev, desc->bam_sgl,
-+ desc->sgl_cnt, desc->dir);
-+ else
-+ dma_unmap_sg(nandc->dev, &desc->adm_sgl, 1,
-+ desc->dir);
-+
-+ kfree(desc);
-+ }
-+
-+ return ret;
-+}
-+EXPORT_SYMBOL(qcom_submit_descs);
-+
-+/**
-+ * qcom_clear_read_regs() - reset the read register buffer
-+ * @nandc: qpic nand controller
-+ *
-+ * This function reset the register read buffer for next NAND operation
-+ */
-+void qcom_clear_read_regs(struct qcom_nand_controller *nandc)
-+{
-+ nandc->reg_read_pos = 0;
-+ qcom_nandc_dev_to_mem(nandc, false);
-+}
-+EXPORT_SYMBOL(qcom_clear_read_regs);
-+
-+/**
-+ * qcom_nandc_unalloc() - unallocate qpic nand controller
-+ * @nandc: qpic nand controller
-+ *
-+ * This function will unallocate memory alloacted for qpic nand controller
-+ */
-+void qcom_nandc_unalloc(struct qcom_nand_controller *nandc)
-+{
-+ if (nandc->props->supports_bam) {
-+ if (!dma_mapping_error(nandc->dev, nandc->reg_read_dma))
-+ dma_unmap_single(nandc->dev, nandc->reg_read_dma,
-+ MAX_REG_RD *
-+ sizeof(*nandc->reg_read_buf),
-+ DMA_FROM_DEVICE);
-+
-+ if (nandc->tx_chan)
-+ dma_release_channel(nandc->tx_chan);
-+
-+ if (nandc->rx_chan)
-+ dma_release_channel(nandc->rx_chan);
-+
-+ if (nandc->cmd_chan)
-+ dma_release_channel(nandc->cmd_chan);
-+ } else {
-+ if (nandc->chan)
-+ dma_release_channel(nandc->chan);
-+ }
-+}
-+EXPORT_SYMBOL(qcom_nandc_unalloc);
-+
-+/**
-+ * qcom_nandc_alloc() - Allocate qpic nand controller
-+ * @nandc: qpic nand controller
-+ *
-+ * This function will allocate memory for qpic nand controller
-+ */
-+int qcom_nandc_alloc(struct qcom_nand_controller *nandc)
-+{
-+ int ret;
-+
-+ ret = dma_set_coherent_mask(nandc->dev, DMA_BIT_MASK(32));
-+ if (ret) {
-+ dev_err(nandc->dev, "failed to set DMA mask\n");
-+ return ret;
-+ }
-+
-+ /*
-+ * we use the internal buffer for reading ONFI params, reading small
-+ * data like ID and status, and preforming read-copy-write operations
-+ * when writing to a codeword partially. 532 is the maximum possible
-+ * size of a codeword for our nand controller
-+ */
-+ nandc->buf_size = 532;
-+
-+ nandc->data_buffer = devm_kzalloc(nandc->dev, nandc->buf_size, GFP_KERNEL);
-+ if (!nandc->data_buffer)
-+ return -ENOMEM;
-+
-+ nandc->regs = devm_kzalloc(nandc->dev, sizeof(*nandc->regs), GFP_KERNEL);
-+ if (!nandc->regs)
-+ return -ENOMEM;
-+
-+ nandc->reg_read_buf = devm_kcalloc(nandc->dev, MAX_REG_RD,
-+ sizeof(*nandc->reg_read_buf),
-+ GFP_KERNEL);
-+ if (!nandc->reg_read_buf)
-+ return -ENOMEM;
-+
-+ if (nandc->props->supports_bam) {
-+ nandc->reg_read_dma =
-+ dma_map_single(nandc->dev, nandc->reg_read_buf,
-+ MAX_REG_RD *
-+ sizeof(*nandc->reg_read_buf),
-+ DMA_FROM_DEVICE);
-+ if (dma_mapping_error(nandc->dev, nandc->reg_read_dma)) {
-+ dev_err(nandc->dev, "failed to DMA MAP reg buffer\n");
-+ return -EIO;
-+ }
-+
-+ nandc->tx_chan = dma_request_chan(nandc->dev, "tx");
-+ if (IS_ERR(nandc->tx_chan)) {
-+ ret = PTR_ERR(nandc->tx_chan);
-+ nandc->tx_chan = NULL;
-+ dev_err_probe(nandc->dev, ret,
-+ "tx DMA channel request failed\n");
-+ goto unalloc;
-+ }
-+
-+ nandc->rx_chan = dma_request_chan(nandc->dev, "rx");
-+ if (IS_ERR(nandc->rx_chan)) {
-+ ret = PTR_ERR(nandc->rx_chan);
-+ nandc->rx_chan = NULL;
-+ dev_err_probe(nandc->dev, ret,
-+ "rx DMA channel request failed\n");
-+ goto unalloc;
-+ }
-+
-+ nandc->cmd_chan = dma_request_chan(nandc->dev, "cmd");
-+ if (IS_ERR(nandc->cmd_chan)) {
-+ ret = PTR_ERR(nandc->cmd_chan);
-+ nandc->cmd_chan = NULL;
-+ dev_err_probe(nandc->dev, ret,
-+ "cmd DMA channel request failed\n");
-+ goto unalloc;
-+ }
-+
-+ /*
-+ * Initially allocate BAM transaction to read ONFI param page.
-+ * After detecting all the devices, this BAM transaction will
-+ * be freed and the next BAM transaction will be allocated with
-+ * maximum codeword size
-+ */
-+ nandc->max_cwperpage = 1;
-+ nandc->bam_txn = qcom_alloc_bam_transaction(nandc);
-+ if (!nandc->bam_txn) {
-+ dev_err(nandc->dev,
-+ "failed to allocate bam transaction\n");
-+ ret = -ENOMEM;
-+ goto unalloc;
-+ }
-+ } else {
-+ nandc->chan = dma_request_chan(nandc->dev, "rxtx");
-+ if (IS_ERR(nandc->chan)) {
-+ ret = PTR_ERR(nandc->chan);
-+ nandc->chan = NULL;
-+ dev_err_probe(nandc->dev, ret,
-+ "rxtx DMA channel request failed\n");
-+ return ret;
-+ }
-+ }
-+
-+ INIT_LIST_HEAD(&nandc->desc_list);
-+ INIT_LIST_HEAD(&nandc->host_list);
-+
-+ return 0;
-+unalloc:
-+ qcom_nandc_unalloc(nandc);
-+ return ret;
-+}
-+EXPORT_SYMBOL(qcom_nandc_alloc);
-+
-+MODULE_DESCRIPTION("QPIC controller common api");
-+MODULE_LICENSE("GPL");
---- a/drivers/mtd/nand/raw/qcom_nandc.c
-+++ b/drivers/mtd/nand/raw/qcom_nandc.c
-@@ -15,417 +15,7 @@
- #include <linux/of.h>
- #include <linux/platform_device.h>
- #include <linux/slab.h>
--
--/* NANDc reg offsets */
--#define NAND_FLASH_CMD 0x00
--#define NAND_ADDR0 0x04
--#define NAND_ADDR1 0x08
--#define NAND_FLASH_CHIP_SELECT 0x0c
--#define NAND_EXEC_CMD 0x10
--#define NAND_FLASH_STATUS 0x14
--#define NAND_BUFFER_STATUS 0x18
--#define NAND_DEV0_CFG0 0x20
--#define NAND_DEV0_CFG1 0x24
--#define NAND_DEV0_ECC_CFG 0x28
--#define NAND_AUTO_STATUS_EN 0x2c
--#define NAND_DEV1_CFG0 0x30
--#define NAND_DEV1_CFG1 0x34
--#define NAND_READ_ID 0x40
--#define NAND_READ_STATUS 0x44
--#define NAND_DEV_CMD0 0xa0
--#define NAND_DEV_CMD1 0xa4
--#define NAND_DEV_CMD2 0xa8
--#define NAND_DEV_CMD_VLD 0xac
--#define SFLASHC_BURST_CFG 0xe0
--#define NAND_ERASED_CW_DETECT_CFG 0xe8
--#define NAND_ERASED_CW_DETECT_STATUS 0xec
--#define NAND_EBI2_ECC_BUF_CFG 0xf0
--#define FLASH_BUF_ACC 0x100
--
--#define NAND_CTRL 0xf00
--#define NAND_VERSION 0xf08
--#define NAND_READ_LOCATION_0 0xf20
--#define NAND_READ_LOCATION_1 0xf24
--#define NAND_READ_LOCATION_2 0xf28
--#define NAND_READ_LOCATION_3 0xf2c
--#define NAND_READ_LOCATION_LAST_CW_0 0xf40
--#define NAND_READ_LOCATION_LAST_CW_1 0xf44
--#define NAND_READ_LOCATION_LAST_CW_2 0xf48
--#define NAND_READ_LOCATION_LAST_CW_3 0xf4c
--
--/* dummy register offsets, used by qcom_write_reg_dma */
--#define NAND_DEV_CMD1_RESTORE 0xdead
--#define NAND_DEV_CMD_VLD_RESTORE 0xbeef
--
--/* NAND_FLASH_CMD bits */
--#define PAGE_ACC BIT(4)
--#define LAST_PAGE BIT(5)
--
--/* NAND_FLASH_CHIP_SELECT bits */
--#define NAND_DEV_SEL 0
--#define DM_EN BIT(2)
--
--/* NAND_FLASH_STATUS bits */
--#define FS_OP_ERR BIT(4)
--#define FS_READY_BSY_N BIT(5)
--#define FS_MPU_ERR BIT(8)
--#define FS_DEVICE_STS_ERR BIT(16)
--#define FS_DEVICE_WP BIT(23)
--
--/* NAND_BUFFER_STATUS bits */
--#define BS_UNCORRECTABLE_BIT BIT(8)
--#define BS_CORRECTABLE_ERR_MSK 0x1f
--
--/* NAND_DEVn_CFG0 bits */
--#define DISABLE_STATUS_AFTER_WRITE 4
--#define CW_PER_PAGE 6
--#define UD_SIZE_BYTES 9
--#define UD_SIZE_BYTES_MASK GENMASK(18, 9)
--#define ECC_PARITY_SIZE_BYTES_RS 19
--#define SPARE_SIZE_BYTES 23
--#define SPARE_SIZE_BYTES_MASK GENMASK(26, 23)
--#define NUM_ADDR_CYCLES 27
--#define STATUS_BFR_READ 30
--#define SET_RD_MODE_AFTER_STATUS 31
--
--/* NAND_DEVn_CFG0 bits */
--#define DEV0_CFG1_ECC_DISABLE 0
--#define WIDE_FLASH 1
--#define NAND_RECOVERY_CYCLES 2
--#define CS_ACTIVE_BSY 5
--#define BAD_BLOCK_BYTE_NUM 6
--#define BAD_BLOCK_IN_SPARE_AREA 16
--#define WR_RD_BSY_GAP 17
--#define ENABLE_BCH_ECC 27
--
--/* NAND_DEV0_ECC_CFG bits */
--#define ECC_CFG_ECC_DISABLE 0
--#define ECC_SW_RESET 1
--#define ECC_MODE 4
--#define ECC_PARITY_SIZE_BYTES_BCH 8
--#define ECC_NUM_DATA_BYTES 16
--#define ECC_NUM_DATA_BYTES_MASK GENMASK(25, 16)
--#define ECC_FORCE_CLK_OPEN 30
--
--/* NAND_DEV_CMD1 bits */
--#define READ_ADDR 0
--
--/* NAND_DEV_CMD_VLD bits */
--#define READ_START_VLD BIT(0)
--#define READ_STOP_VLD BIT(1)
--#define WRITE_START_VLD BIT(2)
--#define ERASE_START_VLD BIT(3)
--#define SEQ_READ_START_VLD BIT(4)
--
--/* NAND_EBI2_ECC_BUF_CFG bits */
--#define NUM_STEPS 0
--
--/* NAND_ERASED_CW_DETECT_CFG bits */
--#define ERASED_CW_ECC_MASK 1
--#define AUTO_DETECT_RES 0
--#define MASK_ECC BIT(ERASED_CW_ECC_MASK)
--#define RESET_ERASED_DET BIT(AUTO_DETECT_RES)
--#define ACTIVE_ERASED_DET (0 << AUTO_DETECT_RES)
--#define CLR_ERASED_PAGE_DET (RESET_ERASED_DET | MASK_ECC)
--#define SET_ERASED_PAGE_DET (ACTIVE_ERASED_DET | MASK_ECC)
--
--/* NAND_ERASED_CW_DETECT_STATUS bits */
--#define PAGE_ALL_ERASED BIT(7)
--#define CODEWORD_ALL_ERASED BIT(6)
--#define PAGE_ERASED BIT(5)
--#define CODEWORD_ERASED BIT(4)
--#define ERASED_PAGE (PAGE_ALL_ERASED | PAGE_ERASED)
--#define ERASED_CW (CODEWORD_ALL_ERASED | CODEWORD_ERASED)
--
--/* NAND_READ_LOCATION_n bits */
--#define READ_LOCATION_OFFSET 0
--#define READ_LOCATION_SIZE 16
--#define READ_LOCATION_LAST 31
--
--/* Version Mask */
--#define NAND_VERSION_MAJOR_MASK 0xf0000000
--#define NAND_VERSION_MAJOR_SHIFT 28
--#define NAND_VERSION_MINOR_MASK 0x0fff0000
--#define NAND_VERSION_MINOR_SHIFT 16
--
--/* NAND OP_CMDs */
--#define OP_PAGE_READ 0x2
--#define OP_PAGE_READ_WITH_ECC 0x3
--#define OP_PAGE_READ_WITH_ECC_SPARE 0x4
--#define OP_PAGE_READ_ONFI_READ 0x5
--#define OP_PROGRAM_PAGE 0x6
--#define OP_PAGE_PROGRAM_WITH_ECC 0x7
--#define OP_PROGRAM_PAGE_SPARE 0x9
--#define OP_BLOCK_ERASE 0xa
--#define OP_CHECK_STATUS 0xc
--#define OP_FETCH_ID 0xb
--#define OP_RESET_DEVICE 0xd
--
--/* Default Value for NAND_DEV_CMD_VLD */
--#define NAND_DEV_CMD_VLD_VAL (READ_START_VLD | WRITE_START_VLD | \
-- ERASE_START_VLD | SEQ_READ_START_VLD)
--
--/* NAND_CTRL bits */
--#define BAM_MODE_EN BIT(0)
--
--/*
-- * the NAND controller performs reads/writes with ECC in 516 byte chunks.
-- * the driver calls the chunks 'step' or 'codeword' interchangeably
-- */
--#define NANDC_STEP_SIZE 512
--
--/*
-- * the largest page size we support is 8K, this will have 16 steps/codewords
-- * of 512 bytes each
-- */
--#define MAX_NUM_STEPS (SZ_8K / NANDC_STEP_SIZE)
--
--/* we read at most 3 registers per codeword scan */
--#define MAX_REG_RD (3 * MAX_NUM_STEPS)
--
--/* ECC modes supported by the controller */
--#define ECC_NONE BIT(0)
--#define ECC_RS_4BIT BIT(1)
--#define ECC_BCH_4BIT BIT(2)
--#define ECC_BCH_8BIT BIT(3)
--
--/*
-- * Returns the actual register address for all NAND_DEV_ registers
-- * (i.e. NAND_DEV_CMD0, NAND_DEV_CMD1, NAND_DEV_CMD2 and NAND_DEV_CMD_VLD)
-- */
--#define dev_cmd_reg_addr(nandc, reg) ((nandc)->props->dev_cmd_reg_start + (reg))
--
--/* Returns the NAND register physical address */
--#define nandc_reg_phys(chip, offset) ((chip)->base_phys + (offset))
--
--/* Returns the dma address for reg read buffer */
--#define reg_buf_dma_addr(chip, vaddr) \
-- ((chip)->reg_read_dma + \
-- ((u8 *)(vaddr) - (u8 *)(chip)->reg_read_buf))
--
--#define QPIC_PER_CW_CMD_ELEMENTS 32
--#define QPIC_PER_CW_CMD_SGL 32
--#define QPIC_PER_CW_DATA_SGL 8
--
--#define QPIC_NAND_COMPLETION_TIMEOUT msecs_to_jiffies(2000)
--
--/*
-- * Flags used in DMA descriptor preparation helper functions
-- * (i.e. qcom_read_reg_dma/qcom_write_reg_dma/qcom_read_data_dma/qcom_write_data_dma)
-- */
--/* Don't set the EOT in current tx BAM sgl */
--#define NAND_BAM_NO_EOT BIT(0)
--/* Set the NWD flag in current BAM sgl */
--#define NAND_BAM_NWD BIT(1)
--/* Finish writing in the current BAM sgl and start writing in another BAM sgl */
--#define NAND_BAM_NEXT_SGL BIT(2)
--/*
-- * Erased codeword status is being used two times in single transfer so this
-- * flag will determine the current value of erased codeword status register
-- */
--#define NAND_ERASED_CW_SET BIT(4)
--
--#define MAX_ADDRESS_CYCLE 5
--
--/*
-- * This data type corresponds to the BAM transaction which will be used for all
-- * NAND transfers.
-- * @bam_ce - the array of BAM command elements
-- * @cmd_sgl - sgl for NAND BAM command pipe
-- * @data_sgl - sgl for NAND BAM consumer/producer pipe
-- * @last_data_desc - last DMA desc in data channel (tx/rx).
-- * @last_cmd_desc - last DMA desc in command channel.
-- * @txn_done - completion for NAND transfer.
-- * @bam_ce_pos - the index in bam_ce which is available for next sgl
-- * @bam_ce_start - the index in bam_ce which marks the start position ce
-- * for current sgl. It will be used for size calculation
-- * for current sgl
-- * @cmd_sgl_pos - current index in command sgl.
-- * @cmd_sgl_start - start index in command sgl.
-- * @tx_sgl_pos - current index in data sgl for tx.
-- * @tx_sgl_start - start index in data sgl for tx.
-- * @rx_sgl_pos - current index in data sgl for rx.
-- * @rx_sgl_start - start index in data sgl for rx.
-- */
--struct bam_transaction {
-- struct bam_cmd_element *bam_ce;
-- struct scatterlist *cmd_sgl;
-- struct scatterlist *data_sgl;
-- struct dma_async_tx_descriptor *last_data_desc;
-- struct dma_async_tx_descriptor *last_cmd_desc;
-- struct completion txn_done;
-- u32 bam_ce_pos;
-- u32 bam_ce_start;
-- u32 cmd_sgl_pos;
-- u32 cmd_sgl_start;
-- u32 tx_sgl_pos;
-- u32 tx_sgl_start;
-- u32 rx_sgl_pos;
-- u32 rx_sgl_start;
--};
--
--/*
-- * This data type corresponds to the nand dma descriptor
-- * @dma_desc - low level DMA engine descriptor
-- * @list - list for desc_info
-- *
-- * @adm_sgl - sgl which will be used for single sgl dma descriptor. Only used by
-- * ADM
-- * @bam_sgl - sgl which will be used for dma descriptor. Only used by BAM
-- * @sgl_cnt - number of SGL in bam_sgl. Only used by BAM
-- * @dir - DMA transfer direction
-- */
--struct desc_info {
-- struct dma_async_tx_descriptor *dma_desc;
-- struct list_head node;
--
-- union {
-- struct scatterlist adm_sgl;
-- struct {
-- struct scatterlist *bam_sgl;
-- int sgl_cnt;
-- };
-- };
-- enum dma_data_direction dir;
--};
--
--/*
-- * holds the current register values that we want to write. acts as a contiguous
-- * chunk of memory which we use to write the controller registers through DMA.
-- */
--struct nandc_regs {
-- __le32 cmd;
-- __le32 addr0;
-- __le32 addr1;
-- __le32 chip_sel;
-- __le32 exec;
--
-- __le32 cfg0;
-- __le32 cfg1;
-- __le32 ecc_bch_cfg;
--
-- __le32 clrflashstatus;
-- __le32 clrreadstatus;
--
-- __le32 cmd1;
-- __le32 vld;
--
-- __le32 orig_cmd1;
-- __le32 orig_vld;
--
-- __le32 ecc_buf_cfg;
-- __le32 read_location0;
-- __le32 read_location1;
-- __le32 read_location2;
-- __le32 read_location3;
-- __le32 read_location_last0;
-- __le32 read_location_last1;
-- __le32 read_location_last2;
-- __le32 read_location_last3;
--
-- __le32 erased_cw_detect_cfg_clr;
-- __le32 erased_cw_detect_cfg_set;
--};
--
--/*
-- * NAND controller data struct
-- *
-- * @dev: parent device
-- *
-- * @base: MMIO base
-- *
-- * @core_clk: controller clock
-- * @aon_clk: another controller clock
-- *
-- * @regs: a contiguous chunk of memory for DMA register
-- * writes. contains the register values to be
-- * written to controller
-- *
-- * @props: properties of current NAND controller,
-- * initialized via DT match data
-- *
-- * @controller: base controller structure
-- * @host_list: list containing all the chips attached to the
-- * controller
-- *
-- * @chan: dma channel
-- * @cmd_crci: ADM DMA CRCI for command flow control
-- * @data_crci: ADM DMA CRCI for data flow control
-- *
-- * @desc_list: DMA descriptor list (list of desc_infos)
-- *
-- * @data_buffer: our local DMA buffer for page read/writes,
-- * used when we can't use the buffer provided
-- * by upper layers directly
-- * @reg_read_buf: local buffer for reading back registers via DMA
-- *
-- * @base_phys: physical base address of controller registers
-- * @base_dma: dma base address of controller registers
-- * @reg_read_dma: contains dma address for register read buffer
-- *
-- * @buf_size/count/start: markers for chip->legacy.read_buf/write_buf
-- * functions
-- * @max_cwperpage: maximum QPIC codewords required. calculated
-- * from all connected NAND devices pagesize
-- *
-- * @reg_read_pos: marker for data read in reg_read_buf
-- *
-- * @cmd1/vld: some fixed controller register values
-- *
-- * @exec_opwrite: flag to select correct number of code word
-- * while reading status
-- */
--struct qcom_nand_controller {
-- struct device *dev;
--
-- void __iomem *base;
--
-- struct clk *core_clk;
-- struct clk *aon_clk;
--
-- struct nandc_regs *regs;
-- struct bam_transaction *bam_txn;
--
-- const struct qcom_nandc_props *props;
--
-- struct nand_controller controller;
-- struct list_head host_list;
--
-- union {
-- /* will be used only by QPIC for BAM DMA */
-- struct {
-- struct dma_chan *tx_chan;
-- struct dma_chan *rx_chan;
-- struct dma_chan *cmd_chan;
-- };
--
-- /* will be used only by EBI2 for ADM DMA */
-- struct {
-- struct dma_chan *chan;
-- unsigned int cmd_crci;
-- unsigned int data_crci;
-- };
-- };
--
-- struct list_head desc_list;
--
-- u8 *data_buffer;
-- __le32 *reg_read_buf;
--
-- phys_addr_t base_phys;
-- dma_addr_t base_dma;
-- dma_addr_t reg_read_dma;
--
-- int buf_size;
-- int buf_count;
-- int buf_start;
-- unsigned int max_cwperpage;
--
-- int reg_read_pos;
--
-- u32 cmd1, vld;
-- bool exec_opwrite;
--};
-+#include <linux/mtd/nand-qpic-common.h>
-
- /*
- * NAND special boot partitions
-@@ -530,97 +120,6 @@ struct qcom_nand_host {
- bool bch_enabled;
- };
-
--/*
-- * This data type corresponds to the NAND controller properties which varies
-- * among different NAND controllers.
-- * @ecc_modes - ecc mode for NAND
-- * @dev_cmd_reg_start - NAND_DEV_CMD_* registers starting offset
-- * @supports_bam - whether NAND controller is using Bus Access Manager (BAM)
-- * @nandc_part_of_qpic - whether NAND controller is part of qpic IP
-- * @qpic_version2 - flag to indicate QPIC IP version 2
-- * @use_codeword_fixup - whether NAND has different layout for boot partitions
-- */
--struct qcom_nandc_props {
-- u32 ecc_modes;
-- u32 dev_cmd_reg_start;
-- bool supports_bam;
-- bool nandc_part_of_qpic;
-- bool qpic_version2;
-- bool use_codeword_fixup;
--};
--
--/* Frees the BAM transaction memory */
--static void qcom_free_bam_transaction(struct qcom_nand_controller *nandc)
--{
-- struct bam_transaction *bam_txn = nandc->bam_txn;
--
-- devm_kfree(nandc->dev, bam_txn);
--}
--
--/* Allocates and Initializes the BAM transaction */
--static struct bam_transaction *
--qcom_alloc_bam_transaction(struct qcom_nand_controller *nandc)
--{
-- struct bam_transaction *bam_txn;
-- size_t bam_txn_size;
-- unsigned int num_cw = nandc->max_cwperpage;
-- void *bam_txn_buf;
--
-- bam_txn_size =
-- sizeof(*bam_txn) + num_cw *
-- ((sizeof(*bam_txn->bam_ce) * QPIC_PER_CW_CMD_ELEMENTS) +
-- (sizeof(*bam_txn->cmd_sgl) * QPIC_PER_CW_CMD_SGL) +
-- (sizeof(*bam_txn->data_sgl) * QPIC_PER_CW_DATA_SGL));
--
-- bam_txn_buf = devm_kzalloc(nandc->dev, bam_txn_size, GFP_KERNEL);
-- if (!bam_txn_buf)
-- return NULL;
--
-- bam_txn = bam_txn_buf;
-- bam_txn_buf += sizeof(*bam_txn);
--
-- bam_txn->bam_ce = bam_txn_buf;
-- bam_txn_buf +=
-- sizeof(*bam_txn->bam_ce) * QPIC_PER_CW_CMD_ELEMENTS * num_cw;
--
-- bam_txn->cmd_sgl = bam_txn_buf;
-- bam_txn_buf +=
-- sizeof(*bam_txn->cmd_sgl) * QPIC_PER_CW_CMD_SGL * num_cw;
--
-- bam_txn->data_sgl = bam_txn_buf;
--
-- init_completion(&bam_txn->txn_done);
--
-- return bam_txn;
--}
--
--/* Clears the BAM transaction indexes */
--static void qcom_clear_bam_transaction(struct qcom_nand_controller *nandc)
--{
-- struct bam_transaction *bam_txn = nandc->bam_txn;
--
-- if (!nandc->props->supports_bam)
-- return;
--
-- memset(&bam_txn->bam_ce_pos, 0, sizeof(u32) * 8);
-- bam_txn->last_data_desc = NULL;
--
-- sg_init_table(bam_txn->cmd_sgl, nandc->max_cwperpage *
-- QPIC_PER_CW_CMD_SGL);
-- sg_init_table(bam_txn->data_sgl, nandc->max_cwperpage *
-- QPIC_PER_CW_DATA_SGL);
--
-- reinit_completion(&bam_txn->txn_done);
--}
--
--/* Callback for DMA descriptor completion */
--static void qcom_qpic_bam_dma_done(void *data)
--{
-- struct bam_transaction *bam_txn = data;
--
-- complete(&bam_txn->txn_done);
--}
--
- static struct qcom_nand_host *to_qcom_nand_host(struct nand_chip *chip)
- {
- return container_of(chip, struct qcom_nand_host, chip);
-@@ -629,8 +128,8 @@ static struct qcom_nand_host *to_qcom_na
- static struct qcom_nand_controller *
- get_qcom_nand_controller(struct nand_chip *chip)
- {
-- return container_of(chip->controller, struct qcom_nand_controller,
-- controller);
-+ return (struct qcom_nand_controller *)
-+ ((u8 *)chip->controller - sizeof(struct qcom_nand_controller));
- }
-
- static u32 nandc_read(struct qcom_nand_controller *nandc, int offset)
-@@ -644,23 +143,6 @@ static void nandc_write(struct qcom_nand
- iowrite32(val, nandc->base + offset);
- }
-
--static void qcom_nandc_dev_to_mem(struct qcom_nand_controller *nandc, bool is_cpu)
--{
-- if (!nandc->props->supports_bam)
-- return;
--
-- if (is_cpu)
-- dma_sync_single_for_cpu(nandc->dev, nandc->reg_read_dma,
-- MAX_REG_RD *
-- sizeof(*nandc->reg_read_buf),
-- DMA_FROM_DEVICE);
-- else
-- dma_sync_single_for_device(nandc->dev, nandc->reg_read_dma,
-- MAX_REG_RD *
-- sizeof(*nandc->reg_read_buf),
-- DMA_FROM_DEVICE);
--}
--
- /* Helper to check whether this is the last CW or not */
- static bool qcom_nandc_is_last_cw(struct nand_ecc_ctrl *ecc, int cw)
- {
-@@ -820,356 +302,6 @@ static void update_rw_regs(struct qcom_n
- }
-
- /*
-- * Maps the scatter gather list for DMA transfer and forms the DMA descriptor
-- * for BAM. This descriptor will be added in the NAND DMA descriptor queue
-- * which will be submitted to DMA engine.
-- */
--static int qcom_prepare_bam_async_desc(struct qcom_nand_controller *nandc,
-- struct dma_chan *chan,
-- unsigned long flags)
--{
-- struct desc_info *desc;
-- struct scatterlist *sgl;
-- unsigned int sgl_cnt;
-- int ret;
-- struct bam_transaction *bam_txn = nandc->bam_txn;
-- enum dma_transfer_direction dir_eng;
-- struct dma_async_tx_descriptor *dma_desc;
--
-- desc = kzalloc(sizeof(*desc), GFP_KERNEL);
-- if (!desc)
-- return -ENOMEM;
--
-- if (chan == nandc->cmd_chan) {
-- sgl = &bam_txn->cmd_sgl[bam_txn->cmd_sgl_start];
-- sgl_cnt = bam_txn->cmd_sgl_pos - bam_txn->cmd_sgl_start;
-- bam_txn->cmd_sgl_start = bam_txn->cmd_sgl_pos;
-- dir_eng = DMA_MEM_TO_DEV;
-- desc->dir = DMA_TO_DEVICE;
-- } else if (chan == nandc->tx_chan) {
-- sgl = &bam_txn->data_sgl[bam_txn->tx_sgl_start];
-- sgl_cnt = bam_txn->tx_sgl_pos - bam_txn->tx_sgl_start;
-- bam_txn->tx_sgl_start = bam_txn->tx_sgl_pos;
-- dir_eng = DMA_MEM_TO_DEV;
-- desc->dir = DMA_TO_DEVICE;
-- } else {
-- sgl = &bam_txn->data_sgl[bam_txn->rx_sgl_start];
-- sgl_cnt = bam_txn->rx_sgl_pos - bam_txn->rx_sgl_start;
-- bam_txn->rx_sgl_start = bam_txn->rx_sgl_pos;
-- dir_eng = DMA_DEV_TO_MEM;
-- desc->dir = DMA_FROM_DEVICE;
-- }
--
-- sg_mark_end(sgl + sgl_cnt - 1);
-- ret = dma_map_sg(nandc->dev, sgl, sgl_cnt, desc->dir);
-- if (ret == 0) {
-- dev_err(nandc->dev, "failure in mapping desc\n");
-- kfree(desc);
-- return -ENOMEM;
-- }
--
-- desc->sgl_cnt = sgl_cnt;
-- desc->bam_sgl = sgl;
--
-- dma_desc = dmaengine_prep_slave_sg(chan, sgl, sgl_cnt, dir_eng,
-- flags);
--
-- if (!dma_desc) {
-- dev_err(nandc->dev, "failure in prep desc\n");
-- dma_unmap_sg(nandc->dev, sgl, sgl_cnt, desc->dir);
-- kfree(desc);
-- return -EINVAL;
-- }
--
-- desc->dma_desc = dma_desc;
--
-- /* update last data/command descriptor */
-- if (chan == nandc->cmd_chan)
-- bam_txn->last_cmd_desc = dma_desc;
-- else
-- bam_txn->last_data_desc = dma_desc;
--
-- list_add_tail(&desc->node, &nandc->desc_list);
--
-- return 0;
--}
--
--/*
-- * Prepares the command descriptor for BAM DMA which will be used for NAND
-- * register reads and writes. The command descriptor requires the command
-- * to be formed in command element type so this function uses the command
-- * element from bam transaction ce array and fills the same with required
-- * data. A single SGL can contain multiple command elements so
-- * NAND_BAM_NEXT_SGL will be used for starting the separate SGL
-- * after the current command element.
-- */
--static int qcom_prep_bam_dma_desc_cmd(struct qcom_nand_controller *nandc, bool read,
-- int reg_off, const void *vaddr,
-- int size, unsigned int flags)
--{
-- int bam_ce_size;
-- int i, ret;
-- struct bam_cmd_element *bam_ce_buffer;
-- struct bam_transaction *bam_txn = nandc->bam_txn;
--
-- bam_ce_buffer = &bam_txn->bam_ce[bam_txn->bam_ce_pos];
--
-- /* fill the command desc */
-- for (i = 0; i < size; i++) {
-- if (read)
-- bam_prep_ce(&bam_ce_buffer[i],
-- nandc_reg_phys(nandc, reg_off + 4 * i),
-- BAM_READ_COMMAND,
-- reg_buf_dma_addr(nandc,
-- (__le32 *)vaddr + i));
-- else
-- bam_prep_ce_le32(&bam_ce_buffer[i],
-- nandc_reg_phys(nandc, reg_off + 4 * i),
-- BAM_WRITE_COMMAND,
-- *((__le32 *)vaddr + i));
-- }
--
-- bam_txn->bam_ce_pos += size;
--
-- /* use the separate sgl after this command */
-- if (flags & NAND_BAM_NEXT_SGL) {
-- bam_ce_buffer = &bam_txn->bam_ce[bam_txn->bam_ce_start];
-- bam_ce_size = (bam_txn->bam_ce_pos -
-- bam_txn->bam_ce_start) *
-- sizeof(struct bam_cmd_element);
-- sg_set_buf(&bam_txn->cmd_sgl[bam_txn->cmd_sgl_pos],
-- bam_ce_buffer, bam_ce_size);
-- bam_txn->cmd_sgl_pos++;
-- bam_txn->bam_ce_start = bam_txn->bam_ce_pos;
--
-- if (flags & NAND_BAM_NWD) {
-- ret = qcom_prepare_bam_async_desc(nandc, nandc->cmd_chan,
-- DMA_PREP_FENCE |
-- DMA_PREP_CMD);
-- if (ret)
-- return ret;
-- }
-- }
--
-- return 0;
--}
--
--/*
-- * Prepares the data descriptor for BAM DMA which will be used for NAND
-- * data reads and writes.
-- */
--static int qcom_prep_bam_dma_desc_data(struct qcom_nand_controller *nandc, bool read,
-- const void *vaddr, int size, unsigned int flags)
--{
-- int ret;
-- struct bam_transaction *bam_txn = nandc->bam_txn;
--
-- if (read) {
-- sg_set_buf(&bam_txn->data_sgl[bam_txn->rx_sgl_pos],
-- vaddr, size);
-- bam_txn->rx_sgl_pos++;
-- } else {
-- sg_set_buf(&bam_txn->data_sgl[bam_txn->tx_sgl_pos],
-- vaddr, size);
-- bam_txn->tx_sgl_pos++;
--
-- /*
-- * BAM will only set EOT for DMA_PREP_INTERRUPT so if this flag
-- * is not set, form the DMA descriptor
-- */
-- if (!(flags & NAND_BAM_NO_EOT)) {
-- ret = qcom_prepare_bam_async_desc(nandc, nandc->tx_chan,
-- DMA_PREP_INTERRUPT);
-- if (ret)
-- return ret;
-- }
-- }
--
-- return 0;
--}
--
--static int qcom_prep_adm_dma_desc(struct qcom_nand_controller *nandc, bool read,
-- int reg_off, const void *vaddr, int size,
-- bool flow_control)
--{
-- struct desc_info *desc;
-- struct dma_async_tx_descriptor *dma_desc;
-- struct scatterlist *sgl;
-- struct dma_slave_config slave_conf;
-- struct qcom_adm_peripheral_config periph_conf = {};
-- enum dma_transfer_direction dir_eng;
-- int ret;
--
-- desc = kzalloc(sizeof(*desc), GFP_KERNEL);
-- if (!desc)
-- return -ENOMEM;
--
-- sgl = &desc->adm_sgl;
--
-- sg_init_one(sgl, vaddr, size);
--
-- if (read) {
-- dir_eng = DMA_DEV_TO_MEM;
-- desc->dir = DMA_FROM_DEVICE;
-- } else {
-- dir_eng = DMA_MEM_TO_DEV;
-- desc->dir = DMA_TO_DEVICE;
-- }
--
-- ret = dma_map_sg(nandc->dev, sgl, 1, desc->dir);
-- if (ret == 0) {
-- ret = -ENOMEM;
-- goto err;
-- }
--
-- memset(&slave_conf, 0x00, sizeof(slave_conf));
--
-- slave_conf.device_fc = flow_control;
-- if (read) {
-- slave_conf.src_maxburst = 16;
-- slave_conf.src_addr = nandc->base_dma + reg_off;
-- if (nandc->data_crci) {
-- periph_conf.crci = nandc->data_crci;
-- slave_conf.peripheral_config = &periph_conf;
-- slave_conf.peripheral_size = sizeof(periph_conf);
-- }
-- } else {
-- slave_conf.dst_maxburst = 16;
-- slave_conf.dst_addr = nandc->base_dma + reg_off;
-- if (nandc->cmd_crci) {
-- periph_conf.crci = nandc->cmd_crci;
-- slave_conf.peripheral_config = &periph_conf;
-- slave_conf.peripheral_size = sizeof(periph_conf);
-- }
-- }
--
-- ret = dmaengine_slave_config(nandc->chan, &slave_conf);
-- if (ret) {
-- dev_err(nandc->dev, "failed to configure dma channel\n");
-- goto err;
-- }
--
-- dma_desc = dmaengine_prep_slave_sg(nandc->chan, sgl, 1, dir_eng, 0);
-- if (!dma_desc) {
-- dev_err(nandc->dev, "failed to prepare desc\n");
-- ret = -EINVAL;
-- goto err;
-- }
--
-- desc->dma_desc = dma_desc;
--
-- list_add_tail(&desc->node, &nandc->desc_list);
--
-- return 0;
--err:
-- kfree(desc);
--
-- return ret;
--}
--
--/*
-- * qcom_read_reg_dma: prepares a descriptor to read a given number of
-- * contiguous registers to the reg_read_buf pointer
-- *
-- * @first: offset of the first register in the contiguous block
-- * @num_regs: number of registers to read
-- * @flags: flags to control DMA descriptor preparation
-- */
--static int qcom_read_reg_dma(struct qcom_nand_controller *nandc, int first,
-- int num_regs, unsigned int flags)
--{
-- bool flow_control = false;
-- void *vaddr;
--
-- vaddr = nandc->reg_read_buf + nandc->reg_read_pos;
-- nandc->reg_read_pos += num_regs;
--
-- if (first == NAND_DEV_CMD_VLD || first == NAND_DEV_CMD1)
-- first = dev_cmd_reg_addr(nandc, first);
--
-- if (nandc->props->supports_bam)
-- return qcom_prep_bam_dma_desc_cmd(nandc, true, first, vaddr,
-- num_regs, flags);
--
-- if (first == NAND_READ_ID || first == NAND_FLASH_STATUS)
-- flow_control = true;
--
-- return qcom_prep_adm_dma_desc(nandc, true, first, vaddr,
-- num_regs * sizeof(u32), flow_control);
--}
--
--/*
-- * qcom_write_reg_dma: prepares a descriptor to write a given number of
-- * contiguous registers
-- *
-- * @vaddr: contiguous memory from where register value will
-- * be written
-- * @first: offset of the first register in the contiguous block
-- * @num_regs: number of registers to write
-- * @flags: flags to control DMA descriptor preparation
-- */
--static int qcom_write_reg_dma(struct qcom_nand_controller *nandc, __le32 *vaddr,
-- int first, int num_regs, unsigned int flags)
--{
-- bool flow_control = false;
--
-- if (first == NAND_EXEC_CMD)
-- flags |= NAND_BAM_NWD;
--
-- if (first == NAND_DEV_CMD1_RESTORE || first == NAND_DEV_CMD1)
-- first = dev_cmd_reg_addr(nandc, NAND_DEV_CMD1);
--
-- if (first == NAND_DEV_CMD_VLD_RESTORE || first == NAND_DEV_CMD_VLD)
-- first = dev_cmd_reg_addr(nandc, NAND_DEV_CMD_VLD);
--
-- if (nandc->props->supports_bam)
-- return qcom_prep_bam_dma_desc_cmd(nandc, false, first, vaddr,
-- num_regs, flags);
--
-- if (first == NAND_FLASH_CMD)
-- flow_control = true;
--
-- return qcom_prep_adm_dma_desc(nandc, false, first, vaddr,
-- num_regs * sizeof(u32), flow_control);
--}
--
--/*
-- * qcom_read_data_dma: prepares a DMA descriptor to transfer data from the
-- * controller's internal buffer to the buffer 'vaddr'
-- *
-- * @reg_off: offset within the controller's data buffer
-- * @vaddr: virtual address of the buffer we want to write to
-- * @size: DMA transaction size in bytes
-- * @flags: flags to control DMA descriptor preparation
-- */
--static int qcom_read_data_dma(struct qcom_nand_controller *nandc, int reg_off,
-- const u8 *vaddr, int size, unsigned int flags)
--{
-- if (nandc->props->supports_bam)
-- return qcom_prep_bam_dma_desc_data(nandc, true, vaddr, size, flags);
--
-- return qcom_prep_adm_dma_desc(nandc, true, reg_off, vaddr, size, false);
--}
--
--/*
-- * qcom_write_data_dma: prepares a DMA descriptor to transfer data from
-- * 'vaddr' to the controller's internal buffer
-- *
-- * @reg_off: offset within the controller's data buffer
-- * @vaddr: virtual address of the buffer we want to read from
-- * @size: DMA transaction size in bytes
-- * @flags: flags to control DMA descriptor preparation
-- */
--static int qcom_write_data_dma(struct qcom_nand_controller *nandc, int reg_off,
-- const u8 *vaddr, int size, unsigned int flags)
--{
-- if (nandc->props->supports_bam)
-- return qcom_prep_bam_dma_desc_data(nandc, false, vaddr, size, flags);
--
-- return qcom_prep_adm_dma_desc(nandc, false, reg_off, vaddr, size, false);
--}
--
--/*
- * Helper to prepare DMA descriptors for configuring registers
- * before reading a NAND page.
- */
-@@ -1262,83 +394,6 @@ static void config_nand_cw_write(struct
- NAND_BAM_NEXT_SGL);
- }
-
--/* helpers to submit/free our list of dma descriptors */
--static int qcom_submit_descs(struct qcom_nand_controller *nandc)
--{
-- struct desc_info *desc, *n;
-- dma_cookie_t cookie = 0;
-- struct bam_transaction *bam_txn = nandc->bam_txn;
-- int ret = 0;
--
-- if (nandc->props->supports_bam) {
-- if (bam_txn->rx_sgl_pos > bam_txn->rx_sgl_start) {
-- ret = qcom_prepare_bam_async_desc(nandc, nandc->rx_chan, 0);
-- if (ret)
-- goto err_unmap_free_desc;
-- }
--
-- if (bam_txn->tx_sgl_pos > bam_txn->tx_sgl_start) {
-- ret = qcom_prepare_bam_async_desc(nandc, nandc->tx_chan,
-- DMA_PREP_INTERRUPT);
-- if (ret)
-- goto err_unmap_free_desc;
-- }
--
-- if (bam_txn->cmd_sgl_pos > bam_txn->cmd_sgl_start) {
-- ret = qcom_prepare_bam_async_desc(nandc, nandc->cmd_chan,
-- DMA_PREP_CMD);
-- if (ret)
-- goto err_unmap_free_desc;
-- }
-- }
--
-- list_for_each_entry(desc, &nandc->desc_list, node)
-- cookie = dmaengine_submit(desc->dma_desc);
--
-- if (nandc->props->supports_bam) {
-- bam_txn->last_cmd_desc->callback = qcom_qpic_bam_dma_done;
-- bam_txn->last_cmd_desc->callback_param = bam_txn;
--
-- dma_async_issue_pending(nandc->tx_chan);
-- dma_async_issue_pending(nandc->rx_chan);
-- dma_async_issue_pending(nandc->cmd_chan);
--
-- if (!wait_for_completion_timeout(&bam_txn->txn_done,
-- QPIC_NAND_COMPLETION_TIMEOUT))
-- ret = -ETIMEDOUT;
-- } else {
-- if (dma_sync_wait(nandc->chan, cookie) != DMA_COMPLETE)
-- ret = -ETIMEDOUT;
-- }
--
--err_unmap_free_desc:
-- /*
-- * Unmap the dma sg_list and free the desc allocated by both
-- * qcom_prepare_bam_async_desc() and qcom_prep_adm_dma_desc() functions.
-- */
-- list_for_each_entry_safe(desc, n, &nandc->desc_list, node) {
-- list_del(&desc->node);
--
-- if (nandc->props->supports_bam)
-- dma_unmap_sg(nandc->dev, desc->bam_sgl,
-- desc->sgl_cnt, desc->dir);
-- else
-- dma_unmap_sg(nandc->dev, &desc->adm_sgl, 1,
-- desc->dir);
--
-- kfree(desc);
-- }
--
-- return ret;
--}
--
--/* reset the register read buffer for next NAND operation */
--static void qcom_clear_read_regs(struct qcom_nand_controller *nandc)
--{
-- nandc->reg_read_pos = 0;
-- qcom_nandc_dev_to_mem(nandc, false);
--}
--
- /*
- * when using BCH ECC, the HW flags an error in NAND_FLASH_STATUS if it read
- * an erased CW, and reports an erased CW in NAND_ERASED_CW_DETECT_STATUS.
-@@ -2975,141 +2030,14 @@ static const struct nand_controller_ops
- .exec_op = qcom_nand_exec_op,
- };
-
--static void qcom_nandc_unalloc(struct qcom_nand_controller *nandc)
--{
-- if (nandc->props->supports_bam) {
-- if (!dma_mapping_error(nandc->dev, nandc->reg_read_dma))
-- dma_unmap_single(nandc->dev, nandc->reg_read_dma,
-- MAX_REG_RD *
-- sizeof(*nandc->reg_read_buf),
-- DMA_FROM_DEVICE);
--
-- if (nandc->tx_chan)
-- dma_release_channel(nandc->tx_chan);
--
-- if (nandc->rx_chan)
-- dma_release_channel(nandc->rx_chan);
--
-- if (nandc->cmd_chan)
-- dma_release_channel(nandc->cmd_chan);
-- } else {
-- if (nandc->chan)
-- dma_release_channel(nandc->chan);
-- }
--}
--
--static int qcom_nandc_alloc(struct qcom_nand_controller *nandc)
--{
-- int ret;
--
-- ret = dma_set_coherent_mask(nandc->dev, DMA_BIT_MASK(32));
-- if (ret) {
-- dev_err(nandc->dev, "failed to set DMA mask\n");
-- return ret;
-- }
--
-- /*
-- * we use the internal buffer for reading ONFI params, reading small
-- * data like ID and status, and preforming read-copy-write operations
-- * when writing to a codeword partially. 532 is the maximum possible
-- * size of a codeword for our nand controller
-- */
-- nandc->buf_size = 532;
--
-- nandc->data_buffer = devm_kzalloc(nandc->dev, nandc->buf_size, GFP_KERNEL);
-- if (!nandc->data_buffer)
-- return -ENOMEM;
--
-- nandc->regs = devm_kzalloc(nandc->dev, sizeof(*nandc->regs), GFP_KERNEL);
-- if (!nandc->regs)
-- return -ENOMEM;
--
-- nandc->reg_read_buf = devm_kcalloc(nandc->dev, MAX_REG_RD,
-- sizeof(*nandc->reg_read_buf),
-- GFP_KERNEL);
-- if (!nandc->reg_read_buf)
-- return -ENOMEM;
--
-- if (nandc->props->supports_bam) {
-- nandc->reg_read_dma =
-- dma_map_single(nandc->dev, nandc->reg_read_buf,
-- MAX_REG_RD *
-- sizeof(*nandc->reg_read_buf),
-- DMA_FROM_DEVICE);
-- if (dma_mapping_error(nandc->dev, nandc->reg_read_dma)) {
-- dev_err(nandc->dev, "failed to DMA MAP reg buffer\n");
-- return -EIO;
-- }
--
-- nandc->tx_chan = dma_request_chan(nandc->dev, "tx");
-- if (IS_ERR(nandc->tx_chan)) {
-- ret = PTR_ERR(nandc->tx_chan);
-- nandc->tx_chan = NULL;
-- dev_err_probe(nandc->dev, ret,
-- "tx DMA channel request failed\n");
-- goto unalloc;
-- }
--
-- nandc->rx_chan = dma_request_chan(nandc->dev, "rx");
-- if (IS_ERR(nandc->rx_chan)) {
-- ret = PTR_ERR(nandc->rx_chan);
-- nandc->rx_chan = NULL;
-- dev_err_probe(nandc->dev, ret,
-- "rx DMA channel request failed\n");
-- goto unalloc;
-- }
--
-- nandc->cmd_chan = dma_request_chan(nandc->dev, "cmd");
-- if (IS_ERR(nandc->cmd_chan)) {
-- ret = PTR_ERR(nandc->cmd_chan);
-- nandc->cmd_chan = NULL;
-- dev_err_probe(nandc->dev, ret,
-- "cmd DMA channel request failed\n");
-- goto unalloc;
-- }
--
-- /*
-- * Initially allocate BAM transaction to read ONFI param page.
-- * After detecting all the devices, this BAM transaction will
-- * be freed and the next BAM transaction will be allocated with
-- * maximum codeword size
-- */
-- nandc->max_cwperpage = 1;
-- nandc->bam_txn = qcom_alloc_bam_transaction(nandc);
-- if (!nandc->bam_txn) {
-- dev_err(nandc->dev,
-- "failed to allocate bam transaction\n");
-- ret = -ENOMEM;
-- goto unalloc;
-- }
-- } else {
-- nandc->chan = dma_request_chan(nandc->dev, "rxtx");
-- if (IS_ERR(nandc->chan)) {
-- ret = PTR_ERR(nandc->chan);
-- nandc->chan = NULL;
-- dev_err_probe(nandc->dev, ret,
-- "rxtx DMA channel request failed\n");
-- return ret;
-- }
-- }
--
-- INIT_LIST_HEAD(&nandc->desc_list);
-- INIT_LIST_HEAD(&nandc->host_list);
--
-- nand_controller_init(&nandc->controller);
-- nandc->controller.ops = &qcom_nandc_ops;
--
-- return 0;
--unalloc:
-- qcom_nandc_unalloc(nandc);
-- return ret;
--}
--
- /* one time setup of a few nand controller registers */
- static int qcom_nandc_setup(struct qcom_nand_controller *nandc)
- {
- u32 nand_ctrl;
-
-+ nand_controller_init(nandc->controller);
-+ nandc->controller->ops = &qcom_nandc_ops;
-+
- /* kill onenand */
- if (!nandc->props->nandc_part_of_qpic)
- nandc_write(nandc, SFLASHC_BURST_CFG, 0);
-@@ -3248,7 +2176,7 @@ static int qcom_nand_host_init_and_regis
- chip->legacy.block_bad = qcom_nandc_block_bad;
- chip->legacy.block_markbad = qcom_nandc_block_markbad;
-
-- chip->controller = &nandc->controller;
-+ chip->controller = nandc->controller;
- chip->options |= NAND_NO_SUBPAGE_WRITE | NAND_USES_DMA |
- NAND_SKIP_BBTSCAN;
-
-@@ -3331,17 +2259,21 @@ static int qcom_nandc_parse_dt(struct pl
- static int qcom_nandc_probe(struct platform_device *pdev)
- {
- struct qcom_nand_controller *nandc;
-+ struct nand_controller *controller;
- const void *dev_data;
- struct device *dev = &pdev->dev;
- struct resource *res;
- int ret;
-
-- nandc = devm_kzalloc(&pdev->dev, sizeof(*nandc), GFP_KERNEL);
-+ nandc = devm_kzalloc(&pdev->dev, sizeof(*nandc) + sizeof(*controller),
-+ GFP_KERNEL);
- if (!nandc)
- return -ENOMEM;
-+ controller = (struct nand_controller *)&nandc[1];
-
- platform_set_drvdata(pdev, nandc);
- nandc->dev = dev;
-+ nandc->controller = controller;
-
- dev_data = of_device_get_match_data(dev);
- if (!dev_data) {
---- /dev/null
-+++ b/include/linux/mtd/nand-qpic-common.h
-@@ -0,0 +1,468 @@
-+/* SPDX-License-Identifier: GPL-2.0 */
-+/*
-+ * QCOM QPIC common APIs header file
-+ *
-+ * Copyright (c) 2023 Qualcomm Inc.
-+ *
-+ */
-+#ifndef __MTD_NAND_QPIC_COMMON_H__
-+#define __MTD_NAND_QPIC_COMMON_H__
-+
-+/* NANDc reg offsets */
-+#define NAND_FLASH_CMD 0x00
-+#define NAND_ADDR0 0x04
-+#define NAND_ADDR1 0x08
-+#define NAND_FLASH_CHIP_SELECT 0x0c
-+#define NAND_EXEC_CMD 0x10
-+#define NAND_FLASH_STATUS 0x14
-+#define NAND_BUFFER_STATUS 0x18
-+#define NAND_DEV0_CFG0 0x20
-+#define NAND_DEV0_CFG1 0x24
-+#define NAND_DEV0_ECC_CFG 0x28
-+#define NAND_AUTO_STATUS_EN 0x2c
-+#define NAND_DEV1_CFG0 0x30
-+#define NAND_DEV1_CFG1 0x34
-+#define NAND_READ_ID 0x40
-+#define NAND_READ_STATUS 0x44
-+#define NAND_DEV_CMD0 0xa0
-+#define NAND_DEV_CMD1 0xa4
-+#define NAND_DEV_CMD2 0xa8
-+#define NAND_DEV_CMD_VLD 0xac
-+#define SFLASHC_BURST_CFG 0xe0
-+#define NAND_ERASED_CW_DETECT_CFG 0xe8
-+#define NAND_ERASED_CW_DETECT_STATUS 0xec
-+#define NAND_EBI2_ECC_BUF_CFG 0xf0
-+#define FLASH_BUF_ACC 0x100
-+
-+#define NAND_CTRL 0xf00
-+#define NAND_VERSION 0xf08
-+#define NAND_READ_LOCATION_0 0xf20
-+#define NAND_READ_LOCATION_1 0xf24
-+#define NAND_READ_LOCATION_2 0xf28
-+#define NAND_READ_LOCATION_3 0xf2c
-+#define NAND_READ_LOCATION_LAST_CW_0 0xf40
-+#define NAND_READ_LOCATION_LAST_CW_1 0xf44
-+#define NAND_READ_LOCATION_LAST_CW_2 0xf48
-+#define NAND_READ_LOCATION_LAST_CW_3 0xf4c
-+
-+/* dummy register offsets, used by qcom_write_reg_dma */
-+#define NAND_DEV_CMD1_RESTORE 0xdead
-+#define NAND_DEV_CMD_VLD_RESTORE 0xbeef
-+
-+/* NAND_FLASH_CMD bits */
-+#define PAGE_ACC BIT(4)
-+#define LAST_PAGE BIT(5)
-+
-+/* NAND_FLASH_CHIP_SELECT bits */
-+#define NAND_DEV_SEL 0
-+#define DM_EN BIT(2)
-+
-+/* NAND_FLASH_STATUS bits */
-+#define FS_OP_ERR BIT(4)
-+#define FS_READY_BSY_N BIT(5)
-+#define FS_MPU_ERR BIT(8)
-+#define FS_DEVICE_STS_ERR BIT(16)
-+#define FS_DEVICE_WP BIT(23)
-+
-+/* NAND_BUFFER_STATUS bits */
-+#define BS_UNCORRECTABLE_BIT BIT(8)
-+#define BS_CORRECTABLE_ERR_MSK 0x1f
-+
-+/* NAND_DEVn_CFG0 bits */
-+#define DISABLE_STATUS_AFTER_WRITE 4
-+#define CW_PER_PAGE 6
-+#define UD_SIZE_BYTES 9
-+#define UD_SIZE_BYTES_MASK GENMASK(18, 9)
-+#define ECC_PARITY_SIZE_BYTES_RS 19
-+#define SPARE_SIZE_BYTES 23
-+#define SPARE_SIZE_BYTES_MASK GENMASK(26, 23)
-+#define NUM_ADDR_CYCLES 27
-+#define STATUS_BFR_READ 30
-+#define SET_RD_MODE_AFTER_STATUS 31
-+
-+/* NAND_DEVn_CFG0 bits */
-+#define DEV0_CFG1_ECC_DISABLE 0
-+#define WIDE_FLASH 1
-+#define NAND_RECOVERY_CYCLES 2
-+#define CS_ACTIVE_BSY 5
-+#define BAD_BLOCK_BYTE_NUM 6
-+#define BAD_BLOCK_IN_SPARE_AREA 16
-+#define WR_RD_BSY_GAP 17
-+#define ENABLE_BCH_ECC 27
-+
-+/* NAND_DEV0_ECC_CFG bits */
-+#define ECC_CFG_ECC_DISABLE 0
-+#define ECC_SW_RESET 1
-+#define ECC_MODE 4
-+#define ECC_PARITY_SIZE_BYTES_BCH 8
-+#define ECC_NUM_DATA_BYTES 16
-+#define ECC_NUM_DATA_BYTES_MASK GENMASK(25, 16)
-+#define ECC_FORCE_CLK_OPEN 30
-+
-+/* NAND_DEV_CMD1 bits */
-+#define READ_ADDR 0
-+
-+/* NAND_DEV_CMD_VLD bits */
-+#define READ_START_VLD BIT(0)
-+#define READ_STOP_VLD BIT(1)
-+#define WRITE_START_VLD BIT(2)
-+#define ERASE_START_VLD BIT(3)
-+#define SEQ_READ_START_VLD BIT(4)
-+
-+/* NAND_EBI2_ECC_BUF_CFG bits */
-+#define NUM_STEPS 0
-+
-+/* NAND_ERASED_CW_DETECT_CFG bits */
-+#define ERASED_CW_ECC_MASK 1
-+#define AUTO_DETECT_RES 0
-+#define MASK_ECC BIT(ERASED_CW_ECC_MASK)
-+#define RESET_ERASED_DET BIT(AUTO_DETECT_RES)
-+#define ACTIVE_ERASED_DET (0 << AUTO_DETECT_RES)
-+#define CLR_ERASED_PAGE_DET (RESET_ERASED_DET | MASK_ECC)
-+#define SET_ERASED_PAGE_DET (ACTIVE_ERASED_DET | MASK_ECC)
-+
-+/* NAND_ERASED_CW_DETECT_STATUS bits */
-+#define PAGE_ALL_ERASED BIT(7)
-+#define CODEWORD_ALL_ERASED BIT(6)
-+#define PAGE_ERASED BIT(5)
-+#define CODEWORD_ERASED BIT(4)
-+#define ERASED_PAGE (PAGE_ALL_ERASED | PAGE_ERASED)
-+#define ERASED_CW (CODEWORD_ALL_ERASED | CODEWORD_ERASED)
-+
-+/* NAND_READ_LOCATION_n bits */
-+#define READ_LOCATION_OFFSET 0
-+#define READ_LOCATION_SIZE 16
-+#define READ_LOCATION_LAST 31
-+
-+/* Version Mask */
-+#define NAND_VERSION_MAJOR_MASK 0xf0000000
-+#define NAND_VERSION_MAJOR_SHIFT 28
-+#define NAND_VERSION_MINOR_MASK 0x0fff0000
-+#define NAND_VERSION_MINOR_SHIFT 16
-+
-+/* NAND OP_CMDs */
-+#define OP_PAGE_READ 0x2
-+#define OP_PAGE_READ_WITH_ECC 0x3
-+#define OP_PAGE_READ_WITH_ECC_SPARE 0x4
-+#define OP_PAGE_READ_ONFI_READ 0x5
-+#define OP_PROGRAM_PAGE 0x6
-+#define OP_PAGE_PROGRAM_WITH_ECC 0x7
-+#define OP_PROGRAM_PAGE_SPARE 0x9
-+#define OP_BLOCK_ERASE 0xa
-+#define OP_CHECK_STATUS 0xc
-+#define OP_FETCH_ID 0xb
-+#define OP_RESET_DEVICE 0xd
-+
-+/* Default Value for NAND_DEV_CMD_VLD */
-+#define NAND_DEV_CMD_VLD_VAL (READ_START_VLD | WRITE_START_VLD | \
-+ ERASE_START_VLD | SEQ_READ_START_VLD)
-+
-+/* NAND_CTRL bits */
-+#define BAM_MODE_EN BIT(0)
-+
-+/*
-+ * the NAND controller performs reads/writes with ECC in 516 byte chunks.
-+ * the driver calls the chunks 'step' or 'codeword' interchangeably
-+ */
-+#define NANDC_STEP_SIZE 512
-+
-+/*
-+ * the largest page size we support is 8K, this will have 16 steps/codewords
-+ * of 512 bytes each
-+ */
-+#define MAX_NUM_STEPS (SZ_8K / NANDC_STEP_SIZE)
-+
-+/* we read at most 3 registers per codeword scan */
-+#define MAX_REG_RD (3 * MAX_NUM_STEPS)
-+
-+/* ECC modes supported by the controller */
-+#define ECC_NONE BIT(0)
-+#define ECC_RS_4BIT BIT(1)
-+#define ECC_BCH_4BIT BIT(2)
-+#define ECC_BCH_8BIT BIT(3)
-+
-+/*
-+ * Returns the actual register address for all NAND_DEV_ registers
-+ * (i.e. NAND_DEV_CMD0, NAND_DEV_CMD1, NAND_DEV_CMD2 and NAND_DEV_CMD_VLD)
-+ */
-+#define dev_cmd_reg_addr(nandc, reg) ((nandc)->props->dev_cmd_reg_start + (reg))
-+
-+/* Returns the NAND register physical address */
-+#define nandc_reg_phys(chip, offset) ((chip)->base_phys + (offset))
-+
-+/* Returns the dma address for reg read buffer */
-+#define reg_buf_dma_addr(chip, vaddr) \
-+ ((chip)->reg_read_dma + \
-+ ((u8 *)(vaddr) - (u8 *)(chip)->reg_read_buf))
-+
-+#define QPIC_PER_CW_CMD_ELEMENTS 32
-+#define QPIC_PER_CW_CMD_SGL 32
-+#define QPIC_PER_CW_DATA_SGL 8
-+
-+#define QPIC_NAND_COMPLETION_TIMEOUT msecs_to_jiffies(2000)
-+
-+/*
-+ * Flags used in DMA descriptor preparation helper functions
-+ * (i.e. qcom_read_reg_dma/qcom_write_reg_dma/qcom_read_data_dma/qcom_write_data_dma)
-+ */
-+/* Don't set the EOT in current tx BAM sgl */
-+#define NAND_BAM_NO_EOT BIT(0)
-+/* Set the NWD flag in current BAM sgl */
-+#define NAND_BAM_NWD BIT(1)
-+/* Finish writing in the current BAM sgl and start writing in another BAM sgl */
-+#define NAND_BAM_NEXT_SGL BIT(2)
-+/*
-+ * Erased codeword status is being used two times in single transfer so this
-+ * flag will determine the current value of erased codeword status register
-+ */
-+#define NAND_ERASED_CW_SET BIT(4)
-+
-+#define MAX_ADDRESS_CYCLE 5
-+
-+/*
-+ * This data type corresponds to the BAM transaction which will be used for all
-+ * NAND transfers.
-+ * @bam_ce - the array of BAM command elements
-+ * @cmd_sgl - sgl for NAND BAM command pipe
-+ * @data_sgl - sgl for NAND BAM consumer/producer pipe
-+ * @last_data_desc - last DMA desc in data channel (tx/rx).
-+ * @last_cmd_desc - last DMA desc in command channel.
-+ * @txn_done - completion for NAND transfer.
-+ * @bam_ce_pos - the index in bam_ce which is available for next sgl
-+ * @bam_ce_start - the index in bam_ce which marks the start position ce
-+ * for current sgl. It will be used for size calculation
-+ * for current sgl
-+ * @cmd_sgl_pos - current index in command sgl.
-+ * @cmd_sgl_start - start index in command sgl.
-+ * @tx_sgl_pos - current index in data sgl for tx.
-+ * @tx_sgl_start - start index in data sgl for tx.
-+ * @rx_sgl_pos - current index in data sgl for rx.
-+ * @rx_sgl_start - start index in data sgl for rx.
-+ */
-+struct bam_transaction {
-+ struct bam_cmd_element *bam_ce;
-+ struct scatterlist *cmd_sgl;
-+ struct scatterlist *data_sgl;
-+ struct dma_async_tx_descriptor *last_data_desc;
-+ struct dma_async_tx_descriptor *last_cmd_desc;
-+ struct completion txn_done;
-+ u32 bam_ce_pos;
-+ u32 bam_ce_start;
-+ u32 cmd_sgl_pos;
-+ u32 cmd_sgl_start;
-+ u32 tx_sgl_pos;
-+ u32 tx_sgl_start;
-+ u32 rx_sgl_pos;
-+ u32 rx_sgl_start;
-+};
-+
-+/*
-+ * This data type corresponds to the nand dma descriptor
-+ * @dma_desc - low level DMA engine descriptor
-+ * @list - list for desc_info
-+ *
-+ * @adm_sgl - sgl which will be used for single sgl dma descriptor. Only used by
-+ * ADM
-+ * @bam_sgl - sgl which will be used for dma descriptor. Only used by BAM
-+ * @sgl_cnt - number of SGL in bam_sgl. Only used by BAM
-+ * @dir - DMA transfer direction
-+ */
-+struct desc_info {
-+ struct dma_async_tx_descriptor *dma_desc;
-+ struct list_head node;
-+
-+ union {
-+ struct scatterlist adm_sgl;
-+ struct {
-+ struct scatterlist *bam_sgl;
-+ int sgl_cnt;
-+ };
-+ };
-+ enum dma_data_direction dir;
-+};
-+
-+/*
-+ * holds the current register values that we want to write. acts as a contiguous
-+ * chunk of memory which we use to write the controller registers through DMA.
-+ */
-+struct nandc_regs {
-+ __le32 cmd;
-+ __le32 addr0;
-+ __le32 addr1;
-+ __le32 chip_sel;
-+ __le32 exec;
-+
-+ __le32 cfg0;
-+ __le32 cfg1;
-+ __le32 ecc_bch_cfg;
-+
-+ __le32 clrflashstatus;
-+ __le32 clrreadstatus;
-+
-+ __le32 cmd1;
-+ __le32 vld;
-+
-+ __le32 orig_cmd1;
-+ __le32 orig_vld;
-+
-+ __le32 ecc_buf_cfg;
-+ __le32 read_location0;
-+ __le32 read_location1;
-+ __le32 read_location2;
-+ __le32 read_location3;
-+ __le32 read_location_last0;
-+ __le32 read_location_last1;
-+ __le32 read_location_last2;
-+ __le32 read_location_last3;
-+
-+ __le32 erased_cw_detect_cfg_clr;
-+ __le32 erased_cw_detect_cfg_set;
-+};
-+
-+/*
-+ * NAND controller data struct
-+ *
-+ * @dev: parent device
-+ *
-+ * @base: MMIO base
-+ *
-+ * @core_clk: controller clock
-+ * @aon_clk: another controller clock
-+ *
-+ * @regs: a contiguous chunk of memory for DMA register
-+ * writes. contains the register values to be
-+ * written to controller
-+ *
-+ * @props: properties of current NAND controller,
-+ * initialized via DT match data
-+ *
-+ * @controller: base controller structure
-+ * @host_list: list containing all the chips attached to the
-+ * controller
-+ *
-+ * @chan: dma channel
-+ * @cmd_crci: ADM DMA CRCI for command flow control
-+ * @data_crci: ADM DMA CRCI for data flow control
-+ *
-+ * @desc_list: DMA descriptor list (list of desc_infos)
-+ *
-+ * @data_buffer: our local DMA buffer for page read/writes,
-+ * used when we can't use the buffer provided
-+ * by upper layers directly
-+ * @reg_read_buf: local buffer for reading back registers via DMA
-+ *
-+ * @base_phys: physical base address of controller registers
-+ * @base_dma: dma base address of controller registers
-+ * @reg_read_dma: contains dma address for register read buffer
-+ *
-+ * @buf_size/count/start: markers for chip->legacy.read_buf/write_buf
-+ * functions
-+ * @max_cwperpage: maximum QPIC codewords required. calculated
-+ * from all connected NAND devices pagesize
-+ *
-+ * @reg_read_pos: marker for data read in reg_read_buf
-+ *
-+ * @cmd1/vld: some fixed controller register values
-+ *
-+ * @exec_opwrite: flag to select correct number of code word
-+ * while reading status
-+ */
-+struct qcom_nand_controller {
-+ struct device *dev;
-+
-+ void __iomem *base;
-+
-+ struct clk *core_clk;
-+ struct clk *aon_clk;
-+
-+ struct nandc_regs *regs;
-+ struct bam_transaction *bam_txn;
-+
-+ const struct qcom_nandc_props *props;
-+
-+ struct nand_controller *controller;
-+ struct list_head host_list;
-+
-+ union {
-+ /* will be used only by QPIC for BAM DMA */
-+ struct {
-+ struct dma_chan *tx_chan;
-+ struct dma_chan *rx_chan;
-+ struct dma_chan *cmd_chan;
-+ };
-+
-+ /* will be used only by EBI2 for ADM DMA */
-+ struct {
-+ struct dma_chan *chan;
-+ unsigned int cmd_crci;
-+ unsigned int data_crci;
-+ };
-+ };
-+
-+ struct list_head desc_list;
-+
-+ u8 *data_buffer;
-+ __le32 *reg_read_buf;
-+
-+ phys_addr_t base_phys;
-+ dma_addr_t base_dma;
-+ dma_addr_t reg_read_dma;
-+
-+ int buf_size;
-+ int buf_count;
-+ int buf_start;
-+ unsigned int max_cwperpage;
-+
-+ int reg_read_pos;
-+
-+ u32 cmd1, vld;
-+ bool exec_opwrite;
-+};
-+
-+/*
-+ * This data type corresponds to the NAND controller properties which varies
-+ * among different NAND controllers.
-+ * @ecc_modes - ecc mode for NAND
-+ * @dev_cmd_reg_start - NAND_DEV_CMD_* registers starting offset
-+ * @supports_bam - whether NAND controller is using BAM
-+ * @nandc_part_of_qpic - whether NAND controller is part of qpic IP
-+ * @qpic_version2 - flag to indicate QPIC IP version 2
-+ * @use_codeword_fixup - whether NAND has different layout for boot partitions
-+ */
-+struct qcom_nandc_props {
-+ u32 ecc_modes;
-+ u32 dev_cmd_reg_start;
-+ bool supports_bam;
-+ bool nandc_part_of_qpic;
-+ bool qpic_version2;
-+ bool use_codeword_fixup;
-+};
-+
-+void qcom_free_bam_transaction(struct qcom_nand_controller *nandc);
-+struct bam_transaction *qcom_alloc_bam_transaction(struct qcom_nand_controller *nandc);
-+void qcom_clear_bam_transaction(struct qcom_nand_controller *nandc);
-+void qcom_qpic_bam_dma_done(void *data);
-+void qcom_nandc_dev_to_mem(struct qcom_nand_controller *nandc, bool is_cpu);
-+int qcom_prepare_bam_async_desc(struct qcom_nand_controller *nandc,
-+ struct dma_chan *chan, unsigned long flags);
-+int qcom_prep_bam_dma_desc_cmd(struct qcom_nand_controller *nandc, bool read,
-+ int reg_off, const void *vaddr, int size, unsigned int flags);
-+int qcom_prep_bam_dma_desc_data(struct qcom_nand_controller *nandc, bool read,
-+ const void *vaddr, int size, unsigned int flags);
-+int qcom_prep_adm_dma_desc(struct qcom_nand_controller *nandc, bool read, int reg_off,
-+ const void *vaddr, int size, bool flow_control);
-+int qcom_read_reg_dma(struct qcom_nand_controller *nandc, int first, int num_regs,
-+ unsigned int flags);
-+int qcom_write_reg_dma(struct qcom_nand_controller *nandc, __le32 *vaddr, int first,
-+ int num_regs, unsigned int flags);
-+int qcom_read_data_dma(struct qcom_nand_controller *nandc, int reg_off, const u8 *vaddr,
-+ int size, unsigned int flags);
-+int qcom_write_data_dma(struct qcom_nand_controller *nandc, int reg_off, const u8 *vaddr,
-+ int size, unsigned int flags);
-+int qcom_submit_descs(struct qcom_nand_controller *nandc);
-+void qcom_clear_read_regs(struct qcom_nand_controller *nandc);
-+void qcom_nandc_unalloc(struct qcom_nand_controller *nandc);
-+int qcom_nandc_alloc(struct qcom_nand_controller *nandc);
-+#endif
-+
+++ /dev/null
-From 0c08080fd71cd5dd59643104b39d3c89d793ab3c Mon Sep 17 00:00:00 2001
-Date: Wed, 20 Nov 2024 14:45:03 +0530
-Subject: [PATCH 4/4] mtd: rawnand: qcom: use FIELD_PREP and GENMASK
-
-Use the bitfield macro FIELD_PREP, and GENMASK to
-do the shift and mask in one go. This makes the code
-more readable.
-
----
- drivers/mtd/nand/raw/qcom_nandc.c | 97 ++++++++++++++--------------
- include/linux/mtd/nand-qpic-common.h | 31 +++++----
- 2 files changed, 67 insertions(+), 61 deletions(-)
-
---- a/drivers/mtd/nand/raw/qcom_nandc.c
-+++ b/drivers/mtd/nand/raw/qcom_nandc.c
-@@ -281,7 +281,7 @@ static void update_rw_regs(struct qcom_n
- (num_cw - 1) << CW_PER_PAGE);
-
- cfg1 = cpu_to_le32(host->cfg1_raw);
-- ecc_bch_cfg = cpu_to_le32(1 << ECC_CFG_ECC_DISABLE);
-+ ecc_bch_cfg = cpu_to_le32(ECC_CFG_ECC_DISABLE);
- }
-
- nandc->regs->cmd = cmd;
-@@ -1494,42 +1494,41 @@ static int qcom_nand_attach_chip(struct
- host->cw_size = host->cw_data + ecc->bytes;
- bad_block_byte = mtd->writesize - host->cw_size * (cwperpage - 1) + 1;
-
-- host->cfg0 = (cwperpage - 1) << CW_PER_PAGE
-- | host->cw_data << UD_SIZE_BYTES
-- | 0 << DISABLE_STATUS_AFTER_WRITE
-- | 5 << NUM_ADDR_CYCLES
-- | host->ecc_bytes_hw << ECC_PARITY_SIZE_BYTES_RS
-- | 0 << STATUS_BFR_READ
-- | 1 << SET_RD_MODE_AFTER_STATUS
-- | host->spare_bytes << SPARE_SIZE_BYTES;
--
-- host->cfg1 = 7 << NAND_RECOVERY_CYCLES
-- | 0 << CS_ACTIVE_BSY
-- | bad_block_byte << BAD_BLOCK_BYTE_NUM
-- | 0 << BAD_BLOCK_IN_SPARE_AREA
-- | 2 << WR_RD_BSY_GAP
-- | wide_bus << WIDE_FLASH
-- | host->bch_enabled << ENABLE_BCH_ECC;
--
-- host->cfg0_raw = (cwperpage - 1) << CW_PER_PAGE
-- | host->cw_size << UD_SIZE_BYTES
-- | 5 << NUM_ADDR_CYCLES
-- | 0 << SPARE_SIZE_BYTES;
--
-- host->cfg1_raw = 7 << NAND_RECOVERY_CYCLES
-- | 0 << CS_ACTIVE_BSY
-- | 17 << BAD_BLOCK_BYTE_NUM
-- | 1 << BAD_BLOCK_IN_SPARE_AREA
-- | 2 << WR_RD_BSY_GAP
-- | wide_bus << WIDE_FLASH
-- | 1 << DEV0_CFG1_ECC_DISABLE;
--
-- host->ecc_bch_cfg = !host->bch_enabled << ECC_CFG_ECC_DISABLE
-- | 0 << ECC_SW_RESET
-- | host->cw_data << ECC_NUM_DATA_BYTES
-- | 1 << ECC_FORCE_CLK_OPEN
-- | ecc_mode << ECC_MODE
-- | host->ecc_bytes_hw << ECC_PARITY_SIZE_BYTES_BCH;
-+ host->cfg0 = FIELD_PREP(CW_PER_PAGE_MASK, (cwperpage - 1)) |
-+ FIELD_PREP(UD_SIZE_BYTES_MASK, host->cw_data) |
-+ FIELD_PREP(DISABLE_STATUS_AFTER_WRITE, 0) |
-+ FIELD_PREP(NUM_ADDR_CYCLES_MASK, 5) |
-+ FIELD_PREP(ECC_PARITY_SIZE_BYTES_RS, host->ecc_bytes_hw) |
-+ FIELD_PREP(STATUS_BFR_READ, 0) |
-+ FIELD_PREP(SET_RD_MODE_AFTER_STATUS, 1) |
-+ FIELD_PREP(SPARE_SIZE_BYTES_MASK, host->spare_bytes);
-+
-+ host->cfg1 = FIELD_PREP(NAND_RECOVERY_CYCLES_MASK, 7) |
-+ FIELD_PREP(BAD_BLOCK_BYTE_NUM_MASK, bad_block_byte) |
-+ FIELD_PREP(BAD_BLOCK_IN_SPARE_AREA, 0) |
-+ FIELD_PREP(WR_RD_BSY_GAP_MASK, 2) |
-+ FIELD_PREP(WIDE_FLASH, wide_bus) |
-+ FIELD_PREP(ENABLE_BCH_ECC, host->bch_enabled);
-+
-+ host->cfg0_raw = FIELD_PREP(CW_PER_PAGE_MASK, (cwperpage - 1)) |
-+ FIELD_PREP(UD_SIZE_BYTES_MASK, host->cw_size) |
-+ FIELD_PREP(NUM_ADDR_CYCLES_MASK, 5) |
-+ FIELD_PREP(SPARE_SIZE_BYTES_MASK, 0);
-+
-+ host->cfg1_raw = FIELD_PREP(NAND_RECOVERY_CYCLES_MASK, 7) |
-+ FIELD_PREP(CS_ACTIVE_BSY, 0) |
-+ FIELD_PREP(BAD_BLOCK_BYTE_NUM_MASK, 17) |
-+ FIELD_PREP(BAD_BLOCK_IN_SPARE_AREA, 1) |
-+ FIELD_PREP(WR_RD_BSY_GAP_MASK, 2) |
-+ FIELD_PREP(WIDE_FLASH, wide_bus) |
-+ FIELD_PREP(DEV0_CFG1_ECC_DISABLE, 1);
-+
-+ host->ecc_bch_cfg = FIELD_PREP(ECC_CFG_ECC_DISABLE, !host->bch_enabled) |
-+ FIELD_PREP(ECC_SW_RESET, 0) |
-+ FIELD_PREP(ECC_NUM_DATA_BYTES_MASK, host->cw_data) |
-+ FIELD_PREP(ECC_FORCE_CLK_OPEN, 1) |
-+ FIELD_PREP(ECC_MODE_MASK, ecc_mode) |
-+ FIELD_PREP(ECC_PARITY_SIZE_BYTES_BCH_MASK, host->ecc_bytes_hw);
-
- if (!nandc->props->qpic_version2)
- host->ecc_buf_cfg = 0x203 << NUM_STEPS;
-@@ -1887,21 +1886,21 @@ static int qcom_param_page_type_exec(str
- nandc->regs->addr0 = 0;
- nandc->regs->addr1 = 0;
-
-- nandc->regs->cfg0 = cpu_to_le32(0 << CW_PER_PAGE |
-- 512 << UD_SIZE_BYTES |
-- 5 << NUM_ADDR_CYCLES |
-- 0 << SPARE_SIZE_BYTES);
--
-- nandc->regs->cfg1 = cpu_to_le32(7 << NAND_RECOVERY_CYCLES |
-- 0 << CS_ACTIVE_BSY |
-- 17 << BAD_BLOCK_BYTE_NUM |
-- 1 << BAD_BLOCK_IN_SPARE_AREA |
-- 2 << WR_RD_BSY_GAP |
-- 0 << WIDE_FLASH |
-- 1 << DEV0_CFG1_ECC_DISABLE);
-+ host->cfg0 = FIELD_PREP(CW_PER_PAGE_MASK, 0) |
-+ FIELD_PREP(UD_SIZE_BYTES_MASK, 512) |
-+ FIELD_PREP(NUM_ADDR_CYCLES_MASK, 5) |
-+ FIELD_PREP(SPARE_SIZE_BYTES_MASK, 0);
-+
-+ host->cfg1 = FIELD_PREP(NAND_RECOVERY_CYCLES_MASK, 7) |
-+ FIELD_PREP(BAD_BLOCK_BYTE_NUM_MASK, 17) |
-+ FIELD_PREP(CS_ACTIVE_BSY, 0) |
-+ FIELD_PREP(BAD_BLOCK_IN_SPARE_AREA, 1) |
-+ FIELD_PREP(WR_RD_BSY_GAP_MASK, 2) |
-+ FIELD_PREP(WIDE_FLASH, 0) |
-+ FIELD_PREP(DEV0_CFG1_ECC_DISABLE, 1);
-
- if (!nandc->props->qpic_version2)
-- nandc->regs->ecc_buf_cfg = cpu_to_le32(1 << ECC_CFG_ECC_DISABLE);
-+ nandc->regs->ecc_buf_cfg = cpu_to_le32(ECC_CFG_ECC_DISABLE);
-
- /* configure CMD1 and VLD for ONFI param probing in QPIC v1 */
- if (!nandc->props->qpic_version2) {
---- a/include/linux/mtd/nand-qpic-common.h
-+++ b/include/linux/mtd/nand-qpic-common.h
-@@ -70,35 +70,42 @@
- #define BS_CORRECTABLE_ERR_MSK 0x1f
-
- /* NAND_DEVn_CFG0 bits */
--#define DISABLE_STATUS_AFTER_WRITE 4
-+#define DISABLE_STATUS_AFTER_WRITE BIT(4)
- #define CW_PER_PAGE 6
-+#define CW_PER_PAGE_MASK GENMASK(8, 6)
- #define UD_SIZE_BYTES 9
- #define UD_SIZE_BYTES_MASK GENMASK(18, 9)
--#define ECC_PARITY_SIZE_BYTES_RS 19
-+#define ECC_PARITY_SIZE_BYTES_RS GENMASK(22, 19)
- #define SPARE_SIZE_BYTES 23
- #define SPARE_SIZE_BYTES_MASK GENMASK(26, 23)
- #define NUM_ADDR_CYCLES 27
--#define STATUS_BFR_READ 30
--#define SET_RD_MODE_AFTER_STATUS 31
-+#define NUM_ADDR_CYCLES_MASK GENMASK(29, 27)
-+#define STATUS_BFR_READ BIT(30)
-+#define SET_RD_MODE_AFTER_STATUS BIT(31)
-
- /* NAND_DEVn_CFG0 bits */
--#define DEV0_CFG1_ECC_DISABLE 0
--#define WIDE_FLASH 1
-+#define DEV0_CFG1_ECC_DISABLE BIT(0)
-+#define WIDE_FLASH BIT(1)
- #define NAND_RECOVERY_CYCLES 2
--#define CS_ACTIVE_BSY 5
-+#define NAND_RECOVERY_CYCLES_MASK GENMASK(4, 2)
-+#define CS_ACTIVE_BSY BIT(5)
- #define BAD_BLOCK_BYTE_NUM 6
--#define BAD_BLOCK_IN_SPARE_AREA 16
-+#define BAD_BLOCK_BYTE_NUM_MASK GENMASK(15, 6)
-+#define BAD_BLOCK_IN_SPARE_AREA BIT(16)
- #define WR_RD_BSY_GAP 17
--#define ENABLE_BCH_ECC 27
-+#define WR_RD_BSY_GAP_MASK GENMASK(22, 17)
-+#define ENABLE_BCH_ECC BIT(27)
-
- /* NAND_DEV0_ECC_CFG bits */
--#define ECC_CFG_ECC_DISABLE 0
--#define ECC_SW_RESET 1
-+#define ECC_CFG_ECC_DISABLE BIT(0)
-+#define ECC_SW_RESET BIT(1)
- #define ECC_MODE 4
-+#define ECC_MODE_MASK GENMASK(5, 4)
- #define ECC_PARITY_SIZE_BYTES_BCH 8
-+#define ECC_PARITY_SIZE_BYTES_BCH_MASK GENMASK(12, 8)
- #define ECC_NUM_DATA_BYTES 16
- #define ECC_NUM_DATA_BYTES_MASK GENMASK(25, 16)
--#define ECC_FORCE_CLK_OPEN 30
-+#define ECC_FORCE_CLK_OPEN BIT(30)
-
- /* NAND_DEV_CMD1 bits */
- #define READ_ADDR 0
+++ /dev/null
-From 9d4ffbcfde283f2a87ea45128ddf7e6651facdd9 Mon Sep 17 00:00:00 2001
-Date: Fri, 7 Feb 2025 20:42:38 +0100
-Subject: [PATCH] mtd: rawnand: qcom: fix broken config in
- qcom_param_page_type_exec
-
-Fix broken config in qcom_param_page_type_exec caused by copy-paste error
-from commit 0c08080fd71c ("mtd: rawnand: qcom: use FIELD_PREP and GENMASK")
-
-In qcom_param_page_type_exec the value needs to be set to
-nandc->regs->cfg0 instead of host->cfg0. This wrong configuration caused
-the Qcom NANDC driver to malfunction on any device that makes use of it
-(IPQ806x, IPQ40xx, IPQ807x, IPQ60xx) with the following error:
-
-[ 0.885369] nand: device found, Manufacturer ID: 0x2c, Chip ID: 0xaa
-[ 0.885909] nand: Micron NAND 256MiB 1,8V 8-bit
-[ 0.892499] nand: 256 MiB, SLC, erase size: 128 KiB, page size: 2048, OOB size: 64
-[ 0.896823] nand: ECC (step, strength) = (512, 8) does not fit in OOB
-[ 0.896836] qcom-nandc 79b0000.nand-controller: No valid ECC settings possible
-[ 0.910996] bam-dma-engine 7984000.dma-controller: Cannot free busy channel
-[ 0.918070] qcom-nandc: probe of 79b0000.nand-controller failed with error -28
-
-Restore original configuration fix the problem and makes the driver work
-again.
-
-Fixes: 0c08080fd71c ("mtd: rawnand: qcom: use FIELD_PREP and GENMASK")
----
- drivers/mtd/nand/raw/qcom_nandc.c | 24 ++++++++++++------------
- 1 file changed, 12 insertions(+), 12 deletions(-)
-
---- a/drivers/mtd/nand/raw/qcom_nandc.c
-+++ b/drivers/mtd/nand/raw/qcom_nandc.c
-@@ -1886,18 +1886,18 @@ static int qcom_param_page_type_exec(str
- nandc->regs->addr0 = 0;
- nandc->regs->addr1 = 0;
-
-- host->cfg0 = FIELD_PREP(CW_PER_PAGE_MASK, 0) |
-- FIELD_PREP(UD_SIZE_BYTES_MASK, 512) |
-- FIELD_PREP(NUM_ADDR_CYCLES_MASK, 5) |
-- FIELD_PREP(SPARE_SIZE_BYTES_MASK, 0);
-+ nandc->regs->cfg0 = FIELD_PREP(CW_PER_PAGE_MASK, 0) |
-+ FIELD_PREP(UD_SIZE_BYTES_MASK, 512) |
-+ FIELD_PREP(NUM_ADDR_CYCLES_MASK, 5) |
-+ FIELD_PREP(SPARE_SIZE_BYTES_MASK, 0);
-
-- host->cfg1 = FIELD_PREP(NAND_RECOVERY_CYCLES_MASK, 7) |
-- FIELD_PREP(BAD_BLOCK_BYTE_NUM_MASK, 17) |
-- FIELD_PREP(CS_ACTIVE_BSY, 0) |
-- FIELD_PREP(BAD_BLOCK_IN_SPARE_AREA, 1) |
-- FIELD_PREP(WR_RD_BSY_GAP_MASK, 2) |
-- FIELD_PREP(WIDE_FLASH, 0) |
-- FIELD_PREP(DEV0_CFG1_ECC_DISABLE, 1);
-+ nandc->regs->cfg1 = FIELD_PREP(NAND_RECOVERY_CYCLES_MASK, 7) |
-+ FIELD_PREP(BAD_BLOCK_BYTE_NUM_MASK, 17) |
-+ FIELD_PREP(CS_ACTIVE_BSY, 0) |
-+ FIELD_PREP(BAD_BLOCK_IN_SPARE_AREA, 1) |
-+ FIELD_PREP(WR_RD_BSY_GAP_MASK, 2) |
-+ FIELD_PREP(WIDE_FLASH, 0) |
-+ FIELD_PREP(DEV0_CFG1_ECC_DISABLE, 1);
-
- if (!nandc->props->qpic_version2)
- nandc->regs->ecc_buf_cfg = cpu_to_le32(ECC_CFG_ECC_DISABLE);
+++ /dev/null
-From b9371866799d67a80be0ea9e01bd41987db22f26 Mon Sep 17 00:00:00 2001
-Date: Mon, 6 Jan 2025 18:45:58 +0530
-Subject: [PATCH] mtd: rawnand: qcom: Fix build issue on x86 architecture
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Fix a buffer overflow issue in qcom_clear_bam_transaction by using
-struct_group to group related fields and avoid FORTIFY_SOURCE warnings.
-
-On x86 architecture, the following error occurs due to warnings being
-treated as errors:
-
-In function ‘fortify_memset_chk’,
- inlined from ‘qcom_clear_bam_transaction’ at
-drivers/mtd/nand/qpic_common.c:88:2:
-./include/linux/fortify-string.h:480:25: error: call to ‘__write_overflow_field’
-declared with attribute warning: detected write beyond size of field
-(1st parameter); maybe use struct_group()? [-Werror=attribute-warning]
- 480 | __write_overflow_field(p_size_field, size);
- | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- LD [M] drivers/mtd/nand/nandcore.o
- CC [M] drivers/w1/masters/mxc_w1.o
-cc1: all warnings being treated as errors
-
-This patch addresses the issue by grouping the related fields in
-struct bam_transaction using struct_group and updating the memset call
-accordingly.
-
-Fixes: 8c52932da5e6 ("mtd: rawnand: qcom: cleanup qcom_nandc driver")
----
- drivers/mtd/nand/qpic_common.c | 2 +-
- include/linux/mtd/nand-qpic-common.h | 19 +++++++++++--------
- 2 files changed, 12 insertions(+), 9 deletions(-)
-
---- a/drivers/mtd/nand/qpic_common.c
-+++ b/drivers/mtd/nand/qpic_common.c
-@@ -85,7 +85,7 @@ void qcom_clear_bam_transaction(struct q
- if (!nandc->props->supports_bam)
- return;
-
-- memset(&bam_txn->bam_ce_pos, 0, sizeof(u32) * 8);
-+ memset(&bam_txn->bam_positions, 0, sizeof(bam_txn->bam_positions));
- bam_txn->last_data_desc = NULL;
-
- sg_init_table(bam_txn->cmd_sgl, nandc->max_cwperpage *
---- a/include/linux/mtd/nand-qpic-common.h
-+++ b/include/linux/mtd/nand-qpic-common.h
-@@ -254,14 +254,17 @@ struct bam_transaction {
- struct dma_async_tx_descriptor *last_data_desc;
- struct dma_async_tx_descriptor *last_cmd_desc;
- struct completion txn_done;
-- u32 bam_ce_pos;
-- u32 bam_ce_start;
-- u32 cmd_sgl_pos;
-- u32 cmd_sgl_start;
-- u32 tx_sgl_pos;
-- u32 tx_sgl_start;
-- u32 rx_sgl_pos;
-- u32 rx_sgl_start;
-+ struct_group(bam_positions,
-+ u32 bam_ce_pos;
-+ u32 bam_ce_start;
-+ u32 cmd_sgl_pos;
-+ u32 cmd_sgl_start;
-+ u32 tx_sgl_pos;
-+ u32 tx_sgl_start;
-+ u32 rx_sgl_pos;
-+ u32 rx_sgl_start;
-+
-+ );
- };
-
- /*
+++ /dev/null
-From 7304d1909080ef0c9da703500a97f46c98393fcd Mon Sep 17 00:00:00 2001
-Date: Mon, 24 Feb 2025 16:44:14 +0530
-Subject: [PATCH] spi: spi-qpic: add driver for QCOM SPI NAND flash Interface
-
-This driver implements support for the SPI-NAND mode of QCOM NAND Flash
-Interface as a SPI-MEM controller with pipelined ECC capability.
-
----
- drivers/mtd/nand/Makefile | 4 +
- drivers/spi/Kconfig | 9 +
- drivers/spi/Makefile | 1 +
- drivers/spi/spi-qpic-snand.c | 1631 ++++++++++++++++++++++++++
- include/linux/mtd/nand-qpic-common.h | 7 +
- 5 files changed, 1652 insertions(+)
- create mode 100644 drivers/spi/spi-qpic-snand.c
-
---- a/drivers/mtd/nand/Makefile
-+++ b/drivers/mtd/nand/Makefile
-@@ -3,7 +3,11 @@
- nandcore-objs := core.o bbt.o
- obj-$(CONFIG_MTD_NAND_CORE) += nandcore.o
- obj-$(CONFIG_MTD_NAND_ECC_MEDIATEK) += ecc-mtk.o
-+ifeq ($(CONFIG_SPI_QPIC_SNAND),y)
-+obj-$(CONFIG_SPI_QPIC_SNAND) += qpic_common.o
-+else
- obj-$(CONFIG_MTD_NAND_QCOM) += qpic_common.o
-+endif
- obj-y += onenand/
- obj-y += raw/
- obj-y += spi/
---- a/drivers/spi/Kconfig
-+++ b/drivers/spi/Kconfig
-@@ -870,6 +870,15 @@ config SPI_QCOM_QSPI
- help
- QSPI(Quad SPI) driver for Qualcomm QSPI controller.
-
-+config SPI_QPIC_SNAND
-+ bool "QPIC SNAND controller"
-+ depends on ARCH_QCOM || COMPILE_TEST
-+ select MTD
-+ help
-+ QPIC_SNAND (QPIC SPI NAND) driver for Qualcomm QPIC controller.
-+ QPIC controller supports both parallel nand and serial nand.
-+ This config will enable serial nand driver for QPIC controller.
-+
- config SPI_QUP
- tristate "Qualcomm SPI controller with QUP interface"
- depends on ARCH_QCOM || COMPILE_TEST
---- a/drivers/spi/Makefile
-+++ b/drivers/spi/Makefile
-@@ -110,6 +110,7 @@ obj-$(CONFIG_SPI_PXA2XX) += spi-pxa2xx-
- obj-$(CONFIG_SPI_PXA2XX_PCI) += spi-pxa2xx-pci.o
- obj-$(CONFIG_SPI_QCOM_GENI) += spi-geni-qcom.o
- obj-$(CONFIG_SPI_QCOM_QSPI) += spi-qcom-qspi.o
-+obj-$(CONFIG_SPI_QPIC_SNAND) += spi-qpic-snand.o
- obj-$(CONFIG_SPI_QUP) += spi-qup.o
- obj-$(CONFIG_SPI_ROCKCHIP) += spi-rockchip.o
- obj-$(CONFIG_SPI_ROCKCHIP_SFC) += spi-rockchip-sfc.o
---- /dev/null
-+++ b/drivers/spi/spi-qpic-snand.c
-@@ -0,0 +1,1631 @@
-+/*
-+ * SPDX-License-Identifier: GPL-2.0
-+ *
-+ * Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved.
-+ *
-+ * Authors:
-+ */
-+#include <linux/bitops.h>
-+#include <linux/clk.h>
-+#include <linux/delay.h>
-+#include <linux/dmaengine.h>
-+#include <linux/dma-mapping.h>
-+#include <linux/dma/qcom_adm.h>
-+#include <linux/dma/qcom_bam_dma.h>
-+#include <linux/module.h>
-+#include <linux/of.h>
-+#include <linux/platform_device.h>
-+#include <linux/slab.h>
-+#include <linux/mtd/nand-qpic-common.h>
-+#include <linux/mtd/spinand.h>
-+#include <linux/bitfield.h>
-+
-+#define NAND_FLASH_SPI_CFG 0xc0
-+#define NAND_NUM_ADDR_CYCLES 0xc4
-+#define NAND_BUSY_CHECK_WAIT_CNT 0xc8
-+#define NAND_FLASH_FEATURES 0xf64
-+
-+/* QSPI NAND config reg bits */
-+#define LOAD_CLK_CNTR_INIT_EN BIT(28)
-+#define CLK_CNTR_INIT_VAL_VEC 0x924
-+#define CLK_CNTR_INIT_VAL_VEC_MASK GENMASK(27, 16)
-+#define FEA_STATUS_DEV_ADDR 0xc0
-+#define FEA_STATUS_DEV_ADDR_MASK GENMASK(15, 8)
-+#define SPI_CFG BIT(0)
-+#define SPI_NUM_ADDR 0xDA4DB
-+#define SPI_WAIT_CNT 0x10
-+#define QPIC_QSPI_NUM_CS 1
-+#define SPI_TRANSFER_MODE_x1 BIT(29)
-+#define SPI_TRANSFER_MODE_x4 (3 << 29)
-+#define SPI_WP BIT(28)
-+#define SPI_HOLD BIT(27)
-+#define QPIC_SET_FEATURE BIT(31)
-+
-+#define SPINAND_RESET 0xff
-+#define SPINAND_READID 0x9f
-+#define SPINAND_GET_FEATURE 0x0f
-+#define SPINAND_SET_FEATURE 0x1f
-+#define SPINAND_READ 0x13
-+#define SPINAND_ERASE 0xd8
-+#define SPINAND_WRITE_EN 0x06
-+#define SPINAND_PROGRAM_EXECUTE 0x10
-+#define SPINAND_PROGRAM_LOAD 0x84
-+
-+#define ACC_FEATURE 0xe
-+#define BAD_BLOCK_MARKER_SIZE 0x2
-+#define OOB_BUF_SIZE 128
-+#define ecceng_to_qspi(eng) container_of(eng, struct qpic_spi_nand, ecc_eng)
-+
-+struct qpic_snand_op {
-+ u32 cmd_reg;
-+ u32 addr1_reg;
-+ u32 addr2_reg;
-+};
-+
-+struct snandc_read_status {
-+ __le32 snandc_flash;
-+ __le32 snandc_buffer;
-+ __le32 snandc_erased_cw;
-+};
-+
-+/*
-+ * ECC state struct
-+ * @corrected: ECC corrected
-+ * @bitflips: Max bit flip
-+ * @failed: ECC failed
-+ */
-+struct qcom_ecc_stats {
-+ u32 corrected;
-+ u32 bitflips;
-+ u32 failed;
-+};
-+
-+struct qpic_ecc {
-+ struct device *dev;
-+ int ecc_bytes_hw;
-+ int spare_bytes;
-+ int bbm_size;
-+ int ecc_mode;
-+ int bytes;
-+ int steps;
-+ int step_size;
-+ int strength;
-+ int cw_size;
-+ int cw_data;
-+ u32 cfg0;
-+ u32 cfg1;
-+ u32 cfg0_raw;
-+ u32 cfg1_raw;
-+ u32 ecc_buf_cfg;
-+ u32 ecc_bch_cfg;
-+ u32 clrflashstatus;
-+ u32 clrreadstatus;
-+ bool bch_enabled;
-+};
-+
-+struct qpic_spi_nand {
-+ struct qcom_nand_controller *snandc;
-+ struct spi_controller *ctlr;
-+ struct mtd_info *mtd;
-+ struct clk *iomacro_clk;
-+ struct qpic_ecc *ecc;
-+ struct qcom_ecc_stats ecc_stats;
-+ struct nand_ecc_engine ecc_eng;
-+ u8 *data_buf;
-+ u8 *oob_buf;
-+ u32 wlen;
-+ __le32 addr1;
-+ __le32 addr2;
-+ __le32 cmd;
-+ u32 num_cw;
-+ bool oob_rw;
-+ bool page_rw;
-+ bool raw_rw;
-+};
-+
-+static void qcom_spi_set_read_loc_first(struct qcom_nand_controller *snandc,
-+ int reg, int cw_offset, int read_size,
-+ int is_last_read_loc)
-+{
-+ __le32 locreg_val;
-+ u32 val = (((cw_offset) << READ_LOCATION_OFFSET) |
-+ ((read_size) << READ_LOCATION_SIZE) | ((is_last_read_loc)
-+ << READ_LOCATION_LAST));
-+
-+ locreg_val = cpu_to_le32(val);
-+
-+ if (reg == NAND_READ_LOCATION_0)
-+ snandc->regs->read_location0 = locreg_val;
-+ else if (reg == NAND_READ_LOCATION_1)
-+ snandc->regs->read_location1 = locreg_val;
-+ else if (reg == NAND_READ_LOCATION_2)
-+ snandc->regs->read_location1 = locreg_val;
-+ else if (reg == NAND_READ_LOCATION_3)
-+ snandc->regs->read_location3 = locreg_val;
-+}
-+
-+static void qcom_spi_set_read_loc_last(struct qcom_nand_controller *snandc,
-+ int reg, int cw_offset, int read_size,
-+ int is_last_read_loc)
-+{
-+ __le32 locreg_val;
-+ u32 val = (((cw_offset) << READ_LOCATION_OFFSET) |
-+ ((read_size) << READ_LOCATION_SIZE) | ((is_last_read_loc)
-+ << READ_LOCATION_LAST));
-+
-+ locreg_val = cpu_to_le32(val);
-+
-+ if (reg == NAND_READ_LOCATION_LAST_CW_0)
-+ snandc->regs->read_location_last0 = locreg_val;
-+ else if (reg == NAND_READ_LOCATION_LAST_CW_1)
-+ snandc->regs->read_location_last1 = locreg_val;
-+ else if (reg == NAND_READ_LOCATION_LAST_CW_2)
-+ snandc->regs->read_location_last2 = locreg_val;
-+ else if (reg == NAND_READ_LOCATION_LAST_CW_3)
-+ snandc->regs->read_location_last3 = locreg_val;
-+}
-+
-+static struct qcom_nand_controller *nand_to_qcom_snand(struct nand_device *nand)
-+{
-+ struct nand_ecc_engine *eng = nand->ecc.engine;
-+ struct qpic_spi_nand *qspi = ecceng_to_qspi(eng);
-+
-+ return qspi->snandc;
-+}
-+
-+static int qcom_spi_init(struct qcom_nand_controller *snandc)
-+{
-+ u32 snand_cfg_val = 0x0;
-+ int ret;
-+
-+ snand_cfg_val = FIELD_PREP(CLK_CNTR_INIT_VAL_VEC_MASK, CLK_CNTR_INIT_VAL_VEC) |
-+ FIELD_PREP(LOAD_CLK_CNTR_INIT_EN, 0) |
-+ FIELD_PREP(FEA_STATUS_DEV_ADDR_MASK, FEA_STATUS_DEV_ADDR) |
-+ FIELD_PREP(SPI_CFG, 0);
-+
-+ snandc->regs->spi_cfg = cpu_to_le32(snand_cfg_val);
-+ snandc->regs->num_addr_cycle = cpu_to_le32(SPI_NUM_ADDR);
-+ snandc->regs->busy_wait_cnt = cpu_to_le32(SPI_WAIT_CNT);
-+
-+ qcom_write_reg_dma(snandc, &snandc->regs->spi_cfg, NAND_FLASH_SPI_CFG, 1, 0);
-+
-+ snand_cfg_val &= ~LOAD_CLK_CNTR_INIT_EN;
-+ snandc->regs->spi_cfg = cpu_to_le32(snand_cfg_val);
-+
-+ qcom_write_reg_dma(snandc, &snandc->regs->spi_cfg, NAND_FLASH_SPI_CFG, 1, 0);
-+
-+ qcom_write_reg_dma(snandc, &snandc->regs->num_addr_cycle, NAND_NUM_ADDR_CYCLES, 1, 0);
-+ qcom_write_reg_dma(snandc, &snandc->regs->busy_wait_cnt, NAND_BUSY_CHECK_WAIT_CNT, 1,
-+ NAND_BAM_NEXT_SGL);
-+
-+ ret = qcom_submit_descs(snandc);
-+ if (ret) {
-+ dev_err(snandc->dev, "failure in submitting spi init descriptor\n");
-+ return ret;
-+ }
-+
-+ return ret;
-+}
-+
-+static int qcom_spi_ooblayout_ecc(struct mtd_info *mtd, int section,
-+ struct mtd_oob_region *oobregion)
-+{
-+ struct nand_device *nand = mtd_to_nanddev(mtd);
-+ struct qcom_nand_controller *snandc = nand_to_qcom_snand(nand);
-+ struct qpic_ecc *qecc = snandc->qspi->ecc;
-+
-+ if (section > 1)
-+ return -ERANGE;
-+
-+ oobregion->length = qecc->ecc_bytes_hw + qecc->spare_bytes;
-+ oobregion->offset = mtd->oobsize - oobregion->length;
-+
-+ return 0;
-+}
-+
-+static int qcom_spi_ooblayout_free(struct mtd_info *mtd, int section,
-+ struct mtd_oob_region *oobregion)
-+{
-+ struct nand_device *nand = mtd_to_nanddev(mtd);
-+ struct qcom_nand_controller *snandc = nand_to_qcom_snand(nand);
-+ struct qpic_ecc *qecc = snandc->qspi->ecc;
-+
-+ if (section)
-+ return -ERANGE;
-+
-+ oobregion->length = qecc->steps * 4;
-+ oobregion->offset = ((qecc->steps - 1) * qecc->bytes) + qecc->bbm_size;
-+
-+ return 0;
-+}
-+
-+static const struct mtd_ooblayout_ops qcom_spi_ooblayout = {
-+ .ecc = qcom_spi_ooblayout_ecc,
-+ .free = qcom_spi_ooblayout_free,
-+};
-+
-+static int qcom_spi_ecc_init_ctx_pipelined(struct nand_device *nand)
-+{
-+ struct qcom_nand_controller *snandc = nand_to_qcom_snand(nand);
-+ struct nand_ecc_props *conf = &nand->ecc.ctx.conf;
-+ struct mtd_info *mtd = nanddev_to_mtd(nand);
-+ int cwperpage, bad_block_byte;
-+ struct qpic_ecc *ecc_cfg;
-+
-+ cwperpage = mtd->writesize / NANDC_STEP_SIZE;
-+ snandc->qspi->num_cw = cwperpage;
-+
-+ ecc_cfg = kzalloc(sizeof(*ecc_cfg), GFP_KERNEL);
-+ if (!ecc_cfg)
-+ return -ENOMEM;
-+ snandc->qspi->oob_buf = kzalloc(mtd->writesize + mtd->oobsize,
-+ GFP_KERNEL);
-+ if (!snandc->qspi->oob_buf)
-+ return -ENOMEM;
-+
-+ memset(snandc->qspi->oob_buf, 0xff, mtd->writesize + mtd->oobsize);
-+
-+ nand->ecc.ctx.priv = ecc_cfg;
-+ snandc->qspi->mtd = mtd;
-+
-+ ecc_cfg->ecc_bytes_hw = 7;
-+ ecc_cfg->spare_bytes = 4;
-+ ecc_cfg->bbm_size = 1;
-+ ecc_cfg->bch_enabled = true;
-+ ecc_cfg->bytes = ecc_cfg->ecc_bytes_hw + ecc_cfg->spare_bytes + ecc_cfg->bbm_size;
-+
-+ ecc_cfg->steps = 4;
-+ ecc_cfg->strength = 4;
-+ ecc_cfg->step_size = 512;
-+ ecc_cfg->cw_data = 516;
-+ ecc_cfg->cw_size = ecc_cfg->cw_data + ecc_cfg->bytes;
-+ bad_block_byte = mtd->writesize - ecc_cfg->cw_size * (cwperpage - 1) + 1;
-+
-+ mtd_set_ooblayout(mtd, &qcom_spi_ooblayout);
-+
-+ ecc_cfg->cfg0 = FIELD_PREP(CW_PER_PAGE_MASK, (cwperpage - 1)) |
-+ FIELD_PREP(UD_SIZE_BYTES_MASK, ecc_cfg->cw_data) |
-+ FIELD_PREP(DISABLE_STATUS_AFTER_WRITE, 1) |
-+ FIELD_PREP(NUM_ADDR_CYCLES_MASK, 3) |
-+ FIELD_PREP(ECC_PARITY_SIZE_BYTES_RS, ecc_cfg->ecc_bytes_hw) |
-+ FIELD_PREP(STATUS_BFR_READ, 0) |
-+ FIELD_PREP(SET_RD_MODE_AFTER_STATUS, 1) |
-+ FIELD_PREP(SPARE_SIZE_BYTES_MASK, ecc_cfg->spare_bytes);
-+
-+ ecc_cfg->cfg1 = FIELD_PREP(NAND_RECOVERY_CYCLES_MASK, 0) |
-+ FIELD_PREP(CS_ACTIVE_BSY, 0) |
-+ FIELD_PREP(BAD_BLOCK_BYTE_NUM_MASK, bad_block_byte) |
-+ FIELD_PREP(BAD_BLOCK_IN_SPARE_AREA, 0) |
-+ FIELD_PREP(WR_RD_BSY_GAP_MASK, 20) |
-+ FIELD_PREP(WIDE_FLASH, 0) |
-+ FIELD_PREP(ENABLE_BCH_ECC, ecc_cfg->bch_enabled);
-+
-+ ecc_cfg->cfg0_raw = FIELD_PREP(CW_PER_PAGE_MASK, (cwperpage - 1)) |
-+ FIELD_PREP(NUM_ADDR_CYCLES_MASK, 3) |
-+ FIELD_PREP(UD_SIZE_BYTES_MASK, ecc_cfg->cw_size) |
-+ FIELD_PREP(SPARE_SIZE_BYTES_MASK, 0);
-+
-+ ecc_cfg->cfg1_raw = FIELD_PREP(NAND_RECOVERY_CYCLES_MASK, 0) |
-+ FIELD_PREP(CS_ACTIVE_BSY, 0) |
-+ FIELD_PREP(BAD_BLOCK_BYTE_NUM_MASK, 17) |
-+ FIELD_PREP(BAD_BLOCK_IN_SPARE_AREA, 1) |
-+ FIELD_PREP(WR_RD_BSY_GAP_MASK, 20) |
-+ FIELD_PREP(WIDE_FLASH, 0) |
-+ FIELD_PREP(DEV0_CFG1_ECC_DISABLE, 1);
-+
-+ ecc_cfg->ecc_bch_cfg = FIELD_PREP(ECC_CFG_ECC_DISABLE, !ecc_cfg->bch_enabled) |
-+ FIELD_PREP(ECC_SW_RESET, 0) |
-+ FIELD_PREP(ECC_NUM_DATA_BYTES_MASK, ecc_cfg->cw_data) |
-+ FIELD_PREP(ECC_FORCE_CLK_OPEN, 1) |
-+ FIELD_PREP(ECC_MODE_MASK, 0) |
-+ FIELD_PREP(ECC_PARITY_SIZE_BYTES_BCH_MASK, ecc_cfg->ecc_bytes_hw);
-+
-+ ecc_cfg->ecc_buf_cfg = 0x203 << NUM_STEPS;
-+ ecc_cfg->clrflashstatus = FS_READY_BSY_N;
-+ ecc_cfg->clrreadstatus = 0xc0;
-+
-+ conf->step_size = ecc_cfg->step_size;
-+ conf->strength = ecc_cfg->strength;
-+
-+ snandc->regs->erased_cw_detect_cfg_clr = cpu_to_le32(CLR_ERASED_PAGE_DET);
-+ snandc->regs->erased_cw_detect_cfg_set = cpu_to_le32(SET_ERASED_PAGE_DET);
-+
-+ dev_dbg(snandc->dev, "ECC strength: %u bits per %u bytes\n",
-+ ecc_cfg->strength, ecc_cfg->step_size);
-+
-+ return 0;
-+}
-+
-+static void qcom_spi_ecc_cleanup_ctx_pipelined(struct nand_device *nand)
-+{
-+ struct qpic_ecc *ecc_cfg = nand_to_ecc_ctx(nand);
-+
-+ kfree(ecc_cfg);
-+}
-+
-+static int qcom_spi_ecc_prepare_io_req_pipelined(struct nand_device *nand,
-+ struct nand_page_io_req *req)
-+{
-+ struct qcom_nand_controller *snandc = nand_to_qcom_snand(nand);
-+ struct qpic_ecc *ecc_cfg = nand_to_ecc_ctx(nand);
-+
-+ snandc->qspi->ecc = ecc_cfg;
-+ snandc->qspi->raw_rw = false;
-+ snandc->qspi->oob_rw = false;
-+ snandc->qspi->page_rw = false;
-+
-+ if (req->datalen)
-+ snandc->qspi->page_rw = true;
-+
-+ if (req->ooblen)
-+ snandc->qspi->oob_rw = true;
-+
-+ if (req->mode == MTD_OPS_RAW)
-+ snandc->qspi->raw_rw = true;
-+
-+ return 0;
-+}
-+
-+static int qcom_spi_ecc_finish_io_req_pipelined(struct nand_device *nand,
-+ struct nand_page_io_req *req)
-+{
-+ struct qcom_nand_controller *snandc = nand_to_qcom_snand(nand);
-+ struct mtd_info *mtd = nanddev_to_mtd(nand);
-+
-+ if (req->mode == MTD_OPS_RAW || req->type != NAND_PAGE_READ)
-+ return 0;
-+
-+ if (snandc->qspi->ecc_stats.failed)
-+ mtd->ecc_stats.failed += snandc->qspi->ecc_stats.failed;
-+ else
-+ mtd->ecc_stats.corrected += snandc->qspi->ecc_stats.corrected;
-+
-+ if (snandc->qspi->ecc_stats.failed)
-+ return -EBADMSG;
-+ else
-+ return snandc->qspi->ecc_stats.bitflips;
-+}
-+
-+static struct nand_ecc_engine_ops qcom_spi_ecc_engine_ops_pipelined = {
-+ .init_ctx = qcom_spi_ecc_init_ctx_pipelined,
-+ .cleanup_ctx = qcom_spi_ecc_cleanup_ctx_pipelined,
-+ .prepare_io_req = qcom_spi_ecc_prepare_io_req_pipelined,
-+ .finish_io_req = qcom_spi_ecc_finish_io_req_pipelined,
-+};
-+
-+/* helper to configure location register values */
-+static void qcom_spi_set_read_loc(struct qcom_nand_controller *snandc, int cw, int reg,
-+ int cw_offset, int read_size, int is_last_read_loc)
-+{
-+ int reg_base = NAND_READ_LOCATION_0;
-+ int num_cw = snandc->qspi->num_cw;
-+
-+ if (cw == (num_cw - 1))
-+ reg_base = NAND_READ_LOCATION_LAST_CW_0;
-+
-+ reg_base += reg * 4;
-+
-+ if (cw == (num_cw - 1))
-+ return qcom_spi_set_read_loc_last(snandc, reg_base, cw_offset,
-+ read_size, is_last_read_loc);
-+ else
-+ return qcom_spi_set_read_loc_first(snandc, reg_base, cw_offset,
-+ read_size, is_last_read_loc);
-+}
-+
-+static void
-+qcom_spi_config_cw_read(struct qcom_nand_controller *snandc, bool use_ecc, int cw)
-+{
-+ __le32 *reg = &snandc->regs->read_location0;
-+ int num_cw = snandc->qspi->num_cw;
-+
-+ qcom_write_reg_dma(snandc, reg, NAND_READ_LOCATION_0, 4, NAND_BAM_NEXT_SGL);
-+ if (cw == (num_cw - 1)) {
-+ reg = &snandc->regs->read_location_last0;
-+ qcom_write_reg_dma(snandc, reg, NAND_READ_LOCATION_LAST_CW_0, 4,
-+ NAND_BAM_NEXT_SGL);
-+ }
-+
-+ qcom_write_reg_dma(snandc, &snandc->regs->cmd, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
-+ qcom_write_reg_dma(snandc, &snandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
-+
-+ qcom_read_reg_dma(snandc, NAND_FLASH_STATUS, 2, 0);
-+ qcom_read_reg_dma(snandc, NAND_ERASED_CW_DETECT_STATUS, 1,
-+ NAND_BAM_NEXT_SGL);
-+}
-+
-+static int qcom_spi_block_erase(struct qcom_nand_controller *snandc)
-+{
-+ struct qpic_ecc *ecc_cfg = snandc->qspi->ecc;
-+ int ret;
-+
-+ snandc->buf_count = 0;
-+ snandc->buf_start = 0;
-+ qcom_clear_read_regs(snandc);
-+ qcom_clear_bam_transaction(snandc);
-+
-+ snandc->regs->cmd = snandc->qspi->cmd;
-+ snandc->regs->addr0 = snandc->qspi->addr1;
-+ snandc->regs->addr1 = snandc->qspi->addr2;
-+ snandc->regs->cfg0 = cpu_to_le32(ecc_cfg->cfg0_raw & ~(7 << CW_PER_PAGE));
-+ snandc->regs->cfg1 = cpu_to_le32(ecc_cfg->cfg1_raw);
-+ snandc->regs->exec = cpu_to_le32(1);
-+
-+ qcom_write_reg_dma(snandc, &snandc->regs->cmd, NAND_FLASH_CMD, 3, NAND_BAM_NEXT_SGL);
-+ qcom_write_reg_dma(snandc, &snandc->regs->cfg0, NAND_DEV0_CFG0, 2, NAND_BAM_NEXT_SGL);
-+ qcom_write_reg_dma(snandc, &snandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
-+
-+ ret = qcom_submit_descs(snandc);
-+ if (ret) {
-+ dev_err(snandc->dev, "failure to erase block\n");
-+ return ret;
-+ }
-+
-+ return 0;
-+}
-+
-+static void qcom_spi_config_single_cw_page_read(struct qcom_nand_controller *snandc,
-+ bool use_ecc, int cw)
-+{
-+ __le32 *reg = &snandc->regs->read_location0;
-+ int num_cw = snandc->qspi->num_cw;
-+
-+ qcom_write_reg_dma(snandc, &snandc->regs->addr0, NAND_ADDR0, 2, 0);
-+ qcom_write_reg_dma(snandc, &snandc->regs->cfg0, NAND_DEV0_CFG0, 3, 0);
-+ qcom_write_reg_dma(snandc, &snandc->regs->erased_cw_detect_cfg_clr,
-+ NAND_ERASED_CW_DETECT_CFG, 1, 0);
-+ qcom_write_reg_dma(snandc, &snandc->regs->erased_cw_detect_cfg_set,
-+ NAND_ERASED_CW_DETECT_CFG, 1,
-+ NAND_ERASED_CW_SET | NAND_BAM_NEXT_SGL);
-+
-+ if (cw == (num_cw - 1)) {
-+ reg = &snandc->regs->read_location_last0;
-+ qcom_write_reg_dma(snandc, reg, NAND_READ_LOCATION_LAST_CW_0, 4, NAND_BAM_NEXT_SGL);
-+ }
-+ qcom_write_reg_dma(snandc, &snandc->regs->cmd, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
-+ qcom_write_reg_dma(snandc, &snandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
-+
-+ qcom_read_reg_dma(snandc, NAND_FLASH_STATUS, 1, 0);
-+}
-+
-+static int qcom_spi_read_last_cw(struct qcom_nand_controller *snandc,
-+ const struct spi_mem_op *op)
-+{
-+ struct qpic_ecc *ecc_cfg = snandc->qspi->ecc;
-+ struct mtd_info *mtd = snandc->qspi->mtd;
-+ int size, ret = 0;
-+ int col, bbpos;
-+ u32 cfg0, cfg1, ecc_bch_cfg;
-+ u32 num_cw = snandc->qspi->num_cw;
-+
-+ qcom_clear_bam_transaction(snandc);
-+ qcom_clear_read_regs(snandc);
-+
-+ size = ecc_cfg->cw_size;
-+ col = ecc_cfg->cw_size * (num_cw - 1);
-+
-+ memset(snandc->data_buffer, 0xff, size);
-+ snandc->regs->addr0 = (snandc->qspi->addr1 | cpu_to_le32(col));
-+ snandc->regs->addr1 = snandc->qspi->addr2;
-+
-+ cfg0 = (ecc_cfg->cfg0_raw & ~(7U << CW_PER_PAGE)) |
-+ 0 << CW_PER_PAGE;
-+ cfg1 = ecc_cfg->cfg1_raw;
-+ ecc_bch_cfg = 1 << ECC_CFG_ECC_DISABLE;
-+
-+ snandc->regs->cmd = snandc->qspi->cmd;
-+ snandc->regs->cfg0 = cpu_to_le32(cfg0);
-+ snandc->regs->cfg1 = cpu_to_le32(cfg1);
-+ snandc->regs->ecc_bch_cfg = cpu_to_le32(ecc_bch_cfg);
-+ snandc->regs->clrflashstatus = cpu_to_le32(ecc_cfg->clrflashstatus);
-+ snandc->regs->clrreadstatus = cpu_to_le32(ecc_cfg->clrreadstatus);
-+ snandc->regs->exec = cpu_to_le32(1);
-+
-+ qcom_spi_set_read_loc(snandc, num_cw - 1, 0, 0, ecc_cfg->cw_size, 1);
-+
-+ qcom_spi_config_single_cw_page_read(snandc, false, num_cw - 1);
-+
-+ qcom_read_data_dma(snandc, FLASH_BUF_ACC, snandc->data_buffer, size, 0);
-+
-+ ret = qcom_submit_descs(snandc);
-+ if (ret) {
-+ dev_err(snandc->dev, "failed to read last cw\n");
-+ return ret;
-+ }
-+
-+ qcom_nandc_dev_to_mem(snandc, true);
-+ u32 flash = le32_to_cpu(snandc->reg_read_buf[0]);
-+
-+ if (flash & (FS_OP_ERR | FS_MPU_ERR))
-+ return -EIO;
-+
-+ bbpos = mtd->writesize - ecc_cfg->cw_size * (num_cw - 1);
-+
-+ if (snandc->data_buffer[bbpos] == 0xff)
-+ snandc->data_buffer[bbpos + 1] = 0xff;
-+ if (snandc->data_buffer[bbpos] != 0xff)
-+ snandc->data_buffer[bbpos + 1] = snandc->data_buffer[bbpos];
-+
-+ memcpy(op->data.buf.in, snandc->data_buffer + bbpos, op->data.nbytes);
-+
-+ return ret;
-+}
-+
-+static int qcom_spi_check_error(struct qcom_nand_controller *snandc, u8 *data_buf, u8 *oob_buf)
-+{
-+ struct snandc_read_status *buf;
-+ struct qpic_ecc *ecc_cfg = snandc->qspi->ecc;
-+ int i, num_cw = snandc->qspi->num_cw;
-+ bool flash_op_err = false, erased;
-+ unsigned int max_bitflips = 0;
-+ unsigned int uncorrectable_cws = 0;
-+
-+ snandc->qspi->ecc_stats.failed = 0;
-+ snandc->qspi->ecc_stats.corrected = 0;
-+
-+ qcom_nandc_dev_to_mem(snandc, true);
-+ buf = (struct snandc_read_status *)snandc->reg_read_buf;
-+
-+ for (i = 0; i < num_cw; i++, buf++) {
-+ u32 flash, buffer, erased_cw;
-+ int data_len, oob_len;
-+
-+ if (i == (num_cw - 1)) {
-+ data_len = NANDC_STEP_SIZE - ((num_cw - 1) << 2);
-+ oob_len = num_cw << 2;
-+ } else {
-+ data_len = ecc_cfg->cw_data;
-+ oob_len = 0;
-+ }
-+
-+ flash = le32_to_cpu(buf->snandc_flash);
-+ buffer = le32_to_cpu(buf->snandc_buffer);
-+ erased_cw = le32_to_cpu(buf->snandc_erased_cw);
-+
-+ if ((flash & FS_OP_ERR) && (buffer & BS_UNCORRECTABLE_BIT)) {
-+ if (ecc_cfg->bch_enabled)
-+ erased = (erased_cw & ERASED_CW) == ERASED_CW;
-+ else
-+ erased = false;
-+
-+ if (!erased)
-+ uncorrectable_cws |= BIT(i);
-+
-+ } else if (flash & (FS_OP_ERR | FS_MPU_ERR)) {
-+ flash_op_err = true;
-+ } else {
-+ unsigned int stat;
-+
-+ stat = buffer & BS_CORRECTABLE_ERR_MSK;
-+ snandc->qspi->ecc_stats.corrected += stat;
-+ max_bitflips = max(max_bitflips, stat);
-+ }
-+
-+ if (data_buf)
-+ data_buf += data_len;
-+ if (oob_buf)
-+ oob_buf += oob_len + ecc_cfg->bytes;
-+ }
-+
-+ if (flash_op_err)
-+ return -EIO;
-+
-+ if (!uncorrectable_cws)
-+ snandc->qspi->ecc_stats.bitflips = max_bitflips;
-+ else
-+ snandc->qspi->ecc_stats.failed++;
-+
-+ return 0;
-+}
-+
-+static int qcom_spi_check_raw_flash_errors(struct qcom_nand_controller *snandc, int cw_cnt)
-+{
-+ int i;
-+
-+ qcom_nandc_dev_to_mem(snandc, true);
-+
-+ for (i = 0; i < cw_cnt; i++) {
-+ u32 flash = le32_to_cpu(snandc->reg_read_buf[i]);
-+
-+ if (flash & (FS_OP_ERR | FS_MPU_ERR))
-+ return -EIO;
-+ }
-+
-+ return 0;
-+}
-+
-+static int qcom_spi_read_cw_raw(struct qcom_nand_controller *snandc, u8 *data_buf,
-+ u8 *oob_buf, int cw)
-+{
-+ struct qpic_ecc *ecc_cfg = snandc->qspi->ecc;
-+ struct mtd_info *mtd = snandc->qspi->mtd;
-+ int data_size1, data_size2, oob_size1, oob_size2;
-+ int ret, reg_off = FLASH_BUF_ACC, read_loc = 0;
-+ int raw_cw = cw;
-+ u32 cfg0, cfg1, ecc_bch_cfg, num_cw = snandc->qspi->num_cw;
-+ int col;
-+
-+ snandc->buf_count = 0;
-+ snandc->buf_start = 0;
-+ qcom_clear_read_regs(snandc);
-+ qcom_clear_bam_transaction(snandc);
-+ raw_cw = num_cw - 1;
-+
-+ cfg0 = (ecc_cfg->cfg0_raw & ~(7U << CW_PER_PAGE)) |
-+ 0 << CW_PER_PAGE;
-+ cfg1 = ecc_cfg->cfg1_raw;
-+ ecc_bch_cfg = ECC_CFG_ECC_DISABLE;
-+
-+ col = ecc_cfg->cw_size * cw;
-+
-+ snandc->regs->addr0 = (snandc->qspi->addr1 | cpu_to_le32(col));
-+ snandc->regs->addr1 = snandc->qspi->addr2;
-+ snandc->regs->cmd = snandc->qspi->cmd;
-+ snandc->regs->cfg0 = cpu_to_le32(cfg0);
-+ snandc->regs->cfg1 = cpu_to_le32(cfg1);
-+ snandc->regs->ecc_bch_cfg = cpu_to_le32(ecc_bch_cfg);
-+ snandc->regs->clrflashstatus = cpu_to_le32(ecc_cfg->clrflashstatus);
-+ snandc->regs->clrreadstatus = cpu_to_le32(ecc_cfg->clrreadstatus);
-+ snandc->regs->exec = cpu_to_le32(1);
-+
-+ qcom_spi_set_read_loc(snandc, raw_cw, 0, 0, ecc_cfg->cw_size, 1);
-+
-+ qcom_write_reg_dma(snandc, &snandc->regs->addr0, NAND_ADDR0, 2, 0);
-+ qcom_write_reg_dma(snandc, &snandc->regs->cfg0, NAND_DEV0_CFG0, 3, 0);
-+ qcom_write_reg_dma(snandc, &snandc->regs->ecc_buf_cfg, NAND_EBI2_ECC_BUF_CFG, 1, 0);
-+
-+ qcom_write_reg_dma(snandc, &snandc->regs->erased_cw_detect_cfg_clr,
-+ NAND_ERASED_CW_DETECT_CFG, 1, 0);
-+ qcom_write_reg_dma(snandc, &snandc->regs->erased_cw_detect_cfg_set,
-+ NAND_ERASED_CW_DETECT_CFG, 1,
-+ NAND_ERASED_CW_SET | NAND_BAM_NEXT_SGL);
-+
-+ data_size1 = mtd->writesize - ecc_cfg->cw_size * (num_cw - 1);
-+ oob_size1 = ecc_cfg->bbm_size;
-+
-+ if (cw == (num_cw - 1)) {
-+ data_size2 = NANDC_STEP_SIZE - data_size1 -
-+ ((num_cw - 1) * 4);
-+ oob_size2 = (num_cw * 4) + ecc_cfg->ecc_bytes_hw +
-+ ecc_cfg->spare_bytes;
-+ } else {
-+ data_size2 = ecc_cfg->cw_data - data_size1;
-+ oob_size2 = ecc_cfg->ecc_bytes_hw + ecc_cfg->spare_bytes;
-+ }
-+
-+ qcom_spi_set_read_loc(snandc, cw, 0, read_loc, data_size1, 0);
-+ read_loc += data_size1;
-+
-+ qcom_spi_set_read_loc(snandc, cw, 1, read_loc, oob_size1, 0);
-+ read_loc += oob_size1;
-+
-+ qcom_spi_set_read_loc(snandc, cw, 2, read_loc, data_size2, 0);
-+ read_loc += data_size2;
-+
-+ qcom_spi_set_read_loc(snandc, cw, 3, read_loc, oob_size2, 1);
-+
-+ qcom_spi_config_cw_read(snandc, false, raw_cw);
-+
-+ qcom_read_data_dma(snandc, reg_off, data_buf, data_size1, 0);
-+ reg_off += data_size1;
-+
-+ qcom_read_data_dma(snandc, reg_off, oob_buf, oob_size1, 0);
-+ reg_off += oob_size1;
-+
-+ qcom_read_data_dma(snandc, reg_off, data_buf + data_size1, data_size2, 0);
-+ reg_off += data_size2;
-+
-+ qcom_read_data_dma(snandc, reg_off, oob_buf + oob_size1, oob_size2, 0);
-+
-+ ret = qcom_submit_descs(snandc);
-+ if (ret) {
-+ dev_err(snandc->dev, "failure to read raw cw %d\n", cw);
-+ return ret;
-+ }
-+
-+ return qcom_spi_check_raw_flash_errors(snandc, 1);
-+}
-+
-+static int qcom_spi_read_page_raw(struct qcom_nand_controller *snandc,
-+ const struct spi_mem_op *op)
-+{
-+ struct qpic_ecc *ecc_cfg = snandc->qspi->ecc;
-+ u8 *data_buf = NULL, *oob_buf = NULL;
-+ int ret, cw;
-+ u32 num_cw = snandc->qspi->num_cw;
-+
-+ if (snandc->qspi->page_rw)
-+ data_buf = op->data.buf.in;
-+
-+ oob_buf = snandc->qspi->oob_buf;
-+ memset(oob_buf, 0xff, OOB_BUF_SIZE);
-+
-+ for (cw = 0; cw < num_cw; cw++) {
-+ ret = qcom_spi_read_cw_raw(snandc, data_buf, oob_buf, cw);
-+ if (ret)
-+ return ret;
-+
-+ if (data_buf)
-+ data_buf += ecc_cfg->cw_data;
-+ if (oob_buf)
-+ oob_buf += ecc_cfg->bytes;
-+ }
-+
-+ return 0;
-+}
-+
-+static int qcom_spi_read_page_ecc(struct qcom_nand_controller *snandc,
-+ const struct spi_mem_op *op)
-+{
-+ struct qpic_ecc *ecc_cfg = snandc->qspi->ecc;
-+ u8 *data_buf = NULL, *data_buf_start, *oob_buf = NULL, *oob_buf_start;
-+ int ret, i;
-+ u32 cfg0, cfg1, ecc_bch_cfg, num_cw = snandc->qspi->num_cw;
-+
-+ data_buf = op->data.buf.in;
-+ data_buf_start = data_buf;
-+
-+ oob_buf = snandc->qspi->oob_buf;
-+ oob_buf_start = oob_buf;
-+
-+ snandc->buf_count = 0;
-+ snandc->buf_start = 0;
-+ qcom_clear_read_regs(snandc);
-+
-+ cfg0 = (ecc_cfg->cfg0 & ~(7U << CW_PER_PAGE)) |
-+ (num_cw - 1) << CW_PER_PAGE;
-+ cfg1 = ecc_cfg->cfg1;
-+ ecc_bch_cfg = ecc_cfg->ecc_bch_cfg;
-+
-+ snandc->regs->addr0 = snandc->qspi->addr1;
-+ snandc->regs->addr1 = snandc->qspi->addr2;
-+ snandc->regs->cmd = snandc->qspi->cmd;
-+ snandc->regs->cfg0 = cpu_to_le32(cfg0);
-+ snandc->regs->cfg1 = cpu_to_le32(cfg1);
-+ snandc->regs->ecc_bch_cfg = cpu_to_le32(ecc_bch_cfg);
-+ snandc->regs->clrflashstatus = cpu_to_le32(ecc_cfg->clrflashstatus);
-+ snandc->regs->clrreadstatus = cpu_to_le32(ecc_cfg->clrreadstatus);
-+ snandc->regs->exec = cpu_to_le32(1);
-+
-+ qcom_spi_set_read_loc(snandc, 0, 0, 0, ecc_cfg->cw_data, 1);
-+
-+ qcom_clear_bam_transaction(snandc);
-+
-+ qcom_write_reg_dma(snandc, &snandc->regs->addr0, NAND_ADDR0, 2, 0);
-+ qcom_write_reg_dma(snandc, &snandc->regs->cfg0, NAND_DEV0_CFG0, 3, 0);
-+ qcom_write_reg_dma(snandc, &snandc->regs->erased_cw_detect_cfg_clr,
-+ NAND_ERASED_CW_DETECT_CFG, 1, 0);
-+ qcom_write_reg_dma(snandc, &snandc->regs->erased_cw_detect_cfg_set,
-+ NAND_ERASED_CW_DETECT_CFG, 1,
-+ NAND_ERASED_CW_SET | NAND_BAM_NEXT_SGL);
-+
-+ for (i = 0; i < num_cw; i++) {
-+ int data_size, oob_size;
-+
-+ if (i == (num_cw - 1)) {
-+ data_size = 512 - ((num_cw - 1) << 2);
-+ oob_size = (num_cw << 2) + ecc_cfg->ecc_bytes_hw +
-+ ecc_cfg->spare_bytes;
-+ } else {
-+ data_size = ecc_cfg->cw_data;
-+ oob_size = ecc_cfg->ecc_bytes_hw + ecc_cfg->spare_bytes;
-+ }
-+
-+ if (data_buf && oob_buf) {
-+ qcom_spi_set_read_loc(snandc, i, 0, 0, data_size, 0);
-+ qcom_spi_set_read_loc(snandc, i, 1, data_size, oob_size, 1);
-+ } else if (data_buf) {
-+ qcom_spi_set_read_loc(snandc, i, 0, 0, data_size, 1);
-+ } else {
-+ qcom_spi_set_read_loc(snandc, i, 0, data_size, oob_size, 1);
-+ }
-+
-+ qcom_spi_config_cw_read(snandc, true, i);
-+
-+ if (data_buf)
-+ qcom_read_data_dma(snandc, FLASH_BUF_ACC, data_buf,
-+ data_size, 0);
-+ if (oob_buf) {
-+ int j;
-+
-+ for (j = 0; j < ecc_cfg->bbm_size; j++)
-+ *oob_buf++ = 0xff;
-+
-+ qcom_read_data_dma(snandc, FLASH_BUF_ACC + data_size,
-+ oob_buf, oob_size, 0);
-+ }
-+
-+ if (data_buf)
-+ data_buf += data_size;
-+ if (oob_buf)
-+ oob_buf += oob_size;
-+ }
-+
-+ ret = qcom_submit_descs(snandc);
-+ if (ret) {
-+ dev_err(snandc->dev, "failure to read page\n");
-+ return ret;
-+ }
-+
-+ return qcom_spi_check_error(snandc, data_buf_start, oob_buf_start);
-+}
-+
-+static int qcom_spi_read_page_oob(struct qcom_nand_controller *snandc,
-+ const struct spi_mem_op *op)
-+{
-+ struct qpic_ecc *ecc_cfg = snandc->qspi->ecc;
-+ u8 *data_buf = NULL, *data_buf_start, *oob_buf = NULL, *oob_buf_start;
-+ int ret, i;
-+ u32 cfg0, cfg1, ecc_bch_cfg, num_cw = snandc->qspi->num_cw;
-+
-+ oob_buf = op->data.buf.in;
-+ oob_buf_start = oob_buf;
-+
-+ data_buf_start = data_buf;
-+
-+ snandc->buf_count = 0;
-+ snandc->buf_start = 0;
-+ qcom_clear_read_regs(snandc);
-+ qcom_clear_bam_transaction(snandc);
-+
-+ cfg0 = (ecc_cfg->cfg0 & ~(7U << CW_PER_PAGE)) |
-+ (num_cw - 1) << CW_PER_PAGE;
-+ cfg1 = ecc_cfg->cfg1;
-+ ecc_bch_cfg = ecc_cfg->ecc_bch_cfg;
-+
-+ snandc->regs->addr0 = snandc->qspi->addr1;
-+ snandc->regs->addr1 = snandc->qspi->addr2;
-+ snandc->regs->cmd = snandc->qspi->cmd;
-+ snandc->regs->cfg0 = cpu_to_le32(cfg0);
-+ snandc->regs->cfg1 = cpu_to_le32(cfg1);
-+ snandc->regs->ecc_bch_cfg = cpu_to_le32(ecc_bch_cfg);
-+ snandc->regs->clrflashstatus = cpu_to_le32(ecc_cfg->clrflashstatus);
-+ snandc->regs->clrreadstatus = cpu_to_le32(ecc_cfg->clrreadstatus);
-+ snandc->regs->exec = cpu_to_le32(1);
-+
-+ qcom_spi_set_read_loc(snandc, 0, 0, 0, ecc_cfg->cw_data, 1);
-+
-+ qcom_write_reg_dma(snandc, &snandc->regs->addr0, NAND_ADDR0, 2, 0);
-+ qcom_write_reg_dma(snandc, &snandc->regs->cfg0, NAND_DEV0_CFG0, 3, 0);
-+ qcom_write_reg_dma(snandc, &snandc->regs->erased_cw_detect_cfg_clr,
-+ NAND_ERASED_CW_DETECT_CFG, 1, 0);
-+ qcom_write_reg_dma(snandc, &snandc->regs->erased_cw_detect_cfg_set,
-+ NAND_ERASED_CW_DETECT_CFG, 1,
-+ NAND_ERASED_CW_SET | NAND_BAM_NEXT_SGL);
-+
-+ for (i = 0; i < num_cw; i++) {
-+ int data_size, oob_size;
-+
-+ if (i == (num_cw - 1)) {
-+ data_size = NANDC_STEP_SIZE - ((num_cw - 1) << 2);
-+ oob_size = (num_cw << 2) + ecc_cfg->ecc_bytes_hw +
-+ ecc_cfg->spare_bytes;
-+ } else {
-+ data_size = ecc_cfg->cw_data;
-+ oob_size = ecc_cfg->ecc_bytes_hw + ecc_cfg->spare_bytes;
-+ }
-+
-+ qcom_spi_set_read_loc(snandc, i, 0, data_size, oob_size, 1);
-+
-+ qcom_spi_config_cw_read(snandc, true, i);
-+
-+ if (oob_buf) {
-+ int j;
-+
-+ for (j = 0; j < ecc_cfg->bbm_size; j++)
-+ *oob_buf++ = 0xff;
-+
-+ qcom_read_data_dma(snandc, FLASH_BUF_ACC + data_size,
-+ oob_buf, oob_size, 0);
-+ }
-+
-+ if (oob_buf)
-+ oob_buf += oob_size;
-+ }
-+
-+ ret = qcom_submit_descs(snandc);
-+ if (ret) {
-+ dev_err(snandc->dev, "failure to read oob\n");
-+ return ret;
-+ }
-+
-+ return qcom_spi_check_error(snandc, data_buf_start, oob_buf_start);
-+}
-+
-+static int qcom_spi_read_page(struct qcom_nand_controller *snandc,
-+ const struct spi_mem_op *op)
-+{
-+ if (snandc->qspi->page_rw && snandc->qspi->raw_rw)
-+ return qcom_spi_read_page_raw(snandc, op);
-+
-+ if (snandc->qspi->page_rw)
-+ return qcom_spi_read_page_ecc(snandc, op);
-+
-+ if (snandc->qspi->oob_rw && snandc->qspi->raw_rw)
-+ return qcom_spi_read_last_cw(snandc, op);
-+
-+ if (snandc->qspi->oob_rw)
-+ return qcom_spi_read_page_oob(snandc, op);
-+
-+ return 0;
-+}
-+
-+static void qcom_spi_config_page_write(struct qcom_nand_controller *snandc)
-+{
-+ qcom_write_reg_dma(snandc, &snandc->regs->addr0, NAND_ADDR0, 2, 0);
-+ qcom_write_reg_dma(snandc, &snandc->regs->cfg0, NAND_DEV0_CFG0, 3, 0);
-+ qcom_write_reg_dma(snandc, &snandc->regs->ecc_buf_cfg, NAND_EBI2_ECC_BUF_CFG,
-+ 1, NAND_BAM_NEXT_SGL);
-+}
-+
-+static void qcom_spi_config_cw_write(struct qcom_nand_controller *snandc)
-+{
-+ qcom_write_reg_dma(snandc, &snandc->regs->cmd, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
-+ qcom_write_reg_dma(snandc, &snandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
-+ qcom_read_reg_dma(snandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL);
-+
-+ qcom_write_reg_dma(snandc, &snandc->regs->clrflashstatus, NAND_FLASH_STATUS, 1, 0);
-+ qcom_write_reg_dma(snandc, &snandc->regs->clrreadstatus, NAND_READ_STATUS, 1,
-+ NAND_BAM_NEXT_SGL);
-+}
-+
-+static int qcom_spi_program_raw(struct qcom_nand_controller *snandc,
-+ const struct spi_mem_op *op)
-+{
-+ struct qpic_ecc *ecc_cfg = snandc->qspi->ecc;
-+ struct mtd_info *mtd = snandc->qspi->mtd;
-+ u8 *data_buf = NULL, *oob_buf = NULL;
-+ int i, ret;
-+ int num_cw = snandc->qspi->num_cw;
-+ u32 cfg0, cfg1, ecc_bch_cfg;
-+
-+ cfg0 = (ecc_cfg->cfg0_raw & ~(7U << CW_PER_PAGE)) |
-+ (num_cw - 1) << CW_PER_PAGE;
-+ cfg1 = ecc_cfg->cfg1_raw;
-+ ecc_bch_cfg = ECC_CFG_ECC_DISABLE;
-+
-+ data_buf = snandc->qspi->data_buf;
-+
-+ oob_buf = snandc->qspi->oob_buf;
-+ memset(oob_buf, 0xff, OOB_BUF_SIZE);
-+
-+ snandc->buf_count = 0;
-+ snandc->buf_start = 0;
-+ qcom_clear_read_regs(snandc);
-+ qcom_clear_bam_transaction(snandc);
-+
-+ snandc->regs->addr0 = snandc->qspi->addr1;
-+ snandc->regs->addr1 = snandc->qspi->addr2;
-+ snandc->regs->cmd = snandc->qspi->cmd;
-+ snandc->regs->cfg0 = cpu_to_le32(cfg0);
-+ snandc->regs->cfg1 = cpu_to_le32(cfg1);
-+ snandc->regs->ecc_bch_cfg = cpu_to_le32(ecc_bch_cfg);
-+ snandc->regs->clrflashstatus = cpu_to_le32(ecc_cfg->clrflashstatus);
-+ snandc->regs->clrreadstatus = cpu_to_le32(ecc_cfg->clrreadstatus);
-+ snandc->regs->exec = cpu_to_le32(1);
-+
-+ qcom_spi_config_page_write(snandc);
-+
-+ for (i = 0; i < num_cw; i++) {
-+ int data_size1, data_size2, oob_size1, oob_size2;
-+ int reg_off = FLASH_BUF_ACC;
-+
-+ data_size1 = mtd->writesize - ecc_cfg->cw_size * (num_cw - 1);
-+ oob_size1 = ecc_cfg->bbm_size;
-+
-+ if (i == (num_cw - 1)) {
-+ data_size2 = NANDC_STEP_SIZE - data_size1 -
-+ ((num_cw - 1) << 2);
-+ oob_size2 = (num_cw << 2) + ecc_cfg->ecc_bytes_hw +
-+ ecc_cfg->spare_bytes;
-+ } else {
-+ data_size2 = ecc_cfg->cw_data - data_size1;
-+ oob_size2 = ecc_cfg->ecc_bytes_hw + ecc_cfg->spare_bytes;
-+ }
-+
-+ qcom_write_data_dma(snandc, reg_off, data_buf, data_size1,
-+ NAND_BAM_NO_EOT);
-+ reg_off += data_size1;
-+ data_buf += data_size1;
-+
-+ qcom_write_data_dma(snandc, reg_off, oob_buf, oob_size1,
-+ NAND_BAM_NO_EOT);
-+ oob_buf += oob_size1;
-+ reg_off += oob_size1;
-+
-+ qcom_write_data_dma(snandc, reg_off, data_buf, data_size2,
-+ NAND_BAM_NO_EOT);
-+ reg_off += data_size2;
-+ data_buf += data_size2;
-+
-+ qcom_write_data_dma(snandc, reg_off, oob_buf, oob_size2, 0);
-+ oob_buf += oob_size2;
-+
-+ qcom_spi_config_cw_write(snandc);
-+ }
-+
-+ ret = qcom_submit_descs(snandc);
-+ if (ret) {
-+ dev_err(snandc->dev, "failure to write raw page\n");
-+ return ret;
-+ }
-+
-+ return 0;
-+}
-+
-+static int qcom_spi_program_ecc(struct qcom_nand_controller *snandc,
-+ const struct spi_mem_op *op)
-+{
-+ struct qpic_ecc *ecc_cfg = snandc->qspi->ecc;
-+ u8 *data_buf = NULL, *oob_buf = NULL;
-+ int i, ret;
-+ int num_cw = snandc->qspi->num_cw;
-+ u32 cfg0, cfg1, ecc_bch_cfg, ecc_buf_cfg;
-+
-+ cfg0 = (ecc_cfg->cfg0 & ~(7U << CW_PER_PAGE)) |
-+ (num_cw - 1) << CW_PER_PAGE;
-+ cfg1 = ecc_cfg->cfg1;
-+ ecc_bch_cfg = ecc_cfg->ecc_bch_cfg;
-+ ecc_buf_cfg = ecc_cfg->ecc_buf_cfg;
-+
-+ if (snandc->qspi->data_buf)
-+ data_buf = snandc->qspi->data_buf;
-+
-+ oob_buf = snandc->qspi->oob_buf;
-+
-+ snandc->buf_count = 0;
-+ snandc->buf_start = 0;
-+ qcom_clear_read_regs(snandc);
-+ qcom_clear_bam_transaction(snandc);
-+
-+ snandc->regs->addr0 = snandc->qspi->addr1;
-+ snandc->regs->addr1 = snandc->qspi->addr2;
-+ snandc->regs->cmd = snandc->qspi->cmd;
-+ snandc->regs->cfg0 = cpu_to_le32(cfg0);
-+ snandc->regs->cfg1 = cpu_to_le32(cfg1);
-+ snandc->regs->ecc_bch_cfg = cpu_to_le32(ecc_bch_cfg);
-+ snandc->regs->ecc_buf_cfg = cpu_to_le32(ecc_buf_cfg);
-+ snandc->regs->exec = cpu_to_le32(1);
-+
-+ qcom_spi_config_page_write(snandc);
-+
-+ for (i = 0; i < num_cw; i++) {
-+ int data_size, oob_size;
-+
-+ if (i == (num_cw - 1)) {
-+ data_size = NANDC_STEP_SIZE - ((num_cw - 1) << 2);
-+ oob_size = (num_cw << 2) + ecc_cfg->ecc_bytes_hw +
-+ ecc_cfg->spare_bytes;
-+ } else {
-+ data_size = ecc_cfg->cw_data;
-+ oob_size = ecc_cfg->bytes;
-+ }
-+
-+ if (data_buf)
-+ qcom_write_data_dma(snandc, FLASH_BUF_ACC, data_buf, data_size,
-+ i == (num_cw - 1) ? NAND_BAM_NO_EOT : 0);
-+
-+ if (i == (num_cw - 1)) {
-+ if (oob_buf) {
-+ oob_buf += ecc_cfg->bbm_size;
-+ qcom_write_data_dma(snandc, FLASH_BUF_ACC + data_size,
-+ oob_buf, oob_size, 0);
-+ }
-+ }
-+
-+ qcom_spi_config_cw_write(snandc);
-+
-+ if (data_buf)
-+ data_buf += data_size;
-+ if (oob_buf)
-+ oob_buf += oob_size;
-+ }
-+
-+ ret = qcom_submit_descs(snandc);
-+ if (ret) {
-+ dev_err(snandc->dev, "failure to write page\n");
-+ return ret;
-+ }
-+
-+ return 0;
-+}
-+
-+static int qcom_spi_program_oob(struct qcom_nand_controller *snandc,
-+ const struct spi_mem_op *op)
-+{
-+ struct qpic_ecc *ecc_cfg = snandc->qspi->ecc;
-+ u8 *oob_buf = NULL;
-+ int ret, col, data_size, oob_size;
-+ int num_cw = snandc->qspi->num_cw;
-+ u32 cfg0, cfg1, ecc_bch_cfg, ecc_buf_cfg;
-+
-+ cfg0 = (ecc_cfg->cfg0 & ~(7U << CW_PER_PAGE)) |
-+ (num_cw - 1) << CW_PER_PAGE;
-+ cfg1 = ecc_cfg->cfg1;
-+ ecc_bch_cfg = ecc_cfg->ecc_bch_cfg;
-+ ecc_buf_cfg = ecc_cfg->ecc_buf_cfg;
-+
-+ col = ecc_cfg->cw_size * (num_cw - 1);
-+
-+ oob_buf = snandc->qspi->data_buf;
-+
-+ snandc->buf_count = 0;
-+ snandc->buf_start = 0;
-+ qcom_clear_read_regs(snandc);
-+ qcom_clear_bam_transaction(snandc);
-+ snandc->regs->addr0 = (snandc->qspi->addr1 | cpu_to_le32(col));
-+ snandc->regs->addr1 = snandc->qspi->addr2;
-+ snandc->regs->cmd = snandc->qspi->cmd;
-+ snandc->regs->cfg0 = cpu_to_le32(cfg0);
-+ snandc->regs->cfg1 = cpu_to_le32(cfg1);
-+ snandc->regs->ecc_bch_cfg = cpu_to_le32(ecc_bch_cfg);
-+ snandc->regs->ecc_buf_cfg = cpu_to_le32(ecc_buf_cfg);
-+ snandc->regs->exec = cpu_to_le32(1);
-+
-+ /* calculate the data and oob size for the last codeword/step */
-+ data_size = NANDC_STEP_SIZE - ((num_cw - 1) << 2);
-+ oob_size = snandc->qspi->mtd->oobavail;
-+
-+ memset(snandc->data_buffer, 0xff, ecc_cfg->cw_data);
-+ /* override new oob content to last codeword */
-+ mtd_ooblayout_get_databytes(snandc->qspi->mtd, snandc->data_buffer + data_size,
-+ oob_buf, 0, snandc->qspi->mtd->oobavail);
-+ qcom_spi_config_page_write(snandc);
-+ qcom_write_data_dma(snandc, FLASH_BUF_ACC, snandc->data_buffer, data_size + oob_size, 0);
-+ qcom_spi_config_cw_write(snandc);
-+
-+ ret = qcom_submit_descs(snandc);
-+ if (ret) {
-+ dev_err(snandc->dev, "failure to write oob\n");
-+ return ret;
-+ }
-+
-+ return 0;
-+}
-+
-+static int qcom_spi_program_execute(struct qcom_nand_controller *snandc,
-+ const struct spi_mem_op *op)
-+{
-+ if (snandc->qspi->page_rw && snandc->qspi->raw_rw)
-+ return qcom_spi_program_raw(snandc, op);
-+
-+ if (snandc->qspi->page_rw)
-+ return qcom_spi_program_ecc(snandc, op);
-+
-+ if (snandc->qspi->oob_rw)
-+ return qcom_spi_program_oob(snandc, op);
-+
-+ return 0;
-+}
-+
-+static int qcom_spi_cmd_mapping(struct qcom_nand_controller *snandc, u32 opcode, u32 *cmd)
-+{
-+ switch (opcode) {
-+ case SPINAND_RESET:
-+ *cmd = (SPI_WP | SPI_HOLD | SPI_TRANSFER_MODE_x1 | OP_RESET_DEVICE);
-+ break;
-+ case SPINAND_READID:
-+ *cmd = (SPI_WP | SPI_HOLD | SPI_TRANSFER_MODE_x1 | OP_FETCH_ID);
-+ break;
-+ case SPINAND_GET_FEATURE:
-+ *cmd = (SPI_TRANSFER_MODE_x1 | SPI_WP | SPI_HOLD | ACC_FEATURE);
-+ break;
-+ case SPINAND_SET_FEATURE:
-+ *cmd = (SPI_TRANSFER_MODE_x1 | SPI_WP | SPI_HOLD | ACC_FEATURE |
-+ QPIC_SET_FEATURE);
-+ break;
-+ case SPINAND_READ:
-+ if (snandc->qspi->raw_rw) {
-+ *cmd = (PAGE_ACC | LAST_PAGE | SPI_TRANSFER_MODE_x1 |
-+ SPI_WP | SPI_HOLD | OP_PAGE_READ);
-+ } else {
-+ *cmd = (PAGE_ACC | LAST_PAGE | SPI_TRANSFER_MODE_x1 |
-+ SPI_WP | SPI_HOLD | OP_PAGE_READ_WITH_ECC);
-+ }
-+
-+ break;
-+ case SPINAND_ERASE:
-+ *cmd = OP_BLOCK_ERASE | PAGE_ACC | LAST_PAGE | SPI_WP |
-+ SPI_HOLD | SPI_TRANSFER_MODE_x1;
-+ break;
-+ case SPINAND_WRITE_EN:
-+ *cmd = SPINAND_WRITE_EN;
-+ break;
-+ case SPINAND_PROGRAM_EXECUTE:
-+ *cmd = (PAGE_ACC | LAST_PAGE | SPI_TRANSFER_MODE_x1 |
-+ SPI_WP | SPI_HOLD | OP_PROGRAM_PAGE);
-+ break;
-+ case SPINAND_PROGRAM_LOAD:
-+ *cmd = SPINAND_PROGRAM_LOAD;
-+ break;
-+ default:
-+ dev_err(snandc->dev, "Opcode not supported: %u\n", opcode);
-+ return -EOPNOTSUPP;
-+ }
-+
-+ return 0;
-+}
-+
-+static int qcom_spi_write_page(struct qcom_nand_controller *snandc,
-+ const struct spi_mem_op *op)
-+{
-+ int ret;
-+ u32 cmd;
-+
-+ ret = qcom_spi_cmd_mapping(snandc, op->cmd.opcode, &cmd);
-+ if (ret < 0)
-+ return ret;
-+
-+ if (op->cmd.opcode == SPINAND_PROGRAM_LOAD)
-+ snandc->qspi->data_buf = (u8 *)op->data.buf.out;
-+
-+ return 0;
-+}
-+
-+static int qcom_spi_send_cmdaddr(struct qcom_nand_controller *snandc,
-+ const struct spi_mem_op *op)
-+{
-+ struct qpic_snand_op s_op = {};
-+ u32 cmd;
-+ int ret, opcode;
-+
-+ ret = qcom_spi_cmd_mapping(snandc, op->cmd.opcode, &cmd);
-+ if (ret < 0)
-+ return ret;
-+
-+ s_op.cmd_reg = cmd;
-+ s_op.addr1_reg = op->addr.val;
-+ s_op.addr2_reg = 0;
-+
-+ opcode = op->cmd.opcode;
-+
-+ switch (opcode) {
-+ case SPINAND_WRITE_EN:
-+ return 0;
-+ case SPINAND_PROGRAM_EXECUTE:
-+ s_op.addr1_reg = op->addr.val << 16;
-+ s_op.addr2_reg = op->addr.val >> 16 & 0xff;
-+ snandc->qspi->addr1 = cpu_to_le32(s_op.addr1_reg);
-+ snandc->qspi->addr2 = cpu_to_le32(s_op.addr2_reg);
-+ snandc->qspi->cmd = cpu_to_le32(cmd);
-+ return qcom_spi_program_execute(snandc, op);
-+ case SPINAND_READ:
-+ s_op.addr1_reg = (op->addr.val << 16);
-+ s_op.addr2_reg = op->addr.val >> 16 & 0xff;
-+ snandc->qspi->addr1 = cpu_to_le32(s_op.addr1_reg);
-+ snandc->qspi->addr2 = cpu_to_le32(s_op.addr2_reg);
-+ snandc->qspi->cmd = cpu_to_le32(cmd);
-+ return 0;
-+ case SPINAND_ERASE:
-+ s_op.addr2_reg = (op->addr.val >> 16) & 0xffff;
-+ s_op.addr1_reg = op->addr.val;
-+ snandc->qspi->addr1 = cpu_to_le32(s_op.addr1_reg << 16);
-+ snandc->qspi->addr2 = cpu_to_le32(s_op.addr2_reg);
-+ snandc->qspi->cmd = cpu_to_le32(cmd);
-+ qcom_spi_block_erase(snandc);
-+ return 0;
-+ default:
-+ break;
-+ }
-+
-+ snandc->buf_count = 0;
-+ snandc->buf_start = 0;
-+ qcom_clear_read_regs(snandc);
-+ qcom_clear_bam_transaction(snandc);
-+
-+ snandc->regs->cmd = cpu_to_le32(s_op.cmd_reg);
-+ snandc->regs->exec = cpu_to_le32(1);
-+ snandc->regs->addr0 = cpu_to_le32(s_op.addr1_reg);
-+ snandc->regs->addr1 = cpu_to_le32(s_op.addr2_reg);
-+
-+ qcom_write_reg_dma(snandc, &snandc->regs->cmd, NAND_FLASH_CMD, 3, NAND_BAM_NEXT_SGL);
-+ qcom_write_reg_dma(snandc, &snandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
-+
-+ ret = qcom_submit_descs(snandc);
-+ if (ret)
-+ dev_err(snandc->dev, "failure in submitting cmd descriptor\n");
-+
-+ return ret;
-+}
-+
-+static int qcom_spi_io_op(struct qcom_nand_controller *snandc, const struct spi_mem_op *op)
-+{
-+ int ret, val, opcode;
-+ bool copy = false, copy_ftr = false;
-+
-+ ret = qcom_spi_send_cmdaddr(snandc, op);
-+ if (ret)
-+ return ret;
-+
-+ snandc->buf_count = 0;
-+ snandc->buf_start = 0;
-+ qcom_clear_read_regs(snandc);
-+ qcom_clear_bam_transaction(snandc);
-+ opcode = op->cmd.opcode;
-+
-+ switch (opcode) {
-+ case SPINAND_READID:
-+ snandc->buf_count = 4;
-+ qcom_read_reg_dma(snandc, NAND_READ_ID, 1, NAND_BAM_NEXT_SGL);
-+ copy = true;
-+ break;
-+ case SPINAND_GET_FEATURE:
-+ snandc->buf_count = 4;
-+ qcom_read_reg_dma(snandc, NAND_FLASH_FEATURES, 1, NAND_BAM_NEXT_SGL);
-+ copy_ftr = true;
-+ break;
-+ case SPINAND_SET_FEATURE:
-+ snandc->regs->flash_feature = cpu_to_le32(*(u32 *)op->data.buf.out);
-+ qcom_write_reg_dma(snandc, &snandc->regs->flash_feature,
-+ NAND_FLASH_FEATURES, 1, NAND_BAM_NEXT_SGL);
-+ break;
-+ case SPINAND_PROGRAM_EXECUTE:
-+ case SPINAND_WRITE_EN:
-+ case SPINAND_RESET:
-+ case SPINAND_ERASE:
-+ case SPINAND_READ:
-+ return 0;
-+ default:
-+ return -EOPNOTSUPP;
-+ }
-+
-+ ret = qcom_submit_descs(snandc);
-+ if (ret)
-+ dev_err(snandc->dev, "failure in submitting descriptor for:%d\n", opcode);
-+
-+ if (copy) {
-+ qcom_nandc_dev_to_mem(snandc, true);
-+ memcpy(op->data.buf.in, snandc->reg_read_buf, snandc->buf_count);
-+ }
-+
-+ if (copy_ftr) {
-+ qcom_nandc_dev_to_mem(snandc, true);
-+ val = le32_to_cpu(*(__le32 *)snandc->reg_read_buf);
-+ val >>= 8;
-+ memcpy(op->data.buf.in, &val, snandc->buf_count);
-+ }
-+
-+ return ret;
-+}
-+
-+static bool qcom_spi_is_page_op(const struct spi_mem_op *op)
-+{
-+ if (op->addr.buswidth != 1 && op->addr.buswidth != 2 && op->addr.buswidth != 4)
-+ return false;
-+
-+ if (op->data.dir == SPI_MEM_DATA_IN) {
-+ if (op->addr.buswidth == 4 && op->data.buswidth == 4)
-+ return true;
-+
-+ if (op->addr.nbytes == 2 && op->addr.buswidth == 1)
-+ return true;
-+
-+ } else if (op->data.dir == SPI_MEM_DATA_OUT) {
-+ if (op->data.buswidth == 4)
-+ return true;
-+ if (op->addr.nbytes == 2 && op->addr.buswidth == 1)
-+ return true;
-+ }
-+
-+ return false;
-+}
-+
-+static bool qcom_spi_supports_op(struct spi_mem *mem, const struct spi_mem_op *op)
-+{
-+ if (!spi_mem_default_supports_op(mem, op))
-+ return false;
-+
-+ if (op->cmd.nbytes != 1 || op->cmd.buswidth != 1)
-+ return false;
-+
-+ if (qcom_spi_is_page_op(op))
-+ return true;
-+
-+ return ((!op->addr.nbytes || op->addr.buswidth == 1) &&
-+ (!op->dummy.nbytes || op->dummy.buswidth == 1) &&
-+ (!op->data.nbytes || op->data.buswidth == 1));
-+}
-+
-+static int qcom_spi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
-+{
-+ struct qcom_nand_controller *snandc = spi_controller_get_devdata(mem->spi->controller);
-+
-+ dev_dbg(snandc->dev, "OP %02x ADDR %08llX@%d:%u DATA %d:%u", op->cmd.opcode,
-+ op->addr.val, op->addr.buswidth, op->addr.nbytes,
-+ op->data.buswidth, op->data.nbytes);
-+
-+ if (qcom_spi_is_page_op(op)) {
-+ if (op->data.dir == SPI_MEM_DATA_IN)
-+ return qcom_spi_read_page(snandc, op);
-+ if (op->data.dir == SPI_MEM_DATA_OUT)
-+ return qcom_spi_write_page(snandc, op);
-+ } else {
-+ return qcom_spi_io_op(snandc, op);
-+ }
-+
-+ return 0;
-+}
-+
-+static const struct spi_controller_mem_ops qcom_spi_mem_ops = {
-+ .supports_op = qcom_spi_supports_op,
-+ .exec_op = qcom_spi_exec_op,
-+};
-+
-+static const struct spi_controller_mem_caps qcom_spi_mem_caps = {
-+ .ecc = true,
-+};
-+
-+static int qcom_spi_probe(struct platform_device *pdev)
-+{
-+ struct device *dev = &pdev->dev;
-+ struct spi_controller *ctlr;
-+ struct qcom_nand_controller *snandc;
-+ struct qpic_spi_nand *qspi;
-+ struct qpic_ecc *ecc;
-+ struct resource *res;
-+ const void *dev_data;
-+ int ret;
-+
-+ ecc = devm_kzalloc(dev, sizeof(*ecc), GFP_KERNEL);
-+ if (!ecc)
-+ return -ENOMEM;
-+
-+ qspi = devm_kzalloc(dev, sizeof(*qspi), GFP_KERNEL);
-+ if (!qspi)
-+ return -ENOMEM;
-+
-+ ctlr = __devm_spi_alloc_controller(dev, sizeof(*snandc), false);
-+ if (!ctlr)
-+ return -ENOMEM;
-+
-+ platform_set_drvdata(pdev, ctlr);
-+
-+ snandc = spi_controller_get_devdata(ctlr);
-+ qspi->snandc = snandc;
-+
-+ snandc->dev = dev;
-+ snandc->qspi = qspi;
-+ snandc->qspi->ctlr = ctlr;
-+ snandc->qspi->ecc = ecc;
-+
-+ dev_data = of_device_get_match_data(dev);
-+ if (!dev_data) {
-+ dev_err(&pdev->dev, "failed to get device data\n");
-+ return -ENODEV;
-+ }
-+
-+ snandc->props = dev_data;
-+ snandc->dev = &pdev->dev;
-+
-+ snandc->core_clk = devm_clk_get(dev, "core");
-+ if (IS_ERR(snandc->core_clk))
-+ return PTR_ERR(snandc->core_clk);
-+
-+ snandc->aon_clk = devm_clk_get(dev, "aon");
-+ if (IS_ERR(snandc->aon_clk))
-+ return PTR_ERR(snandc->aon_clk);
-+
-+ snandc->qspi->iomacro_clk = devm_clk_get(dev, "iom");
-+ if (IS_ERR(snandc->qspi->iomacro_clk))
-+ return PTR_ERR(snandc->qspi->iomacro_clk);
-+
-+ snandc->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
-+ if (IS_ERR(snandc->base))
-+ return PTR_ERR(snandc->base);
-+
-+ snandc->base_phys = res->start;
-+ snandc->base_dma = dma_map_resource(dev, res->start, resource_size(res),
-+ DMA_BIDIRECTIONAL, 0);
-+ if (dma_mapping_error(dev, snandc->base_dma))
-+ return -ENXIO;
-+
-+ ret = clk_prepare_enable(snandc->core_clk);
-+ if (ret)
-+ goto err_dis_core_clk;
-+
-+ ret = clk_prepare_enable(snandc->aon_clk);
-+ if (ret)
-+ goto err_dis_aon_clk;
-+
-+ ret = clk_prepare_enable(snandc->qspi->iomacro_clk);
-+ if (ret)
-+ goto err_dis_iom_clk;
-+
-+ ret = qcom_nandc_alloc(snandc);
-+ if (ret)
-+ goto err_snand_alloc;
-+
-+ ret = qcom_spi_init(snandc);
-+ if (ret)
-+ goto err_spi_init;
-+
-+ /* setup ECC engine */
-+ snandc->qspi->ecc_eng.dev = &pdev->dev;
-+ snandc->qspi->ecc_eng.integration = NAND_ECC_ENGINE_INTEGRATION_PIPELINED;
-+ snandc->qspi->ecc_eng.ops = &qcom_spi_ecc_engine_ops_pipelined;
-+ snandc->qspi->ecc_eng.priv = snandc;
-+
-+ ret = nand_ecc_register_on_host_hw_engine(&snandc->qspi->ecc_eng);
-+ if (ret) {
-+ dev_err(&pdev->dev, "failed to register ecc engine:%d\n", ret);
-+ goto err_spi_init;
-+ }
-+
-+ ctlr->num_chipselect = QPIC_QSPI_NUM_CS;
-+ ctlr->mem_ops = &qcom_spi_mem_ops;
-+ ctlr->mem_caps = &qcom_spi_mem_caps;
-+ ctlr->dev.of_node = pdev->dev.of_node;
-+ ctlr->mode_bits = SPI_TX_DUAL | SPI_RX_DUAL |
-+ SPI_TX_QUAD | SPI_RX_QUAD;
-+
-+ ret = spi_register_controller(ctlr);
-+ if (ret) {
-+ dev_err(&pdev->dev, "spi_register_controller failed.\n");
-+ goto err_spi_init;
-+ }
-+
-+ return 0;
-+
-+err_spi_init:
-+ qcom_nandc_unalloc(snandc);
-+err_snand_alloc:
-+ clk_disable_unprepare(snandc->qspi->iomacro_clk);
-+err_dis_iom_clk:
-+ clk_disable_unprepare(snandc->aon_clk);
-+err_dis_aon_clk:
-+ clk_disable_unprepare(snandc->core_clk);
-+err_dis_core_clk:
-+ dma_unmap_resource(dev, res->start, resource_size(res),
-+ DMA_BIDIRECTIONAL, 0);
-+ return ret;
-+}
-+
-+static void qcom_spi_remove(struct platform_device *pdev)
-+{
-+ struct spi_controller *ctlr = platform_get_drvdata(pdev);
-+ struct qcom_nand_controller *snandc = spi_controller_get_devdata(ctlr);
-+ struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-+
-+ spi_unregister_controller(ctlr);
-+
-+ qcom_nandc_unalloc(snandc);
-+
-+ clk_disable_unprepare(snandc->aon_clk);
-+ clk_disable_unprepare(snandc->core_clk);
-+ clk_disable_unprepare(snandc->qspi->iomacro_clk);
-+
-+ dma_unmap_resource(&pdev->dev, snandc->base_dma, resource_size(res),
-+ DMA_BIDIRECTIONAL, 0);
-+}
-+
-+static const struct qcom_nandc_props ipq9574_snandc_props = {
-+ .dev_cmd_reg_start = 0x7000,
-+ .supports_bam = true,
-+};
-+
-+static const struct of_device_id qcom_snandc_of_match[] = {
-+ {
-+ .compatible = "qcom,ipq9574-snand",
-+ .data = &ipq9574_snandc_props,
-+ },
-+ {}
-+}
-+MODULE_DEVICE_TABLE(of, qcom_snandc_of_match);
-+
-+static struct platform_driver qcom_spi_driver = {
-+ .driver = {
-+ .name = "qcom_snand",
-+ .of_match_table = qcom_snandc_of_match,
-+ },
-+ .probe = qcom_spi_probe,
-+ .remove_new = qcom_spi_remove,
-+};
-+module_platform_driver(qcom_spi_driver);
-+
-+MODULE_DESCRIPTION("SPI driver for QPIC QSPI cores");
-+MODULE_LICENSE("GPL");
-+
---- a/include/linux/mtd/nand-qpic-common.h
-+++ b/include/linux/mtd/nand-qpic-common.h
-@@ -325,6 +325,10 @@ struct nandc_regs {
- __le32 read_location_last1;
- __le32 read_location_last2;
- __le32 read_location_last3;
-+ __le32 spi_cfg;
-+ __le32 num_addr_cycle;
-+ __le32 busy_wait_cnt;
-+ __le32 flash_feature;
-
- __le32 erased_cw_detect_cfg_clr;
- __le32 erased_cw_detect_cfg_set;
-@@ -339,6 +343,7 @@ struct nandc_regs {
- *
- * @core_clk: controller clock
- * @aon_clk: another controller clock
-+ * @iomacro_clk: io macro clock
- *
- * @regs: a contiguous chunk of memory for DMA register
- * writes. contains the register values to be
-@@ -348,6 +353,7 @@ struct nandc_regs {
- * initialized via DT match data
- *
- * @controller: base controller structure
-+ * @qspi: qpic spi structure
- * @host_list: list containing all the chips attached to the
- * controller
- *
-@@ -392,6 +398,7 @@ struct qcom_nand_controller {
- const struct qcom_nandc_props *props;
-
- struct nand_controller *controller;
-+ struct qpic_spi_nand *qspi;
- struct list_head host_list;
-
- union {
+++ /dev/null
-From cf1ba3cb245020459f2ca446b7a7b199839f5d83 Mon Sep 17 00:00:00 2001
-Date: Thu, 6 Mar 2025 12:40:01 +0300
-Subject: [PATCH] spi: spi-qpic-snand: Fix ECC_CFG_ECC_DISABLE shift in
- qcom_spi_read_last_cw()
-
-The ECC_CFG_ECC_DISABLE define is BIT(0). It's supposed to be used
-directly instead of used as a shifter.
-
-Fixes: 7304d1909080 ("spi: spi-qpic: add driver for QCOM SPI NAND flash Interface")
----
- drivers/spi/spi-qpic-snand.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/spi/spi-qpic-snand.c
-+++ b/drivers/spi/spi-qpic-snand.c
-@@ -514,7 +514,7 @@ static int qcom_spi_read_last_cw(struct
- cfg0 = (ecc_cfg->cfg0_raw & ~(7U << CW_PER_PAGE)) |
- 0 << CW_PER_PAGE;
- cfg1 = ecc_cfg->cfg1_raw;
-- ecc_bch_cfg = 1 << ECC_CFG_ECC_DISABLE;
-+ ecc_bch_cfg = ECC_CFG_ECC_DISABLE;
-
- snandc->regs->cmd = snandc->qspi->cmd;
- snandc->regs->cfg0 = cpu_to_le32(cfg0);
+++ /dev/null
-From d450cdd9c4398add1f2aa7200f2c95f1e3b9f9fa Mon Sep 17 00:00:00 2001
-Date: Thu, 13 Mar 2025 19:31:21 +0100
-Subject: [PATCH] spi: spi-qpic-snand: avoid memleak in
- qcom_spi_ecc_init_ctx_pipelined()
-
-When the allocation of the OOB buffer fails, the
-qcom_spi_ecc_init_ctx_pipelined() function returns without freeing
-the memory allocated for 'ecc_cfg' thus it can cause a memory leak.
-
-Call kfree() to free 'ecc_cfg' before returning from the function
-to avoid that.
-
-Fixes: 7304d1909080 ("spi: spi-qpic: add driver for QCOM SPI NAND flash Interface")
----
- drivers/spi/spi-qpic-snand.c | 4 +++-
- 1 file changed, 3 insertions(+), 1 deletion(-)
-
---- a/drivers/spi/spi-qpic-snand.c
-+++ b/drivers/spi/spi-qpic-snand.c
-@@ -263,8 +263,10 @@ static int qcom_spi_ecc_init_ctx_pipelin
- return -ENOMEM;
- snandc->qspi->oob_buf = kzalloc(mtd->writesize + mtd->oobsize,
- GFP_KERNEL);
-- if (!snandc->qspi->oob_buf)
-+ if (!snandc->qspi->oob_buf) {
-+ kfree(ecc_cfg);
- return -ENOMEM;
-+ }
-
- memset(snandc->qspi->oob_buf, 0xff, mtd->writesize + mtd->oobsize);
-
+++ /dev/null
-From d32c4e58545f17caaa854415f854691e32d42075 Mon Sep 17 00:00:00 2001
-Date: Wed, 26 Mar 2025 15:22:19 +0100
-Subject: [PATCH] spi: SPI_QPIC_SNAND should be tristate and depend on MTD
-
-SPI_QPIC_SNAND is the only driver that selects MTD instead of depending
-on it, which could lead to circular dependencies. Moreover, as
-SPI_QPIC_SNAND is bool, this forces MTD (and various related symbols) to
-be built-in, as can be seen in an allmodconfig kernel.
-
-Except for a missing semicolon, there is no reason why SPI_QPIC_SNAND
-cannot be tristate; all MODULE_*() boilerplate is already present.
-Hence make SPI_QPIC_SNAND tristate, let it depend on MTD, and add the
-missing semicolon.
-
-Fixes: 7304d1909080ef0c ("spi: spi-qpic: add driver for QCOM SPI NAND flash Interface")
-Link: https://patch.msgid.link/b63db431cbf35223a4400e44c296293d32c4543c.1742998909.git.geert+renesas@glider.be
----
- drivers/spi/Kconfig | 4 ++--
- drivers/spi/spi-qpic-snand.c | 2 +-
- 2 files changed, 3 insertions(+), 3 deletions(-)
-
---- a/drivers/spi/Kconfig
-+++ b/drivers/spi/Kconfig
-@@ -871,9 +871,9 @@ config SPI_QCOM_QSPI
- QSPI(Quad SPI) driver for Qualcomm QSPI controller.
-
- config SPI_QPIC_SNAND
-- bool "QPIC SNAND controller"
-+ tristate "QPIC SNAND controller"
- depends on ARCH_QCOM || COMPILE_TEST
-- select MTD
-+ depends on MTD
- help
- QPIC_SNAND (QPIC SPI NAND) driver for Qualcomm QPIC controller.
- QPIC controller supports both parallel nand and serial nand.
---- a/drivers/spi/spi-qpic-snand.c
-+++ b/drivers/spi/spi-qpic-snand.c
-@@ -1614,7 +1614,7 @@ static const struct of_device_id qcom_sn
- .data = &ipq9574_snandc_props,
- },
- {}
--}
-+};
- MODULE_DEVICE_TABLE(of, qcom_snandc_of_match);
-
- static struct platform_driver qcom_spi_driver = {
+++ /dev/null
-Date: Wed, 23 Apr 2025 21:31:57 +0200
-Subject: [PATCH] spi: spi-qpic-snand: propagate errors from
- qcom_spi_block_erase()
-
-The qcom_spi_block_erase() function returns with error in case of
-failure. Change the qcom_spi_send_cmdaddr() function to propagate
-these errors to the callers instead of returning with success.
-
-Fixes: 7304d1909080 ("spi: spi-qpic: add driver for QCOM SPI NAND flash Interface")
----
- drivers/spi/spi-qpic-snand.c | 3 +--
- 1 file changed, 1 insertion(+), 2 deletions(-)
-
-
----
-base-commit: 9c32cda43eb78f78c73aee4aa344b777714e259b
-change-id: 20250422-qpic-snand-propagate-error-9c95811ab811
-
-Best regards,
-
---- a/drivers/spi/spi-qpic-snand.c
-+++ b/drivers/spi/spi-qpic-snand.c
-@@ -1307,8 +1307,7 @@ static int qcom_spi_send_cmdaddr(struct
- snandc->qspi->addr1 = cpu_to_le32(s_op.addr1_reg << 16);
- snandc->qspi->addr2 = cpu_to_le32(s_op.addr2_reg);
- snandc->qspi->cmd = cpu_to_le32(cmd);
-- qcom_spi_block_erase(snandc);
-- return 0;
-+ return qcom_spi_block_erase(snandc);
- default:
- break;
- }
+++ /dev/null
-Date: Mon, 28 Apr 2025 09:30:55 +0200
-Subject: [PATCH] spi: spi-qpic-snand: fix NAND_READ_LOCATION_2 register
- handling
-
-The precomputed value for the NAND_READ_LOCATION_2 register should be
-stored in 'snandc->regs->read_location2'.
-
-Fix the qcom_spi_set_read_loc_first() function accordingly.
-
-Fixes: 7304d1909080 ("spi: spi-qpic: add driver for QCOM SPI NAND flash Interface")
----
- drivers/spi/spi-qpic-snand.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-
----
-base-commit: 15cfe55ec58ace931a73e19e5367598734ceb074
-change-id: 20250428-qpic-snand-readloc2-fix-bccd07cf26d3
-
-Best regards,
-
---- a/drivers/spi/spi-qpic-snand.c
-+++ b/drivers/spi/spi-qpic-snand.c
-@@ -142,7 +142,7 @@ static void qcom_spi_set_read_loc_first(
- else if (reg == NAND_READ_LOCATION_1)
- snandc->regs->read_location1 = locreg_val;
- else if (reg == NAND_READ_LOCATION_2)
-- snandc->regs->read_location1 = locreg_val;
-+ snandc->regs->read_location2 = locreg_val;
- else if (reg == NAND_READ_LOCATION_3)
- snandc->regs->read_location3 = locreg_val;
- }
+++ /dev/null
-From f48d80503504257682e493dc17408f2f0b47bcfa Mon Sep 17 00:00:00 2001
-Date: Thu, 20 Mar 2025 19:11:59 +0100
-Subject: [PATCH] spi: spi-qpic-snand: use kmalloc() for OOB buffer allocation
-
-The qcom_spi_ecc_init_ctx_pipelined() function allocates zeroed
-memory for the OOB buffer, then it fills the buffer with '0xff'
-bytes right after the allocation. In this case zeroing the memory
-during allocation is superfluous, so use kmalloc() instead of
-kzalloc() to avoid that.
-
----
- drivers/spi/spi-qpic-snand.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/spi/spi-qpic-snand.c
-+++ b/drivers/spi/spi-qpic-snand.c
-@@ -261,7 +261,7 @@ static int qcom_spi_ecc_init_ctx_pipelin
- ecc_cfg = kzalloc(sizeof(*ecc_cfg), GFP_KERNEL);
- if (!ecc_cfg)
- return -ENOMEM;
-- snandc->qspi->oob_buf = kzalloc(mtd->writesize + mtd->oobsize,
-+ snandc->qspi->oob_buf = kmalloc(mtd->writesize + mtd->oobsize,
- GFP_KERNEL);
- if (!snandc->qspi->oob_buf) {
- kfree(ecc_cfg);
+++ /dev/null
-Date: Thu, 24 Apr 2025 20:10:59 +0200
-Subject: [PATCH] spi: spi-qpic-snand: remove unused 'wlen' member of
- 'struct qpic_spi_nand'
-
-The 'wlen' member of the qpic_spi_nand structure is never used in the
-code so remove that.
-
----
- drivers/spi/spi-qpic-snand.c | 1 -
- 1 file changed, 1 deletion(-)
-
-
----
-base-commit: 9c32cda43eb78f78c73aee4aa344b777714e259b
-change-id: 20250424-qpic-snand-remove-wlen-c0cef3801a7f
-
-Best regards,
-
---- a/drivers/spi/spi-qpic-snand.c
-+++ b/drivers/spi/spi-qpic-snand.c
-@@ -116,7 +116,6 @@ struct qpic_spi_nand {
- struct nand_ecc_engine ecc_eng;
- u8 *data_buf;
- u8 *oob_buf;
-- u32 wlen;
- __le32 addr1;
- __le32 addr2;
- __le32 cmd;
+++ /dev/null
-From 1824520e7477bedf76bd08c32261c755e6405cd9 Mon Sep 17 00:00:00 2001
-Date: Mon, 12 Aug 2024 02:56:41 +0100
-Subject: [PATCH] mtd: spinand: set bitflip_threshold to 75% of ECC strength
-
-Reporting an unclean read from SPI-NAND only when the maximum number
-of correctable bitflip errors has been hit seems a bit late.
-UBI LEB scrubbing, which depends on the lower MTD device reporting
-correctable bitflips, then only kicks in when it's almost too late.
-
-Set bitflip_threshold to 75% of the ECC strength, which is also the
-default for raw NAND.
-
-Link: https://lore.kernel.org/linux-mtd/2117e387260b0a96f95b8e1652ff79e0e2d71d53.1723427450.git.daniel@makrotopia.org
----
- drivers/mtd/nand/spi/core.c | 1 +
- 1 file changed, 1 insertion(+)
-
---- a/drivers/mtd/nand/spi/core.c
-+++ b/drivers/mtd/nand/spi/core.c
-@@ -1290,6 +1290,7 @@ static int spinand_init(struct spinand_d
- /* Propagate ECC information to mtd_info */
- mtd->ecc_strength = nanddev_get_ecc_conf(nand)->strength;
- mtd->ecc_step_size = nanddev_get_ecc_conf(nand)->step_size;
-+ mtd->bitflip_threshold = DIV_ROUND_UP(mtd->ecc_strength * 3, 4);
-
- ret = spinand_create_dirmaps(spinand);
- if (ret) {
+++ /dev/null
-From e2a9fcb36e851adb5b25c4acea53a290fd48a636 Mon Sep 17 00:00:00 2001
-Date: Mon, 5 Aug 2024 19:51:02 +0200
-Subject: [PATCH] mtd: spinand: winbond: add support for W25N01KV
-
-Add support for Winbond W25N01KV 1Gbit SPI-NAND.
-
-It has 4-bit on-die ECC.
-
----
- drivers/mtd/nand/spi/winbond.c | 26 ++++++++++++++++++++++++++
- 1 file changed, 26 insertions(+)
-
---- a/drivers/mtd/nand/spi/winbond.c
-+++ b/drivers/mtd/nand/spi/winbond.c
-@@ -74,6 +74,18 @@ static int w25m02gv_select_target(struct
- return spi_mem_exec_op(spinand->spimem, &op);
- }
-
-+static int w25n01kv_ooblayout_ecc(struct mtd_info *mtd, int section,
-+ struct mtd_oob_region *region)
-+{
-+ if (section > 3)
-+ return -ERANGE;
-+
-+ region->offset = 64 + (8 * section);
-+ region->length = 7;
-+
-+ return 0;
-+}
-+
- static int w25n02kv_ooblayout_ecc(struct mtd_info *mtd, int section,
- struct mtd_oob_region *region)
- {
-@@ -98,6 +110,11 @@ static int w25n02kv_ooblayout_free(struc
- return 0;
- }
-
-+static const struct mtd_ooblayout_ops w25n01kv_ooblayout = {
-+ .ecc = w25n01kv_ooblayout_ecc,
-+ .free = w25n02kv_ooblayout_free,
-+};
-+
- static const struct mtd_ooblayout_ops w25n02kv_ooblayout = {
- .ecc = w25n02kv_ooblayout_ecc,
- .free = w25n02kv_ooblayout_free,
-@@ -160,6 +177,15 @@ static const struct spinand_info winbond
- &update_cache_variants),
- 0,
- SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL)),
-+ SPINAND_INFO("W25N01KV",
-+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xae, 0x21),
-+ NAND_MEMORG(1, 2048, 96, 64, 1024, 20, 1, 1, 1),
-+ NAND_ECCREQ(4, 512),
-+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
-+ &write_cache_variants,
-+ &update_cache_variants),
-+ 0,
-+ SPINAND_ECCINFO(&w25n01kv_ooblayout, w25n02kv_ecc_get_status)),
- SPINAND_INFO("W25N02KV",
- SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xaa, 0x22),
- NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),
+++ /dev/null
-From 5f284dc15ca8695d0394414045ac64616a3b0e69 Mon Sep 17 00:00:00 2001
-Date: Mon, 25 Aug 2025 01:00:13 +0800
-Subject: [PATCH] mtd: spinand: add support for FudanMicro FM25S01A
-
-Add support for FudanMicro FM25S01A SPI NAND.
-Datasheet: http://eng.fmsh.com/nvm/FM25S01A_ds_eng.pdf
-
----
- drivers/mtd/nand/spi/Makefile | 2 +-
- drivers/mtd/nand/spi/core.c | 1 +
- drivers/mtd/nand/spi/fmsh.c | 74 +++++++++++++++++++++++++++++++++++
- include/linux/mtd/spinand.h | 1 +
- 4 files changed, 77 insertions(+), 1 deletion(-)
- create mode 100644 drivers/mtd/nand/spi/fmsh.c
-
---- a/drivers/mtd/nand/spi/Makefile
-+++ b/drivers/mtd/nand/spi/Makefile
-@@ -1,4 +1,4 @@
- # SPDX-License-Identifier: GPL-2.0
--spinand-objs := core.o alliancememory.o ato.o esmt.o foresee.o gigadevice.o macronix.o
-+spinand-objs := core.o alliancememory.o ato.o esmt.o fmsh.o foresee.o gigadevice.o macronix.o
- spinand-objs += micron.o paragon.o toshiba.o winbond.o xtx.o
- obj-$(CONFIG_MTD_SPI_NAND) += spinand.o
---- a/drivers/mtd/nand/spi/core.c
-+++ b/drivers/mtd/nand/spi/core.c
-@@ -943,6 +943,7 @@ static const struct spinand_manufacturer
- &alliancememory_spinand_manufacturer,
- &ato_spinand_manufacturer,
- &esmt_c8_spinand_manufacturer,
-+ &fmsh_spinand_manufacturer,
- &foresee_spinand_manufacturer,
- &gigadevice_spinand_manufacturer,
- ¯onix_spinand_manufacturer,
---- /dev/null
-+++ b/drivers/mtd/nand/spi/fmsh.c
-@@ -0,0 +1,74 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/*
-+ * Copyright (c) 2020-2021 Rockchip Electronics Co., Ltd.
-+ *
-+ */
-+
-+#include <linux/device.h>
-+#include <linux/kernel.h>
-+#include <linux/mtd/spinand.h>
-+
-+#define SPINAND_MFR_FMSH 0xA1
-+
-+static SPINAND_OP_VARIANTS(read_cache_variants,
-+ SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
-+ SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
-+ SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
-+ SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
-+ SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
-+ SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
-+
-+static SPINAND_OP_VARIANTS(write_cache_variants,
-+ SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
-+ SPINAND_PROG_LOAD(true, 0, NULL, 0));
-+
-+static SPINAND_OP_VARIANTS(update_cache_variants,
-+ SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
-+ SPINAND_PROG_LOAD(false, 0, NULL, 0));
-+
-+static int fm25s01a_ooblayout_ecc(struct mtd_info *mtd, int section,
-+ struct mtd_oob_region *region)
-+{
-+ return -ERANGE;
-+}
-+
-+static int fm25s01a_ooblayout_free(struct mtd_info *mtd, int section,
-+ struct mtd_oob_region *region)
-+{
-+ if (section)
-+ return -ERANGE;
-+
-+ region->offset = 2;
-+ region->length = 62;
-+
-+ return 0;
-+}
-+
-+static const struct mtd_ooblayout_ops fm25s01a_ooblayout = {
-+ .ecc = fm25s01a_ooblayout_ecc,
-+ .free = fm25s01a_ooblayout_free,
-+};
-+
-+static const struct spinand_info fmsh_spinand_table[] = {
-+ SPINAND_INFO("FM25S01A",
-+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xE4),
-+ NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
-+ NAND_ECCREQ(1, 512),
-+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
-+ &write_cache_variants,
-+ &update_cache_variants),
-+ SPINAND_HAS_QE_BIT,
-+ SPINAND_ECCINFO(&fm25s01a_ooblayout, NULL)),
-+};
-+
-+static const struct spinand_manufacturer_ops fmsh_spinand_manuf_ops = {
-+};
-+
-+const struct spinand_manufacturer fmsh_spinand_manufacturer = {
-+ .id = SPINAND_MFR_FMSH,
-+ .name = "Fudan Micro",
-+ .chips = fmsh_spinand_table,
-+ .nchips = ARRAY_SIZE(fmsh_spinand_table),
-+ .ops = &fmsh_spinand_manuf_ops,
-+};
---- a/include/linux/mtd/spinand.h
-+++ b/include/linux/mtd/spinand.h
-@@ -263,6 +263,7 @@ struct spinand_manufacturer {
- extern const struct spinand_manufacturer alliancememory_spinand_manufacturer;
- extern const struct spinand_manufacturer ato_spinand_manufacturer;
- extern const struct spinand_manufacturer esmt_c8_spinand_manufacturer;
-+extern const struct spinand_manufacturer fmsh_spinand_manufacturer;
- extern const struct spinand_manufacturer foresee_spinand_manufacturer;
- extern const struct spinand_manufacturer gigadevice_spinand_manufacturer;
- extern const struct spinand_manufacturer macronix_spinand_manufacturer;
+++ /dev/null
-From 56364c910691f6d10ba88c964c9041b9ab777bd6 Mon Sep 17 00:00:00 2001
-Date: Mon, 25 Mar 2024 08:40:28 +0100
-Subject: [PATCH 1/4] net: Remove conditional threaded-NAPI wakeup based on
- task state.
-
-A NAPI thread is scheduled by first setting NAPI_STATE_SCHED bit. If
-successful (the bit was not yet set) then the NAPI_STATE_SCHED_THREADED
-is set but only if thread's state is not TASK_INTERRUPTIBLE (is
-TASK_RUNNING) followed by task wakeup.
-
-If the task is idle (TASK_INTERRUPTIBLE) then the
-NAPI_STATE_SCHED_THREADED bit is not set. The thread is no relying on
-the bit but always leaving the wait-loop after returning from schedule()
-because there must have been a wakeup.
-
-The smpboot-threads implementation for per-CPU threads requires an
-explicit condition and does not support "if we get out of schedule()
-then there must be something to do".
-
-Removing this optimisation simplifies the following integration.
-
-Set NAPI_STATE_SCHED_THREADED unconditionally on wakeup and rely on it
-in the wait path by removing the `woken' condition.
-
----
- net/core/dev.c | 14 ++------------
- 1 file changed, 2 insertions(+), 12 deletions(-)
-
---- a/net/core/dev.c
-+++ b/net/core/dev.c
-@@ -4526,13 +4526,7 @@ static inline void ____napi_schedule(str
- */
- thread = READ_ONCE(napi->thread);
- if (thread) {
-- /* Avoid doing set_bit() if the thread is in
-- * INTERRUPTIBLE state, cause napi_thread_wait()
-- * makes sure to proceed with napi polling
-- * if the thread is explicitly woken from here.
-- */
-- if (READ_ONCE(thread->__state) != TASK_INTERRUPTIBLE)
-- set_bit(NAPI_STATE_SCHED_THREADED, &napi->state);
-+ set_bit(NAPI_STATE_SCHED_THREADED, &napi->state);
- wake_up_process(thread);
- return;
- }
-@@ -6688,8 +6682,6 @@ static int napi_poll(struct napi_struct
-
- static int napi_thread_wait(struct napi_struct *napi)
- {
-- bool woken = false;
--
- set_current_state(TASK_INTERRUPTIBLE);
-
- while (!kthread_should_stop()) {
-@@ -6698,15 +6690,13 @@ static int napi_thread_wait(struct napi_
- * Testing SCHED bit is not enough because SCHED bit might be
- * set by some other busy poll thread or by napi_disable().
- */
-- if (test_bit(NAPI_STATE_SCHED_THREADED, &napi->state) || woken) {
-+ if (test_bit(NAPI_STATE_SCHED_THREADED, &napi->state)) {
- WARN_ON(!list_empty(&napi->poll_list));
- __set_current_state(TASK_RUNNING);
- return 0;
- }
-
- schedule();
-- /* woken being true indicates this thread owns this napi. */
-- woken = true;
- set_current_state(TASK_INTERRUPTIBLE);
- }
- __set_current_state(TASK_RUNNING);
+++ /dev/null
-From dad6b97702639fba27a2bd3e986982ad6f0db3a7 Mon Sep 17 00:00:00 2001
-Date: Mon, 25 Mar 2024 08:40:29 +0100
-Subject: [PATCH 2/4] net: Allow to use SMP threads for backlog NAPI.
-
-Backlog NAPI is a per-CPU NAPI struct only (with no device behind it)
-used by drivers which don't do NAPI them self, RPS and parts of the
-stack which need to avoid recursive deadlocks while processing a packet.
-
-The non-NAPI driver use the CPU local backlog NAPI. If RPS is enabled
-then a flow for the skb is computed and based on the flow the skb can be
-enqueued on a remote CPU. Scheduling/ raising the softirq (for backlog's
-NAPI) on the remote CPU isn't trivial because the softirq is only
-scheduled on the local CPU and performed after the hardirq is done.
-In order to schedule a softirq on the remote CPU, an IPI is sent to the
-remote CPU which schedules the backlog-NAPI on the then local CPU.
-
-On PREEMPT_RT interrupts are force-threaded. The soft interrupts are
-raised within the interrupt thread and processed after the interrupt
-handler completed still within the context of the interrupt thread. The
-softirq is handled in the context where it originated.
-
-With force-threaded interrupts enabled, ksoftirqd is woken up if a
-softirq is raised from hardirq context. This is the case if it is raised
-from an IPI. Additionally there is a warning on PREEMPT_RT if the
-softirq is raised from the idle thread.
-This was done for two reasons:
-- With threaded interrupts the processing should happen in thread
- context (where it originated) and ksoftirqd is the only thread for
- this context if raised from hardirq. Using the currently running task
- instead would "punish" a random task.
-- Once ksoftirqd is active it consumes all further softirqs until it
- stops running. This changed recently and is no longer the case.
-
-Instead of keeping the backlog NAPI in ksoftirqd (in force-threaded/
-PREEMPT_RT setups) I am proposing NAPI-threads for backlog.
-The "proper" setup with threaded-NAPI is not doable because the threads
-are not pinned to an individual CPU and can be modified by the user.
-Additionally a dummy network device would have to be assigned. Also
-CPU-hotplug has to be considered if additional CPUs show up.
-All this can be probably done/ solved but the smpboot-threads already
-provide this infrastructure.
-
-Sending UDP packets over loopback expects that the packet is processed
-within the call. Delaying it by handing it over to the thread hurts
-performance. It is not beneficial to the outcome if the context switch
-happens immediately after enqueue or after a while to process a few
-packets in a batch.
-There is no need to always use the thread if the backlog NAPI is
-requested on the local CPU. This restores the loopback throuput. The
-performance drops mostly to the same value after enabling RPS on the
-loopback comparing the IPI and the tread result.
-
-Create NAPI-threads for backlog if request during boot. The thread runs
-the inner loop from napi_threaded_poll(), the wait part is different. It
-checks for NAPI_STATE_SCHED (the backlog NAPI can not be disabled).
-
-The NAPI threads for backlog are optional, it has to be enabled via the boot
-argument "thread_backlog_napi". It is mandatory for PREEMPT_RT to avoid the
-wakeup of ksoftirqd from the IPI.
-
----
- net/core/dev.c | 148 +++++++++++++++++++++++++++++++++++++------------
- 1 file changed, 113 insertions(+), 35 deletions(-)
-
---- a/net/core/dev.c
-+++ b/net/core/dev.c
-@@ -78,6 +78,7 @@
- #include <linux/slab.h>
- #include <linux/sched.h>
- #include <linux/sched/mm.h>
-+#include <linux/smpboot.h>
- #include <linux/mutex.h>
- #include <linux/rwsem.h>
- #include <linux/string.h>
-@@ -217,6 +218,31 @@ static inline struct hlist_head *dev_ind
- return &net->dev_index_head[ifindex & (NETDEV_HASHENTRIES - 1)];
- }
-
-+#ifndef CONFIG_PREEMPT_RT
-+
-+static DEFINE_STATIC_KEY_FALSE(use_backlog_threads_key);
-+
-+static int __init setup_backlog_napi_threads(char *arg)
-+{
-+ static_branch_enable(&use_backlog_threads_key);
-+ return 0;
-+}
-+early_param("thread_backlog_napi", setup_backlog_napi_threads);
-+
-+static bool use_backlog_threads(void)
-+{
-+ return static_branch_unlikely(&use_backlog_threads_key);
-+}
-+
-+#else
-+
-+static bool use_backlog_threads(void)
-+{
-+ return true;
-+}
-+
-+#endif
-+
- static inline void rps_lock_irqsave(struct softnet_data *sd,
- unsigned long *flags)
- {
-@@ -4494,6 +4520,7 @@ EXPORT_SYMBOL(__dev_direct_xmit);
- /*************************************************************************
- * Receiver routines
- *************************************************************************/
-+static DEFINE_PER_CPU(struct task_struct *, backlog_napi);
-
- int netdev_max_backlog __read_mostly = 1000;
- EXPORT_SYMBOL(netdev_max_backlog);
-@@ -4526,12 +4553,16 @@ static inline void ____napi_schedule(str
- */
- thread = READ_ONCE(napi->thread);
- if (thread) {
-+ if (use_backlog_threads() && thread == raw_cpu_read(backlog_napi))
-+ goto use_local_napi;
-+
- set_bit(NAPI_STATE_SCHED_THREADED, &napi->state);
- wake_up_process(thread);
- return;
- }
- }
-
-+use_local_napi:
- list_add_tail(&napi->poll_list, &sd->poll_list);
- WRITE_ONCE(napi->list_owner, smp_processor_id());
- /* If not called from net_rx_action()
-@@ -4777,6 +4808,11 @@ static void napi_schedule_rps(struct sof
-
- #ifdef CONFIG_RPS
- if (sd != mysd) {
-+ if (use_backlog_threads()) {
-+ __napi_schedule_irqoff(&sd->backlog);
-+ return;
-+ }
-+
- sd->rps_ipi_next = mysd->rps_ipi_list;
- mysd->rps_ipi_list = sd;
-
-@@ -6000,7 +6036,7 @@ static void net_rps_action_and_irq_enabl
- #ifdef CONFIG_RPS
- struct softnet_data *remsd = sd->rps_ipi_list;
-
-- if (remsd) {
-+ if (!use_backlog_threads() && remsd) {
- sd->rps_ipi_list = NULL;
-
- local_irq_enable();
-@@ -6015,7 +6051,7 @@ static void net_rps_action_and_irq_enabl
- static bool sd_has_rps_ipi_waiting(struct softnet_data *sd)
- {
- #ifdef CONFIG_RPS
-- return sd->rps_ipi_list != NULL;
-+ return !use_backlog_threads() && sd->rps_ipi_list;
- #else
- return false;
- #endif
-@@ -6059,7 +6095,7 @@ static int process_backlog(struct napi_s
- * We can use a plain write instead of clear_bit(),
- * and we dont need an smp_mb() memory barrier.
- */
-- napi->state = 0;
-+ napi->state &= NAPIF_STATE_THREADED;
- again = false;
- } else {
- skb_queue_splice_tail_init(&sd->input_pkt_queue,
-@@ -6725,43 +6761,48 @@ static void skb_defer_free_flush(struct
- }
- }
-
--static int napi_threaded_poll(void *data)
-+static void napi_threaded_poll_loop(struct napi_struct *napi)
- {
-- struct napi_struct *napi = data;
- struct softnet_data *sd;
-- void *have;
-+ unsigned long last_qs = jiffies;
-
-- while (!napi_thread_wait(napi)) {
-- unsigned long last_qs = jiffies;
-+ for (;;) {
-+ bool repoll = false;
-+ void *have;
-
-- for (;;) {
-- bool repoll = false;
-+ local_bh_disable();
-+ sd = this_cpu_ptr(&softnet_data);
-+ sd->in_napi_threaded_poll = true;
-
-- local_bh_disable();
-- sd = this_cpu_ptr(&softnet_data);
-- sd->in_napi_threaded_poll = true;
--
-- have = netpoll_poll_lock(napi);
-- __napi_poll(napi, &repoll);
-- netpoll_poll_unlock(have);
--
-- sd->in_napi_threaded_poll = false;
-- barrier();
--
-- if (sd_has_rps_ipi_waiting(sd)) {
-- local_irq_disable();
-- net_rps_action_and_irq_enable(sd);
-- }
-- skb_defer_free_flush(sd);
-- local_bh_enable();
-+ have = netpoll_poll_lock(napi);
-+ __napi_poll(napi, &repoll);
-+ netpoll_poll_unlock(have);
-+
-+ sd->in_napi_threaded_poll = false;
-+ barrier();
-+
-+ if (sd_has_rps_ipi_waiting(sd)) {
-+ local_irq_disable();
-+ net_rps_action_and_irq_enable(sd);
-+ }
-+ skb_defer_free_flush(sd);
-+ local_bh_enable();
-
-- if (!repoll)
-- break;
-+ if (!repoll)
-+ break;
-
-- rcu_softirq_qs_periodic(last_qs);
-- cond_resched();
-- }
-+ rcu_softirq_qs_periodic(last_qs);
-+ cond_resched();
- }
-+}
-+
-+static int napi_threaded_poll(void *data)
-+{
-+ struct napi_struct *napi = data;
-+
-+ while (!napi_thread_wait(napi))
-+ napi_threaded_poll_loop(napi);
-+
- return 0;
- }
-
-@@ -11346,7 +11387,7 @@ static int dev_cpu_dead(unsigned int old
-
- list_del_init(&napi->poll_list);
- if (napi->poll == process_backlog)
-- napi->state = 0;
-+ napi->state &= NAPIF_STATE_THREADED;
- else
- ____napi_schedule(sd, napi);
- }
-@@ -11354,12 +11395,14 @@ static int dev_cpu_dead(unsigned int old
- raise_softirq_irqoff(NET_TX_SOFTIRQ);
- local_irq_enable();
-
-+ if (!use_backlog_threads()) {
- #ifdef CONFIG_RPS
-- remsd = oldsd->rps_ipi_list;
-- oldsd->rps_ipi_list = NULL;
-+ remsd = oldsd->rps_ipi_list;
-+ oldsd->rps_ipi_list = NULL;
- #endif
-- /* send out pending IPI's on offline CPU */
-- net_rps_send_ipi(remsd);
-+ /* send out pending IPI's on offline CPU */
-+ net_rps_send_ipi(remsd);
-+ }
-
- /* Process offline CPU's input_pkt_queue */
- while ((skb = __skb_dequeue(&oldsd->process_queue))) {
-@@ -11622,6 +11665,38 @@ static struct pernet_operations __net_in
- *
- */
-
-+static int backlog_napi_should_run(unsigned int cpu)
-+{
-+ struct softnet_data *sd = per_cpu_ptr(&softnet_data, cpu);
-+ struct napi_struct *napi = &sd->backlog;
-+
-+ return test_bit(NAPI_STATE_SCHED_THREADED, &napi->state);
-+}
-+
-+static void run_backlog_napi(unsigned int cpu)
-+{
-+ struct softnet_data *sd = per_cpu_ptr(&softnet_data, cpu);
-+
-+ napi_threaded_poll_loop(&sd->backlog);
-+}
-+
-+static void backlog_napi_setup(unsigned int cpu)
-+{
-+ struct softnet_data *sd = per_cpu_ptr(&softnet_data, cpu);
-+ struct napi_struct *napi = &sd->backlog;
-+
-+ napi->thread = this_cpu_read(backlog_napi);
-+ set_bit(NAPI_STATE_THREADED, &napi->state);
-+}
-+
-+static struct smp_hotplug_thread backlog_threads = {
-+ .store = &backlog_napi,
-+ .thread_should_run = backlog_napi_should_run,
-+ .thread_fn = run_backlog_napi,
-+ .thread_comm = "backlog_napi/%u",
-+ .setup = backlog_napi_setup,
-+};
-+
- /*
- * This is called single threaded during boot, so no need
- * to take the rtnl semaphore.
-@@ -11672,7 +11747,10 @@ static int __init net_dev_init(void)
- init_gro_hash(&sd->backlog);
- sd->backlog.poll = process_backlog;
- sd->backlog.weight = weight_p;
-+ INIT_LIST_HEAD(&sd->backlog.poll_list);
- }
-+ if (use_backlog_threads())
-+ smpboot_register_percpu_thread(&backlog_threads);
-
- dev_boot_phase = 0;
-
+++ /dev/null
-From 80d2eefcb4c84aa9018b2a997ab3a4c567bc821a Mon Sep 17 00:00:00 2001
-Date: Mon, 25 Mar 2024 08:40:30 +0100
-Subject: [PATCH 3/4] net: Use backlog-NAPI to clean up the defer_list.
-
-The defer_list is a per-CPU list which is used to free skbs outside of
-the socket lock and on the CPU on which they have been allocated.
-The list is processed during NAPI callbacks so ideally the list is
-cleaned up.
-Should the amount of skbs on the list exceed a certain water mark then
-the softirq is triggered remotely on the target CPU by invoking a remote
-function call. The raise of the softirqs via a remote function call
-leads to waking the ksoftirqd on PREEMPT_RT which is undesired.
-The backlog-NAPI threads already provide the infrastructure which can be
-utilized to perform the cleanup of the defer_list.
-
-The NAPI state is updated with the input_pkt_queue.lock acquired. It
-order not to break the state, it is needed to also wake the backlog-NAPI
-thread with the lock held. This requires to acquire the use the lock in
-rps_lock_irq*() if the backlog-NAPI threads are used even with RPS
-disabled.
-
-Move the logic of remotely starting softirqs to clean up the defer_list
-into kick_defer_list_purge(). Make sure a lock is held in
-rps_lock_irq*() if backlog-NAPI threads are used. Schedule backlog-NAPI
-for defer_list cleanup if backlog-NAPI is available.
-
----
- include/linux/netdevice.h | 1 +
- net/core/dev.c | 25 +++++++++++++++++++++----
- net/core/skbuff.c | 4 ++--
- 3 files changed, 24 insertions(+), 6 deletions(-)
-
---- a/include/linux/netdevice.h
-+++ b/include/linux/netdevice.h
-@@ -3309,6 +3309,7 @@ static inline void dev_xmit_recursion_de
- __this_cpu_dec(softnet_data.xmit.recursion);
- }
-
-+void kick_defer_list_purge(struct softnet_data *sd, unsigned int cpu);
- void __netif_schedule(struct Qdisc *q);
- void netif_schedule_queue(struct netdev_queue *txq);
-
---- a/net/core/dev.c
-+++ b/net/core/dev.c
-@@ -246,7 +246,7 @@ static bool use_backlog_threads(void)
- static inline void rps_lock_irqsave(struct softnet_data *sd,
- unsigned long *flags)
- {
-- if (IS_ENABLED(CONFIG_RPS))
-+ if (IS_ENABLED(CONFIG_RPS) || use_backlog_threads())
- spin_lock_irqsave(&sd->input_pkt_queue.lock, *flags);
- else if (!IS_ENABLED(CONFIG_PREEMPT_RT))
- local_irq_save(*flags);
-@@ -254,7 +254,7 @@ static inline void rps_lock_irqsave(stru
-
- static inline void rps_lock_irq_disable(struct softnet_data *sd)
- {
-- if (IS_ENABLED(CONFIG_RPS))
-+ if (IS_ENABLED(CONFIG_RPS) || use_backlog_threads())
- spin_lock_irq(&sd->input_pkt_queue.lock);
- else if (!IS_ENABLED(CONFIG_PREEMPT_RT))
- local_irq_disable();
-@@ -263,7 +263,7 @@ static inline void rps_lock_irq_disable(
- static inline void rps_unlock_irq_restore(struct softnet_data *sd,
- unsigned long *flags)
- {
-- if (IS_ENABLED(CONFIG_RPS))
-+ if (IS_ENABLED(CONFIG_RPS) || use_backlog_threads())
- spin_unlock_irqrestore(&sd->input_pkt_queue.lock, *flags);
- else if (!IS_ENABLED(CONFIG_PREEMPT_RT))
- local_irq_restore(*flags);
-@@ -271,7 +271,7 @@ static inline void rps_unlock_irq_restor
-
- static inline void rps_unlock_irq_enable(struct softnet_data *sd)
- {
-- if (IS_ENABLED(CONFIG_RPS))
-+ if (IS_ENABLED(CONFIG_RPS) || use_backlog_threads())
- spin_unlock_irq(&sd->input_pkt_queue.lock);
- else if (!IS_ENABLED(CONFIG_PREEMPT_RT))
- local_irq_enable();
-@@ -4827,6 +4827,23 @@ static void napi_schedule_rps(struct sof
- __napi_schedule_irqoff(&mysd->backlog);
- }
-
-+void kick_defer_list_purge(struct softnet_data *sd, unsigned int cpu)
-+{
-+ unsigned long flags;
-+
-+ if (use_backlog_threads()) {
-+ rps_lock_irqsave(sd, &flags);
-+
-+ if (!__test_and_set_bit(NAPI_STATE_SCHED, &sd->backlog.state))
-+ __napi_schedule_irqoff(&sd->backlog);
-+
-+ rps_unlock_irq_restore(sd, &flags);
-+
-+ } else if (!cmpxchg(&sd->defer_ipi_scheduled, 0, 1)) {
-+ smp_call_function_single_async(cpu, &sd->defer_csd);
-+ }
-+}
-+
- #ifdef CONFIG_NET_FLOW_LIMIT
- int netdev_flow_limit_table_len __read_mostly = (1 << 12);
- #endif
---- a/net/core/skbuff.c
-+++ b/net/core/skbuff.c
-@@ -6867,8 +6867,8 @@ nodefer: __kfree_skb(skb);
- /* Make sure to trigger NET_RX_SOFTIRQ on the remote CPU
- * if we are unlucky enough (this seems very unlikely).
- */
-- if (unlikely(kick) && !cmpxchg(&sd->defer_ipi_scheduled, 0, 1))
-- smp_call_function_single_async(cpu, &sd->defer_csd);
-+ if (unlikely(kick))
-+ kick_defer_list_purge(sd, cpu);
- }
-
- static void skb_splice_csum_page(struct sk_buff *skb, struct page *page,
+++ /dev/null
-From 765b11f8f4e20b7433e4ba4a3e9106a0d59501ed Mon Sep 17 00:00:00 2001
-Date: Mon, 25 Mar 2024 08:40:31 +0100
-Subject: [PATCH 4/4] net: Rename rps_lock to backlog_lock.
-
-The rps_lock.*() functions use the inner lock of a sk_buff_head for
-locking. This lock is used if RPS is enabled, otherwise the list is
-accessed lockless and disabling interrupts is enough for the
-synchronisation because it is only accessed CPU local. Not only the list
-is protected but also the NAPI state protected.
-With the addition of backlog threads, the lock is also needed because of
-the cross CPU access even without RPS. The clean up of the defer_list
-list is also done via backlog threads (if enabled).
-
-It has been suggested to rename the locking function since it is no
-longer just RPS.
-
-Rename the rps_lock*() functions to backlog_lock*().
-
----
- net/core/dev.c | 34 +++++++++++++++++-----------------
- 1 file changed, 17 insertions(+), 17 deletions(-)
-
---- a/net/core/dev.c
-+++ b/net/core/dev.c
-@@ -243,8 +243,8 @@ static bool use_backlog_threads(void)
-
- #endif
-
--static inline void rps_lock_irqsave(struct softnet_data *sd,
-- unsigned long *flags)
-+static inline void backlog_lock_irq_save(struct softnet_data *sd,
-+ unsigned long *flags)
- {
- if (IS_ENABLED(CONFIG_RPS) || use_backlog_threads())
- spin_lock_irqsave(&sd->input_pkt_queue.lock, *flags);
-@@ -252,7 +252,7 @@ static inline void rps_lock_irqsave(stru
- local_irq_save(*flags);
- }
-
--static inline void rps_lock_irq_disable(struct softnet_data *sd)
-+static inline void backlog_lock_irq_disable(struct softnet_data *sd)
- {
- if (IS_ENABLED(CONFIG_RPS) || use_backlog_threads())
- spin_lock_irq(&sd->input_pkt_queue.lock);
-@@ -260,8 +260,8 @@ static inline void rps_lock_irq_disable(
- local_irq_disable();
- }
-
--static inline void rps_unlock_irq_restore(struct softnet_data *sd,
-- unsigned long *flags)
-+static inline void backlog_unlock_irq_restore(struct softnet_data *sd,
-+ unsigned long *flags)
- {
- if (IS_ENABLED(CONFIG_RPS) || use_backlog_threads())
- spin_unlock_irqrestore(&sd->input_pkt_queue.lock, *flags);
-@@ -269,7 +269,7 @@ static inline void rps_unlock_irq_restor
- local_irq_restore(*flags);
- }
-
--static inline void rps_unlock_irq_enable(struct softnet_data *sd)
-+static inline void backlog_unlock_irq_enable(struct softnet_data *sd)
- {
- if (IS_ENABLED(CONFIG_RPS) || use_backlog_threads())
- spin_unlock_irq(&sd->input_pkt_queue.lock);
-@@ -4832,12 +4832,12 @@ void kick_defer_list_purge(struct softne
- unsigned long flags;
-
- if (use_backlog_threads()) {
-- rps_lock_irqsave(sd, &flags);
-+ backlog_lock_irq_save(sd, &flags);
-
- if (!__test_and_set_bit(NAPI_STATE_SCHED, &sd->backlog.state))
- __napi_schedule_irqoff(&sd->backlog);
-
-- rps_unlock_irq_restore(sd, &flags);
-+ backlog_unlock_irq_restore(sd, &flags);
-
- } else if (!cmpxchg(&sd->defer_ipi_scheduled, 0, 1)) {
- smp_call_function_single_async(cpu, &sd->defer_csd);
-@@ -4899,7 +4899,7 @@ static int enqueue_to_backlog(struct sk_
- reason = SKB_DROP_REASON_NOT_SPECIFIED;
- sd = &per_cpu(softnet_data, cpu);
-
-- rps_lock_irqsave(sd, &flags);
-+ backlog_lock_irq_save(sd, &flags);
- if (!netif_running(skb->dev))
- goto drop;
- qlen = skb_queue_len(&sd->input_pkt_queue);
-@@ -4908,7 +4908,7 @@ static int enqueue_to_backlog(struct sk_
- enqueue:
- __skb_queue_tail(&sd->input_pkt_queue, skb);
- input_queue_tail_incr_save(sd, qtail);
-- rps_unlock_irq_restore(sd, &flags);
-+ backlog_unlock_irq_restore(sd, &flags);
- return NET_RX_SUCCESS;
- }
-
-@@ -4923,7 +4923,7 @@ enqueue:
-
- drop:
- sd->dropped++;
-- rps_unlock_irq_restore(sd, &flags);
-+ backlog_unlock_irq_restore(sd, &flags);
-
- dev_core_stats_rx_dropped_inc(skb->dev);
- kfree_skb_reason(skb, reason);
-@@ -5954,7 +5954,7 @@ static void flush_backlog(struct work_st
- local_bh_disable();
- sd = this_cpu_ptr(&softnet_data);
-
-- rps_lock_irq_disable(sd);
-+ backlog_lock_irq_disable(sd);
- skb_queue_walk_safe(&sd->input_pkt_queue, skb, tmp) {
- if (skb->dev->reg_state == NETREG_UNREGISTERING) {
- __skb_unlink(skb, &sd->input_pkt_queue);
-@@ -5962,7 +5962,7 @@ static void flush_backlog(struct work_st
- input_queue_head_incr(sd);
- }
- }
-- rps_unlock_irq_enable(sd);
-+ backlog_unlock_irq_enable(sd);
-
- skb_queue_walk_safe(&sd->process_queue, skb, tmp) {
- if (skb->dev->reg_state == NETREG_UNREGISTERING) {
-@@ -5980,14 +5980,14 @@ static bool flush_required(int cpu)
- struct softnet_data *sd = &per_cpu(softnet_data, cpu);
- bool do_flush;
-
-- rps_lock_irq_disable(sd);
-+ backlog_lock_irq_disable(sd);
-
- /* as insertion into process_queue happens with the rps lock held,
- * process_queue access may race only with dequeue
- */
- do_flush = !skb_queue_empty(&sd->input_pkt_queue) ||
- !skb_queue_empty_lockless(&sd->process_queue);
-- rps_unlock_irq_enable(sd);
-+ backlog_unlock_irq_enable(sd);
-
- return do_flush;
- #endif
-@@ -6102,7 +6102,7 @@ static int process_backlog(struct napi_s
-
- }
-
-- rps_lock_irq_disable(sd);
-+ backlog_lock_irq_disable(sd);
- if (skb_queue_empty(&sd->input_pkt_queue)) {
- /*
- * Inline a custom version of __napi_complete().
-@@ -6118,7 +6118,7 @@ static int process_backlog(struct napi_s
- skb_queue_splice_tail_init(&sd->input_pkt_queue,
- &sd->process_queue);
- }
-- rps_unlock_irq_enable(sd);
-+ backlog_unlock_irq_enable(sd);
- }
-
- return work;
+++ /dev/null
-From 8cc5f4cb94c0b1c7c1ba8013c14fd02ffb1a25f3 Mon Sep 17 00:00:00 2001
-Date: Fri, 8 Nov 2024 16:01:44 +0000
-Subject: [PATCH 1/5] net: phylink: move manual flow control setting
-
-Move the handling of manual flow control configuration to a common
-location during resolve. We currently evaluate this for all but
-fixed links.
-
----
- drivers/net/phy/phylink.c | 5 +++--
- 1 file changed, 3 insertions(+), 2 deletions(-)
-
---- a/drivers/net/phy/phylink.c
-+++ b/drivers/net/phy/phylink.c
-@@ -1433,7 +1433,6 @@ static void phylink_resolve(struct work_
- switch (pl->cur_link_an_mode) {
- case MLO_AN_PHY:
- link_state = pl->phy_state;
-- phylink_apply_manual_flow(pl, &link_state);
- mac_config = link_state.link;
- break;
-
-@@ -1494,11 +1493,13 @@ static void phylink_resolve(struct work_
- link_state.pause = pl->phy_state.pause;
- mac_config = true;
- }
-- phylink_apply_manual_flow(pl, &link_state);
- break;
- }
- }
-
-+ if (pl->cur_link_an_mode != MLO_AN_FIXED)
-+ phylink_apply_manual_flow(pl, &link_state);
-+
- if (mac_config) {
- if (link_state.interface != pl->link_config.interface) {
- /* The interface has changed, force the link down and
+++ /dev/null
-From 92abfcb4ced482afbe65d18980e6734fe1e62a34 Mon Sep 17 00:00:00 2001
-Date: Fri, 8 Nov 2024 16:01:50 +0000
-Subject: [PATCH 2/5] net: phylink: move MLO_AN_FIXED resolve handling to if()
- statement
-
-The switch() statement doesn't sit very well with the preceeding if()
-statements, and results in excessive indentation that spoils code
-readability. Begin cleaning this up by converting the MLO_AN_FIXED case
-to an if() statement.
-
----
- drivers/net/phy/phylink.c | 8 +++-----
- 1 file changed, 3 insertions(+), 5 deletions(-)
-
---- a/drivers/net/phy/phylink.c
-+++ b/drivers/net/phy/phylink.c
-@@ -1429,6 +1429,9 @@ static void phylink_resolve(struct work_
- } else if (pl->mac_link_dropped) {
- link_state.link = false;
- retrigger = true;
-+ } else if (pl->cur_link_an_mode == MLO_AN_FIXED) {
-+ phylink_get_fixed_state(pl, &link_state);
-+ mac_config = link_state.link;
- } else {
- switch (pl->cur_link_an_mode) {
- case MLO_AN_PHY:
-@@ -1436,11 +1439,6 @@ static void phylink_resolve(struct work_
- mac_config = link_state.link;
- break;
-
-- case MLO_AN_FIXED:
-- phylink_get_fixed_state(pl, &link_state);
-- mac_config = link_state.link;
-- break;
--
- case MLO_AN_INBAND:
- phylink_mac_pcs_get_state(pl, &link_state);
-
+++ /dev/null
-From f0f46c2a3d8ea9d1427298c8103a777d9e616c29 Mon Sep 17 00:00:00 2001
-Date: Fri, 8 Nov 2024 16:01:55 +0000
-Subject: [PATCH 3/5] net: phylink: move MLO_AN_PHY resolve handling to if()
- statement
-
-The switch() statement doesn't sit very well with the preceeding if()
-statements, and results in excessive indentation that spoils code
-readability. Continue cleaning this up by converting the MLO_AN_PHY
-case to use an if() statmeent.
-
----
- drivers/net/phy/phylink.c | 8 +++-----
- 1 file changed, 3 insertions(+), 5 deletions(-)
-
---- a/drivers/net/phy/phylink.c
-+++ b/drivers/net/phy/phylink.c
-@@ -1432,13 +1432,11 @@ static void phylink_resolve(struct work_
- } else if (pl->cur_link_an_mode == MLO_AN_FIXED) {
- phylink_get_fixed_state(pl, &link_state);
- mac_config = link_state.link;
-+ } else if (pl->cur_link_an_mode == MLO_AN_PHY) {
-+ link_state = pl->phy_state;
-+ mac_config = link_state.link;
- } else {
- switch (pl->cur_link_an_mode) {
-- case MLO_AN_PHY:
-- link_state = pl->phy_state;
-- mac_config = link_state.link;
-- break;
--
- case MLO_AN_INBAND:
- phylink_mac_pcs_get_state(pl, &link_state);
-
+++ /dev/null
-From d1a16dbbd84e02d2a6dcfcb8d5c4b8b2c0289f00 Mon Sep 17 00:00:00 2001
-Date: Fri, 8 Nov 2024 16:02:00 +0000
-Subject: [PATCH 4/5] net: phylink: remove switch() statement in resolve
- handling
-
-The switch() statement doesn't sit very well with the preceeding if()
-statements, so let's just convert everything to if()s. As a result of
-the two preceding commits, there is now only one case in the switch()
-statement. Remove the switch statement and reduce the code indentation.
-Code reformatting will be in the following commit.
-
----
- drivers/net/phy/phylink.c | 94 +++++++++++++++++++--------------------
- 1 file changed, 45 insertions(+), 49 deletions(-)
-
---- a/drivers/net/phy/phylink.c
-+++ b/drivers/net/phy/phylink.c
-@@ -1436,60 +1436,56 @@ static void phylink_resolve(struct work_
- link_state = pl->phy_state;
- mac_config = link_state.link;
- } else {
-- switch (pl->cur_link_an_mode) {
-- case MLO_AN_INBAND:
-- phylink_mac_pcs_get_state(pl, &link_state);
--
-- /* The PCS may have a latching link-fail indicator.
-- * If the link was up, bring the link down and
-- * re-trigger the resolve. Otherwise, re-read the
-- * PCS state to get the current status of the link.
-+ phylink_mac_pcs_get_state(pl, &link_state);
-+
-+ /* The PCS may have a latching link-fail indicator.
-+ * If the link was up, bring the link down and
-+ * re-trigger the resolve. Otherwise, re-read the
-+ * PCS state to get the current status of the link.
-+ */
-+ if (!link_state.link) {
-+ if (cur_link_state)
-+ retrigger = true;
-+ else
-+ phylink_mac_pcs_get_state(pl,
-+ &link_state);
-+ }
-+
-+ /* If we have a phy, the "up" state is the union of
-+ * both the PHY and the MAC
-+ */
-+ if (pl->phydev)
-+ link_state.link &= pl->phy_state.link;
-+
-+ /* Only update if the PHY link is up */
-+ if (pl->phydev && pl->phy_state.link) {
-+ /* If the interface has changed, force a
-+ * link down event if the link isn't already
-+ * down, and re-resolve.
- */
-- if (!link_state.link) {
-- if (cur_link_state)
-- retrigger = true;
-- else
-- phylink_mac_pcs_get_state(pl,
-- &link_state);
-+ if (link_state.interface !=
-+ pl->phy_state.interface) {
-+ retrigger = true;
-+ link_state.link = false;
- }
-+ link_state.interface = pl->phy_state.interface;
-
-- /* If we have a phy, the "up" state is the union of
-- * both the PHY and the MAC
-+ /* If we are doing rate matching, then the
-+ * link speed/duplex comes from the PHY
- */
-- if (pl->phydev)
-- link_state.link &= pl->phy_state.link;
--
-- /* Only update if the PHY link is up */
-- if (pl->phydev && pl->phy_state.link) {
-- /* If the interface has changed, force a
-- * link down event if the link isn't already
-- * down, and re-resolve.
-- */
-- if (link_state.interface !=
-- pl->phy_state.interface) {
-- retrigger = true;
-- link_state.link = false;
-- }
-- link_state.interface = pl->phy_state.interface;
--
-- /* If we are doing rate matching, then the
-- * link speed/duplex comes from the PHY
-- */
-- if (pl->phy_state.rate_matching) {
-- link_state.rate_matching =
-- pl->phy_state.rate_matching;
-- link_state.speed = pl->phy_state.speed;
-- link_state.duplex =
-- pl->phy_state.duplex;
-- }
--
-- /* If we have a PHY, we need to update with
-- * the PHY flow control bits.
-- */
-- link_state.pause = pl->phy_state.pause;
-- mac_config = true;
-+ if (pl->phy_state.rate_matching) {
-+ link_state.rate_matching =
-+ pl->phy_state.rate_matching;
-+ link_state.speed = pl->phy_state.speed;
-+ link_state.duplex =
-+ pl->phy_state.duplex;
- }
-- break;
-+
-+ /* If we have a PHY, we need to update with
-+ * the PHY flow control bits.
-+ */
-+ link_state.pause = pl->phy_state.pause;
-+ mac_config = true;
- }
- }
-
+++ /dev/null
-From bc08ce37d99a3992e975a0f397503cb23404f25a Mon Sep 17 00:00:00 2001
-Date: Fri, 8 Nov 2024 16:02:05 +0000
-Subject: [PATCH 5/5] net: phylink: clean up phylink_resolve()
-
-Now that we have reduced the indentation level, clean up the code
-formatting.
-
----
- drivers/net/phy/phylink.c | 35 ++++++++++++++++-------------------
- 1 file changed, 16 insertions(+), 19 deletions(-)
-
---- a/drivers/net/phy/phylink.c
-+++ b/drivers/net/phy/phylink.c
-@@ -1438,51 +1438,48 @@ static void phylink_resolve(struct work_
- } else {
- phylink_mac_pcs_get_state(pl, &link_state);
-
-- /* The PCS may have a latching link-fail indicator.
-- * If the link was up, bring the link down and
-- * re-trigger the resolve. Otherwise, re-read the
-- * PCS state to get the current status of the link.
-+ /* The PCS may have a latching link-fail indicator. If the link
-+ * was up, bring the link down and re-trigger the resolve.
-+ * Otherwise, re-read the PCS state to get the current status
-+ * of the link.
- */
- if (!link_state.link) {
- if (cur_link_state)
- retrigger = true;
- else
-- phylink_mac_pcs_get_state(pl,
-- &link_state);
-+ phylink_mac_pcs_get_state(pl, &link_state);
- }
-
-- /* If we have a phy, the "up" state is the union of
-- * both the PHY and the MAC
-+ /* If we have a phy, the "up" state is the union of both the
-+ * PHY and the MAC
- */
- if (pl->phydev)
- link_state.link &= pl->phy_state.link;
-
- /* Only update if the PHY link is up */
- if (pl->phydev && pl->phy_state.link) {
-- /* If the interface has changed, force a
-- * link down event if the link isn't already
-- * down, and re-resolve.
-+ /* If the interface has changed, force a link down
-+ * event if the link isn't already down, and re-resolve.
- */
-- if (link_state.interface !=
-- pl->phy_state.interface) {
-+ if (link_state.interface != pl->phy_state.interface) {
- retrigger = true;
- link_state.link = false;
- }
-+
- link_state.interface = pl->phy_state.interface;
-
-- /* If we are doing rate matching, then the
-- * link speed/duplex comes from the PHY
-+ /* If we are doing rate matching, then the link
-+ * speed/duplex comes from the PHY
- */
- if (pl->phy_state.rate_matching) {
- link_state.rate_matching =
- pl->phy_state.rate_matching;
- link_state.speed = pl->phy_state.speed;
-- link_state.duplex =
-- pl->phy_state.duplex;
-+ link_state.duplex = pl->phy_state.duplex;
- }
-
-- /* If we have a PHY, we need to update with
-- * the PHY flow control bits.
-+ /* If we have a PHY, we need to update with the PHY
-+ * flow control bits.
- */
- link_state.pause = pl->phy_state.pause;
- mac_config = true;
+++ /dev/null
-From 5e5401d6612ef599ad45785b941eebda7effc90f Mon Sep 17 00:00:00 2001
-Date: Thu, 4 Jan 2024 09:47:36 +0000
-Subject: [PATCH] net: phylink: move phylink_pcs_neg_mode() into phylink.c
-
-Move phylink_pcs_neg_mode() from the header file into the .c file since
-nothing should be using it.
-
----
- drivers/net/phy/phylink.c | 66 +++++++++++++++++++++++++++++++++++++++
- include/linux/phylink.h | 66 ---------------------------------------
- 2 files changed, 66 insertions(+), 66 deletions(-)
-
---- a/drivers/net/phy/phylink.c
-+++ b/drivers/net/phy/phylink.c
-@@ -1116,6 +1116,72 @@ static void phylink_pcs_an_restart(struc
- pl->pcs->ops->pcs_an_restart(pl->pcs);
- }
-
-+/**
-+ * phylink_pcs_neg_mode() - helper to determine PCS inband mode
-+ * @mode: one of %MLO_AN_FIXED, %MLO_AN_PHY, %MLO_AN_INBAND.
-+ * @interface: interface mode to be used
-+ * @advertising: adertisement ethtool link mode mask
-+ *
-+ * Determines the negotiation mode to be used by the PCS, and returns
-+ * one of:
-+ *
-+ * - %PHYLINK_PCS_NEG_NONE: interface mode does not support inband
-+ * - %PHYLINK_PCS_NEG_OUTBAND: an out of band mode (e.g. reading the PHY)
-+ * will be used.
-+ * - %PHYLINK_PCS_NEG_INBAND_DISABLED: inband mode selected but autoneg
-+ * disabled
-+ * - %PHYLINK_PCS_NEG_INBAND_ENABLED: inband mode selected and autoneg enabled
-+ *
-+ * Note: this is for cases where the PCS itself is involved in negotiation
-+ * (e.g. Clause 37, SGMII and similar) not Clause 73.
-+ */
-+static unsigned int phylink_pcs_neg_mode(unsigned int mode,
-+ phy_interface_t interface,
-+ const unsigned long *advertising)
-+{
-+ unsigned int neg_mode;
-+
-+ switch (interface) {
-+ case PHY_INTERFACE_MODE_SGMII:
-+ case PHY_INTERFACE_MODE_QSGMII:
-+ case PHY_INTERFACE_MODE_QUSGMII:
-+ case PHY_INTERFACE_MODE_USXGMII:
-+ /* These protocols are designed for use with a PHY which
-+ * communicates its negotiation result back to the MAC via
-+ * inband communication. Note: there exist PHYs that run
-+ * with SGMII but do not send the inband data.
-+ */
-+ if (!phylink_autoneg_inband(mode))
-+ neg_mode = PHYLINK_PCS_NEG_OUTBAND;
-+ else
-+ neg_mode = PHYLINK_PCS_NEG_INBAND_ENABLED;
-+ break;
-+
-+ case PHY_INTERFACE_MODE_1000BASEX:
-+ case PHY_INTERFACE_MODE_2500BASEX:
-+ /* 1000base-X is designed for use media-side for Fibre
-+ * connections, and thus the Autoneg bit needs to be
-+ * taken into account. We also do this for 2500base-X
-+ * as well, but drivers may not support this, so may
-+ * need to override this.
-+ */
-+ if (!phylink_autoneg_inband(mode))
-+ neg_mode = PHYLINK_PCS_NEG_OUTBAND;
-+ else if (linkmode_test_bit(ETHTOOL_LINK_MODE_Autoneg_BIT,
-+ advertising))
-+ neg_mode = PHYLINK_PCS_NEG_INBAND_ENABLED;
-+ else
-+ neg_mode = PHYLINK_PCS_NEG_INBAND_DISABLED;
-+ break;
-+
-+ default:
-+ neg_mode = PHYLINK_PCS_NEG_NONE;
-+ break;
-+ }
-+
-+ return neg_mode;
-+}
-+
- static void phylink_major_config(struct phylink *pl, bool restart,
- const struct phylink_link_state *state)
- {
---- a/include/linux/phylink.h
-+++ b/include/linux/phylink.h
-@@ -99,72 +99,6 @@ static inline bool phylink_autoneg_inban
- }
-
- /**
-- * phylink_pcs_neg_mode() - helper to determine PCS inband mode
-- * @mode: one of %MLO_AN_FIXED, %MLO_AN_PHY, %MLO_AN_INBAND.
-- * @interface: interface mode to be used
-- * @advertising: adertisement ethtool link mode mask
-- *
-- * Determines the negotiation mode to be used by the PCS, and returns
-- * one of:
-- *
-- * - %PHYLINK_PCS_NEG_NONE: interface mode does not support inband
-- * - %PHYLINK_PCS_NEG_OUTBAND: an out of band mode (e.g. reading the PHY)
-- * will be used.
-- * - %PHYLINK_PCS_NEG_INBAND_DISABLED: inband mode selected but autoneg
-- * disabled
-- * - %PHYLINK_PCS_NEG_INBAND_ENABLED: inband mode selected and autoneg enabled
-- *
-- * Note: this is for cases where the PCS itself is involved in negotiation
-- * (e.g. Clause 37, SGMII and similar) not Clause 73.
-- */
--static inline unsigned int phylink_pcs_neg_mode(unsigned int mode,
-- phy_interface_t interface,
-- const unsigned long *advertising)
--{
-- unsigned int neg_mode;
--
-- switch (interface) {
-- case PHY_INTERFACE_MODE_SGMII:
-- case PHY_INTERFACE_MODE_QSGMII:
-- case PHY_INTERFACE_MODE_QUSGMII:
-- case PHY_INTERFACE_MODE_USXGMII:
-- /* These protocols are designed for use with a PHY which
-- * communicates its negotiation result back to the MAC via
-- * inband communication. Note: there exist PHYs that run
-- * with SGMII but do not send the inband data.
-- */
-- if (!phylink_autoneg_inband(mode))
-- neg_mode = PHYLINK_PCS_NEG_OUTBAND;
-- else
-- neg_mode = PHYLINK_PCS_NEG_INBAND_ENABLED;
-- break;
--
-- case PHY_INTERFACE_MODE_1000BASEX:
-- case PHY_INTERFACE_MODE_2500BASEX:
-- /* 1000base-X is designed for use media-side for Fibre
-- * connections, and thus the Autoneg bit needs to be
-- * taken into account. We also do this for 2500base-X
-- * as well, but drivers may not support this, so may
-- * need to override this.
-- */
-- if (!phylink_autoneg_inband(mode))
-- neg_mode = PHYLINK_PCS_NEG_OUTBAND;
-- else if (linkmode_test_bit(ETHTOOL_LINK_MODE_Autoneg_BIT,
-- advertising))
-- neg_mode = PHYLINK_PCS_NEG_INBAND_ENABLED;
-- else
-- neg_mode = PHYLINK_PCS_NEG_INBAND_DISABLED;
-- break;
--
-- default:
-- neg_mode = PHYLINK_PCS_NEG_NONE;
-- break;
-- }
--
-- return neg_mode;
--}
--
--/**
- * struct phylink_link_state - link state structure
- * @advertising: ethtool bitmask containing advertised link modes
- * @lp_advertising: ethtool bitmask containing link partner advertised link
+++ /dev/null
-From 17ed1911f9c8d4f9af8e13b2c95103ee06dadc0f Mon Sep 17 00:00:00 2001
-Date: Tue, 3 Dec 2024 15:30:47 +0000
-Subject: [PATCH 01/13] net: phylink: pass phylink and pcs into
- phylink_pcs_neg_mode()
-
-Move the call to phylink_pcs_neg_mode() in phylink_major_config() after
-we have selected the appropriate PCS to allow the PCS to be passed in.
-
-Add struct phylink and struct phylink_pcs pointers to
-phylink_pcs_neg_mode() and pass in the appropriate structures. Set
-pl->pcs_neg_mode before returning, and remove the return value.
-
-This will allow the capabilities of the PCS and any PHY to be used when
-deciding which pcs_neg_mode should be used.
-
----
- drivers/net/phy/phylink.c | 26 +++++++++++++-------------
- 1 file changed, 13 insertions(+), 13 deletions(-)
-
---- a/drivers/net/phy/phylink.c
-+++ b/drivers/net/phy/phylink.c
-@@ -1118,7 +1118,8 @@ static void phylink_pcs_an_restart(struc
-
- /**
- * phylink_pcs_neg_mode() - helper to determine PCS inband mode
-- * @mode: one of %MLO_AN_FIXED, %MLO_AN_PHY, %MLO_AN_INBAND.
-+ * @pl: a pointer to a &struct phylink returned from phylink_create()
-+ * @pcs: a pointer to &struct phylink_pcs
- * @interface: interface mode to be used
- * @advertising: adertisement ethtool link mode mask
- *
-@@ -1135,11 +1136,13 @@ static void phylink_pcs_an_restart(struc
- * Note: this is for cases where the PCS itself is involved in negotiation
- * (e.g. Clause 37, SGMII and similar) not Clause 73.
- */
--static unsigned int phylink_pcs_neg_mode(unsigned int mode,
-- phy_interface_t interface,
-- const unsigned long *advertising)
-+static void phylink_pcs_neg_mode(struct phylink *pl, struct phylink_pcs *pcs,
-+ phy_interface_t interface,
-+ const unsigned long *advertising)
- {
-- unsigned int neg_mode;
-+ unsigned int neg_mode, mode;
-+
-+ mode = pl->cur_link_an_mode;
-
- switch (interface) {
- case PHY_INTERFACE_MODE_SGMII:
-@@ -1179,7 +1182,7 @@ static unsigned int phylink_pcs_neg_mode
- break;
- }
-
-- return neg_mode;
-+ pl->pcs_neg_mode = neg_mode;
- }
-
- static void phylink_major_config(struct phylink *pl, bool restart,
-@@ -1193,10 +1196,6 @@ static void phylink_major_config(struct
-
- phylink_dbg(pl, "major config %s\n", phy_modes(state->interface));
-
-- pl->pcs_neg_mode = phylink_pcs_neg_mode(pl->cur_link_an_mode,
-- state->interface,
-- state->advertising);
--
- if (pl->using_mac_select_pcs) {
- pcs = pl->mac_ops->mac_select_pcs(pl->config, state->interface);
- if (IS_ERR(pcs)) {
-@@ -1209,6 +1208,8 @@ static void phylink_major_config(struct
- pcs_changed = pcs && pl->pcs != pcs;
- }
-
-+ phylink_pcs_neg_mode(pl, pcs, state->interface, state->advertising);
-+
- phylink_pcs_poll_stop(pl);
-
- if (pl->mac_ops->mac_prepare) {
-@@ -1299,9 +1300,8 @@ static int phylink_change_inband_advert(
- pl->link_config.pause);
-
- /* Recompute the PCS neg mode */
-- pl->pcs_neg_mode = phylink_pcs_neg_mode(pl->cur_link_an_mode,
-- pl->link_config.interface,
-- pl->link_config.advertising);
-+ phylink_pcs_neg_mode(pl, pl->pcs, pl->link_config.interface,
-+ pl->link_config.advertising);
-
- neg_mode = pl->cur_link_an_mode;
- if (pl->pcs->neg_mode)
+++ /dev/null
-From 1f92ead7e15003f632b5f138e8138095e0997d3d Mon Sep 17 00:00:00 2001
-Date: Tue, 3 Dec 2024 15:30:52 +0000
-Subject: [PATCH 02/13] net: phylink: split cur_link_an_mode into requested and
- active
-
-There is an interdependence between the current link_an_mode and
-pcs_neg_mode that some drivers rely upon to know whether inband or PHY
-mode will be used.
-
-In order to support detection of PCS and PHY inband capabilities
-resulting in automatic selection of inband or PHY mode, we need to
-cater for this, and support changing the MAC link_an_mode. However, we
-end up with an inter-dependency between the current link_an_mode and
-pcs_neg_mode.
-
-To solve this, split the current link_an_mode into the requested
-link_an_mode and active link_an_mode. The requested link_an_mode will
-always be passed to phylink_pcs_neg_mode(), and the active link_an_mode
-will be used for everything else, and only updated during
-phylink_major_config(). This will ensure that phylink_pcs_neg_mode()'s
-link_an_mode will not depend on the active link_an_mode that will,
-in a future patch, depend on pcs_neg_mode.
-
----
- drivers/net/phy/phylink.c | 60 ++++++++++++++++++++-------------------
- 1 file changed, 31 insertions(+), 29 deletions(-)
-
---- a/drivers/net/phy/phylink.c
-+++ b/drivers/net/phy/phylink.c
-@@ -56,7 +56,8 @@ struct phylink {
- struct phy_device *phydev;
- phy_interface_t link_interface; /* PHY_INTERFACE_xxx */
- u8 cfg_link_an_mode; /* MLO_AN_xxx */
-- u8 cur_link_an_mode;
-+ u8 req_link_an_mode; /* Requested MLO_AN_xxx mode */
-+ u8 act_link_an_mode; /* Active MLO_AN_xxx mode */
- u8 link_port; /* The current non-phy ethtool port */
- __ETHTOOL_DECLARE_LINK_MODE_MASK(supported);
-
-@@ -1098,13 +1099,13 @@ static void phylink_mac_config(struct ph
-
- phylink_dbg(pl,
- "%s: mode=%s/%s/%s adv=%*pb pause=%02x\n",
-- __func__, phylink_an_mode_str(pl->cur_link_an_mode),
-+ __func__, phylink_an_mode_str(pl->act_link_an_mode),
- phy_modes(st.interface),
- phy_rate_matching_to_str(st.rate_matching),
- __ETHTOOL_LINK_MODE_MASK_NBITS, st.advertising,
- st.pause);
-
-- pl->mac_ops->mac_config(pl->config, pl->cur_link_an_mode, &st);
-+ pl->mac_ops->mac_config(pl->config, pl->act_link_an_mode, &st);
- }
-
- static void phylink_pcs_an_restart(struct phylink *pl)
-@@ -1112,7 +1113,7 @@ static void phylink_pcs_an_restart(struc
- if (pl->pcs && linkmode_test_bit(ETHTOOL_LINK_MODE_Autoneg_BIT,
- pl->link_config.advertising) &&
- phy_interface_mode_is_8023z(pl->link_config.interface) &&
-- phylink_autoneg_inband(pl->cur_link_an_mode))
-+ phylink_autoneg_inband(pl->act_link_an_mode))
- pl->pcs->ops->pcs_an_restart(pl->pcs);
- }
-
-@@ -1142,7 +1143,7 @@ static void phylink_pcs_neg_mode(struct
- {
- unsigned int neg_mode, mode;
-
-- mode = pl->cur_link_an_mode;
-+ mode = pl->req_link_an_mode;
-
- switch (interface) {
- case PHY_INTERFACE_MODE_SGMII:
-@@ -1183,6 +1184,7 @@ static void phylink_pcs_neg_mode(struct
- }
-
- pl->pcs_neg_mode = neg_mode;
-+ pl->act_link_an_mode = mode;
- }
-
- static void phylink_major_config(struct phylink *pl, bool restart,
-@@ -1213,7 +1215,7 @@ static void phylink_major_config(struct
- phylink_pcs_poll_stop(pl);
-
- if (pl->mac_ops->mac_prepare) {
-- err = pl->mac_ops->mac_prepare(pl->config, pl->cur_link_an_mode,
-+ err = pl->mac_ops->mac_prepare(pl->config, pl->act_link_an_mode,
- state->interface);
- if (err < 0) {
- phylink_err(pl, "mac_prepare failed: %pe\n",
-@@ -1247,7 +1249,7 @@ static void phylink_major_config(struct
- if (pl->pcs_state == PCS_STATE_STARTING || pcs_changed)
- phylink_pcs_enable(pl->pcs);
-
-- neg_mode = pl->cur_link_an_mode;
-+ neg_mode = pl->act_link_an_mode;
- if (pl->pcs && pl->pcs->neg_mode)
- neg_mode = pl->pcs_neg_mode;
-
-@@ -1263,7 +1265,7 @@ static void phylink_major_config(struct
- phylink_pcs_an_restart(pl);
-
- if (pl->mac_ops->mac_finish) {
-- err = pl->mac_ops->mac_finish(pl->config, pl->cur_link_an_mode,
-+ err = pl->mac_ops->mac_finish(pl->config, pl->act_link_an_mode,
- state->interface);
- if (err < 0)
- phylink_err(pl, "mac_finish failed: %pe\n",
-@@ -1294,7 +1296,7 @@ static int phylink_change_inband_advert(
- return 0;
-
- phylink_dbg(pl, "%s: mode=%s/%s adv=%*pb pause=%02x\n", __func__,
-- phylink_an_mode_str(pl->cur_link_an_mode),
-+ phylink_an_mode_str(pl->req_link_an_mode),
- phy_modes(pl->link_config.interface),
- __ETHTOOL_LINK_MODE_MASK_NBITS, pl->link_config.advertising,
- pl->link_config.pause);
-@@ -1303,7 +1305,7 @@ static int phylink_change_inband_advert(
- phylink_pcs_neg_mode(pl, pl->pcs, pl->link_config.interface,
- pl->link_config.advertising);
-
-- neg_mode = pl->cur_link_an_mode;
-+ neg_mode = pl->act_link_an_mode;
- if (pl->pcs->neg_mode)
- neg_mode = pl->pcs_neg_mode;
-
-@@ -1368,7 +1370,7 @@ static void phylink_mac_initial_config(s
- {
- struct phylink_link_state link_state;
-
-- switch (pl->cur_link_an_mode) {
-+ switch (pl->req_link_an_mode) {
- case MLO_AN_PHY:
- link_state = pl->phy_state;
- break;
-@@ -1442,14 +1444,14 @@ static void phylink_link_up(struct phyli
-
- pl->cur_interface = link_state.interface;
-
-- neg_mode = pl->cur_link_an_mode;
-+ neg_mode = pl->act_link_an_mode;
- if (pl->pcs && pl->pcs->neg_mode)
- neg_mode = pl->pcs_neg_mode;
-
- phylink_pcs_link_up(pl->pcs, neg_mode, pl->cur_interface, speed,
- duplex);
-
-- pl->mac_ops->mac_link_up(pl->config, pl->phydev, pl->cur_link_an_mode,
-+ pl->mac_ops->mac_link_up(pl->config, pl->phydev, pl->act_link_an_mode,
- pl->cur_interface, speed, duplex,
- !!(link_state.pause & MLO_PAUSE_TX), rx_pause);
-
-@@ -1469,7 +1471,7 @@ static void phylink_link_down(struct phy
-
- if (ndev)
- netif_carrier_off(ndev);
-- pl->mac_ops->mac_link_down(pl->config, pl->cur_link_an_mode,
-+ pl->mac_ops->mac_link_down(pl->config, pl->act_link_an_mode,
- pl->cur_interface);
- phylink_info(pl, "Link is Down\n");
- }
-@@ -1495,10 +1497,10 @@ static void phylink_resolve(struct work_
- } else if (pl->mac_link_dropped) {
- link_state.link = false;
- retrigger = true;
-- } else if (pl->cur_link_an_mode == MLO_AN_FIXED) {
-+ } else if (pl->act_link_an_mode == MLO_AN_FIXED) {
- phylink_get_fixed_state(pl, &link_state);
- mac_config = link_state.link;
-- } else if (pl->cur_link_an_mode == MLO_AN_PHY) {
-+ } else if (pl->act_link_an_mode == MLO_AN_PHY) {
- link_state = pl->phy_state;
- mac_config = link_state.link;
- } else {
-@@ -1552,7 +1554,7 @@ static void phylink_resolve(struct work_
- }
- }
-
-- if (pl->cur_link_an_mode != MLO_AN_FIXED)
-+ if (pl->act_link_an_mode != MLO_AN_FIXED)
- phylink_apply_manual_flow(pl, &link_state);
-
- if (mac_config) {
-@@ -1729,7 +1731,7 @@ struct phylink *phylink_create(struct ph
- }
- }
-
-- pl->cur_link_an_mode = pl->cfg_link_an_mode;
-+ pl->req_link_an_mode = pl->cfg_link_an_mode;
-
- ret = phylink_register_sfp(pl, fwnode);
- if (ret < 0) {
-@@ -2126,7 +2128,7 @@ void phylink_start(struct phylink *pl)
- ASSERT_RTNL();
-
- phylink_info(pl, "configuring for %s/%s link mode\n",
-- phylink_an_mode_str(pl->cur_link_an_mode),
-+ phylink_an_mode_str(pl->req_link_an_mode),
- phy_modes(pl->link_config.interface));
-
- /* Always set the carrier off */
-@@ -2385,7 +2387,7 @@ int phylink_ethtool_ksettings_get(struct
-
- linkmode_copy(kset->link_modes.supported, pl->supported);
-
-- switch (pl->cur_link_an_mode) {
-+ switch (pl->act_link_an_mode) {
- case MLO_AN_FIXED:
- /* We are using fixed settings. Report these as the
- * current link settings - and note that these also
-@@ -2477,7 +2479,7 @@ int phylink_ethtool_ksettings_set(struct
- /* If we have a fixed link, refuse to change link parameters.
- * If the link parameters match, accept them but do nothing.
- */
-- if (pl->cur_link_an_mode == MLO_AN_FIXED) {
-+ if (pl->req_link_an_mode == MLO_AN_FIXED) {
- if (s->speed != pl->link_config.speed ||
- s->duplex != pl->link_config.duplex)
- return -EINVAL;
-@@ -2493,7 +2495,7 @@ int phylink_ethtool_ksettings_set(struct
- * is our default case) but do not allow the advertisement to
- * be changed. If the advertisement matches, simply return.
- */
-- if (pl->cur_link_an_mode == MLO_AN_FIXED) {
-+ if (pl->req_link_an_mode == MLO_AN_FIXED) {
- if (!linkmode_equal(config.advertising,
- pl->link_config.advertising))
- return -EINVAL;
-@@ -2533,7 +2535,7 @@ int phylink_ethtool_ksettings_set(struct
- linkmode_copy(support, pl->supported);
- if (phylink_validate(pl, support, &config)) {
- phylink_err(pl, "validation of %s/%s with support %*pb failed\n",
-- phylink_an_mode_str(pl->cur_link_an_mode),
-+ phylink_an_mode_str(pl->req_link_an_mode),
- phy_modes(config.interface),
- __ETHTOOL_LINK_MODE_MASK_NBITS, support);
- return -EINVAL;
-@@ -2633,7 +2635,7 @@ int phylink_ethtool_set_pauseparam(struc
-
- ASSERT_RTNL();
-
-- if (pl->cur_link_an_mode == MLO_AN_FIXED)
-+ if (pl->req_link_an_mode == MLO_AN_FIXED)
- return -EOPNOTSUPP;
-
- if (!phylink_test(pl->supported, Pause) &&
-@@ -2897,7 +2899,7 @@ static int phylink_mii_read(struct phyli
- struct phylink_link_state state;
- int val = 0xffff;
-
-- switch (pl->cur_link_an_mode) {
-+ switch (pl->act_link_an_mode) {
- case MLO_AN_FIXED:
- if (phy_id == 0) {
- phylink_get_fixed_state(pl, &state);
-@@ -2922,7 +2924,7 @@ static int phylink_mii_read(struct phyli
- static int phylink_mii_write(struct phylink *pl, unsigned int phy_id,
- unsigned int reg, unsigned int val)
- {
-- switch (pl->cur_link_an_mode) {
-+ switch (pl->act_link_an_mode) {
- case MLO_AN_FIXED:
- break;
-
-@@ -3125,9 +3127,9 @@ static void phylink_sfp_set_config(struc
- changed = true;
- }
-
-- if (pl->cur_link_an_mode != mode ||
-+ if (pl->req_link_an_mode != mode ||
- pl->link_config.interface != state->interface) {
-- pl->cur_link_an_mode = mode;
-+ pl->req_link_an_mode = mode;
- pl->link_config.interface = state->interface;
-
- changed = true;
+++ /dev/null
-From 4e7d000286fe8e12f2d88032711ffab3ab658b12 Mon Sep 17 00:00:00 2001
-Date: Tue, 3 Dec 2024 15:30:57 +0000
-Subject: [PATCH 03/13] net: phylink: add debug for phylink_major_config()
-
-Now that we have a more complexity in phylink_major_config(), augment
-the debugging so we can see what's going on there.
-
----
- drivers/net/phy/phylink.c | 27 ++++++++++++++++++++++++++-
- 1 file changed, 26 insertions(+), 1 deletion(-)
-
---- a/drivers/net/phy/phylink.c
-+++ b/drivers/net/phy/phylink.c
-@@ -163,6 +163,24 @@ static const char *phylink_an_mode_str(u
- return mode < ARRAY_SIZE(modestr) ? modestr[mode] : "unknown";
- }
-
-+static const char *phylink_pcs_mode_str(unsigned int mode)
-+{
-+ if (!mode)
-+ return "none";
-+
-+ if (mode & PHYLINK_PCS_NEG_OUTBAND)
-+ return "outband";
-+
-+ if (mode & PHYLINK_PCS_NEG_INBAND) {
-+ if (mode & PHYLINK_PCS_NEG_ENABLED)
-+ return "inband,an-enabled";
-+ else
-+ return "inband,an-disabled";
-+ }
-+
-+ return "unknown";
-+}
-+
- static unsigned int phylink_interface_signal_rate(phy_interface_t interface)
- {
- switch (interface) {
-@@ -1196,7 +1214,9 @@ static void phylink_major_config(struct
- unsigned int neg_mode;
- int err;
-
-- phylink_dbg(pl, "major config %s\n", phy_modes(state->interface));
-+ phylink_dbg(pl, "major config, requested %s/%s\n",
-+ phylink_an_mode_str(pl->req_link_an_mode),
-+ phy_modes(state->interface));
-
- if (pl->using_mac_select_pcs) {
- pcs = pl->mac_ops->mac_select_pcs(pl->config, state->interface);
-@@ -1212,6 +1232,11 @@ static void phylink_major_config(struct
-
- phylink_pcs_neg_mode(pl, pcs, state->interface, state->advertising);
-
-+ phylink_dbg(pl, "major config, active %s/%s/%s\n",
-+ phylink_an_mode_str(pl->act_link_an_mode),
-+ phylink_pcs_mode_str(pl->pcs_neg_mode),
-+ phy_modes(state->interface));
-+
- phylink_pcs_poll_stop(pl);
-
- if (pl->mac_ops->mac_prepare) {
+++ /dev/null
-From b4c7698dd95f253c6958d8c6ac219098009bf28a Mon Sep 17 00:00:00 2001
-Date: Tue, 3 Dec 2024 15:31:02 +0000
-Subject: [PATCH 04/13] net: phy: add phy_inband_caps()
-
-Add a method to query the PHY's in-band capabilities for a PHY
-interface mode.
-
-Where the interface mode does not have in-band capability, or the PHY
-driver has not been updated to return this information, then
-phy_inband_caps() should return zero. Otherwise, PHY drivers will
-return a value consisting of the following flags:
-
-LINK_INBAND_DISABLE indicates that the hardware does not support
-in-band signalling, or can have in-band signalling configured via
-software to be disabled.
-
-LINK_INBAND_ENABLE indicates that the hardware will use in-band
-signalling, or can have in-band signalling configured via software
-to be enabled.
-
-LINK_INBAND_BYPASS indicates that the hardware has the ability to
-bypass in-band signalling when enabled after a timeout if the link
-partner does not respond to its in-band signalling.
-
-This reports the PHY capabilities for the particular interface mode,
-not the current configuration.
-
----
- drivers/net/phy/phy.c | 21 +++++++++++++++++++++
- include/linux/phy.h | 28 ++++++++++++++++++++++++++++
- 2 files changed, 49 insertions(+)
-
---- a/drivers/net/phy/phy.c
-+++ b/drivers/net/phy/phy.c
-@@ -973,6 +973,27 @@ static int phy_check_link_status(struct
- }
-
- /**
-+ * phy_inband_caps - query which in-band signalling modes are supported
-+ * @phydev: a pointer to a &struct phy_device
-+ * @interface: the interface mode for the PHY
-+ *
-+ * Returns zero if it is unknown what in-band signalling is supported by the
-+ * PHY (e.g. because the PHY driver doesn't implement the method.) Otherwise,
-+ * returns a bit mask of the LINK_INBAND_* values from
-+ * &enum link_inband_signalling to describe which inband modes are supported
-+ * by the PHY for this interface mode.
-+ */
-+unsigned int phy_inband_caps(struct phy_device *phydev,
-+ phy_interface_t interface)
-+{
-+ if (phydev->drv && phydev->drv->inband_caps)
-+ return phydev->drv->inband_caps(phydev, interface);
-+
-+ return 0;
-+}
-+EXPORT_SYMBOL_GPL(phy_inband_caps);
-+
-+/**
- * _phy_start_aneg - start auto-negotiation for this PHY device
- * @phydev: the phy_device struct
- *
---- a/include/linux/phy.h
-+++ b/include/linux/phy.h
-@@ -790,6 +790,24 @@ struct phy_tdr_config {
- #define PHY_PAIR_ALL -1
-
- /**
-+ * enum link_inband_signalling - in-band signalling modes that are supported
-+ *
-+ * @LINK_INBAND_DISABLE: in-band signalling can be disabled
-+ * @LINK_INBAND_ENABLE: in-band signalling can be enabled without bypass
-+ * @LINK_INBAND_BYPASS: in-band signalling can be enabled with bypass
-+ *
-+ * The possible and required bits can only be used if the valid bit is set.
-+ * If possible is clear, that means inband signalling can not be used.
-+ * Required is only valid when possible is set, and means that inband
-+ * signalling must be used.
-+ */
-+enum link_inband_signalling {
-+ LINK_INBAND_DISABLE = BIT(0),
-+ LINK_INBAND_ENABLE = BIT(1),
-+ LINK_INBAND_BYPASS = BIT(2),
-+};
-+
-+/**
- * struct phy_plca_cfg - Configuration of the PLCA (Physical Layer Collision
- * Avoidance) Reconciliation Sublayer.
- *
-@@ -919,6 +937,14 @@ struct phy_driver {
- int (*get_features)(struct phy_device *phydev);
-
- /**
-+ * @inband_caps: query whether in-band is supported for the given PHY
-+ * interface mode. Returns a bitmask of bits defined by enum
-+ * link_inband_signalling.
-+ */
-+ unsigned int (*inband_caps)(struct phy_device *phydev,
-+ phy_interface_t interface);
-+
-+ /**
- * @get_rate_matching: Get the supported type of rate matching for a
- * particular phy interface. This is used by phy consumers to determine
- * whether to advertise lower-speed modes for that interface. It is
-@@ -1735,6 +1761,8 @@ void phy_stop(struct phy_device *phydev)
- int phy_config_aneg(struct phy_device *phydev);
- int phy_start_aneg(struct phy_device *phydev);
- int phy_aneg_done(struct phy_device *phydev);
-+unsigned int phy_inband_caps(struct phy_device *phydev,
-+ phy_interface_t interface);
- int phy_speed_down(struct phy_device *phydev, bool sync);
- int phy_speed_up(struct phy_device *phydev);
- bool phy_check_valid(int speed, int duplex, unsigned long *features);
+++ /dev/null
-From c64c7fa0a774d9da72071a8517e359992baac982 Mon Sep 17 00:00:00 2001
-Date: Tue, 3 Dec 2024 15:31:07 +0000
-Subject: [PATCH 05/13] net: phy: bcm84881: implement phy_inband_caps() method
-
-BCM84881 has no support for inband signalling, so this is a trivial
-implementation that returns no support for inband.
-
----
- drivers/net/phy/bcm84881.c | 10 ++++++++++
- 1 file changed, 10 insertions(+)
-
---- a/drivers/net/phy/bcm84881.c
-+++ b/drivers/net/phy/bcm84881.c
-@@ -223,11 +223,21 @@ static int bcm84881_read_status(struct p
- return genphy_c45_read_mdix(phydev);
- }
-
-+/* The Broadcom BCM84881 in the Methode DM7052 is unable to provide a SGMII
-+ * or 802.3z control word, so inband will not work.
-+ */
-+static unsigned int bcm84881_inband_caps(struct phy_device *phydev,
-+ phy_interface_t interface)
-+{
-+ return LINK_INBAND_DISABLE;
-+}
-+
- static struct phy_driver bcm84881_drivers[] = {
- {
- .phy_id = 0xae025150,
- .phy_id_mask = 0xfffffff0,
- .name = "Broadcom BCM84881",
-+ .inband_caps = bcm84881_inband_caps,
- .config_init = bcm84881_config_init,
- .probe = bcm84881_probe,
- .get_features = bcm84881_get_features,
+++ /dev/null
-From 1c86828dff88e28b8ade6bddeee0163a023faf91 Mon Sep 17 00:00:00 2001
-Date: Tue, 3 Dec 2024 15:31:12 +0000
-Subject: [PATCH 06/13] net: phy: marvell: implement phy_inband_caps() method
-
-Provide an implementation for phy_inband_caps() for Marvell PHYs used
-on SFP modules, so that phylink knows the PHYs capabilities.
-
----
- drivers/net/phy/marvell.c | 17 +++++++++++++++++
- 1 file changed, 17 insertions(+)
-
---- a/drivers/net/phy/marvell.c
-+++ b/drivers/net/phy/marvell.c
-@@ -673,6 +673,20 @@ static int marvell_config_aneg_fiber(str
- return genphy_check_and_restart_aneg(phydev, changed);
- }
-
-+static unsigned int m88e1111_inband_caps(struct phy_device *phydev,
-+ phy_interface_t interface)
-+{
-+ /* In 1000base-X and SGMII modes, the inband mode can be changed
-+ * through the Fibre page BMCR ANENABLE bit.
-+ */
-+ if (interface == PHY_INTERFACE_MODE_1000BASEX ||
-+ interface == PHY_INTERFACE_MODE_SGMII)
-+ return LINK_INBAND_DISABLE | LINK_INBAND_ENABLE |
-+ LINK_INBAND_BYPASS;
-+
-+ return 0;
-+}
-+
- static int m88e1111_config_aneg(struct phy_device *phydev)
- {
- int extsr = phy_read(phydev, MII_M1111_PHY_EXT_SR);
-@@ -3329,6 +3343,7 @@ static struct phy_driver marvell_drivers
- .name = "Marvell 88E1112",
- /* PHY_GBIT_FEATURES */
- .probe = marvell_probe,
-+ .inband_caps = m88e1111_inband_caps,
- .config_init = m88e1112_config_init,
- .config_aneg = marvell_config_aneg,
- .config_intr = marvell_config_intr,
-@@ -3349,6 +3364,7 @@ static struct phy_driver marvell_drivers
- .name = "Marvell 88E1111",
- /* PHY_GBIT_FEATURES */
- .probe = marvell_probe,
-+ .inband_caps = m88e1111_inband_caps,
- .config_init = m88e1111gbe_config_init,
- .config_aneg = m88e1111_config_aneg,
- .read_status = marvell_read_status,
-@@ -3370,6 +3386,7 @@ static struct phy_driver marvell_drivers
- .name = "Marvell 88E1111 (Finisar)",
- /* PHY_GBIT_FEATURES */
- .probe = marvell_probe,
-+ .inband_caps = m88e1111_inband_caps,
- .config_init = m88e1111gbe_config_init,
- .config_aneg = m88e1111_config_aneg,
- .read_status = marvell_read_status,
+++ /dev/null
-From 5d58a890c02770ba8d790b1f3c6e8c0e20514dc2 Mon Sep 17 00:00:00 2001
-Date: Tue, 3 Dec 2024 15:31:18 +0000
-Subject: [PATCH 07/13] net: phy: add phy_config_inband()
-
-Add a method to configure the PHY's in-band mode.
-
----
- drivers/net/phy/phy.c | 32 ++++++++++++++++++++++++++++++++
- include/linux/phy.h | 6 ++++++
- 2 files changed, 38 insertions(+)
-
---- a/drivers/net/phy/phy.c
-+++ b/drivers/net/phy/phy.c
-@@ -994,6 +994,38 @@ unsigned int phy_inband_caps(struct phy_
- EXPORT_SYMBOL_GPL(phy_inband_caps);
-
- /**
-+ * phy_config_inband - configure the desired PHY in-band mode
-+ * @phydev: the phy_device struct
-+ * @modes: in-band modes to configure
-+ *
-+ * Description: disables, enables or enables-with-bypass in-band signalling
-+ * between the PHY and host system.
-+ *
-+ * Returns: zero on success, or negative errno value.
-+ */
-+int phy_config_inband(struct phy_device *phydev, unsigned int modes)
-+{
-+ int err;
-+
-+ if (!!(modes & LINK_INBAND_DISABLE) +
-+ !!(modes & LINK_INBAND_ENABLE) +
-+ !!(modes & LINK_INBAND_BYPASS) != 1)
-+ return -EINVAL;
-+
-+ mutex_lock(&phydev->lock);
-+ if (!phydev->drv)
-+ err = -EIO;
-+ else if (!phydev->drv->config_inband)
-+ err = -EOPNOTSUPP;
-+ else
-+ err = phydev->drv->config_inband(phydev, modes);
-+ mutex_unlock(&phydev->lock);
-+
-+ return err;
-+}
-+EXPORT_SYMBOL(phy_config_inband);
-+
-+/**
- * _phy_start_aneg - start auto-negotiation for this PHY device
- * @phydev: the phy_device struct
- *
---- a/include/linux/phy.h
-+++ b/include/linux/phy.h
-@@ -945,6 +945,11 @@ struct phy_driver {
- phy_interface_t interface);
-
- /**
-+ * @config_inband: configure in-band mode for the PHY
-+ */
-+ int (*config_inband)(struct phy_device *phydev, unsigned int modes);
-+
-+ /**
- * @get_rate_matching: Get the supported type of rate matching for a
- * particular phy interface. This is used by phy consumers to determine
- * whether to advertise lower-speed modes for that interface. It is
-@@ -1763,6 +1768,7 @@ int phy_start_aneg(struct phy_device *ph
- int phy_aneg_done(struct phy_device *phydev);
- unsigned int phy_inband_caps(struct phy_device *phydev,
- phy_interface_t interface);
-+int phy_config_inband(struct phy_device *phydev, unsigned int modes);
- int phy_speed_down(struct phy_device *phydev, bool sync);
- int phy_speed_up(struct phy_device *phydev);
- bool phy_check_valid(int speed, int duplex, unsigned long *features);
+++ /dev/null
-From a219912e0fec73c346e64ef47013cb2e152f88fc Mon Sep 17 00:00:00 2001
-Date: Tue, 3 Dec 2024 15:31:23 +0000
-Subject: [PATCH 08/13] net: phy: marvell: implement config_inband() method
-
-Implement the config_inband() method for Marvell 88E1112, 88E1111,
-and Finisar's 88E1111 variant.
-
----
- drivers/net/phy/marvell.c | 31 +++++++++++++++++++++++++++++++
- 1 file changed, 31 insertions(+)
-
---- a/drivers/net/phy/marvell.c
-+++ b/drivers/net/phy/marvell.c
-@@ -687,6 +687,34 @@ static unsigned int m88e1111_inband_caps
- return 0;
- }
-
-+static int m88e1111_config_inband(struct phy_device *phydev, unsigned int modes)
-+{
-+ u16 extsr, bmcr;
-+ int err;
-+
-+ if (phydev->interface != PHY_INTERFACE_MODE_1000BASEX &&
-+ phydev->interface != PHY_INTERFACE_MODE_SGMII)
-+ return -EINVAL;
-+
-+ if (modes == LINK_INBAND_BYPASS)
-+ extsr = MII_M1111_HWCFG_SERIAL_AN_BYPASS;
-+ else
-+ extsr = 0;
-+
-+ if (modes == LINK_INBAND_DISABLE)
-+ bmcr = 0;
-+ else
-+ bmcr = BMCR_ANENABLE;
-+
-+ err = phy_modify(phydev, MII_M1111_PHY_EXT_SR,
-+ MII_M1111_HWCFG_SERIAL_AN_BYPASS, extsr);
-+ if (err < 0)
-+ return extsr;
-+
-+ return phy_modify_paged(phydev, MII_MARVELL_FIBER_PAGE, MII_BMCR,
-+ BMCR_ANENABLE, bmcr);
-+}
-+
- static int m88e1111_config_aneg(struct phy_device *phydev)
- {
- int extsr = phy_read(phydev, MII_M1111_PHY_EXT_SR);
-@@ -3344,6 +3372,7 @@ static struct phy_driver marvell_drivers
- /* PHY_GBIT_FEATURES */
- .probe = marvell_probe,
- .inband_caps = m88e1111_inband_caps,
-+ .config_inband = m88e1111_config_inband,
- .config_init = m88e1112_config_init,
- .config_aneg = marvell_config_aneg,
- .config_intr = marvell_config_intr,
-@@ -3365,6 +3394,7 @@ static struct phy_driver marvell_drivers
- /* PHY_GBIT_FEATURES */
- .probe = marvell_probe,
- .inband_caps = m88e1111_inband_caps,
-+ .config_inband = m88e1111_config_inband,
- .config_init = m88e1111gbe_config_init,
- .config_aneg = m88e1111_config_aneg,
- .read_status = marvell_read_status,
-@@ -3387,6 +3417,7 @@ static struct phy_driver marvell_drivers
- /* PHY_GBIT_FEATURES */
- .probe = marvell_probe,
- .inband_caps = m88e1111_inband_caps,
-+ .config_inband = m88e1111_config_inband,
- .config_init = m88e1111gbe_config_init,
- .config_aneg = m88e1111_config_aneg,
- .read_status = marvell_read_status,
+++ /dev/null
-From df874f9e52c340cc6f0a0014a97b778f67d46849 Mon Sep 17 00:00:00 2001
-Date: Tue, 3 Dec 2024 15:31:28 +0000
-Subject: [PATCH 09/13] net: phylink: add pcs_inband_caps() method
-
-Add a pcs_inband_caps() method to query the PCS for its inband link
-capabilities, and use this to determine whether link modes used with
-optical SFPs can be supported.
-
-When a PCS does not provide a method, we allow inband negotiation to
-be either on or off, making this a no-op until the pcs_inband_caps()
-method is implemented by a PCS driver.
-
----
- drivers/net/phy/phylink.c | 60 +++++++++++++++++++++++++++++++++++++++
- include/linux/phylink.h | 17 +++++++++++
- 2 files changed, 77 insertions(+)
-
---- a/drivers/net/phy/phylink.c
-+++ b/drivers/net/phy/phylink.c
-@@ -1038,6 +1038,15 @@ static void phylink_resolve_an_pause(str
- }
- }
-
-+static unsigned int phylink_pcs_inband_caps(struct phylink_pcs *pcs,
-+ phy_interface_t interface)
-+{
-+ if (pcs && pcs->ops->pcs_inband_caps)
-+ return pcs->ops->pcs_inband_caps(pcs, interface);
-+
-+ return 0;
-+}
-+
- static void phylink_pcs_pre_config(struct phylink_pcs *pcs,
- phy_interface_t interface)
- {
-@@ -1091,6 +1100,24 @@ static void phylink_pcs_link_up(struct p
- pcs->ops->pcs_link_up(pcs, neg_mode, interface, speed, duplex);
- }
-
-+/* Query inband for a specific interface mode, asking the MAC for the
-+ * PCS which will be used to handle the interface mode.
-+ */
-+static unsigned int phylink_inband_caps(struct phylink *pl,
-+ phy_interface_t interface)
-+{
-+ struct phylink_pcs *pcs;
-+
-+ if (!pl->mac_ops->mac_select_pcs)
-+ return 0;
-+
-+ pcs = pl->mac_ops->mac_select_pcs(pl->config, interface);
-+ if (!pcs)
-+ return 0;
-+
-+ return phylink_pcs_inband_caps(pcs, interface);
-+}
-+
- static void phylink_pcs_poll_stop(struct phylink *pl)
- {
- if (pl->cfg_link_an_mode == MLO_AN_INBAND)
-@@ -2443,6 +2470,26 @@ int phylink_ethtool_ksettings_get(struct
- }
- EXPORT_SYMBOL_GPL(phylink_ethtool_ksettings_get);
-
-+static bool phylink_validate_pcs_inband_autoneg(struct phylink *pl,
-+ phy_interface_t interface,
-+ unsigned long *adv)
-+{
-+ unsigned int inband = phylink_inband_caps(pl, interface);
-+ unsigned int mask;
-+
-+ /* If the PCS doesn't implement inband support, be permissive. */
-+ if (!inband)
-+ return true;
-+
-+ if (linkmode_test_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, adv))
-+ mask = LINK_INBAND_ENABLE;
-+ else
-+ mask = LINK_INBAND_DISABLE;
-+
-+ /* Check whether the PCS implements the required mode */
-+ return !!(inband & mask);
-+}
-+
- /**
- * phylink_ethtool_ksettings_set() - set the link settings
- * @pl: a pointer to a &struct phylink returned from phylink_create()
-@@ -2578,6 +2625,13 @@ int phylink_ethtool_ksettings_set(struct
- phylink_is_empty_linkmode(config.advertising))
- return -EINVAL;
-
-+ /* Validate the autonegotiation state. We don't have a PHY in this
-+ * situation, so the PCS is the media-facing entity.
-+ */
-+ if (!phylink_validate_pcs_inband_autoneg(pl, config.interface,
-+ config.advertising))
-+ return -EINVAL;
-+
- mutex_lock(&pl->state_mutex);
- pl->link_config.speed = config.speed;
- pl->link_config.duplex = config.duplex;
-@@ -3274,6 +3328,12 @@ static int phylink_sfp_config_optical(st
- phylink_dbg(pl, "optical SFP: chosen %s interface\n",
- phy_modes(interface));
-
-+ if (!phylink_validate_pcs_inband_autoneg(pl, interface,
-+ config.advertising)) {
-+ phylink_err(pl, "autoneg setting not compatible with PCS");
-+ return -EINVAL;
-+ }
-+
- config.interface = interface;
-
- /* Ignore errors if we're expecting a PHY to attach later */
---- a/include/linux/phylink.h
-+++ b/include/linux/phylink.h
-@@ -432,6 +432,7 @@ struct phylink_pcs {
- /**
- * struct phylink_pcs_ops - MAC PCS operations structure.
- * @pcs_validate: validate the link configuration.
-+ * @pcs_inband_caps: query inband support for interface mode.
- * @pcs_enable: enable the PCS.
- * @pcs_disable: disable the PCS.
- * @pcs_pre_config: pre-mac_config method (for errata)
-@@ -445,6 +446,8 @@ struct phylink_pcs {
- struct phylink_pcs_ops {
- int (*pcs_validate)(struct phylink_pcs *pcs, unsigned long *supported,
- const struct phylink_link_state *state);
-+ unsigned int (*pcs_inband_caps)(struct phylink_pcs *pcs,
-+ phy_interface_t interface);
- int (*pcs_enable)(struct phylink_pcs *pcs);
- void (*pcs_disable)(struct phylink_pcs *pcs);
- void (*pcs_pre_config)(struct phylink_pcs *pcs,
-@@ -481,6 +484,20 @@ int pcs_validate(struct phylink_pcs *pcs
- const struct phylink_link_state *state);
-
- /**
-+ * pcs_inband_caps - query PCS in-band capabilities for interface mode.
-+ * @pcs: a pointer to a &struct phylink_pcs.
-+ * @interface: interface mode to be queried
-+ *
-+ * Returns zero if it is unknown what in-band signalling is supported by the
-+ * PHY (e.g. because the PHY driver doesn't implement the method.) Otherwise,
-+ * returns a bit mask of the LINK_INBAND_* values from
-+ * &enum link_inband_signalling to describe which inband modes are supported
-+ * for this interface mode.
-+ */
-+unsigned int pcs_inband_caps(struct phylink_pcs *pcs,
-+ phy_interface_t interface);
-+
-+/**
- * pcs_enable() - enable the PCS.
- * @pcs: a pointer to a &struct phylink_pcs.
- */
+++ /dev/null
-From 513e8fb8fa32035b3325e2e14fb9598f8cb545e9 Mon Sep 17 00:00:00 2001
-Date: Tue, 3 Dec 2024 15:31:33 +0000
-Subject: [PATCH 10/13] net: mvneta: implement pcs_inband_caps() method
-
-Report the PCS in-band capabilities to phylink for Marvell NETA
-interfaces.
-
----
- drivers/net/ethernet/marvell/mvneta.c | 27 +++++++++++++++++----------
- 1 file changed, 17 insertions(+), 10 deletions(-)
-
---- a/drivers/net/ethernet/marvell/mvneta.c
-+++ b/drivers/net/ethernet/marvell/mvneta.c
-@@ -3959,20 +3959,27 @@ static struct mvneta_port *mvneta_pcs_to
- return container_of(pcs, struct mvneta_port, phylink_pcs);
- }
-
--static int mvneta_pcs_validate(struct phylink_pcs *pcs,
-- unsigned long *supported,
-- const struct phylink_link_state *state)
-+static unsigned int mvneta_pcs_inband_caps(struct phylink_pcs *pcs,
-+ phy_interface_t interface)
- {
-- /* We only support QSGMII, SGMII, 802.3z and RGMII modes.
-- * When in 802.3z mode, we must have AN enabled:
-+ /* When operating in an 802.3z mode, we must have AN enabled:
- * "Bit 2 Field InBandAnEn In-band Auto-Negotiation enable. ...
- * When <PortType> = 1 (1000BASE-X) this field must be set to 1."
-+ * Therefore, inband is "required".
- */
-- if (phy_interface_mode_is_8023z(state->interface) &&
-- !phylink_test(state->advertising, Autoneg))
-- return -EINVAL;
-+ if (phy_interface_mode_is_8023z(interface))
-+ return LINK_INBAND_ENABLE;
-
-- return 0;
-+ /* QSGMII, SGMII and RGMII can be configured to use inband
-+ * signalling of the AN result. Indicate these as "possible".
-+ */
-+ if (interface == PHY_INTERFACE_MODE_SGMII ||
-+ interface == PHY_INTERFACE_MODE_QSGMII ||
-+ phy_interface_mode_is_rgmii(interface))
-+ return LINK_INBAND_DISABLE | LINK_INBAND_ENABLE;
-+
-+ /* For any other modes, indicate that inband is not supported. */
-+ return LINK_INBAND_DISABLE;
- }
-
- static void mvneta_pcs_get_state(struct phylink_pcs *pcs,
-@@ -4070,7 +4077,7 @@ static void mvneta_pcs_an_restart(struct
- }
-
- static const struct phylink_pcs_ops mvneta_phylink_pcs_ops = {
-- .pcs_validate = mvneta_pcs_validate,
-+ .pcs_inband_caps = mvneta_pcs_inband_caps,
- .pcs_get_state = mvneta_pcs_get_state,
- .pcs_config = mvneta_pcs_config,
- .pcs_an_restart = mvneta_pcs_an_restart,
+++ /dev/null
-From d4169f0c7665afb8d8adb5e1b1df3db88517d0ad Mon Sep 17 00:00:00 2001
-Date: Tue, 3 Dec 2024 15:31:38 +0000
-Subject: [PATCH 11/13] net: mvpp2: implement pcs_inband_caps() method
-
-Report the PCS in-band capabilities to phylink for Marvell PP2
-interfaces.
-
----
- .../net/ethernet/marvell/mvpp2/mvpp2_main.c | 25 ++++++++++++-------
- 1 file changed, 16 insertions(+), 9 deletions(-)
-
---- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
-+++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
-@@ -6214,19 +6214,26 @@ static const struct phylink_pcs_ops mvpp
- .pcs_config = mvpp2_xlg_pcs_config,
- };
-
--static int mvpp2_gmac_pcs_validate(struct phylink_pcs *pcs,
-- unsigned long *supported,
-- const struct phylink_link_state *state)
-+static unsigned int mvpp2_gmac_pcs_inband_caps(struct phylink_pcs *pcs,
-+ phy_interface_t interface)
- {
-- /* When in 802.3z mode, we must have AN enabled:
-+ /* When operating in an 802.3z mode, we must have AN enabled:
- * Bit 2 Field InBandAnEn In-band Auto-Negotiation enable. ...
- * When <PortType> = 1 (1000BASE-X) this field must be set to 1.
-+ * Therefore, inband is "required".
- */
-- if (phy_interface_mode_is_8023z(state->interface) &&
-- !phylink_test(state->advertising, Autoneg))
-- return -EINVAL;
-+ if (phy_interface_mode_is_8023z(interface))
-+ return LINK_INBAND_ENABLE;
-
-- return 0;
-+ /* SGMII and RGMII can be configured to use inband signalling of the
-+ * AN result. Indicate these as "possible".
-+ */
-+ if (interface == PHY_INTERFACE_MODE_SGMII ||
-+ phy_interface_mode_is_rgmii(interface))
-+ return LINK_INBAND_DISABLE | LINK_INBAND_ENABLE;
-+
-+ /* For any other modes, indicate that inband is not supported. */
-+ return LINK_INBAND_DISABLE;
- }
-
- static void mvpp2_gmac_pcs_get_state(struct phylink_pcs *pcs,
-@@ -6333,7 +6340,7 @@ static void mvpp2_gmac_pcs_an_restart(st
- }
-
- static const struct phylink_pcs_ops mvpp2_phylink_gmac_pcs_ops = {
-- .pcs_validate = mvpp2_gmac_pcs_validate,
-+ .pcs_inband_caps = mvpp2_gmac_pcs_inband_caps,
- .pcs_get_state = mvpp2_gmac_pcs_get_state,
- .pcs_config = mvpp2_gmac_pcs_config,
- .pcs_an_restart = mvpp2_gmac_pcs_an_restart,
+++ /dev/null
-From 5fd0f1a02e750e2db4038dee60edea669ce5aab1 Mon Sep 17 00:00:00 2001
-Date: Tue, 3 Dec 2024 15:31:43 +0000
-Subject: [PATCH 12/13] net: phylink: add negotiation of in-band capabilities
-
-Support for in-band signalling with Serdes links is uncertain. Some
-PHYs do not support in-band for e.g. SGMII. Some PCS do not support
-in-band for 2500Base-X. Some PCS require in-band for Base-X protocols.
-
-Simply using what is in DT is insufficient when we have hot-pluggable
-PHYs e.g. in the form of SFP modules, which may not provide the
-in-band signalling.
-
-In order to address this, we have introduced phy_inband_caps() and
-pcs_inband_caps() functions to allow phylink to retrieve the
-capabilities from each end of the PCS/PHY link. This commit adds code
-to resolve whether in-band will be used in the various scenarios that
-we have: In-band not being used, PHY present using SGMII or Base-X,
-PHY not present. We also deal with no capabilties provided.
-
----
- drivers/net/phy/phylink.c | 154 +++++++++++++++++++++++++++++++++++---
- 1 file changed, 144 insertions(+), 10 deletions(-)
-
---- a/drivers/net/phy/phylink.c
-+++ b/drivers/net/phy/phylink.c
-@@ -75,6 +75,7 @@ struct phylink {
-
- struct mutex state_mutex;
- struct phylink_link_state phy_state;
-+ unsigned int phy_ib_mode;
- struct work_struct resolve;
- unsigned int pcs_neg_mode;
- unsigned int pcs_state;
-@@ -1186,10 +1187,18 @@ static void phylink_pcs_neg_mode(struct
- phy_interface_t interface,
- const unsigned long *advertising)
- {
-+ unsigned int pcs_ib_caps = 0;
-+ unsigned int phy_ib_caps = 0;
- unsigned int neg_mode, mode;
-+ enum {
-+ INBAND_CISCO_SGMII,
-+ INBAND_BASEX,
-+ } type;
-
- mode = pl->req_link_an_mode;
-
-+ pl->phy_ib_mode = 0;
-+
- switch (interface) {
- case PHY_INTERFACE_MODE_SGMII:
- case PHY_INTERFACE_MODE_QSGMII:
-@@ -1200,10 +1209,7 @@ static void phylink_pcs_neg_mode(struct
- * inband communication. Note: there exist PHYs that run
- * with SGMII but do not send the inband data.
- */
-- if (!phylink_autoneg_inband(mode))
-- neg_mode = PHYLINK_PCS_NEG_OUTBAND;
-- else
-- neg_mode = PHYLINK_PCS_NEG_INBAND_ENABLED;
-+ type = INBAND_CISCO_SGMII;
- break;
-
- case PHY_INTERFACE_MODE_1000BASEX:
-@@ -1214,18 +1220,139 @@ static void phylink_pcs_neg_mode(struct
- * as well, but drivers may not support this, so may
- * need to override this.
- */
-- if (!phylink_autoneg_inband(mode))
-+ type = INBAND_BASEX;
-+ break;
-+
-+ default:
-+ pl->pcs_neg_mode = PHYLINK_PCS_NEG_NONE;
-+ pl->act_link_an_mode = mode;
-+ return;
-+ }
-+
-+ if (pcs)
-+ pcs_ib_caps = phylink_pcs_inband_caps(pcs, interface);
-+
-+ if (pl->phydev)
-+ phy_ib_caps = phy_inband_caps(pl->phydev, interface);
-+
-+ phylink_dbg(pl, "interface %s inband modes: pcs=%02x phy=%02x\n",
-+ phy_modes(interface), pcs_ib_caps, phy_ib_caps);
-+
-+ if (!phylink_autoneg_inband(mode)) {
-+ bool pcs_ib_only = false;
-+ bool phy_ib_only = false;
-+
-+ if (pcs_ib_caps && pcs_ib_caps != LINK_INBAND_DISABLE) {
-+ /* PCS supports reporting in-band capabilities, and
-+ * supports more than disable mode.
-+ */
-+ if (pcs_ib_caps & LINK_INBAND_DISABLE)
-+ neg_mode = PHYLINK_PCS_NEG_OUTBAND;
-+ else if (pcs_ib_caps & LINK_INBAND_ENABLE)
-+ pcs_ib_only = true;
-+ }
-+
-+ if (phy_ib_caps && phy_ib_caps != LINK_INBAND_DISABLE) {
-+ /* PHY supports in-band capabilities, and supports
-+ * more than disable mode.
-+ */
-+ if (phy_ib_caps & LINK_INBAND_DISABLE)
-+ pl->phy_ib_mode = LINK_INBAND_DISABLE;
-+ else if (phy_ib_caps & LINK_INBAND_BYPASS)
-+ pl->phy_ib_mode = LINK_INBAND_BYPASS;
-+ else if (phy_ib_caps & LINK_INBAND_ENABLE)
-+ phy_ib_only = true;
-+ }
-+
-+ /* If either the PCS or PHY requires inband to be enabled,
-+ * this is an invalid configuration. Provide a diagnostic
-+ * message for this case, but don't try to force the issue.
-+ */
-+ if (pcs_ib_only || phy_ib_only)
-+ phylink_warn(pl,
-+ "firmware wants %s mode, but %s%s%s requires inband\n",
-+ phylink_an_mode_str(mode),
-+ pcs_ib_only ? "PCS" : "",
-+ pcs_ib_only && phy_ib_only ? " and " : "",
-+ phy_ib_only ? "PHY" : "");
-+
-+ neg_mode = PHYLINK_PCS_NEG_OUTBAND;
-+ } else if (type == INBAND_CISCO_SGMII || pl->phydev) {
-+ /* For SGMII modes which are designed to be used with PHYs, or
-+ * Base-X with a PHY, we try to use in-band mode where-ever
-+ * possible. However, there are some PHYs e.g. BCM84881 which
-+ * do not support in-band.
-+ */
-+ const unsigned int inband_ok = LINK_INBAND_ENABLE |
-+ LINK_INBAND_BYPASS;
-+ const unsigned int outband_ok = LINK_INBAND_DISABLE |
-+ LINK_INBAND_BYPASS;
-+ /* PCS PHY
-+ * D E D E
-+ * 0 0 0 0 no information inband enabled
-+ * 1 0 0 0 pcs doesn't support outband
-+ * 0 1 0 0 pcs required inband enabled
-+ * 1 1 0 0 pcs optional inband enabled
-+ * 0 0 1 0 phy doesn't support outband
-+ * 1 0 1 0 pcs+phy doesn't support outband
-+ * 0 1 1 0 pcs required, phy doesn't support, invalid
-+ * 1 1 1 0 pcs optional, phy doesn't support, outband
-+ * 0 0 0 1 phy required inband enabled
-+ * 1 0 0 1 pcs doesn't support, phy required, invalid
-+ * 0 1 0 1 pcs+phy required inband enabled
-+ * 1 1 0 1 pcs optional, phy required inband enabled
-+ * 0 0 1 1 phy optional inband enabled
-+ * 1 0 1 1 pcs doesn't support, phy optional, outband
-+ * 0 1 1 1 pcs required, phy optional inband enabled
-+ * 1 1 1 1 pcs+phy optional inband enabled
-+ */
-+ if ((!pcs_ib_caps || pcs_ib_caps & inband_ok) &&
-+ (!phy_ib_caps || phy_ib_caps & inband_ok)) {
-+ /* In-band supported or unknown at both ends. Enable
-+ * in-band mode with or without bypass at the PHY.
-+ */
-+ if (phy_ib_caps & LINK_INBAND_ENABLE)
-+ pl->phy_ib_mode = LINK_INBAND_ENABLE;
-+ else if (phy_ib_caps & LINK_INBAND_BYPASS)
-+ pl->phy_ib_mode = LINK_INBAND_BYPASS;
-+
-+ neg_mode = PHYLINK_PCS_NEG_INBAND_ENABLED;
-+ } else if ((!pcs_ib_caps || pcs_ib_caps & outband_ok) &&
-+ (!phy_ib_caps || phy_ib_caps & outband_ok)) {
-+ /* Either in-band not supported at at least one end.
-+ * In-band bypass at the other end is possible.
-+ */
-+ if (phy_ib_caps & LINK_INBAND_DISABLE)
-+ pl->phy_ib_mode = LINK_INBAND_DISABLE;
-+ else if (phy_ib_caps & LINK_INBAND_BYPASS)
-+ pl->phy_ib_mode = LINK_INBAND_BYPASS;
-+
- neg_mode = PHYLINK_PCS_NEG_OUTBAND;
-+ if (pl->phydev)
-+ mode = MLO_AN_PHY;
-+ } else {
-+ /* invalid */
-+ phylink_warn(pl, "%s: incompatible in-band capabilities, trying in-band",
-+ phy_modes(interface));
-+ neg_mode = PHYLINK_PCS_NEG_INBAND_ENABLED;
-+ }
-+ } else {
-+ /* For Base-X without a PHY */
-+ if (pcs_ib_caps == LINK_INBAND_DISABLE)
-+ /* If the PCS doesn't support inband, then inband must
-+ * be disabled.
-+ */
-+ neg_mode = PHYLINK_PCS_NEG_INBAND_DISABLED;
-+ else if (pcs_ib_caps == LINK_INBAND_ENABLE)
-+ /* If the PCS requires inband, then inband must always
-+ * be enabled.
-+ */
-+ neg_mode = PHYLINK_PCS_NEG_INBAND_ENABLED;
- else if (linkmode_test_bit(ETHTOOL_LINK_MODE_Autoneg_BIT,
- advertising))
- neg_mode = PHYLINK_PCS_NEG_INBAND_ENABLED;
- else
- neg_mode = PHYLINK_PCS_NEG_INBAND_DISABLED;
-- break;
--
-- default:
-- neg_mode = PHYLINK_PCS_NEG_NONE;
-- break;
- }
-
- pl->pcs_neg_mode = neg_mode;
-@@ -1324,6 +1451,13 @@ static void phylink_major_config(struct
- ERR_PTR(err));
- }
-
-+ if (pl->phydev && pl->phy_ib_mode) {
-+ err = phy_config_inband(pl->phydev, pl->phy_ib_mode);
-+ if (err < 0)
-+ phylink_err(pl, "phy_config_inband: %pe\n",
-+ ERR_PTR(err));
-+ }
-+
- if (pl->sfp_bus) {
- rate_kbd = phylink_interface_signal_rate(state->interface);
- if (rate_kbd)
+++ /dev/null
-From 77ac9a8b2536e0eaca6c6f21070068458bf55981 Mon Sep 17 00:00:00 2001
-Date: Tue, 3 Dec 2024 15:31:48 +0000
-Subject: [PATCH 13/13] net: phylink: remove phylink_phy_no_inband()
-
-Remove phylink_phy_no_inband() now that we are handling the lack of
-inband negotiation by querying the capabilities of the PHY and PCS,
-and the BCM84881 PHY driver provides us the information necessary to
-make the decision.
-
----
- drivers/net/phy/phylink.c | 27 ++++++---------------------
- 1 file changed, 6 insertions(+), 21 deletions(-)
-
---- a/drivers/net/phy/phylink.c
-+++ b/drivers/net/phy/phylink.c
-@@ -3320,10 +3320,11 @@ static phy_interface_t phylink_choose_sf
- return interface;
- }
-
--static void phylink_sfp_set_config(struct phylink *pl, u8 mode,
-+static void phylink_sfp_set_config(struct phylink *pl,
- unsigned long *supported,
- struct phylink_link_state *state)
- {
-+ u8 mode = MLO_AN_INBAND;
- bool changed = false;
-
- phylink_dbg(pl, "requesting link mode %s/%s with support %*pb\n",
-@@ -3357,8 +3358,7 @@ static void phylink_sfp_set_config(struc
- phylink_mac_initial_config(pl, false);
- }
-
--static int phylink_sfp_config_phy(struct phylink *pl, u8 mode,
-- struct phy_device *phy)
-+static int phylink_sfp_config_phy(struct phylink *pl, struct phy_device *phy)
- {
- __ETHTOOL_DECLARE_LINK_MODE_MASK(support1);
- __ETHTOOL_DECLARE_LINK_MODE_MASK(support);
-@@ -3398,7 +3398,7 @@ static int phylink_sfp_config_phy(struct
- if (ret) {
- phylink_err(pl,
- "validation of %s/%s with support %*pb failed: %pe\n",
-- phylink_an_mode_str(mode),
-+ phylink_an_mode_str(pl->req_link_an_mode),
- phy_modes(config.interface),
- __ETHTOOL_LINK_MODE_MASK_NBITS, support,
- ERR_PTR(ret));
-@@ -3407,7 +3407,7 @@ static int phylink_sfp_config_phy(struct
-
- pl->link_port = pl->sfp_port;
-
-- phylink_sfp_set_config(pl, mode, support, &config);
-+ phylink_sfp_set_config(pl, support, &config);
-
- return 0;
- }
-@@ -3481,7 +3481,7 @@ static int phylink_sfp_config_optical(st
-
- pl->link_port = pl->sfp_port;
-
-- phylink_sfp_set_config(pl, MLO_AN_INBAND, pl->sfp_support, &config);
-+ phylink_sfp_set_config(pl, pl->sfp_support, &config);
-
- return 0;
- }
-@@ -3552,20 +3552,10 @@ static void phylink_sfp_link_up(void *up
- phylink_enable_and_run_resolve(pl, PHYLINK_DISABLE_LINK);
- }
-
--/* The Broadcom BCM84881 in the Methode DM7052 is unable to provide a SGMII
-- * or 802.3z control word, so inband will not work.
-- */
--static bool phylink_phy_no_inband(struct phy_device *phy)
--{
-- return phy->is_c45 && phy_id_compare(phy->c45_ids.device_ids[1],
-- 0xae025150, 0xfffffff0);
--}
--
- static int phylink_sfp_connect_phy(void *upstream, struct phy_device *phy)
- {
- struct phylink *pl = upstream;
- phy_interface_t interface;
-- u8 mode;
- int ret;
-
- /*
-@@ -3577,17 +3567,12 @@ static int phylink_sfp_connect_phy(void
- */
- phy_support_asym_pause(phy);
-
-- if (phylink_phy_no_inband(phy))
-- mode = MLO_AN_PHY;
-- else
-- mode = MLO_AN_INBAND;
--
- /* Set the PHY's host supported interfaces */
- phy_interface_and(phy->host_interfaces, phylink_sfp_interfaces,
- pl->config->supported_interfaces);
-
- /* Do the initial configuration */
-- ret = phylink_sfp_config_phy(pl, mode, phy);
-+ ret = phylink_sfp_config_phy(pl, phy);
- if (ret < 0)
- return ret;
-
+++ /dev/null
-From 6561f0e547be221f411fda5eddfcc5bd8bb058a5 Mon Sep 17 00:00:00 2001
-Date: Thu, 5 Dec 2024 09:42:24 +0000
-Subject: [PATCH 1/3] net: pcs: pcs-lynx: implement pcs_inband_caps() method
-
-Report the PCS in-band capabilities to phylink for the Lynx PCS.
-
----
- drivers/net/pcs/pcs-lynx.c | 22 ++++++++++++++++++++++
- 1 file changed, 22 insertions(+)
-
---- a/drivers/net/pcs/pcs-lynx.c
-+++ b/drivers/net/pcs/pcs-lynx.c
-@@ -35,6 +35,27 @@ enum sgmii_speed {
- #define phylink_pcs_to_lynx(pl_pcs) container_of((pl_pcs), struct lynx_pcs, pcs)
- #define lynx_to_phylink_pcs(lynx) (&(lynx)->pcs)
-
-+static unsigned int lynx_pcs_inband_caps(struct phylink_pcs *pcs,
-+ phy_interface_t interface)
-+{
-+ switch (interface) {
-+ case PHY_INTERFACE_MODE_1000BASEX:
-+ case PHY_INTERFACE_MODE_SGMII:
-+ case PHY_INTERFACE_MODE_QSGMII:
-+ return LINK_INBAND_DISABLE | LINK_INBAND_ENABLE;
-+
-+ case PHY_INTERFACE_MODE_10GBASER:
-+ case PHY_INTERFACE_MODE_2500BASEX:
-+ return LINK_INBAND_DISABLE;
-+
-+ case PHY_INTERFACE_MODE_USXGMII:
-+ return LINK_INBAND_ENABLE;
-+
-+ default:
-+ return 0;
-+ }
-+}
-+
- static void lynx_pcs_get_state_usxgmii(struct mdio_device *pcs,
- struct phylink_link_state *state)
- {
-@@ -307,6 +328,7 @@ static void lynx_pcs_link_up(struct phyl
- }
-
- static const struct phylink_pcs_ops lynx_pcs_phylink_ops = {
-+ .pcs_inband_caps = lynx_pcs_inband_caps,
- .pcs_get_state = lynx_pcs_get_state,
- .pcs_config = lynx_pcs_config,
- .pcs_an_restart = lynx_pcs_an_restart,
+++ /dev/null
-From 520d29bdda86915b3caf8c72825a574bff212553 Mon Sep 17 00:00:00 2001
-Date: Thu, 5 Dec 2024 09:42:29 +0000
-Subject: [PATCH 2/3] net: pcs: pcs-mtk-lynxi: implement pcs_inband_caps()
- method
-
-Report the PCS in-band capabilities to phylink for the LynxI PCS.
-
----
- drivers/net/pcs/pcs-mtk-lynxi.c | 16 ++++++++++++++++
- 1 file changed, 16 insertions(+)
-
---- a/drivers/net/pcs/pcs-mtk-lynxi.c
-+++ b/drivers/net/pcs/pcs-mtk-lynxi.c
-@@ -88,6 +88,21 @@ static struct mtk_pcs_lynxi *pcs_to_mtk_
- return container_of(pcs, struct mtk_pcs_lynxi, pcs);
- }
-
-+static unsigned int mtk_pcs_lynxi_inband_caps(struct phylink_pcs *pcs,
-+ phy_interface_t interface)
-+{
-+ switch (interface) {
-+ case PHY_INTERFACE_MODE_1000BASEX:
-+ case PHY_INTERFACE_MODE_2500BASEX:
-+ case PHY_INTERFACE_MODE_SGMII:
-+ case PHY_INTERFACE_MODE_QSGMII:
-+ return LINK_INBAND_DISABLE | LINK_INBAND_ENABLE;
-+
-+ default:
-+ return 0;
-+ }
-+}
-+
- static void mtk_pcs_lynxi_get_state(struct phylink_pcs *pcs,
- struct phylink_link_state *state)
- {
-@@ -241,6 +256,7 @@ static void mtk_pcs_lynxi_disable(struct
- }
-
- static const struct phylink_pcs_ops mtk_pcs_lynxi_ops = {
-+ .pcs_inband_caps = mtk_pcs_lynxi_inband_caps,
- .pcs_get_state = mtk_pcs_lynxi_get_state,
- .pcs_config = mtk_pcs_lynxi_config,
- .pcs_an_restart = mtk_pcs_lynxi_restart_an,
+++ /dev/null
-From 484d0170d6c6bbb5213d037664e9a551f793bacd Mon Sep 17 00:00:00 2001
-Date: Thu, 5 Dec 2024 09:42:34 +0000
-Subject: [PATCH 3/3] net: pcs: xpcs: implement pcs_inband_caps() method
-
-Report the PCS inband capabilities to phylink for XPCS.
-
----
- drivers/net/pcs/pcs-xpcs.c | 28 ++++++++++++++++++++++++++++
- 1 file changed, 28 insertions(+)
-
---- a/drivers/net/pcs/pcs-xpcs.c
-+++ b/drivers/net/pcs/pcs-xpcs.c
-@@ -628,6 +628,33 @@ static int xpcs_validate(struct phylink_
- return 0;
- }
-
-+static unsigned int xpcs_inband_caps(struct phylink_pcs *pcs,
-+ phy_interface_t interface)
-+{
-+ struct dw_xpcs *xpcs = phylink_pcs_to_xpcs(pcs);
-+ const struct xpcs_compat *compat;
-+
-+ compat = xpcs_find_compat(xpcs->id, interface);
-+ if (!compat)
-+ return 0;
-+
-+ switch (compat->an_mode) {
-+ case DW_AN_C73:
-+ return LINK_INBAND_ENABLE;
-+
-+ case DW_AN_C37_SGMII:
-+ case DW_AN_C37_1000BASEX:
-+ return LINK_INBAND_DISABLE | LINK_INBAND_ENABLE;
-+
-+ case DW_10GBASER:
-+ case DW_2500BASEX:
-+ return LINK_INBAND_DISABLE;
-+
-+ default:
-+ return 0;
-+ }
-+}
-+
- void xpcs_get_interfaces(struct dw_xpcs *xpcs, unsigned long *interfaces)
- {
- int i, j;
-@@ -1331,6 +1358,7 @@ static const struct xpcs_id xpcs_id_list
-
- static const struct phylink_pcs_ops xpcs_phylink_ops = {
- .pcs_validate = xpcs_validate,
-+ .pcs_inband_caps = xpcs_inband_caps,
- .pcs_config = xpcs_config,
- .pcs_get_state = xpcs_get_state,
- .pcs_an_restart = xpcs_an_restart,
+++ /dev/null
-From 6c06c88fa838fcc1b7e5380facd086f57fd9d1c4 Mon Sep 17 00:00:00 2001
-Date: Sun, 4 Feb 2024 15:16:46 +0100
-Subject: [PATCH] net: mdio: add 2.5g and 5g related PMA speed constants
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Add constants indicating 2.5g and 5g ability in the MMD PMA speed
-register.
-
----
- include/uapi/linux/mdio.h | 2 ++
- 1 file changed, 2 insertions(+)
-
---- a/include/uapi/linux/mdio.h
-+++ b/include/uapi/linux/mdio.h
-@@ -138,6 +138,8 @@
- #define MDIO_PMA_SPEED_1000 0x0010 /* 1000M capable */
- #define MDIO_PMA_SPEED_100 0x0020 /* 100M capable */
- #define MDIO_PMA_SPEED_10 0x0040 /* 10M capable */
-+#define MDIO_PMA_SPEED_2_5G 0x2000 /* 2.5G capable */
-+#define MDIO_PMA_SPEED_5G 0x4000 /* 5G capable */
- #define MDIO_PCS_SPEED_10P2B 0x0002 /* 10PASS-TS/2BASE-TL capable */
- #define MDIO_PCS_SPEED_2_5G 0x0040 /* 2.5G capable */
- #define MDIO_PCS_SPEED_5G 0x0080 /* 5G capable */
+++ /dev/null
-Date: Wed, 26 Jun 2024 19:51:26 +0200
-Subject: [PATCH] udp: Allow GSO transmit from devices with no checksum offload
-
-Today sending a UDP GSO packet from a TUN device results in an EIO error:
-
- import fcntl, os, struct
- from socket import *
-
- TUNSETIFF = 0x400454CA
- IFF_TUN = 0x0001
- IFF_NO_PI = 0x1000
- UDP_SEGMENT = 103
-
- tun_fd = os.open("/dev/net/tun", os.O_RDWR)
- ifr = struct.pack("16sH", b"tun0", IFF_TUN | IFF_NO_PI)
- fcntl.ioctl(tun_fd, TUNSETIFF, ifr)
-
- os.system("ip addr add 192.0.2.1/24 dev tun0")
- os.system("ip link set dev tun0 up")
-
- s = socket(AF_INET, SOCK_DGRAM)
- s.setsockopt(SOL_UDP, UDP_SEGMENT, 1200)
- s.sendto(b"x" * 3000, ("192.0.2.2", 9)) # EIO
-
-This is due to a check in the udp stack if the egress device offers
-checksum offload. While TUN/TAP devices, by default, don't advertise this
-capability because it requires support from the TUN/TAP reader.
-
-However, the GSO stack has a software fallback for checksum calculation,
-which we can use. This way we don't force UDP_SEGMENT users to handle the
-EIO error and implement a segmentation fallback.
-
-Lift the restriction so that UDP_SEGMENT can be used with any egress
-device. We also need to adjust the UDP GSO code to match the GSO stack
-expectation about ip_summed field, as set in commit 8d63bee643f1 ("net:
-avoid skb_warn_bad_offload false positives on UFO"). Otherwise we will hit
-the bad offload check.
-
-Users should, however, expect a potential performance impact when
-batch-sending packets with UDP_SEGMENT without checksum offload on the
-egress device. In such case the packet payload is read twice: first during
-the sendmsg syscall when copying data from user memory, and then in the GSO
-stack for checksum computation. This double memory read can be less
-efficient than a regular sendmsg where the checksum is calculated during
-the initial data copy from user memory.
-
----
-
---- a/net/ipv4/udp.c
-+++ b/net/ipv4/udp.c
-@@ -942,8 +942,7 @@ static int udp_send_skb(struct sk_buff *
- kfree_skb(skb);
- return -EINVAL;
- }
-- if (skb->ip_summed != CHECKSUM_PARTIAL || is_udplite ||
-- dst_xfrm(skb_dst(skb))) {
-+ if (is_udplite || dst_xfrm(skb_dst(skb))) {
- kfree_skb(skb);
- return -EIO;
- }
---- a/net/ipv4/udp_offload.c
-+++ b/net/ipv4/udp_offload.c
-@@ -448,6 +448,14 @@ struct sk_buff *__udp_gso_segment(struct
- else
- uh->check = gso_make_checksum(seg, ~check) ? : CSUM_MANGLED_0;
-
-+ /* On the TX path, CHECKSUM_NONE and CHECKSUM_UNNECESSARY have the same
-+ * meaning. However, check for bad offloads in the GSO stack expects the
-+ * latter, if the checksum was calculated in software. To vouch for the
-+ * segment skbs we actually need to set it on the gso_skb.
-+ */
-+ if (gso_skb->ip_summed == CHECKSUM_NONE)
-+ gso_skb->ip_summed = CHECKSUM_UNNECESSARY;
-+
- /* update refcount for the packet */
- if (copy_dtor) {
- int delta = sum_truesize - gso_skb->truesize;
---- a/net/ipv6/udp.c
-+++ b/net/ipv6/udp.c
-@@ -1258,8 +1258,7 @@ static int udp_v6_send_skb(struct sk_buf
- kfree_skb(skb);
- return -EINVAL;
- }
-- if (skb->ip_summed != CHECKSUM_PARTIAL || is_udplite ||
-- dst_xfrm(skb_dst(skb))) {
-+ if (is_udplite || dst_xfrm(skb_dst(skb))) {
- kfree_skb(skb);
- return -EIO;
- }
+++ /dev/null
-Date: Thu, 8 Aug 2024 11:56:21 +0200
-Subject: [PATCH] net: Make USO depend on CSUM offload
-
-UDP segmentation offload inherently depends on checksum offload. It should
-not be possible to disable checksum offload while leaving USO enabled.
-Enforce this dependency in code.
-
-There is a single tx-udp-segmentation feature flag to indicate support for
-both IPv4/6, hence the devices wishing to support USO must offer checksum
-offload for both IP versions.
-
-Fixes: 10154dbded6d ("udp: Allow GSO transmit from devices with no checksum offload")
-Link: https://patch.msgid.link/20240808-udp-gso-egress-from-tunnel-v4-1-f5c5b4149ab9@cloudflare.com
----
-
---- a/net/core/dev.c
-+++ b/net/core/dev.c
-@@ -9808,6 +9808,15 @@ static void netdev_sync_lower_features(s
- }
- }
-
-+static bool netdev_has_ip_or_hw_csum(netdev_features_t features)
-+{
-+ netdev_features_t ip_csum_mask = NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
-+ bool ip_csum = (features & ip_csum_mask) == ip_csum_mask;
-+ bool hw_csum = features & NETIF_F_HW_CSUM;
-+
-+ return ip_csum || hw_csum;
-+}
-+
- static netdev_features_t netdev_fix_features(struct net_device *dev,
- netdev_features_t features)
- {
-@@ -9889,15 +9898,9 @@ static netdev_features_t netdev_fix_feat
- features &= ~NETIF_F_LRO;
- }
-
-- if (features & NETIF_F_HW_TLS_TX) {
-- bool ip_csum = (features & (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM)) ==
-- (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM);
-- bool hw_csum = features & NETIF_F_HW_CSUM;
--
-- if (!ip_csum && !hw_csum) {
-- netdev_dbg(dev, "Dropping TLS TX HW offload feature since no CSUM feature.\n");
-- features &= ~NETIF_F_HW_TLS_TX;
-- }
-+ if ((features & NETIF_F_HW_TLS_TX) && !netdev_has_ip_or_hw_csum(features)) {
-+ netdev_dbg(dev, "Dropping TLS TX HW offload feature since no CSUM feature.\n");
-+ features &= ~NETIF_F_HW_TLS_TX;
- }
-
- if ((features & NETIF_F_HW_TLS_RX) && !(features & NETIF_F_RXCSUM)) {
-@@ -9905,6 +9908,11 @@ static netdev_features_t netdev_fix_feat
- features &= ~NETIF_F_HW_TLS_RX;
- }
-
-+ if ((features & NETIF_F_GSO_UDP_L4) && !netdev_has_ip_or_hw_csum(features)) {
-+ netdev_dbg(dev, "Dropping USO feature since no CSUM feature.\n");
-+ features &= ~NETIF_F_GSO_UDP_L4;
-+ }
-+
- return features;
- }
-
+++ /dev/null
-Date: Thu, 8 Aug 2024 11:56:22 +0200
-Subject: [PATCH] udp: Fall back to software USO if IPv6 extension headers are
- present
-
-In commit 10154dbded6d ("udp: Allow GSO transmit from devices with no
-checksum offload") we have intentionally allowed UDP GSO packets marked
-CHECKSUM_NONE to pass to the GSO stack, so that they can be segmented and
-checksummed by a software fallback when the egress device lacks these
-features.
-
-What was not taken into consideration is that a CHECKSUM_NONE skb can be
-handed over to the GSO stack also when the egress device advertises the
-tx-udp-segmentation / NETIF_F_GSO_UDP_L4 feature.
-
-This will happen when there are IPv6 extension headers present, which we
-check for in __ip6_append_data(). Syzbot has discovered this scenario,
-producing a warning as below:
-
- ip6tnl0: caps=(0x00000006401d7869, 0x00000006401d7869)
- WARNING: CPU: 0 PID: 5112 at net/core/dev.c:3293 skb_warn_bad_offload+0x166/0x1a0 net/core/dev.c:3291
- Modules linked in:
- CPU: 0 PID: 5112 Comm: syz-executor391 Not tainted 6.10.0-rc7-syzkaller-01603-g80ab5445da62 #0
- Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 06/07/2024
- RIP: 0010:skb_warn_bad_offload+0x166/0x1a0 net/core/dev.c:3291
- [...]
- Call Trace:
- <TASK>
- __skb_gso_segment+0x3be/0x4c0 net/core/gso.c:127
- skb_gso_segment include/net/gso.h:83 [inline]
- validate_xmit_skb+0x585/0x1120 net/core/dev.c:3661
- __dev_queue_xmit+0x17a4/0x3e90 net/core/dev.c:4415
- neigh_output include/net/neighbour.h:542 [inline]
- ip6_finish_output2+0xffa/0x1680 net/ipv6/ip6_output.c:137
- ip6_finish_output+0x41e/0x810 net/ipv6/ip6_output.c:222
- ip6_send_skb+0x112/0x230 net/ipv6/ip6_output.c:1958
- udp_v6_send_skb+0xbf5/0x1870 net/ipv6/udp.c:1292
- udpv6_sendmsg+0x23b3/0x3270 net/ipv6/udp.c:1588
- sock_sendmsg_nosec net/socket.c:730 [inline]
- __sock_sendmsg+0xef/0x270 net/socket.c:745
- ____sys_sendmsg+0x525/0x7d0 net/socket.c:2585
- ___sys_sendmsg net/socket.c:2639 [inline]
- __sys_sendmmsg+0x3b2/0x740 net/socket.c:2725
- __do_sys_sendmmsg net/socket.c:2754 [inline]
- __se_sys_sendmmsg net/socket.c:2751 [inline]
- __x64_sys_sendmmsg+0xa0/0xb0 net/socket.c:2751
- do_syscall_x64 arch/x86/entry/common.c:52 [inline]
- do_syscall_64+0xf3/0x230 arch/x86/entry/common.c:83
- entry_SYSCALL_64_after_hwframe+0x77/0x7f
- [...]
- </TASK>
-
-We are hitting the bad offload warning because when an egress device is
-capable of handling segmentation offload requested by
-skb_shinfo(skb)->gso_type, the chain of gso_segment callbacks won't produce
-any segment skbs and return NULL. See the skb_gso_ok() branch in
-{__udp,tcp,sctp}_gso_segment helpers.
-
-To fix it, force a fallback to software USO when processing a packet with
-IPv6 extension headers, since we don't know if these can checksummed by
-all devices which offer USO.
-
-Fixes: 10154dbded6d ("udp: Allow GSO transmit from devices with no checksum offload")
-Link: https://patch.msgid.link/20240808-udp-gso-egress-from-tunnel-v4-2-f5c5b4149ab9@cloudflare.com
----
-
---- a/net/ipv4/udp_offload.c
-+++ b/net/ipv4/udp_offload.c
-@@ -343,6 +343,12 @@ struct sk_buff *__udp_gso_segment(struct
- !(skb_shinfo(gso_skb)->gso_type & SKB_GSO_FRAGLIST)))
- return ERR_PTR(-EINVAL);
-
-+ /* We don't know if egress device can segment and checksum the packet
-+ * when IPv6 extension headers are present. Fall back to software GSO.
-+ */
-+ if (gso_skb->ip_summed != CHECKSUM_PARTIAL)
-+ features &= ~(NETIF_F_GSO_UDP_L4 | NETIF_F_CSUM_MASK);
-+
- if (skb_gso_ok(gso_skb, features | NETIF_F_GSO_ROBUST)) {
- /* Packet is from an untrusted source, reset gso_segs. */
- skb_shinfo(gso_skb)->gso_segs = DIV_ROUND_UP(gso_skb->len - sizeof(*uh),
+++ /dev/null
-Date: Wed, 28 Feb 2024 03:31:21 -0800
-Subject: [PATCH] net: get stats64 if device if driver is configured
-
-If the network driver is relying in the net core to do stats allocation,
-then we want to dev_get_tstats64() instead of netdev_stats_to_stats64(),
-since there are per-cpu stats that needs to be taken in consideration.
-
-This will also simplify the drivers in regard to statistics. Once the
-driver sets NETDEV_PCPU_STAT_TSTATS, it doesn't not need to allocate the
-stacks, neither it needs to set `.ndo_get_stats64 = dev_get_tstats64`
-for the generic stats collection function anymore.
-
----
-
---- a/net/core/dev.c
-+++ b/net/core/dev.c
-@@ -10715,6 +10715,8 @@ struct rtnl_link_stats64 *dev_get_stats(
- ops->ndo_get_stats64(dev, storage);
- } else if (ops->ndo_get_stats) {
- netdev_stats_to_stats64(storage, ops->ndo_get_stats(dev));
-+ } else if (dev->pcpu_stat_type == NETDEV_PCPU_STAT_TSTATS) {
-+ dev_get_tstats64(dev, storage);
- } else {
- netdev_stats_to_stats64(storage, &dev->stats);
- }
+++ /dev/null
-Date: Fri, 13 Oct 2023 14:48:21 +0800
-Subject: [PATCH] page_pool: fragment API support for 32-bit arch with 64-bit
- DMA
-
-Currently page_pool_alloc_frag() is not supported in 32-bit
-arch with 64-bit DMA because of the overlap issue between
-pp_frag_count and dma_addr_upper in 'struct page' for those
-arches, which seems to be quite common, see [1], which means
-driver may need to handle it when using fragment API.
-
-It is assumed that the combination of the above arch with an
-address space >16TB does not exist, as all those arches have
-64b equivalent, it seems logical to use the 64b version for a
-system with a large address space. It is also assumed that dma
-address is page aligned when we are dma mapping a page aligned
-buffer, see [2].
-
-That means we're storing 12 bits of 0 at the lower end for a
-dma address, we can reuse those bits for the above arches to
-support 32b+12b, which is 16TB of memory.
-
-If we make a wrong assumption, a warning is emitted so that
-user can report to us.
-
-
----
-
---- a/include/linux/mm_types.h
-+++ b/include/linux/mm_types.h
-@@ -125,18 +125,7 @@ struct page {
- struct page_pool *pp;
- unsigned long _pp_mapping_pad;
- unsigned long dma_addr;
-- union {
-- /**
-- * dma_addr_upper: might require a 64-bit
-- * value on 32-bit architectures.
-- */
-- unsigned long dma_addr_upper;
-- /**
-- * For frag page support, not supported in
-- * 32-bit architectures with 64-bit DMA.
-- */
-- atomic_long_t pp_frag_count;
-- };
-+ atomic_long_t pp_frag_count;
- };
- struct { /* Tail pages of compound page */
- unsigned long compound_head; /* Bit zero is set */
---- a/include/net/page_pool/helpers.h
-+++ b/include/net/page_pool/helpers.h
-@@ -197,7 +197,7 @@ static inline void page_pool_recycle_dir
- page_pool_put_full_page(pool, page, true);
- }
-
--#define PAGE_POOL_DMA_USE_PP_FRAG_COUNT \
-+#define PAGE_POOL_32BIT_ARCH_WITH_64BIT_DMA \
- (sizeof(dma_addr_t) > sizeof(unsigned long))
-
- /**
-@@ -211,17 +211,25 @@ static inline dma_addr_t page_pool_get_d
- {
- dma_addr_t ret = page->dma_addr;
-
-- if (PAGE_POOL_DMA_USE_PP_FRAG_COUNT)
-- ret |= (dma_addr_t)page->dma_addr_upper << 16 << 16;
-+ if (PAGE_POOL_32BIT_ARCH_WITH_64BIT_DMA)
-+ ret <<= PAGE_SHIFT;
-
- return ret;
- }
-
--static inline void page_pool_set_dma_addr(struct page *page, dma_addr_t addr)
-+static inline bool page_pool_set_dma_addr(struct page *page, dma_addr_t addr)
- {
-+ if (PAGE_POOL_32BIT_ARCH_WITH_64BIT_DMA) {
-+ page->dma_addr = addr >> PAGE_SHIFT;
-+
-+ /* We assume page alignment to shave off bottom bits,
-+ * if this "compression" doesn't work we need to drop.
-+ */
-+ return addr != (dma_addr_t)page->dma_addr << PAGE_SHIFT;
-+ }
-+
- page->dma_addr = addr;
-- if (PAGE_POOL_DMA_USE_PP_FRAG_COUNT)
-- page->dma_addr_upper = upper_32_bits(addr);
-+ return false;
- }
-
- static inline bool page_pool_put(struct page_pool *pool)
---- a/net/core/page_pool.c
-+++ b/net/core/page_pool.c
-@@ -207,10 +207,6 @@ static int page_pool_init(struct page_po
- */
- }
-
-- if (PAGE_POOL_DMA_USE_PP_FRAG_COUNT &&
-- pool->p.flags & PP_FLAG_PAGE_FRAG)
-- return -EINVAL;
--
- #ifdef CONFIG_PAGE_POOL_STATS
- pool->recycle_stats = alloc_percpu(struct page_pool_recycle_stats);
- if (!pool->recycle_stats)
-@@ -359,12 +355,20 @@ static bool page_pool_dma_map(struct pag
- if (dma_mapping_error(pool->p.dev, dma))
- return false;
-
-- page_pool_set_dma_addr(page, dma);
-+ if (page_pool_set_dma_addr(page, dma))
-+ goto unmap_failed;
-
- if (pool->p.flags & PP_FLAG_DMA_SYNC_DEV)
- page_pool_dma_sync_for_device(pool, page, pool->p.max_len);
-
- return true;
-+
-+unmap_failed:
-+ WARN_ON_ONCE("unexpected DMA address, please report to netdev@");
-+ dma_unmap_page_attrs(pool->p.dev, dma,
-+ PAGE_SIZE << pool->p.order, pool->p.dma_dir,
-+ DMA_ATTR_SKIP_CPU_SYNC | DMA_ATTR_WEAK_ORDERING);
-+ return false;
- }
-
- static void page_pool_set_pp_info(struct page_pool *pool,
+++ /dev/null
-Date: Fri, 20 Oct 2023 17:59:48 +0800
-Subject: [PATCH] page_pool: unify frag_count handling in
- page_pool_is_last_frag()
-
-Currently when page_pool_create() is called with
-PP_FLAG_PAGE_FRAG flag, page_pool_alloc_pages() is only
-allowed to be called under the below constraints:
-1. page_pool_fragment_page() need to be called to setup
- page->pp_frag_count immediately.
-2. page_pool_defrag_page() often need to be called to drain
- the page->pp_frag_count when there is no more user will
- be holding on to that page.
-
-Those constraints exist in order to support a page to be
-split into multi fragments.
-
-And those constraints have some overhead because of the
-cache line dirtying/bouncing and atomic update.
-
-Those constraints are unavoidable for case when we need a
-page to be split into more than one fragment, but there is
-also case that we want to avoid the above constraints and
-their overhead when a page can't be split as it can only
-hold a fragment as requested by user, depending on different
-use cases:
-use case 1: allocate page without page splitting.
-use case 2: allocate page with page splitting.
-use case 3: allocate page with or without page splitting
- depending on the fragment size.
-
-Currently page pool only provide page_pool_alloc_pages() and
-page_pool_alloc_frag() API to enable the 1 & 2 separately,
-so we can not use a combination of 1 & 2 to enable 3, it is
-not possible yet because of the per page_pool flag
-PP_FLAG_PAGE_FRAG.
-
-So in order to allow allocating unsplit page without the
-overhead of split page while still allow allocating split
-page we need to remove the per page_pool flag in
-page_pool_is_last_frag(), as best as I can think of, it seems
-there are two methods as below:
-1. Add per page flag/bit to indicate a page is split or
- not, which means we might need to update that flag/bit
- everytime the page is recycled, dirtying the cache line
- of 'struct page' for use case 1.
-2. Unify the page->pp_frag_count handling for both split and
- unsplit page by assuming all pages in the page pool is split
- into a big fragment initially.
-
-As page pool already supports use case 1 without dirtying the
-cache line of 'struct page' whenever a page is recyclable, we
-need to support the above use case 3 with minimal overhead,
-especially not adding any noticeable overhead for use case 1,
-and we are already doing an optimization by not updating
-pp_frag_count in page_pool_defrag_page() for the last fragment
-user, this patch chooses to unify the pp_frag_count handling
-to support the above use case 3.
-
-There is no noticeable performance degradation and some
-justification for unifying the frag_count handling with this
-patch applied using a micro-benchmark testing in [1].
-
-
----
-
---- a/include/net/page_pool/helpers.h
-+++ b/include/net/page_pool/helpers.h
-@@ -115,28 +115,49 @@ static inline long page_pool_defrag_page
- long ret;
-
- /* If nr == pp_frag_count then we have cleared all remaining
-- * references to the page. No need to actually overwrite it, instead
-- * we can leave this to be overwritten by the calling function.
-+ * references to the page:
-+ * 1. 'n == 1': no need to actually overwrite it.
-+ * 2. 'n != 1': overwrite it with one, which is the rare case
-+ * for pp_frag_count draining.
- *
-- * The main advantage to doing this is that an atomic_read is
-- * generally a much cheaper operation than an atomic update,
-- * especially when dealing with a page that may be partitioned
-- * into only 2 or 3 pieces.
-+ * The main advantage to doing this is that not only we avoid a atomic
-+ * update, as an atomic_read is generally a much cheaper operation than
-+ * an atomic update, especially when dealing with a page that may be
-+ * partitioned into only 2 or 3 pieces; but also unify the pp_frag_count
-+ * handling by ensuring all pages have partitioned into only 1 piece
-+ * initially, and only overwrite it when the page is partitioned into
-+ * more than one piece.
- */
-- if (atomic_long_read(&page->pp_frag_count) == nr)
-+ if (atomic_long_read(&page->pp_frag_count) == nr) {
-+ /* As we have ensured nr is always one for constant case using
-+ * the BUILD_BUG_ON(), only need to handle the non-constant case
-+ * here for pp_frag_count draining, which is a rare case.
-+ */
-+ BUILD_BUG_ON(__builtin_constant_p(nr) && nr != 1);
-+ if (!__builtin_constant_p(nr))
-+ atomic_long_set(&page->pp_frag_count, 1);
-+
- return 0;
-+ }
-
- ret = atomic_long_sub_return(nr, &page->pp_frag_count);
- WARN_ON(ret < 0);
-+
-+ /* We are the last user here too, reset pp_frag_count back to 1 to
-+ * ensure all pages have been partitioned into 1 piece initially,
-+ * this should be the rare case when the last two fragment users call
-+ * page_pool_defrag_page() currently.
-+ */
-+ if (unlikely(!ret))
-+ atomic_long_set(&page->pp_frag_count, 1);
-+
- return ret;
- }
-
--static inline bool page_pool_is_last_frag(struct page_pool *pool,
-- struct page *page)
-+static inline bool page_pool_is_last_frag(struct page *page)
- {
-- /* If fragments aren't enabled or count is 0 we were the last user */
-- return !(pool->p.flags & PP_FLAG_PAGE_FRAG) ||
-- (page_pool_defrag_page(page, 1) == 0);
-+ /* If page_pool_defrag_page() returns 0, we were the last user */
-+ return page_pool_defrag_page(page, 1) == 0;
- }
-
- /**
-@@ -161,7 +182,7 @@ static inline void page_pool_put_page(st
- * allow registering MEM_TYPE_PAGE_POOL, but shield linker.
- */
- #ifdef CONFIG_PAGE_POOL
-- if (!page_pool_is_last_frag(pool, page))
-+ if (!page_pool_is_last_frag(page))
- return;
-
- page_pool_put_defragged_page(pool, page, dma_sync_size, allow_direct);
---- a/net/core/page_pool.c
-+++ b/net/core/page_pool.c
-@@ -376,6 +376,14 @@ static void page_pool_set_pp_info(struct
- {
- page->pp = pool;
- page->pp_magic |= PP_SIGNATURE;
-+
-+ /* Ensuring all pages have been split into one fragment initially:
-+ * page_pool_set_pp_info() is only called once for every page when it
-+ * is allocated from the page allocator and page_pool_fragment_page()
-+ * is dirtying the same cache line as the page->pp_magic above, so
-+ * the overhead is negligible.
-+ */
-+ page_pool_fragment_page(page, 1);
- if (pool->p.init_callback)
- pool->p.init_callback(page, pool->p.init_arg);
- }
-@@ -678,7 +686,7 @@ void page_pool_put_page_bulk(struct page
- struct page *page = virt_to_head_page(data[i]);
-
- /* It is not the last user for the page frag case */
-- if (!page_pool_is_last_frag(pool, page))
-+ if (!page_pool_is_last_frag(page))
- continue;
-
- page = __page_pool_put_page(pool, page, -1, false);
-@@ -754,8 +762,7 @@ struct page *page_pool_alloc_frag(struct
- unsigned int max_size = PAGE_SIZE << pool->p.order;
- struct page *page = pool->frag_page;
-
-- if (WARN_ON(!(pool->p.flags & PP_FLAG_PAGE_FRAG) ||
-- size > max_size))
-+ if (WARN_ON(size > max_size))
- return NULL;
-
- size = ALIGN(size, dma_get_cache_alignment());
+++ /dev/null
-From 8928756d53d5b99dcd18073dc7738b8ebdbe7d96 Mon Sep 17 00:00:00 2001
-Date: Thu, 2 May 2024 10:44:42 +0200
-Subject: [PATCH 1/6] net: move skb_gro_receive_list from udp to core
-
-This helper function will be used for TCP fraglist GRO support
-
----
- include/net/gro.h | 1 +
- net/core/gro.c | 27 +++++++++++++++++++++++++++
- net/ipv4/udp_offload.c | 27 ---------------------------
- 3 files changed, 28 insertions(+), 27 deletions(-)
-
---- a/include/net/gro.h
-+++ b/include/net/gro.h
-@@ -442,6 +442,7 @@ static inline __wsum ip6_gro_compute_pse
- }
-
- int skb_gro_receive(struct sk_buff *p, struct sk_buff *skb);
-+int skb_gro_receive_list(struct sk_buff *p, struct sk_buff *skb);
-
- /* Pass the currently batched GRO_NORMAL SKBs up to the stack. */
- static inline void gro_normal_list(struct napi_struct *napi)
---- a/net/core/gro.c
-+++ b/net/core/gro.c
-@@ -225,6 +225,33 @@ done:
- return 0;
- }
-
-+int skb_gro_receive_list(struct sk_buff *p, struct sk_buff *skb)
-+{
-+ if (unlikely(p->len + skb->len >= 65536))
-+ return -E2BIG;
-+
-+ if (NAPI_GRO_CB(p)->last == p)
-+ skb_shinfo(p)->frag_list = skb;
-+ else
-+ NAPI_GRO_CB(p)->last->next = skb;
-+
-+ skb_pull(skb, skb_gro_offset(skb));
-+
-+ NAPI_GRO_CB(p)->last = skb;
-+ NAPI_GRO_CB(p)->count++;
-+ p->data_len += skb->len;
-+
-+ /* sk ownership - if any - completely transferred to the aggregated packet */
-+ skb->destructor = NULL;
-+ skb->sk = NULL;
-+ p->truesize += skb->truesize;
-+ p->len += skb->len;
-+
-+ NAPI_GRO_CB(skb)->same_flow = 1;
-+
-+ return 0;
-+}
-+
-
- static void napi_gro_complete(struct napi_struct *napi, struct sk_buff *skb)
- {
---- a/net/ipv4/udp_offload.c
-+++ b/net/ipv4/udp_offload.c
-@@ -538,33 +538,6 @@ out:
- return segs;
- }
-
--static int skb_gro_receive_list(struct sk_buff *p, struct sk_buff *skb)
--{
-- if (unlikely(p->len + skb->len >= 65536))
-- return -E2BIG;
--
-- if (NAPI_GRO_CB(p)->last == p)
-- skb_shinfo(p)->frag_list = skb;
-- else
-- NAPI_GRO_CB(p)->last->next = skb;
--
-- skb_pull(skb, skb_gro_offset(skb));
--
-- NAPI_GRO_CB(p)->last = skb;
-- NAPI_GRO_CB(p)->count++;
-- p->data_len += skb->len;
--
-- /* sk ownership - if any - completely transferred to the aggregated packet */
-- skb->destructor = NULL;
-- skb->sk = NULL;
-- p->truesize += skb->truesize;
-- p->len += skb->len;
--
-- NAPI_GRO_CB(skb)->same_flow = 1;
--
-- return 0;
--}
--
-
- #define UDP_GRO_CNT_MAX 64
- static struct sk_buff *udp_gro_receive_segment(struct list_head *head,
+++ /dev/null
-From bee88cd5bd83d40b8aec4d6cb729378f707f6197 Mon Sep 17 00:00:00 2001
-Date: Thu, 2 May 2024 10:44:43 +0200
-Subject: [PATCH 2/6] net: add support for segmenting TCP fraglist GSO packets
-
-Preparation for adding TCP fraglist GRO support. It expects packets to be
-combined in a similar way as UDP fraglist GSO packets.
-For IPv4 packets, NAT is handled in the same way as UDP fraglist GSO.
-
----
- net/ipv4/tcp_offload.c | 67 ++++++++++++++++++++++++++++++++++++++++
- net/ipv6/tcpv6_offload.c | 58 ++++++++++++++++++++++++++++++++++
- 2 files changed, 125 insertions(+)
-
---- a/net/ipv4/tcp_offload.c
-+++ b/net/ipv4/tcp_offload.c
-@@ -31,6 +31,70 @@ static void tcp_gso_tstamp(struct sk_buf
- }
- }
-
-+static void __tcpv4_gso_segment_csum(struct sk_buff *seg,
-+ __be32 *oldip, __be32 newip,
-+ __be16 *oldport, __be16 newport)
-+{
-+ struct tcphdr *th;
-+ struct iphdr *iph;
-+
-+ if (*oldip == newip && *oldport == newport)
-+ return;
-+
-+ th = tcp_hdr(seg);
-+ iph = ip_hdr(seg);
-+
-+ inet_proto_csum_replace4(&th->check, seg, *oldip, newip, true);
-+ inet_proto_csum_replace2(&th->check, seg, *oldport, newport, false);
-+ *oldport = newport;
-+
-+ csum_replace4(&iph->check, *oldip, newip);
-+ *oldip = newip;
-+}
-+
-+static struct sk_buff *__tcpv4_gso_segment_list_csum(struct sk_buff *segs)
-+{
-+ const struct tcphdr *th;
-+ const struct iphdr *iph;
-+ struct sk_buff *seg;
-+ struct tcphdr *th2;
-+ struct iphdr *iph2;
-+
-+ seg = segs;
-+ th = tcp_hdr(seg);
-+ iph = ip_hdr(seg);
-+ th2 = tcp_hdr(seg->next);
-+ iph2 = ip_hdr(seg->next);
-+
-+ if (!(*(const u32 *)&th->source ^ *(const u32 *)&th2->source) &&
-+ iph->daddr == iph2->daddr && iph->saddr == iph2->saddr)
-+ return segs;
-+
-+ while ((seg = seg->next)) {
-+ th2 = tcp_hdr(seg);
-+ iph2 = ip_hdr(seg);
-+
-+ __tcpv4_gso_segment_csum(seg,
-+ &iph2->saddr, iph->saddr,
-+ &th2->source, th->source);
-+ __tcpv4_gso_segment_csum(seg,
-+ &iph2->daddr, iph->daddr,
-+ &th2->dest, th->dest);
-+ }
-+
-+ return segs;
-+}
-+
-+static struct sk_buff *__tcp4_gso_segment_list(struct sk_buff *skb,
-+ netdev_features_t features)
-+{
-+ skb = skb_segment_list(skb, features, skb_mac_header_len(skb));
-+ if (IS_ERR(skb))
-+ return skb;
-+
-+ return __tcpv4_gso_segment_list_csum(skb);
-+}
-+
- static struct sk_buff *tcp4_gso_segment(struct sk_buff *skb,
- netdev_features_t features)
- {
-@@ -40,6 +104,9 @@ static struct sk_buff *tcp4_gso_segment(
- if (!pskb_may_pull(skb, sizeof(struct tcphdr)))
- return ERR_PTR(-EINVAL);
-
-+ if (skb_shinfo(skb)->gso_type & SKB_GSO_FRAGLIST)
-+ return __tcp4_gso_segment_list(skb, features);
-+
- if (unlikely(skb->ip_summed != CHECKSUM_PARTIAL)) {
- const struct iphdr *iph = ip_hdr(skb);
- struct tcphdr *th = tcp_hdr(skb);
---- a/net/ipv6/tcpv6_offload.c
-+++ b/net/ipv6/tcpv6_offload.c
-@@ -40,6 +40,61 @@ INDIRECT_CALLABLE_SCOPE int tcp6_gro_com
- return 0;
- }
-
-+static void __tcpv6_gso_segment_csum(struct sk_buff *seg,
-+ __be16 *oldport, __be16 newport)
-+{
-+ struct tcphdr *th;
-+
-+ if (*oldport == newport)
-+ return;
-+
-+ th = tcp_hdr(seg);
-+ inet_proto_csum_replace2(&th->check, seg, *oldport, newport, false);
-+ *oldport = newport;
-+}
-+
-+static struct sk_buff *__tcpv6_gso_segment_list_csum(struct sk_buff *segs)
-+{
-+ const struct tcphdr *th;
-+ const struct ipv6hdr *iph;
-+ struct sk_buff *seg;
-+ struct tcphdr *th2;
-+ struct ipv6hdr *iph2;
-+
-+ seg = segs;
-+ th = tcp_hdr(seg);
-+ iph = ipv6_hdr(seg);
-+ th2 = tcp_hdr(seg->next);
-+ iph2 = ipv6_hdr(seg->next);
-+
-+ if (!(*(const u32 *)&th->source ^ *(const u32 *)&th2->source) &&
-+ ipv6_addr_equal(&iph->saddr, &iph2->saddr) &&
-+ ipv6_addr_equal(&iph->daddr, &iph2->daddr))
-+ return segs;
-+
-+ while ((seg = seg->next)) {
-+ th2 = tcp_hdr(seg);
-+ iph2 = ipv6_hdr(seg);
-+
-+ iph2->saddr = iph->saddr;
-+ iph2->daddr = iph->daddr;
-+ __tcpv6_gso_segment_csum(seg, &th2->source, th->source);
-+ __tcpv6_gso_segment_csum(seg, &th2->dest, th->dest);
-+ }
-+
-+ return segs;
-+}
-+
-+static struct sk_buff *__tcp6_gso_segment_list(struct sk_buff *skb,
-+ netdev_features_t features)
-+{
-+ skb = skb_segment_list(skb, features, skb_mac_header_len(skb));
-+ if (IS_ERR(skb))
-+ return skb;
-+
-+ return __tcpv6_gso_segment_list_csum(skb);
-+}
-+
- static struct sk_buff *tcp6_gso_segment(struct sk_buff *skb,
- netdev_features_t features)
- {
-@@ -51,6 +106,9 @@ static struct sk_buff *tcp6_gso_segment(
- if (!pskb_may_pull(skb, sizeof(*th)))
- return ERR_PTR(-EINVAL);
-
-+ if (skb_shinfo(skb)->gso_type & SKB_GSO_FRAGLIST)
-+ return __tcp6_gso_segment_list(skb, features);
-+
- if (unlikely(skb->ip_summed != CHECKSUM_PARTIAL)) {
- const struct ipv6hdr *ipv6h = ipv6_hdr(skb);
- struct tcphdr *th = tcp_hdr(skb);
+++ /dev/null
-From 8d95dc474f85481652a0e422d2f1f079de81f63c Mon Sep 17 00:00:00 2001
-Date: Thu, 2 May 2024 10:44:44 +0200
-Subject: [PATCH 3/6] net: add code for TCP fraglist GRO
-
-This implements fraglist GRO similar to how it's handled in UDP, however
-no functional changes are added yet. The next change adds a heuristic for
-using fraglist GRO instead of regular GRO.
-
----
- net/ipv4/tcp_offload.c | 21 +++++++++++++++++++++
- net/ipv6/tcpv6_offload.c | 9 +++++++++
- 2 files changed, 30 insertions(+)
-
---- a/net/ipv4/tcp_offload.c
-+++ b/net/ipv4/tcp_offload.c
-@@ -342,6 +342,18 @@ found:
- flush |= p->decrypted ^ skb->decrypted;
- #endif
-
-+ if (unlikely(NAPI_GRO_CB(p)->is_flist)) {
-+ flush |= (__force int)(flags ^ tcp_flag_word(th2));
-+ flush |= skb->ip_summed != p->ip_summed;
-+ flush |= skb->csum_level != p->csum_level;
-+ flush |= NAPI_GRO_CB(p)->count >= 64;
-+
-+ if (flush || skb_gro_receive_list(p, skb))
-+ mss = 1;
-+
-+ goto out_check_final;
-+ }
-+
- if (flush || skb_gro_receive(p, skb)) {
- mss = 1;
- goto out_check_final;
-@@ -406,6 +418,15 @@ INDIRECT_CALLABLE_SCOPE int tcp4_gro_com
- const struct iphdr *iph = ip_hdr(skb);
- struct tcphdr *th = tcp_hdr(skb);
-
-+ if (unlikely(NAPI_GRO_CB(skb)->is_flist)) {
-+ skb_shinfo(skb)->gso_type |= SKB_GSO_FRAGLIST | SKB_GSO_TCPV4;
-+ skb_shinfo(skb)->gso_segs = NAPI_GRO_CB(skb)->count;
-+
-+ __skb_incr_checksum_unnecessary(skb);
-+
-+ return 0;
-+ }
-+
- th->check = ~tcp_v4_check(skb->len - thoff, iph->saddr,
- iph->daddr, 0);
- skb_shinfo(skb)->gso_type |= SKB_GSO_TCPV4;
---- a/net/ipv6/tcpv6_offload.c
-+++ b/net/ipv6/tcpv6_offload.c
-@@ -32,6 +32,15 @@ INDIRECT_CALLABLE_SCOPE int tcp6_gro_com
- const struct ipv6hdr *iph = ipv6_hdr(skb);
- struct tcphdr *th = tcp_hdr(skb);
-
-+ if (unlikely(NAPI_GRO_CB(skb)->is_flist)) {
-+ skb_shinfo(skb)->gso_type |= SKB_GSO_FRAGLIST | SKB_GSO_TCPV6;
-+ skb_shinfo(skb)->gso_segs = NAPI_GRO_CB(skb)->count;
-+
-+ __skb_incr_checksum_unnecessary(skb);
-+
-+ return 0;
-+ }
-+
- th->check = ~tcp_v6_check(skb->len - thoff, &iph->saddr,
- &iph->daddr, 0);
- skb_shinfo(skb)->gso_type |= SKB_GSO_TCPV6;
+++ /dev/null
-From 80e85fbdf19ecc4dfa31ecf639adb55555db02fe Mon Sep 17 00:00:00 2001
-Date: Thu, 2 May 2024 10:44:45 +0200
-Subject: [PATCH 4/6] net: create tcp_gro_lookup helper function
-
-This pulls the flow port matching out of tcp_gro_receive, so that it can be
-reused for the next change, which adds the TCP fraglist GRO heuristic.
-
----
- include/net/tcp.h | 1 +
- net/ipv4/tcp_offload.c | 41 +++++++++++++++++++++++++----------------
- 2 files changed, 26 insertions(+), 16 deletions(-)
-
---- a/include/net/tcp.h
-+++ b/include/net/tcp.h
-@@ -2101,6 +2101,7 @@ void tcp_v4_destroy_sock(struct sock *sk
-
- struct sk_buff *tcp_gso_segment(struct sk_buff *skb,
- netdev_features_t features);
-+struct sk_buff *tcp_gro_lookup(struct list_head *head, struct tcphdr *th);
- struct sk_buff *tcp_gro_receive(struct list_head *head, struct sk_buff *skb);
- INDIRECT_CALLABLE_DECLARE(int tcp4_gro_complete(struct sk_buff *skb, int thoff));
- INDIRECT_CALLABLE_DECLARE(struct sk_buff *tcp4_gro_receive(struct list_head *head, struct sk_buff *skb));
---- a/net/ipv4/tcp_offload.c
-+++ b/net/ipv4/tcp_offload.c
-@@ -251,6 +251,27 @@ out:
- return segs;
- }
-
-+struct sk_buff *tcp_gro_lookup(struct list_head *head, struct tcphdr *th)
-+{
-+ struct tcphdr *th2;
-+ struct sk_buff *p;
-+
-+ list_for_each_entry(p, head, list) {
-+ if (!NAPI_GRO_CB(p)->same_flow)
-+ continue;
-+
-+ th2 = tcp_hdr(p);
-+ if (*(u32 *)&th->source ^ *(u32 *)&th2->source) {
-+ NAPI_GRO_CB(p)->same_flow = 0;
-+ continue;
-+ }
-+
-+ return p;
-+ }
-+
-+ return NULL;
-+}
-+
- struct sk_buff *tcp_gro_receive(struct list_head *head, struct sk_buff *skb)
- {
- struct sk_buff *pp = NULL;
-@@ -288,24 +309,12 @@ struct sk_buff *tcp_gro_receive(struct l
- len = skb_gro_len(skb);
- flags = tcp_flag_word(th);
-
-- list_for_each_entry(p, head, list) {
-- if (!NAPI_GRO_CB(p)->same_flow)
-- continue;
--
-- th2 = tcp_hdr(p);
--
-- if (*(u32 *)&th->source ^ *(u32 *)&th2->source) {
-- NAPI_GRO_CB(p)->same_flow = 0;
-- continue;
-- }
--
-- goto found;
-- }
-- p = NULL;
-- goto out_check_final;
-+ p = tcp_gro_lookup(head, th);
-+ if (!p)
-+ goto out_check_final;
-
--found:
- /* Include the IP ID check below from the inner most IP hdr */
-+ th2 = tcp_hdr(p);
- flush = NAPI_GRO_CB(p)->flush;
- flush |= (__force int)(flags & TCP_FLAG_CWR);
- flush |= (__force int)((flags ^ tcp_flag_word(th2)) &
+++ /dev/null
-From 7516b27c555c1711ec17a5d891befb6986e573a3 Mon Sep 17 00:00:00 2001
-Date: Thu, 2 May 2024 10:44:46 +0200
-Subject: [PATCH 5/6] net: create tcp_gro_header_pull helper function
-
-Pull the code out of tcp_gro_receive in order to access the tcp header
-from tcp4/6_gro_receive.
-
----
- include/net/tcp.h | 4 ++-
- net/ipv4/tcp_offload.c | 55 +++++++++++++++++++++++++---------------
- net/ipv6/tcpv6_offload.c | 18 +++++++++----
- 3 files changed, 50 insertions(+), 27 deletions(-)
-
---- a/include/net/tcp.h
-+++ b/include/net/tcp.h
-@@ -2101,8 +2101,10 @@ void tcp_v4_destroy_sock(struct sock *sk
-
- struct sk_buff *tcp_gso_segment(struct sk_buff *skb,
- netdev_features_t features);
-+struct tcphdr *tcp_gro_pull_header(struct sk_buff *skb);
- struct sk_buff *tcp_gro_lookup(struct list_head *head, struct tcphdr *th);
--struct sk_buff *tcp_gro_receive(struct list_head *head, struct sk_buff *skb);
-+struct sk_buff *tcp_gro_receive(struct list_head *head, struct sk_buff *skb,
-+ struct tcphdr *th);
- INDIRECT_CALLABLE_DECLARE(int tcp4_gro_complete(struct sk_buff *skb, int thoff));
- INDIRECT_CALLABLE_DECLARE(struct sk_buff *tcp4_gro_receive(struct list_head *head, struct sk_buff *skb));
- INDIRECT_CALLABLE_DECLARE(int tcp6_gro_complete(struct sk_buff *skb, int thoff));
---- a/net/ipv4/tcp_offload.c
-+++ b/net/ipv4/tcp_offload.c
-@@ -272,40 +272,46 @@ struct sk_buff *tcp_gro_lookup(struct li
- return NULL;
- }
-
--struct sk_buff *tcp_gro_receive(struct list_head *head, struct sk_buff *skb)
-+struct tcphdr *tcp_gro_pull_header(struct sk_buff *skb)
- {
-- struct sk_buff *pp = NULL;
-- struct sk_buff *p;
-+ unsigned int thlen, hlen, off;
- struct tcphdr *th;
-- struct tcphdr *th2;
-- unsigned int len;
-- unsigned int thlen;
-- __be32 flags;
-- unsigned int mss = 1;
-- unsigned int hlen;
-- unsigned int off;
-- int flush = 1;
-- int i;
-
- off = skb_gro_offset(skb);
- hlen = off + sizeof(*th);
- th = skb_gro_header(skb, hlen, off);
- if (unlikely(!th))
-- goto out;
-+ return NULL;
-
- thlen = th->doff * 4;
- if (thlen < sizeof(*th))
-- goto out;
-+ return NULL;
-
- hlen = off + thlen;
- if (skb_gro_header_hard(skb, hlen)) {
- th = skb_gro_header_slow(skb, hlen, off);
- if (unlikely(!th))
-- goto out;
-+ return NULL;
- }
-
- skb_gro_pull(skb, thlen);
-
-+ return th;
-+}
-+
-+struct sk_buff *tcp_gro_receive(struct list_head *head, struct sk_buff *skb,
-+ struct tcphdr *th)
-+{
-+ unsigned int thlen = th->doff * 4;
-+ struct sk_buff *pp = NULL;
-+ struct sk_buff *p;
-+ struct tcphdr *th2;
-+ unsigned int len;
-+ __be32 flags;
-+ unsigned int mss = 1;
-+ int flush = 1;
-+ int i;
-+
- len = skb_gro_len(skb);
- flags = tcp_flag_word(th);
-
-@@ -384,7 +390,6 @@ out_check_final:
- if (p && (!NAPI_GRO_CB(skb)->same_flow || flush))
- pp = p;
-
--out:
- NAPI_GRO_CB(skb)->flush |= (flush != 0);
-
- return pp;
-@@ -411,15 +416,23 @@ EXPORT_SYMBOL(tcp_gro_complete);
- INDIRECT_CALLABLE_SCOPE
- struct sk_buff *tcp4_gro_receive(struct list_head *head, struct sk_buff *skb)
- {
-+ struct tcphdr *th;
-+
- /* Don't bother verifying checksum if we're going to flush anyway. */
- if (!NAPI_GRO_CB(skb)->flush &&
- skb_gro_checksum_validate(skb, IPPROTO_TCP,
-- inet_gro_compute_pseudo)) {
-- NAPI_GRO_CB(skb)->flush = 1;
-- return NULL;
-- }
-+ inet_gro_compute_pseudo))
-+ goto flush;
-
-- return tcp_gro_receive(head, skb);
-+ th = tcp_gro_pull_header(skb);
-+ if (!th)
-+ goto flush;
-+
-+ return tcp_gro_receive(head, skb, th);
-+
-+flush:
-+ NAPI_GRO_CB(skb)->flush = 1;
-+ return NULL;
- }
-
- INDIRECT_CALLABLE_SCOPE int tcp4_gro_complete(struct sk_buff *skb, int thoff)
---- a/net/ipv6/tcpv6_offload.c
-+++ b/net/ipv6/tcpv6_offload.c
-@@ -16,15 +16,23 @@
- INDIRECT_CALLABLE_SCOPE
- struct sk_buff *tcp6_gro_receive(struct list_head *head, struct sk_buff *skb)
- {
-+ struct tcphdr *th;
-+
- /* Don't bother verifying checksum if we're going to flush anyway. */
- if (!NAPI_GRO_CB(skb)->flush &&
- skb_gro_checksum_validate(skb, IPPROTO_TCP,
-- ip6_gro_compute_pseudo)) {
-- NAPI_GRO_CB(skb)->flush = 1;
-- return NULL;
-- }
-+ ip6_gro_compute_pseudo))
-+ goto flush;
-+
-+ th = tcp_gro_pull_header(skb);
-+ if (!th)
-+ goto flush;
-+
-+ return tcp_gro_receive(head, skb, th);
-
-- return tcp_gro_receive(head, skb);
-+flush:
-+ NAPI_GRO_CB(skb)->flush = 1;
-+ return NULL;
- }
-
- INDIRECT_CALLABLE_SCOPE int tcp6_gro_complete(struct sk_buff *skb, int thoff)
+++ /dev/null
-From c9d1d23e5239f41700be69133a5769ac5ebc88a8 Mon Sep 17 00:00:00 2001
-Date: Thu, 2 May 2024 10:44:47 +0200
-Subject: [PATCH 6/6] net: add heuristic for enabling TCP fraglist GRO
-
-When forwarding TCP after GRO, software segmentation is very expensive,
-especially when the checksum needs to be recalculated.
-One case where that's currently unavoidable is when routing packets over
-PPPoE. Performance improves significantly when using fraglist GRO
-implemented in the same way as for UDP.
-
-When NETIF_F_GRO_FRAGLIST is enabled, perform a lookup for an established
-socket in the same netns as the receiving device. While this may not
-cover all relevant use cases in multi-netns configurations, it should be
-good enough for most configurations that need this.
-
-Here's a measurement of running 2 TCP streams through a MediaTek MT7622
-device (2-core Cortex-A53), which runs NAT with flow offload enabled from
-one ethernet port to PPPoE on another ethernet port + cake qdisc set to
-1Gbps.
-
-rx-gro-list off: 630 Mbit/s, CPU 35% idle
-rx-gro-list on: 770 Mbit/s, CPU 40% idle
-
----
- net/ipv4/tcp_offload.c | 32 ++++++++++++++++++++++++++++++++
- net/ipv6/tcpv6_offload.c | 35 +++++++++++++++++++++++++++++++++++
- 2 files changed, 67 insertions(+)
-
---- a/net/ipv4/tcp_offload.c
-+++ b/net/ipv4/tcp_offload.c
-@@ -413,6 +413,36 @@ void tcp_gro_complete(struct sk_buff *sk
- }
- EXPORT_SYMBOL(tcp_gro_complete);
-
-+static void tcp4_check_fraglist_gro(struct list_head *head, struct sk_buff *skb,
-+ struct tcphdr *th)
-+{
-+ const struct iphdr *iph;
-+ struct sk_buff *p;
-+ struct sock *sk;
-+ struct net *net;
-+ int iif, sdif;
-+
-+ if (likely(!(skb->dev->features & NETIF_F_GRO_FRAGLIST)))
-+ return;
-+
-+ p = tcp_gro_lookup(head, th);
-+ if (p) {
-+ NAPI_GRO_CB(skb)->is_flist = NAPI_GRO_CB(p)->is_flist;
-+ return;
-+ }
-+
-+ inet_get_iif_sdif(skb, &iif, &sdif);
-+ iph = skb_gro_network_header(skb);
-+ net = dev_net(skb->dev);
-+ sk = __inet_lookup_established(net, net->ipv4.tcp_death_row.hashinfo,
-+ iph->saddr, th->source,
-+ iph->daddr, ntohs(th->dest),
-+ iif, sdif);
-+ NAPI_GRO_CB(skb)->is_flist = !sk;
-+ if (sk)
-+ sock_put(sk);
-+}
-+
- INDIRECT_CALLABLE_SCOPE
- struct sk_buff *tcp4_gro_receive(struct list_head *head, struct sk_buff *skb)
- {
-@@ -428,6 +458,8 @@ struct sk_buff *tcp4_gro_receive(struct
- if (!th)
- goto flush;
-
-+ tcp4_check_fraglist_gro(head, skb, th);
-+
- return tcp_gro_receive(head, skb, th);
-
- flush:
---- a/net/ipv6/tcpv6_offload.c
-+++ b/net/ipv6/tcpv6_offload.c
-@@ -7,12 +7,45 @@
- */
- #include <linux/indirect_call_wrapper.h>
- #include <linux/skbuff.h>
-+#include <net/inet6_hashtables.h>
- #include <net/gro.h>
- #include <net/protocol.h>
- #include <net/tcp.h>
- #include <net/ip6_checksum.h>
- #include "ip6_offload.h"
-
-+static void tcp6_check_fraglist_gro(struct list_head *head, struct sk_buff *skb,
-+ struct tcphdr *th)
-+{
-+#if IS_ENABLED(CONFIG_IPV6)
-+ const struct ipv6hdr *hdr;
-+ struct sk_buff *p;
-+ struct sock *sk;
-+ struct net *net;
-+ int iif, sdif;
-+
-+ if (likely(!(skb->dev->features & NETIF_F_GRO_FRAGLIST)))
-+ return;
-+
-+ p = tcp_gro_lookup(head, th);
-+ if (p) {
-+ NAPI_GRO_CB(skb)->is_flist = NAPI_GRO_CB(p)->is_flist;
-+ return;
-+ }
-+
-+ inet6_get_iif_sdif(skb, &iif, &sdif);
-+ hdr = skb_gro_network_header(skb);
-+ net = dev_net(skb->dev);
-+ sk = __inet6_lookup_established(net, net->ipv4.tcp_death_row.hashinfo,
-+ &hdr->saddr, th->source,
-+ &hdr->daddr, ntohs(th->dest),
-+ iif, sdif);
-+ NAPI_GRO_CB(skb)->is_flist = !sk;
-+ if (sk)
-+ sock_put(sk);
-+#endif /* IS_ENABLED(CONFIG_IPV6) */
-+}
-+
- INDIRECT_CALLABLE_SCOPE
- struct sk_buff *tcp6_gro_receive(struct list_head *head, struct sk_buff *skb)
- {
-@@ -28,6 +61,8 @@ struct sk_buff *tcp6_gro_receive(struct
- if (!th)
- goto flush;
-
-+ tcp6_check_fraglist_gro(head, skb, th);
-+
- return tcp_gro_receive(head, skb, th);
-
- flush:
+++ /dev/null
-From 17bd3bd82f9f79f3feba15476c2b2c95a9b11ff8 Mon Sep 17 00:00:00 2001
-Date: Thu, 26 Sep 2024 10:53:14 +0200
-Subject: [PATCH] net: gso: fix tcp fraglist segmentation after pull from
- frag_list
-
-Detect tcp gso fraglist skbs with corrupted geometry (see below) and
-pass these to skb_segment instead of skb_segment_list, as the first
-can segment them correctly.
-
-Valid SKB_GSO_FRAGLIST skbs
-- consist of two or more segments
-- the head_skb holds the protocol headers plus first gso_size
-- one or more frag_list skbs hold exactly one segment
-- all but the last must be gso_size
-
-Optional datapath hooks such as NAT and BPF (bpf_skb_pull_data) can
-modify these skbs, breaking these invariants.
-
-In extreme cases they pull all data into skb linear. For TCP, this
-causes a NULL ptr deref in __tcpv4_gso_segment_list_csum at
-tcp_hdr(seg->next).
-
-Detect invalid geometry due to pull, by checking head_skb size.
-Don't just drop, as this may blackhole a destination. Convert to be
-able to pass to regular skb_segment.
-
-Approach and description based on a patch by Willem de Bruijn.
-
-Fixes: bee88cd5bd83 ("net: add support for segmenting TCP fraglist GSO packets")
----
- net/ipv4/tcp_offload.c | 10 ++++++++--
- net/ipv6/tcpv6_offload.c | 10 ++++++++--
- 2 files changed, 16 insertions(+), 4 deletions(-)
-
---- a/net/ipv4/tcp_offload.c
-+++ b/net/ipv4/tcp_offload.c
-@@ -104,8 +104,14 @@ static struct sk_buff *tcp4_gso_segment(
- if (!pskb_may_pull(skb, sizeof(struct tcphdr)))
- return ERR_PTR(-EINVAL);
-
-- if (skb_shinfo(skb)->gso_type & SKB_GSO_FRAGLIST)
-- return __tcp4_gso_segment_list(skb, features);
-+ if (skb_shinfo(skb)->gso_type & SKB_GSO_FRAGLIST) {
-+ struct tcphdr *th = tcp_hdr(skb);
-+
-+ if (skb_pagelen(skb) - th->doff * 4 == skb_shinfo(skb)->gso_size)
-+ return __tcp4_gso_segment_list(skb, features);
-+
-+ skb->ip_summed = CHECKSUM_NONE;
-+ }
-
- if (unlikely(skb->ip_summed != CHECKSUM_PARTIAL)) {
- const struct iphdr *iph = ip_hdr(skb);
---- a/net/ipv6/tcpv6_offload.c
-+++ b/net/ipv6/tcpv6_offload.c
-@@ -158,8 +158,14 @@ static struct sk_buff *tcp6_gso_segment(
- if (!pskb_may_pull(skb, sizeof(*th)))
- return ERR_PTR(-EINVAL);
-
-- if (skb_shinfo(skb)->gso_type & SKB_GSO_FRAGLIST)
-- return __tcp6_gso_segment_list(skb, features);
-+ if (skb_shinfo(skb)->gso_type & SKB_GSO_FRAGLIST) {
-+ struct tcphdr *th = tcp_hdr(skb);
-+
-+ if (skb_pagelen(skb) - th->doff * 4 == skb_shinfo(skb)->gso_size)
-+ return __tcp6_gso_segment_list(skb, features);
-+
-+ skb->ip_summed = CHECKSUM_NONE;
-+ }
-
- if (unlikely(skb->ip_summed != CHECKSUM_PARTIAL)) {
- const struct ipv6hdr *ipv6h = ipv6_hdr(skb);
+++ /dev/null
-From daa624d3c2ddffdcbad140a9625a4064371db44f Mon Sep 17 00:00:00 2001
-Date: Tue, 11 Mar 2025 22:25:30 +0100
-Subject: [PATCH] net: ipv6: fix TCP GSO segmentation with NAT
-
-When updating the source/destination address, the TCP/UDP checksum needs to
-be updated as well.
-
-Fixes: bee88cd5bd83 ("net: add support for segmenting TCP fraglist GSO packets")
----
- net/ipv6/tcpv6_offload.c | 21 +++++++++++++++------
- 1 file changed, 15 insertions(+), 6 deletions(-)
-
---- a/net/ipv6/tcpv6_offload.c
-+++ b/net/ipv6/tcpv6_offload.c
-@@ -93,14 +93,23 @@ INDIRECT_CALLABLE_SCOPE int tcp6_gro_com
- }
-
- static void __tcpv6_gso_segment_csum(struct sk_buff *seg,
-+ struct in6_addr *oldip,
-+ const struct in6_addr *newip,
- __be16 *oldport, __be16 newport)
- {
-- struct tcphdr *th;
-+ struct tcphdr *th = tcp_hdr(seg);
-+
-+ if (!ipv6_addr_equal(oldip, newip)) {
-+ inet_proto_csum_replace16(&th->check, seg,
-+ oldip->s6_addr32,
-+ newip->s6_addr32,
-+ true);
-+ *oldip = *newip;
-+ }
-
- if (*oldport == newport)
- return;
-
-- th = tcp_hdr(seg);
- inet_proto_csum_replace2(&th->check, seg, *oldport, newport, false);
- *oldport = newport;
- }
-@@ -128,10 +137,10 @@ static struct sk_buff *__tcpv6_gso_segme
- th2 = tcp_hdr(seg);
- iph2 = ipv6_hdr(seg);
-
-- iph2->saddr = iph->saddr;
-- iph2->daddr = iph->daddr;
-- __tcpv6_gso_segment_csum(seg, &th2->source, th->source);
-- __tcpv6_gso_segment_csum(seg, &th2->dest, th->dest);
-+ __tcpv6_gso_segment_csum(seg, &iph2->saddr, &iph->saddr,
-+ &th2->source, th->source);
-+ __tcpv6_gso_segment_csum(seg, &iph2->daddr, &iph->daddr,
-+ &th2->dest, th->dest);
- }
-
- return segs;
+++ /dev/null
-Date: Sat, 1 Mar 2025 21:55:16 +0800
-Subject: [PATCH] ppp: use IFF_NO_QUEUE in virtual interfaces
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-For PPPoE, PPTP, and PPPoL2TP, the start_xmit() function directly
-forwards packets to the underlying network stack and never returns
-anything other than 1. So these interfaces do not require a qdisc,
-and the IFF_NO_QUEUE flag should be set.
-
-Introduces a direct_xmit flag in struct ppp_channel to indicate when
-IFF_NO_QUEUE should be applied. The flag is set in ppp_connect_channel()
-for relevant protocols.
-
-While at it, remove the usused latency member from struct ppp_channel.
-
----
-
---- a/drivers/net/ppp/ppp_generic.c
-+++ b/drivers/net/ppp/ppp_generic.c
-@@ -3504,6 +3504,10 @@ ppp_connect_channel(struct channel *pch,
- ret = -ENOTCONN;
- goto outl;
- }
-+ if (pch->chan->direct_xmit)
-+ ppp->dev->priv_flags |= IFF_NO_QUEUE;
-+ else
-+ ppp->dev->priv_flags &= ~IFF_NO_QUEUE;
- spin_unlock_bh(&pch->downl);
- if (pch->file.hdrlen > ppp->file.hdrlen)
- ppp->file.hdrlen = pch->file.hdrlen;
---- a/drivers/net/ppp/pppoe.c
-+++ b/drivers/net/ppp/pppoe.c
-@@ -693,6 +693,7 @@ static int pppoe_connect(struct socket *
- po->chan.mtu = dev->mtu - sizeof(struct pppoe_hdr) - 2;
- po->chan.private = sk;
- po->chan.ops = &pppoe_chan_ops;
-+ po->chan.direct_xmit = true;
-
- error = ppp_register_net_channel(dev_net(dev), &po->chan);
- if (error) {
---- a/drivers/net/ppp/pptp.c
-+++ b/drivers/net/ppp/pptp.c
-@@ -469,6 +469,7 @@ static int pptp_connect(struct socket *s
- po->chan.mtu -= PPTP_HEADER_OVERHEAD;
-
- po->chan.hdrlen = 2 + sizeof(struct pptp_gre_header);
-+ po->chan.direct_xmit = true;
- error = ppp_register_channel(&po->chan);
- if (error) {
- pr_err("PPTP: failed to register PPP channel (%d)\n", error);
---- a/include/linux/ppp_channel.h
-+++ b/include/linux/ppp_channel.h
-@@ -42,8 +42,7 @@ struct ppp_channel {
- int hdrlen; /* amount of headroom channel needs */
- void *ppp; /* opaque to channel */
- int speed; /* transfer rate (bytes/second) */
-- /* the following is not used at present */
-- int latency; /* overhead time in milliseconds */
-+ bool direct_xmit; /* no qdisc, xmit directly */
- };
-
- #ifdef __KERNEL__
---- a/net/l2tp/l2tp_ppp.c
-+++ b/net/l2tp/l2tp_ppp.c
-@@ -820,6 +820,7 @@ static int pppol2tp_connect(struct socke
- po->chan.private = sk;
- po->chan.ops = &pppol2tp_chan_ops;
- po->chan.mtu = pppol2tp_tunnel_mtu(tunnel);
-+ po->chan.direct_xmit = true;
-
- error = ppp_register_net_channel(sock_net(sk), &po->chan);
- if (error) {
+++ /dev/null
-From a496d2f0fd612ab9e10700afe00dc9267bad788b Mon Sep 17 00:00:00 2001
-Date: Mon, 14 Apr 2025 18:56:01 +0800
-Subject: net: bridge: locally receive all multicast packets if IFF_ALLMULTI is
- set
-
-If multicast snooping is enabled, multicast packets may not always end up
-on the local bridge interface, if the host is not a member of the multicast
-group. Similar to how IFF_PROMISC allows all packets to be received
-locally, let IFF_ALLMULTI allow all multicast packets to be received.
-
-OpenWrt uses a user space daemon for DHCPv6/RA/NDP handling, and in relay
-mode it sets the ALLMULTI flag in order to receive all relevant queries on
-the network.
-
-This works for normal network interfaces and non-snooping bridges, but not
-snooping bridges (unless multicast routing is enabled).
-
-Closes: https://github.com/openwrt/openwrt/issues/15857#issuecomment-2662851243
-Link: https://patch.msgid.link/OSZPR01MB8434308370ACAFA90A22980798B32@OSZPR01MB8434.jpnprd01.prod.outlook.com
----
- net/bridge/br_input.c | 3 ++-
- 1 file changed, 2 insertions(+), 1 deletion(-)
-
---- a/net/bridge/br_input.c
-+++ b/net/bridge/br_input.c
-@@ -184,7 +184,8 @@ int br_handle_frame_finish(struct net *n
- if ((mdst || BR_INPUT_SKB_CB_MROUTERS_ONLY(skb)) &&
- br_multicast_querier_exists(brmctx, eth_hdr(skb), mdst)) {
- if ((mdst && mdst->host_joined) ||
-- br_multicast_is_router(brmctx, skb)) {
-+ br_multicast_is_router(brmctx, skb) ||
-+ br->dev->flags & IFF_ALLMULTI) {
- local_rcv = true;
- DEV_STATS_INC(br->dev, multicast);
- }
+++ /dev/null
-From c661050f93d3fd37a33c06041bb18a89688de7d2 Mon Sep 17 00:00:00 2001
-Date: Mon, 22 Apr 2024 05:38:56 -0700
-Subject: [PATCH] net: create a dummy net_device allocator
-
-It is impossible to use init_dummy_netdev together with alloc_netdev()
-as the 'setup' argument.
-
-This is because alloc_netdev() initializes some fields in the net_device
-structure, and later init_dummy_netdev() memzero them all. This causes
-some problems as reported here:
-
-
-Split the init_dummy_netdev() function in two. Create a new function called
-init_dummy_netdev_core() that does not memzero the net_device structure.
-Then have init_dummy_netdev() memzero-ing and calling
-init_dummy_netdev_core(), keeping the old behaviour.
-
-init_dummy_netdev_core() is the new function that could be called as an
-argument for alloc_netdev().
-
-Also, create a helper to allocate and initialize dummy net devices,
-leveraging init_dummy_netdev_core() as the setup argument. This function
-basically simplify the allocation of dummy devices, by allocating and
-initializing it. Freeing the device continue to be done through
-free_netdev()
-
----
- include/linux/netdevice.h | 3 +++
- net/core/dev.c | 56 ++++++++++++++++++++++++++-------------
- 2 files changed, 41 insertions(+), 18 deletions(-)
-
---- a/include/linux/netdevice.h
-+++ b/include/linux/netdevice.h
-@@ -4581,6 +4581,9 @@ static inline void netif_addr_unlock_bh(
-
- void ether_setup(struct net_device *dev);
-
-+/* Allocate dummy net_device */
-+struct net_device *alloc_netdev_dummy(int sizeof_priv);
-+
- /* Support for loadable net-drivers */
- struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name,
- unsigned char name_assign_type,
---- a/net/core/dev.c
-+++ b/net/core/dev.c
-@@ -10402,25 +10402,12 @@ err_free_name:
- }
- EXPORT_SYMBOL(register_netdevice);
-
--/**
-- * init_dummy_netdev - init a dummy network device for NAPI
-- * @dev: device to init
-- *
-- * This takes a network device structure and initialize the minimum
-- * amount of fields so it can be used to schedule NAPI polls without
-- * registering a full blown interface. This is to be used by drivers
-- * that need to tie several hardware interfaces to a single NAPI
-- * poll scheduler due to HW limitations.
-+/* Initialize the core of a dummy net device.
-+ * This is useful if you are calling this function after alloc_netdev(),
-+ * since it does not memset the net_device fields.
- */
--int init_dummy_netdev(struct net_device *dev)
-+static void init_dummy_netdev_core(struct net_device *dev)
- {
-- /* Clear everything. Note we don't initialize spinlocks
-- * are they aren't supposed to be taken by any of the
-- * NAPI code and this dummy netdev is supposed to be
-- * only ever used for NAPI polls
-- */
-- memset(dev, 0, sizeof(struct net_device));
--
- /* make sure we BUG if trying to hit standard
- * register/unregister code path
- */
-@@ -10440,12 +10427,32 @@ int init_dummy_netdev(struct net_device
- * because users of this 'device' dont need to change
- * its refcount.
- */
-+}
-+
-+/**
-+ * init_dummy_netdev - init a dummy network device for NAPI
-+ * @dev: device to init
-+ *
-+ * This takes a network device structure and initializes the minimum
-+ * amount of fields so it can be used to schedule NAPI polls without
-+ * registering a full blown interface. This is to be used by drivers
-+ * that need to tie several hardware interfaces to a single NAPI
-+ * poll scheduler due to HW limitations.
-+ */
-+int init_dummy_netdev(struct net_device *dev)
-+{
-+ /* Clear everything. Note we don't initialize spinlocks
-+ * as they aren't supposed to be taken by any of the
-+ * NAPI code and this dummy netdev is supposed to be
-+ * only ever used for NAPI polls
-+ */
-+ memset(dev, 0, sizeof(struct net_device));
-+ init_dummy_netdev_core(dev);
-
- return 0;
- }
- EXPORT_SYMBOL_GPL(init_dummy_netdev);
-
--
- /**
- * register_netdev - register a network device
- * @dev: device to register
-@@ -11039,6 +11046,19 @@ void free_netdev(struct net_device *dev)
- EXPORT_SYMBOL(free_netdev);
-
- /**
-+ * alloc_netdev_dummy - Allocate and initialize a dummy net device.
-+ * @sizeof_priv: size of private data to allocate space for
-+ *
-+ * Return: the allocated net_device on success, NULL otherwise
-+ */
-+struct net_device *alloc_netdev_dummy(int sizeof_priv)
-+{
-+ return alloc_netdev(sizeof_priv, "dummy#", NET_NAME_UNKNOWN,
-+ init_dummy_netdev_core);
-+}
-+EXPORT_SYMBOL_GPL(alloc_netdev_dummy);
-+
-+/**
- * synchronize_net - Synchronize with packet receive processing
- *
- * Wait for packets currently being received to be done.
+++ /dev/null
-From 84443741faab9045d53f022a9ac6a6633067a481 Mon Sep 17 00:00:00 2001
-Date: Wed, 14 Feb 2024 15:42:35 +0100
-Subject: [PATCH] netfilter: nf_tables: fix bidirectional offload regression
-
-Commit 8f84780b84d6 ("netfilter: flowtable: allow unidirectional rules")
-made unidirectional flow offload possible, while completely ignoring (and
-breaking) bidirectional flow offload for nftables.
-Add the missing flag that was left out as an exercise for the reader :)
-
-Fixes: 8f84780b84d6 ("netfilter: flowtable: allow unidirectional rules")
----
- net/netfilter/nft_flow_offload.c | 1 +
- 1 file changed, 1 insertion(+)
-
---- a/net/netfilter/nft_flow_offload.c
-+++ b/net/netfilter/nft_flow_offload.c
-@@ -367,6 +367,7 @@ static void nft_flow_offload_eval(const
- if (tcph)
- flow_offload_ct_tcp(ct);
-
-+ __set_bit(NF_FLOW_HW_BIDIRECTIONAL, &flow->flags);
- ret = flow_offload_add(flowtable, flow);
- if (ret < 0)
- goto err_flow_add;
+++ /dev/null
-From d2213db3f49bce8e7a87c8de05b9a091f78f654e Mon Sep 17 00:00:00 2001
-Date: Tue, 14 Nov 2023 15:08:41 +0100
-Subject: [PATCH 1/3] net: phy: aquantia: move to separate directory
-
-Move aquantia PHY driver to separate driectory in preparation for
-firmware loading support to keep things tidy.
-
----
- drivers/net/phy/Kconfig | 5 +----
- drivers/net/phy/Makefile | 6 +-----
- drivers/net/phy/aquantia/Kconfig | 5 +++++
- drivers/net/phy/aquantia/Makefile | 6 ++++++
- drivers/net/phy/{ => aquantia}/aquantia.h | 0
- drivers/net/phy/{ => aquantia}/aquantia_hwmon.c | 0
- drivers/net/phy/{ => aquantia}/aquantia_main.c | 0
- 7 files changed, 13 insertions(+), 9 deletions(-)
- create mode 100644 drivers/net/phy/aquantia/Kconfig
- create mode 100644 drivers/net/phy/aquantia/Makefile
- rename drivers/net/phy/{ => aquantia}/aquantia.h (100%)
- rename drivers/net/phy/{ => aquantia}/aquantia_hwmon.c (100%)
- rename drivers/net/phy/{ => aquantia}/aquantia_main.c (100%)
-
---- a/drivers/net/phy/Kconfig
-+++ b/drivers/net/phy/Kconfig
-@@ -96,10 +96,7 @@ config ADIN1100_PHY
- Currently supports the:
- - ADIN1100 - Robust,Industrial, Low Power 10BASE-T1L Ethernet PHY
-
--config AQUANTIA_PHY
-- tristate "Aquantia PHYs"
-- help
-- Currently supports the Aquantia AQ1202, AQ2104, AQR105, AQR405
-+source "drivers/net/phy/aquantia/Kconfig"
-
- config AX88796B_PHY
- tristate "Asix PHYs"
---- a/drivers/net/phy/Makefile
-+++ b/drivers/net/phy/Makefile
-@@ -35,11 +35,7 @@ obj-y += $(sfp-obj-y) $(sfp-obj-m)
- obj-$(CONFIG_ADIN_PHY) += adin.o
- obj-$(CONFIG_ADIN1100_PHY) += adin1100.o
- obj-$(CONFIG_AMD_PHY) += amd.o
--aquantia-objs += aquantia_main.o
--ifdef CONFIG_HWMON
--aquantia-objs += aquantia_hwmon.o
--endif
--obj-$(CONFIG_AQUANTIA_PHY) += aquantia.o
-+obj-$(CONFIG_AQUANTIA_PHY) += aquantia/
- obj-$(CONFIG_AT803X_PHY) += at803x.o
- obj-$(CONFIG_AX88796B_PHY) += ax88796b.o
- obj-$(CONFIG_BCM54140_PHY) += bcm54140.o
---- /dev/null
-+++ b/drivers/net/phy/aquantia/Kconfig
-@@ -0,0 +1,5 @@
-+# SPDX-License-Identifier: GPL-2.0-only
-+config AQUANTIA_PHY
-+ tristate "Aquantia PHYs"
-+ help
-+ Currently supports the Aquantia AQ1202, AQ2104, AQR105, AQR405
---- /dev/null
-+++ b/drivers/net/phy/aquantia/Makefile
-@@ -0,0 +1,6 @@
-+# SPDX-License-Identifier: GPL-2.0
-+aquantia-objs += aquantia_main.o
-+ifdef CONFIG_HWMON
-+aquantia-objs += aquantia_hwmon.o
-+endif
-+obj-$(CONFIG_AQUANTIA_PHY) += aquantia.o
---- a/drivers/net/phy/aquantia.h
-+++ /dev/null
-@@ -1,16 +0,0 @@
--/* SPDX-License-Identifier: GPL-2.0 */
--/* HWMON driver for Aquantia PHY
-- *
-- */
--
--#include <linux/device.h>
--#include <linux/phy.h>
--
--#if IS_REACHABLE(CONFIG_HWMON)
--int aqr_hwmon_probe(struct phy_device *phydev);
--#else
--static inline int aqr_hwmon_probe(struct phy_device *phydev) { return 0; }
--#endif
---- /dev/null
-+++ b/drivers/net/phy/aquantia/aquantia.h
-@@ -0,0 +1,16 @@
-+/* SPDX-License-Identifier: GPL-2.0 */
-+/* HWMON driver for Aquantia PHY
-+ *
-+ */
-+
-+#include <linux/device.h>
-+#include <linux/phy.h>
-+
-+#if IS_REACHABLE(CONFIG_HWMON)
-+int aqr_hwmon_probe(struct phy_device *phydev);
-+#else
-+static inline int aqr_hwmon_probe(struct phy_device *phydev) { return 0; }
-+#endif
---- /dev/null
-+++ b/drivers/net/phy/aquantia/aquantia_hwmon.c
-@@ -0,0 +1,250 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/* HWMON driver for Aquantia PHY
-+ *
-+ */
-+
-+#include <linux/phy.h>
-+#include <linux/device.h>
-+#include <linux/ctype.h>
-+#include <linux/hwmon.h>
-+
-+#include "aquantia.h"
-+
-+/* Vendor specific 1, MDIO_MMD_VEND2 */
-+#define VEND1_THERMAL_PROV_HIGH_TEMP_FAIL 0xc421
-+#define VEND1_THERMAL_PROV_LOW_TEMP_FAIL 0xc422
-+#define VEND1_THERMAL_PROV_HIGH_TEMP_WARN 0xc423
-+#define VEND1_THERMAL_PROV_LOW_TEMP_WARN 0xc424
-+#define VEND1_THERMAL_STAT1 0xc820
-+#define VEND1_THERMAL_STAT2 0xc821
-+#define VEND1_THERMAL_STAT2_VALID BIT(0)
-+#define VEND1_GENERAL_STAT1 0xc830
-+#define VEND1_GENERAL_STAT1_HIGH_TEMP_FAIL BIT(14)
-+#define VEND1_GENERAL_STAT1_LOW_TEMP_FAIL BIT(13)
-+#define VEND1_GENERAL_STAT1_HIGH_TEMP_WARN BIT(12)
-+#define VEND1_GENERAL_STAT1_LOW_TEMP_WARN BIT(11)
-+
-+#if IS_REACHABLE(CONFIG_HWMON)
-+
-+static umode_t aqr_hwmon_is_visible(const void *data,
-+ enum hwmon_sensor_types type,
-+ u32 attr, int channel)
-+{
-+ if (type != hwmon_temp)
-+ return 0;
-+
-+ switch (attr) {
-+ case hwmon_temp_input:
-+ case hwmon_temp_min_alarm:
-+ case hwmon_temp_max_alarm:
-+ case hwmon_temp_lcrit_alarm:
-+ case hwmon_temp_crit_alarm:
-+ return 0444;
-+ case hwmon_temp_min:
-+ case hwmon_temp_max:
-+ case hwmon_temp_lcrit:
-+ case hwmon_temp_crit:
-+ return 0644;
-+ default:
-+ return 0;
-+ }
-+}
-+
-+static int aqr_hwmon_get(struct phy_device *phydev, int reg, long *value)
-+{
-+ int temp = phy_read_mmd(phydev, MDIO_MMD_VEND1, reg);
-+
-+ if (temp < 0)
-+ return temp;
-+
-+ /* 16 bit value is 2's complement with LSB = 1/256th degree Celsius */
-+ *value = (s16)temp * 1000 / 256;
-+
-+ return 0;
-+}
-+
-+static int aqr_hwmon_set(struct phy_device *phydev, int reg, long value)
-+{
-+ int temp;
-+
-+ if (value >= 128000 || value < -128000)
-+ return -ERANGE;
-+
-+ temp = value * 256 / 1000;
-+
-+ /* temp is in s16 range and we're interested in lower 16 bits only */
-+ return phy_write_mmd(phydev, MDIO_MMD_VEND1, reg, (u16)temp);
-+}
-+
-+static int aqr_hwmon_test_bit(struct phy_device *phydev, int reg, int bit)
-+{
-+ int val = phy_read_mmd(phydev, MDIO_MMD_VEND1, reg);
-+
-+ if (val < 0)
-+ return val;
-+
-+ return !!(val & bit);
-+}
-+
-+static int aqr_hwmon_status1(struct phy_device *phydev, int bit, long *value)
-+{
-+ int val = aqr_hwmon_test_bit(phydev, VEND1_GENERAL_STAT1, bit);
-+
-+ if (val < 0)
-+ return val;
-+
-+ *value = val;
-+
-+ return 0;
-+}
-+
-+static int aqr_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
-+ u32 attr, int channel, long *value)
-+{
-+ struct phy_device *phydev = dev_get_drvdata(dev);
-+ int reg;
-+
-+ if (type != hwmon_temp)
-+ return -EOPNOTSUPP;
-+
-+ switch (attr) {
-+ case hwmon_temp_input:
-+ reg = aqr_hwmon_test_bit(phydev, VEND1_THERMAL_STAT2,
-+ VEND1_THERMAL_STAT2_VALID);
-+ if (reg < 0)
-+ return reg;
-+ if (!reg)
-+ return -EBUSY;
-+
-+ return aqr_hwmon_get(phydev, VEND1_THERMAL_STAT1, value);
-+
-+ case hwmon_temp_lcrit:
-+ return aqr_hwmon_get(phydev, VEND1_THERMAL_PROV_LOW_TEMP_FAIL,
-+ value);
-+ case hwmon_temp_min:
-+ return aqr_hwmon_get(phydev, VEND1_THERMAL_PROV_LOW_TEMP_WARN,
-+ value);
-+ case hwmon_temp_max:
-+ return aqr_hwmon_get(phydev, VEND1_THERMAL_PROV_HIGH_TEMP_WARN,
-+ value);
-+ case hwmon_temp_crit:
-+ return aqr_hwmon_get(phydev, VEND1_THERMAL_PROV_HIGH_TEMP_FAIL,
-+ value);
-+ case hwmon_temp_lcrit_alarm:
-+ return aqr_hwmon_status1(phydev,
-+ VEND1_GENERAL_STAT1_LOW_TEMP_FAIL,
-+ value);
-+ case hwmon_temp_min_alarm:
-+ return aqr_hwmon_status1(phydev,
-+ VEND1_GENERAL_STAT1_LOW_TEMP_WARN,
-+ value);
-+ case hwmon_temp_max_alarm:
-+ return aqr_hwmon_status1(phydev,
-+ VEND1_GENERAL_STAT1_HIGH_TEMP_WARN,
-+ value);
-+ case hwmon_temp_crit_alarm:
-+ return aqr_hwmon_status1(phydev,
-+ VEND1_GENERAL_STAT1_HIGH_TEMP_FAIL,
-+ value);
-+ default:
-+ return -EOPNOTSUPP;
-+ }
-+}
-+
-+static int aqr_hwmon_write(struct device *dev, enum hwmon_sensor_types type,
-+ u32 attr, int channel, long value)
-+{
-+ struct phy_device *phydev = dev_get_drvdata(dev);
-+
-+ if (type != hwmon_temp)
-+ return -EOPNOTSUPP;
-+
-+ switch (attr) {
-+ case hwmon_temp_lcrit:
-+ return aqr_hwmon_set(phydev, VEND1_THERMAL_PROV_LOW_TEMP_FAIL,
-+ value);
-+ case hwmon_temp_min:
-+ return aqr_hwmon_set(phydev, VEND1_THERMAL_PROV_LOW_TEMP_WARN,
-+ value);
-+ case hwmon_temp_max:
-+ return aqr_hwmon_set(phydev, VEND1_THERMAL_PROV_HIGH_TEMP_WARN,
-+ value);
-+ case hwmon_temp_crit:
-+ return aqr_hwmon_set(phydev, VEND1_THERMAL_PROV_HIGH_TEMP_FAIL,
-+ value);
-+ default:
-+ return -EOPNOTSUPP;
-+ }
-+}
-+
-+static const struct hwmon_ops aqr_hwmon_ops = {
-+ .is_visible = aqr_hwmon_is_visible,
-+ .read = aqr_hwmon_read,
-+ .write = aqr_hwmon_write,
-+};
-+
-+static u32 aqr_hwmon_chip_config[] = {
-+ HWMON_C_REGISTER_TZ,
-+ 0,
-+};
-+
-+static const struct hwmon_channel_info aqr_hwmon_chip = {
-+ .type = hwmon_chip,
-+ .config = aqr_hwmon_chip_config,
-+};
-+
-+static u32 aqr_hwmon_temp_config[] = {
-+ HWMON_T_INPUT |
-+ HWMON_T_MAX | HWMON_T_MIN |
-+ HWMON_T_MAX_ALARM | HWMON_T_MIN_ALARM |
-+ HWMON_T_CRIT | HWMON_T_LCRIT |
-+ HWMON_T_CRIT_ALARM | HWMON_T_LCRIT_ALARM,
-+ 0,
-+};
-+
-+static const struct hwmon_channel_info aqr_hwmon_temp = {
-+ .type = hwmon_temp,
-+ .config = aqr_hwmon_temp_config,
-+};
-+
-+static const struct hwmon_channel_info * const aqr_hwmon_info[] = {
-+ &aqr_hwmon_chip,
-+ &aqr_hwmon_temp,
-+ NULL,
-+};
-+
-+static const struct hwmon_chip_info aqr_hwmon_chip_info = {
-+ .ops = &aqr_hwmon_ops,
-+ .info = aqr_hwmon_info,
-+};
-+
-+int aqr_hwmon_probe(struct phy_device *phydev)
-+{
-+ struct device *dev = &phydev->mdio.dev;
-+ struct device *hwmon_dev;
-+ char *hwmon_name;
-+ int i, j;
-+
-+ hwmon_name = devm_kstrdup(dev, dev_name(dev), GFP_KERNEL);
-+ if (!hwmon_name)
-+ return -ENOMEM;
-+
-+ for (i = j = 0; hwmon_name[i]; i++) {
-+ if (isalnum(hwmon_name[i])) {
-+ if (i != j)
-+ hwmon_name[j] = hwmon_name[i];
-+ j++;
-+ }
-+ }
-+ hwmon_name[j] = '\0';
-+
-+ hwmon_dev = devm_hwmon_device_register_with_info(dev, hwmon_name,
-+ phydev, &aqr_hwmon_chip_info, NULL);
-+
-+ return PTR_ERR_OR_ZERO(hwmon_dev);
-+}
-+
-+#endif
---- /dev/null
-+++ b/drivers/net/phy/aquantia/aquantia_main.c
-@@ -0,0 +1,882 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/*
-+ * Driver for Aquantia PHY
-+ *
-+ *
-+ * Copyright 2015 Freescale Semiconductor, Inc.
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/delay.h>
-+#include <linux/bitfield.h>
-+#include <linux/phy.h>
-+
-+#include "aquantia.h"
-+
-+#define PHY_ID_AQ1202 0x03a1b445
-+#define PHY_ID_AQ2104 0x03a1b460
-+#define PHY_ID_AQR105 0x03a1b4a2
-+#define PHY_ID_AQR106 0x03a1b4d0
-+#define PHY_ID_AQR107 0x03a1b4e0
-+#define PHY_ID_AQCS109 0x03a1b5c2
-+#define PHY_ID_AQR405 0x03a1b4b0
-+#define PHY_ID_AQR112 0x03a1b662
-+#define PHY_ID_AQR412 0x03a1b712
-+#define PHY_ID_AQR113C 0x31c31c12
-+
-+#define MDIO_PHYXS_VEND_IF_STATUS 0xe812
-+#define MDIO_PHYXS_VEND_IF_STATUS_TYPE_MASK GENMASK(7, 3)
-+#define MDIO_PHYXS_VEND_IF_STATUS_TYPE_KR 0
-+#define MDIO_PHYXS_VEND_IF_STATUS_TYPE_KX 1
-+#define MDIO_PHYXS_VEND_IF_STATUS_TYPE_XFI 2
-+#define MDIO_PHYXS_VEND_IF_STATUS_TYPE_USXGMII 3
-+#define MDIO_PHYXS_VEND_IF_STATUS_TYPE_XAUI 4
-+#define MDIO_PHYXS_VEND_IF_STATUS_TYPE_SGMII 6
-+#define MDIO_PHYXS_VEND_IF_STATUS_TYPE_RXAUI 7
-+#define MDIO_PHYXS_VEND_IF_STATUS_TYPE_OCSGMII 10
-+
-+#define MDIO_AN_VEND_PROV 0xc400
-+#define MDIO_AN_VEND_PROV_1000BASET_FULL BIT(15)
-+#define MDIO_AN_VEND_PROV_1000BASET_HALF BIT(14)
-+#define MDIO_AN_VEND_PROV_5000BASET_FULL BIT(11)
-+#define MDIO_AN_VEND_PROV_2500BASET_FULL BIT(10)
-+#define MDIO_AN_VEND_PROV_DOWNSHIFT_EN BIT(4)
-+#define MDIO_AN_VEND_PROV_DOWNSHIFT_MASK GENMASK(3, 0)
-+#define MDIO_AN_VEND_PROV_DOWNSHIFT_DFLT 4
-+
-+#define MDIO_AN_TX_VEND_STATUS1 0xc800
-+#define MDIO_AN_TX_VEND_STATUS1_RATE_MASK GENMASK(3, 1)
-+#define MDIO_AN_TX_VEND_STATUS1_10BASET 0
-+#define MDIO_AN_TX_VEND_STATUS1_100BASETX 1
-+#define MDIO_AN_TX_VEND_STATUS1_1000BASET 2
-+#define MDIO_AN_TX_VEND_STATUS1_10GBASET 3
-+#define MDIO_AN_TX_VEND_STATUS1_2500BASET 4
-+#define MDIO_AN_TX_VEND_STATUS1_5000BASET 5
-+#define MDIO_AN_TX_VEND_STATUS1_FULL_DUPLEX BIT(0)
-+
-+#define MDIO_AN_TX_VEND_INT_STATUS1 0xcc00
-+#define MDIO_AN_TX_VEND_INT_STATUS1_DOWNSHIFT BIT(1)
-+
-+#define MDIO_AN_TX_VEND_INT_STATUS2 0xcc01
-+#define MDIO_AN_TX_VEND_INT_STATUS2_MASK BIT(0)
-+
-+#define MDIO_AN_TX_VEND_INT_MASK2 0xd401
-+#define MDIO_AN_TX_VEND_INT_MASK2_LINK BIT(0)
-+
-+#define MDIO_AN_RX_LP_STAT1 0xe820
-+#define MDIO_AN_RX_LP_STAT1_1000BASET_FULL BIT(15)
-+#define MDIO_AN_RX_LP_STAT1_1000BASET_HALF BIT(14)
-+#define MDIO_AN_RX_LP_STAT1_SHORT_REACH BIT(13)
-+#define MDIO_AN_RX_LP_STAT1_AQRATE_DOWNSHIFT BIT(12)
-+#define MDIO_AN_RX_LP_STAT1_AQ_PHY BIT(2)
-+
-+#define MDIO_AN_RX_LP_STAT4 0xe823
-+#define MDIO_AN_RX_LP_STAT4_FW_MAJOR GENMASK(15, 8)
-+#define MDIO_AN_RX_LP_STAT4_FW_MINOR GENMASK(7, 0)
-+
-+#define MDIO_AN_RX_VEND_STAT3 0xe832
-+#define MDIO_AN_RX_VEND_STAT3_AFR BIT(0)
-+
-+/* MDIO_MMD_C22EXT */
-+#define MDIO_C22EXT_STAT_SGMII_RX_GOOD_FRAMES 0xd292
-+#define MDIO_C22EXT_STAT_SGMII_RX_BAD_FRAMES 0xd294
-+#define MDIO_C22EXT_STAT_SGMII_RX_FALSE_CARRIER 0xd297
-+#define MDIO_C22EXT_STAT_SGMII_TX_GOOD_FRAMES 0xd313
-+#define MDIO_C22EXT_STAT_SGMII_TX_BAD_FRAMES 0xd315
-+#define MDIO_C22EXT_STAT_SGMII_TX_FALSE_CARRIER 0xd317
-+#define MDIO_C22EXT_STAT_SGMII_TX_COLLISIONS 0xd318
-+#define MDIO_C22EXT_STAT_SGMII_TX_LINE_COLLISIONS 0xd319
-+#define MDIO_C22EXT_STAT_SGMII_TX_FRAME_ALIGN_ERR 0xd31a
-+#define MDIO_C22EXT_STAT_SGMII_TX_RUNT_FRAMES 0xd31b
-+
-+/* Vendor specific 1, MDIO_MMD_VEND1 */
-+#define VEND1_GLOBAL_FW_ID 0x0020
-+#define VEND1_GLOBAL_FW_ID_MAJOR GENMASK(15, 8)
-+#define VEND1_GLOBAL_FW_ID_MINOR GENMASK(7, 0)
-+
-+#define VEND1_GLOBAL_GEN_STAT2 0xc831
-+#define VEND1_GLOBAL_GEN_STAT2_OP_IN_PROG BIT(15)
-+
-+/* The following registers all have similar layouts; first the registers... */
-+#define VEND1_GLOBAL_CFG_10M 0x0310
-+#define VEND1_GLOBAL_CFG_100M 0x031b
-+#define VEND1_GLOBAL_CFG_1G 0x031c
-+#define VEND1_GLOBAL_CFG_2_5G 0x031d
-+#define VEND1_GLOBAL_CFG_5G 0x031e
-+#define VEND1_GLOBAL_CFG_10G 0x031f
-+/* ...and now the fields */
-+#define VEND1_GLOBAL_CFG_RATE_ADAPT GENMASK(8, 7)
-+#define VEND1_GLOBAL_CFG_RATE_ADAPT_NONE 0
-+#define VEND1_GLOBAL_CFG_RATE_ADAPT_USX 1
-+#define VEND1_GLOBAL_CFG_RATE_ADAPT_PAUSE 2
-+
-+#define VEND1_GLOBAL_RSVD_STAT1 0xc885
-+#define VEND1_GLOBAL_RSVD_STAT1_FW_BUILD_ID GENMASK(7, 4)
-+#define VEND1_GLOBAL_RSVD_STAT1_PROV_ID GENMASK(3, 0)
-+
-+#define VEND1_GLOBAL_RSVD_STAT9 0xc88d
-+#define VEND1_GLOBAL_RSVD_STAT9_MODE GENMASK(7, 0)
-+#define VEND1_GLOBAL_RSVD_STAT9_1000BT2 0x23
-+
-+#define VEND1_GLOBAL_INT_STD_STATUS 0xfc00
-+#define VEND1_GLOBAL_INT_VEND_STATUS 0xfc01
-+
-+#define VEND1_GLOBAL_INT_STD_MASK 0xff00
-+#define VEND1_GLOBAL_INT_STD_MASK_PMA1 BIT(15)
-+#define VEND1_GLOBAL_INT_STD_MASK_PMA2 BIT(14)
-+#define VEND1_GLOBAL_INT_STD_MASK_PCS1 BIT(13)
-+#define VEND1_GLOBAL_INT_STD_MASK_PCS2 BIT(12)
-+#define VEND1_GLOBAL_INT_STD_MASK_PCS3 BIT(11)
-+#define VEND1_GLOBAL_INT_STD_MASK_PHY_XS1 BIT(10)
-+#define VEND1_GLOBAL_INT_STD_MASK_PHY_XS2 BIT(9)
-+#define VEND1_GLOBAL_INT_STD_MASK_AN1 BIT(8)
-+#define VEND1_GLOBAL_INT_STD_MASK_AN2 BIT(7)
-+#define VEND1_GLOBAL_INT_STD_MASK_GBE BIT(6)
-+#define VEND1_GLOBAL_INT_STD_MASK_ALL BIT(0)
-+
-+#define VEND1_GLOBAL_INT_VEND_MASK 0xff01
-+#define VEND1_GLOBAL_INT_VEND_MASK_PMA BIT(15)
-+#define VEND1_GLOBAL_INT_VEND_MASK_PCS BIT(14)
-+#define VEND1_GLOBAL_INT_VEND_MASK_PHY_XS BIT(13)
-+#define VEND1_GLOBAL_INT_VEND_MASK_AN BIT(12)
-+#define VEND1_GLOBAL_INT_VEND_MASK_GBE BIT(11)
-+#define VEND1_GLOBAL_INT_VEND_MASK_GLOBAL1 BIT(2)
-+#define VEND1_GLOBAL_INT_VEND_MASK_GLOBAL2 BIT(1)
-+#define VEND1_GLOBAL_INT_VEND_MASK_GLOBAL3 BIT(0)
-+
-+/* Sleep and timeout for checking if the Processor-Intensive
-+ * MDIO operation is finished
-+ */
-+#define AQR107_OP_IN_PROG_SLEEP 1000
-+#define AQR107_OP_IN_PROG_TIMEOUT 100000
-+
-+struct aqr107_hw_stat {
-+ const char *name;
-+ int reg;
-+ int size;
-+};
-+
-+#define SGMII_STAT(n, r, s) { n, MDIO_C22EXT_STAT_SGMII_ ## r, s }
-+static const struct aqr107_hw_stat aqr107_hw_stats[] = {
-+ SGMII_STAT("sgmii_rx_good_frames", RX_GOOD_FRAMES, 26),
-+ SGMII_STAT("sgmii_rx_bad_frames", RX_BAD_FRAMES, 26),
-+ SGMII_STAT("sgmii_rx_false_carrier_events", RX_FALSE_CARRIER, 8),
-+ SGMII_STAT("sgmii_tx_good_frames", TX_GOOD_FRAMES, 26),
-+ SGMII_STAT("sgmii_tx_bad_frames", TX_BAD_FRAMES, 26),
-+ SGMII_STAT("sgmii_tx_false_carrier_events", TX_FALSE_CARRIER, 8),
-+ SGMII_STAT("sgmii_tx_collisions", TX_COLLISIONS, 8),
-+ SGMII_STAT("sgmii_tx_line_collisions", TX_LINE_COLLISIONS, 8),
-+ SGMII_STAT("sgmii_tx_frame_alignment_err", TX_FRAME_ALIGN_ERR, 16),
-+ SGMII_STAT("sgmii_tx_runt_frames", TX_RUNT_FRAMES, 22),
-+};
-+#define AQR107_SGMII_STAT_SZ ARRAY_SIZE(aqr107_hw_stats)
-+
-+struct aqr107_priv {
-+ u64 sgmii_stats[AQR107_SGMII_STAT_SZ];
-+};
-+
-+static int aqr107_get_sset_count(struct phy_device *phydev)
-+{
-+ return AQR107_SGMII_STAT_SZ;
-+}
-+
-+static void aqr107_get_strings(struct phy_device *phydev, u8 *data)
-+{
-+ int i;
-+
-+ for (i = 0; i < AQR107_SGMII_STAT_SZ; i++)
-+ strscpy(data + i * ETH_GSTRING_LEN, aqr107_hw_stats[i].name,
-+ ETH_GSTRING_LEN);
-+}
-+
-+static u64 aqr107_get_stat(struct phy_device *phydev, int index)
-+{
-+ const struct aqr107_hw_stat *stat = aqr107_hw_stats + index;
-+ int len_l = min(stat->size, 16);
-+ int len_h = stat->size - len_l;
-+ u64 ret;
-+ int val;
-+
-+ val = phy_read_mmd(phydev, MDIO_MMD_C22EXT, stat->reg);
-+ if (val < 0)
-+ return U64_MAX;
-+
-+ ret = val & GENMASK(len_l - 1, 0);
-+ if (len_h) {
-+ val = phy_read_mmd(phydev, MDIO_MMD_C22EXT, stat->reg + 1);
-+ if (val < 0)
-+ return U64_MAX;
-+
-+ ret += (val & GENMASK(len_h - 1, 0)) << 16;
-+ }
-+
-+ return ret;
-+}
-+
-+static void aqr107_get_stats(struct phy_device *phydev,
-+ struct ethtool_stats *stats, u64 *data)
-+{
-+ struct aqr107_priv *priv = phydev->priv;
-+ u64 val;
-+ int i;
-+
-+ for (i = 0; i < AQR107_SGMII_STAT_SZ; i++) {
-+ val = aqr107_get_stat(phydev, i);
-+ if (val == U64_MAX)
-+ phydev_err(phydev, "Reading HW Statistics failed for %s\n",
-+ aqr107_hw_stats[i].name);
-+ else
-+ priv->sgmii_stats[i] += val;
-+
-+ data[i] = priv->sgmii_stats[i];
-+ }
-+}
-+
-+static int aqr_config_aneg(struct phy_device *phydev)
-+{
-+ bool changed = false;
-+ u16 reg;
-+ int ret;
-+
-+ if (phydev->autoneg == AUTONEG_DISABLE)
-+ return genphy_c45_pma_setup_forced(phydev);
-+
-+ ret = genphy_c45_an_config_aneg(phydev);
-+ if (ret < 0)
-+ return ret;
-+ if (ret > 0)
-+ changed = true;
-+
-+ /* Clause 45 has no standardized support for 1000BaseT, therefore
-+ * use vendor registers for this mode.
-+ */
-+ reg = 0;
-+ if (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
-+ phydev->advertising))
-+ reg |= MDIO_AN_VEND_PROV_1000BASET_FULL;
-+
-+ if (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT,
-+ phydev->advertising))
-+ reg |= MDIO_AN_VEND_PROV_1000BASET_HALF;
-+
-+ /* Handle the case when the 2.5G and 5G speeds are not advertised */
-+ if (linkmode_test_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
-+ phydev->advertising))
-+ reg |= MDIO_AN_VEND_PROV_2500BASET_FULL;
-+
-+ if (linkmode_test_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT,
-+ phydev->advertising))
-+ reg |= MDIO_AN_VEND_PROV_5000BASET_FULL;
-+
-+ ret = phy_modify_mmd_changed(phydev, MDIO_MMD_AN, MDIO_AN_VEND_PROV,
-+ MDIO_AN_VEND_PROV_1000BASET_HALF |
-+ MDIO_AN_VEND_PROV_1000BASET_FULL |
-+ MDIO_AN_VEND_PROV_2500BASET_FULL |
-+ MDIO_AN_VEND_PROV_5000BASET_FULL, reg);
-+ if (ret < 0)
-+ return ret;
-+ if (ret > 0)
-+ changed = true;
-+
-+ return genphy_c45_check_and_restart_aneg(phydev, changed);
-+}
-+
-+static int aqr_config_intr(struct phy_device *phydev)
-+{
-+ bool en = phydev->interrupts == PHY_INTERRUPT_ENABLED;
-+ int err;
-+
-+ if (en) {
-+ /* Clear any pending interrupts before enabling them */
-+ err = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_TX_VEND_INT_STATUS2);
-+ if (err < 0)
-+ return err;
-+ }
-+
-+ err = phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_TX_VEND_INT_MASK2,
-+ en ? MDIO_AN_TX_VEND_INT_MASK2_LINK : 0);
-+ if (err < 0)
-+ return err;
-+
-+ err = phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLOBAL_INT_STD_MASK,
-+ en ? VEND1_GLOBAL_INT_STD_MASK_ALL : 0);
-+ if (err < 0)
-+ return err;
-+
-+ err = phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLOBAL_INT_VEND_MASK,
-+ en ? VEND1_GLOBAL_INT_VEND_MASK_GLOBAL3 |
-+ VEND1_GLOBAL_INT_VEND_MASK_AN : 0);
-+ if (err < 0)
-+ return err;
-+
-+ if (!en) {
-+ /* Clear any pending interrupts after we have disabled them */
-+ err = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_TX_VEND_INT_STATUS2);
-+ if (err < 0)
-+ return err;
-+ }
-+
-+ return 0;
-+}
-+
-+static irqreturn_t aqr_handle_interrupt(struct phy_device *phydev)
-+{
-+ int irq_status;
-+
-+ irq_status = phy_read_mmd(phydev, MDIO_MMD_AN,
-+ MDIO_AN_TX_VEND_INT_STATUS2);
-+ if (irq_status < 0) {
-+ phy_error(phydev);
-+ return IRQ_NONE;
-+ }
-+
-+ if (!(irq_status & MDIO_AN_TX_VEND_INT_STATUS2_MASK))
-+ return IRQ_NONE;
-+
-+ phy_trigger_machine(phydev);
-+
-+ return IRQ_HANDLED;
-+}
-+
-+static int aqr_read_status(struct phy_device *phydev)
-+{
-+ int val;
-+
-+ if (phydev->autoneg == AUTONEG_ENABLE) {
-+ val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_RX_LP_STAT1);
-+ if (val < 0)
-+ return val;
-+
-+ linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
-+ phydev->lp_advertising,
-+ val & MDIO_AN_RX_LP_STAT1_1000BASET_FULL);
-+ linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT,
-+ phydev->lp_advertising,
-+ val & MDIO_AN_RX_LP_STAT1_1000BASET_HALF);
-+ }
-+
-+ return genphy_c45_read_status(phydev);
-+}
-+
-+static int aqr107_read_rate(struct phy_device *phydev)
-+{
-+ u32 config_reg;
-+ int val;
-+
-+ val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_TX_VEND_STATUS1);
-+ if (val < 0)
-+ return val;
-+
-+ if (val & MDIO_AN_TX_VEND_STATUS1_FULL_DUPLEX)
-+ phydev->duplex = DUPLEX_FULL;
-+ else
-+ phydev->duplex = DUPLEX_HALF;
-+
-+ switch (FIELD_GET(MDIO_AN_TX_VEND_STATUS1_RATE_MASK, val)) {
-+ case MDIO_AN_TX_VEND_STATUS1_10BASET:
-+ phydev->speed = SPEED_10;
-+ config_reg = VEND1_GLOBAL_CFG_10M;
-+ break;
-+ case MDIO_AN_TX_VEND_STATUS1_100BASETX:
-+ phydev->speed = SPEED_100;
-+ config_reg = VEND1_GLOBAL_CFG_100M;
-+ break;
-+ case MDIO_AN_TX_VEND_STATUS1_1000BASET:
-+ phydev->speed = SPEED_1000;
-+ config_reg = VEND1_GLOBAL_CFG_1G;
-+ break;
-+ case MDIO_AN_TX_VEND_STATUS1_2500BASET:
-+ phydev->speed = SPEED_2500;
-+ config_reg = VEND1_GLOBAL_CFG_2_5G;
-+ break;
-+ case MDIO_AN_TX_VEND_STATUS1_5000BASET:
-+ phydev->speed = SPEED_5000;
-+ config_reg = VEND1_GLOBAL_CFG_5G;
-+ break;
-+ case MDIO_AN_TX_VEND_STATUS1_10GBASET:
-+ phydev->speed = SPEED_10000;
-+ config_reg = VEND1_GLOBAL_CFG_10G;
-+ break;
-+ default:
-+ phydev->speed = SPEED_UNKNOWN;
-+ return 0;
-+ }
-+
-+ val = phy_read_mmd(phydev, MDIO_MMD_VEND1, config_reg);
-+ if (val < 0)
-+ return val;
-+
-+ if (FIELD_GET(VEND1_GLOBAL_CFG_RATE_ADAPT, val) ==
-+ VEND1_GLOBAL_CFG_RATE_ADAPT_PAUSE)
-+ phydev->rate_matching = RATE_MATCH_PAUSE;
-+ else
-+ phydev->rate_matching = RATE_MATCH_NONE;
-+
-+ return 0;
-+}
-+
-+static int aqr107_read_status(struct phy_device *phydev)
-+{
-+ int val, ret;
-+
-+ ret = aqr_read_status(phydev);
-+ if (ret)
-+ return ret;
-+
-+ if (!phydev->link || phydev->autoneg == AUTONEG_DISABLE)
-+ return 0;
-+
-+ val = phy_read_mmd(phydev, MDIO_MMD_PHYXS, MDIO_PHYXS_VEND_IF_STATUS);
-+ if (val < 0)
-+ return val;
-+
-+ switch (FIELD_GET(MDIO_PHYXS_VEND_IF_STATUS_TYPE_MASK, val)) {
-+ case MDIO_PHYXS_VEND_IF_STATUS_TYPE_KR:
-+ phydev->interface = PHY_INTERFACE_MODE_10GKR;
-+ break;
-+ case MDIO_PHYXS_VEND_IF_STATUS_TYPE_KX:
-+ phydev->interface = PHY_INTERFACE_MODE_1000BASEKX;
-+ break;
-+ case MDIO_PHYXS_VEND_IF_STATUS_TYPE_XFI:
-+ phydev->interface = PHY_INTERFACE_MODE_10GBASER;
-+ break;
-+ case MDIO_PHYXS_VEND_IF_STATUS_TYPE_USXGMII:
-+ phydev->interface = PHY_INTERFACE_MODE_USXGMII;
-+ break;
-+ case MDIO_PHYXS_VEND_IF_STATUS_TYPE_XAUI:
-+ phydev->interface = PHY_INTERFACE_MODE_XAUI;
-+ break;
-+ case MDIO_PHYXS_VEND_IF_STATUS_TYPE_SGMII:
-+ phydev->interface = PHY_INTERFACE_MODE_SGMII;
-+ break;
-+ case MDIO_PHYXS_VEND_IF_STATUS_TYPE_RXAUI:
-+ phydev->interface = PHY_INTERFACE_MODE_RXAUI;
-+ break;
-+ case MDIO_PHYXS_VEND_IF_STATUS_TYPE_OCSGMII:
-+ phydev->interface = PHY_INTERFACE_MODE_2500BASEX;
-+ break;
-+ default:
-+ phydev->interface = PHY_INTERFACE_MODE_NA;
-+ break;
-+ }
-+
-+ /* Read possibly downshifted rate from vendor register */
-+ return aqr107_read_rate(phydev);
-+}
-+
-+static int aqr107_get_downshift(struct phy_device *phydev, u8 *data)
-+{
-+ int val, cnt, enable;
-+
-+ val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_VEND_PROV);
-+ if (val < 0)
-+ return val;
-+
-+ enable = FIELD_GET(MDIO_AN_VEND_PROV_DOWNSHIFT_EN, val);
-+ cnt = FIELD_GET(MDIO_AN_VEND_PROV_DOWNSHIFT_MASK, val);
-+
-+ *data = enable && cnt ? cnt : DOWNSHIFT_DEV_DISABLE;
-+
-+ return 0;
-+}
-+
-+static int aqr107_set_downshift(struct phy_device *phydev, u8 cnt)
-+{
-+ int val = 0;
-+
-+ if (!FIELD_FIT(MDIO_AN_VEND_PROV_DOWNSHIFT_MASK, cnt))
-+ return -E2BIG;
-+
-+ if (cnt != DOWNSHIFT_DEV_DISABLE) {
-+ val = MDIO_AN_VEND_PROV_DOWNSHIFT_EN;
-+ val |= FIELD_PREP(MDIO_AN_VEND_PROV_DOWNSHIFT_MASK, cnt);
-+ }
-+
-+ return phy_modify_mmd(phydev, MDIO_MMD_AN, MDIO_AN_VEND_PROV,
-+ MDIO_AN_VEND_PROV_DOWNSHIFT_EN |
-+ MDIO_AN_VEND_PROV_DOWNSHIFT_MASK, val);
-+}
-+
-+static int aqr107_get_tunable(struct phy_device *phydev,
-+ struct ethtool_tunable *tuna, void *data)
-+{
-+ switch (tuna->id) {
-+ case ETHTOOL_PHY_DOWNSHIFT:
-+ return aqr107_get_downshift(phydev, data);
-+ default:
-+ return -EOPNOTSUPP;
-+ }
-+}
-+
-+static int aqr107_set_tunable(struct phy_device *phydev,
-+ struct ethtool_tunable *tuna, const void *data)
-+{
-+ switch (tuna->id) {
-+ case ETHTOOL_PHY_DOWNSHIFT:
-+ return aqr107_set_downshift(phydev, *(const u8 *)data);
-+ default:
-+ return -EOPNOTSUPP;
-+ }
-+}
-+
-+/* If we configure settings whilst firmware is still initializing the chip,
-+ * then these settings may be overwritten. Therefore make sure chip
-+ * initialization has completed. Use presence of the firmware ID as
-+ * indicator for initialization having completed.
-+ * The chip also provides a "reset completed" bit, but it's cleared after
-+ * read. Therefore function would time out if called again.
-+ */
-+static int aqr107_wait_reset_complete(struct phy_device *phydev)
-+{
-+ int val;
-+
-+ return phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND1,
-+ VEND1_GLOBAL_FW_ID, val, val != 0,
-+ 20000, 2000000, false);
-+}
-+
-+static void aqr107_chip_info(struct phy_device *phydev)
-+{
-+ u8 fw_major, fw_minor, build_id, prov_id;
-+ int val;
-+
-+ val = phy_read_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLOBAL_FW_ID);
-+ if (val < 0)
-+ return;
-+
-+ fw_major = FIELD_GET(VEND1_GLOBAL_FW_ID_MAJOR, val);
-+ fw_minor = FIELD_GET(VEND1_GLOBAL_FW_ID_MINOR, val);
-+
-+ val = phy_read_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLOBAL_RSVD_STAT1);
-+ if (val < 0)
-+ return;
-+
-+ build_id = FIELD_GET(VEND1_GLOBAL_RSVD_STAT1_FW_BUILD_ID, val);
-+ prov_id = FIELD_GET(VEND1_GLOBAL_RSVD_STAT1_PROV_ID, val);
-+
-+ phydev_dbg(phydev, "FW %u.%u, Build %u, Provisioning %u\n",
-+ fw_major, fw_minor, build_id, prov_id);
-+}
-+
-+static int aqr107_config_init(struct phy_device *phydev)
-+{
-+ int ret;
-+
-+ /* Check that the PHY interface type is compatible */
-+ if (phydev->interface != PHY_INTERFACE_MODE_SGMII &&
-+ phydev->interface != PHY_INTERFACE_MODE_1000BASEKX &&
-+ phydev->interface != PHY_INTERFACE_MODE_2500BASEX &&
-+ phydev->interface != PHY_INTERFACE_MODE_XGMII &&
-+ phydev->interface != PHY_INTERFACE_MODE_USXGMII &&
-+ phydev->interface != PHY_INTERFACE_MODE_10GKR &&
-+ phydev->interface != PHY_INTERFACE_MODE_10GBASER &&
-+ phydev->interface != PHY_INTERFACE_MODE_XAUI &&
-+ phydev->interface != PHY_INTERFACE_MODE_RXAUI)
-+ return -ENODEV;
-+
-+ WARN(phydev->interface == PHY_INTERFACE_MODE_XGMII,
-+ "Your devicetree is out of date, please update it. The AQR107 family doesn't support XGMII, maybe you mean USXGMII.\n");
-+
-+ ret = aqr107_wait_reset_complete(phydev);
-+ if (!ret)
-+ aqr107_chip_info(phydev);
-+
-+ return aqr107_set_downshift(phydev, MDIO_AN_VEND_PROV_DOWNSHIFT_DFLT);
-+}
-+
-+static int aqcs109_config_init(struct phy_device *phydev)
-+{
-+ int ret;
-+
-+ /* Check that the PHY interface type is compatible */
-+ if (phydev->interface != PHY_INTERFACE_MODE_SGMII &&
-+ phydev->interface != PHY_INTERFACE_MODE_2500BASEX)
-+ return -ENODEV;
-+
-+ ret = aqr107_wait_reset_complete(phydev);
-+ if (!ret)
-+ aqr107_chip_info(phydev);
-+
-+ /* AQCS109 belongs to a chip family partially supporting 10G and 5G.
-+ * PMA speed ability bits are the same for all members of the family,
-+ * AQCS109 however supports speeds up to 2.5G only.
-+ */
-+ phy_set_max_speed(phydev, SPEED_2500);
-+
-+ return aqr107_set_downshift(phydev, MDIO_AN_VEND_PROV_DOWNSHIFT_DFLT);
-+}
-+
-+static void aqr107_link_change_notify(struct phy_device *phydev)
-+{
-+ u8 fw_major, fw_minor;
-+ bool downshift, short_reach, afr;
-+ int mode, val;
-+
-+ if (phydev->state != PHY_RUNNING || phydev->autoneg == AUTONEG_DISABLE)
-+ return;
-+
-+ val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_RX_LP_STAT1);
-+ /* call failed or link partner is no Aquantia PHY */
-+ if (val < 0 || !(val & MDIO_AN_RX_LP_STAT1_AQ_PHY))
-+ return;
-+
-+ short_reach = val & MDIO_AN_RX_LP_STAT1_SHORT_REACH;
-+ downshift = val & MDIO_AN_RX_LP_STAT1_AQRATE_DOWNSHIFT;
-+
-+ val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_RX_LP_STAT4);
-+ if (val < 0)
-+ return;
-+
-+ fw_major = FIELD_GET(MDIO_AN_RX_LP_STAT4_FW_MAJOR, val);
-+ fw_minor = FIELD_GET(MDIO_AN_RX_LP_STAT4_FW_MINOR, val);
-+
-+ val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_RX_VEND_STAT3);
-+ if (val < 0)
-+ return;
-+
-+ afr = val & MDIO_AN_RX_VEND_STAT3_AFR;
-+
-+ phydev_dbg(phydev, "Link partner is Aquantia PHY, FW %u.%u%s%s%s\n",
-+ fw_major, fw_minor,
-+ short_reach ? ", short reach mode" : "",
-+ downshift ? ", fast-retrain downshift advertised" : "",
-+ afr ? ", fast reframe advertised" : "");
-+
-+ val = phy_read_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLOBAL_RSVD_STAT9);
-+ if (val < 0)
-+ return;
-+
-+ mode = FIELD_GET(VEND1_GLOBAL_RSVD_STAT9_MODE, val);
-+ if (mode == VEND1_GLOBAL_RSVD_STAT9_1000BT2)
-+ phydev_info(phydev, "Aquantia 1000Base-T2 mode active\n");
-+}
-+
-+static int aqr107_wait_processor_intensive_op(struct phy_device *phydev)
-+{
-+ int val, err;
-+
-+ /* The datasheet notes to wait at least 1ms after issuing a
-+ * processor intensive operation before checking.
-+ * We cannot use the 'sleep_before_read' parameter of read_poll_timeout
-+ * because that just determines the maximum time slept, not the minimum.
-+ */
-+ usleep_range(1000, 5000);
-+
-+ err = phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND1,
-+ VEND1_GLOBAL_GEN_STAT2, val,
-+ !(val & VEND1_GLOBAL_GEN_STAT2_OP_IN_PROG),
-+ AQR107_OP_IN_PROG_SLEEP,
-+ AQR107_OP_IN_PROG_TIMEOUT, false);
-+ if (err) {
-+ phydev_err(phydev, "timeout: processor-intensive MDIO operation\n");
-+ return err;
-+ }
-+
-+ return 0;
-+}
-+
-+static int aqr107_get_rate_matching(struct phy_device *phydev,
-+ phy_interface_t iface)
-+{
-+ if (iface == PHY_INTERFACE_MODE_10GBASER ||
-+ iface == PHY_INTERFACE_MODE_2500BASEX ||
-+ iface == PHY_INTERFACE_MODE_NA)
-+ return RATE_MATCH_PAUSE;
-+ return RATE_MATCH_NONE;
-+}
-+
-+static int aqr107_suspend(struct phy_device *phydev)
-+{
-+ int err;
-+
-+ err = phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MDIO_CTRL1,
-+ MDIO_CTRL1_LPOWER);
-+ if (err)
-+ return err;
-+
-+ return aqr107_wait_processor_intensive_op(phydev);
-+}
-+
-+static int aqr107_resume(struct phy_device *phydev)
-+{
-+ int err;
-+
-+ err = phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MDIO_CTRL1,
-+ MDIO_CTRL1_LPOWER);
-+ if (err)
-+ return err;
-+
-+ return aqr107_wait_processor_intensive_op(phydev);
-+}
-+
-+static int aqr107_probe(struct phy_device *phydev)
-+{
-+ phydev->priv = devm_kzalloc(&phydev->mdio.dev,
-+ sizeof(struct aqr107_priv), GFP_KERNEL);
-+ if (!phydev->priv)
-+ return -ENOMEM;
-+
-+ return aqr_hwmon_probe(phydev);
-+}
-+
-+static struct phy_driver aqr_driver[] = {
-+{
-+ PHY_ID_MATCH_MODEL(PHY_ID_AQ1202),
-+ .name = "Aquantia AQ1202",
-+ .config_aneg = aqr_config_aneg,
-+ .config_intr = aqr_config_intr,
-+ .handle_interrupt = aqr_handle_interrupt,
-+ .read_status = aqr_read_status,
-+},
-+{
-+ PHY_ID_MATCH_MODEL(PHY_ID_AQ2104),
-+ .name = "Aquantia AQ2104",
-+ .config_aneg = aqr_config_aneg,
-+ .config_intr = aqr_config_intr,
-+ .handle_interrupt = aqr_handle_interrupt,
-+ .read_status = aqr_read_status,
-+},
-+{
-+ PHY_ID_MATCH_MODEL(PHY_ID_AQR105),
-+ .name = "Aquantia AQR105",
-+ .config_aneg = aqr_config_aneg,
-+ .config_intr = aqr_config_intr,
-+ .handle_interrupt = aqr_handle_interrupt,
-+ .read_status = aqr_read_status,
-+ .suspend = aqr107_suspend,
-+ .resume = aqr107_resume,
-+},
-+{
-+ PHY_ID_MATCH_MODEL(PHY_ID_AQR106),
-+ .name = "Aquantia AQR106",
-+ .config_aneg = aqr_config_aneg,
-+ .config_intr = aqr_config_intr,
-+ .handle_interrupt = aqr_handle_interrupt,
-+ .read_status = aqr_read_status,
-+},
-+{
-+ PHY_ID_MATCH_MODEL(PHY_ID_AQR107),
-+ .name = "Aquantia AQR107",
-+ .probe = aqr107_probe,
-+ .get_rate_matching = aqr107_get_rate_matching,
-+ .config_init = aqr107_config_init,
-+ .config_aneg = aqr_config_aneg,
-+ .config_intr = aqr_config_intr,
-+ .handle_interrupt = aqr_handle_interrupt,
-+ .read_status = aqr107_read_status,
-+ .get_tunable = aqr107_get_tunable,
-+ .set_tunable = aqr107_set_tunable,
-+ .suspend = aqr107_suspend,
-+ .resume = aqr107_resume,
-+ .get_sset_count = aqr107_get_sset_count,
-+ .get_strings = aqr107_get_strings,
-+ .get_stats = aqr107_get_stats,
-+ .link_change_notify = aqr107_link_change_notify,
-+},
-+{
-+ PHY_ID_MATCH_MODEL(PHY_ID_AQCS109),
-+ .name = "Aquantia AQCS109",
-+ .probe = aqr107_probe,
-+ .get_rate_matching = aqr107_get_rate_matching,
-+ .config_init = aqcs109_config_init,
-+ .config_aneg = aqr_config_aneg,
-+ .config_intr = aqr_config_intr,
-+ .handle_interrupt = aqr_handle_interrupt,
-+ .read_status = aqr107_read_status,
-+ .get_tunable = aqr107_get_tunable,
-+ .set_tunable = aqr107_set_tunable,
-+ .suspend = aqr107_suspend,
-+ .resume = aqr107_resume,
-+ .get_sset_count = aqr107_get_sset_count,
-+ .get_strings = aqr107_get_strings,
-+ .get_stats = aqr107_get_stats,
-+ .link_change_notify = aqr107_link_change_notify,
-+},
-+{
-+ PHY_ID_MATCH_MODEL(PHY_ID_AQR405),
-+ .name = "Aquantia AQR405",
-+ .config_aneg = aqr_config_aneg,
-+ .config_intr = aqr_config_intr,
-+ .handle_interrupt = aqr_handle_interrupt,
-+ .read_status = aqr_read_status,
-+},
-+{
-+ PHY_ID_MATCH_MODEL(PHY_ID_AQR112),
-+ .name = "Aquantia AQR112",
-+ .probe = aqr107_probe,
-+ .config_aneg = aqr_config_aneg,
-+ .config_intr = aqr_config_intr,
-+ .handle_interrupt = aqr_handle_interrupt,
-+ .get_tunable = aqr107_get_tunable,
-+ .set_tunable = aqr107_set_tunable,
-+ .suspend = aqr107_suspend,
-+ .resume = aqr107_resume,
-+ .read_status = aqr107_read_status,
-+ .get_rate_matching = aqr107_get_rate_matching,
-+ .get_sset_count = aqr107_get_sset_count,
-+ .get_strings = aqr107_get_strings,
-+ .get_stats = aqr107_get_stats,
-+ .link_change_notify = aqr107_link_change_notify,
-+},
-+{
-+ PHY_ID_MATCH_MODEL(PHY_ID_AQR412),
-+ .name = "Aquantia AQR412",
-+ .probe = aqr107_probe,
-+ .config_aneg = aqr_config_aneg,
-+ .config_intr = aqr_config_intr,
-+ .handle_interrupt = aqr_handle_interrupt,
-+ .get_tunable = aqr107_get_tunable,
-+ .set_tunable = aqr107_set_tunable,
-+ .suspend = aqr107_suspend,
-+ .resume = aqr107_resume,
-+ .read_status = aqr107_read_status,
-+ .get_rate_matching = aqr107_get_rate_matching,
-+ .get_sset_count = aqr107_get_sset_count,
-+ .get_strings = aqr107_get_strings,
-+ .get_stats = aqr107_get_stats,
-+ .link_change_notify = aqr107_link_change_notify,
-+},
-+{
-+ PHY_ID_MATCH_MODEL(PHY_ID_AQR113C),
-+ .name = "Aquantia AQR113C",
-+ .probe = aqr107_probe,
-+ .get_rate_matching = aqr107_get_rate_matching,
-+ .config_init = aqr107_config_init,
-+ .config_aneg = aqr_config_aneg,
-+ .config_intr = aqr_config_intr,
-+ .handle_interrupt = aqr_handle_interrupt,
-+ .read_status = aqr107_read_status,
-+ .get_tunable = aqr107_get_tunable,
-+ .set_tunable = aqr107_set_tunable,
-+ .suspend = aqr107_suspend,
-+ .resume = aqr107_resume,
-+ .get_sset_count = aqr107_get_sset_count,
-+ .get_strings = aqr107_get_strings,
-+ .get_stats = aqr107_get_stats,
-+ .link_change_notify = aqr107_link_change_notify,
-+},
-+};
-+
-+module_phy_driver(aqr_driver);
-+
-+static struct mdio_device_id __maybe_unused aqr_tbl[] = {
-+ { PHY_ID_MATCH_MODEL(PHY_ID_AQ1202) },
-+ { PHY_ID_MATCH_MODEL(PHY_ID_AQ2104) },
-+ { PHY_ID_MATCH_MODEL(PHY_ID_AQR105) },
-+ { PHY_ID_MATCH_MODEL(PHY_ID_AQR106) },
-+ { PHY_ID_MATCH_MODEL(PHY_ID_AQR107) },
-+ { PHY_ID_MATCH_MODEL(PHY_ID_AQCS109) },
-+ { PHY_ID_MATCH_MODEL(PHY_ID_AQR405) },
-+ { PHY_ID_MATCH_MODEL(PHY_ID_AQR112) },
-+ { PHY_ID_MATCH_MODEL(PHY_ID_AQR412) },
-+ { PHY_ID_MATCH_MODEL(PHY_ID_AQR113C) },
-+ { }
-+};
-+
-+MODULE_DEVICE_TABLE(mdio, aqr_tbl);
-+
-+MODULE_DESCRIPTION("Aquantia PHY driver");
-+MODULE_LICENSE("GPL v2");
---- a/drivers/net/phy/aquantia_hwmon.c
-+++ /dev/null
-@@ -1,250 +0,0 @@
--// SPDX-License-Identifier: GPL-2.0
--/* HWMON driver for Aquantia PHY
-- *
-- */
--
--#include <linux/phy.h>
--#include <linux/device.h>
--#include <linux/ctype.h>
--#include <linux/hwmon.h>
--
--#include "aquantia.h"
--
--/* Vendor specific 1, MDIO_MMD_VEND2 */
--#define VEND1_THERMAL_PROV_HIGH_TEMP_FAIL 0xc421
--#define VEND1_THERMAL_PROV_LOW_TEMP_FAIL 0xc422
--#define VEND1_THERMAL_PROV_HIGH_TEMP_WARN 0xc423
--#define VEND1_THERMAL_PROV_LOW_TEMP_WARN 0xc424
--#define VEND1_THERMAL_STAT1 0xc820
--#define VEND1_THERMAL_STAT2 0xc821
--#define VEND1_THERMAL_STAT2_VALID BIT(0)
--#define VEND1_GENERAL_STAT1 0xc830
--#define VEND1_GENERAL_STAT1_HIGH_TEMP_FAIL BIT(14)
--#define VEND1_GENERAL_STAT1_LOW_TEMP_FAIL BIT(13)
--#define VEND1_GENERAL_STAT1_HIGH_TEMP_WARN BIT(12)
--#define VEND1_GENERAL_STAT1_LOW_TEMP_WARN BIT(11)
--
--#if IS_REACHABLE(CONFIG_HWMON)
--
--static umode_t aqr_hwmon_is_visible(const void *data,
-- enum hwmon_sensor_types type,
-- u32 attr, int channel)
--{
-- if (type != hwmon_temp)
-- return 0;
--
-- switch (attr) {
-- case hwmon_temp_input:
-- case hwmon_temp_min_alarm:
-- case hwmon_temp_max_alarm:
-- case hwmon_temp_lcrit_alarm:
-- case hwmon_temp_crit_alarm:
-- return 0444;
-- case hwmon_temp_min:
-- case hwmon_temp_max:
-- case hwmon_temp_lcrit:
-- case hwmon_temp_crit:
-- return 0644;
-- default:
-- return 0;
-- }
--}
--
--static int aqr_hwmon_get(struct phy_device *phydev, int reg, long *value)
--{
-- int temp = phy_read_mmd(phydev, MDIO_MMD_VEND1, reg);
--
-- if (temp < 0)
-- return temp;
--
-- /* 16 bit value is 2's complement with LSB = 1/256th degree Celsius */
-- *value = (s16)temp * 1000 / 256;
--
-- return 0;
--}
--
--static int aqr_hwmon_set(struct phy_device *phydev, int reg, long value)
--{
-- int temp;
--
-- if (value >= 128000 || value < -128000)
-- return -ERANGE;
--
-- temp = value * 256 / 1000;
--
-- /* temp is in s16 range and we're interested in lower 16 bits only */
-- return phy_write_mmd(phydev, MDIO_MMD_VEND1, reg, (u16)temp);
--}
--
--static int aqr_hwmon_test_bit(struct phy_device *phydev, int reg, int bit)
--{
-- int val = phy_read_mmd(phydev, MDIO_MMD_VEND1, reg);
--
-- if (val < 0)
-- return val;
--
-- return !!(val & bit);
--}
--
--static int aqr_hwmon_status1(struct phy_device *phydev, int bit, long *value)
--{
-- int val = aqr_hwmon_test_bit(phydev, VEND1_GENERAL_STAT1, bit);
--
-- if (val < 0)
-- return val;
--
-- *value = val;
--
-- return 0;
--}
--
--static int aqr_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
-- u32 attr, int channel, long *value)
--{
-- struct phy_device *phydev = dev_get_drvdata(dev);
-- int reg;
--
-- if (type != hwmon_temp)
-- return -EOPNOTSUPP;
--
-- switch (attr) {
-- case hwmon_temp_input:
-- reg = aqr_hwmon_test_bit(phydev, VEND1_THERMAL_STAT2,
-- VEND1_THERMAL_STAT2_VALID);
-- if (reg < 0)
-- return reg;
-- if (!reg)
-- return -EBUSY;
--
-- return aqr_hwmon_get(phydev, VEND1_THERMAL_STAT1, value);
--
-- case hwmon_temp_lcrit:
-- return aqr_hwmon_get(phydev, VEND1_THERMAL_PROV_LOW_TEMP_FAIL,
-- value);
-- case hwmon_temp_min:
-- return aqr_hwmon_get(phydev, VEND1_THERMAL_PROV_LOW_TEMP_WARN,
-- value);
-- case hwmon_temp_max:
-- return aqr_hwmon_get(phydev, VEND1_THERMAL_PROV_HIGH_TEMP_WARN,
-- value);
-- case hwmon_temp_crit:
-- return aqr_hwmon_get(phydev, VEND1_THERMAL_PROV_HIGH_TEMP_FAIL,
-- value);
-- case hwmon_temp_lcrit_alarm:
-- return aqr_hwmon_status1(phydev,
-- VEND1_GENERAL_STAT1_LOW_TEMP_FAIL,
-- value);
-- case hwmon_temp_min_alarm:
-- return aqr_hwmon_status1(phydev,
-- VEND1_GENERAL_STAT1_LOW_TEMP_WARN,
-- value);
-- case hwmon_temp_max_alarm:
-- return aqr_hwmon_status1(phydev,
-- VEND1_GENERAL_STAT1_HIGH_TEMP_WARN,
-- value);
-- case hwmon_temp_crit_alarm:
-- return aqr_hwmon_status1(phydev,
-- VEND1_GENERAL_STAT1_HIGH_TEMP_FAIL,
-- value);
-- default:
-- return -EOPNOTSUPP;
-- }
--}
--
--static int aqr_hwmon_write(struct device *dev, enum hwmon_sensor_types type,
-- u32 attr, int channel, long value)
--{
-- struct phy_device *phydev = dev_get_drvdata(dev);
--
-- if (type != hwmon_temp)
-- return -EOPNOTSUPP;
--
-- switch (attr) {
-- case hwmon_temp_lcrit:
-- return aqr_hwmon_set(phydev, VEND1_THERMAL_PROV_LOW_TEMP_FAIL,
-- value);
-- case hwmon_temp_min:
-- return aqr_hwmon_set(phydev, VEND1_THERMAL_PROV_LOW_TEMP_WARN,
-- value);
-- case hwmon_temp_max:
-- return aqr_hwmon_set(phydev, VEND1_THERMAL_PROV_HIGH_TEMP_WARN,
-- value);
-- case hwmon_temp_crit:
-- return aqr_hwmon_set(phydev, VEND1_THERMAL_PROV_HIGH_TEMP_FAIL,
-- value);
-- default:
-- return -EOPNOTSUPP;
-- }
--}
--
--static const struct hwmon_ops aqr_hwmon_ops = {
-- .is_visible = aqr_hwmon_is_visible,
-- .read = aqr_hwmon_read,
-- .write = aqr_hwmon_write,
--};
--
--static u32 aqr_hwmon_chip_config[] = {
-- HWMON_C_REGISTER_TZ,
-- 0,
--};
--
--static const struct hwmon_channel_info aqr_hwmon_chip = {
-- .type = hwmon_chip,
-- .config = aqr_hwmon_chip_config,
--};
--
--static u32 aqr_hwmon_temp_config[] = {
-- HWMON_T_INPUT |
-- HWMON_T_MAX | HWMON_T_MIN |
-- HWMON_T_MAX_ALARM | HWMON_T_MIN_ALARM |
-- HWMON_T_CRIT | HWMON_T_LCRIT |
-- HWMON_T_CRIT_ALARM | HWMON_T_LCRIT_ALARM,
-- 0,
--};
--
--static const struct hwmon_channel_info aqr_hwmon_temp = {
-- .type = hwmon_temp,
-- .config = aqr_hwmon_temp_config,
--};
--
--static const struct hwmon_channel_info * const aqr_hwmon_info[] = {
-- &aqr_hwmon_chip,
-- &aqr_hwmon_temp,
-- NULL,
--};
--
--static const struct hwmon_chip_info aqr_hwmon_chip_info = {
-- .ops = &aqr_hwmon_ops,
-- .info = aqr_hwmon_info,
--};
--
--int aqr_hwmon_probe(struct phy_device *phydev)
--{
-- struct device *dev = &phydev->mdio.dev;
-- struct device *hwmon_dev;
-- char *hwmon_name;
-- int i, j;
--
-- hwmon_name = devm_kstrdup(dev, dev_name(dev), GFP_KERNEL);
-- if (!hwmon_name)
-- return -ENOMEM;
--
-- for (i = j = 0; hwmon_name[i]; i++) {
-- if (isalnum(hwmon_name[i])) {
-- if (i != j)
-- hwmon_name[j] = hwmon_name[i];
-- j++;
-- }
-- }
-- hwmon_name[j] = '\0';
--
-- hwmon_dev = devm_hwmon_device_register_with_info(dev, hwmon_name,
-- phydev, &aqr_hwmon_chip_info, NULL);
--
-- return PTR_ERR_OR_ZERO(hwmon_dev);
--}
--
--#endif
---- a/drivers/net/phy/aquantia_main.c
-+++ /dev/null
-@@ -1,882 +0,0 @@
--// SPDX-License-Identifier: GPL-2.0
--/*
-- * Driver for Aquantia PHY
-- *
-- *
-- * Copyright 2015 Freescale Semiconductor, Inc.
-- */
--
--#include <linux/kernel.h>
--#include <linux/module.h>
--#include <linux/delay.h>
--#include <linux/bitfield.h>
--#include <linux/phy.h>
--
--#include "aquantia.h"
--
--#define PHY_ID_AQ1202 0x03a1b445
--#define PHY_ID_AQ2104 0x03a1b460
--#define PHY_ID_AQR105 0x03a1b4a2
--#define PHY_ID_AQR106 0x03a1b4d0
--#define PHY_ID_AQR107 0x03a1b4e0
--#define PHY_ID_AQCS109 0x03a1b5c2
--#define PHY_ID_AQR405 0x03a1b4b0
--#define PHY_ID_AQR112 0x03a1b662
--#define PHY_ID_AQR412 0x03a1b712
--#define PHY_ID_AQR113C 0x31c31c12
--
--#define MDIO_PHYXS_VEND_IF_STATUS 0xe812
--#define MDIO_PHYXS_VEND_IF_STATUS_TYPE_MASK GENMASK(7, 3)
--#define MDIO_PHYXS_VEND_IF_STATUS_TYPE_KR 0
--#define MDIO_PHYXS_VEND_IF_STATUS_TYPE_KX 1
--#define MDIO_PHYXS_VEND_IF_STATUS_TYPE_XFI 2
--#define MDIO_PHYXS_VEND_IF_STATUS_TYPE_USXGMII 3
--#define MDIO_PHYXS_VEND_IF_STATUS_TYPE_XAUI 4
--#define MDIO_PHYXS_VEND_IF_STATUS_TYPE_SGMII 6
--#define MDIO_PHYXS_VEND_IF_STATUS_TYPE_RXAUI 7
--#define MDIO_PHYXS_VEND_IF_STATUS_TYPE_OCSGMII 10
--
--#define MDIO_AN_VEND_PROV 0xc400
--#define MDIO_AN_VEND_PROV_1000BASET_FULL BIT(15)
--#define MDIO_AN_VEND_PROV_1000BASET_HALF BIT(14)
--#define MDIO_AN_VEND_PROV_5000BASET_FULL BIT(11)
--#define MDIO_AN_VEND_PROV_2500BASET_FULL BIT(10)
--#define MDIO_AN_VEND_PROV_DOWNSHIFT_EN BIT(4)
--#define MDIO_AN_VEND_PROV_DOWNSHIFT_MASK GENMASK(3, 0)
--#define MDIO_AN_VEND_PROV_DOWNSHIFT_DFLT 4
--
--#define MDIO_AN_TX_VEND_STATUS1 0xc800
--#define MDIO_AN_TX_VEND_STATUS1_RATE_MASK GENMASK(3, 1)
--#define MDIO_AN_TX_VEND_STATUS1_10BASET 0
--#define MDIO_AN_TX_VEND_STATUS1_100BASETX 1
--#define MDIO_AN_TX_VEND_STATUS1_1000BASET 2
--#define MDIO_AN_TX_VEND_STATUS1_10GBASET 3
--#define MDIO_AN_TX_VEND_STATUS1_2500BASET 4
--#define MDIO_AN_TX_VEND_STATUS1_5000BASET 5
--#define MDIO_AN_TX_VEND_STATUS1_FULL_DUPLEX BIT(0)
--
--#define MDIO_AN_TX_VEND_INT_STATUS1 0xcc00
--#define MDIO_AN_TX_VEND_INT_STATUS1_DOWNSHIFT BIT(1)
--
--#define MDIO_AN_TX_VEND_INT_STATUS2 0xcc01
--#define MDIO_AN_TX_VEND_INT_STATUS2_MASK BIT(0)
--
--#define MDIO_AN_TX_VEND_INT_MASK2 0xd401
--#define MDIO_AN_TX_VEND_INT_MASK2_LINK BIT(0)
--
--#define MDIO_AN_RX_LP_STAT1 0xe820
--#define MDIO_AN_RX_LP_STAT1_1000BASET_FULL BIT(15)
--#define MDIO_AN_RX_LP_STAT1_1000BASET_HALF BIT(14)
--#define MDIO_AN_RX_LP_STAT1_SHORT_REACH BIT(13)
--#define MDIO_AN_RX_LP_STAT1_AQRATE_DOWNSHIFT BIT(12)
--#define MDIO_AN_RX_LP_STAT1_AQ_PHY BIT(2)
--
--#define MDIO_AN_RX_LP_STAT4 0xe823
--#define MDIO_AN_RX_LP_STAT4_FW_MAJOR GENMASK(15, 8)
--#define MDIO_AN_RX_LP_STAT4_FW_MINOR GENMASK(7, 0)
--
--#define MDIO_AN_RX_VEND_STAT3 0xe832
--#define MDIO_AN_RX_VEND_STAT3_AFR BIT(0)
--
--/* MDIO_MMD_C22EXT */
--#define MDIO_C22EXT_STAT_SGMII_RX_GOOD_FRAMES 0xd292
--#define MDIO_C22EXT_STAT_SGMII_RX_BAD_FRAMES 0xd294
--#define MDIO_C22EXT_STAT_SGMII_RX_FALSE_CARRIER 0xd297
--#define MDIO_C22EXT_STAT_SGMII_TX_GOOD_FRAMES 0xd313
--#define MDIO_C22EXT_STAT_SGMII_TX_BAD_FRAMES 0xd315
--#define MDIO_C22EXT_STAT_SGMII_TX_FALSE_CARRIER 0xd317
--#define MDIO_C22EXT_STAT_SGMII_TX_COLLISIONS 0xd318
--#define MDIO_C22EXT_STAT_SGMII_TX_LINE_COLLISIONS 0xd319
--#define MDIO_C22EXT_STAT_SGMII_TX_FRAME_ALIGN_ERR 0xd31a
--#define MDIO_C22EXT_STAT_SGMII_TX_RUNT_FRAMES 0xd31b
--
--/* Vendor specific 1, MDIO_MMD_VEND1 */
--#define VEND1_GLOBAL_FW_ID 0x0020
--#define VEND1_GLOBAL_FW_ID_MAJOR GENMASK(15, 8)
--#define VEND1_GLOBAL_FW_ID_MINOR GENMASK(7, 0)
--
--#define VEND1_GLOBAL_GEN_STAT2 0xc831
--#define VEND1_GLOBAL_GEN_STAT2_OP_IN_PROG BIT(15)
--
--/* The following registers all have similar layouts; first the registers... */
--#define VEND1_GLOBAL_CFG_10M 0x0310
--#define VEND1_GLOBAL_CFG_100M 0x031b
--#define VEND1_GLOBAL_CFG_1G 0x031c
--#define VEND1_GLOBAL_CFG_2_5G 0x031d
--#define VEND1_GLOBAL_CFG_5G 0x031e
--#define VEND1_GLOBAL_CFG_10G 0x031f
--/* ...and now the fields */
--#define VEND1_GLOBAL_CFG_RATE_ADAPT GENMASK(8, 7)
--#define VEND1_GLOBAL_CFG_RATE_ADAPT_NONE 0
--#define VEND1_GLOBAL_CFG_RATE_ADAPT_USX 1
--#define VEND1_GLOBAL_CFG_RATE_ADAPT_PAUSE 2
--
--#define VEND1_GLOBAL_RSVD_STAT1 0xc885
--#define VEND1_GLOBAL_RSVD_STAT1_FW_BUILD_ID GENMASK(7, 4)
--#define VEND1_GLOBAL_RSVD_STAT1_PROV_ID GENMASK(3, 0)
--
--#define VEND1_GLOBAL_RSVD_STAT9 0xc88d
--#define VEND1_GLOBAL_RSVD_STAT9_MODE GENMASK(7, 0)
--#define VEND1_GLOBAL_RSVD_STAT9_1000BT2 0x23
--
--#define VEND1_GLOBAL_INT_STD_STATUS 0xfc00
--#define VEND1_GLOBAL_INT_VEND_STATUS 0xfc01
--
--#define VEND1_GLOBAL_INT_STD_MASK 0xff00
--#define VEND1_GLOBAL_INT_STD_MASK_PMA1 BIT(15)
--#define VEND1_GLOBAL_INT_STD_MASK_PMA2 BIT(14)
--#define VEND1_GLOBAL_INT_STD_MASK_PCS1 BIT(13)
--#define VEND1_GLOBAL_INT_STD_MASK_PCS2 BIT(12)
--#define VEND1_GLOBAL_INT_STD_MASK_PCS3 BIT(11)
--#define VEND1_GLOBAL_INT_STD_MASK_PHY_XS1 BIT(10)
--#define VEND1_GLOBAL_INT_STD_MASK_PHY_XS2 BIT(9)
--#define VEND1_GLOBAL_INT_STD_MASK_AN1 BIT(8)
--#define VEND1_GLOBAL_INT_STD_MASK_AN2 BIT(7)
--#define VEND1_GLOBAL_INT_STD_MASK_GBE BIT(6)
--#define VEND1_GLOBAL_INT_STD_MASK_ALL BIT(0)
--
--#define VEND1_GLOBAL_INT_VEND_MASK 0xff01
--#define VEND1_GLOBAL_INT_VEND_MASK_PMA BIT(15)
--#define VEND1_GLOBAL_INT_VEND_MASK_PCS BIT(14)
--#define VEND1_GLOBAL_INT_VEND_MASK_PHY_XS BIT(13)
--#define VEND1_GLOBAL_INT_VEND_MASK_AN BIT(12)
--#define VEND1_GLOBAL_INT_VEND_MASK_GBE BIT(11)
--#define VEND1_GLOBAL_INT_VEND_MASK_GLOBAL1 BIT(2)
--#define VEND1_GLOBAL_INT_VEND_MASK_GLOBAL2 BIT(1)
--#define VEND1_GLOBAL_INT_VEND_MASK_GLOBAL3 BIT(0)
--
--/* Sleep and timeout for checking if the Processor-Intensive
-- * MDIO operation is finished
-- */
--#define AQR107_OP_IN_PROG_SLEEP 1000
--#define AQR107_OP_IN_PROG_TIMEOUT 100000
--
--struct aqr107_hw_stat {
-- const char *name;
-- int reg;
-- int size;
--};
--
--#define SGMII_STAT(n, r, s) { n, MDIO_C22EXT_STAT_SGMII_ ## r, s }
--static const struct aqr107_hw_stat aqr107_hw_stats[] = {
-- SGMII_STAT("sgmii_rx_good_frames", RX_GOOD_FRAMES, 26),
-- SGMII_STAT("sgmii_rx_bad_frames", RX_BAD_FRAMES, 26),
-- SGMII_STAT("sgmii_rx_false_carrier_events", RX_FALSE_CARRIER, 8),
-- SGMII_STAT("sgmii_tx_good_frames", TX_GOOD_FRAMES, 26),
-- SGMII_STAT("sgmii_tx_bad_frames", TX_BAD_FRAMES, 26),
-- SGMII_STAT("sgmii_tx_false_carrier_events", TX_FALSE_CARRIER, 8),
-- SGMII_STAT("sgmii_tx_collisions", TX_COLLISIONS, 8),
-- SGMII_STAT("sgmii_tx_line_collisions", TX_LINE_COLLISIONS, 8),
-- SGMII_STAT("sgmii_tx_frame_alignment_err", TX_FRAME_ALIGN_ERR, 16),
-- SGMII_STAT("sgmii_tx_runt_frames", TX_RUNT_FRAMES, 22),
--};
--#define AQR107_SGMII_STAT_SZ ARRAY_SIZE(aqr107_hw_stats)
--
--struct aqr107_priv {
-- u64 sgmii_stats[AQR107_SGMII_STAT_SZ];
--};
--
--static int aqr107_get_sset_count(struct phy_device *phydev)
--{
-- return AQR107_SGMII_STAT_SZ;
--}
--
--static void aqr107_get_strings(struct phy_device *phydev, u8 *data)
--{
-- int i;
--
-- for (i = 0; i < AQR107_SGMII_STAT_SZ; i++)
-- strscpy(data + i * ETH_GSTRING_LEN, aqr107_hw_stats[i].name,
-- ETH_GSTRING_LEN);
--}
--
--static u64 aqr107_get_stat(struct phy_device *phydev, int index)
--{
-- const struct aqr107_hw_stat *stat = aqr107_hw_stats + index;
-- int len_l = min(stat->size, 16);
-- int len_h = stat->size - len_l;
-- u64 ret;
-- int val;
--
-- val = phy_read_mmd(phydev, MDIO_MMD_C22EXT, stat->reg);
-- if (val < 0)
-- return U64_MAX;
--
-- ret = val & GENMASK(len_l - 1, 0);
-- if (len_h) {
-- val = phy_read_mmd(phydev, MDIO_MMD_C22EXT, stat->reg + 1);
-- if (val < 0)
-- return U64_MAX;
--
-- ret += (val & GENMASK(len_h - 1, 0)) << 16;
-- }
--
-- return ret;
--}
--
--static void aqr107_get_stats(struct phy_device *phydev,
-- struct ethtool_stats *stats, u64 *data)
--{
-- struct aqr107_priv *priv = phydev->priv;
-- u64 val;
-- int i;
--
-- for (i = 0; i < AQR107_SGMII_STAT_SZ; i++) {
-- val = aqr107_get_stat(phydev, i);
-- if (val == U64_MAX)
-- phydev_err(phydev, "Reading HW Statistics failed for %s\n",
-- aqr107_hw_stats[i].name);
-- else
-- priv->sgmii_stats[i] += val;
--
-- data[i] = priv->sgmii_stats[i];
-- }
--}
--
--static int aqr_config_aneg(struct phy_device *phydev)
--{
-- bool changed = false;
-- u16 reg;
-- int ret;
--
-- if (phydev->autoneg == AUTONEG_DISABLE)
-- return genphy_c45_pma_setup_forced(phydev);
--
-- ret = genphy_c45_an_config_aneg(phydev);
-- if (ret < 0)
-- return ret;
-- if (ret > 0)
-- changed = true;
--
-- /* Clause 45 has no standardized support for 1000BaseT, therefore
-- * use vendor registers for this mode.
-- */
-- reg = 0;
-- if (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
-- phydev->advertising))
-- reg |= MDIO_AN_VEND_PROV_1000BASET_FULL;
--
-- if (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT,
-- phydev->advertising))
-- reg |= MDIO_AN_VEND_PROV_1000BASET_HALF;
--
-- /* Handle the case when the 2.5G and 5G speeds are not advertised */
-- if (linkmode_test_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
-- phydev->advertising))
-- reg |= MDIO_AN_VEND_PROV_2500BASET_FULL;
--
-- if (linkmode_test_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT,
-- phydev->advertising))
-- reg |= MDIO_AN_VEND_PROV_5000BASET_FULL;
--
-- ret = phy_modify_mmd_changed(phydev, MDIO_MMD_AN, MDIO_AN_VEND_PROV,
-- MDIO_AN_VEND_PROV_1000BASET_HALF |
-- MDIO_AN_VEND_PROV_1000BASET_FULL |
-- MDIO_AN_VEND_PROV_2500BASET_FULL |
-- MDIO_AN_VEND_PROV_5000BASET_FULL, reg);
-- if (ret < 0)
-- return ret;
-- if (ret > 0)
-- changed = true;
--
-- return genphy_c45_check_and_restart_aneg(phydev, changed);
--}
--
--static int aqr_config_intr(struct phy_device *phydev)
--{
-- bool en = phydev->interrupts == PHY_INTERRUPT_ENABLED;
-- int err;
--
-- if (en) {
-- /* Clear any pending interrupts before enabling them */
-- err = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_TX_VEND_INT_STATUS2);
-- if (err < 0)
-- return err;
-- }
--
-- err = phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_TX_VEND_INT_MASK2,
-- en ? MDIO_AN_TX_VEND_INT_MASK2_LINK : 0);
-- if (err < 0)
-- return err;
--
-- err = phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLOBAL_INT_STD_MASK,
-- en ? VEND1_GLOBAL_INT_STD_MASK_ALL : 0);
-- if (err < 0)
-- return err;
--
-- err = phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLOBAL_INT_VEND_MASK,
-- en ? VEND1_GLOBAL_INT_VEND_MASK_GLOBAL3 |
-- VEND1_GLOBAL_INT_VEND_MASK_AN : 0);
-- if (err < 0)
-- return err;
--
-- if (!en) {
-- /* Clear any pending interrupts after we have disabled them */
-- err = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_TX_VEND_INT_STATUS2);
-- if (err < 0)
-- return err;
-- }
--
-- return 0;
--}
--
--static irqreturn_t aqr_handle_interrupt(struct phy_device *phydev)
--{
-- int irq_status;
--
-- irq_status = phy_read_mmd(phydev, MDIO_MMD_AN,
-- MDIO_AN_TX_VEND_INT_STATUS2);
-- if (irq_status < 0) {
-- phy_error(phydev);
-- return IRQ_NONE;
-- }
--
-- if (!(irq_status & MDIO_AN_TX_VEND_INT_STATUS2_MASK))
-- return IRQ_NONE;
--
-- phy_trigger_machine(phydev);
--
-- return IRQ_HANDLED;
--}
--
--static int aqr_read_status(struct phy_device *phydev)
--{
-- int val;
--
-- if (phydev->autoneg == AUTONEG_ENABLE) {
-- val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_RX_LP_STAT1);
-- if (val < 0)
-- return val;
--
-- linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
-- phydev->lp_advertising,
-- val & MDIO_AN_RX_LP_STAT1_1000BASET_FULL);
-- linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT,
-- phydev->lp_advertising,
-- val & MDIO_AN_RX_LP_STAT1_1000BASET_HALF);
-- }
--
-- return genphy_c45_read_status(phydev);
--}
--
--static int aqr107_read_rate(struct phy_device *phydev)
--{
-- u32 config_reg;
-- int val;
--
-- val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_TX_VEND_STATUS1);
-- if (val < 0)
-- return val;
--
-- if (val & MDIO_AN_TX_VEND_STATUS1_FULL_DUPLEX)
-- phydev->duplex = DUPLEX_FULL;
-- else
-- phydev->duplex = DUPLEX_HALF;
--
-- switch (FIELD_GET(MDIO_AN_TX_VEND_STATUS1_RATE_MASK, val)) {
-- case MDIO_AN_TX_VEND_STATUS1_10BASET:
-- phydev->speed = SPEED_10;
-- config_reg = VEND1_GLOBAL_CFG_10M;
-- break;
-- case MDIO_AN_TX_VEND_STATUS1_100BASETX:
-- phydev->speed = SPEED_100;
-- config_reg = VEND1_GLOBAL_CFG_100M;
-- break;
-- case MDIO_AN_TX_VEND_STATUS1_1000BASET:
-- phydev->speed = SPEED_1000;
-- config_reg = VEND1_GLOBAL_CFG_1G;
-- break;
-- case MDIO_AN_TX_VEND_STATUS1_2500BASET:
-- phydev->speed = SPEED_2500;
-- config_reg = VEND1_GLOBAL_CFG_2_5G;
-- break;
-- case MDIO_AN_TX_VEND_STATUS1_5000BASET:
-- phydev->speed = SPEED_5000;
-- config_reg = VEND1_GLOBAL_CFG_5G;
-- break;
-- case MDIO_AN_TX_VEND_STATUS1_10GBASET:
-- phydev->speed = SPEED_10000;
-- config_reg = VEND1_GLOBAL_CFG_10G;
-- break;
-- default:
-- phydev->speed = SPEED_UNKNOWN;
-- return 0;
-- }
--
-- val = phy_read_mmd(phydev, MDIO_MMD_VEND1, config_reg);
-- if (val < 0)
-- return val;
--
-- if (FIELD_GET(VEND1_GLOBAL_CFG_RATE_ADAPT, val) ==
-- VEND1_GLOBAL_CFG_RATE_ADAPT_PAUSE)
-- phydev->rate_matching = RATE_MATCH_PAUSE;
-- else
-- phydev->rate_matching = RATE_MATCH_NONE;
--
-- return 0;
--}
--
--static int aqr107_read_status(struct phy_device *phydev)
--{
-- int val, ret;
--
-- ret = aqr_read_status(phydev);
-- if (ret)
-- return ret;
--
-- if (!phydev->link || phydev->autoneg == AUTONEG_DISABLE)
-- return 0;
--
-- val = phy_read_mmd(phydev, MDIO_MMD_PHYXS, MDIO_PHYXS_VEND_IF_STATUS);
-- if (val < 0)
-- return val;
--
-- switch (FIELD_GET(MDIO_PHYXS_VEND_IF_STATUS_TYPE_MASK, val)) {
-- case MDIO_PHYXS_VEND_IF_STATUS_TYPE_KR:
-- phydev->interface = PHY_INTERFACE_MODE_10GKR;
-- break;
-- case MDIO_PHYXS_VEND_IF_STATUS_TYPE_KX:
-- phydev->interface = PHY_INTERFACE_MODE_1000BASEKX;
-- break;
-- case MDIO_PHYXS_VEND_IF_STATUS_TYPE_XFI:
-- phydev->interface = PHY_INTERFACE_MODE_10GBASER;
-- break;
-- case MDIO_PHYXS_VEND_IF_STATUS_TYPE_USXGMII:
-- phydev->interface = PHY_INTERFACE_MODE_USXGMII;
-- break;
-- case MDIO_PHYXS_VEND_IF_STATUS_TYPE_XAUI:
-- phydev->interface = PHY_INTERFACE_MODE_XAUI;
-- break;
-- case MDIO_PHYXS_VEND_IF_STATUS_TYPE_SGMII:
-- phydev->interface = PHY_INTERFACE_MODE_SGMII;
-- break;
-- case MDIO_PHYXS_VEND_IF_STATUS_TYPE_RXAUI:
-- phydev->interface = PHY_INTERFACE_MODE_RXAUI;
-- break;
-- case MDIO_PHYXS_VEND_IF_STATUS_TYPE_OCSGMII:
-- phydev->interface = PHY_INTERFACE_MODE_2500BASEX;
-- break;
-- default:
-- phydev->interface = PHY_INTERFACE_MODE_NA;
-- break;
-- }
--
-- /* Read possibly downshifted rate from vendor register */
-- return aqr107_read_rate(phydev);
--}
--
--static int aqr107_get_downshift(struct phy_device *phydev, u8 *data)
--{
-- int val, cnt, enable;
--
-- val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_VEND_PROV);
-- if (val < 0)
-- return val;
--
-- enable = FIELD_GET(MDIO_AN_VEND_PROV_DOWNSHIFT_EN, val);
-- cnt = FIELD_GET(MDIO_AN_VEND_PROV_DOWNSHIFT_MASK, val);
--
-- *data = enable && cnt ? cnt : DOWNSHIFT_DEV_DISABLE;
--
-- return 0;
--}
--
--static int aqr107_set_downshift(struct phy_device *phydev, u8 cnt)
--{
-- int val = 0;
--
-- if (!FIELD_FIT(MDIO_AN_VEND_PROV_DOWNSHIFT_MASK, cnt))
-- return -E2BIG;
--
-- if (cnt != DOWNSHIFT_DEV_DISABLE) {
-- val = MDIO_AN_VEND_PROV_DOWNSHIFT_EN;
-- val |= FIELD_PREP(MDIO_AN_VEND_PROV_DOWNSHIFT_MASK, cnt);
-- }
--
-- return phy_modify_mmd(phydev, MDIO_MMD_AN, MDIO_AN_VEND_PROV,
-- MDIO_AN_VEND_PROV_DOWNSHIFT_EN |
-- MDIO_AN_VEND_PROV_DOWNSHIFT_MASK, val);
--}
--
--static int aqr107_get_tunable(struct phy_device *phydev,
-- struct ethtool_tunable *tuna, void *data)
--{
-- switch (tuna->id) {
-- case ETHTOOL_PHY_DOWNSHIFT:
-- return aqr107_get_downshift(phydev, data);
-- default:
-- return -EOPNOTSUPP;
-- }
--}
--
--static int aqr107_set_tunable(struct phy_device *phydev,
-- struct ethtool_tunable *tuna, const void *data)
--{
-- switch (tuna->id) {
-- case ETHTOOL_PHY_DOWNSHIFT:
-- return aqr107_set_downshift(phydev, *(const u8 *)data);
-- default:
-- return -EOPNOTSUPP;
-- }
--}
--
--/* If we configure settings whilst firmware is still initializing the chip,
-- * then these settings may be overwritten. Therefore make sure chip
-- * initialization has completed. Use presence of the firmware ID as
-- * indicator for initialization having completed.
-- * The chip also provides a "reset completed" bit, but it's cleared after
-- * read. Therefore function would time out if called again.
-- */
--static int aqr107_wait_reset_complete(struct phy_device *phydev)
--{
-- int val;
--
-- return phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND1,
-- VEND1_GLOBAL_FW_ID, val, val != 0,
-- 20000, 2000000, false);
--}
--
--static void aqr107_chip_info(struct phy_device *phydev)
--{
-- u8 fw_major, fw_minor, build_id, prov_id;
-- int val;
--
-- val = phy_read_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLOBAL_FW_ID);
-- if (val < 0)
-- return;
--
-- fw_major = FIELD_GET(VEND1_GLOBAL_FW_ID_MAJOR, val);
-- fw_minor = FIELD_GET(VEND1_GLOBAL_FW_ID_MINOR, val);
--
-- val = phy_read_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLOBAL_RSVD_STAT1);
-- if (val < 0)
-- return;
--
-- build_id = FIELD_GET(VEND1_GLOBAL_RSVD_STAT1_FW_BUILD_ID, val);
-- prov_id = FIELD_GET(VEND1_GLOBAL_RSVD_STAT1_PROV_ID, val);
--
-- phydev_dbg(phydev, "FW %u.%u, Build %u, Provisioning %u\n",
-- fw_major, fw_minor, build_id, prov_id);
--}
--
--static int aqr107_config_init(struct phy_device *phydev)
--{
-- int ret;
--
-- /* Check that the PHY interface type is compatible */
-- if (phydev->interface != PHY_INTERFACE_MODE_SGMII &&
-- phydev->interface != PHY_INTERFACE_MODE_1000BASEKX &&
-- phydev->interface != PHY_INTERFACE_MODE_2500BASEX &&
-- phydev->interface != PHY_INTERFACE_MODE_XGMII &&
-- phydev->interface != PHY_INTERFACE_MODE_USXGMII &&
-- phydev->interface != PHY_INTERFACE_MODE_10GKR &&
-- phydev->interface != PHY_INTERFACE_MODE_10GBASER &&
-- phydev->interface != PHY_INTERFACE_MODE_XAUI &&
-- phydev->interface != PHY_INTERFACE_MODE_RXAUI)
-- return -ENODEV;
--
-- WARN(phydev->interface == PHY_INTERFACE_MODE_XGMII,
-- "Your devicetree is out of date, please update it. The AQR107 family doesn't support XGMII, maybe you mean USXGMII.\n");
--
-- ret = aqr107_wait_reset_complete(phydev);
-- if (!ret)
-- aqr107_chip_info(phydev);
--
-- return aqr107_set_downshift(phydev, MDIO_AN_VEND_PROV_DOWNSHIFT_DFLT);
--}
--
--static int aqcs109_config_init(struct phy_device *phydev)
--{
-- int ret;
--
-- /* Check that the PHY interface type is compatible */
-- if (phydev->interface != PHY_INTERFACE_MODE_SGMII &&
-- phydev->interface != PHY_INTERFACE_MODE_2500BASEX)
-- return -ENODEV;
--
-- ret = aqr107_wait_reset_complete(phydev);
-- if (!ret)
-- aqr107_chip_info(phydev);
--
-- /* AQCS109 belongs to a chip family partially supporting 10G and 5G.
-- * PMA speed ability bits are the same for all members of the family,
-- * AQCS109 however supports speeds up to 2.5G only.
-- */
-- phy_set_max_speed(phydev, SPEED_2500);
--
-- return aqr107_set_downshift(phydev, MDIO_AN_VEND_PROV_DOWNSHIFT_DFLT);
--}
--
--static void aqr107_link_change_notify(struct phy_device *phydev)
--{
-- u8 fw_major, fw_minor;
-- bool downshift, short_reach, afr;
-- int mode, val;
--
-- if (phydev->state != PHY_RUNNING || phydev->autoneg == AUTONEG_DISABLE)
-- return;
--
-- val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_RX_LP_STAT1);
-- /* call failed or link partner is no Aquantia PHY */
-- if (val < 0 || !(val & MDIO_AN_RX_LP_STAT1_AQ_PHY))
-- return;
--
-- short_reach = val & MDIO_AN_RX_LP_STAT1_SHORT_REACH;
-- downshift = val & MDIO_AN_RX_LP_STAT1_AQRATE_DOWNSHIFT;
--
-- val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_RX_LP_STAT4);
-- if (val < 0)
-- return;
--
-- fw_major = FIELD_GET(MDIO_AN_RX_LP_STAT4_FW_MAJOR, val);
-- fw_minor = FIELD_GET(MDIO_AN_RX_LP_STAT4_FW_MINOR, val);
--
-- val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_RX_VEND_STAT3);
-- if (val < 0)
-- return;
--
-- afr = val & MDIO_AN_RX_VEND_STAT3_AFR;
--
-- phydev_dbg(phydev, "Link partner is Aquantia PHY, FW %u.%u%s%s%s\n",
-- fw_major, fw_minor,
-- short_reach ? ", short reach mode" : "",
-- downshift ? ", fast-retrain downshift advertised" : "",
-- afr ? ", fast reframe advertised" : "");
--
-- val = phy_read_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLOBAL_RSVD_STAT9);
-- if (val < 0)
-- return;
--
-- mode = FIELD_GET(VEND1_GLOBAL_RSVD_STAT9_MODE, val);
-- if (mode == VEND1_GLOBAL_RSVD_STAT9_1000BT2)
-- phydev_info(phydev, "Aquantia 1000Base-T2 mode active\n");
--}
--
--static int aqr107_wait_processor_intensive_op(struct phy_device *phydev)
--{
-- int val, err;
--
-- /* The datasheet notes to wait at least 1ms after issuing a
-- * processor intensive operation before checking.
-- * We cannot use the 'sleep_before_read' parameter of read_poll_timeout
-- * because that just determines the maximum time slept, not the minimum.
-- */
-- usleep_range(1000, 5000);
--
-- err = phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND1,
-- VEND1_GLOBAL_GEN_STAT2, val,
-- !(val & VEND1_GLOBAL_GEN_STAT2_OP_IN_PROG),
-- AQR107_OP_IN_PROG_SLEEP,
-- AQR107_OP_IN_PROG_TIMEOUT, false);
-- if (err) {
-- phydev_err(phydev, "timeout: processor-intensive MDIO operation\n");
-- return err;
-- }
--
-- return 0;
--}
--
--static int aqr107_get_rate_matching(struct phy_device *phydev,
-- phy_interface_t iface)
--{
-- if (iface == PHY_INTERFACE_MODE_10GBASER ||
-- iface == PHY_INTERFACE_MODE_2500BASEX ||
-- iface == PHY_INTERFACE_MODE_NA)
-- return RATE_MATCH_PAUSE;
-- return RATE_MATCH_NONE;
--}
--
--static int aqr107_suspend(struct phy_device *phydev)
--{
-- int err;
--
-- err = phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MDIO_CTRL1,
-- MDIO_CTRL1_LPOWER);
-- if (err)
-- return err;
--
-- return aqr107_wait_processor_intensive_op(phydev);
--}
--
--static int aqr107_resume(struct phy_device *phydev)
--{
-- int err;
--
-- err = phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MDIO_CTRL1,
-- MDIO_CTRL1_LPOWER);
-- if (err)
-- return err;
--
-- return aqr107_wait_processor_intensive_op(phydev);
--}
--
--static int aqr107_probe(struct phy_device *phydev)
--{
-- phydev->priv = devm_kzalloc(&phydev->mdio.dev,
-- sizeof(struct aqr107_priv), GFP_KERNEL);
-- if (!phydev->priv)
-- return -ENOMEM;
--
-- return aqr_hwmon_probe(phydev);
--}
--
--static struct phy_driver aqr_driver[] = {
--{
-- PHY_ID_MATCH_MODEL(PHY_ID_AQ1202),
-- .name = "Aquantia AQ1202",
-- .config_aneg = aqr_config_aneg,
-- .config_intr = aqr_config_intr,
-- .handle_interrupt = aqr_handle_interrupt,
-- .read_status = aqr_read_status,
--},
--{
-- PHY_ID_MATCH_MODEL(PHY_ID_AQ2104),
-- .name = "Aquantia AQ2104",
-- .config_aneg = aqr_config_aneg,
-- .config_intr = aqr_config_intr,
-- .handle_interrupt = aqr_handle_interrupt,
-- .read_status = aqr_read_status,
--},
--{
-- PHY_ID_MATCH_MODEL(PHY_ID_AQR105),
-- .name = "Aquantia AQR105",
-- .config_aneg = aqr_config_aneg,
-- .config_intr = aqr_config_intr,
-- .handle_interrupt = aqr_handle_interrupt,
-- .read_status = aqr_read_status,
-- .suspend = aqr107_suspend,
-- .resume = aqr107_resume,
--},
--{
-- PHY_ID_MATCH_MODEL(PHY_ID_AQR106),
-- .name = "Aquantia AQR106",
-- .config_aneg = aqr_config_aneg,
-- .config_intr = aqr_config_intr,
-- .handle_interrupt = aqr_handle_interrupt,
-- .read_status = aqr_read_status,
--},
--{
-- PHY_ID_MATCH_MODEL(PHY_ID_AQR107),
-- .name = "Aquantia AQR107",
-- .probe = aqr107_probe,
-- .get_rate_matching = aqr107_get_rate_matching,
-- .config_init = aqr107_config_init,
-- .config_aneg = aqr_config_aneg,
-- .config_intr = aqr_config_intr,
-- .handle_interrupt = aqr_handle_interrupt,
-- .read_status = aqr107_read_status,
-- .get_tunable = aqr107_get_tunable,
-- .set_tunable = aqr107_set_tunable,
-- .suspend = aqr107_suspend,
-- .resume = aqr107_resume,
-- .get_sset_count = aqr107_get_sset_count,
-- .get_strings = aqr107_get_strings,
-- .get_stats = aqr107_get_stats,
-- .link_change_notify = aqr107_link_change_notify,
--},
--{
-- PHY_ID_MATCH_MODEL(PHY_ID_AQCS109),
-- .name = "Aquantia AQCS109",
-- .probe = aqr107_probe,
-- .get_rate_matching = aqr107_get_rate_matching,
-- .config_init = aqcs109_config_init,
-- .config_aneg = aqr_config_aneg,
-- .config_intr = aqr_config_intr,
-- .handle_interrupt = aqr_handle_interrupt,
-- .read_status = aqr107_read_status,
-- .get_tunable = aqr107_get_tunable,
-- .set_tunable = aqr107_set_tunable,
-- .suspend = aqr107_suspend,
-- .resume = aqr107_resume,
-- .get_sset_count = aqr107_get_sset_count,
-- .get_strings = aqr107_get_strings,
-- .get_stats = aqr107_get_stats,
-- .link_change_notify = aqr107_link_change_notify,
--},
--{
-- PHY_ID_MATCH_MODEL(PHY_ID_AQR405),
-- .name = "Aquantia AQR405",
-- .config_aneg = aqr_config_aneg,
-- .config_intr = aqr_config_intr,
-- .handle_interrupt = aqr_handle_interrupt,
-- .read_status = aqr_read_status,
--},
--{
-- PHY_ID_MATCH_MODEL(PHY_ID_AQR112),
-- .name = "Aquantia AQR112",
-- .probe = aqr107_probe,
-- .config_aneg = aqr_config_aneg,
-- .config_intr = aqr_config_intr,
-- .handle_interrupt = aqr_handle_interrupt,
-- .get_tunable = aqr107_get_tunable,
-- .set_tunable = aqr107_set_tunable,
-- .suspend = aqr107_suspend,
-- .resume = aqr107_resume,
-- .read_status = aqr107_read_status,
-- .get_rate_matching = aqr107_get_rate_matching,
-- .get_sset_count = aqr107_get_sset_count,
-- .get_strings = aqr107_get_strings,
-- .get_stats = aqr107_get_stats,
-- .link_change_notify = aqr107_link_change_notify,
--},
--{
-- PHY_ID_MATCH_MODEL(PHY_ID_AQR412),
-- .name = "Aquantia AQR412",
-- .probe = aqr107_probe,
-- .config_aneg = aqr_config_aneg,
-- .config_intr = aqr_config_intr,
-- .handle_interrupt = aqr_handle_interrupt,
-- .get_tunable = aqr107_get_tunable,
-- .set_tunable = aqr107_set_tunable,
-- .suspend = aqr107_suspend,
-- .resume = aqr107_resume,
-- .read_status = aqr107_read_status,
-- .get_rate_matching = aqr107_get_rate_matching,
-- .get_sset_count = aqr107_get_sset_count,
-- .get_strings = aqr107_get_strings,
-- .get_stats = aqr107_get_stats,
-- .link_change_notify = aqr107_link_change_notify,
--},
--{
-- PHY_ID_MATCH_MODEL(PHY_ID_AQR113C),
-- .name = "Aquantia AQR113C",
-- .probe = aqr107_probe,
-- .get_rate_matching = aqr107_get_rate_matching,
-- .config_init = aqr107_config_init,
-- .config_aneg = aqr_config_aneg,
-- .config_intr = aqr_config_intr,
-- .handle_interrupt = aqr_handle_interrupt,
-- .read_status = aqr107_read_status,
-- .get_tunable = aqr107_get_tunable,
-- .set_tunable = aqr107_set_tunable,
-- .suspend = aqr107_suspend,
-- .resume = aqr107_resume,
-- .get_sset_count = aqr107_get_sset_count,
-- .get_strings = aqr107_get_strings,
-- .get_stats = aqr107_get_stats,
-- .link_change_notify = aqr107_link_change_notify,
--},
--};
--
--module_phy_driver(aqr_driver);
--
--static struct mdio_device_id __maybe_unused aqr_tbl[] = {
-- { PHY_ID_MATCH_MODEL(PHY_ID_AQ1202) },
-- { PHY_ID_MATCH_MODEL(PHY_ID_AQ2104) },
-- { PHY_ID_MATCH_MODEL(PHY_ID_AQR105) },
-- { PHY_ID_MATCH_MODEL(PHY_ID_AQR106) },
-- { PHY_ID_MATCH_MODEL(PHY_ID_AQR107) },
-- { PHY_ID_MATCH_MODEL(PHY_ID_AQCS109) },
-- { PHY_ID_MATCH_MODEL(PHY_ID_AQR405) },
-- { PHY_ID_MATCH_MODEL(PHY_ID_AQR112) },
-- { PHY_ID_MATCH_MODEL(PHY_ID_AQR412) },
-- { PHY_ID_MATCH_MODEL(PHY_ID_AQR113C) },
-- { }
--};
--
--MODULE_DEVICE_TABLE(mdio, aqr_tbl);
--
--MODULE_DESCRIPTION("Aquantia PHY driver");
--MODULE_LICENSE("GPL v2");
+++ /dev/null
-From e1fbfa4a995d42e02e22b0dff2f8b4fdee1504b3 Mon Sep 17 00:00:00 2001
-Date: Tue, 14 Nov 2023 15:08:42 +0100
-Subject: [PATCH 2/3] net: phy: aquantia: move MMD_VEND define to header
-
-Move MMD_VEND define to header to clean things up and in preparation for
-firmware loading support that require some define placed in
-aquantia_main.
-
----
- drivers/net/phy/aquantia/aquantia.h | 69 +++++++++++++++++++++++
- drivers/net/phy/aquantia/aquantia_hwmon.c | 14 -----
- drivers/net/phy/aquantia/aquantia_main.c | 55 ------------------
- 3 files changed, 69 insertions(+), 69 deletions(-)
-
---- a/drivers/net/phy/aquantia/aquantia.h
-+++ b/drivers/net/phy/aquantia/aquantia.h
-@@ -9,6 +9,75 @@
- #include <linux/device.h>
- #include <linux/phy.h>
-
-+/* Vendor specific 1, MDIO_MMD_VEND1 */
-+#define VEND1_GLOBAL_FW_ID 0x0020
-+#define VEND1_GLOBAL_FW_ID_MAJOR GENMASK(15, 8)
-+#define VEND1_GLOBAL_FW_ID_MINOR GENMASK(7, 0)
-+
-+/* The following registers all have similar layouts; first the registers... */
-+#define VEND1_GLOBAL_CFG_10M 0x0310
-+#define VEND1_GLOBAL_CFG_100M 0x031b
-+#define VEND1_GLOBAL_CFG_1G 0x031c
-+#define VEND1_GLOBAL_CFG_2_5G 0x031d
-+#define VEND1_GLOBAL_CFG_5G 0x031e
-+#define VEND1_GLOBAL_CFG_10G 0x031f
-+/* ...and now the fields */
-+#define VEND1_GLOBAL_CFG_RATE_ADAPT GENMASK(8, 7)
-+#define VEND1_GLOBAL_CFG_RATE_ADAPT_NONE 0
-+#define VEND1_GLOBAL_CFG_RATE_ADAPT_USX 1
-+#define VEND1_GLOBAL_CFG_RATE_ADAPT_PAUSE 2
-+
-+/* Vendor specific 1, MDIO_MMD_VEND2 */
-+#define VEND1_THERMAL_PROV_HIGH_TEMP_FAIL 0xc421
-+#define VEND1_THERMAL_PROV_LOW_TEMP_FAIL 0xc422
-+#define VEND1_THERMAL_PROV_HIGH_TEMP_WARN 0xc423
-+#define VEND1_THERMAL_PROV_LOW_TEMP_WARN 0xc424
-+#define VEND1_THERMAL_STAT1 0xc820
-+#define VEND1_THERMAL_STAT2 0xc821
-+#define VEND1_THERMAL_STAT2_VALID BIT(0)
-+#define VEND1_GENERAL_STAT1 0xc830
-+#define VEND1_GENERAL_STAT1_HIGH_TEMP_FAIL BIT(14)
-+#define VEND1_GENERAL_STAT1_LOW_TEMP_FAIL BIT(13)
-+#define VEND1_GENERAL_STAT1_HIGH_TEMP_WARN BIT(12)
-+#define VEND1_GENERAL_STAT1_LOW_TEMP_WARN BIT(11)
-+
-+#define VEND1_GLOBAL_GEN_STAT2 0xc831
-+#define VEND1_GLOBAL_GEN_STAT2_OP_IN_PROG BIT(15)
-+
-+#define VEND1_GLOBAL_RSVD_STAT1 0xc885
-+#define VEND1_GLOBAL_RSVD_STAT1_FW_BUILD_ID GENMASK(7, 4)
-+#define VEND1_GLOBAL_RSVD_STAT1_PROV_ID GENMASK(3, 0)
-+
-+#define VEND1_GLOBAL_RSVD_STAT9 0xc88d
-+#define VEND1_GLOBAL_RSVD_STAT9_MODE GENMASK(7, 0)
-+#define VEND1_GLOBAL_RSVD_STAT9_1000BT2 0x23
-+
-+#define VEND1_GLOBAL_INT_STD_STATUS 0xfc00
-+#define VEND1_GLOBAL_INT_VEND_STATUS 0xfc01
-+
-+#define VEND1_GLOBAL_INT_STD_MASK 0xff00
-+#define VEND1_GLOBAL_INT_STD_MASK_PMA1 BIT(15)
-+#define VEND1_GLOBAL_INT_STD_MASK_PMA2 BIT(14)
-+#define VEND1_GLOBAL_INT_STD_MASK_PCS1 BIT(13)
-+#define VEND1_GLOBAL_INT_STD_MASK_PCS2 BIT(12)
-+#define VEND1_GLOBAL_INT_STD_MASK_PCS3 BIT(11)
-+#define VEND1_GLOBAL_INT_STD_MASK_PHY_XS1 BIT(10)
-+#define VEND1_GLOBAL_INT_STD_MASK_PHY_XS2 BIT(9)
-+#define VEND1_GLOBAL_INT_STD_MASK_AN1 BIT(8)
-+#define VEND1_GLOBAL_INT_STD_MASK_AN2 BIT(7)
-+#define VEND1_GLOBAL_INT_STD_MASK_GBE BIT(6)
-+#define VEND1_GLOBAL_INT_STD_MASK_ALL BIT(0)
-+
-+#define VEND1_GLOBAL_INT_VEND_MASK 0xff01
-+#define VEND1_GLOBAL_INT_VEND_MASK_PMA BIT(15)
-+#define VEND1_GLOBAL_INT_VEND_MASK_PCS BIT(14)
-+#define VEND1_GLOBAL_INT_VEND_MASK_PHY_XS BIT(13)
-+#define VEND1_GLOBAL_INT_VEND_MASK_AN BIT(12)
-+#define VEND1_GLOBAL_INT_VEND_MASK_GBE BIT(11)
-+#define VEND1_GLOBAL_INT_VEND_MASK_GLOBAL1 BIT(2)
-+#define VEND1_GLOBAL_INT_VEND_MASK_GLOBAL2 BIT(1)
-+#define VEND1_GLOBAL_INT_VEND_MASK_GLOBAL3 BIT(0)
-+
- #if IS_REACHABLE(CONFIG_HWMON)
- int aqr_hwmon_probe(struct phy_device *phydev);
- #else
---- a/drivers/net/phy/aquantia/aquantia_hwmon.c
-+++ b/drivers/net/phy/aquantia/aquantia_hwmon.c
-@@ -13,20 +13,6 @@
-
- #include "aquantia.h"
-
--/* Vendor specific 1, MDIO_MMD_VEND2 */
--#define VEND1_THERMAL_PROV_HIGH_TEMP_FAIL 0xc421
--#define VEND1_THERMAL_PROV_LOW_TEMP_FAIL 0xc422
--#define VEND1_THERMAL_PROV_HIGH_TEMP_WARN 0xc423
--#define VEND1_THERMAL_PROV_LOW_TEMP_WARN 0xc424
--#define VEND1_THERMAL_STAT1 0xc820
--#define VEND1_THERMAL_STAT2 0xc821
--#define VEND1_THERMAL_STAT2_VALID BIT(0)
--#define VEND1_GENERAL_STAT1 0xc830
--#define VEND1_GENERAL_STAT1_HIGH_TEMP_FAIL BIT(14)
--#define VEND1_GENERAL_STAT1_LOW_TEMP_FAIL BIT(13)
--#define VEND1_GENERAL_STAT1_HIGH_TEMP_WARN BIT(12)
--#define VEND1_GENERAL_STAT1_LOW_TEMP_WARN BIT(11)
--
- #if IS_REACHABLE(CONFIG_HWMON)
-
- static umode_t aqr_hwmon_is_visible(const void *data,
---- a/drivers/net/phy/aquantia/aquantia_main.c
-+++ b/drivers/net/phy/aquantia/aquantia_main.c
-@@ -91,61 +91,6 @@
- #define MDIO_C22EXT_STAT_SGMII_TX_FRAME_ALIGN_ERR 0xd31a
- #define MDIO_C22EXT_STAT_SGMII_TX_RUNT_FRAMES 0xd31b
-
--/* Vendor specific 1, MDIO_MMD_VEND1 */
--#define VEND1_GLOBAL_FW_ID 0x0020
--#define VEND1_GLOBAL_FW_ID_MAJOR GENMASK(15, 8)
--#define VEND1_GLOBAL_FW_ID_MINOR GENMASK(7, 0)
--
--#define VEND1_GLOBAL_GEN_STAT2 0xc831
--#define VEND1_GLOBAL_GEN_STAT2_OP_IN_PROG BIT(15)
--
--/* The following registers all have similar layouts; first the registers... */
--#define VEND1_GLOBAL_CFG_10M 0x0310
--#define VEND1_GLOBAL_CFG_100M 0x031b
--#define VEND1_GLOBAL_CFG_1G 0x031c
--#define VEND1_GLOBAL_CFG_2_5G 0x031d
--#define VEND1_GLOBAL_CFG_5G 0x031e
--#define VEND1_GLOBAL_CFG_10G 0x031f
--/* ...and now the fields */
--#define VEND1_GLOBAL_CFG_RATE_ADAPT GENMASK(8, 7)
--#define VEND1_GLOBAL_CFG_RATE_ADAPT_NONE 0
--#define VEND1_GLOBAL_CFG_RATE_ADAPT_USX 1
--#define VEND1_GLOBAL_CFG_RATE_ADAPT_PAUSE 2
--
--#define VEND1_GLOBAL_RSVD_STAT1 0xc885
--#define VEND1_GLOBAL_RSVD_STAT1_FW_BUILD_ID GENMASK(7, 4)
--#define VEND1_GLOBAL_RSVD_STAT1_PROV_ID GENMASK(3, 0)
--
--#define VEND1_GLOBAL_RSVD_STAT9 0xc88d
--#define VEND1_GLOBAL_RSVD_STAT9_MODE GENMASK(7, 0)
--#define VEND1_GLOBAL_RSVD_STAT9_1000BT2 0x23
--
--#define VEND1_GLOBAL_INT_STD_STATUS 0xfc00
--#define VEND1_GLOBAL_INT_VEND_STATUS 0xfc01
--
--#define VEND1_GLOBAL_INT_STD_MASK 0xff00
--#define VEND1_GLOBAL_INT_STD_MASK_PMA1 BIT(15)
--#define VEND1_GLOBAL_INT_STD_MASK_PMA2 BIT(14)
--#define VEND1_GLOBAL_INT_STD_MASK_PCS1 BIT(13)
--#define VEND1_GLOBAL_INT_STD_MASK_PCS2 BIT(12)
--#define VEND1_GLOBAL_INT_STD_MASK_PCS3 BIT(11)
--#define VEND1_GLOBAL_INT_STD_MASK_PHY_XS1 BIT(10)
--#define VEND1_GLOBAL_INT_STD_MASK_PHY_XS2 BIT(9)
--#define VEND1_GLOBAL_INT_STD_MASK_AN1 BIT(8)
--#define VEND1_GLOBAL_INT_STD_MASK_AN2 BIT(7)
--#define VEND1_GLOBAL_INT_STD_MASK_GBE BIT(6)
--#define VEND1_GLOBAL_INT_STD_MASK_ALL BIT(0)
--
--#define VEND1_GLOBAL_INT_VEND_MASK 0xff01
--#define VEND1_GLOBAL_INT_VEND_MASK_PMA BIT(15)
--#define VEND1_GLOBAL_INT_VEND_MASK_PCS BIT(14)
--#define VEND1_GLOBAL_INT_VEND_MASK_PHY_XS BIT(13)
--#define VEND1_GLOBAL_INT_VEND_MASK_AN BIT(12)
--#define VEND1_GLOBAL_INT_VEND_MASK_GBE BIT(11)
--#define VEND1_GLOBAL_INT_VEND_MASK_GLOBAL1 BIT(2)
--#define VEND1_GLOBAL_INT_VEND_MASK_GLOBAL2 BIT(1)
--#define VEND1_GLOBAL_INT_VEND_MASK_GLOBAL3 BIT(0)
--
- /* Sleep and timeout for checking if the Processor-Intensive
- * MDIO operation is finished
- */
+++ /dev/null
-From e93984ebc1c82bd34f7a1b3391efaceee0a8ae96 Mon Sep 17 00:00:00 2001
-Date: Tue, 14 Nov 2023 15:08:43 +0100
-Subject: [PATCH 3/3] net: phy: aquantia: add firmware load support
-
-Aquantia PHY-s require firmware to be loaded before they start operating.
-It can be automatically loaded in case when there is a SPI-NOR connected
-to Aquantia PHY-s or can be loaded from the host via MDIO.
-
-This patch adds support for loading the firmware via MDIO as in most cases
-there is no SPI-NOR being used to save on cost.
-Firmware loading code itself is ported from mainline U-boot with cleanups.
-
-The firmware has mixed values both in big and little endian.
-PHY core itself is big-endian but it expects values to be in little-endian.
-The firmware is little-endian but CRC-16 value for it is stored at the end
-of firmware in big-endian.
-
-It seems the PHY does the conversion internally from firmware that is
-little-endian to the PHY that is big-endian on using the mailbox
-but mailbox returns a big-endian CRC-16 to verify the written data
-integrity.
-
----
- drivers/net/phy/aquantia/Kconfig | 1 +
- drivers/net/phy/aquantia/Makefile | 2 +-
- drivers/net/phy/aquantia/aquantia.h | 32 ++
- drivers/net/phy/aquantia/aquantia_firmware.c | 370 +++++++++++++++++++
- drivers/net/phy/aquantia/aquantia_main.c | 6 +
- 5 files changed, 410 insertions(+), 1 deletion(-)
- create mode 100644 drivers/net/phy/aquantia/aquantia_firmware.c
-
---- a/drivers/net/phy/aquantia/Kconfig
-+++ b/drivers/net/phy/aquantia/Kconfig
-@@ -1,5 +1,6 @@
- # SPDX-License-Identifier: GPL-2.0-only
- config AQUANTIA_PHY
- tristate "Aquantia PHYs"
-+ select CRC_CCITT
- help
- Currently supports the Aquantia AQ1202, AQ2104, AQR105, AQR405
---- a/drivers/net/phy/aquantia/Makefile
-+++ b/drivers/net/phy/aquantia/Makefile
-@@ -1,5 +1,5 @@
- # SPDX-License-Identifier: GPL-2.0
--aquantia-objs += aquantia_main.o
-+aquantia-objs += aquantia_main.o aquantia_firmware.o
- ifdef CONFIG_HWMON
- aquantia-objs += aquantia_hwmon.o
- endif
---- a/drivers/net/phy/aquantia/aquantia.h
-+++ b/drivers/net/phy/aquantia/aquantia.h
-@@ -10,10 +10,35 @@
- #include <linux/phy.h>
-
- /* Vendor specific 1, MDIO_MMD_VEND1 */
-+#define VEND1_GLOBAL_SC 0x0
-+#define VEND1_GLOBAL_SC_SOFT_RESET BIT(15)
-+#define VEND1_GLOBAL_SC_LOW_POWER BIT(11)
-+
- #define VEND1_GLOBAL_FW_ID 0x0020
- #define VEND1_GLOBAL_FW_ID_MAJOR GENMASK(15, 8)
- #define VEND1_GLOBAL_FW_ID_MINOR GENMASK(7, 0)
-
-+#define VEND1_GLOBAL_MAILBOX_INTERFACE1 0x0200
-+#define VEND1_GLOBAL_MAILBOX_INTERFACE1_EXECUTE BIT(15)
-+#define VEND1_GLOBAL_MAILBOX_INTERFACE1_WRITE BIT(14)
-+#define VEND1_GLOBAL_MAILBOX_INTERFACE1_CRC_RESET BIT(12)
-+#define VEND1_GLOBAL_MAILBOX_INTERFACE1_BUSY BIT(8)
-+
-+#define VEND1_GLOBAL_MAILBOX_INTERFACE2 0x0201
-+#define VEND1_GLOBAL_MAILBOX_INTERFACE3 0x0202
-+#define VEND1_GLOBAL_MAILBOX_INTERFACE3_MSW_ADDR_MASK GENMASK(15, 0)
-+#define VEND1_GLOBAL_MAILBOX_INTERFACE3_MSW_ADDR(x) FIELD_PREP(VEND1_GLOBAL_MAILBOX_INTERFACE3_MSW_ADDR_MASK, (u16)((x) >> 16))
-+#define VEND1_GLOBAL_MAILBOX_INTERFACE4 0x0203
-+#define VEND1_GLOBAL_MAILBOX_INTERFACE4_LSW_ADDR_MASK GENMASK(15, 2)
-+#define VEND1_GLOBAL_MAILBOX_INTERFACE4_LSW_ADDR(x) FIELD_PREP(VEND1_GLOBAL_MAILBOX_INTERFACE4_LSW_ADDR_MASK, (u16)(x))
-+
-+#define VEND1_GLOBAL_MAILBOX_INTERFACE5 0x0204
-+#define VEND1_GLOBAL_MAILBOX_INTERFACE5_MSW_DATA_MASK GENMASK(15, 0)
-+#define VEND1_GLOBAL_MAILBOX_INTERFACE5_MSW_DATA(x) FIELD_PREP(VEND1_GLOBAL_MAILBOX_INTERFACE5_MSW_DATA_MASK, (u16)((x) >> 16))
-+#define VEND1_GLOBAL_MAILBOX_INTERFACE6 0x0205
-+#define VEND1_GLOBAL_MAILBOX_INTERFACE6_LSW_DATA_MASK GENMASK(15, 0)
-+#define VEND1_GLOBAL_MAILBOX_INTERFACE6_LSW_DATA(x) FIELD_PREP(VEND1_GLOBAL_MAILBOX_INTERFACE6_LSW_DATA_MASK, (u16)(x))
-+
- /* The following registers all have similar layouts; first the registers... */
- #define VEND1_GLOBAL_CFG_10M 0x0310
- #define VEND1_GLOBAL_CFG_100M 0x031b
-@@ -28,6 +53,11 @@
- #define VEND1_GLOBAL_CFG_RATE_ADAPT_PAUSE 2
-
- /* Vendor specific 1, MDIO_MMD_VEND2 */
-+#define VEND1_GLOBAL_CONTROL2 0xc001
-+#define VEND1_GLOBAL_CONTROL2_UP_RUN_STALL_RST BIT(15)
-+#define VEND1_GLOBAL_CONTROL2_UP_RUN_STALL_OVD BIT(6)
-+#define VEND1_GLOBAL_CONTROL2_UP_RUN_STALL BIT(0)
-+
- #define VEND1_THERMAL_PROV_HIGH_TEMP_FAIL 0xc421
- #define VEND1_THERMAL_PROV_LOW_TEMP_FAIL 0xc422
- #define VEND1_THERMAL_PROV_HIGH_TEMP_WARN 0xc423
-@@ -83,3 +113,5 @@ int aqr_hwmon_probe(struct phy_device *p
- #else
- static inline int aqr_hwmon_probe(struct phy_device *phydev) { return 0; }
- #endif
-+
-+int aqr_firmware_load(struct phy_device *phydev);
---- /dev/null
-+++ b/drivers/net/phy/aquantia/aquantia_firmware.c
-@@ -0,0 +1,370 @@
-+// SPDX-License-Identifier: GPL-2.0
-+
-+#include <linux/bitfield.h>
-+#include <linux/of.h>
-+#include <linux/firmware.h>
-+#include <linux/crc-ccitt.h>
-+#include <linux/nvmem-consumer.h>
-+
-+#include <asm/unaligned.h>
-+
-+#include "aquantia.h"
-+
-+#define UP_RESET_SLEEP 100
-+
-+/* addresses of memory segments in the phy */
-+#define DRAM_BASE_ADDR 0x3FFE0000
-+#define IRAM_BASE_ADDR 0x40000000
-+
-+/* firmware image format constants */
-+#define VERSION_STRING_SIZE 0x40
-+#define VERSION_STRING_OFFSET 0x0200
-+/* primary offset is written at an offset from the start of the fw blob */
-+#define PRIMARY_OFFSET_OFFSET 0x8
-+/* primary offset needs to be then added to a base offset */
-+#define PRIMARY_OFFSET_SHIFT 12
-+#define PRIMARY_OFFSET(x) ((x) << PRIMARY_OFFSET_SHIFT)
-+#define HEADER_OFFSET 0x300
-+
-+struct aqr_fw_header {
-+ u32 padding;
-+ u8 iram_offset[3];
-+ u8 iram_size[3];
-+ u8 dram_offset[3];
-+ u8 dram_size[3];
-+} __packed;
-+
-+enum aqr_fw_src {
-+ AQR_FW_SRC_NVMEM = 0,
-+ AQR_FW_SRC_FS,
-+};
-+
-+static const char * const aqr_fw_src_string[] = {
-+ [AQR_FW_SRC_NVMEM] = "NVMEM",
-+ [AQR_FW_SRC_FS] = "FS",
-+};
-+
-+/* AQR firmware doesn't have fixed offsets for iram and dram section
-+ * but instead provide an header with the offset to use on reading
-+ * and parsing the firmware.
-+ *
-+ * AQR firmware can't be trusted and each offset is validated to be
-+ * not negative and be in the size of the firmware itself.
-+ */
-+static bool aqr_fw_validate_get(size_t size, size_t offset, size_t get_size)
-+{
-+ return offset + get_size <= size;
-+}
-+
-+static int aqr_fw_get_be16(const u8 *data, size_t offset, size_t size, u16 *value)
-+{
-+ if (!aqr_fw_validate_get(size, offset, sizeof(u16)))
-+ return -EINVAL;
-+
-+ *value = get_unaligned_be16(data + offset);
-+
-+ return 0;
-+}
-+
-+static int aqr_fw_get_le16(const u8 *data, size_t offset, size_t size, u16 *value)
-+{
-+ if (!aqr_fw_validate_get(size, offset, sizeof(u16)))
-+ return -EINVAL;
-+
-+ *value = get_unaligned_le16(data + offset);
-+
-+ return 0;
-+}
-+
-+static int aqr_fw_get_le24(const u8 *data, size_t offset, size_t size, u32 *value)
-+{
-+ if (!aqr_fw_validate_get(size, offset, sizeof(u8) * 3))
-+ return -EINVAL;
-+
-+ *value = get_unaligned_le24(data + offset);
-+
-+ return 0;
-+}
-+
-+/* load data into the phy's memory */
-+static int aqr_fw_load_memory(struct phy_device *phydev, u32 addr,
-+ const u8 *data, size_t len)
-+{
-+ u16 crc = 0, up_crc;
-+ size_t pos;
-+
-+ /* PHY expect addr in LE */
-+ addr = (__force u32)cpu_to_le32(addr);
-+
-+ phy_write_mmd(phydev, MDIO_MMD_VEND1,
-+ VEND1_GLOBAL_MAILBOX_INTERFACE1,
-+ VEND1_GLOBAL_MAILBOX_INTERFACE1_CRC_RESET);
-+ phy_write_mmd(phydev, MDIO_MMD_VEND1,
-+ VEND1_GLOBAL_MAILBOX_INTERFACE3,
-+ VEND1_GLOBAL_MAILBOX_INTERFACE3_MSW_ADDR(addr));
-+ phy_write_mmd(phydev, MDIO_MMD_VEND1,
-+ VEND1_GLOBAL_MAILBOX_INTERFACE4,
-+ VEND1_GLOBAL_MAILBOX_INTERFACE4_LSW_ADDR(addr));
-+
-+ /* We assume and enforce the size to be word aligned.
-+ * If a firmware that is not word aligned is found, please report upstream.
-+ */
-+ for (pos = 0; pos < len; pos += sizeof(u32)) {
-+ u32 word;
-+
-+ /* FW data is always stored in little-endian */
-+ word = get_unaligned((const u32 *)(data + pos));
-+
-+ phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLOBAL_MAILBOX_INTERFACE5,
-+ VEND1_GLOBAL_MAILBOX_INTERFACE5_MSW_DATA(word));
-+ phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLOBAL_MAILBOX_INTERFACE6,
-+ VEND1_GLOBAL_MAILBOX_INTERFACE6_LSW_DATA(word));
-+
-+ phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLOBAL_MAILBOX_INTERFACE1,
-+ VEND1_GLOBAL_MAILBOX_INTERFACE1_EXECUTE |
-+ VEND1_GLOBAL_MAILBOX_INTERFACE1_WRITE);
-+
-+ /* calculate CRC as we load data to the mailbox.
-+ * We convert word to big-endian as PHY is BE and mailbox will
-+ * return a BE CRC.
-+ */
-+ word = (__force u32)cpu_to_be32(word);
-+ crc = crc_ccitt_false(crc, (u8 *)&word, sizeof(word));
-+ }
-+
-+ up_crc = phy_read_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLOBAL_MAILBOX_INTERFACE2);
-+ if (crc != up_crc) {
-+ phydev_err(phydev, "CRC mismatch: calculated 0x%04x PHY 0x%04x\n",
-+ crc, up_crc);
-+ return -EINVAL;
-+ }
-+
-+ return 0;
-+}
-+
-+static int aqr_fw_boot(struct phy_device *phydev, const u8 *data, size_t size,
-+ enum aqr_fw_src fw_src)
-+{
-+ u16 calculated_crc, read_crc, read_primary_offset;
-+ u32 iram_offset = 0, iram_size = 0;
-+ u32 dram_offset = 0, dram_size = 0;
-+ char version[VERSION_STRING_SIZE];
-+ u32 primary_offset = 0;
-+ int ret;
-+
-+ /* extract saved CRC at the end of the fw
-+ * CRC is saved in big-endian as PHY is BE
-+ */
-+ ret = aqr_fw_get_be16(data, size - sizeof(u16), size, &read_crc);
-+ if (ret) {
-+ phydev_err(phydev, "bad firmware CRC in firmware\n");
-+ return ret;
-+ }
-+ calculated_crc = crc_ccitt_false(0, data, size - sizeof(u16));
-+ if (read_crc != calculated_crc) {
-+ phydev_err(phydev, "bad firmware CRC: file 0x%04x calculated 0x%04x\n",
-+ read_crc, calculated_crc);
-+ return -EINVAL;
-+ }
-+
-+ /* Get the primary offset to extract DRAM and IRAM sections. */
-+ ret = aqr_fw_get_le16(data, PRIMARY_OFFSET_OFFSET, size, &read_primary_offset);
-+ if (ret) {
-+ phydev_err(phydev, "bad primary offset in firmware\n");
-+ return ret;
-+ }
-+ primary_offset = PRIMARY_OFFSET(read_primary_offset);
-+
-+ /* Find the DRAM and IRAM sections within the firmware file.
-+ * Make sure the fw_header is correctly in the firmware.
-+ */
-+ if (!aqr_fw_validate_get(size, primary_offset + HEADER_OFFSET,
-+ sizeof(struct aqr_fw_header))) {
-+ phydev_err(phydev, "bad fw_header in firmware\n");
-+ return -EINVAL;
-+ }
-+
-+ /* offset are in LE and values needs to be converted to cpu endian */
-+ ret = aqr_fw_get_le24(data, primary_offset + HEADER_OFFSET +
-+ offsetof(struct aqr_fw_header, iram_offset),
-+ size, &iram_offset);
-+ if (ret) {
-+ phydev_err(phydev, "bad iram offset in firmware\n");
-+ return ret;
-+ }
-+ ret = aqr_fw_get_le24(data, primary_offset + HEADER_OFFSET +
-+ offsetof(struct aqr_fw_header, iram_size),
-+ size, &iram_size);
-+ if (ret) {
-+ phydev_err(phydev, "invalid iram size in firmware\n");
-+ return ret;
-+ }
-+ ret = aqr_fw_get_le24(data, primary_offset + HEADER_OFFSET +
-+ offsetof(struct aqr_fw_header, dram_offset),
-+ size, &dram_offset);
-+ if (ret) {
-+ phydev_err(phydev, "bad dram offset in firmware\n");
-+ return ret;
-+ }
-+ ret = aqr_fw_get_le24(data, primary_offset + HEADER_OFFSET +
-+ offsetof(struct aqr_fw_header, dram_size),
-+ size, &dram_size);
-+ if (ret) {
-+ phydev_err(phydev, "invalid dram size in firmware\n");
-+ return ret;
-+ }
-+
-+ /* Increment the offset with the primary offset.
-+ * Validate iram/dram offset and size.
-+ */
-+ iram_offset += primary_offset;
-+ if (iram_size % sizeof(u32)) {
-+ phydev_err(phydev, "iram size if not aligned to word size. Please report this upstream!\n");
-+ return -EINVAL;
-+ }
-+ if (!aqr_fw_validate_get(size, iram_offset, iram_size)) {
-+ phydev_err(phydev, "invalid iram offset for iram size\n");
-+ return -EINVAL;
-+ }
-+
-+ dram_offset += primary_offset;
-+ if (dram_size % sizeof(u32)) {
-+ phydev_err(phydev, "dram size if not aligned to word size. Please report this upstream!\n");
-+ return -EINVAL;
-+ }
-+ if (!aqr_fw_validate_get(size, dram_offset, dram_size)) {
-+ phydev_err(phydev, "invalid iram offset for iram size\n");
-+ return -EINVAL;
-+ }
-+
-+ phydev_dbg(phydev, "primary %d IRAM offset=%d size=%d DRAM offset=%d size=%d\n",
-+ primary_offset, iram_offset, iram_size, dram_offset, dram_size);
-+
-+ if (!aqr_fw_validate_get(size, dram_offset + VERSION_STRING_OFFSET,
-+ VERSION_STRING_SIZE)) {
-+ phydev_err(phydev, "invalid version in firmware\n");
-+ return -EINVAL;
-+ }
-+ strscpy(version, (char *)data + dram_offset + VERSION_STRING_OFFSET,
-+ VERSION_STRING_SIZE);
-+ if (version[0] == '\0') {
-+ phydev_err(phydev, "invalid version in firmware\n");
-+ return -EINVAL;
-+ }
-+ phydev_info(phydev, "loading firmware version '%s' from '%s'\n", version,
-+ aqr_fw_src_string[fw_src]);
-+
-+ /* stall the microcprocessor */
-+ phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLOBAL_CONTROL2,
-+ VEND1_GLOBAL_CONTROL2_UP_RUN_STALL | VEND1_GLOBAL_CONTROL2_UP_RUN_STALL_OVD);
-+
-+ phydev_dbg(phydev, "loading DRAM 0x%08x from offset=%d size=%d\n",
-+ DRAM_BASE_ADDR, dram_offset, dram_size);
-+ ret = aqr_fw_load_memory(phydev, DRAM_BASE_ADDR, data + dram_offset,
-+ dram_size);
-+ if (ret)
-+ return ret;
-+
-+ phydev_dbg(phydev, "loading IRAM 0x%08x from offset=%d size=%d\n",
-+ IRAM_BASE_ADDR, iram_offset, iram_size);
-+ ret = aqr_fw_load_memory(phydev, IRAM_BASE_ADDR, data + iram_offset,
-+ iram_size);
-+ if (ret)
-+ return ret;
-+
-+ /* make sure soft reset and low power mode are clear */
-+ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLOBAL_SC,
-+ VEND1_GLOBAL_SC_SOFT_RESET | VEND1_GLOBAL_SC_LOW_POWER);
-+
-+ /* Release the microprocessor. UP_RESET must be held for 100 usec. */
-+ phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLOBAL_CONTROL2,
-+ VEND1_GLOBAL_CONTROL2_UP_RUN_STALL |
-+ VEND1_GLOBAL_CONTROL2_UP_RUN_STALL_OVD |
-+ VEND1_GLOBAL_CONTROL2_UP_RUN_STALL_RST);
-+ usleep_range(UP_RESET_SLEEP, UP_RESET_SLEEP * 2);
-+
-+ phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLOBAL_CONTROL2,
-+ VEND1_GLOBAL_CONTROL2_UP_RUN_STALL_OVD);
-+
-+ return 0;
-+}
-+
-+static int aqr_firmware_load_nvmem(struct phy_device *phydev)
-+{
-+ struct nvmem_cell *cell;
-+ size_t size;
-+ u8 *buf;
-+ int ret;
-+
-+ cell = nvmem_cell_get(&phydev->mdio.dev, "firmware");
-+ if (IS_ERR(cell))
-+ return PTR_ERR(cell);
-+
-+ buf = nvmem_cell_read(cell, &size);
-+ if (IS_ERR(buf)) {
-+ ret = PTR_ERR(buf);
-+ goto exit;
-+ }
-+
-+ ret = aqr_fw_boot(phydev, buf, size, AQR_FW_SRC_NVMEM);
-+ if (ret)
-+ phydev_err(phydev, "firmware loading failed: %d\n", ret);
-+
-+ kfree(buf);
-+exit:
-+ nvmem_cell_put(cell);
-+
-+ return ret;
-+}
-+
-+static int aqr_firmware_load_fs(struct phy_device *phydev)
-+{
-+ struct device *dev = &phydev->mdio.dev;
-+ const struct firmware *fw;
-+ const char *fw_name;
-+ int ret;
-+
-+ ret = of_property_read_string(dev->of_node, "firmware-name",
-+ &fw_name);
-+ if (ret)
-+ return ret;
-+
-+ ret = request_firmware(&fw, fw_name, dev);
-+ if (ret) {
-+ phydev_err(phydev, "failed to find FW file %s (%d)\n",
-+ fw_name, ret);
-+ return ret;
-+ }
-+
-+ ret = aqr_fw_boot(phydev, fw->data, fw->size, AQR_FW_SRC_FS);
-+ if (ret)
-+ phydev_err(phydev, "firmware loading failed: %d\n", ret);
-+
-+ release_firmware(fw);
-+
-+ return ret;
-+}
-+
-+int aqr_firmware_load(struct phy_device *phydev)
-+{
-+ int ret;
-+
-+ /* Check if the firmware is not already loaded by pooling
-+ * the current version returned by the PHY. If 0 is returned,
-+ * no firmware is loaded.
-+ */
-+ ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLOBAL_FW_ID);
-+ if (ret > 0)
-+ goto exit;
-+
-+ ret = aqr_firmware_load_nvmem(phydev);
-+ if (!ret)
-+ goto exit;
-+
-+ ret = aqr_firmware_load_fs(phydev);
-+ if (ret)
-+ return ret;
-+
-+exit:
-+ return 0;
-+}
---- a/drivers/net/phy/aquantia/aquantia_main.c
-+++ b/drivers/net/phy/aquantia/aquantia_main.c
-@@ -658,11 +658,17 @@ static int aqr107_resume(struct phy_devi
-
- static int aqr107_probe(struct phy_device *phydev)
- {
-+ int ret;
-+
- phydev->priv = devm_kzalloc(&phydev->mdio.dev,
- sizeof(struct aqr107_priv), GFP_KERNEL);
- if (!phydev->priv)
- return -ENOMEM;
-
-+ ret = aqr_firmware_load(phydev);
-+ if (ret)
-+ return ret;
-+
- return aqr_hwmon_probe(phydev);
- }
-
+++ /dev/null
-From d11e63119432bdb55065d094cb6fd37e9147c70d Mon Sep 17 00:00:00 2001
-Date: Thu, 11 Apr 2024 10:52:54 +0000
-Subject: [PATCH] flow_offload: add control flag checking helpers
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-These helpers aim to help drivers, with checking
-for the presence of unsupported control flags.
-
-For drivers supporting at least one control flag:
- flow_rule_is_supp_control_flags()
-
-For drivers using flow_rule_match_control(), but not using flags:
- flow_rule_has_control_flags()
-
-For drivers not using flow_rule_match_control():
- flow_rule_match_has_control_flags()
-
-While primarily aimed at FLOW_DISSECTOR_KEY_CONTROL
-and flow_rule_match_control(), then the first two
-can also be used with FLOW_DISSECTOR_KEY_ENC_CONTROL
-and flow_rule_match_enc_control().
-
-These helpers mirrors the existing check done in sfc:
- drivers/net/ethernet/sfc/tc.c +276
-
-Only compile-tested.
-
----
- include/net/flow_offload.h | 55 ++++++++++++++++++++++++++++++++++++++
- 1 file changed, 55 insertions(+)
-
---- a/include/net/flow_offload.h
-+++ b/include/net/flow_offload.h
-@@ -449,6 +449,61 @@ static inline bool flow_rule_match_key(c
- return dissector_uses_key(rule->match.dissector, key);
- }
-
-+/**
-+ * flow_rule_is_supp_control_flags() - check for supported control flags
-+ * @supp_flags: control flags supported by driver
-+ * @ctrl_flags: control flags present in rule
-+ * @extack: The netlink extended ACK for reporting errors.
-+ *
-+ * Return: true if only supported control flags are set, false otherwise.
-+ */
-+static inline bool flow_rule_is_supp_control_flags(const u32 supp_flags,
-+ const u32 ctrl_flags,
-+ struct netlink_ext_ack *extack)
-+{
-+ if (likely((ctrl_flags & ~supp_flags) == 0))
-+ return true;
-+
-+ NL_SET_ERR_MSG_FMT_MOD(extack,
-+ "Unsupported match on control.flags %#x",
-+ ctrl_flags);
-+
-+ return false;
-+}
-+
-+/**
-+ * flow_rule_has_control_flags() - check for presence of any control flags
-+ * @ctrl_flags: control flags present in rule
-+ * @extack: The netlink extended ACK for reporting errors.
-+ *
-+ * Return: true if control flags are set, false otherwise.
-+ */
-+static inline bool flow_rule_has_control_flags(const u32 ctrl_flags,
-+ struct netlink_ext_ack *extack)
-+{
-+ return !flow_rule_is_supp_control_flags(0, ctrl_flags, extack);
-+}
-+
-+/**
-+ * flow_rule_match_has_control_flags() - match and check for any control flags
-+ * @rule: The flow_rule under evaluation.
-+ * @extack: The netlink extended ACK for reporting errors.
-+ *
-+ * Return: true if control flags are set, false otherwise.
-+ */
-+static inline bool flow_rule_match_has_control_flags(struct flow_rule *rule,
-+ struct netlink_ext_ack *extack)
-+{
-+ struct flow_match_control match;
-+
-+ if (!flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_CONTROL))
-+ return false;
-+
-+ flow_rule_match_control(rule, &match);
-+
-+ return flow_rule_has_control_flags(match.mask->flags, extack);
-+}
-+
- struct flow_stats {
- u64 pkts;
- u64 bytes;
+++ /dev/null
-From f40a455d01f80c6638be382d75cb1c4e7748d8af Mon Sep 17 00:00:00 2001
-Date: Tue, 13 Aug 2024 14:33:47 +0100
-Subject: [PATCH] ipv6: Add ipv6_addr_{cpu_to_be32,be32_to_cpu} helpers
-
-Add helpers to convert an ipv6 addr, expressed as an array
-of words, from CPU to big-endian byte order, and vice versa.
-
-No functional change intended.
-Compile tested only.
-
----
- include/net/ipv6.h | 12 ++++++++++++
- 1 file changed, 12 insertions(+)
-
---- a/include/net/ipv6.h
-+++ b/include/net/ipv6.h
-@@ -1382,4 +1382,16 @@ static inline void ip6_sock_set_recvpkti
- release_sock(sk);
- }
-
-+#define IPV6_ADDR_WORDS 4
-+
-+static inline void ipv6_addr_cpu_to_be32(__be32 *dst, const u32 *src)
-+{
-+ cpu_to_be32_array(dst, src, IPV6_ADDR_WORDS);
-+}
-+
-+static inline void ipv6_addr_be32_to_cpu(u32 *dst, const __be32 *src)
-+{
-+ be32_to_cpu_array(dst, src, IPV6_ADDR_WORDS);
-+}
-+
- #endif /* _NET_IPV6_H */
+++ /dev/null
-From 6a3b8c573b5a152a6aa7a0b54c5e18b84c6ba6f5 Mon Sep 17 00:00:00 2001
-Date: Fri, 8 Dec 2023 15:51:49 +0100
-Subject: [PATCH 02/13] net: phy: at803x: move disable WOL to specific at8031
- probe
-
-Move the WOL disable call to specific at8031 probe to make at803x_probe
-more generic and drop extra check for PHY ID.
-
-Keep the same previous behaviour by first calling at803x_probe and then
-disabling WOL.
-
----
- drivers/net/phy/at803x.c | 27 +++++++++++++++++----------
- 1 file changed, 17 insertions(+), 10 deletions(-)
-
---- a/drivers/net/phy/at803x.c
-+++ b/drivers/net/phy/at803x.c
-@@ -886,15 +886,6 @@ static int at803x_probe(struct phy_devic
- priv->is_fiber = true;
- break;
- }
--
-- /* Disable WoL in 1588 register which is enabled
-- * by default
-- */
-- ret = phy_modify_mmd(phydev, MDIO_MMD_PCS,
-- AT803X_PHY_MMD3_WOL_CTRL,
-- AT803X_WOL_EN, 0);
-- if (ret)
-- return ret;
- }
-
- return 0;
-@@ -1591,6 +1582,22 @@ static int at803x_cable_test_start(struc
- return 0;
- }
-
-+static int at8031_probe(struct phy_device *phydev)
-+{
-+ int ret;
-+
-+ ret = at803x_probe(phydev);
-+ if (ret)
-+ return ret;
-+
-+ /* Disable WoL in 1588 register which is enabled
-+ * by default
-+ */
-+ return phy_modify_mmd(phydev, MDIO_MMD_PCS,
-+ AT803X_PHY_MMD3_WOL_CTRL,
-+ AT803X_WOL_EN, 0);
-+}
-+
- static int qca83xx_config_init(struct phy_device *phydev)
- {
- u8 switch_revision;
-@@ -2092,7 +2099,7 @@ static struct phy_driver at803x_driver[]
- PHY_ID_MATCH_EXACT(ATH8031_PHY_ID),
- .name = "Qualcomm Atheros AR8031/AR8033",
- .flags = PHY_POLL_CABLE_TEST,
-- .probe = at803x_probe,
-+ .probe = at8031_probe,
- .config_init = at803x_config_init,
- .config_aneg = at803x_config_aneg,
- .soft_reset = genphy_soft_reset,
+++ /dev/null
-From 07b1ad83b9ed6db1735ba10baf67b7a565ac0cef Mon Sep 17 00:00:00 2001
-Date: Fri, 8 Dec 2023 15:51:50 +0100
-Subject: [PATCH 03/13] net: phy: at803x: raname hw_stats functions to qca83xx
- specific name
-
-The function and the struct related to hw_stats were specific to qca83xx
-PHY but were called following the convention in the driver of calling
-everything with at803x prefix.
-
-To better organize the code, rename these function a more specific name
-to better describe that they are specific to 83xx PHY family.
-
----
- drivers/net/phy/at803x.c | 44 ++++++++++++++++++++--------------------
- 1 file changed, 22 insertions(+), 22 deletions(-)
-
---- a/drivers/net/phy/at803x.c
-+++ b/drivers/net/phy/at803x.c
-@@ -295,7 +295,7 @@ struct at803x_hw_stat {
- enum stat_access_type access_type;
- };
-
--static struct at803x_hw_stat at803x_hw_stats[] = {
-+static struct at803x_hw_stat qca83xx_hw_stats[] = {
- { "phy_idle_errors", 0xa, GENMASK(7, 0), PHY},
- { "phy_receive_errors", 0x15, GENMASK(15, 0), PHY},
- { "eee_wake_errors", 0x16, GENMASK(15, 0), MMD},
-@@ -311,7 +311,7 @@ struct at803x_priv {
- bool is_1000basex;
- struct regulator_dev *vddio_rdev;
- struct regulator_dev *vddh_rdev;
-- u64 stats[ARRAY_SIZE(at803x_hw_stats)];
-+ u64 stats[ARRAY_SIZE(qca83xx_hw_stats)];
- };
-
- struct at803x_context {
-@@ -529,24 +529,24 @@ static void at803x_get_wol(struct phy_de
- wol->wolopts |= WAKE_MAGIC;
- }
-
--static int at803x_get_sset_count(struct phy_device *phydev)
-+static int qca83xx_get_sset_count(struct phy_device *phydev)
- {
-- return ARRAY_SIZE(at803x_hw_stats);
-+ return ARRAY_SIZE(qca83xx_hw_stats);
- }
-
--static void at803x_get_strings(struct phy_device *phydev, u8 *data)
-+static void qca83xx_get_strings(struct phy_device *phydev, u8 *data)
- {
- int i;
-
-- for (i = 0; i < ARRAY_SIZE(at803x_hw_stats); i++) {
-+ for (i = 0; i < ARRAY_SIZE(qca83xx_hw_stats); i++) {
- strscpy(data + i * ETH_GSTRING_LEN,
-- at803x_hw_stats[i].string, ETH_GSTRING_LEN);
-+ qca83xx_hw_stats[i].string, ETH_GSTRING_LEN);
- }
- }
-
--static u64 at803x_get_stat(struct phy_device *phydev, int i)
-+static u64 qca83xx_get_stat(struct phy_device *phydev, int i)
- {
-- struct at803x_hw_stat stat = at803x_hw_stats[i];
-+ struct at803x_hw_stat stat = qca83xx_hw_stats[i];
- struct at803x_priv *priv = phydev->priv;
- int val;
- u64 ret;
-@@ -567,13 +567,13 @@ static u64 at803x_get_stat(struct phy_de
- return ret;
- }
-
--static void at803x_get_stats(struct phy_device *phydev,
-- struct ethtool_stats *stats, u64 *data)
-+static void qca83xx_get_stats(struct phy_device *phydev,
-+ struct ethtool_stats *stats, u64 *data)
- {
- int i;
-
-- for (i = 0; i < ARRAY_SIZE(at803x_hw_stats); i++)
-- data[i] = at803x_get_stat(phydev, i);
-+ for (i = 0; i < ARRAY_SIZE(qca83xx_hw_stats); i++)
-+ data[i] = qca83xx_get_stat(phydev, i);
- }
-
- static int at803x_suspend(struct phy_device *phydev)
-@@ -2175,9 +2175,9 @@ static struct phy_driver at803x_driver[]
- .flags = PHY_IS_INTERNAL,
- .config_init = qca83xx_config_init,
- .soft_reset = genphy_soft_reset,
-- .get_sset_count = at803x_get_sset_count,
-- .get_strings = at803x_get_strings,
-- .get_stats = at803x_get_stats,
-+ .get_sset_count = qca83xx_get_sset_count,
-+ .get_strings = qca83xx_get_strings,
-+ .get_stats = qca83xx_get_stats,
- .suspend = qca83xx_suspend,
- .resume = qca83xx_resume,
- }, {
-@@ -2191,9 +2191,9 @@ static struct phy_driver at803x_driver[]
- .flags = PHY_IS_INTERNAL,
- .config_init = qca83xx_config_init,
- .soft_reset = genphy_soft_reset,
-- .get_sset_count = at803x_get_sset_count,
-- .get_strings = at803x_get_strings,
-- .get_stats = at803x_get_stats,
-+ .get_sset_count = qca83xx_get_sset_count,
-+ .get_strings = qca83xx_get_strings,
-+ .get_stats = qca83xx_get_stats,
- .suspend = qca83xx_suspend,
- .resume = qca83xx_resume,
- }, {
-@@ -2207,9 +2207,9 @@ static struct phy_driver at803x_driver[]
- .flags = PHY_IS_INTERNAL,
- .config_init = qca83xx_config_init,
- .soft_reset = genphy_soft_reset,
-- .get_sset_count = at803x_get_sset_count,
-- .get_strings = at803x_get_strings,
-- .get_stats = at803x_get_stats,
-+ .get_sset_count = qca83xx_get_sset_count,
-+ .get_strings = qca83xx_get_strings,
-+ .get_stats = qca83xx_get_stats,
- .suspend = qca83xx_suspend,
- .resume = qca83xx_resume,
- }, {
+++ /dev/null
-From d43cff3f82336c0bd965ea552232d9f4ddac71a6 Mon Sep 17 00:00:00 2001
-Date: Fri, 8 Dec 2023 15:51:51 +0100
-Subject: [PATCH 04/13] net: phy: at803x: move qca83xx specific check in
- dedicated functions
-
-Rework qca83xx specific check to dedicated function to tidy things up
-and drop useless phy_id check.
-
-Also drop an useless link_change_notify for QCA8337 as it did nothing an
-returned early.
-
----
- drivers/net/phy/at803x.c | 68 ++++++++++++++++++++++------------------
- 1 file changed, 37 insertions(+), 31 deletions(-)
-
---- a/drivers/net/phy/at803x.c
-+++ b/drivers/net/phy/at803x.c
-@@ -1623,27 +1623,26 @@ static int qca83xx_config_init(struct ph
- break;
- }
-
-+ /* Following original QCA sourcecode set port to prefer master */
-+ phy_set_bits(phydev, MII_CTRL1000, CTL1000_PREFER_MASTER);
-+
-+ return 0;
-+}
-+
-+static int qca8327_config_init(struct phy_device *phydev)
-+{
- /* QCA8327 require DAC amplitude adjustment for 100m set to +6%.
- * Disable on init and enable only with 100m speed following
- * qca original source code.
- */
-- if (phydev->drv->phy_id == QCA8327_A_PHY_ID ||
-- phydev->drv->phy_id == QCA8327_B_PHY_ID)
-- at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL,
-- QCA8327_DEBUG_MANU_CTRL_EN, 0);
-+ at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL,
-+ QCA8327_DEBUG_MANU_CTRL_EN, 0);
-
-- /* Following original QCA sourcecode set port to prefer master */
-- phy_set_bits(phydev, MII_CTRL1000, CTL1000_PREFER_MASTER);
--
-- return 0;
-+ return qca83xx_config_init(phydev);
- }
-
- static void qca83xx_link_change_notify(struct phy_device *phydev)
- {
-- /* QCA8337 doesn't require DAC Amplitude adjustement */
-- if (phydev->drv->phy_id == QCA8337_PHY_ID)
-- return;
--
- /* Set DAC Amplitude adjustment to +6% for 100m on link running */
- if (phydev->state == PHY_RUNNING) {
- if (phydev->speed == SPEED_100)
-@@ -1686,19 +1685,6 @@ static int qca83xx_resume(struct phy_dev
-
- static int qca83xx_suspend(struct phy_device *phydev)
- {
-- u16 mask = 0;
--
-- /* Only QCA8337 support actual suspend.
-- * QCA8327 cause port unreliability when phy suspend
-- * is set.
-- */
-- if (phydev->drv->phy_id == QCA8337_PHY_ID) {
-- genphy_suspend(phydev);
-- } else {
-- mask |= ~(BMCR_SPEED1000 | BMCR_FULLDPLX);
-- phy_modify(phydev, MII_BMCR, mask, 0);
-- }
--
- at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_GREEN,
- AT803X_DEBUG_GATE_CLK_IN1000, 0);
-
-@@ -1709,6 +1695,27 @@ static int qca83xx_suspend(struct phy_de
- return 0;
- }
-
-+static int qca8337_suspend(struct phy_device *phydev)
-+{
-+ /* Only QCA8337 support actual suspend. */
-+ genphy_suspend(phydev);
-+
-+ return qca83xx_suspend(phydev);
-+}
-+
-+static int qca8327_suspend(struct phy_device *phydev)
-+{
-+ u16 mask = 0;
-+
-+ /* QCA8327 cause port unreliability when phy suspend
-+ * is set.
-+ */
-+ mask |= ~(BMCR_SPEED1000 | BMCR_FULLDPLX);
-+ phy_modify(phydev, MII_BMCR, mask, 0);
-+
-+ return qca83xx_suspend(phydev);
-+}
-+
- static int qca808x_phy_fast_retrain_config(struct phy_device *phydev)
- {
- int ret;
-@@ -2170,7 +2177,6 @@ static struct phy_driver at803x_driver[]
- .phy_id_mask = QCA8K_PHY_ID_MASK,
- .name = "Qualcomm Atheros 8337 internal PHY",
- /* PHY_GBIT_FEATURES */
-- .link_change_notify = qca83xx_link_change_notify,
- .probe = at803x_probe,
- .flags = PHY_IS_INTERNAL,
- .config_init = qca83xx_config_init,
-@@ -2178,7 +2184,7 @@ static struct phy_driver at803x_driver[]
- .get_sset_count = qca83xx_get_sset_count,
- .get_strings = qca83xx_get_strings,
- .get_stats = qca83xx_get_stats,
-- .suspend = qca83xx_suspend,
-+ .suspend = qca8337_suspend,
- .resume = qca83xx_resume,
- }, {
- /* QCA8327-A from switch QCA8327-AL1A */
-@@ -2189,12 +2195,12 @@ static struct phy_driver at803x_driver[]
- .link_change_notify = qca83xx_link_change_notify,
- .probe = at803x_probe,
- .flags = PHY_IS_INTERNAL,
-- .config_init = qca83xx_config_init,
-+ .config_init = qca8327_config_init,
- .soft_reset = genphy_soft_reset,
- .get_sset_count = qca83xx_get_sset_count,
- .get_strings = qca83xx_get_strings,
- .get_stats = qca83xx_get_stats,
-- .suspend = qca83xx_suspend,
-+ .suspend = qca8327_suspend,
- .resume = qca83xx_resume,
- }, {
- /* QCA8327-B from switch QCA8327-BL1A */
-@@ -2205,12 +2211,12 @@ static struct phy_driver at803x_driver[]
- .link_change_notify = qca83xx_link_change_notify,
- .probe = at803x_probe,
- .flags = PHY_IS_INTERNAL,
-- .config_init = qca83xx_config_init,
-+ .config_init = qca8327_config_init,
- .soft_reset = genphy_soft_reset,
- .get_sset_count = qca83xx_get_sset_count,
- .get_strings = qca83xx_get_strings,
- .get_stats = qca83xx_get_stats,
-- .suspend = qca83xx_suspend,
-+ .suspend = qca8327_suspend,
- .resume = qca83xx_resume,
- }, {
- /* Qualcomm QCA8081 */
+++ /dev/null
-From 900eef75cc5018e149c52fe305c9c3fe424c52a7 Mon Sep 17 00:00:00 2001
-Date: Fri, 8 Dec 2023 15:51:52 +0100
-Subject: [PATCH 05/13] net: phy: at803x: move specific DT option for at8031 to
- specific probe
-
-Move specific DT options for at8031 to specific probe to tidy things up
-and make at803x_parse_dt more generic.
-
----
- drivers/net/phy/at803x.c | 55 ++++++++++++++++++++++------------------
- 1 file changed, 31 insertions(+), 24 deletions(-)
-
---- a/drivers/net/phy/at803x.c
-+++ b/drivers/net/phy/at803x.c
-@@ -825,30 +825,6 @@ static int at803x_parse_dt(struct phy_de
- }
- }
-
-- /* Only supported on AR8031/AR8033, the AR8030/AR8035 use strapping
-- * options.
-- */
-- if (phydev->drv->phy_id == ATH8031_PHY_ID) {
-- if (of_property_read_bool(node, "qca,keep-pll-enabled"))
-- priv->flags |= AT803X_KEEP_PLL_ENABLED;
--
-- ret = at8031_register_regulators(phydev);
-- if (ret < 0)
-- return ret;
--
-- ret = devm_regulator_get_enable_optional(&phydev->mdio.dev,
-- "vddio");
-- if (ret) {
-- phydev_err(phydev, "failed to get VDDIO regulator\n");
-- return ret;
-- }
--
-- /* Only AR8031/8033 support 1000Base-X for SFP modules */
-- ret = phy_sfp_probe(phydev, &at803x_sfp_ops);
-- if (ret < 0)
-- return ret;
-- }
--
- return 0;
- }
-
-@@ -1582,6 +1558,30 @@ static int at803x_cable_test_start(struc
- return 0;
- }
-
-+static int at8031_parse_dt(struct phy_device *phydev)
-+{
-+ struct device_node *node = phydev->mdio.dev.of_node;
-+ struct at803x_priv *priv = phydev->priv;
-+ int ret;
-+
-+ if (of_property_read_bool(node, "qca,keep-pll-enabled"))
-+ priv->flags |= AT803X_KEEP_PLL_ENABLED;
-+
-+ ret = at8031_register_regulators(phydev);
-+ if (ret < 0)
-+ return ret;
-+
-+ ret = devm_regulator_get_enable_optional(&phydev->mdio.dev,
-+ "vddio");
-+ if (ret) {
-+ phydev_err(phydev, "failed to get VDDIO regulator\n");
-+ return ret;
-+ }
-+
-+ /* Only AR8031/8033 support 1000Base-X for SFP modules */
-+ return phy_sfp_probe(phydev, &at803x_sfp_ops);
-+}
-+
- static int at8031_probe(struct phy_device *phydev)
- {
- int ret;
-@@ -1590,6 +1590,13 @@ static int at8031_probe(struct phy_devic
- if (ret)
- return ret;
-
-+ /* Only supported on AR8031/AR8033, the AR8030/AR8035 use strapping
-+ * options.
-+ */
-+ ret = at8031_parse_dt(phydev);
-+ if (ret)
-+ return ret;
-+
- /* Disable WoL in 1588 register which is enabled
- * by default
- */
+++ /dev/null
-From 25d2ba94005fac18fe68878cddff59a67e115554 Mon Sep 17 00:00:00 2001
-Date: Fri, 8 Dec 2023 15:51:53 +0100
-Subject: [PATCH 06/13] net: phy: at803x: move specific at8031 probe mode check
- to dedicated probe
-
-Move specific at8031 probe mode check to dedicated probe to make
-at803x_probe more generic and keep code tidy.
-
----
- drivers/net/phy/at803x.c | 39 +++++++++++++++++++--------------------
- 1 file changed, 19 insertions(+), 20 deletions(-)
-
---- a/drivers/net/phy/at803x.c
-+++ b/drivers/net/phy/at803x.c
-@@ -844,26 +844,6 @@ static int at803x_probe(struct phy_devic
- if (ret)
- return ret;
-
-- if (phydev->drv->phy_id == ATH8031_PHY_ID) {
-- int ccr = phy_read(phydev, AT803X_REG_CHIP_CONFIG);
-- int mode_cfg;
--
-- if (ccr < 0)
-- return ccr;
-- mode_cfg = ccr & AT803X_MODE_CFG_MASK;
--
-- switch (mode_cfg) {
-- case AT803X_MODE_CFG_BX1000_RGMII_50OHM:
-- case AT803X_MODE_CFG_BX1000_RGMII_75OHM:
-- priv->is_1000basex = true;
-- fallthrough;
-- case AT803X_MODE_CFG_FX100_RGMII_50OHM:
-- case AT803X_MODE_CFG_FX100_RGMII_75OHM:
-- priv->is_fiber = true;
-- break;
-- }
-- }
--
- return 0;
- }
-
-@@ -1584,6 +1564,9 @@ static int at8031_parse_dt(struct phy_de
-
- static int at8031_probe(struct phy_device *phydev)
- {
-+ struct at803x_priv *priv = phydev->priv;
-+ int mode_cfg;
-+ int ccr;
- int ret;
-
- ret = at803x_probe(phydev);
-@@ -1597,6 +1580,22 @@ static int at8031_probe(struct phy_devic
- if (ret)
- return ret;
-
-+ ccr = phy_read(phydev, AT803X_REG_CHIP_CONFIG);
-+ if (ccr < 0)
-+ return ccr;
-+ mode_cfg = ccr & AT803X_MODE_CFG_MASK;
-+
-+ switch (mode_cfg) {
-+ case AT803X_MODE_CFG_BX1000_RGMII_50OHM:
-+ case AT803X_MODE_CFG_BX1000_RGMII_75OHM:
-+ priv->is_1000basex = true;
-+ fallthrough;
-+ case AT803X_MODE_CFG_FX100_RGMII_50OHM:
-+ case AT803X_MODE_CFG_FX100_RGMII_75OHM:
-+ priv->is_fiber = true;
-+ break;
-+ }
-+
- /* Disable WoL in 1588 register which is enabled
- * by default
- */
+++ /dev/null
-From 3ae3bc426eaf57ca8f53d75777d9a5ef779bc7b7 Mon Sep 17 00:00:00 2001
-Date: Fri, 8 Dec 2023 15:51:54 +0100
-Subject: [PATCH 07/13] net: phy: at803x: move specific at8031 config_init to
- dedicated function
-
-Move specific at8031 config_init to dedicated function to make
-at803x_config_init more generic and tidy things up.
-
----
- drivers/net/phy/at803x.c | 45 ++++++++++++++++++++++------------------
- 1 file changed, 25 insertions(+), 20 deletions(-)
-
---- a/drivers/net/phy/at803x.c
-+++ b/drivers/net/phy/at803x.c
-@@ -951,27 +951,8 @@ static int at803x_hibernation_mode_confi
-
- static int at803x_config_init(struct phy_device *phydev)
- {
-- struct at803x_priv *priv = phydev->priv;
- int ret;
-
-- if (phydev->drv->phy_id == ATH8031_PHY_ID) {
-- /* Some bootloaders leave the fiber page selected.
-- * Switch to the appropriate page (fiber or copper), as otherwise we
-- * read the PHY capabilities from the wrong page.
-- */
-- phy_lock_mdio_bus(phydev);
-- ret = at803x_write_page(phydev,
-- priv->is_fiber ? AT803X_PAGE_FIBER :
-- AT803X_PAGE_COPPER);
-- phy_unlock_mdio_bus(phydev);
-- if (ret)
-- return ret;
--
-- ret = at8031_pll_config(phydev);
-- if (ret < 0)
-- return ret;
-- }
--
- /* The RX and TX delay default is:
- * after HW reset: RX delay enabled and TX delay disabled
- * after SW reset: RX delay enabled, while TX delay retains the
-@@ -1604,6 +1585,30 @@ static int at8031_probe(struct phy_devic
- AT803X_WOL_EN, 0);
- }
-
-+static int at8031_config_init(struct phy_device *phydev)
-+{
-+ struct at803x_priv *priv = phydev->priv;
-+ int ret;
-+
-+ /* Some bootloaders leave the fiber page selected.
-+ * Switch to the appropriate page (fiber or copper), as otherwise we
-+ * read the PHY capabilities from the wrong page.
-+ */
-+ phy_lock_mdio_bus(phydev);
-+ ret = at803x_write_page(phydev,
-+ priv->is_fiber ? AT803X_PAGE_FIBER :
-+ AT803X_PAGE_COPPER);
-+ phy_unlock_mdio_bus(phydev);
-+ if (ret)
-+ return ret;
-+
-+ ret = at8031_pll_config(phydev);
-+ if (ret < 0)
-+ return ret;
-+
-+ return at803x_config_init(phydev);
-+}
-+
- static int qca83xx_config_init(struct phy_device *phydev)
- {
- u8 switch_revision;
-@@ -2113,7 +2118,7 @@ static struct phy_driver at803x_driver[]
- .name = "Qualcomm Atheros AR8031/AR8033",
- .flags = PHY_POLL_CABLE_TEST,
- .probe = at8031_probe,
-- .config_init = at803x_config_init,
-+ .config_init = at8031_config_init,
- .config_aneg = at803x_config_aneg,
- .soft_reset = genphy_soft_reset,
- .set_wol = at803x_set_wol,
+++ /dev/null
-From 27b89c9dc1b0393090d68d651b82f30ad2696baa Mon Sep 17 00:00:00 2001
-Date: Fri, 8 Dec 2023 15:51:55 +0100
-Subject: [PATCH 08/13] net: phy: at803x: move specific at8031 WOL bits to
- dedicated function
-
-Move specific at8031 WOL enable/disable to dedicated function to make
-at803x_set_wol more generic.
-
-This is needed in preparation for PHY driver split as qca8081 share the
-same function to toggle WOL settings.
-
-In this new implementation WOL module in at8031 is enabled after the
-generic interrupt is setup. This should not cause any problem as the
-WOL_INT has a separate implementation and only relay on MAC bits.
-
----
- drivers/net/phy/at803x.c | 42 ++++++++++++++++++++++++----------------
- 1 file changed, 25 insertions(+), 17 deletions(-)
-
---- a/drivers/net/phy/at803x.c
-+++ b/drivers/net/phy/at803x.c
-@@ -466,27 +466,11 @@ static int at803x_set_wol(struct phy_dev
- phy_write_mmd(phydev, MDIO_MMD_PCS, offsets[i],
- mac[(i * 2) + 1] | (mac[(i * 2)] << 8));
-
-- /* Enable WOL function for 1588 */
-- if (phydev->drv->phy_id == ATH8031_PHY_ID) {
-- ret = phy_modify_mmd(phydev, MDIO_MMD_PCS,
-- AT803X_PHY_MMD3_WOL_CTRL,
-- 0, AT803X_WOL_EN);
-- if (ret)
-- return ret;
-- }
- /* Enable WOL interrupt */
- ret = phy_modify(phydev, AT803X_INTR_ENABLE, 0, AT803X_INTR_ENABLE_WOL);
- if (ret)
- return ret;
- } else {
-- /* Disable WoL function for 1588 */
-- if (phydev->drv->phy_id == ATH8031_PHY_ID) {
-- ret = phy_modify_mmd(phydev, MDIO_MMD_PCS,
-- AT803X_PHY_MMD3_WOL_CTRL,
-- AT803X_WOL_EN, 0);
-- if (ret)
-- return ret;
-- }
- /* Disable WOL interrupt */
- ret = phy_modify(phydev, AT803X_INTR_ENABLE, AT803X_INTR_ENABLE_WOL, 0);
- if (ret)
-@@ -1609,6 +1593,30 @@ static int at8031_config_init(struct phy
- return at803x_config_init(phydev);
- }
-
-+static int at8031_set_wol(struct phy_device *phydev,
-+ struct ethtool_wolinfo *wol)
-+{
-+ int ret;
-+
-+ /* First setup MAC address and enable WOL interrupt */
-+ ret = at803x_set_wol(phydev, wol);
-+ if (ret)
-+ return ret;
-+
-+ if (wol->wolopts & WAKE_MAGIC)
-+ /* Enable WOL function for 1588 */
-+ ret = phy_modify_mmd(phydev, MDIO_MMD_PCS,
-+ AT803X_PHY_MMD3_WOL_CTRL,
-+ 0, AT803X_WOL_EN);
-+ else
-+ /* Disable WoL function for 1588 */
-+ ret = phy_modify_mmd(phydev, MDIO_MMD_PCS,
-+ AT803X_PHY_MMD3_WOL_CTRL,
-+ AT803X_WOL_EN, 0);
-+
-+ return ret;
-+}
-+
- static int qca83xx_config_init(struct phy_device *phydev)
- {
- u8 switch_revision;
-@@ -2121,7 +2129,7 @@ static struct phy_driver at803x_driver[]
- .config_init = at8031_config_init,
- .config_aneg = at803x_config_aneg,
- .soft_reset = genphy_soft_reset,
-- .set_wol = at803x_set_wol,
-+ .set_wol = at8031_set_wol,
- .get_wol = at803x_get_wol,
- .suspend = at803x_suspend,
- .resume = at803x_resume,
+++ /dev/null
-From 30dd62191d3dd97c08f7f9dc9ce77ffab457e4fb Mon Sep 17 00:00:00 2001
-Date: Fri, 8 Dec 2023 15:51:56 +0100
-Subject: [PATCH 09/13] net: phy: at803x: move specific at8031 config_intr to
- dedicated function
-
-Move specific at8031 config_intr bits to dedicated function to make
-at803x_config_initr more generic.
-
-This is needed in preparation for PHY driver split as qca8081 share the
-same function to setup interrupts.
-
----
- drivers/net/phy/at803x.c | 30 ++++++++++++++++++++++++------
- 1 file changed, 24 insertions(+), 6 deletions(-)
-
---- a/drivers/net/phy/at803x.c
-+++ b/drivers/net/phy/at803x.c
-@@ -990,7 +990,6 @@ static int at803x_ack_interrupt(struct p
-
- static int at803x_config_intr(struct phy_device *phydev)
- {
-- struct at803x_priv *priv = phydev->priv;
- int err;
- int value;
-
-@@ -1007,10 +1006,6 @@ static int at803x_config_intr(struct phy
- value |= AT803X_INTR_ENABLE_DUPLEX_CHANGED;
- value |= AT803X_INTR_ENABLE_LINK_FAIL;
- value |= AT803X_INTR_ENABLE_LINK_SUCCESS;
-- if (priv->is_fiber) {
-- value |= AT803X_INTR_ENABLE_LINK_FAIL_BX;
-- value |= AT803X_INTR_ENABLE_LINK_SUCCESS_BX;
-- }
-
- err = phy_write(phydev, AT803X_INTR_ENABLE, value);
- } else {
-@@ -1617,6 +1612,29 @@ static int at8031_set_wol(struct phy_dev
- return ret;
- }
-
-+static int at8031_config_intr(struct phy_device *phydev)
-+{
-+ struct at803x_priv *priv = phydev->priv;
-+ int err, value = 0;
-+
-+ if (phydev->interrupts == PHY_INTERRUPT_ENABLED &&
-+ priv->is_fiber) {
-+ /* Clear any pending interrupts */
-+ err = at803x_ack_interrupt(phydev);
-+ if (err)
-+ return err;
-+
-+ value |= AT803X_INTR_ENABLE_LINK_FAIL_BX;
-+ value |= AT803X_INTR_ENABLE_LINK_SUCCESS_BX;
-+
-+ err = phy_set_bits(phydev, AT803X_INTR_ENABLE, value);
-+ if (err)
-+ return err;
-+ }
-+
-+ return at803x_config_intr(phydev);
-+}
-+
- static int qca83xx_config_init(struct phy_device *phydev)
- {
- u8 switch_revision;
-@@ -2137,7 +2155,7 @@ static struct phy_driver at803x_driver[]
- .write_page = at803x_write_page,
- .get_features = at803x_get_features,
- .read_status = at803x_read_status,
-- .config_intr = at803x_config_intr,
-+ .config_intr = at8031_config_intr,
- .handle_interrupt = at803x_handle_interrupt,
- .get_tunable = at803x_get_tunable,
- .set_tunable = at803x_set_tunable,
+++ /dev/null
-From a5ab9d8e7ae0da8328ac1637a9755311508dc8ab Mon Sep 17 00:00:00 2001
-Date: Fri, 8 Dec 2023 15:51:57 +0100
-Subject: [PATCH 10/13] net: phy: at803x: make at8031 related DT functions name
- more specific
-
-Rename at8031 related DT function name to a more specific name
-referencing they are only related to at8031 and not to the generic
-at803x PHY family.
-
----
- drivers/net/phy/at803x.c | 16 ++++++++--------
- 1 file changed, 8 insertions(+), 8 deletions(-)
-
---- a/drivers/net/phy/at803x.c
-+++ b/drivers/net/phy/at803x.c
-@@ -583,7 +583,7 @@ static int at803x_resume(struct phy_devi
- return phy_modify(phydev, MII_BMCR, BMCR_PDOWN | BMCR_ISOLATE, 0);
- }
-
--static int at803x_rgmii_reg_set_voltage_sel(struct regulator_dev *rdev,
-+static int at8031_rgmii_reg_set_voltage_sel(struct regulator_dev *rdev,
- unsigned int selector)
- {
- struct phy_device *phydev = rdev_get_drvdata(rdev);
-@@ -596,7 +596,7 @@ static int at803x_rgmii_reg_set_voltage_
- AT803X_DEBUG_RGMII_1V8, 0);
- }
-
--static int at803x_rgmii_reg_get_voltage_sel(struct regulator_dev *rdev)
-+static int at8031_rgmii_reg_get_voltage_sel(struct regulator_dev *rdev)
- {
- struct phy_device *phydev = rdev_get_drvdata(rdev);
- int val;
-@@ -610,8 +610,8 @@ static int at803x_rgmii_reg_get_voltage_
-
- static const struct regulator_ops vddio_regulator_ops = {
- .list_voltage = regulator_list_voltage_table,
-- .set_voltage_sel = at803x_rgmii_reg_set_voltage_sel,
-- .get_voltage_sel = at803x_rgmii_reg_get_voltage_sel,
-+ .set_voltage_sel = at8031_rgmii_reg_set_voltage_sel,
-+ .get_voltage_sel = at8031_rgmii_reg_get_voltage_sel,
- };
-
- static const unsigned int vddio_voltage_table[] = {
-@@ -666,7 +666,7 @@ static int at8031_register_regulators(st
- return 0;
- }
-
--static int at803x_sfp_insert(void *upstream, const struct sfp_eeprom_id *id)
-+static int at8031_sfp_insert(void *upstream, const struct sfp_eeprom_id *id)
- {
- struct phy_device *phydev = upstream;
- __ETHTOOL_DECLARE_LINK_MODE_MASK(phy_support);
-@@ -710,10 +710,10 @@ static int at803x_sfp_insert(void *upstr
- return 0;
- }
-
--static const struct sfp_upstream_ops at803x_sfp_ops = {
-+static const struct sfp_upstream_ops at8031_sfp_ops = {
- .attach = phy_sfp_attach,
- .detach = phy_sfp_detach,
-- .module_insert = at803x_sfp_insert,
-+ .module_insert = at8031_sfp_insert,
- };
-
- static int at803x_parse_dt(struct phy_device *phydev)
-@@ -1519,7 +1519,7 @@ static int at8031_parse_dt(struct phy_de
- }
-
- /* Only AR8031/8033 support 1000Base-X for SFP modules */
-- return phy_sfp_probe(phydev, &at803x_sfp_ops);
-+ return phy_sfp_probe(phydev, &at8031_sfp_ops);
- }
-
- static int at8031_probe(struct phy_device *phydev)
+++ /dev/null
-From f932a6dc8bae0dae9645b5b1b4c65aed8a8acb2a Mon Sep 17 00:00:00 2001
-Date: Fri, 8 Dec 2023 15:51:58 +0100
-Subject: [PATCH 11/13] net: phy: at803x: move at8031 functions in dedicated
- section
-
-Move at8031 functions in dedicated section with dedicated at8031
-parse_dt and probe.
-
----
- drivers/net/phy/at803x.c | 266 +++++++++++++++++++--------------------
- 1 file changed, 133 insertions(+), 133 deletions(-)
-
---- a/drivers/net/phy/at803x.c
-+++ b/drivers/net/phy/at803x.c
-@@ -583,139 +583,6 @@ static int at803x_resume(struct phy_devi
- return phy_modify(phydev, MII_BMCR, BMCR_PDOWN | BMCR_ISOLATE, 0);
- }
-
--static int at8031_rgmii_reg_set_voltage_sel(struct regulator_dev *rdev,
-- unsigned int selector)
--{
-- struct phy_device *phydev = rdev_get_drvdata(rdev);
--
-- if (selector)
-- return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_1F,
-- 0, AT803X_DEBUG_RGMII_1V8);
-- else
-- return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_1F,
-- AT803X_DEBUG_RGMII_1V8, 0);
--}
--
--static int at8031_rgmii_reg_get_voltage_sel(struct regulator_dev *rdev)
--{
-- struct phy_device *phydev = rdev_get_drvdata(rdev);
-- int val;
--
-- val = at803x_debug_reg_read(phydev, AT803X_DEBUG_REG_1F);
-- if (val < 0)
-- return val;
--
-- return (val & AT803X_DEBUG_RGMII_1V8) ? 1 : 0;
--}
--
--static const struct regulator_ops vddio_regulator_ops = {
-- .list_voltage = regulator_list_voltage_table,
-- .set_voltage_sel = at8031_rgmii_reg_set_voltage_sel,
-- .get_voltage_sel = at8031_rgmii_reg_get_voltage_sel,
--};
--
--static const unsigned int vddio_voltage_table[] = {
-- 1500000,
-- 1800000,
--};
--
--static const struct regulator_desc vddio_desc = {
-- .name = "vddio",
-- .of_match = of_match_ptr("vddio-regulator"),
-- .n_voltages = ARRAY_SIZE(vddio_voltage_table),
-- .volt_table = vddio_voltage_table,
-- .ops = &vddio_regulator_ops,
-- .type = REGULATOR_VOLTAGE,
-- .owner = THIS_MODULE,
--};
--
--static const struct regulator_ops vddh_regulator_ops = {
--};
--
--static const struct regulator_desc vddh_desc = {
-- .name = "vddh",
-- .of_match = of_match_ptr("vddh-regulator"),
-- .n_voltages = 1,
-- .fixed_uV = 2500000,
-- .ops = &vddh_regulator_ops,
-- .type = REGULATOR_VOLTAGE,
-- .owner = THIS_MODULE,
--};
--
--static int at8031_register_regulators(struct phy_device *phydev)
--{
-- struct at803x_priv *priv = phydev->priv;
-- struct device *dev = &phydev->mdio.dev;
-- struct regulator_config config = { };
--
-- config.dev = dev;
-- config.driver_data = phydev;
--
-- priv->vddio_rdev = devm_regulator_register(dev, &vddio_desc, &config);
-- if (IS_ERR(priv->vddio_rdev)) {
-- phydev_err(phydev, "failed to register VDDIO regulator\n");
-- return PTR_ERR(priv->vddio_rdev);
-- }
--
-- priv->vddh_rdev = devm_regulator_register(dev, &vddh_desc, &config);
-- if (IS_ERR(priv->vddh_rdev)) {
-- phydev_err(phydev, "failed to register VDDH regulator\n");
-- return PTR_ERR(priv->vddh_rdev);
-- }
--
-- return 0;
--}
--
--static int at8031_sfp_insert(void *upstream, const struct sfp_eeprom_id *id)
--{
-- struct phy_device *phydev = upstream;
-- __ETHTOOL_DECLARE_LINK_MODE_MASK(phy_support);
-- __ETHTOOL_DECLARE_LINK_MODE_MASK(sfp_support);
-- DECLARE_PHY_INTERFACE_MASK(interfaces);
-- phy_interface_t iface;
--
-- linkmode_zero(phy_support);
-- phylink_set(phy_support, 1000baseX_Full);
-- phylink_set(phy_support, 1000baseT_Full);
-- phylink_set(phy_support, Autoneg);
-- phylink_set(phy_support, Pause);
-- phylink_set(phy_support, Asym_Pause);
--
-- linkmode_zero(sfp_support);
-- sfp_parse_support(phydev->sfp_bus, id, sfp_support, interfaces);
-- /* Some modules support 10G modes as well as others we support.
-- * Mask out non-supported modes so the correct interface is picked.
-- */
-- linkmode_and(sfp_support, phy_support, sfp_support);
--
-- if (linkmode_empty(sfp_support)) {
-- dev_err(&phydev->mdio.dev, "incompatible SFP module inserted\n");
-- return -EINVAL;
-- }
--
-- iface = sfp_select_interface(phydev->sfp_bus, sfp_support);
--
-- /* Only 1000Base-X is supported by AR8031/8033 as the downstream SerDes
-- * interface for use with SFP modules.
-- * However, some copper modules detected as having a preferred SGMII
-- * interface do default to and function in 1000Base-X mode, so just
-- * print a warning and allow such modules, as they may have some chance
-- * of working.
-- */
-- if (iface == PHY_INTERFACE_MODE_SGMII)
-- dev_warn(&phydev->mdio.dev, "module may not function if 1000Base-X not supported\n");
-- else if (iface != PHY_INTERFACE_MODE_1000BASEX)
-- return -EINVAL;
--
-- return 0;
--}
--
--static const struct sfp_upstream_ops at8031_sfp_ops = {
-- .attach = phy_sfp_attach,
-- .detach = phy_sfp_detach,
-- .module_insert = at8031_sfp_insert,
--};
--
- static int at803x_parse_dt(struct phy_device *phydev)
- {
- struct device_node *node = phydev->mdio.dev.of_node;
-@@ -1498,6 +1365,139 @@ static int at803x_cable_test_start(struc
- return 0;
- }
-
-+static int at8031_rgmii_reg_set_voltage_sel(struct regulator_dev *rdev,
-+ unsigned int selector)
-+{
-+ struct phy_device *phydev = rdev_get_drvdata(rdev);
-+
-+ if (selector)
-+ return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_1F,
-+ 0, AT803X_DEBUG_RGMII_1V8);
-+ else
-+ return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_1F,
-+ AT803X_DEBUG_RGMII_1V8, 0);
-+}
-+
-+static int at8031_rgmii_reg_get_voltage_sel(struct regulator_dev *rdev)
-+{
-+ struct phy_device *phydev = rdev_get_drvdata(rdev);
-+ int val;
-+
-+ val = at803x_debug_reg_read(phydev, AT803X_DEBUG_REG_1F);
-+ if (val < 0)
-+ return val;
-+
-+ return (val & AT803X_DEBUG_RGMII_1V8) ? 1 : 0;
-+}
-+
-+static const struct regulator_ops vddio_regulator_ops = {
-+ .list_voltage = regulator_list_voltage_table,
-+ .set_voltage_sel = at8031_rgmii_reg_set_voltage_sel,
-+ .get_voltage_sel = at8031_rgmii_reg_get_voltage_sel,
-+};
-+
-+static const unsigned int vddio_voltage_table[] = {
-+ 1500000,
-+ 1800000,
-+};
-+
-+static const struct regulator_desc vddio_desc = {
-+ .name = "vddio",
-+ .of_match = of_match_ptr("vddio-regulator"),
-+ .n_voltages = ARRAY_SIZE(vddio_voltage_table),
-+ .volt_table = vddio_voltage_table,
-+ .ops = &vddio_regulator_ops,
-+ .type = REGULATOR_VOLTAGE,
-+ .owner = THIS_MODULE,
-+};
-+
-+static const struct regulator_ops vddh_regulator_ops = {
-+};
-+
-+static const struct regulator_desc vddh_desc = {
-+ .name = "vddh",
-+ .of_match = of_match_ptr("vddh-regulator"),
-+ .n_voltages = 1,
-+ .fixed_uV = 2500000,
-+ .ops = &vddh_regulator_ops,
-+ .type = REGULATOR_VOLTAGE,
-+ .owner = THIS_MODULE,
-+};
-+
-+static int at8031_register_regulators(struct phy_device *phydev)
-+{
-+ struct at803x_priv *priv = phydev->priv;
-+ struct device *dev = &phydev->mdio.dev;
-+ struct regulator_config config = { };
-+
-+ config.dev = dev;
-+ config.driver_data = phydev;
-+
-+ priv->vddio_rdev = devm_regulator_register(dev, &vddio_desc, &config);
-+ if (IS_ERR(priv->vddio_rdev)) {
-+ phydev_err(phydev, "failed to register VDDIO regulator\n");
-+ return PTR_ERR(priv->vddio_rdev);
-+ }
-+
-+ priv->vddh_rdev = devm_regulator_register(dev, &vddh_desc, &config);
-+ if (IS_ERR(priv->vddh_rdev)) {
-+ phydev_err(phydev, "failed to register VDDH regulator\n");
-+ return PTR_ERR(priv->vddh_rdev);
-+ }
-+
-+ return 0;
-+}
-+
-+static int at8031_sfp_insert(void *upstream, const struct sfp_eeprom_id *id)
-+{
-+ struct phy_device *phydev = upstream;
-+ __ETHTOOL_DECLARE_LINK_MODE_MASK(phy_support);
-+ __ETHTOOL_DECLARE_LINK_MODE_MASK(sfp_support);
-+ DECLARE_PHY_INTERFACE_MASK(interfaces);
-+ phy_interface_t iface;
-+
-+ linkmode_zero(phy_support);
-+ phylink_set(phy_support, 1000baseX_Full);
-+ phylink_set(phy_support, 1000baseT_Full);
-+ phylink_set(phy_support, Autoneg);
-+ phylink_set(phy_support, Pause);
-+ phylink_set(phy_support, Asym_Pause);
-+
-+ linkmode_zero(sfp_support);
-+ sfp_parse_support(phydev->sfp_bus, id, sfp_support, interfaces);
-+ /* Some modules support 10G modes as well as others we support.
-+ * Mask out non-supported modes so the correct interface is picked.
-+ */
-+ linkmode_and(sfp_support, phy_support, sfp_support);
-+
-+ if (linkmode_empty(sfp_support)) {
-+ dev_err(&phydev->mdio.dev, "incompatible SFP module inserted\n");
-+ return -EINVAL;
-+ }
-+
-+ iface = sfp_select_interface(phydev->sfp_bus, sfp_support);
-+
-+ /* Only 1000Base-X is supported by AR8031/8033 as the downstream SerDes
-+ * interface for use with SFP modules.
-+ * However, some copper modules detected as having a preferred SGMII
-+ * interface do default to and function in 1000Base-X mode, so just
-+ * print a warning and allow such modules, as they may have some chance
-+ * of working.
-+ */
-+ if (iface == PHY_INTERFACE_MODE_SGMII)
-+ dev_warn(&phydev->mdio.dev, "module may not function if 1000Base-X not supported\n");
-+ else if (iface != PHY_INTERFACE_MODE_1000BASEX)
-+ return -EINVAL;
-+
-+ return 0;
-+}
-+
-+static const struct sfp_upstream_ops at8031_sfp_ops = {
-+ .attach = phy_sfp_attach,
-+ .detach = phy_sfp_detach,
-+ .module_insert = at8031_sfp_insert,
-+};
-+
- static int at8031_parse_dt(struct phy_device *phydev)
- {
- struct device_node *node = phydev->mdio.dev.of_node;
+++ /dev/null
-From 21a2802a8365cfa82cc02187c1f95136d85592ad Mon Sep 17 00:00:00 2001
-Date: Fri, 8 Dec 2023 15:51:59 +0100
-Subject: [PATCH 12/13] net: phy: at803x: move at8035 specific DT parse to
- dedicated probe
-
-Move at8035 specific DT parse for clock out frequency to dedicated probe
-to make at803x probe function more generic.
-
-This is to tidy code and no behaviour change are intended.
-
-Detection logic is changed, we check if the clk 25m mask is set and if
-it's not zero, we assume the qca,clk-out-frequency property is set.
-
-The property is checked in the generic at803x_parse_dt called by
-at803x_probe.
-
----
- drivers/net/phy/at803x.c | 60 +++++++++++++++++++++++++++-------------
- 1 file changed, 41 insertions(+), 19 deletions(-)
-
---- a/drivers/net/phy/at803x.c
-+++ b/drivers/net/phy/at803x.c
-@@ -638,23 +638,6 @@ static int at803x_parse_dt(struct phy_de
-
- priv->clk_25m_reg |= FIELD_PREP(AT803X_CLK_OUT_MASK, sel);
- priv->clk_25m_mask |= AT803X_CLK_OUT_MASK;
--
-- /* Fixup for the AR8030/AR8035. This chip has another mask and
-- * doesn't support the DSP reference. Eg. the lowest bit of the
-- * mask. The upper two bits select the same frequencies. Mask
-- * the lowest bit here.
-- *
-- * Warning:
-- * There was no datasheet for the AR8030 available so this is
-- * just a guess. But the AR8035 is listed as pin compatible
-- * to the AR8030 so there might be a good chance it works on
-- * the AR8030 too.
-- */
-- if (phydev->drv->phy_id == ATH8030_PHY_ID ||
-- phydev->drv->phy_id == ATH8035_PHY_ID) {
-- priv->clk_25m_reg &= AT8035_CLK_OUT_MASK;
-- priv->clk_25m_mask &= AT8035_CLK_OUT_MASK;
-- }
- }
-
- ret = of_property_read_u32(node, "qca,clk-out-strength", &strength);
-@@ -1635,6 +1618,45 @@ static int at8031_config_intr(struct phy
- return at803x_config_intr(phydev);
- }
-
-+static int at8035_parse_dt(struct phy_device *phydev)
-+{
-+ struct at803x_priv *priv = phydev->priv;
-+
-+ /* Mask is set by the generic at803x_parse_dt
-+ * if property is set. Assume property is set
-+ * with the mask not zero.
-+ */
-+ if (priv->clk_25m_mask) {
-+ /* Fixup for the AR8030/AR8035. This chip has another mask and
-+ * doesn't support the DSP reference. Eg. the lowest bit of the
-+ * mask. The upper two bits select the same frequencies. Mask
-+ * the lowest bit here.
-+ *
-+ * Warning:
-+ * There was no datasheet for the AR8030 available so this is
-+ * just a guess. But the AR8035 is listed as pin compatible
-+ * to the AR8030 so there might be a good chance it works on
-+ * the AR8030 too.
-+ */
-+ priv->clk_25m_reg &= AT8035_CLK_OUT_MASK;
-+ priv->clk_25m_mask &= AT8035_CLK_OUT_MASK;
-+ }
-+
-+ return 0;
-+}
-+
-+/* AR8030 and AR8035 shared the same special mask for clk_25m */
-+static int at8035_probe(struct phy_device *phydev)
-+{
-+ int ret;
-+
-+ ret = at803x_probe(phydev);
-+ if (ret)
-+ return ret;
-+
-+ return at8035_parse_dt(phydev);
-+}
-+
- static int qca83xx_config_init(struct phy_device *phydev)
- {
- u8 switch_revision;
-@@ -2107,7 +2129,7 @@ static struct phy_driver at803x_driver[]
- PHY_ID_MATCH_EXACT(ATH8035_PHY_ID),
- .name = "Qualcomm Atheros AR8035",
- .flags = PHY_POLL_CABLE_TEST,
-- .probe = at803x_probe,
-+ .probe = at8035_probe,
- .config_aneg = at803x_config_aneg,
- .config_init = at803x_config_init,
- .soft_reset = genphy_soft_reset,
-@@ -2128,7 +2150,7 @@ static struct phy_driver at803x_driver[]
- .phy_id = ATH8030_PHY_ID,
- .name = "Qualcomm Atheros AR8030",
- .phy_id_mask = AT8030_PHY_ID_MASK,
-- .probe = at803x_probe,
-+ .probe = at8035_probe,
- .config_init = at803x_config_init,
- .link_change_notify = at803x_link_change_notify,
- .set_wol = at803x_set_wol,
+++ /dev/null
-From ef9df47b449e32e06501a11272809be49019bdb6 Mon Sep 17 00:00:00 2001
-Date: Fri, 8 Dec 2023 15:52:00 +0100
-Subject: [PATCH 13/13] net: phy: at803x: drop specific PHY ID check from cable
- test functions
-
-Drop specific PHY ID check for cable test functions for at803x. This is
-done to make functions more generic. While at it better describe what
-the functions does by using more symbolic function names.
-
-PHYs that requires to set additional reg are moved to specific function
-calling the more generic one.
-
-cdt_start and cdt_wait_for_completion are changed to take an additional
-arg to pass specific values specific to the PHY.
-
----
- drivers/net/phy/at803x.c | 95 +++++++++++++++++++++-------------------
- 1 file changed, 50 insertions(+), 45 deletions(-)
-
---- a/drivers/net/phy/at803x.c
-+++ b/drivers/net/phy/at803x.c
-@@ -1222,31 +1222,16 @@ static int at803x_cdt_fault_length(u16 s
- return (dt * 824) / 10;
- }
-
--static int at803x_cdt_start(struct phy_device *phydev, int pair)
-+static int at803x_cdt_start(struct phy_device *phydev,
-+ u32 cdt_start)
- {
-- u16 cdt;
--
-- /* qca8081 takes the different bit 15 to enable CDT test */
-- if (phydev->drv->phy_id == QCA8081_PHY_ID)
-- cdt = QCA808X_CDT_ENABLE_TEST |
-- QCA808X_CDT_LENGTH_UNIT |
-- QCA808X_CDT_INTER_CHECK_DIS;
-- else
-- cdt = FIELD_PREP(AT803X_CDT_MDI_PAIR_MASK, pair) |
-- AT803X_CDT_ENABLE_TEST;
--
-- return phy_write(phydev, AT803X_CDT, cdt);
-+ return phy_write(phydev, AT803X_CDT, cdt_start);
- }
-
--static int at803x_cdt_wait_for_completion(struct phy_device *phydev)
-+static int at803x_cdt_wait_for_completion(struct phy_device *phydev,
-+ u32 cdt_en)
- {
- int val, ret;
-- u16 cdt_en;
--
-- if (phydev->drv->phy_id == QCA8081_PHY_ID)
-- cdt_en = QCA808X_CDT_ENABLE_TEST;
-- else
-- cdt_en = AT803X_CDT_ENABLE_TEST;
-
- /* One test run takes about 25ms */
- ret = phy_read_poll_timeout(phydev, AT803X_CDT, val,
-@@ -1266,11 +1251,13 @@ static int at803x_cable_test_one_pair(st
- };
- int ret, val;
-
-- ret = at803x_cdt_start(phydev, pair);
-+ val = FIELD_PREP(AT803X_CDT_MDI_PAIR_MASK, pair) |
-+ AT803X_CDT_ENABLE_TEST;
-+ ret = at803x_cdt_start(phydev, val);
- if (ret)
- return ret;
-
-- ret = at803x_cdt_wait_for_completion(phydev);
-+ ret = at803x_cdt_wait_for_completion(phydev, AT803X_CDT_ENABLE_TEST);
- if (ret)
- return ret;
-
-@@ -1292,19 +1279,11 @@ static int at803x_cable_test_one_pair(st
- }
-
- static int at803x_cable_test_get_status(struct phy_device *phydev,
-- bool *finished)
-+ bool *finished, unsigned long pair_mask)
- {
-- unsigned long pair_mask;
- int retries = 20;
- int pair, ret;
-
-- if (phydev->phy_id == ATH9331_PHY_ID ||
-- phydev->phy_id == ATH8032_PHY_ID ||
-- phydev->phy_id == QCA9561_PHY_ID)
-- pair_mask = 0x3;
-- else
-- pair_mask = 0xf;
--
- *finished = false;
-
- /* According to the datasheet the CDT can be performed when
-@@ -1331,7 +1310,7 @@ static int at803x_cable_test_get_status(
- return 0;
- }
-
--static int at803x_cable_test_start(struct phy_device *phydev)
-+static void at803x_cable_test_autoneg(struct phy_device *phydev)
- {
- /* Enable auto-negotiation, but advertise no capabilities, no link
- * will be established. A restart of the auto-negotiation is not
-@@ -1339,11 +1318,11 @@ static int at803x_cable_test_start(struc
- */
- phy_write(phydev, MII_BMCR, BMCR_ANENABLE);
- phy_write(phydev, MII_ADVERTISE, ADVERTISE_CSMA);
-- if (phydev->phy_id != ATH9331_PHY_ID &&
-- phydev->phy_id != ATH8032_PHY_ID &&
-- phydev->phy_id != QCA9561_PHY_ID)
-- phy_write(phydev, MII_CTRL1000, 0);
-+}
-
-+static int at803x_cable_test_start(struct phy_device *phydev)
-+{
-+ at803x_cable_test_autoneg(phydev);
- /* we do all the (time consuming) work later */
- return 0;
- }
-@@ -1618,6 +1597,29 @@ static int at8031_config_intr(struct phy
- return at803x_config_intr(phydev);
- }
-
-+/* AR8031 and AR8035 share the same cable test get status reg */
-+static int at8031_cable_test_get_status(struct phy_device *phydev,
-+ bool *finished)
-+{
-+ return at803x_cable_test_get_status(phydev, finished, 0xf);
-+}
-+
-+/* AR8031 and AR8035 share the same cable test start logic */
-+static int at8031_cable_test_start(struct phy_device *phydev)
-+{
-+ at803x_cable_test_autoneg(phydev);
-+ phy_write(phydev, MII_CTRL1000, 0);
-+ /* we do all the (time consuming) work later */
-+ return 0;
-+}
-+
-+/* AR8032, AR9331 and QCA9561 share the same cable test get status reg */
-+static int at8032_cable_test_get_status(struct phy_device *phydev,
-+ bool *finished)
-+{
-+ return at803x_cable_test_get_status(phydev, finished, 0x3);
-+}
-+
- static int at8035_parse_dt(struct phy_device *phydev)
- {
- struct at803x_priv *priv = phydev->priv;
-@@ -2041,11 +2043,14 @@ static int qca808x_cable_test_get_status
-
- *finished = false;
-
-- ret = at803x_cdt_start(phydev, 0);
-+ val = QCA808X_CDT_ENABLE_TEST |
-+ QCA808X_CDT_LENGTH_UNIT |
-+ QCA808X_CDT_INTER_CHECK_DIS;
-+ ret = at803x_cdt_start(phydev, val);
- if (ret)
- return ret;
-
-- ret = at803x_cdt_wait_for_completion(phydev);
-+ ret = at803x_cdt_wait_for_completion(phydev, QCA808X_CDT_ENABLE_TEST);
- if (ret)
- return ret;
-
-@@ -2143,8 +2148,8 @@ static struct phy_driver at803x_driver[]
- .handle_interrupt = at803x_handle_interrupt,
- .get_tunable = at803x_get_tunable,
- .set_tunable = at803x_set_tunable,
-- .cable_test_start = at803x_cable_test_start,
-- .cable_test_get_status = at803x_cable_test_get_status,
-+ .cable_test_start = at8031_cable_test_start,
-+ .cable_test_get_status = at8031_cable_test_get_status,
- }, {
- /* Qualcomm Atheros AR8030 */
- .phy_id = ATH8030_PHY_ID,
-@@ -2181,8 +2186,8 @@ static struct phy_driver at803x_driver[]
- .handle_interrupt = at803x_handle_interrupt,
- .get_tunable = at803x_get_tunable,
- .set_tunable = at803x_set_tunable,
-- .cable_test_start = at803x_cable_test_start,
-- .cable_test_get_status = at803x_cable_test_get_status,
-+ .cable_test_start = at8031_cable_test_start,
-+ .cable_test_get_status = at8031_cable_test_get_status,
- }, {
- /* Qualcomm Atheros AR8032 */
- PHY_ID_MATCH_EXACT(ATH8032_PHY_ID),
-@@ -2197,7 +2202,7 @@ static struct phy_driver at803x_driver[]
- .config_intr = at803x_config_intr,
- .handle_interrupt = at803x_handle_interrupt,
- .cable_test_start = at803x_cable_test_start,
-- .cable_test_get_status = at803x_cable_test_get_status,
-+ .cable_test_get_status = at8032_cable_test_get_status,
- }, {
- /* ATHEROS AR9331 */
- PHY_ID_MATCH_EXACT(ATH9331_PHY_ID),
-@@ -2210,7 +2215,7 @@ static struct phy_driver at803x_driver[]
- .config_intr = at803x_config_intr,
- .handle_interrupt = at803x_handle_interrupt,
- .cable_test_start = at803x_cable_test_start,
-- .cable_test_get_status = at803x_cable_test_get_status,
-+ .cable_test_get_status = at8032_cable_test_get_status,
- .read_status = at803x_read_status,
- .soft_reset = genphy_soft_reset,
- .config_aneg = at803x_config_aneg,
-@@ -2226,7 +2231,7 @@ static struct phy_driver at803x_driver[]
- .config_intr = at803x_config_intr,
- .handle_interrupt = at803x_handle_interrupt,
- .cable_test_start = at803x_cable_test_start,
-- .cable_test_get_status = at803x_cable_test_get_status,
-+ .cable_test_get_status = at8032_cable_test_get_status,
- .read_status = at803x_read_status,
- .soft_reset = genphy_soft_reset,
- .config_aneg = at803x_config_aneg,
+++ /dev/null
-From 8e732f1c6f2dc5e18f766d0f1b11df9db2dd044a Mon Sep 17 00:00:00 2001
-Date: Thu, 14 Dec 2023 01:44:31 +0100
-Subject: [PATCH 1/2] net: phy: at803x: move specific qca808x config_aneg to
- dedicated function
-
-Move specific qca808x config_aneg to dedicated function to permit easier
-split of qca808x portion from at803x driver.
-
----
- drivers/net/phy/at803x.c | 66 ++++++++++++++++++++++++----------------
- 1 file changed, 40 insertions(+), 26 deletions(-)
-
---- a/drivers/net/phy/at803x.c
-+++ b/drivers/net/phy/at803x.c
-@@ -1045,9 +1045,8 @@ static int at803x_config_mdix(struct phy
- FIELD_PREP(AT803X_SFC_MDI_CROSSOVER_MODE_M, val));
- }
-
--static int at803x_config_aneg(struct phy_device *phydev)
-+static int at803x_prepare_config_aneg(struct phy_device *phydev)
- {
-- struct at803x_priv *priv = phydev->priv;
- int ret;
-
- ret = at803x_config_mdix(phydev, phydev->mdix_ctrl);
-@@ -1064,33 +1063,22 @@ static int at803x_config_aneg(struct phy
- return ret;
- }
-
-- if (priv->is_1000basex)
-- return genphy_c37_config_aneg(phydev);
--
-- /* Do not restart auto-negotiation by setting ret to 0 defautly,
-- * when calling __genphy_config_aneg later.
-- */
-- ret = 0;
--
-- if (phydev->drv->phy_id == QCA8081_PHY_ID) {
-- int phy_ctrl = 0;
-+ return 0;
-+}
-
-- /* The reg MII_BMCR also needs to be configured for force mode, the
-- * genphy_config_aneg is also needed.
-- */
-- if (phydev->autoneg == AUTONEG_DISABLE)
-- genphy_c45_pma_setup_forced(phydev);
-+static int at803x_config_aneg(struct phy_device *phydev)
-+{
-+ struct at803x_priv *priv = phydev->priv;
-+ int ret;
-
-- if (linkmode_test_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, phydev->advertising))
-- phy_ctrl = MDIO_AN_10GBT_CTRL_ADV2_5G;
-+ ret = at803x_prepare_config_aneg(phydev);
-+ if (ret)
-+ return ret;
-
-- ret = phy_modify_mmd_changed(phydev, MDIO_MMD_AN, MDIO_AN_10GBT_CTRL,
-- MDIO_AN_10GBT_CTRL_ADV2_5G, phy_ctrl);
-- if (ret < 0)
-- return ret;
-- }
-+ if (priv->is_1000basex)
-+ return genphy_c37_config_aneg(phydev);
-
-- return __genphy_config_aneg(phydev, ret);
-+ return genphy_config_aneg(phydev);
- }
-
- static int at803x_get_downshift(struct phy_device *phydev, u8 *d)
-@@ -2118,6 +2106,32 @@ static int qca808x_get_features(struct p
- return 0;
- }
-
-+static int qca808x_config_aneg(struct phy_device *phydev)
-+{
-+ int phy_ctrl = 0;
-+ int ret;
-+
-+ ret = at803x_prepare_config_aneg(phydev);
-+ if (ret)
-+ return ret;
-+
-+ /* The reg MII_BMCR also needs to be configured for force mode, the
-+ * genphy_config_aneg is also needed.
-+ */
-+ if (phydev->autoneg == AUTONEG_DISABLE)
-+ genphy_c45_pma_setup_forced(phydev);
-+
-+ if (linkmode_test_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, phydev->advertising))
-+ phy_ctrl = MDIO_AN_10GBT_CTRL_ADV2_5G;
-+
-+ ret = phy_modify_mmd_changed(phydev, MDIO_MMD_AN, MDIO_AN_10GBT_CTRL,
-+ MDIO_AN_10GBT_CTRL_ADV2_5G, phy_ctrl);
-+ if (ret < 0)
-+ return ret;
-+
-+ return __genphy_config_aneg(phydev, ret);
-+}
-+
- static void qca808x_link_change_notify(struct phy_device *phydev)
- {
- /* Assert interface sgmii fifo on link down, deassert it on link up,
-@@ -2295,7 +2309,7 @@ static struct phy_driver at803x_driver[]
- .set_wol = at803x_set_wol,
- .get_wol = at803x_get_wol,
- .get_features = qca808x_get_features,
-- .config_aneg = at803x_config_aneg,
-+ .config_aneg = qca808x_config_aneg,
- .suspend = genphy_suspend,
- .resume = genphy_resume,
- .read_status = qca808x_read_status,
+++ /dev/null
-From 38eb804e8458ba181a03a0498ce4bf84eebd1931 Mon Sep 17 00:00:00 2001
-Date: Thu, 14 Dec 2023 01:44:32 +0100
-Subject: [PATCH 2/2] net: phy: at803x: make read specific status function more
- generic
-
-Rework read specific status function to be more generic. The function
-apply different speed mask based on the PHY ID. Make it more generic by
-adding an additional arg to pass the specific speed (ss) mask and use
-the provided mask to parse the speed value.
-
-This is needed to permit an easier deatch of qca808x code from the
-at803x driver.
-
----
- drivers/net/phy/at803x.c | 26 ++++++++++++++++++--------
- 1 file changed, 18 insertions(+), 8 deletions(-)
-
---- a/drivers/net/phy/at803x.c
-+++ b/drivers/net/phy/at803x.c
-@@ -301,6 +301,11 @@ static struct at803x_hw_stat qca83xx_hw_
- { "eee_wake_errors", 0x16, GENMASK(15, 0), MMD},
- };
-
-+struct at803x_ss_mask {
-+ u16 speed_mask;
-+ u8 speed_shift;
-+};
-+
- struct at803x_priv {
- int flags;
- u16 clk_25m_reg;
-@@ -921,7 +926,8 @@ static void at803x_link_change_notify(st
- }
- }
-
--static int at803x_read_specific_status(struct phy_device *phydev)
-+static int at803x_read_specific_status(struct phy_device *phydev,
-+ struct at803x_ss_mask ss_mask)
- {
- int ss;
-
-@@ -940,11 +946,8 @@ static int at803x_read_specific_status(s
- if (sfc < 0)
- return sfc;
-
-- /* qca8081 takes the different bits for speed value from at803x */
-- if (phydev->drv->phy_id == QCA8081_PHY_ID)
-- speed = FIELD_GET(QCA808X_SS_SPEED_MASK, ss);
-- else
-- speed = FIELD_GET(AT803X_SS_SPEED_MASK, ss);
-+ speed = ss & ss_mask.speed_mask;
-+ speed >>= ss_mask.speed_shift;
-
- switch (speed) {
- case AT803X_SS_SPEED_10:
-@@ -989,6 +992,7 @@ static int at803x_read_specific_status(s
- static int at803x_read_status(struct phy_device *phydev)
- {
- struct at803x_priv *priv = phydev->priv;
-+ struct at803x_ss_mask ss_mask = { 0 };
- int err, old_link = phydev->link;
-
- if (priv->is_1000basex)
-@@ -1012,7 +1016,9 @@ static int at803x_read_status(struct phy
- if (err < 0)
- return err;
-
-- err = at803x_read_specific_status(phydev);
-+ ss_mask.speed_mask = AT803X_SS_SPEED_MASK;
-+ ss_mask.speed_shift = __bf_shf(AT803X_SS_SPEED_MASK);
-+ err = at803x_read_specific_status(phydev, ss_mask);
- if (err < 0)
- return err;
-
-@@ -1869,6 +1875,7 @@ static int qca808x_config_init(struct ph
-
- static int qca808x_read_status(struct phy_device *phydev)
- {
-+ struct at803x_ss_mask ss_mask = { 0 };
- int ret;
-
- ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_10GBT_STAT);
-@@ -1882,7 +1889,10 @@ static int qca808x_read_status(struct ph
- if (ret)
- return ret;
-
-- ret = at803x_read_specific_status(phydev);
-+ /* qca8081 takes the different bits for speed value from at803x */
-+ ss_mask.speed_mask = QCA808X_SS_SPEED_MASK;
-+ ss_mask.speed_shift = __bf_shf(QCA808X_SS_SPEED_MASK);
-+ ret = at803x_read_specific_status(phydev, ss_mask);
- if (ret < 0)
- return ret;
-
+++ /dev/null
-From fc9d7264ddc32eaa647d6bfcdc25cdf9f786fde0 Mon Sep 17 00:00:00 2001
-Date: Mon, 18 Dec 2023 00:27:39 +0100
-Subject: [PATCH 1/2] net: phy: at803x: remove extra space after cast
-
-Remove extra space after cast as reported by checkpatch to keep code
-clean.
-
----
- drivers/net/phy/at803x.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/net/phy/at803x.c
-+++ b/drivers/net/phy/at803x.c
-@@ -462,7 +462,7 @@ static int at803x_set_wol(struct phy_dev
- if (!ndev)
- return -ENODEV;
-
-- mac = (const u8 *) ndev->dev_addr;
-+ mac = (const u8 *)ndev->dev_addr;
-
- if (!is_valid_ether_addr(mac))
- return -EINVAL;
+++ /dev/null
-From 3ab5720881a924fb6405d9e6a3b09f1026467c47 Mon Sep 17 00:00:00 2001
-Date: Mon, 18 Dec 2023 00:25:08 +0100
-Subject: [PATCH 2/2] net: phy: at803x: replace msleep(1) with usleep_range
-
-Replace msleep(1) with usleep_range as suggested by timers-howto guide.
-
----
- drivers/net/phy/at803x.c | 6 +++---
- 1 file changed, 3 insertions(+), 3 deletions(-)
-
---- a/drivers/net/phy/at803x.c
-+++ b/drivers/net/phy/at803x.c
-@@ -916,9 +916,9 @@ static void at803x_link_change_notify(st
- at803x_context_save(phydev, &context);
-
- phy_device_reset(phydev, 1);
-- msleep(1);
-+ usleep_range(1000, 2000);
- phy_device_reset(phydev, 0);
-- msleep(1);
-+ usleep_range(1000, 2000);
-
- at803x_context_restore(phydev, &context);
-
-@@ -1733,7 +1733,7 @@ static int qca83xx_resume(struct phy_dev
- if (ret)
- return ret;
-
-- msleep(1);
-+ usleep_range(1000, 2000);
-
- return 0;
- }
+++ /dev/null
-From 7961ef1fa10ec35ad6923fb5751877116e4b035b Mon Sep 17 00:00:00 2001
-Date: Tue, 19 Dec 2023 21:21:24 +0100
-Subject: [PATCH] net: phy: at803x: better align function varibles to open
- parenthesis
-
-Better align function variables to open parenthesis as suggested by
-checkpatch script for qca808x function to make code cleaner.
-
-For cable_test_get_status function some additional rework was needed to
-handle too long functions.
-
----
- drivers/net/phy/at803x.c | 67 ++++++++++++++++++++++------------------
- 1 file changed, 37 insertions(+), 30 deletions(-)
-
---- a/drivers/net/phy/at803x.c
-+++ b/drivers/net/phy/at803x.c
-@@ -1781,27 +1781,27 @@ static int qca808x_phy_fast_retrain_conf
- return ret;
-
- phy_write_mmd(phydev, MDIO_MMD_AN, QCA808X_PHY_MMD7_TOP_OPTION1,
-- QCA808X_TOP_OPTION1_DATA);
-+ QCA808X_TOP_OPTION1_DATA);
- phy_write_mmd(phydev, MDIO_MMD_PMAPMD, QCA808X_PHY_MMD1_MSE_THRESHOLD_20DB,
-- QCA808X_MSE_THRESHOLD_20DB_VALUE);
-+ QCA808X_MSE_THRESHOLD_20DB_VALUE);
- phy_write_mmd(phydev, MDIO_MMD_PMAPMD, QCA808X_PHY_MMD1_MSE_THRESHOLD_17DB,
-- QCA808X_MSE_THRESHOLD_17DB_VALUE);
-+ QCA808X_MSE_THRESHOLD_17DB_VALUE);
- phy_write_mmd(phydev, MDIO_MMD_PMAPMD, QCA808X_PHY_MMD1_MSE_THRESHOLD_27DB,
-- QCA808X_MSE_THRESHOLD_27DB_VALUE);
-+ QCA808X_MSE_THRESHOLD_27DB_VALUE);
- phy_write_mmd(phydev, MDIO_MMD_PMAPMD, QCA808X_PHY_MMD1_MSE_THRESHOLD_28DB,
-- QCA808X_MSE_THRESHOLD_28DB_VALUE);
-+ QCA808X_MSE_THRESHOLD_28DB_VALUE);
- phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_1,
-- QCA808X_MMD3_DEBUG_1_VALUE);
-+ QCA808X_MMD3_DEBUG_1_VALUE);
- phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_4,
-- QCA808X_MMD3_DEBUG_4_VALUE);
-+ QCA808X_MMD3_DEBUG_4_VALUE);
- phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_5,
-- QCA808X_MMD3_DEBUG_5_VALUE);
-+ QCA808X_MMD3_DEBUG_5_VALUE);
- phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_3,
-- QCA808X_MMD3_DEBUG_3_VALUE);
-+ QCA808X_MMD3_DEBUG_3_VALUE);
- phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_6,
-- QCA808X_MMD3_DEBUG_6_VALUE);
-+ QCA808X_MMD3_DEBUG_6_VALUE);
- phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_2,
-- QCA808X_MMD3_DEBUG_2_VALUE);
-+ QCA808X_MMD3_DEBUG_2_VALUE);
-
- return 0;
- }
-@@ -1838,13 +1838,14 @@ static int qca808x_config_init(struct ph
-
- /* Active adc&vga on 802.3az for the link 1000M and 100M */
- ret = phy_modify_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_ADDR_CLD_CTRL7,
-- QCA808X_8023AZ_AFE_CTRL_MASK, QCA808X_8023AZ_AFE_EN);
-+ QCA808X_8023AZ_AFE_CTRL_MASK, QCA808X_8023AZ_AFE_EN);
- if (ret)
- return ret;
-
- /* Adjust the threshold on 802.3az for the link 1000M */
- ret = phy_write_mmd(phydev, MDIO_MMD_PCS,
-- QCA808X_PHY_MMD3_AZ_TRAINING_CTRL, QCA808X_MMD3_AZ_TRAINING_VAL);
-+ QCA808X_PHY_MMD3_AZ_TRAINING_CTRL,
-+ QCA808X_MMD3_AZ_TRAINING_VAL);
- if (ret)
- return ret;
-
-@@ -1870,7 +1871,8 @@ static int qca808x_config_init(struct ph
-
- /* Configure adc threshold as 100mv for the link 10M */
- return at803x_debug_reg_mask(phydev, QCA808X_PHY_DEBUG_ADC_THRESHOLD,
-- QCA808X_ADC_THRESHOLD_MASK, QCA808X_ADC_THRESHOLD_100MV);
-+ QCA808X_ADC_THRESHOLD_MASK,
-+ QCA808X_ADC_THRESHOLD_100MV);
- }
-
- static int qca808x_read_status(struct phy_device *phydev)
-@@ -1883,7 +1885,7 @@ static int qca808x_read_status(struct ph
- return ret;
-
- linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, phydev->lp_advertising,
-- ret & MDIO_AN_10GBT_STAT_LP2_5G);
-+ ret & MDIO_AN_10GBT_STAT_LP2_5G);
-
- ret = genphy_read_status(phydev);
- if (ret)
-@@ -1913,7 +1915,7 @@ static int qca808x_read_status(struct ph
- */
- if (qca808x_has_fast_retrain_or_slave_seed(phydev)) {
- if (phydev->master_slave_state == MASTER_SLAVE_STATE_ERR ||
-- qca808x_is_prefer_master(phydev)) {
-+ qca808x_is_prefer_master(phydev)) {
- qca808x_phy_ms_seed_enable(phydev, false);
- } else {
- qca808x_phy_ms_seed_enable(phydev, true);
-@@ -2070,18 +2072,22 @@ static int qca808x_cable_test_get_status
- ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_D,
- qca808x_cable_test_result_trans(pair_d));
-
-- if (qca808x_cdt_fault_length_valid(pair_a))
-- ethnl_cable_test_fault_length(phydev, ETHTOOL_A_CABLE_PAIR_A,
-- qca808x_cdt_fault_length(phydev, ETHTOOL_A_CABLE_PAIR_A));
-- if (qca808x_cdt_fault_length_valid(pair_b))
-- ethnl_cable_test_fault_length(phydev, ETHTOOL_A_CABLE_PAIR_B,
-- qca808x_cdt_fault_length(phydev, ETHTOOL_A_CABLE_PAIR_B));
-- if (qca808x_cdt_fault_length_valid(pair_c))
-- ethnl_cable_test_fault_length(phydev, ETHTOOL_A_CABLE_PAIR_C,
-- qca808x_cdt_fault_length(phydev, ETHTOOL_A_CABLE_PAIR_C));
-- if (qca808x_cdt_fault_length_valid(pair_d))
-- ethnl_cable_test_fault_length(phydev, ETHTOOL_A_CABLE_PAIR_D,
-- qca808x_cdt_fault_length(phydev, ETHTOOL_A_CABLE_PAIR_D));
-+ if (qca808x_cdt_fault_length_valid(pair_a)) {
-+ val = qca808x_cdt_fault_length(phydev, ETHTOOL_A_CABLE_PAIR_A);
-+ ethnl_cable_test_fault_length(phydev, ETHTOOL_A_CABLE_PAIR_A, val);
-+ }
-+ if (qca808x_cdt_fault_length_valid(pair_b)) {
-+ val = qca808x_cdt_fault_length(phydev, ETHTOOL_A_CABLE_PAIR_B);
-+ ethnl_cable_test_fault_length(phydev, ETHTOOL_A_CABLE_PAIR_B, val);
-+ }
-+ if (qca808x_cdt_fault_length_valid(pair_c)) {
-+ val = qca808x_cdt_fault_length(phydev, ETHTOOL_A_CABLE_PAIR_C);
-+ ethnl_cable_test_fault_length(phydev, ETHTOOL_A_CABLE_PAIR_C, val);
-+ }
-+ if (qca808x_cdt_fault_length_valid(pair_d)) {
-+ val = qca808x_cdt_fault_length(phydev, ETHTOOL_A_CABLE_PAIR_D);
-+ ethnl_cable_test_fault_length(phydev, ETHTOOL_A_CABLE_PAIR_D, val);
-+ }
-
- *finished = true;
-
-@@ -2148,8 +2154,9 @@ static void qca808x_link_change_notify(s
- * the interface device address is always phy address added by 1.
- */
- mdiobus_c45_modify_changed(phydev->mdio.bus, phydev->mdio.addr + 1,
-- MDIO_MMD_PMAPMD, QCA8081_PHY_SERDES_MMD1_FIFO_CTRL,
-- QCA8081_PHY_FIFO_RSTN, phydev->link ? QCA8081_PHY_FIFO_RSTN : 0);
-+ MDIO_MMD_PMAPMD, QCA8081_PHY_SERDES_MMD1_FIFO_CTRL,
-+ QCA8081_PHY_FIFO_RSTN,
-+ phydev->link ? QCA8081_PHY_FIFO_RSTN : 0);
- }
-
- static struct phy_driver at803x_driver[] = {
+++ /dev/null
-From 22eb276098da820d9440fad22901f9b74ed4d659 Mon Sep 17 00:00:00 2001
-Date: Thu, 4 Jan 2024 22:30:38 +0100
-Subject: [PATCH 1/4] net: phy: at803x: generalize cdt fault length function
-
-Generalize cable test fault length function since they all base on the
-same magic values (already reverse engineered to understand the meaning
-of it) to have consistenct values on every PHY.
-
----
- drivers/net/phy/at803x.c | 13 ++++++-------
- 1 file changed, 6 insertions(+), 7 deletions(-)
-
---- a/drivers/net/phy/at803x.c
-+++ b/drivers/net/phy/at803x.c
-@@ -1192,10 +1192,8 @@ static bool at803x_cdt_fault_length_vali
- return false;
- }
-
--static int at803x_cdt_fault_length(u16 status)
-+static int at803x_cdt_fault_length(int dt)
- {
-- int dt;
--
- /* According to the datasheet the distance to the fault is
- * DELTA_TIME * 0.824 meters.
- *
-@@ -1211,8 +1209,6 @@ static int at803x_cdt_fault_length(u16 s
- * With a VF of 0.69 we get the factor 0.824 mentioned in the
- * datasheet.
- */
-- dt = FIELD_GET(AT803X_CDT_STATUS_DELTA_TIME_MASK, status);
--
- return (dt * 824) / 10;
- }
-
-@@ -1265,9 +1261,11 @@ static int at803x_cable_test_one_pair(st
- ethnl_cable_test_result(phydev, ethtool_pair[pair],
- at803x_cable_test_result_trans(val));
-
-- if (at803x_cdt_fault_length_valid(val))
-+ if (at803x_cdt_fault_length_valid(val)) {
-+ val = FIELD_GET(AT803X_CDT_STATUS_DELTA_TIME_MASK, val);
- ethnl_cable_test_fault_length(phydev, ethtool_pair[pair],
- at803x_cdt_fault_length(val));
-+ }
-
- return 1;
- }
-@@ -1992,7 +1990,8 @@ static int qca808x_cdt_fault_length(stru
- if (val < 0)
- return val;
-
-- return (FIELD_GET(QCA808X_CDT_DIAG_LENGTH, val) * 824) / 10;
-+ val = FIELD_GET(QCA808X_CDT_DIAG_LENGTH, val);
-+ return at803x_cdt_fault_length(val);
- }
-
- static int qca808x_cable_test_start(struct phy_device *phydev)
+++ /dev/null
-From e0e9ada1df6133513249861c1d91c1dbefd9383b Mon Sep 17 00:00:00 2001
-Date: Thu, 4 Jan 2024 22:30:39 +0100
-Subject: [PATCH 2/4] net: phy: at803x: refactor qca808x cable test get status
- function
-
-Refactor qca808x cable test get status function to remove code
-duplication and clean things up.
-
-The same logic is applied to each pair hence it can be generalized and
-moved to a common function.
-
----
- drivers/net/phy/at803x.c | 80 ++++++++++++++++++++++++----------------
- 1 file changed, 49 insertions(+), 31 deletions(-)
-
---- a/drivers/net/phy/at803x.c
-+++ b/drivers/net/phy/at803x.c
-@@ -2035,10 +2035,43 @@ static int qca808x_cable_test_start(stru
- return 0;
- }
-
-+static int qca808x_cable_test_get_pair_status(struct phy_device *phydev, u8 pair,
-+ u16 status)
-+{
-+ u16 pair_code;
-+ int length;
-+
-+ switch (pair) {
-+ case ETHTOOL_A_CABLE_PAIR_A:
-+ pair_code = FIELD_GET(QCA808X_CDT_CODE_PAIR_A, status);
-+ break;
-+ case ETHTOOL_A_CABLE_PAIR_B:
-+ pair_code = FIELD_GET(QCA808X_CDT_CODE_PAIR_B, status);
-+ break;
-+ case ETHTOOL_A_CABLE_PAIR_C:
-+ pair_code = FIELD_GET(QCA808X_CDT_CODE_PAIR_C, status);
-+ break;
-+ case ETHTOOL_A_CABLE_PAIR_D:
-+ pair_code = FIELD_GET(QCA808X_CDT_CODE_PAIR_D, status);
-+ break;
-+ default:
-+ return -EINVAL;
-+ }
-+
-+ ethnl_cable_test_result(phydev, pair,
-+ qca808x_cable_test_result_trans(pair_code));
-+
-+ if (qca808x_cdt_fault_length_valid(pair_code)) {
-+ length = qca808x_cdt_fault_length(phydev, pair);
-+ ethnl_cable_test_fault_length(phydev, pair, length);
-+ }
-+
-+ return 0;
-+}
-+
- static int qca808x_cable_test_get_status(struct phy_device *phydev, bool *finished)
- {
- int ret, val;
-- int pair_a, pair_b, pair_c, pair_d;
-
- *finished = false;
-
-@@ -2057,36 +2090,21 @@ static int qca808x_cable_test_get_status
- if (val < 0)
- return val;
-
-- pair_a = FIELD_GET(QCA808X_CDT_CODE_PAIR_A, val);
-- pair_b = FIELD_GET(QCA808X_CDT_CODE_PAIR_B, val);
-- pair_c = FIELD_GET(QCA808X_CDT_CODE_PAIR_C, val);
-- pair_d = FIELD_GET(QCA808X_CDT_CODE_PAIR_D, val);
--
-- ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_A,
-- qca808x_cable_test_result_trans(pair_a));
-- ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_B,
-- qca808x_cable_test_result_trans(pair_b));
-- ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_C,
-- qca808x_cable_test_result_trans(pair_c));
-- ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_D,
-- qca808x_cable_test_result_trans(pair_d));
--
-- if (qca808x_cdt_fault_length_valid(pair_a)) {
-- val = qca808x_cdt_fault_length(phydev, ETHTOOL_A_CABLE_PAIR_A);
-- ethnl_cable_test_fault_length(phydev, ETHTOOL_A_CABLE_PAIR_A, val);
-- }
-- if (qca808x_cdt_fault_length_valid(pair_b)) {
-- val = qca808x_cdt_fault_length(phydev, ETHTOOL_A_CABLE_PAIR_B);
-- ethnl_cable_test_fault_length(phydev, ETHTOOL_A_CABLE_PAIR_B, val);
-- }
-- if (qca808x_cdt_fault_length_valid(pair_c)) {
-- val = qca808x_cdt_fault_length(phydev, ETHTOOL_A_CABLE_PAIR_C);
-- ethnl_cable_test_fault_length(phydev, ETHTOOL_A_CABLE_PAIR_C, val);
-- }
-- if (qca808x_cdt_fault_length_valid(pair_d)) {
-- val = qca808x_cdt_fault_length(phydev, ETHTOOL_A_CABLE_PAIR_D);
-- ethnl_cable_test_fault_length(phydev, ETHTOOL_A_CABLE_PAIR_D, val);
-- }
-+ ret = qca808x_cable_test_get_pair_status(phydev, ETHTOOL_A_CABLE_PAIR_A, val);
-+ if (ret)
-+ return ret;
-+
-+ ret = qca808x_cable_test_get_pair_status(phydev, ETHTOOL_A_CABLE_PAIR_B, val);
-+ if (ret)
-+ return ret;
-+
-+ ret = qca808x_cable_test_get_pair_status(phydev, ETHTOOL_A_CABLE_PAIR_C, val);
-+ if (ret)
-+ return ret;
-+
-+ ret = qca808x_cable_test_get_pair_status(phydev, ETHTOOL_A_CABLE_PAIR_D, val);
-+ if (ret)
-+ return ret;
-
- *finished = true;
-
+++ /dev/null
-From ea73e5ea442ee2aade67b1fb1233ccb3cbea2ceb Mon Sep 17 00:00:00 2001
-Date: Thu, 4 Jan 2024 22:30:40 +0100
-Subject: [PATCH 3/4] net: phy: at803x: add support for cdt cross short test
- for qca808x
-
-QCA808x PHY Family supports Cable Diagnostic Test also for Cross Pair
-Short.
-
-Add all the define to make enable and support these additional tests.
-
-Cross Short test was previously disabled by default, this is now changed
-and enabled by default. In this mode, the mask changed a bit and length
-is shifted based on the fault condition.
-
----
- drivers/net/phy/at803x.c | 86 ++++++++++++++++++++++++++++++++--------
- 1 file changed, 69 insertions(+), 17 deletions(-)
-
---- a/drivers/net/phy/at803x.c
-+++ b/drivers/net/phy/at803x.c
-@@ -254,6 +254,7 @@
-
- #define QCA808X_CDT_ENABLE_TEST BIT(15)
- #define QCA808X_CDT_INTER_CHECK_DIS BIT(13)
-+#define QCA808X_CDT_STATUS BIT(11)
- #define QCA808X_CDT_LENGTH_UNIT BIT(10)
-
- #define QCA808X_MMD3_CDT_STATUS 0x8064
-@@ -261,16 +262,44 @@
- #define QCA808X_MMD3_CDT_DIAG_PAIR_B 0x8066
- #define QCA808X_MMD3_CDT_DIAG_PAIR_C 0x8067
- #define QCA808X_MMD3_CDT_DIAG_PAIR_D 0x8068
--#define QCA808X_CDT_DIAG_LENGTH GENMASK(7, 0)
-+#define QCA808X_CDT_DIAG_LENGTH_SAME_SHORT GENMASK(15, 8)
-+#define QCA808X_CDT_DIAG_LENGTH_CROSS_SHORT GENMASK(7, 0)
-
- #define QCA808X_CDT_CODE_PAIR_A GENMASK(15, 12)
- #define QCA808X_CDT_CODE_PAIR_B GENMASK(11, 8)
- #define QCA808X_CDT_CODE_PAIR_C GENMASK(7, 4)
- #define QCA808X_CDT_CODE_PAIR_D GENMASK(3, 0)
--#define QCA808X_CDT_STATUS_STAT_FAIL 0
--#define QCA808X_CDT_STATUS_STAT_NORMAL 1
--#define QCA808X_CDT_STATUS_STAT_OPEN 2
--#define QCA808X_CDT_STATUS_STAT_SHORT 3
-+
-+#define QCA808X_CDT_STATUS_STAT_TYPE GENMASK(1, 0)
-+#define QCA808X_CDT_STATUS_STAT_FAIL FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_TYPE, 0)
-+#define QCA808X_CDT_STATUS_STAT_NORMAL FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_TYPE, 1)
-+#define QCA808X_CDT_STATUS_STAT_SAME_OPEN FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_TYPE, 2)
-+#define QCA808X_CDT_STATUS_STAT_SAME_SHORT FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_TYPE, 3)
-+
-+#define QCA808X_CDT_STATUS_STAT_MDI GENMASK(3, 2)
-+#define QCA808X_CDT_STATUS_STAT_MDI1 FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_MDI, 1)
-+#define QCA808X_CDT_STATUS_STAT_MDI2 FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_MDI, 2)
-+#define QCA808X_CDT_STATUS_STAT_MDI3 FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_MDI, 3)
-+
-+/* NORMAL are MDI with type set to 0 */
-+#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_NORMAL QCA808X_CDT_STATUS_STAT_MDI1
-+#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_OPEN (QCA808X_CDT_STATUS_STAT_SAME_OPEN |\
-+ QCA808X_CDT_STATUS_STAT_MDI1)
-+#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_SHORT (QCA808X_CDT_STATUS_STAT_SAME_SHORT |\
-+ QCA808X_CDT_STATUS_STAT_MDI1)
-+#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_NORMAL QCA808X_CDT_STATUS_STAT_MDI2
-+#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_OPEN (QCA808X_CDT_STATUS_STAT_SAME_OPEN |\
-+ QCA808X_CDT_STATUS_STAT_MDI2)
-+#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_SHORT (QCA808X_CDT_STATUS_STAT_SAME_SHORT |\
-+ QCA808X_CDT_STATUS_STAT_MDI2)
-+#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_NORMAL QCA808X_CDT_STATUS_STAT_MDI3
-+#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_OPEN (QCA808X_CDT_STATUS_STAT_SAME_OPEN |\
-+ QCA808X_CDT_STATUS_STAT_MDI3)
-+#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_SHORT (QCA808X_CDT_STATUS_STAT_SAME_SHORT |\
-+ QCA808X_CDT_STATUS_STAT_MDI3)
-+
-+/* Added for reference of existence but should be handled by wait_for_completion already */
-+#define QCA808X_CDT_STATUS_STAT_BUSY (BIT(1) | BIT(3))
-
- /* QCA808X 1G chip type */
- #define QCA808X_PHY_MMD7_CHIP_TYPE 0x901d
-@@ -1941,8 +1970,17 @@ static int qca808x_soft_reset(struct phy
- static bool qca808x_cdt_fault_length_valid(int cdt_code)
- {
- switch (cdt_code) {
-- case QCA808X_CDT_STATUS_STAT_SHORT:
-- case QCA808X_CDT_STATUS_STAT_OPEN:
-+ case QCA808X_CDT_STATUS_STAT_SAME_SHORT:
-+ case QCA808X_CDT_STATUS_STAT_SAME_OPEN:
-+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_NORMAL:
-+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_OPEN:
-+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_SHORT:
-+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_NORMAL:
-+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_OPEN:
-+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_SHORT:
-+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_NORMAL:
-+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_OPEN:
-+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_SHORT:
- return true;
- default:
- return false;
-@@ -1954,17 +1992,28 @@ static int qca808x_cable_test_result_tra
- switch (cdt_code) {
- case QCA808X_CDT_STATUS_STAT_NORMAL:
- return ETHTOOL_A_CABLE_RESULT_CODE_OK;
-- case QCA808X_CDT_STATUS_STAT_SHORT:
-+ case QCA808X_CDT_STATUS_STAT_SAME_SHORT:
- return ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT;
-- case QCA808X_CDT_STATUS_STAT_OPEN:
-+ case QCA808X_CDT_STATUS_STAT_SAME_OPEN:
- return ETHTOOL_A_CABLE_RESULT_CODE_OPEN;
-+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_NORMAL:
-+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_OPEN:
-+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_SHORT:
-+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_NORMAL:
-+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_OPEN:
-+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_SHORT:
-+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_NORMAL:
-+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_OPEN:
-+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_SHORT:
-+ return ETHTOOL_A_CABLE_RESULT_CODE_CROSS_SHORT;
- case QCA808X_CDT_STATUS_STAT_FAIL:
- default:
- return ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC;
- }
- }
-
--static int qca808x_cdt_fault_length(struct phy_device *phydev, int pair)
-+static int qca808x_cdt_fault_length(struct phy_device *phydev, int pair,
-+ int result)
- {
- int val;
- u32 cdt_length_reg = 0;
-@@ -1990,7 +2039,11 @@ static int qca808x_cdt_fault_length(stru
- if (val < 0)
- return val;
-
-- val = FIELD_GET(QCA808X_CDT_DIAG_LENGTH, val);
-+ if (result == ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT)
-+ val = FIELD_GET(QCA808X_CDT_DIAG_LENGTH_SAME_SHORT, val);
-+ else
-+ val = FIELD_GET(QCA808X_CDT_DIAG_LENGTH_CROSS_SHORT, val);
-+
- return at803x_cdt_fault_length(val);
- }
-
-@@ -2038,8 +2091,8 @@ static int qca808x_cable_test_start(stru
- static int qca808x_cable_test_get_pair_status(struct phy_device *phydev, u8 pair,
- u16 status)
- {
-+ int length, result;
- u16 pair_code;
-- int length;
-
- switch (pair) {
- case ETHTOOL_A_CABLE_PAIR_A:
-@@ -2058,11 +2111,11 @@ static int qca808x_cable_test_get_pair_s
- return -EINVAL;
- }
-
-- ethnl_cable_test_result(phydev, pair,
-- qca808x_cable_test_result_trans(pair_code));
-+ result = qca808x_cable_test_result_trans(pair_code);
-+ ethnl_cable_test_result(phydev, pair, result);
-
- if (qca808x_cdt_fault_length_valid(pair_code)) {
-- length = qca808x_cdt_fault_length(phydev, pair);
-+ length = qca808x_cdt_fault_length(phydev, pair, result);
- ethnl_cable_test_fault_length(phydev, pair, length);
- }
-
-@@ -2076,8 +2129,7 @@ static int qca808x_cable_test_get_status
- *finished = false;
-
- val = QCA808X_CDT_ENABLE_TEST |
-- QCA808X_CDT_LENGTH_UNIT |
-- QCA808X_CDT_INTER_CHECK_DIS;
-+ QCA808X_CDT_LENGTH_UNIT;
- ret = at803x_cdt_start(phydev, val);
- if (ret)
- return ret;
+++ /dev/null
-From c34d9452d4e5d98a655d7b625e85466320885416 Mon Sep 17 00:00:00 2001
-Date: Thu, 4 Jan 2024 22:30:41 +0100
-Subject: [PATCH 4/4] net: phy: at803x: make read_status more generic
-
-Make read_status more generic in preparation on moving it to shared
-library as other PHY Family Driver will have the exact same
-implementation.
-
-The only specific part was a check for AR8031/33 if 1000basex was used.
-The check is moved to a dedicated function specific for those PHYs.
-
----
- drivers/net/phy/at803x.c | 17 ++++++++++++-----
- 1 file changed, 12 insertions(+), 5 deletions(-)
-
---- a/drivers/net/phy/at803x.c
-+++ b/drivers/net/phy/at803x.c
-@@ -1020,13 +1020,9 @@ static int at803x_read_specific_status(s
-
- static int at803x_read_status(struct phy_device *phydev)
- {
-- struct at803x_priv *priv = phydev->priv;
- struct at803x_ss_mask ss_mask = { 0 };
- int err, old_link = phydev->link;
-
-- if (priv->is_1000basex)
-- return genphy_c37_read_status(phydev);
--
- /* Update the link, but return if there was an error */
- err = genphy_update_link(phydev);
- if (err)
-@@ -1618,6 +1614,17 @@ static int at8031_config_intr(struct phy
- return at803x_config_intr(phydev);
- }
-
-+/* AR8031 and AR8033 share the same read status logic */
-+static int at8031_read_status(struct phy_device *phydev)
-+{
-+ struct at803x_priv *priv = phydev->priv;
-+
-+ if (priv->is_1000basex)
-+ return genphy_c37_read_status(phydev);
-+
-+ return at803x_read_status(phydev);
-+}
-+
- /* AR8031 and AR8035 share the same cable test get status reg */
- static int at8031_cable_test_get_status(struct phy_device *phydev,
- bool *finished)
-@@ -2281,7 +2288,7 @@ static struct phy_driver at803x_driver[]
- .read_page = at803x_read_page,
- .write_page = at803x_write_page,
- .get_features = at803x_get_features,
-- .read_status = at803x_read_status,
-+ .read_status = at8031_read_status,
- .config_intr = at8031_config_intr,
- .handle_interrupt = at803x_handle_interrupt,
- .get_tunable = at803x_get_tunable,
+++ /dev/null
-From 7196062b64ee470b91015f3d2e82d225948258ea Mon Sep 17 00:00:00 2001
-Date: Thu, 25 Jan 2024 21:37:01 +0100
-Subject: [PATCH 5/5] net: phy: at803x: add LED support for qca808x
-
-Add LED support for QCA8081 PHY.
-
-Documentation for this LEDs PHY is very scarce even with NDA access
-to Documentation for OEMs. Only the blink pattern are documented and are
-very confusing most of the time. No documentation is present about
-forcing the LED on/off or to always blink.
-
-Those settings were reversed by poking the regs and trying to find the
-correct bits to trigger these modes. Some bits mode are not clear and
-maybe the documentation option are not 100% correct. For the sake of LED
-support the reversed option are enough to add support for current LED
-APIs.
-
-Supported HW control modes are:
-- tx
-- rx
-- link_10
-- link_100
-- link_1000
-- link_2500
-- half_duplex
-- full_duplex
-
-Also add support for LED polarity set to set LED polarity to active
-high or low. QSDK sets this value to high by default but PHY reset value
-doesn't have this enabled by default.
-
-QSDK also sets 2 additional bits but their usage is not clear, info about
-this is added in the header. It was verified that for correct function
-of the LED if active high is needed, only BIT 6 is needed.
-
----
- drivers/net/phy/at803x.c | 327 +++++++++++++++++++++++++++++++++++++++
- 1 file changed, 327 insertions(+)
-
---- a/drivers/net/phy/at803x.c
-+++ b/drivers/net/phy/at803x.c
-@@ -301,6 +301,87 @@
- /* Added for reference of existence but should be handled by wait_for_completion already */
- #define QCA808X_CDT_STATUS_STAT_BUSY (BIT(1) | BIT(3))
-
-+#define QCA808X_MMD7_LED_GLOBAL 0x8073
-+#define QCA808X_LED_BLINK_1 GENMASK(11, 6)
-+#define QCA808X_LED_BLINK_2 GENMASK(5, 0)
-+/* Values are the same for both BLINK_1 and BLINK_2 */
-+#define QCA808X_LED_BLINK_FREQ_MASK GENMASK(5, 3)
-+#define QCA808X_LED_BLINK_FREQ_2HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x0)
-+#define QCA808X_LED_BLINK_FREQ_4HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x1)
-+#define QCA808X_LED_BLINK_FREQ_8HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x2)
-+#define QCA808X_LED_BLINK_FREQ_16HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x3)
-+#define QCA808X_LED_BLINK_FREQ_32HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x4)
-+#define QCA808X_LED_BLINK_FREQ_64HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x5)
-+#define QCA808X_LED_BLINK_FREQ_128HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x6)
-+#define QCA808X_LED_BLINK_FREQ_256HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x7)
-+#define QCA808X_LED_BLINK_DUTY_MASK GENMASK(2, 0)
-+#define QCA808X_LED_BLINK_DUTY_50_50 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x0)
-+#define QCA808X_LED_BLINK_DUTY_75_25 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x1)
-+#define QCA808X_LED_BLINK_DUTY_25_75 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x2)
-+#define QCA808X_LED_BLINK_DUTY_33_67 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x3)
-+#define QCA808X_LED_BLINK_DUTY_67_33 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x4)
-+#define QCA808X_LED_BLINK_DUTY_17_83 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x5)
-+#define QCA808X_LED_BLINK_DUTY_83_17 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x6)
-+#define QCA808X_LED_BLINK_DUTY_8_92 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x7)
-+
-+#define QCA808X_MMD7_LED2_CTRL 0x8074
-+#define QCA808X_MMD7_LED2_FORCE_CTRL 0x8075
-+#define QCA808X_MMD7_LED1_CTRL 0x8076
-+#define QCA808X_MMD7_LED1_FORCE_CTRL 0x8077
-+#define QCA808X_MMD7_LED0_CTRL 0x8078
-+#define QCA808X_MMD7_LED_CTRL(x) (0x8078 - ((x) * 2))
-+
-+/* LED hw control pattern is the same for every LED */
-+#define QCA808X_LED_PATTERN_MASK GENMASK(15, 0)
-+#define QCA808X_LED_SPEED2500_ON BIT(15)
-+#define QCA808X_LED_SPEED2500_BLINK BIT(14)
-+/* Follow blink trigger even if duplex or speed condition doesn't match */
-+#define QCA808X_LED_BLINK_CHECK_BYPASS BIT(13)
-+#define QCA808X_LED_FULL_DUPLEX_ON BIT(12)
-+#define QCA808X_LED_HALF_DUPLEX_ON BIT(11)
-+#define QCA808X_LED_TX_BLINK BIT(10)
-+#define QCA808X_LED_RX_BLINK BIT(9)
-+#define QCA808X_LED_TX_ON_10MS BIT(8)
-+#define QCA808X_LED_RX_ON_10MS BIT(7)
-+#define QCA808X_LED_SPEED1000_ON BIT(6)
-+#define QCA808X_LED_SPEED100_ON BIT(5)
-+#define QCA808X_LED_SPEED10_ON BIT(4)
-+#define QCA808X_LED_COLLISION_BLINK BIT(3)
-+#define QCA808X_LED_SPEED1000_BLINK BIT(2)
-+#define QCA808X_LED_SPEED100_BLINK BIT(1)
-+#define QCA808X_LED_SPEED10_BLINK BIT(0)
-+
-+#define QCA808X_MMD7_LED0_FORCE_CTRL 0x8079
-+#define QCA808X_MMD7_LED_FORCE_CTRL(x) (0x8079 - ((x) * 2))
-+
-+/* LED force ctrl is the same for every LED
-+ * No documentation exist for this, not even internal one
-+ * with NDA as QCOM gives only info about configuring
-+ * hw control pattern rules and doesn't indicate any way
-+ * to force the LED to specific mode.
-+ * These define comes from reverse and testing and maybe
-+ * lack of some info or some info are not entirely correct.
-+ * For the basic LED control and hw control these finding
-+ * are enough to support LED control in all the required APIs.
-+ *
-+ * On doing some comparison with implementation with qca807x,
-+ * it was found that it's 1:1 equal to it and confirms all the
-+ * reverse done. It was also found further specification with the
-+ * force mode and the blink modes.
-+ */
-+#define QCA808X_LED_FORCE_EN BIT(15)
-+#define QCA808X_LED_FORCE_MODE_MASK GENMASK(14, 13)
-+#define QCA808X_LED_FORCE_BLINK_1 FIELD_PREP(QCA808X_LED_FORCE_MODE_MASK, 0x3)
-+#define QCA808X_LED_FORCE_BLINK_2 FIELD_PREP(QCA808X_LED_FORCE_MODE_MASK, 0x2)
-+#define QCA808X_LED_FORCE_ON FIELD_PREP(QCA808X_LED_FORCE_MODE_MASK, 0x1)
-+#define QCA808X_LED_FORCE_OFF FIELD_PREP(QCA808X_LED_FORCE_MODE_MASK, 0x0)
-+
-+#define QCA808X_MMD7_LED_POLARITY_CTRL 0x901a
-+/* QSDK sets by default 0x46 to this reg that sets BIT 6 for
-+ * LED to active high. It's not clear what BIT 3 and BIT 4 does.
-+ */
-+#define QCA808X_LED_ACTIVE_HIGH BIT(6)
-+
- /* QCA808X 1G chip type */
- #define QCA808X_PHY_MMD7_CHIP_TYPE 0x901d
- #define QCA808X_PHY_CHIP_TYPE_1G BIT(0)
-@@ -346,6 +427,7 @@ struct at803x_priv {
- struct regulator_dev *vddio_rdev;
- struct regulator_dev *vddh_rdev;
- u64 stats[ARRAY_SIZE(qca83xx_hw_stats)];
-+ int led_polarity_mode;
- };
-
- struct at803x_context {
-@@ -706,6 +788,9 @@ static int at803x_probe(struct phy_devic
- if (!priv)
- return -ENOMEM;
-
-+ /* Init LED polarity mode to -1 */
-+ priv->led_polarity_mode = -1;
-+
- phydev->priv = priv;
-
- ret = at803x_parse_dt(phydev);
-@@ -2235,6 +2320,242 @@ static void qca808x_link_change_notify(s
- phydev->link ? QCA8081_PHY_FIFO_RSTN : 0);
- }
-
-+static int qca808x_led_parse_netdev(struct phy_device *phydev, unsigned long rules,
-+ u16 *offload_trigger)
-+{
-+ /* Parsing specific to netdev trigger */
-+ if (test_bit(TRIGGER_NETDEV_TX, &rules))
-+ *offload_trigger |= QCA808X_LED_TX_BLINK;
-+ if (test_bit(TRIGGER_NETDEV_RX, &rules))
-+ *offload_trigger |= QCA808X_LED_RX_BLINK;
-+ if (test_bit(TRIGGER_NETDEV_LINK_10, &rules))
-+ *offload_trigger |= QCA808X_LED_SPEED10_ON;
-+ if (test_bit(TRIGGER_NETDEV_LINK_100, &rules))
-+ *offload_trigger |= QCA808X_LED_SPEED100_ON;
-+ if (test_bit(TRIGGER_NETDEV_LINK_1000, &rules))
-+ *offload_trigger |= QCA808X_LED_SPEED1000_ON;
-+ if (test_bit(TRIGGER_NETDEV_LINK_2500, &rules))
-+ *offload_trigger |= QCA808X_LED_SPEED2500_ON;
-+ if (test_bit(TRIGGER_NETDEV_HALF_DUPLEX, &rules))
-+ *offload_trigger |= QCA808X_LED_HALF_DUPLEX_ON;
-+ if (test_bit(TRIGGER_NETDEV_FULL_DUPLEX, &rules))
-+ *offload_trigger |= QCA808X_LED_FULL_DUPLEX_ON;
-+
-+ if (rules && !*offload_trigger)
-+ return -EOPNOTSUPP;
-+
-+ /* Enable BLINK_CHECK_BYPASS by default to make the LED
-+ * blink even with duplex or speed mode not enabled.
-+ */
-+ *offload_trigger |= QCA808X_LED_BLINK_CHECK_BYPASS;
-+
-+ return 0;
-+}
-+
-+static int qca808x_led_hw_control_enable(struct phy_device *phydev, u8 index)
-+{
-+ u16 reg;
-+
-+ if (index > 2)
-+ return -EINVAL;
-+
-+ reg = QCA808X_MMD7_LED_FORCE_CTRL(index);
-+
-+ return phy_clear_bits_mmd(phydev, MDIO_MMD_AN, reg,
-+ QCA808X_LED_FORCE_EN);
-+}
-+
-+static int qca808x_led_hw_is_supported(struct phy_device *phydev, u8 index,
-+ unsigned long rules)
-+{
-+ u16 offload_trigger = 0;
-+
-+ if (index > 2)
-+ return -EINVAL;
-+
-+ return qca808x_led_parse_netdev(phydev, rules, &offload_trigger);
-+}
-+
-+static int qca808x_led_hw_control_set(struct phy_device *phydev, u8 index,
-+ unsigned long rules)
-+{
-+ u16 reg, offload_trigger = 0;
-+ int ret;
-+
-+ if (index > 2)
-+ return -EINVAL;
-+
-+ reg = QCA808X_MMD7_LED_CTRL(index);
-+
-+ ret = qca808x_led_parse_netdev(phydev, rules, &offload_trigger);
-+ if (ret)
-+ return ret;
-+
-+ ret = qca808x_led_hw_control_enable(phydev, index);
-+ if (ret)
-+ return ret;
-+
-+ return phy_modify_mmd(phydev, MDIO_MMD_AN, reg,
-+ QCA808X_LED_PATTERN_MASK,
-+ offload_trigger);
-+}
-+
-+static bool qca808x_led_hw_control_status(struct phy_device *phydev, u8 index)
-+{
-+ u16 reg;
-+ int val;
-+
-+ if (index > 2)
-+ return false;
-+
-+ reg = QCA808X_MMD7_LED_FORCE_CTRL(index);
-+
-+ val = phy_read_mmd(phydev, MDIO_MMD_AN, reg);
-+
-+ return !(val & QCA808X_LED_FORCE_EN);
-+}
-+
-+static int qca808x_led_hw_control_get(struct phy_device *phydev, u8 index,
-+ unsigned long *rules)
-+{
-+ u16 reg;
-+ int val;
-+
-+ if (index > 2)
-+ return -EINVAL;
-+
-+ /* Check if we have hw control enabled */
-+ if (qca808x_led_hw_control_status(phydev, index))
-+ return -EINVAL;
-+
-+ reg = QCA808X_MMD7_LED_CTRL(index);
-+
-+ val = phy_read_mmd(phydev, MDIO_MMD_AN, reg);
-+ if (val & QCA808X_LED_TX_BLINK)
-+ set_bit(TRIGGER_NETDEV_TX, rules);
-+ if (val & QCA808X_LED_RX_BLINK)
-+ set_bit(TRIGGER_NETDEV_RX, rules);
-+ if (val & QCA808X_LED_SPEED10_ON)
-+ set_bit(TRIGGER_NETDEV_LINK_10, rules);
-+ if (val & QCA808X_LED_SPEED100_ON)
-+ set_bit(TRIGGER_NETDEV_LINK_100, rules);
-+ if (val & QCA808X_LED_SPEED1000_ON)
-+ set_bit(TRIGGER_NETDEV_LINK_1000, rules);
-+ if (val & QCA808X_LED_SPEED2500_ON)
-+ set_bit(TRIGGER_NETDEV_LINK_2500, rules);
-+ if (val & QCA808X_LED_HALF_DUPLEX_ON)
-+ set_bit(TRIGGER_NETDEV_HALF_DUPLEX, rules);
-+ if (val & QCA808X_LED_FULL_DUPLEX_ON)
-+ set_bit(TRIGGER_NETDEV_FULL_DUPLEX, rules);
-+
-+ return 0;
-+}
-+
-+static int qca808x_led_hw_control_reset(struct phy_device *phydev, u8 index)
-+{
-+ u16 reg;
-+
-+ if (index > 2)
-+ return -EINVAL;
-+
-+ reg = QCA808X_MMD7_LED_CTRL(index);
-+
-+ return phy_clear_bits_mmd(phydev, MDIO_MMD_AN, reg,
-+ QCA808X_LED_PATTERN_MASK);
-+}
-+
-+static int qca808x_led_brightness_set(struct phy_device *phydev,
-+ u8 index, enum led_brightness value)
-+{
-+ u16 reg;
-+ int ret;
-+
-+ if (index > 2)
-+ return -EINVAL;
-+
-+ if (!value) {
-+ ret = qca808x_led_hw_control_reset(phydev, index);
-+ if (ret)
-+ return ret;
-+ }
-+
-+ reg = QCA808X_MMD7_LED_FORCE_CTRL(index);
-+
-+ return phy_modify_mmd(phydev, MDIO_MMD_AN, reg,
-+ QCA808X_LED_FORCE_EN | QCA808X_LED_FORCE_MODE_MASK,
-+ QCA808X_LED_FORCE_EN | value ? QCA808X_LED_FORCE_ON :
-+ QCA808X_LED_FORCE_OFF);
-+}
-+
-+static int qca808x_led_blink_set(struct phy_device *phydev, u8 index,
-+ unsigned long *delay_on,
-+ unsigned long *delay_off)
-+{
-+ int ret;
-+ u16 reg;
-+
-+ if (index > 2)
-+ return -EINVAL;
-+
-+ reg = QCA808X_MMD7_LED_FORCE_CTRL(index);
-+
-+ /* Set blink to 50% off, 50% on at 4Hz by default */
-+ ret = phy_modify_mmd(phydev, MDIO_MMD_AN, QCA808X_MMD7_LED_GLOBAL,
-+ QCA808X_LED_BLINK_FREQ_MASK | QCA808X_LED_BLINK_DUTY_MASK,
-+ QCA808X_LED_BLINK_FREQ_4HZ | QCA808X_LED_BLINK_DUTY_50_50);
-+ if (ret)
-+ return ret;
-+
-+ /* We use BLINK_1 for normal blinking */
-+ ret = phy_modify_mmd(phydev, MDIO_MMD_AN, reg,
-+ QCA808X_LED_FORCE_EN | QCA808X_LED_FORCE_MODE_MASK,
-+ QCA808X_LED_FORCE_EN | QCA808X_LED_FORCE_BLINK_1);
-+ if (ret)
-+ return ret;
-+
-+ /* We set blink to 4Hz, aka 250ms */
-+ *delay_on = 250 / 2;
-+ *delay_off = 250 / 2;
-+
-+ return 0;
-+}
-+
-+static int qca808x_led_polarity_set(struct phy_device *phydev, int index,
-+ unsigned long modes)
-+{
-+ struct at803x_priv *priv = phydev->priv;
-+ bool active_low = false;
-+ u32 mode;
-+
-+ for_each_set_bit(mode, &modes, __PHY_LED_MODES_NUM) {
-+ switch (mode) {
-+ case PHY_LED_ACTIVE_LOW:
-+ active_low = true;
-+ break;
-+ default:
-+ return -EINVAL;
-+ }
-+ }
-+
-+ /* PHY polarity is global and can't be set per LED.
-+ * To detect this, check if last requested polarity mode
-+ * match the new one.
-+ */
-+ if (priv->led_polarity_mode >= 0 &&
-+ priv->led_polarity_mode != active_low) {
-+ phydev_err(phydev, "PHY polarity is global. Mismatched polarity on different LED\n");
-+ return -EINVAL;
-+ }
-+
-+ /* Save the last PHY polarity mode */
-+ priv->led_polarity_mode = active_low;
-+
-+ return phy_modify_mmd(phydev, MDIO_MMD_AN,
-+ QCA808X_MMD7_LED_POLARITY_CTRL,
-+ QCA808X_LED_ACTIVE_HIGH,
-+ active_low ? 0 : QCA808X_LED_ACTIVE_HIGH);
-+}
-+
- static struct phy_driver at803x_driver[] = {
- {
- /* Qualcomm Atheros AR8035 */
-@@ -2411,6 +2732,12 @@ static struct phy_driver at803x_driver[]
- .cable_test_start = qca808x_cable_test_start,
- .cable_test_get_status = qca808x_cable_test_get_status,
- .link_change_notify = qca808x_link_change_notify,
-+ .led_brightness_set = qca808x_led_brightness_set,
-+ .led_blink_set = qca808x_led_blink_set,
-+ .led_hw_is_supported = qca808x_led_hw_is_supported,
-+ .led_hw_control_set = qca808x_led_hw_control_set,
-+ .led_hw_control_get = qca808x_led_hw_control_get,
-+ .led_polarity_set = qca808x_led_polarity_set,
- }, };
-
- module_phy_driver(at803x_driver);
+++ /dev/null
-From 9e56ff53b4115875667760445b028357848b4748 Mon Sep 17 00:00:00 2001
-Date: Mon, 29 Jan 2024 15:15:19 +0100
-Subject: [PATCH 1/5] net: phy: move at803x PHY driver to dedicated directory
-
-In preparation for addition of other Qcom PHY and to tidy things up,
-move the at803x PHY driver to dedicated directory.
-
-The same order in the Kconfig selection is saved.
-
----
- drivers/net/phy/Kconfig | 7 +------
- drivers/net/phy/Makefile | 2 +-
- drivers/net/phy/qcom/Kconfig | 7 +++++++
- drivers/net/phy/qcom/Makefile | 2 ++
- drivers/net/phy/{ => qcom}/at803x.c | 0
- 5 files changed, 11 insertions(+), 7 deletions(-)
- create mode 100644 drivers/net/phy/qcom/Kconfig
- create mode 100644 drivers/net/phy/qcom/Makefile
- rename drivers/net/phy/{ => qcom}/at803x.c (100%)
-
---- a/drivers/net/phy/Kconfig
-+++ b/drivers/net/phy/Kconfig
-@@ -318,12 +318,7 @@ config NCN26000_PHY
- Currently supports the NCN26000 10BASE-T1S Industrial PHY
- with MII interface.
-
--config AT803X_PHY
-- tristate "Qualcomm Atheros AR803X PHYs and QCA833x PHYs"
-- depends on REGULATOR
-- help
-- Currently supports the AR8030, AR8031, AR8033, AR8035 and internal
-- QCA8337(Internal qca8k PHY) model
-+source "drivers/net/phy/qcom/Kconfig"
-
- config QSEMI_PHY
- tristate "Quality Semiconductor PHYs"
---- a/drivers/net/phy/Makefile
-+++ b/drivers/net/phy/Makefile
-@@ -36,7 +36,6 @@ obj-$(CONFIG_ADIN_PHY) += adin.o
- obj-$(CONFIG_ADIN1100_PHY) += adin1100.o
- obj-$(CONFIG_AMD_PHY) += amd.o
- obj-$(CONFIG_AQUANTIA_PHY) += aquantia/
--obj-$(CONFIG_AT803X_PHY) += at803x.o
- obj-$(CONFIG_AX88796B_PHY) += ax88796b.o
- obj-$(CONFIG_BCM54140_PHY) += bcm54140.o
- obj-$(CONFIG_BCM63XX_PHY) += bcm63xx.o
-@@ -82,6 +81,7 @@ obj-$(CONFIG_NCN26000_PHY) += ncn26000.o
- obj-$(CONFIG_NXP_C45_TJA11XX_PHY) += nxp-c45-tja11xx.o
- obj-$(CONFIG_NXP_CBTX_PHY) += nxp-cbtx.o
- obj-$(CONFIG_NXP_TJA11XX_PHY) += nxp-tja11xx.o
-+obj-y += qcom/
- obj-$(CONFIG_QSEMI_PHY) += qsemi.o
- obj-$(CONFIG_REALTEK_PHY) += realtek.o
- obj-$(CONFIG_RENESAS_PHY) += uPD60620.o
---- /dev/null
-+++ b/drivers/net/phy/qcom/Kconfig
-@@ -0,0 +1,7 @@
-+# SPDX-License-Identifier: GPL-2.0-only
-+config AT803X_PHY
-+ tristate "Qualcomm Atheros AR803X PHYs and QCA833x PHYs"
-+ depends on REGULATOR
-+ help
-+ Currently supports the AR8030, AR8031, AR8033, AR8035 and internal
-+ QCA8337(Internal qca8k PHY) model
---- /dev/null
-+++ b/drivers/net/phy/qcom/Makefile
-@@ -0,0 +1,2 @@
-+# SPDX-License-Identifier: GPL-2.0
-+obj-$(CONFIG_AT803X_PHY) += at803x.o
---- a/drivers/net/phy/at803x.c
-+++ /dev/null
-@@ -1,2759 +0,0 @@
--// SPDX-License-Identifier: GPL-2.0+
--/*
-- * drivers/net/phy/at803x.c
-- *
-- * Driver for Qualcomm Atheros AR803x PHY
-- *
-- */
--
--#include <linux/phy.h>
--#include <linux/module.h>
--#include <linux/string.h>
--#include <linux/netdevice.h>
--#include <linux/etherdevice.h>
--#include <linux/ethtool_netlink.h>
--#include <linux/bitfield.h>
--#include <linux/regulator/of_regulator.h>
--#include <linux/regulator/driver.h>
--#include <linux/regulator/consumer.h>
--#include <linux/of.h>
--#include <linux/phylink.h>
--#include <linux/sfp.h>
--#include <dt-bindings/net/qca-ar803x.h>
--
--#define AT803X_SPECIFIC_FUNCTION_CONTROL 0x10
--#define AT803X_SFC_ASSERT_CRS BIT(11)
--#define AT803X_SFC_FORCE_LINK BIT(10)
--#define AT803X_SFC_MDI_CROSSOVER_MODE_M GENMASK(6, 5)
--#define AT803X_SFC_AUTOMATIC_CROSSOVER 0x3
--#define AT803X_SFC_MANUAL_MDIX 0x1
--#define AT803X_SFC_MANUAL_MDI 0x0
--#define AT803X_SFC_SQE_TEST BIT(2)
--#define AT803X_SFC_POLARITY_REVERSAL BIT(1)
--#define AT803X_SFC_DISABLE_JABBER BIT(0)
--
--#define AT803X_SPECIFIC_STATUS 0x11
--#define AT803X_SS_SPEED_MASK GENMASK(15, 14)
--#define AT803X_SS_SPEED_1000 2
--#define AT803X_SS_SPEED_100 1
--#define AT803X_SS_SPEED_10 0
--#define AT803X_SS_DUPLEX BIT(13)
--#define AT803X_SS_SPEED_DUPLEX_RESOLVED BIT(11)
--#define AT803X_SS_MDIX BIT(6)
--
--#define QCA808X_SS_SPEED_MASK GENMASK(9, 7)
--#define QCA808X_SS_SPEED_2500 4
--
--#define AT803X_INTR_ENABLE 0x12
--#define AT803X_INTR_ENABLE_AUTONEG_ERR BIT(15)
--#define AT803X_INTR_ENABLE_SPEED_CHANGED BIT(14)
--#define AT803X_INTR_ENABLE_DUPLEX_CHANGED BIT(13)
--#define AT803X_INTR_ENABLE_PAGE_RECEIVED BIT(12)
--#define AT803X_INTR_ENABLE_LINK_FAIL BIT(11)
--#define AT803X_INTR_ENABLE_LINK_SUCCESS BIT(10)
--#define AT803X_INTR_ENABLE_LINK_FAIL_BX BIT(8)
--#define AT803X_INTR_ENABLE_LINK_SUCCESS_BX BIT(7)
--#define AT803X_INTR_ENABLE_WIRESPEED_DOWNGRADE BIT(5)
--#define AT803X_INTR_ENABLE_POLARITY_CHANGED BIT(1)
--#define AT803X_INTR_ENABLE_WOL BIT(0)
--
--#define AT803X_INTR_STATUS 0x13
--
--#define AT803X_SMART_SPEED 0x14
--#define AT803X_SMART_SPEED_ENABLE BIT(5)
--#define AT803X_SMART_SPEED_RETRY_LIMIT_MASK GENMASK(4, 2)
--#define AT803X_SMART_SPEED_BYPASS_TIMER BIT(1)
--#define AT803X_CDT 0x16
--#define AT803X_CDT_MDI_PAIR_MASK GENMASK(9, 8)
--#define AT803X_CDT_ENABLE_TEST BIT(0)
--#define AT803X_CDT_STATUS 0x1c
--#define AT803X_CDT_STATUS_STAT_NORMAL 0
--#define AT803X_CDT_STATUS_STAT_SHORT 1
--#define AT803X_CDT_STATUS_STAT_OPEN 2
--#define AT803X_CDT_STATUS_STAT_FAIL 3
--#define AT803X_CDT_STATUS_STAT_MASK GENMASK(9, 8)
--#define AT803X_CDT_STATUS_DELTA_TIME_MASK GENMASK(7, 0)
--#define AT803X_LED_CONTROL 0x18
--
--#define AT803X_PHY_MMD3_WOL_CTRL 0x8012
--#define AT803X_WOL_EN BIT(5)
--#define AT803X_LOC_MAC_ADDR_0_15_OFFSET 0x804C
--#define AT803X_LOC_MAC_ADDR_16_31_OFFSET 0x804B
--#define AT803X_LOC_MAC_ADDR_32_47_OFFSET 0x804A
--#define AT803X_REG_CHIP_CONFIG 0x1f
--#define AT803X_BT_BX_REG_SEL 0x8000
--
--#define AT803X_DEBUG_ADDR 0x1D
--#define AT803X_DEBUG_DATA 0x1E
--
--#define AT803X_MODE_CFG_MASK 0x0F
--#define AT803X_MODE_CFG_BASET_RGMII 0x00
--#define AT803X_MODE_CFG_BASET_SGMII 0x01
--#define AT803X_MODE_CFG_BX1000_RGMII_50OHM 0x02
--#define AT803X_MODE_CFG_BX1000_RGMII_75OHM 0x03
--#define AT803X_MODE_CFG_BX1000_CONV_50OHM 0x04
--#define AT803X_MODE_CFG_BX1000_CONV_75OHM 0x05
--#define AT803X_MODE_CFG_FX100_RGMII_50OHM 0x06
--#define AT803X_MODE_CFG_FX100_CONV_50OHM 0x07
--#define AT803X_MODE_CFG_RGMII_AUTO_MDET 0x0B
--#define AT803X_MODE_CFG_FX100_RGMII_75OHM 0x0E
--#define AT803X_MODE_CFG_FX100_CONV_75OHM 0x0F
--
--#define AT803X_PSSR 0x11 /*PHY-Specific Status Register*/
--#define AT803X_PSSR_MR_AN_COMPLETE 0x0200
--
--#define AT803X_DEBUG_ANALOG_TEST_CTRL 0x00
--#define QCA8327_DEBUG_MANU_CTRL_EN BIT(2)
--#define QCA8337_DEBUG_MANU_CTRL_EN GENMASK(3, 2)
--#define AT803X_DEBUG_RX_CLK_DLY_EN BIT(15)
--
--#define AT803X_DEBUG_SYSTEM_CTRL_MODE 0x05
--#define AT803X_DEBUG_TX_CLK_DLY_EN BIT(8)
--
--#define AT803X_DEBUG_REG_HIB_CTRL 0x0b
--#define AT803X_DEBUG_HIB_CTRL_SEL_RST_80U BIT(10)
--#define AT803X_DEBUG_HIB_CTRL_EN_ANY_CHANGE BIT(13)
--#define AT803X_DEBUG_HIB_CTRL_PS_HIB_EN BIT(15)
--
--#define AT803X_DEBUG_REG_3C 0x3C
--
--#define AT803X_DEBUG_REG_GREEN 0x3D
--#define AT803X_DEBUG_GATE_CLK_IN1000 BIT(6)
--
--#define AT803X_DEBUG_REG_1F 0x1F
--#define AT803X_DEBUG_PLL_ON BIT(2)
--#define AT803X_DEBUG_RGMII_1V8 BIT(3)
--
--#define MDIO_AZ_DEBUG 0x800D
--
--/* AT803x supports either the XTAL input pad, an internal PLL or the
-- * DSP as clock reference for the clock output pad. The XTAL reference
-- * is only used for 25 MHz output, all other frequencies need the PLL.
-- * The DSP as a clock reference is used in synchronous ethernet
-- * applications.
-- *
-- * By default the PLL is only enabled if there is a link. Otherwise
-- * the PHY will go into low power state and disabled the PLL. You can
-- * set the PLL_ON bit (see debug register 0x1f) to keep the PLL always
-- * enabled.
-- */
--#define AT803X_MMD7_CLK25M 0x8016
--#define AT803X_CLK_OUT_MASK GENMASK(4, 2)
--#define AT803X_CLK_OUT_25MHZ_XTAL 0
--#define AT803X_CLK_OUT_25MHZ_DSP 1
--#define AT803X_CLK_OUT_50MHZ_PLL 2
--#define AT803X_CLK_OUT_50MHZ_DSP 3
--#define AT803X_CLK_OUT_62_5MHZ_PLL 4
--#define AT803X_CLK_OUT_62_5MHZ_DSP 5
--#define AT803X_CLK_OUT_125MHZ_PLL 6
--#define AT803X_CLK_OUT_125MHZ_DSP 7
--
--/* The AR8035 has another mask which is compatible with the AR8031/AR8033 mask
-- * but doesn't support choosing between XTAL/PLL and DSP.
-- */
--#define AT8035_CLK_OUT_MASK GENMASK(4, 3)
--
--#define AT803X_CLK_OUT_STRENGTH_MASK GENMASK(8, 7)
--#define AT803X_CLK_OUT_STRENGTH_FULL 0
--#define AT803X_CLK_OUT_STRENGTH_HALF 1
--#define AT803X_CLK_OUT_STRENGTH_QUARTER 2
--
--#define AT803X_DEFAULT_DOWNSHIFT 5
--#define AT803X_MIN_DOWNSHIFT 2
--#define AT803X_MAX_DOWNSHIFT 9
--
--#define AT803X_MMD3_SMARTEEE_CTL1 0x805b
--#define AT803X_MMD3_SMARTEEE_CTL2 0x805c
--#define AT803X_MMD3_SMARTEEE_CTL3 0x805d
--#define AT803X_MMD3_SMARTEEE_CTL3_LPI_EN BIT(8)
--
--#define ATH9331_PHY_ID 0x004dd041
--#define ATH8030_PHY_ID 0x004dd076
--#define ATH8031_PHY_ID 0x004dd074
--#define ATH8032_PHY_ID 0x004dd023
--#define ATH8035_PHY_ID 0x004dd072
--#define AT8030_PHY_ID_MASK 0xffffffef
--
--#define QCA8081_PHY_ID 0x004dd101
--
--#define QCA8327_A_PHY_ID 0x004dd033
--#define QCA8327_B_PHY_ID 0x004dd034
--#define QCA8337_PHY_ID 0x004dd036
--#define QCA9561_PHY_ID 0x004dd042
--#define QCA8K_PHY_ID_MASK 0xffffffff
--
--#define QCA8K_DEVFLAGS_REVISION_MASK GENMASK(2, 0)
--
--#define AT803X_PAGE_FIBER 0
--#define AT803X_PAGE_COPPER 1
--
--/* don't turn off internal PLL */
--#define AT803X_KEEP_PLL_ENABLED BIT(0)
--#define AT803X_DISABLE_SMARTEEE BIT(1)
--
--/* disable hibernation mode */
--#define AT803X_DISABLE_HIBERNATION_MODE BIT(2)
--
--/* ADC threshold */
--#define QCA808X_PHY_DEBUG_ADC_THRESHOLD 0x2c80
--#define QCA808X_ADC_THRESHOLD_MASK GENMASK(7, 0)
--#define QCA808X_ADC_THRESHOLD_80MV 0
--#define QCA808X_ADC_THRESHOLD_100MV 0xf0
--#define QCA808X_ADC_THRESHOLD_200MV 0x0f
--#define QCA808X_ADC_THRESHOLD_300MV 0xff
--
--/* CLD control */
--#define QCA808X_PHY_MMD3_ADDR_CLD_CTRL7 0x8007
--#define QCA808X_8023AZ_AFE_CTRL_MASK GENMASK(8, 4)
--#define QCA808X_8023AZ_AFE_EN 0x90
--
--/* AZ control */
--#define QCA808X_PHY_MMD3_AZ_TRAINING_CTRL 0x8008
--#define QCA808X_MMD3_AZ_TRAINING_VAL 0x1c32
--
--#define QCA808X_PHY_MMD1_MSE_THRESHOLD_20DB 0x8014
--#define QCA808X_MSE_THRESHOLD_20DB_VALUE 0x529
--
--#define QCA808X_PHY_MMD1_MSE_THRESHOLD_17DB 0x800E
--#define QCA808X_MSE_THRESHOLD_17DB_VALUE 0x341
--
--#define QCA808X_PHY_MMD1_MSE_THRESHOLD_27DB 0x801E
--#define QCA808X_MSE_THRESHOLD_27DB_VALUE 0x419
--
--#define QCA808X_PHY_MMD1_MSE_THRESHOLD_28DB 0x8020
--#define QCA808X_MSE_THRESHOLD_28DB_VALUE 0x341
--
--#define QCA808X_PHY_MMD7_TOP_OPTION1 0x901c
--#define QCA808X_TOP_OPTION1_DATA 0x0
--
--#define QCA808X_PHY_MMD3_DEBUG_1 0xa100
--#define QCA808X_MMD3_DEBUG_1_VALUE 0x9203
--#define QCA808X_PHY_MMD3_DEBUG_2 0xa101
--#define QCA808X_MMD3_DEBUG_2_VALUE 0x48ad
--#define QCA808X_PHY_MMD3_DEBUG_3 0xa103
--#define QCA808X_MMD3_DEBUG_3_VALUE 0x1698
--#define QCA808X_PHY_MMD3_DEBUG_4 0xa105
--#define QCA808X_MMD3_DEBUG_4_VALUE 0x8001
--#define QCA808X_PHY_MMD3_DEBUG_5 0xa106
--#define QCA808X_MMD3_DEBUG_5_VALUE 0x1111
--#define QCA808X_PHY_MMD3_DEBUG_6 0xa011
--#define QCA808X_MMD3_DEBUG_6_VALUE 0x5f85
--
--/* master/slave seed config */
--#define QCA808X_PHY_DEBUG_LOCAL_SEED 9
--#define QCA808X_MASTER_SLAVE_SEED_ENABLE BIT(1)
--#define QCA808X_MASTER_SLAVE_SEED_CFG GENMASK(12, 2)
--#define QCA808X_MASTER_SLAVE_SEED_RANGE 0x32
--
--/* Hibernation yields lower power consumpiton in contrast with normal operation mode.
-- * when the copper cable is unplugged, the PHY enters into hibernation mode in about 10s.
-- */
--#define QCA808X_DBG_AN_TEST 0xb
--#define QCA808X_HIBERNATION_EN BIT(15)
--
--#define QCA808X_CDT_ENABLE_TEST BIT(15)
--#define QCA808X_CDT_INTER_CHECK_DIS BIT(13)
--#define QCA808X_CDT_STATUS BIT(11)
--#define QCA808X_CDT_LENGTH_UNIT BIT(10)
--
--#define QCA808X_MMD3_CDT_STATUS 0x8064
--#define QCA808X_MMD3_CDT_DIAG_PAIR_A 0x8065
--#define QCA808X_MMD3_CDT_DIAG_PAIR_B 0x8066
--#define QCA808X_MMD3_CDT_DIAG_PAIR_C 0x8067
--#define QCA808X_MMD3_CDT_DIAG_PAIR_D 0x8068
--#define QCA808X_CDT_DIAG_LENGTH_SAME_SHORT GENMASK(15, 8)
--#define QCA808X_CDT_DIAG_LENGTH_CROSS_SHORT GENMASK(7, 0)
--
--#define QCA808X_CDT_CODE_PAIR_A GENMASK(15, 12)
--#define QCA808X_CDT_CODE_PAIR_B GENMASK(11, 8)
--#define QCA808X_CDT_CODE_PAIR_C GENMASK(7, 4)
--#define QCA808X_CDT_CODE_PAIR_D GENMASK(3, 0)
--
--#define QCA808X_CDT_STATUS_STAT_TYPE GENMASK(1, 0)
--#define QCA808X_CDT_STATUS_STAT_FAIL FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_TYPE, 0)
--#define QCA808X_CDT_STATUS_STAT_NORMAL FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_TYPE, 1)
--#define QCA808X_CDT_STATUS_STAT_SAME_OPEN FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_TYPE, 2)
--#define QCA808X_CDT_STATUS_STAT_SAME_SHORT FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_TYPE, 3)
--
--#define QCA808X_CDT_STATUS_STAT_MDI GENMASK(3, 2)
--#define QCA808X_CDT_STATUS_STAT_MDI1 FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_MDI, 1)
--#define QCA808X_CDT_STATUS_STAT_MDI2 FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_MDI, 2)
--#define QCA808X_CDT_STATUS_STAT_MDI3 FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_MDI, 3)
--
--/* NORMAL are MDI with type set to 0 */
--#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_NORMAL QCA808X_CDT_STATUS_STAT_MDI1
--#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_OPEN (QCA808X_CDT_STATUS_STAT_SAME_OPEN |\
-- QCA808X_CDT_STATUS_STAT_MDI1)
--#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_SHORT (QCA808X_CDT_STATUS_STAT_SAME_SHORT |\
-- QCA808X_CDT_STATUS_STAT_MDI1)
--#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_NORMAL QCA808X_CDT_STATUS_STAT_MDI2
--#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_OPEN (QCA808X_CDT_STATUS_STAT_SAME_OPEN |\
-- QCA808X_CDT_STATUS_STAT_MDI2)
--#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_SHORT (QCA808X_CDT_STATUS_STAT_SAME_SHORT |\
-- QCA808X_CDT_STATUS_STAT_MDI2)
--#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_NORMAL QCA808X_CDT_STATUS_STAT_MDI3
--#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_OPEN (QCA808X_CDT_STATUS_STAT_SAME_OPEN |\
-- QCA808X_CDT_STATUS_STAT_MDI3)
--#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_SHORT (QCA808X_CDT_STATUS_STAT_SAME_SHORT |\
-- QCA808X_CDT_STATUS_STAT_MDI3)
--
--/* Added for reference of existence but should be handled by wait_for_completion already */
--#define QCA808X_CDT_STATUS_STAT_BUSY (BIT(1) | BIT(3))
--
--#define QCA808X_MMD7_LED_GLOBAL 0x8073
--#define QCA808X_LED_BLINK_1 GENMASK(11, 6)
--#define QCA808X_LED_BLINK_2 GENMASK(5, 0)
--/* Values are the same for both BLINK_1 and BLINK_2 */
--#define QCA808X_LED_BLINK_FREQ_MASK GENMASK(5, 3)
--#define QCA808X_LED_BLINK_FREQ_2HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x0)
--#define QCA808X_LED_BLINK_FREQ_4HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x1)
--#define QCA808X_LED_BLINK_FREQ_8HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x2)
--#define QCA808X_LED_BLINK_FREQ_16HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x3)
--#define QCA808X_LED_BLINK_FREQ_32HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x4)
--#define QCA808X_LED_BLINK_FREQ_64HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x5)
--#define QCA808X_LED_BLINK_FREQ_128HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x6)
--#define QCA808X_LED_BLINK_FREQ_256HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x7)
--#define QCA808X_LED_BLINK_DUTY_MASK GENMASK(2, 0)
--#define QCA808X_LED_BLINK_DUTY_50_50 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x0)
--#define QCA808X_LED_BLINK_DUTY_75_25 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x1)
--#define QCA808X_LED_BLINK_DUTY_25_75 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x2)
--#define QCA808X_LED_BLINK_DUTY_33_67 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x3)
--#define QCA808X_LED_BLINK_DUTY_67_33 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x4)
--#define QCA808X_LED_BLINK_DUTY_17_83 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x5)
--#define QCA808X_LED_BLINK_DUTY_83_17 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x6)
--#define QCA808X_LED_BLINK_DUTY_8_92 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x7)
--
--#define QCA808X_MMD7_LED2_CTRL 0x8074
--#define QCA808X_MMD7_LED2_FORCE_CTRL 0x8075
--#define QCA808X_MMD7_LED1_CTRL 0x8076
--#define QCA808X_MMD7_LED1_FORCE_CTRL 0x8077
--#define QCA808X_MMD7_LED0_CTRL 0x8078
--#define QCA808X_MMD7_LED_CTRL(x) (0x8078 - ((x) * 2))
--
--/* LED hw control pattern is the same for every LED */
--#define QCA808X_LED_PATTERN_MASK GENMASK(15, 0)
--#define QCA808X_LED_SPEED2500_ON BIT(15)
--#define QCA808X_LED_SPEED2500_BLINK BIT(14)
--/* Follow blink trigger even if duplex or speed condition doesn't match */
--#define QCA808X_LED_BLINK_CHECK_BYPASS BIT(13)
--#define QCA808X_LED_FULL_DUPLEX_ON BIT(12)
--#define QCA808X_LED_HALF_DUPLEX_ON BIT(11)
--#define QCA808X_LED_TX_BLINK BIT(10)
--#define QCA808X_LED_RX_BLINK BIT(9)
--#define QCA808X_LED_TX_ON_10MS BIT(8)
--#define QCA808X_LED_RX_ON_10MS BIT(7)
--#define QCA808X_LED_SPEED1000_ON BIT(6)
--#define QCA808X_LED_SPEED100_ON BIT(5)
--#define QCA808X_LED_SPEED10_ON BIT(4)
--#define QCA808X_LED_COLLISION_BLINK BIT(3)
--#define QCA808X_LED_SPEED1000_BLINK BIT(2)
--#define QCA808X_LED_SPEED100_BLINK BIT(1)
--#define QCA808X_LED_SPEED10_BLINK BIT(0)
--
--#define QCA808X_MMD7_LED0_FORCE_CTRL 0x8079
--#define QCA808X_MMD7_LED_FORCE_CTRL(x) (0x8079 - ((x) * 2))
--
--/* LED force ctrl is the same for every LED
-- * No documentation exist for this, not even internal one
-- * with NDA as QCOM gives only info about configuring
-- * hw control pattern rules and doesn't indicate any way
-- * to force the LED to specific mode.
-- * These define comes from reverse and testing and maybe
-- * lack of some info or some info are not entirely correct.
-- * For the basic LED control and hw control these finding
-- * are enough to support LED control in all the required APIs.
-- *
-- * On doing some comparison with implementation with qca807x,
-- * it was found that it's 1:1 equal to it and confirms all the
-- * reverse done. It was also found further specification with the
-- * force mode and the blink modes.
-- */
--#define QCA808X_LED_FORCE_EN BIT(15)
--#define QCA808X_LED_FORCE_MODE_MASK GENMASK(14, 13)
--#define QCA808X_LED_FORCE_BLINK_1 FIELD_PREP(QCA808X_LED_FORCE_MODE_MASK, 0x3)
--#define QCA808X_LED_FORCE_BLINK_2 FIELD_PREP(QCA808X_LED_FORCE_MODE_MASK, 0x2)
--#define QCA808X_LED_FORCE_ON FIELD_PREP(QCA808X_LED_FORCE_MODE_MASK, 0x1)
--#define QCA808X_LED_FORCE_OFF FIELD_PREP(QCA808X_LED_FORCE_MODE_MASK, 0x0)
--
--#define QCA808X_MMD7_LED_POLARITY_CTRL 0x901a
--/* QSDK sets by default 0x46 to this reg that sets BIT 6 for
-- * LED to active high. It's not clear what BIT 3 and BIT 4 does.
-- */
--#define QCA808X_LED_ACTIVE_HIGH BIT(6)
--
--/* QCA808X 1G chip type */
--#define QCA808X_PHY_MMD7_CHIP_TYPE 0x901d
--#define QCA808X_PHY_CHIP_TYPE_1G BIT(0)
--
--#define QCA8081_PHY_SERDES_MMD1_FIFO_CTRL 0x9072
--#define QCA8081_PHY_FIFO_RSTN BIT(11)
--
--MODULE_DESCRIPTION("Qualcomm Atheros AR803x and QCA808X PHY driver");
--MODULE_AUTHOR("Matus Ujhelyi");
--MODULE_LICENSE("GPL");
--
--enum stat_access_type {
-- PHY,
-- MMD
--};
--
--struct at803x_hw_stat {
-- const char *string;
-- u8 reg;
-- u32 mask;
-- enum stat_access_type access_type;
--};
--
--static struct at803x_hw_stat qca83xx_hw_stats[] = {
-- { "phy_idle_errors", 0xa, GENMASK(7, 0), PHY},
-- { "phy_receive_errors", 0x15, GENMASK(15, 0), PHY},
-- { "eee_wake_errors", 0x16, GENMASK(15, 0), MMD},
--};
--
--struct at803x_ss_mask {
-- u16 speed_mask;
-- u8 speed_shift;
--};
--
--struct at803x_priv {
-- int flags;
-- u16 clk_25m_reg;
-- u16 clk_25m_mask;
-- u8 smarteee_lpi_tw_1g;
-- u8 smarteee_lpi_tw_100m;
-- bool is_fiber;
-- bool is_1000basex;
-- struct regulator_dev *vddio_rdev;
-- struct regulator_dev *vddh_rdev;
-- u64 stats[ARRAY_SIZE(qca83xx_hw_stats)];
-- int led_polarity_mode;
--};
--
--struct at803x_context {
-- u16 bmcr;
-- u16 advertise;
-- u16 control1000;
-- u16 int_enable;
-- u16 smart_speed;
-- u16 led_control;
--};
--
--static int at803x_debug_reg_write(struct phy_device *phydev, u16 reg, u16 data)
--{
-- int ret;
--
-- ret = phy_write(phydev, AT803X_DEBUG_ADDR, reg);
-- if (ret < 0)
-- return ret;
--
-- return phy_write(phydev, AT803X_DEBUG_DATA, data);
--}
--
--static int at803x_debug_reg_read(struct phy_device *phydev, u16 reg)
--{
-- int ret;
--
-- ret = phy_write(phydev, AT803X_DEBUG_ADDR, reg);
-- if (ret < 0)
-- return ret;
--
-- return phy_read(phydev, AT803X_DEBUG_DATA);
--}
--
--static int at803x_debug_reg_mask(struct phy_device *phydev, u16 reg,
-- u16 clear, u16 set)
--{
-- u16 val;
-- int ret;
--
-- ret = at803x_debug_reg_read(phydev, reg);
-- if (ret < 0)
-- return ret;
--
-- val = ret & 0xffff;
-- val &= ~clear;
-- val |= set;
--
-- return phy_write(phydev, AT803X_DEBUG_DATA, val);
--}
--
--static int at803x_write_page(struct phy_device *phydev, int page)
--{
-- int mask;
-- int set;
--
-- if (page == AT803X_PAGE_COPPER) {
-- set = AT803X_BT_BX_REG_SEL;
-- mask = 0;
-- } else {
-- set = 0;
-- mask = AT803X_BT_BX_REG_SEL;
-- }
--
-- return __phy_modify(phydev, AT803X_REG_CHIP_CONFIG, mask, set);
--}
--
--static int at803x_read_page(struct phy_device *phydev)
--{
-- int ccr = __phy_read(phydev, AT803X_REG_CHIP_CONFIG);
--
-- if (ccr < 0)
-- return ccr;
--
-- if (ccr & AT803X_BT_BX_REG_SEL)
-- return AT803X_PAGE_COPPER;
--
-- return AT803X_PAGE_FIBER;
--}
--
--static int at803x_enable_rx_delay(struct phy_device *phydev)
--{
-- return at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL, 0,
-- AT803X_DEBUG_RX_CLK_DLY_EN);
--}
--
--static int at803x_enable_tx_delay(struct phy_device *phydev)
--{
-- return at803x_debug_reg_mask(phydev, AT803X_DEBUG_SYSTEM_CTRL_MODE, 0,
-- AT803X_DEBUG_TX_CLK_DLY_EN);
--}
--
--static int at803x_disable_rx_delay(struct phy_device *phydev)
--{
-- return at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL,
-- AT803X_DEBUG_RX_CLK_DLY_EN, 0);
--}
--
--static int at803x_disable_tx_delay(struct phy_device *phydev)
--{
-- return at803x_debug_reg_mask(phydev, AT803X_DEBUG_SYSTEM_CTRL_MODE,
-- AT803X_DEBUG_TX_CLK_DLY_EN, 0);
--}
--
--/* save relevant PHY registers to private copy */
--static void at803x_context_save(struct phy_device *phydev,
-- struct at803x_context *context)
--{
-- context->bmcr = phy_read(phydev, MII_BMCR);
-- context->advertise = phy_read(phydev, MII_ADVERTISE);
-- context->control1000 = phy_read(phydev, MII_CTRL1000);
-- context->int_enable = phy_read(phydev, AT803X_INTR_ENABLE);
-- context->smart_speed = phy_read(phydev, AT803X_SMART_SPEED);
-- context->led_control = phy_read(phydev, AT803X_LED_CONTROL);
--}
--
--/* restore relevant PHY registers from private copy */
--static void at803x_context_restore(struct phy_device *phydev,
-- const struct at803x_context *context)
--{
-- phy_write(phydev, MII_BMCR, context->bmcr);
-- phy_write(phydev, MII_ADVERTISE, context->advertise);
-- phy_write(phydev, MII_CTRL1000, context->control1000);
-- phy_write(phydev, AT803X_INTR_ENABLE, context->int_enable);
-- phy_write(phydev, AT803X_SMART_SPEED, context->smart_speed);
-- phy_write(phydev, AT803X_LED_CONTROL, context->led_control);
--}
--
--static int at803x_set_wol(struct phy_device *phydev,
-- struct ethtool_wolinfo *wol)
--{
-- int ret, irq_enabled;
--
-- if (wol->wolopts & WAKE_MAGIC) {
-- struct net_device *ndev = phydev->attached_dev;
-- const u8 *mac;
-- unsigned int i;
-- static const unsigned int offsets[] = {
-- AT803X_LOC_MAC_ADDR_32_47_OFFSET,
-- AT803X_LOC_MAC_ADDR_16_31_OFFSET,
-- AT803X_LOC_MAC_ADDR_0_15_OFFSET,
-- };
--
-- if (!ndev)
-- return -ENODEV;
--
-- mac = (const u8 *)ndev->dev_addr;
--
-- if (!is_valid_ether_addr(mac))
-- return -EINVAL;
--
-- for (i = 0; i < 3; i++)
-- phy_write_mmd(phydev, MDIO_MMD_PCS, offsets[i],
-- mac[(i * 2) + 1] | (mac[(i * 2)] << 8));
--
-- /* Enable WOL interrupt */
-- ret = phy_modify(phydev, AT803X_INTR_ENABLE, 0, AT803X_INTR_ENABLE_WOL);
-- if (ret)
-- return ret;
-- } else {
-- /* Disable WOL interrupt */
-- ret = phy_modify(phydev, AT803X_INTR_ENABLE, AT803X_INTR_ENABLE_WOL, 0);
-- if (ret)
-- return ret;
-- }
--
-- /* Clear WOL status */
-- ret = phy_read(phydev, AT803X_INTR_STATUS);
-- if (ret < 0)
-- return ret;
--
-- /* Check if there are other interrupts except for WOL triggered when PHY is
-- * in interrupt mode, only the interrupts enabled by AT803X_INTR_ENABLE can
-- * be passed up to the interrupt PIN.
-- */
-- irq_enabled = phy_read(phydev, AT803X_INTR_ENABLE);
-- if (irq_enabled < 0)
-- return irq_enabled;
--
-- irq_enabled &= ~AT803X_INTR_ENABLE_WOL;
-- if (ret & irq_enabled && !phy_polling_mode(phydev))
-- phy_trigger_machine(phydev);
--
-- return 0;
--}
--
--static void at803x_get_wol(struct phy_device *phydev,
-- struct ethtool_wolinfo *wol)
--{
-- int value;
--
-- wol->supported = WAKE_MAGIC;
-- wol->wolopts = 0;
--
-- value = phy_read(phydev, AT803X_INTR_ENABLE);
-- if (value < 0)
-- return;
--
-- if (value & AT803X_INTR_ENABLE_WOL)
-- wol->wolopts |= WAKE_MAGIC;
--}
--
--static int qca83xx_get_sset_count(struct phy_device *phydev)
--{
-- return ARRAY_SIZE(qca83xx_hw_stats);
--}
--
--static void qca83xx_get_strings(struct phy_device *phydev, u8 *data)
--{
-- int i;
--
-- for (i = 0; i < ARRAY_SIZE(qca83xx_hw_stats); i++) {
-- strscpy(data + i * ETH_GSTRING_LEN,
-- qca83xx_hw_stats[i].string, ETH_GSTRING_LEN);
-- }
--}
--
--static u64 qca83xx_get_stat(struct phy_device *phydev, int i)
--{
-- struct at803x_hw_stat stat = qca83xx_hw_stats[i];
-- struct at803x_priv *priv = phydev->priv;
-- int val;
-- u64 ret;
--
-- if (stat.access_type == MMD)
-- val = phy_read_mmd(phydev, MDIO_MMD_PCS, stat.reg);
-- else
-- val = phy_read(phydev, stat.reg);
--
-- if (val < 0) {
-- ret = U64_MAX;
-- } else {
-- val = val & stat.mask;
-- priv->stats[i] += val;
-- ret = priv->stats[i];
-- }
--
-- return ret;
--}
--
--static void qca83xx_get_stats(struct phy_device *phydev,
-- struct ethtool_stats *stats, u64 *data)
--{
-- int i;
--
-- for (i = 0; i < ARRAY_SIZE(qca83xx_hw_stats); i++)
-- data[i] = qca83xx_get_stat(phydev, i);
--}
--
--static int at803x_suspend(struct phy_device *phydev)
--{
-- int value;
-- int wol_enabled;
--
-- value = phy_read(phydev, AT803X_INTR_ENABLE);
-- wol_enabled = value & AT803X_INTR_ENABLE_WOL;
--
-- if (wol_enabled)
-- value = BMCR_ISOLATE;
-- else
-- value = BMCR_PDOWN;
--
-- phy_modify(phydev, MII_BMCR, 0, value);
--
-- return 0;
--}
--
--static int at803x_resume(struct phy_device *phydev)
--{
-- return phy_modify(phydev, MII_BMCR, BMCR_PDOWN | BMCR_ISOLATE, 0);
--}
--
--static int at803x_parse_dt(struct phy_device *phydev)
--{
-- struct device_node *node = phydev->mdio.dev.of_node;
-- struct at803x_priv *priv = phydev->priv;
-- u32 freq, strength, tw;
-- unsigned int sel;
-- int ret;
--
-- if (!IS_ENABLED(CONFIG_OF_MDIO))
-- return 0;
--
-- if (of_property_read_bool(node, "qca,disable-smarteee"))
-- priv->flags |= AT803X_DISABLE_SMARTEEE;
--
-- if (of_property_read_bool(node, "qca,disable-hibernation-mode"))
-- priv->flags |= AT803X_DISABLE_HIBERNATION_MODE;
--
-- if (!of_property_read_u32(node, "qca,smarteee-tw-us-1g", &tw)) {
-- if (!tw || tw > 255) {
-- phydev_err(phydev, "invalid qca,smarteee-tw-us-1g\n");
-- return -EINVAL;
-- }
-- priv->smarteee_lpi_tw_1g = tw;
-- }
--
-- if (!of_property_read_u32(node, "qca,smarteee-tw-us-100m", &tw)) {
-- if (!tw || tw > 255) {
-- phydev_err(phydev, "invalid qca,smarteee-tw-us-100m\n");
-- return -EINVAL;
-- }
-- priv->smarteee_lpi_tw_100m = tw;
-- }
--
-- ret = of_property_read_u32(node, "qca,clk-out-frequency", &freq);
-- if (!ret) {
-- switch (freq) {
-- case 25000000:
-- sel = AT803X_CLK_OUT_25MHZ_XTAL;
-- break;
-- case 50000000:
-- sel = AT803X_CLK_OUT_50MHZ_PLL;
-- break;
-- case 62500000:
-- sel = AT803X_CLK_OUT_62_5MHZ_PLL;
-- break;
-- case 125000000:
-- sel = AT803X_CLK_OUT_125MHZ_PLL;
-- break;
-- default:
-- phydev_err(phydev, "invalid qca,clk-out-frequency\n");
-- return -EINVAL;
-- }
--
-- priv->clk_25m_reg |= FIELD_PREP(AT803X_CLK_OUT_MASK, sel);
-- priv->clk_25m_mask |= AT803X_CLK_OUT_MASK;
-- }
--
-- ret = of_property_read_u32(node, "qca,clk-out-strength", &strength);
-- if (!ret) {
-- priv->clk_25m_mask |= AT803X_CLK_OUT_STRENGTH_MASK;
-- switch (strength) {
-- case AR803X_STRENGTH_FULL:
-- priv->clk_25m_reg |= AT803X_CLK_OUT_STRENGTH_FULL;
-- break;
-- case AR803X_STRENGTH_HALF:
-- priv->clk_25m_reg |= AT803X_CLK_OUT_STRENGTH_HALF;
-- break;
-- case AR803X_STRENGTH_QUARTER:
-- priv->clk_25m_reg |= AT803X_CLK_OUT_STRENGTH_QUARTER;
-- break;
-- default:
-- phydev_err(phydev, "invalid qca,clk-out-strength\n");
-- return -EINVAL;
-- }
-- }
--
-- return 0;
--}
--
--static int at803x_probe(struct phy_device *phydev)
--{
-- struct device *dev = &phydev->mdio.dev;
-- struct at803x_priv *priv;
-- int ret;
--
-- priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
-- if (!priv)
-- return -ENOMEM;
--
-- /* Init LED polarity mode to -1 */
-- priv->led_polarity_mode = -1;
--
-- phydev->priv = priv;
--
-- ret = at803x_parse_dt(phydev);
-- if (ret)
-- return ret;
--
-- return 0;
--}
--
--static int at803x_get_features(struct phy_device *phydev)
--{
-- struct at803x_priv *priv = phydev->priv;
-- int err;
--
-- err = genphy_read_abilities(phydev);
-- if (err)
-- return err;
--
-- if (phydev->drv->phy_id != ATH8031_PHY_ID)
-- return 0;
--
-- /* AR8031/AR8033 have different status registers
-- * for copper and fiber operation. However, the
-- * extended status register is the same for both
-- * operation modes.
-- *
-- * As a result of that, ESTATUS_1000_XFULL is set
-- * to 1 even when operating in copper TP mode.
-- *
-- * Remove this mode from the supported link modes
-- * when not operating in 1000BaseX mode.
-- */
-- if (!priv->is_1000basex)
-- linkmode_clear_bit(ETHTOOL_LINK_MODE_1000baseX_Full_BIT,
-- phydev->supported);
--
-- return 0;
--}
--
--static int at803x_smarteee_config(struct phy_device *phydev)
--{
-- struct at803x_priv *priv = phydev->priv;
-- u16 mask = 0, val = 0;
-- int ret;
--
-- if (priv->flags & AT803X_DISABLE_SMARTEEE)
-- return phy_modify_mmd(phydev, MDIO_MMD_PCS,
-- AT803X_MMD3_SMARTEEE_CTL3,
-- AT803X_MMD3_SMARTEEE_CTL3_LPI_EN, 0);
--
-- if (priv->smarteee_lpi_tw_1g) {
-- mask |= 0xff00;
-- val |= priv->smarteee_lpi_tw_1g << 8;
-- }
-- if (priv->smarteee_lpi_tw_100m) {
-- mask |= 0x00ff;
-- val |= priv->smarteee_lpi_tw_100m;
-- }
-- if (!mask)
-- return 0;
--
-- ret = phy_modify_mmd(phydev, MDIO_MMD_PCS, AT803X_MMD3_SMARTEEE_CTL1,
-- mask, val);
-- if (ret)
-- return ret;
--
-- return phy_modify_mmd(phydev, MDIO_MMD_PCS, AT803X_MMD3_SMARTEEE_CTL3,
-- AT803X_MMD3_SMARTEEE_CTL3_LPI_EN,
-- AT803X_MMD3_SMARTEEE_CTL3_LPI_EN);
--}
--
--static int at803x_clk_out_config(struct phy_device *phydev)
--{
-- struct at803x_priv *priv = phydev->priv;
--
-- if (!priv->clk_25m_mask)
-- return 0;
--
-- return phy_modify_mmd(phydev, MDIO_MMD_AN, AT803X_MMD7_CLK25M,
-- priv->clk_25m_mask, priv->clk_25m_reg);
--}
--
--static int at8031_pll_config(struct phy_device *phydev)
--{
-- struct at803x_priv *priv = phydev->priv;
--
-- /* The default after hardware reset is PLL OFF. After a soft reset, the
-- * values are retained.
-- */
-- if (priv->flags & AT803X_KEEP_PLL_ENABLED)
-- return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_1F,
-- 0, AT803X_DEBUG_PLL_ON);
-- else
-- return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_1F,
-- AT803X_DEBUG_PLL_ON, 0);
--}
--
--static int at803x_hibernation_mode_config(struct phy_device *phydev)
--{
-- struct at803x_priv *priv = phydev->priv;
--
-- /* The default after hardware reset is hibernation mode enabled. After
-- * software reset, the value is retained.
-- */
-- if (!(priv->flags & AT803X_DISABLE_HIBERNATION_MODE))
-- return 0;
--
-- return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_HIB_CTRL,
-- AT803X_DEBUG_HIB_CTRL_PS_HIB_EN, 0);
--}
--
--static int at803x_config_init(struct phy_device *phydev)
--{
-- int ret;
--
-- /* The RX and TX delay default is:
-- * after HW reset: RX delay enabled and TX delay disabled
-- * after SW reset: RX delay enabled, while TX delay retains the
-- * value before reset.
-- */
-- if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
-- phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID)
-- ret = at803x_enable_rx_delay(phydev);
-- else
-- ret = at803x_disable_rx_delay(phydev);
-- if (ret < 0)
-- return ret;
--
-- if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
-- phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)
-- ret = at803x_enable_tx_delay(phydev);
-- else
-- ret = at803x_disable_tx_delay(phydev);
-- if (ret < 0)
-- return ret;
--
-- ret = at803x_smarteee_config(phydev);
-- if (ret < 0)
-- return ret;
--
-- ret = at803x_clk_out_config(phydev);
-- if (ret < 0)
-- return ret;
--
-- ret = at803x_hibernation_mode_config(phydev);
-- if (ret < 0)
-- return ret;
--
-- /* Ar803x extended next page bit is enabled by default. Cisco
-- * multigig switches read this bit and attempt to negotiate 10Gbps
-- * rates even if the next page bit is disabled. This is incorrect
-- * behaviour but we still need to accommodate it. XNP is only needed
-- * for 10Gbps support, so disable XNP.
-- */
-- return phy_modify(phydev, MII_ADVERTISE, MDIO_AN_CTRL1_XNP, 0);
--}
--
--static int at803x_ack_interrupt(struct phy_device *phydev)
--{
-- int err;
--
-- err = phy_read(phydev, AT803X_INTR_STATUS);
--
-- return (err < 0) ? err : 0;
--}
--
--static int at803x_config_intr(struct phy_device *phydev)
--{
-- int err;
-- int value;
--
-- value = phy_read(phydev, AT803X_INTR_ENABLE);
--
-- if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
-- /* Clear any pending interrupts */
-- err = at803x_ack_interrupt(phydev);
-- if (err)
-- return err;
--
-- value |= AT803X_INTR_ENABLE_AUTONEG_ERR;
-- value |= AT803X_INTR_ENABLE_SPEED_CHANGED;
-- value |= AT803X_INTR_ENABLE_DUPLEX_CHANGED;
-- value |= AT803X_INTR_ENABLE_LINK_FAIL;
-- value |= AT803X_INTR_ENABLE_LINK_SUCCESS;
--
-- err = phy_write(phydev, AT803X_INTR_ENABLE, value);
-- } else {
-- err = phy_write(phydev, AT803X_INTR_ENABLE, 0);
-- if (err)
-- return err;
--
-- /* Clear any pending interrupts */
-- err = at803x_ack_interrupt(phydev);
-- }
--
-- return err;
--}
--
--static irqreturn_t at803x_handle_interrupt(struct phy_device *phydev)
--{
-- int irq_status, int_enabled;
--
-- irq_status = phy_read(phydev, AT803X_INTR_STATUS);
-- if (irq_status < 0) {
-- phy_error(phydev);
-- return IRQ_NONE;
-- }
--
-- /* Read the current enabled interrupts */
-- int_enabled = phy_read(phydev, AT803X_INTR_ENABLE);
-- if (int_enabled < 0) {
-- phy_error(phydev);
-- return IRQ_NONE;
-- }
--
-- /* See if this was one of our enabled interrupts */
-- if (!(irq_status & int_enabled))
-- return IRQ_NONE;
--
-- phy_trigger_machine(phydev);
--
-- return IRQ_HANDLED;
--}
--
--static void at803x_link_change_notify(struct phy_device *phydev)
--{
-- /*
-- * Conduct a hardware reset for AT8030 every time a link loss is
-- * signalled. This is necessary to circumvent a hardware bug that
-- * occurs when the cable is unplugged while TX packets are pending
-- * in the FIFO. In such cases, the FIFO enters an error mode it
-- * cannot recover from by software.
-- */
-- if (phydev->state == PHY_NOLINK && phydev->mdio.reset_gpio) {
-- struct at803x_context context;
--
-- at803x_context_save(phydev, &context);
--
-- phy_device_reset(phydev, 1);
-- usleep_range(1000, 2000);
-- phy_device_reset(phydev, 0);
-- usleep_range(1000, 2000);
--
-- at803x_context_restore(phydev, &context);
--
-- phydev_dbg(phydev, "%s(): phy was reset\n", __func__);
-- }
--}
--
--static int at803x_read_specific_status(struct phy_device *phydev,
-- struct at803x_ss_mask ss_mask)
--{
-- int ss;
--
-- /* Read the AT8035 PHY-Specific Status register, which indicates the
-- * speed and duplex that the PHY is actually using, irrespective of
-- * whether we are in autoneg mode or not.
-- */
-- ss = phy_read(phydev, AT803X_SPECIFIC_STATUS);
-- if (ss < 0)
-- return ss;
--
-- if (ss & AT803X_SS_SPEED_DUPLEX_RESOLVED) {
-- int sfc, speed;
--
-- sfc = phy_read(phydev, AT803X_SPECIFIC_FUNCTION_CONTROL);
-- if (sfc < 0)
-- return sfc;
--
-- speed = ss & ss_mask.speed_mask;
-- speed >>= ss_mask.speed_shift;
--
-- switch (speed) {
-- case AT803X_SS_SPEED_10:
-- phydev->speed = SPEED_10;
-- break;
-- case AT803X_SS_SPEED_100:
-- phydev->speed = SPEED_100;
-- break;
-- case AT803X_SS_SPEED_1000:
-- phydev->speed = SPEED_1000;
-- break;
-- case QCA808X_SS_SPEED_2500:
-- phydev->speed = SPEED_2500;
-- break;
-- }
-- if (ss & AT803X_SS_DUPLEX)
-- phydev->duplex = DUPLEX_FULL;
-- else
-- phydev->duplex = DUPLEX_HALF;
--
-- if (ss & AT803X_SS_MDIX)
-- phydev->mdix = ETH_TP_MDI_X;
-- else
-- phydev->mdix = ETH_TP_MDI;
--
-- switch (FIELD_GET(AT803X_SFC_MDI_CROSSOVER_MODE_M, sfc)) {
-- case AT803X_SFC_MANUAL_MDI:
-- phydev->mdix_ctrl = ETH_TP_MDI;
-- break;
-- case AT803X_SFC_MANUAL_MDIX:
-- phydev->mdix_ctrl = ETH_TP_MDI_X;
-- break;
-- case AT803X_SFC_AUTOMATIC_CROSSOVER:
-- phydev->mdix_ctrl = ETH_TP_MDI_AUTO;
-- break;
-- }
-- }
--
-- return 0;
--}
--
--static int at803x_read_status(struct phy_device *phydev)
--{
-- struct at803x_ss_mask ss_mask = { 0 };
-- int err, old_link = phydev->link;
--
-- /* Update the link, but return if there was an error */
-- err = genphy_update_link(phydev);
-- if (err)
-- return err;
--
-- /* why bother the PHY if nothing can have changed */
-- if (phydev->autoneg == AUTONEG_ENABLE && old_link && phydev->link)
-- return 0;
--
-- phydev->speed = SPEED_UNKNOWN;
-- phydev->duplex = DUPLEX_UNKNOWN;
-- phydev->pause = 0;
-- phydev->asym_pause = 0;
--
-- err = genphy_read_lpa(phydev);
-- if (err < 0)
-- return err;
--
-- ss_mask.speed_mask = AT803X_SS_SPEED_MASK;
-- ss_mask.speed_shift = __bf_shf(AT803X_SS_SPEED_MASK);
-- err = at803x_read_specific_status(phydev, ss_mask);
-- if (err < 0)
-- return err;
--
-- if (phydev->autoneg == AUTONEG_ENABLE && phydev->autoneg_complete)
-- phy_resolve_aneg_pause(phydev);
--
-- return 0;
--}
--
--static int at803x_config_mdix(struct phy_device *phydev, u8 ctrl)
--{
-- u16 val;
--
-- switch (ctrl) {
-- case ETH_TP_MDI:
-- val = AT803X_SFC_MANUAL_MDI;
-- break;
-- case ETH_TP_MDI_X:
-- val = AT803X_SFC_MANUAL_MDIX;
-- break;
-- case ETH_TP_MDI_AUTO:
-- val = AT803X_SFC_AUTOMATIC_CROSSOVER;
-- break;
-- default:
-- return 0;
-- }
--
-- return phy_modify_changed(phydev, AT803X_SPECIFIC_FUNCTION_CONTROL,
-- AT803X_SFC_MDI_CROSSOVER_MODE_M,
-- FIELD_PREP(AT803X_SFC_MDI_CROSSOVER_MODE_M, val));
--}
--
--static int at803x_prepare_config_aneg(struct phy_device *phydev)
--{
-- int ret;
--
-- ret = at803x_config_mdix(phydev, phydev->mdix_ctrl);
-- if (ret < 0)
-- return ret;
--
-- /* Changes of the midx bits are disruptive to the normal operation;
-- * therefore any changes to these registers must be followed by a
-- * software reset to take effect.
-- */
-- if (ret == 1) {
-- ret = genphy_soft_reset(phydev);
-- if (ret < 0)
-- return ret;
-- }
--
-- return 0;
--}
--
--static int at803x_config_aneg(struct phy_device *phydev)
--{
-- struct at803x_priv *priv = phydev->priv;
-- int ret;
--
-- ret = at803x_prepare_config_aneg(phydev);
-- if (ret)
-- return ret;
--
-- if (priv->is_1000basex)
-- return genphy_c37_config_aneg(phydev);
--
-- return genphy_config_aneg(phydev);
--}
--
--static int at803x_get_downshift(struct phy_device *phydev, u8 *d)
--{
-- int val;
--
-- val = phy_read(phydev, AT803X_SMART_SPEED);
-- if (val < 0)
-- return val;
--
-- if (val & AT803X_SMART_SPEED_ENABLE)
-- *d = FIELD_GET(AT803X_SMART_SPEED_RETRY_LIMIT_MASK, val) + 2;
-- else
-- *d = DOWNSHIFT_DEV_DISABLE;
--
-- return 0;
--}
--
--static int at803x_set_downshift(struct phy_device *phydev, u8 cnt)
--{
-- u16 mask, set;
-- int ret;
--
-- switch (cnt) {
-- case DOWNSHIFT_DEV_DEFAULT_COUNT:
-- cnt = AT803X_DEFAULT_DOWNSHIFT;
-- fallthrough;
-- case AT803X_MIN_DOWNSHIFT ... AT803X_MAX_DOWNSHIFT:
-- set = AT803X_SMART_SPEED_ENABLE |
-- AT803X_SMART_SPEED_BYPASS_TIMER |
-- FIELD_PREP(AT803X_SMART_SPEED_RETRY_LIMIT_MASK, cnt - 2);
-- mask = AT803X_SMART_SPEED_RETRY_LIMIT_MASK;
-- break;
-- case DOWNSHIFT_DEV_DISABLE:
-- set = 0;
-- mask = AT803X_SMART_SPEED_ENABLE |
-- AT803X_SMART_SPEED_BYPASS_TIMER;
-- break;
-- default:
-- return -EINVAL;
-- }
--
-- ret = phy_modify_changed(phydev, AT803X_SMART_SPEED, mask, set);
--
-- /* After changing the smart speed settings, we need to perform a
-- * software reset, use phy_init_hw() to make sure we set the
-- * reapply any values which might got lost during software reset.
-- */
-- if (ret == 1)
-- ret = phy_init_hw(phydev);
--
-- return ret;
--}
--
--static int at803x_get_tunable(struct phy_device *phydev,
-- struct ethtool_tunable *tuna, void *data)
--{
-- switch (tuna->id) {
-- case ETHTOOL_PHY_DOWNSHIFT:
-- return at803x_get_downshift(phydev, data);
-- default:
-- return -EOPNOTSUPP;
-- }
--}
--
--static int at803x_set_tunable(struct phy_device *phydev,
-- struct ethtool_tunable *tuna, const void *data)
--{
-- switch (tuna->id) {
-- case ETHTOOL_PHY_DOWNSHIFT:
-- return at803x_set_downshift(phydev, *(const u8 *)data);
-- default:
-- return -EOPNOTSUPP;
-- }
--}
--
--static int at803x_cable_test_result_trans(u16 status)
--{
-- switch (FIELD_GET(AT803X_CDT_STATUS_STAT_MASK, status)) {
-- case AT803X_CDT_STATUS_STAT_NORMAL:
-- return ETHTOOL_A_CABLE_RESULT_CODE_OK;
-- case AT803X_CDT_STATUS_STAT_SHORT:
-- return ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT;
-- case AT803X_CDT_STATUS_STAT_OPEN:
-- return ETHTOOL_A_CABLE_RESULT_CODE_OPEN;
-- case AT803X_CDT_STATUS_STAT_FAIL:
-- default:
-- return ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC;
-- }
--}
--
--static bool at803x_cdt_test_failed(u16 status)
--{
-- return FIELD_GET(AT803X_CDT_STATUS_STAT_MASK, status) ==
-- AT803X_CDT_STATUS_STAT_FAIL;
--}
--
--static bool at803x_cdt_fault_length_valid(u16 status)
--{
-- switch (FIELD_GET(AT803X_CDT_STATUS_STAT_MASK, status)) {
-- case AT803X_CDT_STATUS_STAT_OPEN:
-- case AT803X_CDT_STATUS_STAT_SHORT:
-- return true;
-- }
-- return false;
--}
--
--static int at803x_cdt_fault_length(int dt)
--{
-- /* According to the datasheet the distance to the fault is
-- * DELTA_TIME * 0.824 meters.
-- *
-- * The author suspect the correct formula is:
-- *
-- * fault_distance = DELTA_TIME * (c * VF) / 125MHz / 2
-- *
-- * where c is the speed of light, VF is the velocity factor of
-- * the twisted pair cable, 125MHz the counter frequency and
-- * we need to divide by 2 because the hardware will measure the
-- * round trip time to the fault and back to the PHY.
-- *
-- * With a VF of 0.69 we get the factor 0.824 mentioned in the
-- * datasheet.
-- */
-- return (dt * 824) / 10;
--}
--
--static int at803x_cdt_start(struct phy_device *phydev,
-- u32 cdt_start)
--{
-- return phy_write(phydev, AT803X_CDT, cdt_start);
--}
--
--static int at803x_cdt_wait_for_completion(struct phy_device *phydev,
-- u32 cdt_en)
--{
-- int val, ret;
--
-- /* One test run takes about 25ms */
-- ret = phy_read_poll_timeout(phydev, AT803X_CDT, val,
-- !(val & cdt_en),
-- 30000, 100000, true);
--
-- return ret < 0 ? ret : 0;
--}
--
--static int at803x_cable_test_one_pair(struct phy_device *phydev, int pair)
--{
-- static const int ethtool_pair[] = {
-- ETHTOOL_A_CABLE_PAIR_A,
-- ETHTOOL_A_CABLE_PAIR_B,
-- ETHTOOL_A_CABLE_PAIR_C,
-- ETHTOOL_A_CABLE_PAIR_D,
-- };
-- int ret, val;
--
-- val = FIELD_PREP(AT803X_CDT_MDI_PAIR_MASK, pair) |
-- AT803X_CDT_ENABLE_TEST;
-- ret = at803x_cdt_start(phydev, val);
-- if (ret)
-- return ret;
--
-- ret = at803x_cdt_wait_for_completion(phydev, AT803X_CDT_ENABLE_TEST);
-- if (ret)
-- return ret;
--
-- val = phy_read(phydev, AT803X_CDT_STATUS);
-- if (val < 0)
-- return val;
--
-- if (at803x_cdt_test_failed(val))
-- return 0;
--
-- ethnl_cable_test_result(phydev, ethtool_pair[pair],
-- at803x_cable_test_result_trans(val));
--
-- if (at803x_cdt_fault_length_valid(val)) {
-- val = FIELD_GET(AT803X_CDT_STATUS_DELTA_TIME_MASK, val);
-- ethnl_cable_test_fault_length(phydev, ethtool_pair[pair],
-- at803x_cdt_fault_length(val));
-- }
--
-- return 1;
--}
--
--static int at803x_cable_test_get_status(struct phy_device *phydev,
-- bool *finished, unsigned long pair_mask)
--{
-- int retries = 20;
-- int pair, ret;
--
-- *finished = false;
--
-- /* According to the datasheet the CDT can be performed when
-- * there is no link partner or when the link partner is
-- * auto-negotiating. Starting the test will restart the AN
-- * automatically. It seems that doing this repeatedly we will
-- * get a slot where our link partner won't disturb our
-- * measurement.
-- */
-- while (pair_mask && retries--) {
-- for_each_set_bit(pair, &pair_mask, 4) {
-- ret = at803x_cable_test_one_pair(phydev, pair);
-- if (ret < 0)
-- return ret;
-- if (ret)
-- clear_bit(pair, &pair_mask);
-- }
-- if (pair_mask)
-- msleep(250);
-- }
--
-- *finished = true;
--
-- return 0;
--}
--
--static void at803x_cable_test_autoneg(struct phy_device *phydev)
--{
-- /* Enable auto-negotiation, but advertise no capabilities, no link
-- * will be established. A restart of the auto-negotiation is not
-- * required, because the cable test will automatically break the link.
-- */
-- phy_write(phydev, MII_BMCR, BMCR_ANENABLE);
-- phy_write(phydev, MII_ADVERTISE, ADVERTISE_CSMA);
--}
--
--static int at803x_cable_test_start(struct phy_device *phydev)
--{
-- at803x_cable_test_autoneg(phydev);
-- /* we do all the (time consuming) work later */
-- return 0;
--}
--
--static int at8031_rgmii_reg_set_voltage_sel(struct regulator_dev *rdev,
-- unsigned int selector)
--{
-- struct phy_device *phydev = rdev_get_drvdata(rdev);
--
-- if (selector)
-- return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_1F,
-- 0, AT803X_DEBUG_RGMII_1V8);
-- else
-- return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_1F,
-- AT803X_DEBUG_RGMII_1V8, 0);
--}
--
--static int at8031_rgmii_reg_get_voltage_sel(struct regulator_dev *rdev)
--{
-- struct phy_device *phydev = rdev_get_drvdata(rdev);
-- int val;
--
-- val = at803x_debug_reg_read(phydev, AT803X_DEBUG_REG_1F);
-- if (val < 0)
-- return val;
--
-- return (val & AT803X_DEBUG_RGMII_1V8) ? 1 : 0;
--}
--
--static const struct regulator_ops vddio_regulator_ops = {
-- .list_voltage = regulator_list_voltage_table,
-- .set_voltage_sel = at8031_rgmii_reg_set_voltage_sel,
-- .get_voltage_sel = at8031_rgmii_reg_get_voltage_sel,
--};
--
--static const unsigned int vddio_voltage_table[] = {
-- 1500000,
-- 1800000,
--};
--
--static const struct regulator_desc vddio_desc = {
-- .name = "vddio",
-- .of_match = of_match_ptr("vddio-regulator"),
-- .n_voltages = ARRAY_SIZE(vddio_voltage_table),
-- .volt_table = vddio_voltage_table,
-- .ops = &vddio_regulator_ops,
-- .type = REGULATOR_VOLTAGE,
-- .owner = THIS_MODULE,
--};
--
--static const struct regulator_ops vddh_regulator_ops = {
--};
--
--static const struct regulator_desc vddh_desc = {
-- .name = "vddh",
-- .of_match = of_match_ptr("vddh-regulator"),
-- .n_voltages = 1,
-- .fixed_uV = 2500000,
-- .ops = &vddh_regulator_ops,
-- .type = REGULATOR_VOLTAGE,
-- .owner = THIS_MODULE,
--};
--
--static int at8031_register_regulators(struct phy_device *phydev)
--{
-- struct at803x_priv *priv = phydev->priv;
-- struct device *dev = &phydev->mdio.dev;
-- struct regulator_config config = { };
--
-- config.dev = dev;
-- config.driver_data = phydev;
--
-- priv->vddio_rdev = devm_regulator_register(dev, &vddio_desc, &config);
-- if (IS_ERR(priv->vddio_rdev)) {
-- phydev_err(phydev, "failed to register VDDIO regulator\n");
-- return PTR_ERR(priv->vddio_rdev);
-- }
--
-- priv->vddh_rdev = devm_regulator_register(dev, &vddh_desc, &config);
-- if (IS_ERR(priv->vddh_rdev)) {
-- phydev_err(phydev, "failed to register VDDH regulator\n");
-- return PTR_ERR(priv->vddh_rdev);
-- }
--
-- return 0;
--}
--
--static int at8031_sfp_insert(void *upstream, const struct sfp_eeprom_id *id)
--{
-- struct phy_device *phydev = upstream;
-- __ETHTOOL_DECLARE_LINK_MODE_MASK(phy_support);
-- __ETHTOOL_DECLARE_LINK_MODE_MASK(sfp_support);
-- DECLARE_PHY_INTERFACE_MASK(interfaces);
-- phy_interface_t iface;
--
-- linkmode_zero(phy_support);
-- phylink_set(phy_support, 1000baseX_Full);
-- phylink_set(phy_support, 1000baseT_Full);
-- phylink_set(phy_support, Autoneg);
-- phylink_set(phy_support, Pause);
-- phylink_set(phy_support, Asym_Pause);
--
-- linkmode_zero(sfp_support);
-- sfp_parse_support(phydev->sfp_bus, id, sfp_support, interfaces);
-- /* Some modules support 10G modes as well as others we support.
-- * Mask out non-supported modes so the correct interface is picked.
-- */
-- linkmode_and(sfp_support, phy_support, sfp_support);
--
-- if (linkmode_empty(sfp_support)) {
-- dev_err(&phydev->mdio.dev, "incompatible SFP module inserted\n");
-- return -EINVAL;
-- }
--
-- iface = sfp_select_interface(phydev->sfp_bus, sfp_support);
--
-- /* Only 1000Base-X is supported by AR8031/8033 as the downstream SerDes
-- * interface for use with SFP modules.
-- * However, some copper modules detected as having a preferred SGMII
-- * interface do default to and function in 1000Base-X mode, so just
-- * print a warning and allow such modules, as they may have some chance
-- * of working.
-- */
-- if (iface == PHY_INTERFACE_MODE_SGMII)
-- dev_warn(&phydev->mdio.dev, "module may not function if 1000Base-X not supported\n");
-- else if (iface != PHY_INTERFACE_MODE_1000BASEX)
-- return -EINVAL;
--
-- return 0;
--}
--
--static const struct sfp_upstream_ops at8031_sfp_ops = {
-- .attach = phy_sfp_attach,
-- .detach = phy_sfp_detach,
-- .module_insert = at8031_sfp_insert,
--};
--
--static int at8031_parse_dt(struct phy_device *phydev)
--{
-- struct device_node *node = phydev->mdio.dev.of_node;
-- struct at803x_priv *priv = phydev->priv;
-- int ret;
--
-- if (of_property_read_bool(node, "qca,keep-pll-enabled"))
-- priv->flags |= AT803X_KEEP_PLL_ENABLED;
--
-- ret = at8031_register_regulators(phydev);
-- if (ret < 0)
-- return ret;
--
-- ret = devm_regulator_get_enable_optional(&phydev->mdio.dev,
-- "vddio");
-- if (ret) {
-- phydev_err(phydev, "failed to get VDDIO regulator\n");
-- return ret;
-- }
--
-- /* Only AR8031/8033 support 1000Base-X for SFP modules */
-- return phy_sfp_probe(phydev, &at8031_sfp_ops);
--}
--
--static int at8031_probe(struct phy_device *phydev)
--{
-- struct at803x_priv *priv = phydev->priv;
-- int mode_cfg;
-- int ccr;
-- int ret;
--
-- ret = at803x_probe(phydev);
-- if (ret)
-- return ret;
--
-- /* Only supported on AR8031/AR8033, the AR8030/AR8035 use strapping
-- * options.
-- */
-- ret = at8031_parse_dt(phydev);
-- if (ret)
-- return ret;
--
-- ccr = phy_read(phydev, AT803X_REG_CHIP_CONFIG);
-- if (ccr < 0)
-- return ccr;
-- mode_cfg = ccr & AT803X_MODE_CFG_MASK;
--
-- switch (mode_cfg) {
-- case AT803X_MODE_CFG_BX1000_RGMII_50OHM:
-- case AT803X_MODE_CFG_BX1000_RGMII_75OHM:
-- priv->is_1000basex = true;
-- fallthrough;
-- case AT803X_MODE_CFG_FX100_RGMII_50OHM:
-- case AT803X_MODE_CFG_FX100_RGMII_75OHM:
-- priv->is_fiber = true;
-- break;
-- }
--
-- /* Disable WoL in 1588 register which is enabled
-- * by default
-- */
-- return phy_modify_mmd(phydev, MDIO_MMD_PCS,
-- AT803X_PHY_MMD3_WOL_CTRL,
-- AT803X_WOL_EN, 0);
--}
--
--static int at8031_config_init(struct phy_device *phydev)
--{
-- struct at803x_priv *priv = phydev->priv;
-- int ret;
--
-- /* Some bootloaders leave the fiber page selected.
-- * Switch to the appropriate page (fiber or copper), as otherwise we
-- * read the PHY capabilities from the wrong page.
-- */
-- phy_lock_mdio_bus(phydev);
-- ret = at803x_write_page(phydev,
-- priv->is_fiber ? AT803X_PAGE_FIBER :
-- AT803X_PAGE_COPPER);
-- phy_unlock_mdio_bus(phydev);
-- if (ret)
-- return ret;
--
-- ret = at8031_pll_config(phydev);
-- if (ret < 0)
-- return ret;
--
-- return at803x_config_init(phydev);
--}
--
--static int at8031_set_wol(struct phy_device *phydev,
-- struct ethtool_wolinfo *wol)
--{
-- int ret;
--
-- /* First setup MAC address and enable WOL interrupt */
-- ret = at803x_set_wol(phydev, wol);
-- if (ret)
-- return ret;
--
-- if (wol->wolopts & WAKE_MAGIC)
-- /* Enable WOL function for 1588 */
-- ret = phy_modify_mmd(phydev, MDIO_MMD_PCS,
-- AT803X_PHY_MMD3_WOL_CTRL,
-- 0, AT803X_WOL_EN);
-- else
-- /* Disable WoL function for 1588 */
-- ret = phy_modify_mmd(phydev, MDIO_MMD_PCS,
-- AT803X_PHY_MMD3_WOL_CTRL,
-- AT803X_WOL_EN, 0);
--
-- return ret;
--}
--
--static int at8031_config_intr(struct phy_device *phydev)
--{
-- struct at803x_priv *priv = phydev->priv;
-- int err, value = 0;
--
-- if (phydev->interrupts == PHY_INTERRUPT_ENABLED &&
-- priv->is_fiber) {
-- /* Clear any pending interrupts */
-- err = at803x_ack_interrupt(phydev);
-- if (err)
-- return err;
--
-- value |= AT803X_INTR_ENABLE_LINK_FAIL_BX;
-- value |= AT803X_INTR_ENABLE_LINK_SUCCESS_BX;
--
-- err = phy_set_bits(phydev, AT803X_INTR_ENABLE, value);
-- if (err)
-- return err;
-- }
--
-- return at803x_config_intr(phydev);
--}
--
--/* AR8031 and AR8033 share the same read status logic */
--static int at8031_read_status(struct phy_device *phydev)
--{
-- struct at803x_priv *priv = phydev->priv;
--
-- if (priv->is_1000basex)
-- return genphy_c37_read_status(phydev);
--
-- return at803x_read_status(phydev);
--}
--
--/* AR8031 and AR8035 share the same cable test get status reg */
--static int at8031_cable_test_get_status(struct phy_device *phydev,
-- bool *finished)
--{
-- return at803x_cable_test_get_status(phydev, finished, 0xf);
--}
--
--/* AR8031 and AR8035 share the same cable test start logic */
--static int at8031_cable_test_start(struct phy_device *phydev)
--{
-- at803x_cable_test_autoneg(phydev);
-- phy_write(phydev, MII_CTRL1000, 0);
-- /* we do all the (time consuming) work later */
-- return 0;
--}
--
--/* AR8032, AR9331 and QCA9561 share the same cable test get status reg */
--static int at8032_cable_test_get_status(struct phy_device *phydev,
-- bool *finished)
--{
-- return at803x_cable_test_get_status(phydev, finished, 0x3);
--}
--
--static int at8035_parse_dt(struct phy_device *phydev)
--{
-- struct at803x_priv *priv = phydev->priv;
--
-- /* Mask is set by the generic at803x_parse_dt
-- * if property is set. Assume property is set
-- * with the mask not zero.
-- */
-- if (priv->clk_25m_mask) {
-- /* Fixup for the AR8030/AR8035. This chip has another mask and
-- * doesn't support the DSP reference. Eg. the lowest bit of the
-- * mask. The upper two bits select the same frequencies. Mask
-- * the lowest bit here.
-- *
-- * Warning:
-- * There was no datasheet for the AR8030 available so this is
-- * just a guess. But the AR8035 is listed as pin compatible
-- * to the AR8030 so there might be a good chance it works on
-- * the AR8030 too.
-- */
-- priv->clk_25m_reg &= AT8035_CLK_OUT_MASK;
-- priv->clk_25m_mask &= AT8035_CLK_OUT_MASK;
-- }
--
-- return 0;
--}
--
--/* AR8030 and AR8035 shared the same special mask for clk_25m */
--static int at8035_probe(struct phy_device *phydev)
--{
-- int ret;
--
-- ret = at803x_probe(phydev);
-- if (ret)
-- return ret;
--
-- return at8035_parse_dt(phydev);
--}
--
--static int qca83xx_config_init(struct phy_device *phydev)
--{
-- u8 switch_revision;
--
-- switch_revision = phydev->dev_flags & QCA8K_DEVFLAGS_REVISION_MASK;
--
-- switch (switch_revision) {
-- case 1:
-- /* For 100M waveform */
-- at803x_debug_reg_write(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL, 0x02ea);
-- /* Turn on Gigabit clock */
-- at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_GREEN, 0x68a0);
-- break;
--
-- case 2:
-- phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV, 0x0);
-- fallthrough;
-- case 4:
-- phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_AZ_DEBUG, 0x803f);
-- at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_GREEN, 0x6860);
-- at803x_debug_reg_write(phydev, AT803X_DEBUG_SYSTEM_CTRL_MODE, 0x2c46);
-- at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_3C, 0x6000);
-- break;
-- }
--
-- /* Following original QCA sourcecode set port to prefer master */
-- phy_set_bits(phydev, MII_CTRL1000, CTL1000_PREFER_MASTER);
--
-- return 0;
--}
--
--static int qca8327_config_init(struct phy_device *phydev)
--{
-- /* QCA8327 require DAC amplitude adjustment for 100m set to +6%.
-- * Disable on init and enable only with 100m speed following
-- * qca original source code.
-- */
-- at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL,
-- QCA8327_DEBUG_MANU_CTRL_EN, 0);
--
-- return qca83xx_config_init(phydev);
--}
--
--static void qca83xx_link_change_notify(struct phy_device *phydev)
--{
-- /* Set DAC Amplitude adjustment to +6% for 100m on link running */
-- if (phydev->state == PHY_RUNNING) {
-- if (phydev->speed == SPEED_100)
-- at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL,
-- QCA8327_DEBUG_MANU_CTRL_EN,
-- QCA8327_DEBUG_MANU_CTRL_EN);
-- } else {
-- /* Reset DAC Amplitude adjustment */
-- at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL,
-- QCA8327_DEBUG_MANU_CTRL_EN, 0);
-- }
--}
--
--static int qca83xx_resume(struct phy_device *phydev)
--{
-- int ret, val;
--
-- /* Skip reset if not suspended */
-- if (!phydev->suspended)
-- return 0;
--
-- /* Reinit the port, reset values set by suspend */
-- qca83xx_config_init(phydev);
--
-- /* Reset the port on port resume */
-- phy_set_bits(phydev, MII_BMCR, BMCR_RESET | BMCR_ANENABLE);
--
-- /* On resume from suspend the switch execute a reset and
-- * restart auto-negotiation. Wait for reset to complete.
-- */
-- ret = phy_read_poll_timeout(phydev, MII_BMCR, val, !(val & BMCR_RESET),
-- 50000, 600000, true);
-- if (ret)
-- return ret;
--
-- usleep_range(1000, 2000);
--
-- return 0;
--}
--
--static int qca83xx_suspend(struct phy_device *phydev)
--{
-- at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_GREEN,
-- AT803X_DEBUG_GATE_CLK_IN1000, 0);
--
-- at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_HIB_CTRL,
-- AT803X_DEBUG_HIB_CTRL_EN_ANY_CHANGE |
-- AT803X_DEBUG_HIB_CTRL_SEL_RST_80U, 0);
--
-- return 0;
--}
--
--static int qca8337_suspend(struct phy_device *phydev)
--{
-- /* Only QCA8337 support actual suspend. */
-- genphy_suspend(phydev);
--
-- return qca83xx_suspend(phydev);
--}
--
--static int qca8327_suspend(struct phy_device *phydev)
--{
-- u16 mask = 0;
--
-- /* QCA8327 cause port unreliability when phy suspend
-- * is set.
-- */
-- mask |= ~(BMCR_SPEED1000 | BMCR_FULLDPLX);
-- phy_modify(phydev, MII_BMCR, mask, 0);
--
-- return qca83xx_suspend(phydev);
--}
--
--static int qca808x_phy_fast_retrain_config(struct phy_device *phydev)
--{
-- int ret;
--
-- /* Enable fast retrain */
-- ret = genphy_c45_fast_retrain(phydev, true);
-- if (ret)
-- return ret;
--
-- phy_write_mmd(phydev, MDIO_MMD_AN, QCA808X_PHY_MMD7_TOP_OPTION1,
-- QCA808X_TOP_OPTION1_DATA);
-- phy_write_mmd(phydev, MDIO_MMD_PMAPMD, QCA808X_PHY_MMD1_MSE_THRESHOLD_20DB,
-- QCA808X_MSE_THRESHOLD_20DB_VALUE);
-- phy_write_mmd(phydev, MDIO_MMD_PMAPMD, QCA808X_PHY_MMD1_MSE_THRESHOLD_17DB,
-- QCA808X_MSE_THRESHOLD_17DB_VALUE);
-- phy_write_mmd(phydev, MDIO_MMD_PMAPMD, QCA808X_PHY_MMD1_MSE_THRESHOLD_27DB,
-- QCA808X_MSE_THRESHOLD_27DB_VALUE);
-- phy_write_mmd(phydev, MDIO_MMD_PMAPMD, QCA808X_PHY_MMD1_MSE_THRESHOLD_28DB,
-- QCA808X_MSE_THRESHOLD_28DB_VALUE);
-- phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_1,
-- QCA808X_MMD3_DEBUG_1_VALUE);
-- phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_4,
-- QCA808X_MMD3_DEBUG_4_VALUE);
-- phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_5,
-- QCA808X_MMD3_DEBUG_5_VALUE);
-- phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_3,
-- QCA808X_MMD3_DEBUG_3_VALUE);
-- phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_6,
-- QCA808X_MMD3_DEBUG_6_VALUE);
-- phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_2,
-- QCA808X_MMD3_DEBUG_2_VALUE);
--
-- return 0;
--}
--
--static int qca808x_phy_ms_seed_enable(struct phy_device *phydev, bool enable)
--{
-- u16 seed_value;
--
-- if (!enable)
-- return at803x_debug_reg_mask(phydev, QCA808X_PHY_DEBUG_LOCAL_SEED,
-- QCA808X_MASTER_SLAVE_SEED_ENABLE, 0);
--
-- seed_value = get_random_u32_below(QCA808X_MASTER_SLAVE_SEED_RANGE);
-- return at803x_debug_reg_mask(phydev, QCA808X_PHY_DEBUG_LOCAL_SEED,
-- QCA808X_MASTER_SLAVE_SEED_CFG | QCA808X_MASTER_SLAVE_SEED_ENABLE,
-- FIELD_PREP(QCA808X_MASTER_SLAVE_SEED_CFG, seed_value) |
-- QCA808X_MASTER_SLAVE_SEED_ENABLE);
--}
--
--static bool qca808x_is_prefer_master(struct phy_device *phydev)
--{
-- return (phydev->master_slave_get == MASTER_SLAVE_CFG_MASTER_FORCE) ||
-- (phydev->master_slave_get == MASTER_SLAVE_CFG_MASTER_PREFERRED);
--}
--
--static bool qca808x_has_fast_retrain_or_slave_seed(struct phy_device *phydev)
--{
-- return linkmode_test_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, phydev->supported);
--}
--
--static int qca808x_config_init(struct phy_device *phydev)
--{
-- int ret;
--
-- /* Active adc&vga on 802.3az for the link 1000M and 100M */
-- ret = phy_modify_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_ADDR_CLD_CTRL7,
-- QCA808X_8023AZ_AFE_CTRL_MASK, QCA808X_8023AZ_AFE_EN);
-- if (ret)
-- return ret;
--
-- /* Adjust the threshold on 802.3az for the link 1000M */
-- ret = phy_write_mmd(phydev, MDIO_MMD_PCS,
-- QCA808X_PHY_MMD3_AZ_TRAINING_CTRL,
-- QCA808X_MMD3_AZ_TRAINING_VAL);
-- if (ret)
-- return ret;
--
-- if (qca808x_has_fast_retrain_or_slave_seed(phydev)) {
-- /* Config the fast retrain for the link 2500M */
-- ret = qca808x_phy_fast_retrain_config(phydev);
-- if (ret)
-- return ret;
--
-- ret = genphy_read_master_slave(phydev);
-- if (ret < 0)
-- return ret;
--
-- if (!qca808x_is_prefer_master(phydev)) {
-- /* Enable seed and configure lower ramdom seed to make phy
-- * linked as slave mode.
-- */
-- ret = qca808x_phy_ms_seed_enable(phydev, true);
-- if (ret)
-- return ret;
-- }
-- }
--
-- /* Configure adc threshold as 100mv for the link 10M */
-- return at803x_debug_reg_mask(phydev, QCA808X_PHY_DEBUG_ADC_THRESHOLD,
-- QCA808X_ADC_THRESHOLD_MASK,
-- QCA808X_ADC_THRESHOLD_100MV);
--}
--
--static int qca808x_read_status(struct phy_device *phydev)
--{
-- struct at803x_ss_mask ss_mask = { 0 };
-- int ret;
--
-- ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_10GBT_STAT);
-- if (ret < 0)
-- return ret;
--
-- linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, phydev->lp_advertising,
-- ret & MDIO_AN_10GBT_STAT_LP2_5G);
--
-- ret = genphy_read_status(phydev);
-- if (ret)
-- return ret;
--
-- /* qca8081 takes the different bits for speed value from at803x */
-- ss_mask.speed_mask = QCA808X_SS_SPEED_MASK;
-- ss_mask.speed_shift = __bf_shf(QCA808X_SS_SPEED_MASK);
-- ret = at803x_read_specific_status(phydev, ss_mask);
-- if (ret < 0)
-- return ret;
--
-- if (phydev->link) {
-- if (phydev->speed == SPEED_2500)
-- phydev->interface = PHY_INTERFACE_MODE_2500BASEX;
-- else
-- phydev->interface = PHY_INTERFACE_MODE_SGMII;
-- } else {
-- /* generate seed as a lower random value to make PHY linked as SLAVE easily,
-- * except for master/slave configuration fault detected or the master mode
-- * preferred.
-- *
-- * the reason for not putting this code into the function link_change_notify is
-- * the corner case where the link partner is also the qca8081 PHY and the seed
-- * value is configured as the same value, the link can't be up and no link change
-- * occurs.
-- */
-- if (qca808x_has_fast_retrain_or_slave_seed(phydev)) {
-- if (phydev->master_slave_state == MASTER_SLAVE_STATE_ERR ||
-- qca808x_is_prefer_master(phydev)) {
-- qca808x_phy_ms_seed_enable(phydev, false);
-- } else {
-- qca808x_phy_ms_seed_enable(phydev, true);
-- }
-- }
-- }
--
-- return 0;
--}
--
--static int qca808x_soft_reset(struct phy_device *phydev)
--{
-- int ret;
--
-- ret = genphy_soft_reset(phydev);
-- if (ret < 0)
-- return ret;
--
-- if (qca808x_has_fast_retrain_or_slave_seed(phydev))
-- ret = qca808x_phy_ms_seed_enable(phydev, true);
--
-- return ret;
--}
--
--static bool qca808x_cdt_fault_length_valid(int cdt_code)
--{
-- switch (cdt_code) {
-- case QCA808X_CDT_STATUS_STAT_SAME_SHORT:
-- case QCA808X_CDT_STATUS_STAT_SAME_OPEN:
-- case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_NORMAL:
-- case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_OPEN:
-- case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_SHORT:
-- case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_NORMAL:
-- case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_OPEN:
-- case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_SHORT:
-- case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_NORMAL:
-- case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_OPEN:
-- case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_SHORT:
-- return true;
-- default:
-- return false;
-- }
--}
--
--static int qca808x_cable_test_result_trans(int cdt_code)
--{
-- switch (cdt_code) {
-- case QCA808X_CDT_STATUS_STAT_NORMAL:
-- return ETHTOOL_A_CABLE_RESULT_CODE_OK;
-- case QCA808X_CDT_STATUS_STAT_SAME_SHORT:
-- return ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT;
-- case QCA808X_CDT_STATUS_STAT_SAME_OPEN:
-- return ETHTOOL_A_CABLE_RESULT_CODE_OPEN;
-- case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_NORMAL:
-- case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_OPEN:
-- case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_SHORT:
-- case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_NORMAL:
-- case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_OPEN:
-- case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_SHORT:
-- case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_NORMAL:
-- case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_OPEN:
-- case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_SHORT:
-- return ETHTOOL_A_CABLE_RESULT_CODE_CROSS_SHORT;
-- case QCA808X_CDT_STATUS_STAT_FAIL:
-- default:
-- return ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC;
-- }
--}
--
--static int qca808x_cdt_fault_length(struct phy_device *phydev, int pair,
-- int result)
--{
-- int val;
-- u32 cdt_length_reg = 0;
--
-- switch (pair) {
-- case ETHTOOL_A_CABLE_PAIR_A:
-- cdt_length_reg = QCA808X_MMD3_CDT_DIAG_PAIR_A;
-- break;
-- case ETHTOOL_A_CABLE_PAIR_B:
-- cdt_length_reg = QCA808X_MMD3_CDT_DIAG_PAIR_B;
-- break;
-- case ETHTOOL_A_CABLE_PAIR_C:
-- cdt_length_reg = QCA808X_MMD3_CDT_DIAG_PAIR_C;
-- break;
-- case ETHTOOL_A_CABLE_PAIR_D:
-- cdt_length_reg = QCA808X_MMD3_CDT_DIAG_PAIR_D;
-- break;
-- default:
-- return -EINVAL;
-- }
--
-- val = phy_read_mmd(phydev, MDIO_MMD_PCS, cdt_length_reg);
-- if (val < 0)
-- return val;
--
-- if (result == ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT)
-- val = FIELD_GET(QCA808X_CDT_DIAG_LENGTH_SAME_SHORT, val);
-- else
-- val = FIELD_GET(QCA808X_CDT_DIAG_LENGTH_CROSS_SHORT, val);
--
-- return at803x_cdt_fault_length(val);
--}
--
--static int qca808x_cable_test_start(struct phy_device *phydev)
--{
-- int ret;
--
-- /* perform CDT with the following configs:
-- * 1. disable hibernation.
-- * 2. force PHY working in MDI mode.
-- * 3. for PHY working in 1000BaseT.
-- * 4. configure the threshold.
-- */
--
-- ret = at803x_debug_reg_mask(phydev, QCA808X_DBG_AN_TEST, QCA808X_HIBERNATION_EN, 0);
-- if (ret < 0)
-- return ret;
--
-- ret = at803x_config_mdix(phydev, ETH_TP_MDI);
-- if (ret < 0)
-- return ret;
--
-- /* Force 1000base-T needs to configure PMA/PMD and MII_BMCR */
-- phydev->duplex = DUPLEX_FULL;
-- phydev->speed = SPEED_1000;
-- ret = genphy_c45_pma_setup_forced(phydev);
-- if (ret < 0)
-- return ret;
--
-- ret = genphy_setup_forced(phydev);
-- if (ret < 0)
-- return ret;
--
-- /* configure the thresholds for open, short, pair ok test */
-- phy_write_mmd(phydev, MDIO_MMD_PCS, 0x8074, 0xc040);
-- phy_write_mmd(phydev, MDIO_MMD_PCS, 0x8076, 0xc040);
-- phy_write_mmd(phydev, MDIO_MMD_PCS, 0x8077, 0xa060);
-- phy_write_mmd(phydev, MDIO_MMD_PCS, 0x8078, 0xc050);
-- phy_write_mmd(phydev, MDIO_MMD_PCS, 0x807a, 0xc060);
-- phy_write_mmd(phydev, MDIO_MMD_PCS, 0x807e, 0xb060);
--
-- return 0;
--}
--
--static int qca808x_cable_test_get_pair_status(struct phy_device *phydev, u8 pair,
-- u16 status)
--{
-- int length, result;
-- u16 pair_code;
--
-- switch (pair) {
-- case ETHTOOL_A_CABLE_PAIR_A:
-- pair_code = FIELD_GET(QCA808X_CDT_CODE_PAIR_A, status);
-- break;
-- case ETHTOOL_A_CABLE_PAIR_B:
-- pair_code = FIELD_GET(QCA808X_CDT_CODE_PAIR_B, status);
-- break;
-- case ETHTOOL_A_CABLE_PAIR_C:
-- pair_code = FIELD_GET(QCA808X_CDT_CODE_PAIR_C, status);
-- break;
-- case ETHTOOL_A_CABLE_PAIR_D:
-- pair_code = FIELD_GET(QCA808X_CDT_CODE_PAIR_D, status);
-- break;
-- default:
-- return -EINVAL;
-- }
--
-- result = qca808x_cable_test_result_trans(pair_code);
-- ethnl_cable_test_result(phydev, pair, result);
--
-- if (qca808x_cdt_fault_length_valid(pair_code)) {
-- length = qca808x_cdt_fault_length(phydev, pair, result);
-- ethnl_cable_test_fault_length(phydev, pair, length);
-- }
--
-- return 0;
--}
--
--static int qca808x_cable_test_get_status(struct phy_device *phydev, bool *finished)
--{
-- int ret, val;
--
-- *finished = false;
--
-- val = QCA808X_CDT_ENABLE_TEST |
-- QCA808X_CDT_LENGTH_UNIT;
-- ret = at803x_cdt_start(phydev, val);
-- if (ret)
-- return ret;
--
-- ret = at803x_cdt_wait_for_completion(phydev, QCA808X_CDT_ENABLE_TEST);
-- if (ret)
-- return ret;
--
-- val = phy_read_mmd(phydev, MDIO_MMD_PCS, QCA808X_MMD3_CDT_STATUS);
-- if (val < 0)
-- return val;
--
-- ret = qca808x_cable_test_get_pair_status(phydev, ETHTOOL_A_CABLE_PAIR_A, val);
-- if (ret)
-- return ret;
--
-- ret = qca808x_cable_test_get_pair_status(phydev, ETHTOOL_A_CABLE_PAIR_B, val);
-- if (ret)
-- return ret;
--
-- ret = qca808x_cable_test_get_pair_status(phydev, ETHTOOL_A_CABLE_PAIR_C, val);
-- if (ret)
-- return ret;
--
-- ret = qca808x_cable_test_get_pair_status(phydev, ETHTOOL_A_CABLE_PAIR_D, val);
-- if (ret)
-- return ret;
--
-- *finished = true;
--
-- return 0;
--}
--
--static int qca808x_get_features(struct phy_device *phydev)
--{
-- int ret;
--
-- ret = genphy_c45_pma_read_abilities(phydev);
-- if (ret)
-- return ret;
--
-- /* The autoneg ability is not existed in bit3 of MMD7.1,
-- * but it is supported by qca808x PHY, so we add it here
-- * manually.
-- */
-- linkmode_set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, phydev->supported);
--
-- /* As for the qca8081 1G version chip, the 2500baseT ability is also
-- * existed in the bit0 of MMD1.21, we need to remove it manually if
-- * it is the qca8081 1G chip according to the bit0 of MMD7.0x901d.
-- */
-- ret = phy_read_mmd(phydev, MDIO_MMD_AN, QCA808X_PHY_MMD7_CHIP_TYPE);
-- if (ret < 0)
-- return ret;
--
-- if (QCA808X_PHY_CHIP_TYPE_1G & ret)
-- linkmode_clear_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, phydev->supported);
--
-- return 0;
--}
--
--static int qca808x_config_aneg(struct phy_device *phydev)
--{
-- int phy_ctrl = 0;
-- int ret;
--
-- ret = at803x_prepare_config_aneg(phydev);
-- if (ret)
-- return ret;
--
-- /* The reg MII_BMCR also needs to be configured for force mode, the
-- * genphy_config_aneg is also needed.
-- */
-- if (phydev->autoneg == AUTONEG_DISABLE)
-- genphy_c45_pma_setup_forced(phydev);
--
-- if (linkmode_test_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, phydev->advertising))
-- phy_ctrl = MDIO_AN_10GBT_CTRL_ADV2_5G;
--
-- ret = phy_modify_mmd_changed(phydev, MDIO_MMD_AN, MDIO_AN_10GBT_CTRL,
-- MDIO_AN_10GBT_CTRL_ADV2_5G, phy_ctrl);
-- if (ret < 0)
-- return ret;
--
-- return __genphy_config_aneg(phydev, ret);
--}
--
--static void qca808x_link_change_notify(struct phy_device *phydev)
--{
-- /* Assert interface sgmii fifo on link down, deassert it on link up,
-- * the interface device address is always phy address added by 1.
-- */
-- mdiobus_c45_modify_changed(phydev->mdio.bus, phydev->mdio.addr + 1,
-- MDIO_MMD_PMAPMD, QCA8081_PHY_SERDES_MMD1_FIFO_CTRL,
-- QCA8081_PHY_FIFO_RSTN,
-- phydev->link ? QCA8081_PHY_FIFO_RSTN : 0);
--}
--
--static int qca808x_led_parse_netdev(struct phy_device *phydev, unsigned long rules,
-- u16 *offload_trigger)
--{
-- /* Parsing specific to netdev trigger */
-- if (test_bit(TRIGGER_NETDEV_TX, &rules))
-- *offload_trigger |= QCA808X_LED_TX_BLINK;
-- if (test_bit(TRIGGER_NETDEV_RX, &rules))
-- *offload_trigger |= QCA808X_LED_RX_BLINK;
-- if (test_bit(TRIGGER_NETDEV_LINK_10, &rules))
-- *offload_trigger |= QCA808X_LED_SPEED10_ON;
-- if (test_bit(TRIGGER_NETDEV_LINK_100, &rules))
-- *offload_trigger |= QCA808X_LED_SPEED100_ON;
-- if (test_bit(TRIGGER_NETDEV_LINK_1000, &rules))
-- *offload_trigger |= QCA808X_LED_SPEED1000_ON;
-- if (test_bit(TRIGGER_NETDEV_LINK_2500, &rules))
-- *offload_trigger |= QCA808X_LED_SPEED2500_ON;
-- if (test_bit(TRIGGER_NETDEV_HALF_DUPLEX, &rules))
-- *offload_trigger |= QCA808X_LED_HALF_DUPLEX_ON;
-- if (test_bit(TRIGGER_NETDEV_FULL_DUPLEX, &rules))
-- *offload_trigger |= QCA808X_LED_FULL_DUPLEX_ON;
--
-- if (rules && !*offload_trigger)
-- return -EOPNOTSUPP;
--
-- /* Enable BLINK_CHECK_BYPASS by default to make the LED
-- * blink even with duplex or speed mode not enabled.
-- */
-- *offload_trigger |= QCA808X_LED_BLINK_CHECK_BYPASS;
--
-- return 0;
--}
--
--static int qca808x_led_hw_control_enable(struct phy_device *phydev, u8 index)
--{
-- u16 reg;
--
-- if (index > 2)
-- return -EINVAL;
--
-- reg = QCA808X_MMD7_LED_FORCE_CTRL(index);
--
-- return phy_clear_bits_mmd(phydev, MDIO_MMD_AN, reg,
-- QCA808X_LED_FORCE_EN);
--}
--
--static int qca808x_led_hw_is_supported(struct phy_device *phydev, u8 index,
-- unsigned long rules)
--{
-- u16 offload_trigger = 0;
--
-- if (index > 2)
-- return -EINVAL;
--
-- return qca808x_led_parse_netdev(phydev, rules, &offload_trigger);
--}
--
--static int qca808x_led_hw_control_set(struct phy_device *phydev, u8 index,
-- unsigned long rules)
--{
-- u16 reg, offload_trigger = 0;
-- int ret;
--
-- if (index > 2)
-- return -EINVAL;
--
-- reg = QCA808X_MMD7_LED_CTRL(index);
--
-- ret = qca808x_led_parse_netdev(phydev, rules, &offload_trigger);
-- if (ret)
-- return ret;
--
-- ret = qca808x_led_hw_control_enable(phydev, index);
-- if (ret)
-- return ret;
--
-- return phy_modify_mmd(phydev, MDIO_MMD_AN, reg,
-- QCA808X_LED_PATTERN_MASK,
-- offload_trigger);
--}
--
--static bool qca808x_led_hw_control_status(struct phy_device *phydev, u8 index)
--{
-- u16 reg;
-- int val;
--
-- if (index > 2)
-- return false;
--
-- reg = QCA808X_MMD7_LED_FORCE_CTRL(index);
--
-- val = phy_read_mmd(phydev, MDIO_MMD_AN, reg);
--
-- return !(val & QCA808X_LED_FORCE_EN);
--}
--
--static int qca808x_led_hw_control_get(struct phy_device *phydev, u8 index,
-- unsigned long *rules)
--{
-- u16 reg;
-- int val;
--
-- if (index > 2)
-- return -EINVAL;
--
-- /* Check if we have hw control enabled */
-- if (qca808x_led_hw_control_status(phydev, index))
-- return -EINVAL;
--
-- reg = QCA808X_MMD7_LED_CTRL(index);
--
-- val = phy_read_mmd(phydev, MDIO_MMD_AN, reg);
-- if (val & QCA808X_LED_TX_BLINK)
-- set_bit(TRIGGER_NETDEV_TX, rules);
-- if (val & QCA808X_LED_RX_BLINK)
-- set_bit(TRIGGER_NETDEV_RX, rules);
-- if (val & QCA808X_LED_SPEED10_ON)
-- set_bit(TRIGGER_NETDEV_LINK_10, rules);
-- if (val & QCA808X_LED_SPEED100_ON)
-- set_bit(TRIGGER_NETDEV_LINK_100, rules);
-- if (val & QCA808X_LED_SPEED1000_ON)
-- set_bit(TRIGGER_NETDEV_LINK_1000, rules);
-- if (val & QCA808X_LED_SPEED2500_ON)
-- set_bit(TRIGGER_NETDEV_LINK_2500, rules);
-- if (val & QCA808X_LED_HALF_DUPLEX_ON)
-- set_bit(TRIGGER_NETDEV_HALF_DUPLEX, rules);
-- if (val & QCA808X_LED_FULL_DUPLEX_ON)
-- set_bit(TRIGGER_NETDEV_FULL_DUPLEX, rules);
--
-- return 0;
--}
--
--static int qca808x_led_hw_control_reset(struct phy_device *phydev, u8 index)
--{
-- u16 reg;
--
-- if (index > 2)
-- return -EINVAL;
--
-- reg = QCA808X_MMD7_LED_CTRL(index);
--
-- return phy_clear_bits_mmd(phydev, MDIO_MMD_AN, reg,
-- QCA808X_LED_PATTERN_MASK);
--}
--
--static int qca808x_led_brightness_set(struct phy_device *phydev,
-- u8 index, enum led_brightness value)
--{
-- u16 reg;
-- int ret;
--
-- if (index > 2)
-- return -EINVAL;
--
-- if (!value) {
-- ret = qca808x_led_hw_control_reset(phydev, index);
-- if (ret)
-- return ret;
-- }
--
-- reg = QCA808X_MMD7_LED_FORCE_CTRL(index);
--
-- return phy_modify_mmd(phydev, MDIO_MMD_AN, reg,
-- QCA808X_LED_FORCE_EN | QCA808X_LED_FORCE_MODE_MASK,
-- QCA808X_LED_FORCE_EN | value ? QCA808X_LED_FORCE_ON :
-- QCA808X_LED_FORCE_OFF);
--}
--
--static int qca808x_led_blink_set(struct phy_device *phydev, u8 index,
-- unsigned long *delay_on,
-- unsigned long *delay_off)
--{
-- int ret;
-- u16 reg;
--
-- if (index > 2)
-- return -EINVAL;
--
-- reg = QCA808X_MMD7_LED_FORCE_CTRL(index);
--
-- /* Set blink to 50% off, 50% on at 4Hz by default */
-- ret = phy_modify_mmd(phydev, MDIO_MMD_AN, QCA808X_MMD7_LED_GLOBAL,
-- QCA808X_LED_BLINK_FREQ_MASK | QCA808X_LED_BLINK_DUTY_MASK,
-- QCA808X_LED_BLINK_FREQ_4HZ | QCA808X_LED_BLINK_DUTY_50_50);
-- if (ret)
-- return ret;
--
-- /* We use BLINK_1 for normal blinking */
-- ret = phy_modify_mmd(phydev, MDIO_MMD_AN, reg,
-- QCA808X_LED_FORCE_EN | QCA808X_LED_FORCE_MODE_MASK,
-- QCA808X_LED_FORCE_EN | QCA808X_LED_FORCE_BLINK_1);
-- if (ret)
-- return ret;
--
-- /* We set blink to 4Hz, aka 250ms */
-- *delay_on = 250 / 2;
-- *delay_off = 250 / 2;
--
-- return 0;
--}
--
--static int qca808x_led_polarity_set(struct phy_device *phydev, int index,
-- unsigned long modes)
--{
-- struct at803x_priv *priv = phydev->priv;
-- bool active_low = false;
-- u32 mode;
--
-- for_each_set_bit(mode, &modes, __PHY_LED_MODES_NUM) {
-- switch (mode) {
-- case PHY_LED_ACTIVE_LOW:
-- active_low = true;
-- break;
-- default:
-- return -EINVAL;
-- }
-- }
--
-- /* PHY polarity is global and can't be set per LED.
-- * To detect this, check if last requested polarity mode
-- * match the new one.
-- */
-- if (priv->led_polarity_mode >= 0 &&
-- priv->led_polarity_mode != active_low) {
-- phydev_err(phydev, "PHY polarity is global. Mismatched polarity on different LED\n");
-- return -EINVAL;
-- }
--
-- /* Save the last PHY polarity mode */
-- priv->led_polarity_mode = active_low;
--
-- return phy_modify_mmd(phydev, MDIO_MMD_AN,
-- QCA808X_MMD7_LED_POLARITY_CTRL,
-- QCA808X_LED_ACTIVE_HIGH,
-- active_low ? 0 : QCA808X_LED_ACTIVE_HIGH);
--}
--
--static struct phy_driver at803x_driver[] = {
--{
-- /* Qualcomm Atheros AR8035 */
-- PHY_ID_MATCH_EXACT(ATH8035_PHY_ID),
-- .name = "Qualcomm Atheros AR8035",
-- .flags = PHY_POLL_CABLE_TEST,
-- .probe = at8035_probe,
-- .config_aneg = at803x_config_aneg,
-- .config_init = at803x_config_init,
-- .soft_reset = genphy_soft_reset,
-- .set_wol = at803x_set_wol,
-- .get_wol = at803x_get_wol,
-- .suspend = at803x_suspend,
-- .resume = at803x_resume,
-- /* PHY_GBIT_FEATURES */
-- .read_status = at803x_read_status,
-- .config_intr = at803x_config_intr,
-- .handle_interrupt = at803x_handle_interrupt,
-- .get_tunable = at803x_get_tunable,
-- .set_tunable = at803x_set_tunable,
-- .cable_test_start = at8031_cable_test_start,
-- .cable_test_get_status = at8031_cable_test_get_status,
--}, {
-- /* Qualcomm Atheros AR8030 */
-- .phy_id = ATH8030_PHY_ID,
-- .name = "Qualcomm Atheros AR8030",
-- .phy_id_mask = AT8030_PHY_ID_MASK,
-- .probe = at8035_probe,
-- .config_init = at803x_config_init,
-- .link_change_notify = at803x_link_change_notify,
-- .set_wol = at803x_set_wol,
-- .get_wol = at803x_get_wol,
-- .suspend = at803x_suspend,
-- .resume = at803x_resume,
-- /* PHY_BASIC_FEATURES */
-- .config_intr = at803x_config_intr,
-- .handle_interrupt = at803x_handle_interrupt,
--}, {
-- /* Qualcomm Atheros AR8031/AR8033 */
-- PHY_ID_MATCH_EXACT(ATH8031_PHY_ID),
-- .name = "Qualcomm Atheros AR8031/AR8033",
-- .flags = PHY_POLL_CABLE_TEST,
-- .probe = at8031_probe,
-- .config_init = at8031_config_init,
-- .config_aneg = at803x_config_aneg,
-- .soft_reset = genphy_soft_reset,
-- .set_wol = at8031_set_wol,
-- .get_wol = at803x_get_wol,
-- .suspend = at803x_suspend,
-- .resume = at803x_resume,
-- .read_page = at803x_read_page,
-- .write_page = at803x_write_page,
-- .get_features = at803x_get_features,
-- .read_status = at8031_read_status,
-- .config_intr = at8031_config_intr,
-- .handle_interrupt = at803x_handle_interrupt,
-- .get_tunable = at803x_get_tunable,
-- .set_tunable = at803x_set_tunable,
-- .cable_test_start = at8031_cable_test_start,
-- .cable_test_get_status = at8031_cable_test_get_status,
--}, {
-- /* Qualcomm Atheros AR8032 */
-- PHY_ID_MATCH_EXACT(ATH8032_PHY_ID),
-- .name = "Qualcomm Atheros AR8032",
-- .probe = at803x_probe,
-- .flags = PHY_POLL_CABLE_TEST,
-- .config_init = at803x_config_init,
-- .link_change_notify = at803x_link_change_notify,
-- .suspend = at803x_suspend,
-- .resume = at803x_resume,
-- /* PHY_BASIC_FEATURES */
-- .config_intr = at803x_config_intr,
-- .handle_interrupt = at803x_handle_interrupt,
-- .cable_test_start = at803x_cable_test_start,
-- .cable_test_get_status = at8032_cable_test_get_status,
--}, {
-- /* ATHEROS AR9331 */
-- PHY_ID_MATCH_EXACT(ATH9331_PHY_ID),
-- .name = "Qualcomm Atheros AR9331 built-in PHY",
-- .probe = at803x_probe,
-- .suspend = at803x_suspend,
-- .resume = at803x_resume,
-- .flags = PHY_POLL_CABLE_TEST,
-- /* PHY_BASIC_FEATURES */
-- .config_intr = at803x_config_intr,
-- .handle_interrupt = at803x_handle_interrupt,
-- .cable_test_start = at803x_cable_test_start,
-- .cable_test_get_status = at8032_cable_test_get_status,
-- .read_status = at803x_read_status,
-- .soft_reset = genphy_soft_reset,
-- .config_aneg = at803x_config_aneg,
--}, {
-- /* Qualcomm Atheros QCA9561 */
-- PHY_ID_MATCH_EXACT(QCA9561_PHY_ID),
-- .name = "Qualcomm Atheros QCA9561 built-in PHY",
-- .probe = at803x_probe,
-- .suspend = at803x_suspend,
-- .resume = at803x_resume,
-- .flags = PHY_POLL_CABLE_TEST,
-- /* PHY_BASIC_FEATURES */
-- .config_intr = at803x_config_intr,
-- .handle_interrupt = at803x_handle_interrupt,
-- .cable_test_start = at803x_cable_test_start,
-- .cable_test_get_status = at8032_cable_test_get_status,
-- .read_status = at803x_read_status,
-- .soft_reset = genphy_soft_reset,
-- .config_aneg = at803x_config_aneg,
--}, {
-- /* QCA8337 */
-- .phy_id = QCA8337_PHY_ID,
-- .phy_id_mask = QCA8K_PHY_ID_MASK,
-- .name = "Qualcomm Atheros 8337 internal PHY",
-- /* PHY_GBIT_FEATURES */
-- .probe = at803x_probe,
-- .flags = PHY_IS_INTERNAL,
-- .config_init = qca83xx_config_init,
-- .soft_reset = genphy_soft_reset,
-- .get_sset_count = qca83xx_get_sset_count,
-- .get_strings = qca83xx_get_strings,
-- .get_stats = qca83xx_get_stats,
-- .suspend = qca8337_suspend,
-- .resume = qca83xx_resume,
--}, {
-- /* QCA8327-A from switch QCA8327-AL1A */
-- .phy_id = QCA8327_A_PHY_ID,
-- .phy_id_mask = QCA8K_PHY_ID_MASK,
-- .name = "Qualcomm Atheros 8327-A internal PHY",
-- /* PHY_GBIT_FEATURES */
-- .link_change_notify = qca83xx_link_change_notify,
-- .probe = at803x_probe,
-- .flags = PHY_IS_INTERNAL,
-- .config_init = qca8327_config_init,
-- .soft_reset = genphy_soft_reset,
-- .get_sset_count = qca83xx_get_sset_count,
-- .get_strings = qca83xx_get_strings,
-- .get_stats = qca83xx_get_stats,
-- .suspend = qca8327_suspend,
-- .resume = qca83xx_resume,
--}, {
-- /* QCA8327-B from switch QCA8327-BL1A */
-- .phy_id = QCA8327_B_PHY_ID,
-- .phy_id_mask = QCA8K_PHY_ID_MASK,
-- .name = "Qualcomm Atheros 8327-B internal PHY",
-- /* PHY_GBIT_FEATURES */
-- .link_change_notify = qca83xx_link_change_notify,
-- .probe = at803x_probe,
-- .flags = PHY_IS_INTERNAL,
-- .config_init = qca8327_config_init,
-- .soft_reset = genphy_soft_reset,
-- .get_sset_count = qca83xx_get_sset_count,
-- .get_strings = qca83xx_get_strings,
-- .get_stats = qca83xx_get_stats,
-- .suspend = qca8327_suspend,
-- .resume = qca83xx_resume,
--}, {
-- /* Qualcomm QCA8081 */
-- PHY_ID_MATCH_EXACT(QCA8081_PHY_ID),
-- .name = "Qualcomm QCA8081",
-- .flags = PHY_POLL_CABLE_TEST,
-- .probe = at803x_probe,
-- .config_intr = at803x_config_intr,
-- .handle_interrupt = at803x_handle_interrupt,
-- .get_tunable = at803x_get_tunable,
-- .set_tunable = at803x_set_tunable,
-- .set_wol = at803x_set_wol,
-- .get_wol = at803x_get_wol,
-- .get_features = qca808x_get_features,
-- .config_aneg = qca808x_config_aneg,
-- .suspend = genphy_suspend,
-- .resume = genphy_resume,
-- .read_status = qca808x_read_status,
-- .config_init = qca808x_config_init,
-- .soft_reset = qca808x_soft_reset,
-- .cable_test_start = qca808x_cable_test_start,
-- .cable_test_get_status = qca808x_cable_test_get_status,
-- .link_change_notify = qca808x_link_change_notify,
-- .led_brightness_set = qca808x_led_brightness_set,
-- .led_blink_set = qca808x_led_blink_set,
-- .led_hw_is_supported = qca808x_led_hw_is_supported,
-- .led_hw_control_set = qca808x_led_hw_control_set,
-- .led_hw_control_get = qca808x_led_hw_control_get,
-- .led_polarity_set = qca808x_led_polarity_set,
--}, };
--
--module_phy_driver(at803x_driver);
--
--static struct mdio_device_id __maybe_unused atheros_tbl[] = {
-- { ATH8030_PHY_ID, AT8030_PHY_ID_MASK },
-- { PHY_ID_MATCH_EXACT(ATH8031_PHY_ID) },
-- { PHY_ID_MATCH_EXACT(ATH8032_PHY_ID) },
-- { PHY_ID_MATCH_EXACT(ATH8035_PHY_ID) },
-- { PHY_ID_MATCH_EXACT(ATH9331_PHY_ID) },
-- { PHY_ID_MATCH_EXACT(QCA8337_PHY_ID) },
-- { PHY_ID_MATCH_EXACT(QCA8327_A_PHY_ID) },
-- { PHY_ID_MATCH_EXACT(QCA8327_B_PHY_ID) },
-- { PHY_ID_MATCH_EXACT(QCA9561_PHY_ID) },
-- { PHY_ID_MATCH_EXACT(QCA8081_PHY_ID) },
-- { }
--};
--
--MODULE_DEVICE_TABLE(mdio, atheros_tbl);
---- /dev/null
-+++ b/drivers/net/phy/qcom/at803x.c
-@@ -0,0 +1,2759 @@
-+// SPDX-License-Identifier: GPL-2.0+
-+/*
-+ * drivers/net/phy/at803x.c
-+ *
-+ * Driver for Qualcomm Atheros AR803x PHY
-+ *
-+ */
-+
-+#include <linux/phy.h>
-+#include <linux/module.h>
-+#include <linux/string.h>
-+#include <linux/netdevice.h>
-+#include <linux/etherdevice.h>
-+#include <linux/ethtool_netlink.h>
-+#include <linux/bitfield.h>
-+#include <linux/regulator/of_regulator.h>
-+#include <linux/regulator/driver.h>
-+#include <linux/regulator/consumer.h>
-+#include <linux/of.h>
-+#include <linux/phylink.h>
-+#include <linux/sfp.h>
-+#include <dt-bindings/net/qca-ar803x.h>
-+
-+#define AT803X_SPECIFIC_FUNCTION_CONTROL 0x10
-+#define AT803X_SFC_ASSERT_CRS BIT(11)
-+#define AT803X_SFC_FORCE_LINK BIT(10)
-+#define AT803X_SFC_MDI_CROSSOVER_MODE_M GENMASK(6, 5)
-+#define AT803X_SFC_AUTOMATIC_CROSSOVER 0x3
-+#define AT803X_SFC_MANUAL_MDIX 0x1
-+#define AT803X_SFC_MANUAL_MDI 0x0
-+#define AT803X_SFC_SQE_TEST BIT(2)
-+#define AT803X_SFC_POLARITY_REVERSAL BIT(1)
-+#define AT803X_SFC_DISABLE_JABBER BIT(0)
-+
-+#define AT803X_SPECIFIC_STATUS 0x11
-+#define AT803X_SS_SPEED_MASK GENMASK(15, 14)
-+#define AT803X_SS_SPEED_1000 2
-+#define AT803X_SS_SPEED_100 1
-+#define AT803X_SS_SPEED_10 0
-+#define AT803X_SS_DUPLEX BIT(13)
-+#define AT803X_SS_SPEED_DUPLEX_RESOLVED BIT(11)
-+#define AT803X_SS_MDIX BIT(6)
-+
-+#define QCA808X_SS_SPEED_MASK GENMASK(9, 7)
-+#define QCA808X_SS_SPEED_2500 4
-+
-+#define AT803X_INTR_ENABLE 0x12
-+#define AT803X_INTR_ENABLE_AUTONEG_ERR BIT(15)
-+#define AT803X_INTR_ENABLE_SPEED_CHANGED BIT(14)
-+#define AT803X_INTR_ENABLE_DUPLEX_CHANGED BIT(13)
-+#define AT803X_INTR_ENABLE_PAGE_RECEIVED BIT(12)
-+#define AT803X_INTR_ENABLE_LINK_FAIL BIT(11)
-+#define AT803X_INTR_ENABLE_LINK_SUCCESS BIT(10)
-+#define AT803X_INTR_ENABLE_LINK_FAIL_BX BIT(8)
-+#define AT803X_INTR_ENABLE_LINK_SUCCESS_BX BIT(7)
-+#define AT803X_INTR_ENABLE_WIRESPEED_DOWNGRADE BIT(5)
-+#define AT803X_INTR_ENABLE_POLARITY_CHANGED BIT(1)
-+#define AT803X_INTR_ENABLE_WOL BIT(0)
-+
-+#define AT803X_INTR_STATUS 0x13
-+
-+#define AT803X_SMART_SPEED 0x14
-+#define AT803X_SMART_SPEED_ENABLE BIT(5)
-+#define AT803X_SMART_SPEED_RETRY_LIMIT_MASK GENMASK(4, 2)
-+#define AT803X_SMART_SPEED_BYPASS_TIMER BIT(1)
-+#define AT803X_CDT 0x16
-+#define AT803X_CDT_MDI_PAIR_MASK GENMASK(9, 8)
-+#define AT803X_CDT_ENABLE_TEST BIT(0)
-+#define AT803X_CDT_STATUS 0x1c
-+#define AT803X_CDT_STATUS_STAT_NORMAL 0
-+#define AT803X_CDT_STATUS_STAT_SHORT 1
-+#define AT803X_CDT_STATUS_STAT_OPEN 2
-+#define AT803X_CDT_STATUS_STAT_FAIL 3
-+#define AT803X_CDT_STATUS_STAT_MASK GENMASK(9, 8)
-+#define AT803X_CDT_STATUS_DELTA_TIME_MASK GENMASK(7, 0)
-+#define AT803X_LED_CONTROL 0x18
-+
-+#define AT803X_PHY_MMD3_WOL_CTRL 0x8012
-+#define AT803X_WOL_EN BIT(5)
-+#define AT803X_LOC_MAC_ADDR_0_15_OFFSET 0x804C
-+#define AT803X_LOC_MAC_ADDR_16_31_OFFSET 0x804B
-+#define AT803X_LOC_MAC_ADDR_32_47_OFFSET 0x804A
-+#define AT803X_REG_CHIP_CONFIG 0x1f
-+#define AT803X_BT_BX_REG_SEL 0x8000
-+
-+#define AT803X_DEBUG_ADDR 0x1D
-+#define AT803X_DEBUG_DATA 0x1E
-+
-+#define AT803X_MODE_CFG_MASK 0x0F
-+#define AT803X_MODE_CFG_BASET_RGMII 0x00
-+#define AT803X_MODE_CFG_BASET_SGMII 0x01
-+#define AT803X_MODE_CFG_BX1000_RGMII_50OHM 0x02
-+#define AT803X_MODE_CFG_BX1000_RGMII_75OHM 0x03
-+#define AT803X_MODE_CFG_BX1000_CONV_50OHM 0x04
-+#define AT803X_MODE_CFG_BX1000_CONV_75OHM 0x05
-+#define AT803X_MODE_CFG_FX100_RGMII_50OHM 0x06
-+#define AT803X_MODE_CFG_FX100_CONV_50OHM 0x07
-+#define AT803X_MODE_CFG_RGMII_AUTO_MDET 0x0B
-+#define AT803X_MODE_CFG_FX100_RGMII_75OHM 0x0E
-+#define AT803X_MODE_CFG_FX100_CONV_75OHM 0x0F
-+
-+#define AT803X_PSSR 0x11 /*PHY-Specific Status Register*/
-+#define AT803X_PSSR_MR_AN_COMPLETE 0x0200
-+
-+#define AT803X_DEBUG_ANALOG_TEST_CTRL 0x00
-+#define QCA8327_DEBUG_MANU_CTRL_EN BIT(2)
-+#define QCA8337_DEBUG_MANU_CTRL_EN GENMASK(3, 2)
-+#define AT803X_DEBUG_RX_CLK_DLY_EN BIT(15)
-+
-+#define AT803X_DEBUG_SYSTEM_CTRL_MODE 0x05
-+#define AT803X_DEBUG_TX_CLK_DLY_EN BIT(8)
-+
-+#define AT803X_DEBUG_REG_HIB_CTRL 0x0b
-+#define AT803X_DEBUG_HIB_CTRL_SEL_RST_80U BIT(10)
-+#define AT803X_DEBUG_HIB_CTRL_EN_ANY_CHANGE BIT(13)
-+#define AT803X_DEBUG_HIB_CTRL_PS_HIB_EN BIT(15)
-+
-+#define AT803X_DEBUG_REG_3C 0x3C
-+
-+#define AT803X_DEBUG_REG_GREEN 0x3D
-+#define AT803X_DEBUG_GATE_CLK_IN1000 BIT(6)
-+
-+#define AT803X_DEBUG_REG_1F 0x1F
-+#define AT803X_DEBUG_PLL_ON BIT(2)
-+#define AT803X_DEBUG_RGMII_1V8 BIT(3)
-+
-+#define MDIO_AZ_DEBUG 0x800D
-+
-+/* AT803x supports either the XTAL input pad, an internal PLL or the
-+ * DSP as clock reference for the clock output pad. The XTAL reference
-+ * is only used for 25 MHz output, all other frequencies need the PLL.
-+ * The DSP as a clock reference is used in synchronous ethernet
-+ * applications.
-+ *
-+ * By default the PLL is only enabled if there is a link. Otherwise
-+ * the PHY will go into low power state and disabled the PLL. You can
-+ * set the PLL_ON bit (see debug register 0x1f) to keep the PLL always
-+ * enabled.
-+ */
-+#define AT803X_MMD7_CLK25M 0x8016
-+#define AT803X_CLK_OUT_MASK GENMASK(4, 2)
-+#define AT803X_CLK_OUT_25MHZ_XTAL 0
-+#define AT803X_CLK_OUT_25MHZ_DSP 1
-+#define AT803X_CLK_OUT_50MHZ_PLL 2
-+#define AT803X_CLK_OUT_50MHZ_DSP 3
-+#define AT803X_CLK_OUT_62_5MHZ_PLL 4
-+#define AT803X_CLK_OUT_62_5MHZ_DSP 5
-+#define AT803X_CLK_OUT_125MHZ_PLL 6
-+#define AT803X_CLK_OUT_125MHZ_DSP 7
-+
-+/* The AR8035 has another mask which is compatible with the AR8031/AR8033 mask
-+ * but doesn't support choosing between XTAL/PLL and DSP.
-+ */
-+#define AT8035_CLK_OUT_MASK GENMASK(4, 3)
-+
-+#define AT803X_CLK_OUT_STRENGTH_MASK GENMASK(8, 7)
-+#define AT803X_CLK_OUT_STRENGTH_FULL 0
-+#define AT803X_CLK_OUT_STRENGTH_HALF 1
-+#define AT803X_CLK_OUT_STRENGTH_QUARTER 2
-+
-+#define AT803X_DEFAULT_DOWNSHIFT 5
-+#define AT803X_MIN_DOWNSHIFT 2
-+#define AT803X_MAX_DOWNSHIFT 9
-+
-+#define AT803X_MMD3_SMARTEEE_CTL1 0x805b
-+#define AT803X_MMD3_SMARTEEE_CTL2 0x805c
-+#define AT803X_MMD3_SMARTEEE_CTL3 0x805d
-+#define AT803X_MMD3_SMARTEEE_CTL3_LPI_EN BIT(8)
-+
-+#define ATH9331_PHY_ID 0x004dd041
-+#define ATH8030_PHY_ID 0x004dd076
-+#define ATH8031_PHY_ID 0x004dd074
-+#define ATH8032_PHY_ID 0x004dd023
-+#define ATH8035_PHY_ID 0x004dd072
-+#define AT8030_PHY_ID_MASK 0xffffffef
-+
-+#define QCA8081_PHY_ID 0x004dd101
-+
-+#define QCA8327_A_PHY_ID 0x004dd033
-+#define QCA8327_B_PHY_ID 0x004dd034
-+#define QCA8337_PHY_ID 0x004dd036
-+#define QCA9561_PHY_ID 0x004dd042
-+#define QCA8K_PHY_ID_MASK 0xffffffff
-+
-+#define QCA8K_DEVFLAGS_REVISION_MASK GENMASK(2, 0)
-+
-+#define AT803X_PAGE_FIBER 0
-+#define AT803X_PAGE_COPPER 1
-+
-+/* don't turn off internal PLL */
-+#define AT803X_KEEP_PLL_ENABLED BIT(0)
-+#define AT803X_DISABLE_SMARTEEE BIT(1)
-+
-+/* disable hibernation mode */
-+#define AT803X_DISABLE_HIBERNATION_MODE BIT(2)
-+
-+/* ADC threshold */
-+#define QCA808X_PHY_DEBUG_ADC_THRESHOLD 0x2c80
-+#define QCA808X_ADC_THRESHOLD_MASK GENMASK(7, 0)
-+#define QCA808X_ADC_THRESHOLD_80MV 0
-+#define QCA808X_ADC_THRESHOLD_100MV 0xf0
-+#define QCA808X_ADC_THRESHOLD_200MV 0x0f
-+#define QCA808X_ADC_THRESHOLD_300MV 0xff
-+
-+/* CLD control */
-+#define QCA808X_PHY_MMD3_ADDR_CLD_CTRL7 0x8007
-+#define QCA808X_8023AZ_AFE_CTRL_MASK GENMASK(8, 4)
-+#define QCA808X_8023AZ_AFE_EN 0x90
-+
-+/* AZ control */
-+#define QCA808X_PHY_MMD3_AZ_TRAINING_CTRL 0x8008
-+#define QCA808X_MMD3_AZ_TRAINING_VAL 0x1c32
-+
-+#define QCA808X_PHY_MMD1_MSE_THRESHOLD_20DB 0x8014
-+#define QCA808X_MSE_THRESHOLD_20DB_VALUE 0x529
-+
-+#define QCA808X_PHY_MMD1_MSE_THRESHOLD_17DB 0x800E
-+#define QCA808X_MSE_THRESHOLD_17DB_VALUE 0x341
-+
-+#define QCA808X_PHY_MMD1_MSE_THRESHOLD_27DB 0x801E
-+#define QCA808X_MSE_THRESHOLD_27DB_VALUE 0x419
-+
-+#define QCA808X_PHY_MMD1_MSE_THRESHOLD_28DB 0x8020
-+#define QCA808X_MSE_THRESHOLD_28DB_VALUE 0x341
-+
-+#define QCA808X_PHY_MMD7_TOP_OPTION1 0x901c
-+#define QCA808X_TOP_OPTION1_DATA 0x0
-+
-+#define QCA808X_PHY_MMD3_DEBUG_1 0xa100
-+#define QCA808X_MMD3_DEBUG_1_VALUE 0x9203
-+#define QCA808X_PHY_MMD3_DEBUG_2 0xa101
-+#define QCA808X_MMD3_DEBUG_2_VALUE 0x48ad
-+#define QCA808X_PHY_MMD3_DEBUG_3 0xa103
-+#define QCA808X_MMD3_DEBUG_3_VALUE 0x1698
-+#define QCA808X_PHY_MMD3_DEBUG_4 0xa105
-+#define QCA808X_MMD3_DEBUG_4_VALUE 0x8001
-+#define QCA808X_PHY_MMD3_DEBUG_5 0xa106
-+#define QCA808X_MMD3_DEBUG_5_VALUE 0x1111
-+#define QCA808X_PHY_MMD3_DEBUG_6 0xa011
-+#define QCA808X_MMD3_DEBUG_6_VALUE 0x5f85
-+
-+/* master/slave seed config */
-+#define QCA808X_PHY_DEBUG_LOCAL_SEED 9
-+#define QCA808X_MASTER_SLAVE_SEED_ENABLE BIT(1)
-+#define QCA808X_MASTER_SLAVE_SEED_CFG GENMASK(12, 2)
-+#define QCA808X_MASTER_SLAVE_SEED_RANGE 0x32
-+
-+/* Hibernation yields lower power consumpiton in contrast with normal operation mode.
-+ * when the copper cable is unplugged, the PHY enters into hibernation mode in about 10s.
-+ */
-+#define QCA808X_DBG_AN_TEST 0xb
-+#define QCA808X_HIBERNATION_EN BIT(15)
-+
-+#define QCA808X_CDT_ENABLE_TEST BIT(15)
-+#define QCA808X_CDT_INTER_CHECK_DIS BIT(13)
-+#define QCA808X_CDT_STATUS BIT(11)
-+#define QCA808X_CDT_LENGTH_UNIT BIT(10)
-+
-+#define QCA808X_MMD3_CDT_STATUS 0x8064
-+#define QCA808X_MMD3_CDT_DIAG_PAIR_A 0x8065
-+#define QCA808X_MMD3_CDT_DIAG_PAIR_B 0x8066
-+#define QCA808X_MMD3_CDT_DIAG_PAIR_C 0x8067
-+#define QCA808X_MMD3_CDT_DIAG_PAIR_D 0x8068
-+#define QCA808X_CDT_DIAG_LENGTH_SAME_SHORT GENMASK(15, 8)
-+#define QCA808X_CDT_DIAG_LENGTH_CROSS_SHORT GENMASK(7, 0)
-+
-+#define QCA808X_CDT_CODE_PAIR_A GENMASK(15, 12)
-+#define QCA808X_CDT_CODE_PAIR_B GENMASK(11, 8)
-+#define QCA808X_CDT_CODE_PAIR_C GENMASK(7, 4)
-+#define QCA808X_CDT_CODE_PAIR_D GENMASK(3, 0)
-+
-+#define QCA808X_CDT_STATUS_STAT_TYPE GENMASK(1, 0)
-+#define QCA808X_CDT_STATUS_STAT_FAIL FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_TYPE, 0)
-+#define QCA808X_CDT_STATUS_STAT_NORMAL FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_TYPE, 1)
-+#define QCA808X_CDT_STATUS_STAT_SAME_OPEN FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_TYPE, 2)
-+#define QCA808X_CDT_STATUS_STAT_SAME_SHORT FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_TYPE, 3)
-+
-+#define QCA808X_CDT_STATUS_STAT_MDI GENMASK(3, 2)
-+#define QCA808X_CDT_STATUS_STAT_MDI1 FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_MDI, 1)
-+#define QCA808X_CDT_STATUS_STAT_MDI2 FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_MDI, 2)
-+#define QCA808X_CDT_STATUS_STAT_MDI3 FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_MDI, 3)
-+
-+/* NORMAL are MDI with type set to 0 */
-+#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_NORMAL QCA808X_CDT_STATUS_STAT_MDI1
-+#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_OPEN (QCA808X_CDT_STATUS_STAT_SAME_OPEN |\
-+ QCA808X_CDT_STATUS_STAT_MDI1)
-+#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_SHORT (QCA808X_CDT_STATUS_STAT_SAME_SHORT |\
-+ QCA808X_CDT_STATUS_STAT_MDI1)
-+#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_NORMAL QCA808X_CDT_STATUS_STAT_MDI2
-+#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_OPEN (QCA808X_CDT_STATUS_STAT_SAME_OPEN |\
-+ QCA808X_CDT_STATUS_STAT_MDI2)
-+#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_SHORT (QCA808X_CDT_STATUS_STAT_SAME_SHORT |\
-+ QCA808X_CDT_STATUS_STAT_MDI2)
-+#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_NORMAL QCA808X_CDT_STATUS_STAT_MDI3
-+#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_OPEN (QCA808X_CDT_STATUS_STAT_SAME_OPEN |\
-+ QCA808X_CDT_STATUS_STAT_MDI3)
-+#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_SHORT (QCA808X_CDT_STATUS_STAT_SAME_SHORT |\
-+ QCA808X_CDT_STATUS_STAT_MDI3)
-+
-+/* Added for reference of existence but should be handled by wait_for_completion already */
-+#define QCA808X_CDT_STATUS_STAT_BUSY (BIT(1) | BIT(3))
-+
-+#define QCA808X_MMD7_LED_GLOBAL 0x8073
-+#define QCA808X_LED_BLINK_1 GENMASK(11, 6)
-+#define QCA808X_LED_BLINK_2 GENMASK(5, 0)
-+/* Values are the same for both BLINK_1 and BLINK_2 */
-+#define QCA808X_LED_BLINK_FREQ_MASK GENMASK(5, 3)
-+#define QCA808X_LED_BLINK_FREQ_2HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x0)
-+#define QCA808X_LED_BLINK_FREQ_4HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x1)
-+#define QCA808X_LED_BLINK_FREQ_8HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x2)
-+#define QCA808X_LED_BLINK_FREQ_16HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x3)
-+#define QCA808X_LED_BLINK_FREQ_32HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x4)
-+#define QCA808X_LED_BLINK_FREQ_64HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x5)
-+#define QCA808X_LED_BLINK_FREQ_128HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x6)
-+#define QCA808X_LED_BLINK_FREQ_256HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x7)
-+#define QCA808X_LED_BLINK_DUTY_MASK GENMASK(2, 0)
-+#define QCA808X_LED_BLINK_DUTY_50_50 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x0)
-+#define QCA808X_LED_BLINK_DUTY_75_25 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x1)
-+#define QCA808X_LED_BLINK_DUTY_25_75 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x2)
-+#define QCA808X_LED_BLINK_DUTY_33_67 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x3)
-+#define QCA808X_LED_BLINK_DUTY_67_33 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x4)
-+#define QCA808X_LED_BLINK_DUTY_17_83 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x5)
-+#define QCA808X_LED_BLINK_DUTY_83_17 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x6)
-+#define QCA808X_LED_BLINK_DUTY_8_92 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x7)
-+
-+#define QCA808X_MMD7_LED2_CTRL 0x8074
-+#define QCA808X_MMD7_LED2_FORCE_CTRL 0x8075
-+#define QCA808X_MMD7_LED1_CTRL 0x8076
-+#define QCA808X_MMD7_LED1_FORCE_CTRL 0x8077
-+#define QCA808X_MMD7_LED0_CTRL 0x8078
-+#define QCA808X_MMD7_LED_CTRL(x) (0x8078 - ((x) * 2))
-+
-+/* LED hw control pattern is the same for every LED */
-+#define QCA808X_LED_PATTERN_MASK GENMASK(15, 0)
-+#define QCA808X_LED_SPEED2500_ON BIT(15)
-+#define QCA808X_LED_SPEED2500_BLINK BIT(14)
-+/* Follow blink trigger even if duplex or speed condition doesn't match */
-+#define QCA808X_LED_BLINK_CHECK_BYPASS BIT(13)
-+#define QCA808X_LED_FULL_DUPLEX_ON BIT(12)
-+#define QCA808X_LED_HALF_DUPLEX_ON BIT(11)
-+#define QCA808X_LED_TX_BLINK BIT(10)
-+#define QCA808X_LED_RX_BLINK BIT(9)
-+#define QCA808X_LED_TX_ON_10MS BIT(8)
-+#define QCA808X_LED_RX_ON_10MS BIT(7)
-+#define QCA808X_LED_SPEED1000_ON BIT(6)
-+#define QCA808X_LED_SPEED100_ON BIT(5)
-+#define QCA808X_LED_SPEED10_ON BIT(4)
-+#define QCA808X_LED_COLLISION_BLINK BIT(3)
-+#define QCA808X_LED_SPEED1000_BLINK BIT(2)
-+#define QCA808X_LED_SPEED100_BLINK BIT(1)
-+#define QCA808X_LED_SPEED10_BLINK BIT(0)
-+
-+#define QCA808X_MMD7_LED0_FORCE_CTRL 0x8079
-+#define QCA808X_MMD7_LED_FORCE_CTRL(x) (0x8079 - ((x) * 2))
-+
-+/* LED force ctrl is the same for every LED
-+ * No documentation exist for this, not even internal one
-+ * with NDA as QCOM gives only info about configuring
-+ * hw control pattern rules and doesn't indicate any way
-+ * to force the LED to specific mode.
-+ * These define comes from reverse and testing and maybe
-+ * lack of some info or some info are not entirely correct.
-+ * For the basic LED control and hw control these finding
-+ * are enough to support LED control in all the required APIs.
-+ *
-+ * On doing some comparison with implementation with qca807x,
-+ * it was found that it's 1:1 equal to it and confirms all the
-+ * reverse done. It was also found further specification with the
-+ * force mode and the blink modes.
-+ */
-+#define QCA808X_LED_FORCE_EN BIT(15)
-+#define QCA808X_LED_FORCE_MODE_MASK GENMASK(14, 13)
-+#define QCA808X_LED_FORCE_BLINK_1 FIELD_PREP(QCA808X_LED_FORCE_MODE_MASK, 0x3)
-+#define QCA808X_LED_FORCE_BLINK_2 FIELD_PREP(QCA808X_LED_FORCE_MODE_MASK, 0x2)
-+#define QCA808X_LED_FORCE_ON FIELD_PREP(QCA808X_LED_FORCE_MODE_MASK, 0x1)
-+#define QCA808X_LED_FORCE_OFF FIELD_PREP(QCA808X_LED_FORCE_MODE_MASK, 0x0)
-+
-+#define QCA808X_MMD7_LED_POLARITY_CTRL 0x901a
-+/* QSDK sets by default 0x46 to this reg that sets BIT 6 for
-+ * LED to active high. It's not clear what BIT 3 and BIT 4 does.
-+ */
-+#define QCA808X_LED_ACTIVE_HIGH BIT(6)
-+
-+/* QCA808X 1G chip type */
-+#define QCA808X_PHY_MMD7_CHIP_TYPE 0x901d
-+#define QCA808X_PHY_CHIP_TYPE_1G BIT(0)
-+
-+#define QCA8081_PHY_SERDES_MMD1_FIFO_CTRL 0x9072
-+#define QCA8081_PHY_FIFO_RSTN BIT(11)
-+
-+MODULE_DESCRIPTION("Qualcomm Atheros AR803x and QCA808X PHY driver");
-+MODULE_AUTHOR("Matus Ujhelyi");
-+MODULE_LICENSE("GPL");
-+
-+enum stat_access_type {
-+ PHY,
-+ MMD
-+};
-+
-+struct at803x_hw_stat {
-+ const char *string;
-+ u8 reg;
-+ u32 mask;
-+ enum stat_access_type access_type;
-+};
-+
-+static struct at803x_hw_stat qca83xx_hw_stats[] = {
-+ { "phy_idle_errors", 0xa, GENMASK(7, 0), PHY},
-+ { "phy_receive_errors", 0x15, GENMASK(15, 0), PHY},
-+ { "eee_wake_errors", 0x16, GENMASK(15, 0), MMD},
-+};
-+
-+struct at803x_ss_mask {
-+ u16 speed_mask;
-+ u8 speed_shift;
-+};
-+
-+struct at803x_priv {
-+ int flags;
-+ u16 clk_25m_reg;
-+ u16 clk_25m_mask;
-+ u8 smarteee_lpi_tw_1g;
-+ u8 smarteee_lpi_tw_100m;
-+ bool is_fiber;
-+ bool is_1000basex;
-+ struct regulator_dev *vddio_rdev;
-+ struct regulator_dev *vddh_rdev;
-+ u64 stats[ARRAY_SIZE(qca83xx_hw_stats)];
-+ int led_polarity_mode;
-+};
-+
-+struct at803x_context {
-+ u16 bmcr;
-+ u16 advertise;
-+ u16 control1000;
-+ u16 int_enable;
-+ u16 smart_speed;
-+ u16 led_control;
-+};
-+
-+static int at803x_debug_reg_write(struct phy_device *phydev, u16 reg, u16 data)
-+{
-+ int ret;
-+
-+ ret = phy_write(phydev, AT803X_DEBUG_ADDR, reg);
-+ if (ret < 0)
-+ return ret;
-+
-+ return phy_write(phydev, AT803X_DEBUG_DATA, data);
-+}
-+
-+static int at803x_debug_reg_read(struct phy_device *phydev, u16 reg)
-+{
-+ int ret;
-+
-+ ret = phy_write(phydev, AT803X_DEBUG_ADDR, reg);
-+ if (ret < 0)
-+ return ret;
-+
-+ return phy_read(phydev, AT803X_DEBUG_DATA);
-+}
-+
-+static int at803x_debug_reg_mask(struct phy_device *phydev, u16 reg,
-+ u16 clear, u16 set)
-+{
-+ u16 val;
-+ int ret;
-+
-+ ret = at803x_debug_reg_read(phydev, reg);
-+ if (ret < 0)
-+ return ret;
-+
-+ val = ret & 0xffff;
-+ val &= ~clear;
-+ val |= set;
-+
-+ return phy_write(phydev, AT803X_DEBUG_DATA, val);
-+}
-+
-+static int at803x_write_page(struct phy_device *phydev, int page)
-+{
-+ int mask;
-+ int set;
-+
-+ if (page == AT803X_PAGE_COPPER) {
-+ set = AT803X_BT_BX_REG_SEL;
-+ mask = 0;
-+ } else {
-+ set = 0;
-+ mask = AT803X_BT_BX_REG_SEL;
-+ }
-+
-+ return __phy_modify(phydev, AT803X_REG_CHIP_CONFIG, mask, set);
-+}
-+
-+static int at803x_read_page(struct phy_device *phydev)
-+{
-+ int ccr = __phy_read(phydev, AT803X_REG_CHIP_CONFIG);
-+
-+ if (ccr < 0)
-+ return ccr;
-+
-+ if (ccr & AT803X_BT_BX_REG_SEL)
-+ return AT803X_PAGE_COPPER;
-+
-+ return AT803X_PAGE_FIBER;
-+}
-+
-+static int at803x_enable_rx_delay(struct phy_device *phydev)
-+{
-+ return at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL, 0,
-+ AT803X_DEBUG_RX_CLK_DLY_EN);
-+}
-+
-+static int at803x_enable_tx_delay(struct phy_device *phydev)
-+{
-+ return at803x_debug_reg_mask(phydev, AT803X_DEBUG_SYSTEM_CTRL_MODE, 0,
-+ AT803X_DEBUG_TX_CLK_DLY_EN);
-+}
-+
-+static int at803x_disable_rx_delay(struct phy_device *phydev)
-+{
-+ return at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL,
-+ AT803X_DEBUG_RX_CLK_DLY_EN, 0);
-+}
-+
-+static int at803x_disable_tx_delay(struct phy_device *phydev)
-+{
-+ return at803x_debug_reg_mask(phydev, AT803X_DEBUG_SYSTEM_CTRL_MODE,
-+ AT803X_DEBUG_TX_CLK_DLY_EN, 0);
-+}
-+
-+/* save relevant PHY registers to private copy */
-+static void at803x_context_save(struct phy_device *phydev,
-+ struct at803x_context *context)
-+{
-+ context->bmcr = phy_read(phydev, MII_BMCR);
-+ context->advertise = phy_read(phydev, MII_ADVERTISE);
-+ context->control1000 = phy_read(phydev, MII_CTRL1000);
-+ context->int_enable = phy_read(phydev, AT803X_INTR_ENABLE);
-+ context->smart_speed = phy_read(phydev, AT803X_SMART_SPEED);
-+ context->led_control = phy_read(phydev, AT803X_LED_CONTROL);
-+}
-+
-+/* restore relevant PHY registers from private copy */
-+static void at803x_context_restore(struct phy_device *phydev,
-+ const struct at803x_context *context)
-+{
-+ phy_write(phydev, MII_BMCR, context->bmcr);
-+ phy_write(phydev, MII_ADVERTISE, context->advertise);
-+ phy_write(phydev, MII_CTRL1000, context->control1000);
-+ phy_write(phydev, AT803X_INTR_ENABLE, context->int_enable);
-+ phy_write(phydev, AT803X_SMART_SPEED, context->smart_speed);
-+ phy_write(phydev, AT803X_LED_CONTROL, context->led_control);
-+}
-+
-+static int at803x_set_wol(struct phy_device *phydev,
-+ struct ethtool_wolinfo *wol)
-+{
-+ int ret, irq_enabled;
-+
-+ if (wol->wolopts & WAKE_MAGIC) {
-+ struct net_device *ndev = phydev->attached_dev;
-+ const u8 *mac;
-+ unsigned int i;
-+ static const unsigned int offsets[] = {
-+ AT803X_LOC_MAC_ADDR_32_47_OFFSET,
-+ AT803X_LOC_MAC_ADDR_16_31_OFFSET,
-+ AT803X_LOC_MAC_ADDR_0_15_OFFSET,
-+ };
-+
-+ if (!ndev)
-+ return -ENODEV;
-+
-+ mac = (const u8 *)ndev->dev_addr;
-+
-+ if (!is_valid_ether_addr(mac))
-+ return -EINVAL;
-+
-+ for (i = 0; i < 3; i++)
-+ phy_write_mmd(phydev, MDIO_MMD_PCS, offsets[i],
-+ mac[(i * 2) + 1] | (mac[(i * 2)] << 8));
-+
-+ /* Enable WOL interrupt */
-+ ret = phy_modify(phydev, AT803X_INTR_ENABLE, 0, AT803X_INTR_ENABLE_WOL);
-+ if (ret)
-+ return ret;
-+ } else {
-+ /* Disable WOL interrupt */
-+ ret = phy_modify(phydev, AT803X_INTR_ENABLE, AT803X_INTR_ENABLE_WOL, 0);
-+ if (ret)
-+ return ret;
-+ }
-+
-+ /* Clear WOL status */
-+ ret = phy_read(phydev, AT803X_INTR_STATUS);
-+ if (ret < 0)
-+ return ret;
-+
-+ /* Check if there are other interrupts except for WOL triggered when PHY is
-+ * in interrupt mode, only the interrupts enabled by AT803X_INTR_ENABLE can
-+ * be passed up to the interrupt PIN.
-+ */
-+ irq_enabled = phy_read(phydev, AT803X_INTR_ENABLE);
-+ if (irq_enabled < 0)
-+ return irq_enabled;
-+
-+ irq_enabled &= ~AT803X_INTR_ENABLE_WOL;
-+ if (ret & irq_enabled && !phy_polling_mode(phydev))
-+ phy_trigger_machine(phydev);
-+
-+ return 0;
-+}
-+
-+static void at803x_get_wol(struct phy_device *phydev,
-+ struct ethtool_wolinfo *wol)
-+{
-+ int value;
-+
-+ wol->supported = WAKE_MAGIC;
-+ wol->wolopts = 0;
-+
-+ value = phy_read(phydev, AT803X_INTR_ENABLE);
-+ if (value < 0)
-+ return;
-+
-+ if (value & AT803X_INTR_ENABLE_WOL)
-+ wol->wolopts |= WAKE_MAGIC;
-+}
-+
-+static int qca83xx_get_sset_count(struct phy_device *phydev)
-+{
-+ return ARRAY_SIZE(qca83xx_hw_stats);
-+}
-+
-+static void qca83xx_get_strings(struct phy_device *phydev, u8 *data)
-+{
-+ int i;
-+
-+ for (i = 0; i < ARRAY_SIZE(qca83xx_hw_stats); i++) {
-+ strscpy(data + i * ETH_GSTRING_LEN,
-+ qca83xx_hw_stats[i].string, ETH_GSTRING_LEN);
-+ }
-+}
-+
-+static u64 qca83xx_get_stat(struct phy_device *phydev, int i)
-+{
-+ struct at803x_hw_stat stat = qca83xx_hw_stats[i];
-+ struct at803x_priv *priv = phydev->priv;
-+ int val;
-+ u64 ret;
-+
-+ if (stat.access_type == MMD)
-+ val = phy_read_mmd(phydev, MDIO_MMD_PCS, stat.reg);
-+ else
-+ val = phy_read(phydev, stat.reg);
-+
-+ if (val < 0) {
-+ ret = U64_MAX;
-+ } else {
-+ val = val & stat.mask;
-+ priv->stats[i] += val;
-+ ret = priv->stats[i];
-+ }
-+
-+ return ret;
-+}
-+
-+static void qca83xx_get_stats(struct phy_device *phydev,
-+ struct ethtool_stats *stats, u64 *data)
-+{
-+ int i;
-+
-+ for (i = 0; i < ARRAY_SIZE(qca83xx_hw_stats); i++)
-+ data[i] = qca83xx_get_stat(phydev, i);
-+}
-+
-+static int at803x_suspend(struct phy_device *phydev)
-+{
-+ int value;
-+ int wol_enabled;
-+
-+ value = phy_read(phydev, AT803X_INTR_ENABLE);
-+ wol_enabled = value & AT803X_INTR_ENABLE_WOL;
-+
-+ if (wol_enabled)
-+ value = BMCR_ISOLATE;
-+ else
-+ value = BMCR_PDOWN;
-+
-+ phy_modify(phydev, MII_BMCR, 0, value);
-+
-+ return 0;
-+}
-+
-+static int at803x_resume(struct phy_device *phydev)
-+{
-+ return phy_modify(phydev, MII_BMCR, BMCR_PDOWN | BMCR_ISOLATE, 0);
-+}
-+
-+static int at803x_parse_dt(struct phy_device *phydev)
-+{
-+ struct device_node *node = phydev->mdio.dev.of_node;
-+ struct at803x_priv *priv = phydev->priv;
-+ u32 freq, strength, tw;
-+ unsigned int sel;
-+ int ret;
-+
-+ if (!IS_ENABLED(CONFIG_OF_MDIO))
-+ return 0;
-+
-+ if (of_property_read_bool(node, "qca,disable-smarteee"))
-+ priv->flags |= AT803X_DISABLE_SMARTEEE;
-+
-+ if (of_property_read_bool(node, "qca,disable-hibernation-mode"))
-+ priv->flags |= AT803X_DISABLE_HIBERNATION_MODE;
-+
-+ if (!of_property_read_u32(node, "qca,smarteee-tw-us-1g", &tw)) {
-+ if (!tw || tw > 255) {
-+ phydev_err(phydev, "invalid qca,smarteee-tw-us-1g\n");
-+ return -EINVAL;
-+ }
-+ priv->smarteee_lpi_tw_1g = tw;
-+ }
-+
-+ if (!of_property_read_u32(node, "qca,smarteee-tw-us-100m", &tw)) {
-+ if (!tw || tw > 255) {
-+ phydev_err(phydev, "invalid qca,smarteee-tw-us-100m\n");
-+ return -EINVAL;
-+ }
-+ priv->smarteee_lpi_tw_100m = tw;
-+ }
-+
-+ ret = of_property_read_u32(node, "qca,clk-out-frequency", &freq);
-+ if (!ret) {
-+ switch (freq) {
-+ case 25000000:
-+ sel = AT803X_CLK_OUT_25MHZ_XTAL;
-+ break;
-+ case 50000000:
-+ sel = AT803X_CLK_OUT_50MHZ_PLL;
-+ break;
-+ case 62500000:
-+ sel = AT803X_CLK_OUT_62_5MHZ_PLL;
-+ break;
-+ case 125000000:
-+ sel = AT803X_CLK_OUT_125MHZ_PLL;
-+ break;
-+ default:
-+ phydev_err(phydev, "invalid qca,clk-out-frequency\n");
-+ return -EINVAL;
-+ }
-+
-+ priv->clk_25m_reg |= FIELD_PREP(AT803X_CLK_OUT_MASK, sel);
-+ priv->clk_25m_mask |= AT803X_CLK_OUT_MASK;
-+ }
-+
-+ ret = of_property_read_u32(node, "qca,clk-out-strength", &strength);
-+ if (!ret) {
-+ priv->clk_25m_mask |= AT803X_CLK_OUT_STRENGTH_MASK;
-+ switch (strength) {
-+ case AR803X_STRENGTH_FULL:
-+ priv->clk_25m_reg |= AT803X_CLK_OUT_STRENGTH_FULL;
-+ break;
-+ case AR803X_STRENGTH_HALF:
-+ priv->clk_25m_reg |= AT803X_CLK_OUT_STRENGTH_HALF;
-+ break;
-+ case AR803X_STRENGTH_QUARTER:
-+ priv->clk_25m_reg |= AT803X_CLK_OUT_STRENGTH_QUARTER;
-+ break;
-+ default:
-+ phydev_err(phydev, "invalid qca,clk-out-strength\n");
-+ return -EINVAL;
-+ }
-+ }
-+
-+ return 0;
-+}
-+
-+static int at803x_probe(struct phy_device *phydev)
-+{
-+ struct device *dev = &phydev->mdio.dev;
-+ struct at803x_priv *priv;
-+ int ret;
-+
-+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
-+ if (!priv)
-+ return -ENOMEM;
-+
-+ /* Init LED polarity mode to -1 */
-+ priv->led_polarity_mode = -1;
-+
-+ phydev->priv = priv;
-+
-+ ret = at803x_parse_dt(phydev);
-+ if (ret)
-+ return ret;
-+
-+ return 0;
-+}
-+
-+static int at803x_get_features(struct phy_device *phydev)
-+{
-+ struct at803x_priv *priv = phydev->priv;
-+ int err;
-+
-+ err = genphy_read_abilities(phydev);
-+ if (err)
-+ return err;
-+
-+ if (phydev->drv->phy_id != ATH8031_PHY_ID)
-+ return 0;
-+
-+ /* AR8031/AR8033 have different status registers
-+ * for copper and fiber operation. However, the
-+ * extended status register is the same for both
-+ * operation modes.
-+ *
-+ * As a result of that, ESTATUS_1000_XFULL is set
-+ * to 1 even when operating in copper TP mode.
-+ *
-+ * Remove this mode from the supported link modes
-+ * when not operating in 1000BaseX mode.
-+ */
-+ if (!priv->is_1000basex)
-+ linkmode_clear_bit(ETHTOOL_LINK_MODE_1000baseX_Full_BIT,
-+ phydev->supported);
-+
-+ return 0;
-+}
-+
-+static int at803x_smarteee_config(struct phy_device *phydev)
-+{
-+ struct at803x_priv *priv = phydev->priv;
-+ u16 mask = 0, val = 0;
-+ int ret;
-+
-+ if (priv->flags & AT803X_DISABLE_SMARTEEE)
-+ return phy_modify_mmd(phydev, MDIO_MMD_PCS,
-+ AT803X_MMD3_SMARTEEE_CTL3,
-+ AT803X_MMD3_SMARTEEE_CTL3_LPI_EN, 0);
-+
-+ if (priv->smarteee_lpi_tw_1g) {
-+ mask |= 0xff00;
-+ val |= priv->smarteee_lpi_tw_1g << 8;
-+ }
-+ if (priv->smarteee_lpi_tw_100m) {
-+ mask |= 0x00ff;
-+ val |= priv->smarteee_lpi_tw_100m;
-+ }
-+ if (!mask)
-+ return 0;
-+
-+ ret = phy_modify_mmd(phydev, MDIO_MMD_PCS, AT803X_MMD3_SMARTEEE_CTL1,
-+ mask, val);
-+ if (ret)
-+ return ret;
-+
-+ return phy_modify_mmd(phydev, MDIO_MMD_PCS, AT803X_MMD3_SMARTEEE_CTL3,
-+ AT803X_MMD3_SMARTEEE_CTL3_LPI_EN,
-+ AT803X_MMD3_SMARTEEE_CTL3_LPI_EN);
-+}
-+
-+static int at803x_clk_out_config(struct phy_device *phydev)
-+{
-+ struct at803x_priv *priv = phydev->priv;
-+
-+ if (!priv->clk_25m_mask)
-+ return 0;
-+
-+ return phy_modify_mmd(phydev, MDIO_MMD_AN, AT803X_MMD7_CLK25M,
-+ priv->clk_25m_mask, priv->clk_25m_reg);
-+}
-+
-+static int at8031_pll_config(struct phy_device *phydev)
-+{
-+ struct at803x_priv *priv = phydev->priv;
-+
-+ /* The default after hardware reset is PLL OFF. After a soft reset, the
-+ * values are retained.
-+ */
-+ if (priv->flags & AT803X_KEEP_PLL_ENABLED)
-+ return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_1F,
-+ 0, AT803X_DEBUG_PLL_ON);
-+ else
-+ return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_1F,
-+ AT803X_DEBUG_PLL_ON, 0);
-+}
-+
-+static int at803x_hibernation_mode_config(struct phy_device *phydev)
-+{
-+ struct at803x_priv *priv = phydev->priv;
-+
-+ /* The default after hardware reset is hibernation mode enabled. After
-+ * software reset, the value is retained.
-+ */
-+ if (!(priv->flags & AT803X_DISABLE_HIBERNATION_MODE))
-+ return 0;
-+
-+ return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_HIB_CTRL,
-+ AT803X_DEBUG_HIB_CTRL_PS_HIB_EN, 0);
-+}
-+
-+static int at803x_config_init(struct phy_device *phydev)
-+{
-+ int ret;
-+
-+ /* The RX and TX delay default is:
-+ * after HW reset: RX delay enabled and TX delay disabled
-+ * after SW reset: RX delay enabled, while TX delay retains the
-+ * value before reset.
-+ */
-+ if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
-+ phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID)
-+ ret = at803x_enable_rx_delay(phydev);
-+ else
-+ ret = at803x_disable_rx_delay(phydev);
-+ if (ret < 0)
-+ return ret;
-+
-+ if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
-+ phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)
-+ ret = at803x_enable_tx_delay(phydev);
-+ else
-+ ret = at803x_disable_tx_delay(phydev);
-+ if (ret < 0)
-+ return ret;
-+
-+ ret = at803x_smarteee_config(phydev);
-+ if (ret < 0)
-+ return ret;
-+
-+ ret = at803x_clk_out_config(phydev);
-+ if (ret < 0)
-+ return ret;
-+
-+ ret = at803x_hibernation_mode_config(phydev);
-+ if (ret < 0)
-+ return ret;
-+
-+ /* Ar803x extended next page bit is enabled by default. Cisco
-+ * multigig switches read this bit and attempt to negotiate 10Gbps
-+ * rates even if the next page bit is disabled. This is incorrect
-+ * behaviour but we still need to accommodate it. XNP is only needed
-+ * for 10Gbps support, so disable XNP.
-+ */
-+ return phy_modify(phydev, MII_ADVERTISE, MDIO_AN_CTRL1_XNP, 0);
-+}
-+
-+static int at803x_ack_interrupt(struct phy_device *phydev)
-+{
-+ int err;
-+
-+ err = phy_read(phydev, AT803X_INTR_STATUS);
-+
-+ return (err < 0) ? err : 0;
-+}
-+
-+static int at803x_config_intr(struct phy_device *phydev)
-+{
-+ int err;
-+ int value;
-+
-+ value = phy_read(phydev, AT803X_INTR_ENABLE);
-+
-+ if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
-+ /* Clear any pending interrupts */
-+ err = at803x_ack_interrupt(phydev);
-+ if (err)
-+ return err;
-+
-+ value |= AT803X_INTR_ENABLE_AUTONEG_ERR;
-+ value |= AT803X_INTR_ENABLE_SPEED_CHANGED;
-+ value |= AT803X_INTR_ENABLE_DUPLEX_CHANGED;
-+ value |= AT803X_INTR_ENABLE_LINK_FAIL;
-+ value |= AT803X_INTR_ENABLE_LINK_SUCCESS;
-+
-+ err = phy_write(phydev, AT803X_INTR_ENABLE, value);
-+ } else {
-+ err = phy_write(phydev, AT803X_INTR_ENABLE, 0);
-+ if (err)
-+ return err;
-+
-+ /* Clear any pending interrupts */
-+ err = at803x_ack_interrupt(phydev);
-+ }
-+
-+ return err;
-+}
-+
-+static irqreturn_t at803x_handle_interrupt(struct phy_device *phydev)
-+{
-+ int irq_status, int_enabled;
-+
-+ irq_status = phy_read(phydev, AT803X_INTR_STATUS);
-+ if (irq_status < 0) {
-+ phy_error(phydev);
-+ return IRQ_NONE;
-+ }
-+
-+ /* Read the current enabled interrupts */
-+ int_enabled = phy_read(phydev, AT803X_INTR_ENABLE);
-+ if (int_enabled < 0) {
-+ phy_error(phydev);
-+ return IRQ_NONE;
-+ }
-+
-+ /* See if this was one of our enabled interrupts */
-+ if (!(irq_status & int_enabled))
-+ return IRQ_NONE;
-+
-+ phy_trigger_machine(phydev);
-+
-+ return IRQ_HANDLED;
-+}
-+
-+static void at803x_link_change_notify(struct phy_device *phydev)
-+{
-+ /*
-+ * Conduct a hardware reset for AT8030 every time a link loss is
-+ * signalled. This is necessary to circumvent a hardware bug that
-+ * occurs when the cable is unplugged while TX packets are pending
-+ * in the FIFO. In such cases, the FIFO enters an error mode it
-+ * cannot recover from by software.
-+ */
-+ if (phydev->state == PHY_NOLINK && phydev->mdio.reset_gpio) {
-+ struct at803x_context context;
-+
-+ at803x_context_save(phydev, &context);
-+
-+ phy_device_reset(phydev, 1);
-+ usleep_range(1000, 2000);
-+ phy_device_reset(phydev, 0);
-+ usleep_range(1000, 2000);
-+
-+ at803x_context_restore(phydev, &context);
-+
-+ phydev_dbg(phydev, "%s(): phy was reset\n", __func__);
-+ }
-+}
-+
-+static int at803x_read_specific_status(struct phy_device *phydev,
-+ struct at803x_ss_mask ss_mask)
-+{
-+ int ss;
-+
-+ /* Read the AT8035 PHY-Specific Status register, which indicates the
-+ * speed and duplex that the PHY is actually using, irrespective of
-+ * whether we are in autoneg mode or not.
-+ */
-+ ss = phy_read(phydev, AT803X_SPECIFIC_STATUS);
-+ if (ss < 0)
-+ return ss;
-+
-+ if (ss & AT803X_SS_SPEED_DUPLEX_RESOLVED) {
-+ int sfc, speed;
-+
-+ sfc = phy_read(phydev, AT803X_SPECIFIC_FUNCTION_CONTROL);
-+ if (sfc < 0)
-+ return sfc;
-+
-+ speed = ss & ss_mask.speed_mask;
-+ speed >>= ss_mask.speed_shift;
-+
-+ switch (speed) {
-+ case AT803X_SS_SPEED_10:
-+ phydev->speed = SPEED_10;
-+ break;
-+ case AT803X_SS_SPEED_100:
-+ phydev->speed = SPEED_100;
-+ break;
-+ case AT803X_SS_SPEED_1000:
-+ phydev->speed = SPEED_1000;
-+ break;
-+ case QCA808X_SS_SPEED_2500:
-+ phydev->speed = SPEED_2500;
-+ break;
-+ }
-+ if (ss & AT803X_SS_DUPLEX)
-+ phydev->duplex = DUPLEX_FULL;
-+ else
-+ phydev->duplex = DUPLEX_HALF;
-+
-+ if (ss & AT803X_SS_MDIX)
-+ phydev->mdix = ETH_TP_MDI_X;
-+ else
-+ phydev->mdix = ETH_TP_MDI;
-+
-+ switch (FIELD_GET(AT803X_SFC_MDI_CROSSOVER_MODE_M, sfc)) {
-+ case AT803X_SFC_MANUAL_MDI:
-+ phydev->mdix_ctrl = ETH_TP_MDI;
-+ break;
-+ case AT803X_SFC_MANUAL_MDIX:
-+ phydev->mdix_ctrl = ETH_TP_MDI_X;
-+ break;
-+ case AT803X_SFC_AUTOMATIC_CROSSOVER:
-+ phydev->mdix_ctrl = ETH_TP_MDI_AUTO;
-+ break;
-+ }
-+ }
-+
-+ return 0;
-+}
-+
-+static int at803x_read_status(struct phy_device *phydev)
-+{
-+ struct at803x_ss_mask ss_mask = { 0 };
-+ int err, old_link = phydev->link;
-+
-+ /* Update the link, but return if there was an error */
-+ err = genphy_update_link(phydev);
-+ if (err)
-+ return err;
-+
-+ /* why bother the PHY if nothing can have changed */
-+ if (phydev->autoneg == AUTONEG_ENABLE && old_link && phydev->link)
-+ return 0;
-+
-+ phydev->speed = SPEED_UNKNOWN;
-+ phydev->duplex = DUPLEX_UNKNOWN;
-+ phydev->pause = 0;
-+ phydev->asym_pause = 0;
-+
-+ err = genphy_read_lpa(phydev);
-+ if (err < 0)
-+ return err;
-+
-+ ss_mask.speed_mask = AT803X_SS_SPEED_MASK;
-+ ss_mask.speed_shift = __bf_shf(AT803X_SS_SPEED_MASK);
-+ err = at803x_read_specific_status(phydev, ss_mask);
-+ if (err < 0)
-+ return err;
-+
-+ if (phydev->autoneg == AUTONEG_ENABLE && phydev->autoneg_complete)
-+ phy_resolve_aneg_pause(phydev);
-+
-+ return 0;
-+}
-+
-+static int at803x_config_mdix(struct phy_device *phydev, u8 ctrl)
-+{
-+ u16 val;
-+
-+ switch (ctrl) {
-+ case ETH_TP_MDI:
-+ val = AT803X_SFC_MANUAL_MDI;
-+ break;
-+ case ETH_TP_MDI_X:
-+ val = AT803X_SFC_MANUAL_MDIX;
-+ break;
-+ case ETH_TP_MDI_AUTO:
-+ val = AT803X_SFC_AUTOMATIC_CROSSOVER;
-+ break;
-+ default:
-+ return 0;
-+ }
-+
-+ return phy_modify_changed(phydev, AT803X_SPECIFIC_FUNCTION_CONTROL,
-+ AT803X_SFC_MDI_CROSSOVER_MODE_M,
-+ FIELD_PREP(AT803X_SFC_MDI_CROSSOVER_MODE_M, val));
-+}
-+
-+static int at803x_prepare_config_aneg(struct phy_device *phydev)
-+{
-+ int ret;
-+
-+ ret = at803x_config_mdix(phydev, phydev->mdix_ctrl);
-+ if (ret < 0)
-+ return ret;
-+
-+ /* Changes of the midx bits are disruptive to the normal operation;
-+ * therefore any changes to these registers must be followed by a
-+ * software reset to take effect.
-+ */
-+ if (ret == 1) {
-+ ret = genphy_soft_reset(phydev);
-+ if (ret < 0)
-+ return ret;
-+ }
-+
-+ return 0;
-+}
-+
-+static int at803x_config_aneg(struct phy_device *phydev)
-+{
-+ struct at803x_priv *priv = phydev->priv;
-+ int ret;
-+
-+ ret = at803x_prepare_config_aneg(phydev);
-+ if (ret)
-+ return ret;
-+
-+ if (priv->is_1000basex)
-+ return genphy_c37_config_aneg(phydev);
-+
-+ return genphy_config_aneg(phydev);
-+}
-+
-+static int at803x_get_downshift(struct phy_device *phydev, u8 *d)
-+{
-+ int val;
-+
-+ val = phy_read(phydev, AT803X_SMART_SPEED);
-+ if (val < 0)
-+ return val;
-+
-+ if (val & AT803X_SMART_SPEED_ENABLE)
-+ *d = FIELD_GET(AT803X_SMART_SPEED_RETRY_LIMIT_MASK, val) + 2;
-+ else
-+ *d = DOWNSHIFT_DEV_DISABLE;
-+
-+ return 0;
-+}
-+
-+static int at803x_set_downshift(struct phy_device *phydev, u8 cnt)
-+{
-+ u16 mask, set;
-+ int ret;
-+
-+ switch (cnt) {
-+ case DOWNSHIFT_DEV_DEFAULT_COUNT:
-+ cnt = AT803X_DEFAULT_DOWNSHIFT;
-+ fallthrough;
-+ case AT803X_MIN_DOWNSHIFT ... AT803X_MAX_DOWNSHIFT:
-+ set = AT803X_SMART_SPEED_ENABLE |
-+ AT803X_SMART_SPEED_BYPASS_TIMER |
-+ FIELD_PREP(AT803X_SMART_SPEED_RETRY_LIMIT_MASK, cnt - 2);
-+ mask = AT803X_SMART_SPEED_RETRY_LIMIT_MASK;
-+ break;
-+ case DOWNSHIFT_DEV_DISABLE:
-+ set = 0;
-+ mask = AT803X_SMART_SPEED_ENABLE |
-+ AT803X_SMART_SPEED_BYPASS_TIMER;
-+ break;
-+ default:
-+ return -EINVAL;
-+ }
-+
-+ ret = phy_modify_changed(phydev, AT803X_SMART_SPEED, mask, set);
-+
-+ /* After changing the smart speed settings, we need to perform a
-+ * software reset, use phy_init_hw() to make sure we set the
-+ * reapply any values which might got lost during software reset.
-+ */
-+ if (ret == 1)
-+ ret = phy_init_hw(phydev);
-+
-+ return ret;
-+}
-+
-+static int at803x_get_tunable(struct phy_device *phydev,
-+ struct ethtool_tunable *tuna, void *data)
-+{
-+ switch (tuna->id) {
-+ case ETHTOOL_PHY_DOWNSHIFT:
-+ return at803x_get_downshift(phydev, data);
-+ default:
-+ return -EOPNOTSUPP;
-+ }
-+}
-+
-+static int at803x_set_tunable(struct phy_device *phydev,
-+ struct ethtool_tunable *tuna, const void *data)
-+{
-+ switch (tuna->id) {
-+ case ETHTOOL_PHY_DOWNSHIFT:
-+ return at803x_set_downshift(phydev, *(const u8 *)data);
-+ default:
-+ return -EOPNOTSUPP;
-+ }
-+}
-+
-+static int at803x_cable_test_result_trans(u16 status)
-+{
-+ switch (FIELD_GET(AT803X_CDT_STATUS_STAT_MASK, status)) {
-+ case AT803X_CDT_STATUS_STAT_NORMAL:
-+ return ETHTOOL_A_CABLE_RESULT_CODE_OK;
-+ case AT803X_CDT_STATUS_STAT_SHORT:
-+ return ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT;
-+ case AT803X_CDT_STATUS_STAT_OPEN:
-+ return ETHTOOL_A_CABLE_RESULT_CODE_OPEN;
-+ case AT803X_CDT_STATUS_STAT_FAIL:
-+ default:
-+ return ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC;
-+ }
-+}
-+
-+static bool at803x_cdt_test_failed(u16 status)
-+{
-+ return FIELD_GET(AT803X_CDT_STATUS_STAT_MASK, status) ==
-+ AT803X_CDT_STATUS_STAT_FAIL;
-+}
-+
-+static bool at803x_cdt_fault_length_valid(u16 status)
-+{
-+ switch (FIELD_GET(AT803X_CDT_STATUS_STAT_MASK, status)) {
-+ case AT803X_CDT_STATUS_STAT_OPEN:
-+ case AT803X_CDT_STATUS_STAT_SHORT:
-+ return true;
-+ }
-+ return false;
-+}
-+
-+static int at803x_cdt_fault_length(int dt)
-+{
-+ /* According to the datasheet the distance to the fault is
-+ * DELTA_TIME * 0.824 meters.
-+ *
-+ * The author suspect the correct formula is:
-+ *
-+ * fault_distance = DELTA_TIME * (c * VF) / 125MHz / 2
-+ *
-+ * where c is the speed of light, VF is the velocity factor of
-+ * the twisted pair cable, 125MHz the counter frequency and
-+ * we need to divide by 2 because the hardware will measure the
-+ * round trip time to the fault and back to the PHY.
-+ *
-+ * With a VF of 0.69 we get the factor 0.824 mentioned in the
-+ * datasheet.
-+ */
-+ return (dt * 824) / 10;
-+}
-+
-+static int at803x_cdt_start(struct phy_device *phydev,
-+ u32 cdt_start)
-+{
-+ return phy_write(phydev, AT803X_CDT, cdt_start);
-+}
-+
-+static int at803x_cdt_wait_for_completion(struct phy_device *phydev,
-+ u32 cdt_en)
-+{
-+ int val, ret;
-+
-+ /* One test run takes about 25ms */
-+ ret = phy_read_poll_timeout(phydev, AT803X_CDT, val,
-+ !(val & cdt_en),
-+ 30000, 100000, true);
-+
-+ return ret < 0 ? ret : 0;
-+}
-+
-+static int at803x_cable_test_one_pair(struct phy_device *phydev, int pair)
-+{
-+ static const int ethtool_pair[] = {
-+ ETHTOOL_A_CABLE_PAIR_A,
-+ ETHTOOL_A_CABLE_PAIR_B,
-+ ETHTOOL_A_CABLE_PAIR_C,
-+ ETHTOOL_A_CABLE_PAIR_D,
-+ };
-+ int ret, val;
-+
-+ val = FIELD_PREP(AT803X_CDT_MDI_PAIR_MASK, pair) |
-+ AT803X_CDT_ENABLE_TEST;
-+ ret = at803x_cdt_start(phydev, val);
-+ if (ret)
-+ return ret;
-+
-+ ret = at803x_cdt_wait_for_completion(phydev, AT803X_CDT_ENABLE_TEST);
-+ if (ret)
-+ return ret;
-+
-+ val = phy_read(phydev, AT803X_CDT_STATUS);
-+ if (val < 0)
-+ return val;
-+
-+ if (at803x_cdt_test_failed(val))
-+ return 0;
-+
-+ ethnl_cable_test_result(phydev, ethtool_pair[pair],
-+ at803x_cable_test_result_trans(val));
-+
-+ if (at803x_cdt_fault_length_valid(val)) {
-+ val = FIELD_GET(AT803X_CDT_STATUS_DELTA_TIME_MASK, val);
-+ ethnl_cable_test_fault_length(phydev, ethtool_pair[pair],
-+ at803x_cdt_fault_length(val));
-+ }
-+
-+ return 1;
-+}
-+
-+static int at803x_cable_test_get_status(struct phy_device *phydev,
-+ bool *finished, unsigned long pair_mask)
-+{
-+ int retries = 20;
-+ int pair, ret;
-+
-+ *finished = false;
-+
-+ /* According to the datasheet the CDT can be performed when
-+ * there is no link partner or when the link partner is
-+ * auto-negotiating. Starting the test will restart the AN
-+ * automatically. It seems that doing this repeatedly we will
-+ * get a slot where our link partner won't disturb our
-+ * measurement.
-+ */
-+ while (pair_mask && retries--) {
-+ for_each_set_bit(pair, &pair_mask, 4) {
-+ ret = at803x_cable_test_one_pair(phydev, pair);
-+ if (ret < 0)
-+ return ret;
-+ if (ret)
-+ clear_bit(pair, &pair_mask);
-+ }
-+ if (pair_mask)
-+ msleep(250);
-+ }
-+
-+ *finished = true;
-+
-+ return 0;
-+}
-+
-+static void at803x_cable_test_autoneg(struct phy_device *phydev)
-+{
-+ /* Enable auto-negotiation, but advertise no capabilities, no link
-+ * will be established. A restart of the auto-negotiation is not
-+ * required, because the cable test will automatically break the link.
-+ */
-+ phy_write(phydev, MII_BMCR, BMCR_ANENABLE);
-+ phy_write(phydev, MII_ADVERTISE, ADVERTISE_CSMA);
-+}
-+
-+static int at803x_cable_test_start(struct phy_device *phydev)
-+{
-+ at803x_cable_test_autoneg(phydev);
-+ /* we do all the (time consuming) work later */
-+ return 0;
-+}
-+
-+static int at8031_rgmii_reg_set_voltage_sel(struct regulator_dev *rdev,
-+ unsigned int selector)
-+{
-+ struct phy_device *phydev = rdev_get_drvdata(rdev);
-+
-+ if (selector)
-+ return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_1F,
-+ 0, AT803X_DEBUG_RGMII_1V8);
-+ else
-+ return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_1F,
-+ AT803X_DEBUG_RGMII_1V8, 0);
-+}
-+
-+static int at8031_rgmii_reg_get_voltage_sel(struct regulator_dev *rdev)
-+{
-+ struct phy_device *phydev = rdev_get_drvdata(rdev);
-+ int val;
-+
-+ val = at803x_debug_reg_read(phydev, AT803X_DEBUG_REG_1F);
-+ if (val < 0)
-+ return val;
-+
-+ return (val & AT803X_DEBUG_RGMII_1V8) ? 1 : 0;
-+}
-+
-+static const struct regulator_ops vddio_regulator_ops = {
-+ .list_voltage = regulator_list_voltage_table,
-+ .set_voltage_sel = at8031_rgmii_reg_set_voltage_sel,
-+ .get_voltage_sel = at8031_rgmii_reg_get_voltage_sel,
-+};
-+
-+static const unsigned int vddio_voltage_table[] = {
-+ 1500000,
-+ 1800000,
-+};
-+
-+static const struct regulator_desc vddio_desc = {
-+ .name = "vddio",
-+ .of_match = of_match_ptr("vddio-regulator"),
-+ .n_voltages = ARRAY_SIZE(vddio_voltage_table),
-+ .volt_table = vddio_voltage_table,
-+ .ops = &vddio_regulator_ops,
-+ .type = REGULATOR_VOLTAGE,
-+ .owner = THIS_MODULE,
-+};
-+
-+static const struct regulator_ops vddh_regulator_ops = {
-+};
-+
-+static const struct regulator_desc vddh_desc = {
-+ .name = "vddh",
-+ .of_match = of_match_ptr("vddh-regulator"),
-+ .n_voltages = 1,
-+ .fixed_uV = 2500000,
-+ .ops = &vddh_regulator_ops,
-+ .type = REGULATOR_VOLTAGE,
-+ .owner = THIS_MODULE,
-+};
-+
-+static int at8031_register_regulators(struct phy_device *phydev)
-+{
-+ struct at803x_priv *priv = phydev->priv;
-+ struct device *dev = &phydev->mdio.dev;
-+ struct regulator_config config = { };
-+
-+ config.dev = dev;
-+ config.driver_data = phydev;
-+
-+ priv->vddio_rdev = devm_regulator_register(dev, &vddio_desc, &config);
-+ if (IS_ERR(priv->vddio_rdev)) {
-+ phydev_err(phydev, "failed to register VDDIO regulator\n");
-+ return PTR_ERR(priv->vddio_rdev);
-+ }
-+
-+ priv->vddh_rdev = devm_regulator_register(dev, &vddh_desc, &config);
-+ if (IS_ERR(priv->vddh_rdev)) {
-+ phydev_err(phydev, "failed to register VDDH regulator\n");
-+ return PTR_ERR(priv->vddh_rdev);
-+ }
-+
-+ return 0;
-+}
-+
-+static int at8031_sfp_insert(void *upstream, const struct sfp_eeprom_id *id)
-+{
-+ struct phy_device *phydev = upstream;
-+ __ETHTOOL_DECLARE_LINK_MODE_MASK(phy_support);
-+ __ETHTOOL_DECLARE_LINK_MODE_MASK(sfp_support);
-+ DECLARE_PHY_INTERFACE_MASK(interfaces);
-+ phy_interface_t iface;
-+
-+ linkmode_zero(phy_support);
-+ phylink_set(phy_support, 1000baseX_Full);
-+ phylink_set(phy_support, 1000baseT_Full);
-+ phylink_set(phy_support, Autoneg);
-+ phylink_set(phy_support, Pause);
-+ phylink_set(phy_support, Asym_Pause);
-+
-+ linkmode_zero(sfp_support);
-+ sfp_parse_support(phydev->sfp_bus, id, sfp_support, interfaces);
-+ /* Some modules support 10G modes as well as others we support.
-+ * Mask out non-supported modes so the correct interface is picked.
-+ */
-+ linkmode_and(sfp_support, phy_support, sfp_support);
-+
-+ if (linkmode_empty(sfp_support)) {
-+ dev_err(&phydev->mdio.dev, "incompatible SFP module inserted\n");
-+ return -EINVAL;
-+ }
-+
-+ iface = sfp_select_interface(phydev->sfp_bus, sfp_support);
-+
-+ /* Only 1000Base-X is supported by AR8031/8033 as the downstream SerDes
-+ * interface for use with SFP modules.
-+ * However, some copper modules detected as having a preferred SGMII
-+ * interface do default to and function in 1000Base-X mode, so just
-+ * print a warning and allow such modules, as they may have some chance
-+ * of working.
-+ */
-+ if (iface == PHY_INTERFACE_MODE_SGMII)
-+ dev_warn(&phydev->mdio.dev, "module may not function if 1000Base-X not supported\n");
-+ else if (iface != PHY_INTERFACE_MODE_1000BASEX)
-+ return -EINVAL;
-+
-+ return 0;
-+}
-+
-+static const struct sfp_upstream_ops at8031_sfp_ops = {
-+ .attach = phy_sfp_attach,
-+ .detach = phy_sfp_detach,
-+ .module_insert = at8031_sfp_insert,
-+};
-+
-+static int at8031_parse_dt(struct phy_device *phydev)
-+{
-+ struct device_node *node = phydev->mdio.dev.of_node;
-+ struct at803x_priv *priv = phydev->priv;
-+ int ret;
-+
-+ if (of_property_read_bool(node, "qca,keep-pll-enabled"))
-+ priv->flags |= AT803X_KEEP_PLL_ENABLED;
-+
-+ ret = at8031_register_regulators(phydev);
-+ if (ret < 0)
-+ return ret;
-+
-+ ret = devm_regulator_get_enable_optional(&phydev->mdio.dev,
-+ "vddio");
-+ if (ret) {
-+ phydev_err(phydev, "failed to get VDDIO regulator\n");
-+ return ret;
-+ }
-+
-+ /* Only AR8031/8033 support 1000Base-X for SFP modules */
-+ return phy_sfp_probe(phydev, &at8031_sfp_ops);
-+}
-+
-+static int at8031_probe(struct phy_device *phydev)
-+{
-+ struct at803x_priv *priv = phydev->priv;
-+ int mode_cfg;
-+ int ccr;
-+ int ret;
-+
-+ ret = at803x_probe(phydev);
-+ if (ret)
-+ return ret;
-+
-+ /* Only supported on AR8031/AR8033, the AR8030/AR8035 use strapping
-+ * options.
-+ */
-+ ret = at8031_parse_dt(phydev);
-+ if (ret)
-+ return ret;
-+
-+ ccr = phy_read(phydev, AT803X_REG_CHIP_CONFIG);
-+ if (ccr < 0)
-+ return ccr;
-+ mode_cfg = ccr & AT803X_MODE_CFG_MASK;
-+
-+ switch (mode_cfg) {
-+ case AT803X_MODE_CFG_BX1000_RGMII_50OHM:
-+ case AT803X_MODE_CFG_BX1000_RGMII_75OHM:
-+ priv->is_1000basex = true;
-+ fallthrough;
-+ case AT803X_MODE_CFG_FX100_RGMII_50OHM:
-+ case AT803X_MODE_CFG_FX100_RGMII_75OHM:
-+ priv->is_fiber = true;
-+ break;
-+ }
-+
-+ /* Disable WoL in 1588 register which is enabled
-+ * by default
-+ */
-+ return phy_modify_mmd(phydev, MDIO_MMD_PCS,
-+ AT803X_PHY_MMD3_WOL_CTRL,
-+ AT803X_WOL_EN, 0);
-+}
-+
-+static int at8031_config_init(struct phy_device *phydev)
-+{
-+ struct at803x_priv *priv = phydev->priv;
-+ int ret;
-+
-+ /* Some bootloaders leave the fiber page selected.
-+ * Switch to the appropriate page (fiber or copper), as otherwise we
-+ * read the PHY capabilities from the wrong page.
-+ */
-+ phy_lock_mdio_bus(phydev);
-+ ret = at803x_write_page(phydev,
-+ priv->is_fiber ? AT803X_PAGE_FIBER :
-+ AT803X_PAGE_COPPER);
-+ phy_unlock_mdio_bus(phydev);
-+ if (ret)
-+ return ret;
-+
-+ ret = at8031_pll_config(phydev);
-+ if (ret < 0)
-+ return ret;
-+
-+ return at803x_config_init(phydev);
-+}
-+
-+static int at8031_set_wol(struct phy_device *phydev,
-+ struct ethtool_wolinfo *wol)
-+{
-+ int ret;
-+
-+ /* First setup MAC address and enable WOL interrupt */
-+ ret = at803x_set_wol(phydev, wol);
-+ if (ret)
-+ return ret;
-+
-+ if (wol->wolopts & WAKE_MAGIC)
-+ /* Enable WOL function for 1588 */
-+ ret = phy_modify_mmd(phydev, MDIO_MMD_PCS,
-+ AT803X_PHY_MMD3_WOL_CTRL,
-+ 0, AT803X_WOL_EN);
-+ else
-+ /* Disable WoL function for 1588 */
-+ ret = phy_modify_mmd(phydev, MDIO_MMD_PCS,
-+ AT803X_PHY_MMD3_WOL_CTRL,
-+ AT803X_WOL_EN, 0);
-+
-+ return ret;
-+}
-+
-+static int at8031_config_intr(struct phy_device *phydev)
-+{
-+ struct at803x_priv *priv = phydev->priv;
-+ int err, value = 0;
-+
-+ if (phydev->interrupts == PHY_INTERRUPT_ENABLED &&
-+ priv->is_fiber) {
-+ /* Clear any pending interrupts */
-+ err = at803x_ack_interrupt(phydev);
-+ if (err)
-+ return err;
-+
-+ value |= AT803X_INTR_ENABLE_LINK_FAIL_BX;
-+ value |= AT803X_INTR_ENABLE_LINK_SUCCESS_BX;
-+
-+ err = phy_set_bits(phydev, AT803X_INTR_ENABLE, value);
-+ if (err)
-+ return err;
-+ }
-+
-+ return at803x_config_intr(phydev);
-+}
-+
-+/* AR8031 and AR8033 share the same read status logic */
-+static int at8031_read_status(struct phy_device *phydev)
-+{
-+ struct at803x_priv *priv = phydev->priv;
-+
-+ if (priv->is_1000basex)
-+ return genphy_c37_read_status(phydev);
-+
-+ return at803x_read_status(phydev);
-+}
-+
-+/* AR8031 and AR8035 share the same cable test get status reg */
-+static int at8031_cable_test_get_status(struct phy_device *phydev,
-+ bool *finished)
-+{
-+ return at803x_cable_test_get_status(phydev, finished, 0xf);
-+}
-+
-+/* AR8031 and AR8035 share the same cable test start logic */
-+static int at8031_cable_test_start(struct phy_device *phydev)
-+{
-+ at803x_cable_test_autoneg(phydev);
-+ phy_write(phydev, MII_CTRL1000, 0);
-+ /* we do all the (time consuming) work later */
-+ return 0;
-+}
-+
-+/* AR8032, AR9331 and QCA9561 share the same cable test get status reg */
-+static int at8032_cable_test_get_status(struct phy_device *phydev,
-+ bool *finished)
-+{
-+ return at803x_cable_test_get_status(phydev, finished, 0x3);
-+}
-+
-+static int at8035_parse_dt(struct phy_device *phydev)
-+{
-+ struct at803x_priv *priv = phydev->priv;
-+
-+ /* Mask is set by the generic at803x_parse_dt
-+ * if property is set. Assume property is set
-+ * with the mask not zero.
-+ */
-+ if (priv->clk_25m_mask) {
-+ /* Fixup for the AR8030/AR8035. This chip has another mask and
-+ * doesn't support the DSP reference. Eg. the lowest bit of the
-+ * mask. The upper two bits select the same frequencies. Mask
-+ * the lowest bit here.
-+ *
-+ * Warning:
-+ * There was no datasheet for the AR8030 available so this is
-+ * just a guess. But the AR8035 is listed as pin compatible
-+ * to the AR8030 so there might be a good chance it works on
-+ * the AR8030 too.
-+ */
-+ priv->clk_25m_reg &= AT8035_CLK_OUT_MASK;
-+ priv->clk_25m_mask &= AT8035_CLK_OUT_MASK;
-+ }
-+
-+ return 0;
-+}
-+
-+/* AR8030 and AR8035 shared the same special mask for clk_25m */
-+static int at8035_probe(struct phy_device *phydev)
-+{
-+ int ret;
-+
-+ ret = at803x_probe(phydev);
-+ if (ret)
-+ return ret;
-+
-+ return at8035_parse_dt(phydev);
-+}
-+
-+static int qca83xx_config_init(struct phy_device *phydev)
-+{
-+ u8 switch_revision;
-+
-+ switch_revision = phydev->dev_flags & QCA8K_DEVFLAGS_REVISION_MASK;
-+
-+ switch (switch_revision) {
-+ case 1:
-+ /* For 100M waveform */
-+ at803x_debug_reg_write(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL, 0x02ea);
-+ /* Turn on Gigabit clock */
-+ at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_GREEN, 0x68a0);
-+ break;
-+
-+ case 2:
-+ phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV, 0x0);
-+ fallthrough;
-+ case 4:
-+ phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_AZ_DEBUG, 0x803f);
-+ at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_GREEN, 0x6860);
-+ at803x_debug_reg_write(phydev, AT803X_DEBUG_SYSTEM_CTRL_MODE, 0x2c46);
-+ at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_3C, 0x6000);
-+ break;
-+ }
-+
-+ /* Following original QCA sourcecode set port to prefer master */
-+ phy_set_bits(phydev, MII_CTRL1000, CTL1000_PREFER_MASTER);
-+
-+ return 0;
-+}
-+
-+static int qca8327_config_init(struct phy_device *phydev)
-+{
-+ /* QCA8327 require DAC amplitude adjustment for 100m set to +6%.
-+ * Disable on init and enable only with 100m speed following
-+ * qca original source code.
-+ */
-+ at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL,
-+ QCA8327_DEBUG_MANU_CTRL_EN, 0);
-+
-+ return qca83xx_config_init(phydev);
-+}
-+
-+static void qca83xx_link_change_notify(struct phy_device *phydev)
-+{
-+ /* Set DAC Amplitude adjustment to +6% for 100m on link running */
-+ if (phydev->state == PHY_RUNNING) {
-+ if (phydev->speed == SPEED_100)
-+ at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL,
-+ QCA8327_DEBUG_MANU_CTRL_EN,
-+ QCA8327_DEBUG_MANU_CTRL_EN);
-+ } else {
-+ /* Reset DAC Amplitude adjustment */
-+ at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL,
-+ QCA8327_DEBUG_MANU_CTRL_EN, 0);
-+ }
-+}
-+
-+static int qca83xx_resume(struct phy_device *phydev)
-+{
-+ int ret, val;
-+
-+ /* Skip reset if not suspended */
-+ if (!phydev->suspended)
-+ return 0;
-+
-+ /* Reinit the port, reset values set by suspend */
-+ qca83xx_config_init(phydev);
-+
-+ /* Reset the port on port resume */
-+ phy_set_bits(phydev, MII_BMCR, BMCR_RESET | BMCR_ANENABLE);
-+
-+ /* On resume from suspend the switch execute a reset and
-+ * restart auto-negotiation. Wait for reset to complete.
-+ */
-+ ret = phy_read_poll_timeout(phydev, MII_BMCR, val, !(val & BMCR_RESET),
-+ 50000, 600000, true);
-+ if (ret)
-+ return ret;
-+
-+ usleep_range(1000, 2000);
-+
-+ return 0;
-+}
-+
-+static int qca83xx_suspend(struct phy_device *phydev)
-+{
-+ at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_GREEN,
-+ AT803X_DEBUG_GATE_CLK_IN1000, 0);
-+
-+ at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_HIB_CTRL,
-+ AT803X_DEBUG_HIB_CTRL_EN_ANY_CHANGE |
-+ AT803X_DEBUG_HIB_CTRL_SEL_RST_80U, 0);
-+
-+ return 0;
-+}
-+
-+static int qca8337_suspend(struct phy_device *phydev)
-+{
-+ /* Only QCA8337 support actual suspend. */
-+ genphy_suspend(phydev);
-+
-+ return qca83xx_suspend(phydev);
-+}
-+
-+static int qca8327_suspend(struct phy_device *phydev)
-+{
-+ u16 mask = 0;
-+
-+ /* QCA8327 cause port unreliability when phy suspend
-+ * is set.
-+ */
-+ mask |= ~(BMCR_SPEED1000 | BMCR_FULLDPLX);
-+ phy_modify(phydev, MII_BMCR, mask, 0);
-+
-+ return qca83xx_suspend(phydev);
-+}
-+
-+static int qca808x_phy_fast_retrain_config(struct phy_device *phydev)
-+{
-+ int ret;
-+
-+ /* Enable fast retrain */
-+ ret = genphy_c45_fast_retrain(phydev, true);
-+ if (ret)
-+ return ret;
-+
-+ phy_write_mmd(phydev, MDIO_MMD_AN, QCA808X_PHY_MMD7_TOP_OPTION1,
-+ QCA808X_TOP_OPTION1_DATA);
-+ phy_write_mmd(phydev, MDIO_MMD_PMAPMD, QCA808X_PHY_MMD1_MSE_THRESHOLD_20DB,
-+ QCA808X_MSE_THRESHOLD_20DB_VALUE);
-+ phy_write_mmd(phydev, MDIO_MMD_PMAPMD, QCA808X_PHY_MMD1_MSE_THRESHOLD_17DB,
-+ QCA808X_MSE_THRESHOLD_17DB_VALUE);
-+ phy_write_mmd(phydev, MDIO_MMD_PMAPMD, QCA808X_PHY_MMD1_MSE_THRESHOLD_27DB,
-+ QCA808X_MSE_THRESHOLD_27DB_VALUE);
-+ phy_write_mmd(phydev, MDIO_MMD_PMAPMD, QCA808X_PHY_MMD1_MSE_THRESHOLD_28DB,
-+ QCA808X_MSE_THRESHOLD_28DB_VALUE);
-+ phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_1,
-+ QCA808X_MMD3_DEBUG_1_VALUE);
-+ phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_4,
-+ QCA808X_MMD3_DEBUG_4_VALUE);
-+ phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_5,
-+ QCA808X_MMD3_DEBUG_5_VALUE);
-+ phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_3,
-+ QCA808X_MMD3_DEBUG_3_VALUE);
-+ phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_6,
-+ QCA808X_MMD3_DEBUG_6_VALUE);
-+ phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_2,
-+ QCA808X_MMD3_DEBUG_2_VALUE);
-+
-+ return 0;
-+}
-+
-+static int qca808x_phy_ms_seed_enable(struct phy_device *phydev, bool enable)
-+{
-+ u16 seed_value;
-+
-+ if (!enable)
-+ return at803x_debug_reg_mask(phydev, QCA808X_PHY_DEBUG_LOCAL_SEED,
-+ QCA808X_MASTER_SLAVE_SEED_ENABLE, 0);
-+
-+ seed_value = get_random_u32_below(QCA808X_MASTER_SLAVE_SEED_RANGE);
-+ return at803x_debug_reg_mask(phydev, QCA808X_PHY_DEBUG_LOCAL_SEED,
-+ QCA808X_MASTER_SLAVE_SEED_CFG | QCA808X_MASTER_SLAVE_SEED_ENABLE,
-+ FIELD_PREP(QCA808X_MASTER_SLAVE_SEED_CFG, seed_value) |
-+ QCA808X_MASTER_SLAVE_SEED_ENABLE);
-+}
-+
-+static bool qca808x_is_prefer_master(struct phy_device *phydev)
-+{
-+ return (phydev->master_slave_get == MASTER_SLAVE_CFG_MASTER_FORCE) ||
-+ (phydev->master_slave_get == MASTER_SLAVE_CFG_MASTER_PREFERRED);
-+}
-+
-+static bool qca808x_has_fast_retrain_or_slave_seed(struct phy_device *phydev)
-+{
-+ return linkmode_test_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, phydev->supported);
-+}
-+
-+static int qca808x_config_init(struct phy_device *phydev)
-+{
-+ int ret;
-+
-+ /* Active adc&vga on 802.3az for the link 1000M and 100M */
-+ ret = phy_modify_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_ADDR_CLD_CTRL7,
-+ QCA808X_8023AZ_AFE_CTRL_MASK, QCA808X_8023AZ_AFE_EN);
-+ if (ret)
-+ return ret;
-+
-+ /* Adjust the threshold on 802.3az for the link 1000M */
-+ ret = phy_write_mmd(phydev, MDIO_MMD_PCS,
-+ QCA808X_PHY_MMD3_AZ_TRAINING_CTRL,
-+ QCA808X_MMD3_AZ_TRAINING_VAL);
-+ if (ret)
-+ return ret;
-+
-+ if (qca808x_has_fast_retrain_or_slave_seed(phydev)) {
-+ /* Config the fast retrain for the link 2500M */
-+ ret = qca808x_phy_fast_retrain_config(phydev);
-+ if (ret)
-+ return ret;
-+
-+ ret = genphy_read_master_slave(phydev);
-+ if (ret < 0)
-+ return ret;
-+
-+ if (!qca808x_is_prefer_master(phydev)) {
-+ /* Enable seed and configure lower ramdom seed to make phy
-+ * linked as slave mode.
-+ */
-+ ret = qca808x_phy_ms_seed_enable(phydev, true);
-+ if (ret)
-+ return ret;
-+ }
-+ }
-+
-+ /* Configure adc threshold as 100mv for the link 10M */
-+ return at803x_debug_reg_mask(phydev, QCA808X_PHY_DEBUG_ADC_THRESHOLD,
-+ QCA808X_ADC_THRESHOLD_MASK,
-+ QCA808X_ADC_THRESHOLD_100MV);
-+}
-+
-+static int qca808x_read_status(struct phy_device *phydev)
-+{
-+ struct at803x_ss_mask ss_mask = { 0 };
-+ int ret;
-+
-+ ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_10GBT_STAT);
-+ if (ret < 0)
-+ return ret;
-+
-+ linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, phydev->lp_advertising,
-+ ret & MDIO_AN_10GBT_STAT_LP2_5G);
-+
-+ ret = genphy_read_status(phydev);
-+ if (ret)
-+ return ret;
-+
-+ /* qca8081 takes the different bits for speed value from at803x */
-+ ss_mask.speed_mask = QCA808X_SS_SPEED_MASK;
-+ ss_mask.speed_shift = __bf_shf(QCA808X_SS_SPEED_MASK);
-+ ret = at803x_read_specific_status(phydev, ss_mask);
-+ if (ret < 0)
-+ return ret;
-+
-+ if (phydev->link) {
-+ if (phydev->speed == SPEED_2500)
-+ phydev->interface = PHY_INTERFACE_MODE_2500BASEX;
-+ else
-+ phydev->interface = PHY_INTERFACE_MODE_SGMII;
-+ } else {
-+ /* generate seed as a lower random value to make PHY linked as SLAVE easily,
-+ * except for master/slave configuration fault detected or the master mode
-+ * preferred.
-+ *
-+ * the reason for not putting this code into the function link_change_notify is
-+ * the corner case where the link partner is also the qca8081 PHY and the seed
-+ * value is configured as the same value, the link can't be up and no link change
-+ * occurs.
-+ */
-+ if (qca808x_has_fast_retrain_or_slave_seed(phydev)) {
-+ if (phydev->master_slave_state == MASTER_SLAVE_STATE_ERR ||
-+ qca808x_is_prefer_master(phydev)) {
-+ qca808x_phy_ms_seed_enable(phydev, false);
-+ } else {
-+ qca808x_phy_ms_seed_enable(phydev, true);
-+ }
-+ }
-+ }
-+
-+ return 0;
-+}
-+
-+static int qca808x_soft_reset(struct phy_device *phydev)
-+{
-+ int ret;
-+
-+ ret = genphy_soft_reset(phydev);
-+ if (ret < 0)
-+ return ret;
-+
-+ if (qca808x_has_fast_retrain_or_slave_seed(phydev))
-+ ret = qca808x_phy_ms_seed_enable(phydev, true);
-+
-+ return ret;
-+}
-+
-+static bool qca808x_cdt_fault_length_valid(int cdt_code)
-+{
-+ switch (cdt_code) {
-+ case QCA808X_CDT_STATUS_STAT_SAME_SHORT:
-+ case QCA808X_CDT_STATUS_STAT_SAME_OPEN:
-+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_NORMAL:
-+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_OPEN:
-+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_SHORT:
-+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_NORMAL:
-+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_OPEN:
-+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_SHORT:
-+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_NORMAL:
-+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_OPEN:
-+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_SHORT:
-+ return true;
-+ default:
-+ return false;
-+ }
-+}
-+
-+static int qca808x_cable_test_result_trans(int cdt_code)
-+{
-+ switch (cdt_code) {
-+ case QCA808X_CDT_STATUS_STAT_NORMAL:
-+ return ETHTOOL_A_CABLE_RESULT_CODE_OK;
-+ case QCA808X_CDT_STATUS_STAT_SAME_SHORT:
-+ return ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT;
-+ case QCA808X_CDT_STATUS_STAT_SAME_OPEN:
-+ return ETHTOOL_A_CABLE_RESULT_CODE_OPEN;
-+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_NORMAL:
-+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_OPEN:
-+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_SHORT:
-+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_NORMAL:
-+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_OPEN:
-+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_SHORT:
-+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_NORMAL:
-+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_OPEN:
-+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_SHORT:
-+ return ETHTOOL_A_CABLE_RESULT_CODE_CROSS_SHORT;
-+ case QCA808X_CDT_STATUS_STAT_FAIL:
-+ default:
-+ return ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC;
-+ }
-+}
-+
-+static int qca808x_cdt_fault_length(struct phy_device *phydev, int pair,
-+ int result)
-+{
-+ int val;
-+ u32 cdt_length_reg = 0;
-+
-+ switch (pair) {
-+ case ETHTOOL_A_CABLE_PAIR_A:
-+ cdt_length_reg = QCA808X_MMD3_CDT_DIAG_PAIR_A;
-+ break;
-+ case ETHTOOL_A_CABLE_PAIR_B:
-+ cdt_length_reg = QCA808X_MMD3_CDT_DIAG_PAIR_B;
-+ break;
-+ case ETHTOOL_A_CABLE_PAIR_C:
-+ cdt_length_reg = QCA808X_MMD3_CDT_DIAG_PAIR_C;
-+ break;
-+ case ETHTOOL_A_CABLE_PAIR_D:
-+ cdt_length_reg = QCA808X_MMD3_CDT_DIAG_PAIR_D;
-+ break;
-+ default:
-+ return -EINVAL;
-+ }
-+
-+ val = phy_read_mmd(phydev, MDIO_MMD_PCS, cdt_length_reg);
-+ if (val < 0)
-+ return val;
-+
-+ if (result == ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT)
-+ val = FIELD_GET(QCA808X_CDT_DIAG_LENGTH_SAME_SHORT, val);
-+ else
-+ val = FIELD_GET(QCA808X_CDT_DIAG_LENGTH_CROSS_SHORT, val);
-+
-+ return at803x_cdt_fault_length(val);
-+}
-+
-+static int qca808x_cable_test_start(struct phy_device *phydev)
-+{
-+ int ret;
-+
-+ /* perform CDT with the following configs:
-+ * 1. disable hibernation.
-+ * 2. force PHY working in MDI mode.
-+ * 3. for PHY working in 1000BaseT.
-+ * 4. configure the threshold.
-+ */
-+
-+ ret = at803x_debug_reg_mask(phydev, QCA808X_DBG_AN_TEST, QCA808X_HIBERNATION_EN, 0);
-+ if (ret < 0)
-+ return ret;
-+
-+ ret = at803x_config_mdix(phydev, ETH_TP_MDI);
-+ if (ret < 0)
-+ return ret;
-+
-+ /* Force 1000base-T needs to configure PMA/PMD and MII_BMCR */
-+ phydev->duplex = DUPLEX_FULL;
-+ phydev->speed = SPEED_1000;
-+ ret = genphy_c45_pma_setup_forced(phydev);
-+ if (ret < 0)
-+ return ret;
-+
-+ ret = genphy_setup_forced(phydev);
-+ if (ret < 0)
-+ return ret;
-+
-+ /* configure the thresholds for open, short, pair ok test */
-+ phy_write_mmd(phydev, MDIO_MMD_PCS, 0x8074, 0xc040);
-+ phy_write_mmd(phydev, MDIO_MMD_PCS, 0x8076, 0xc040);
-+ phy_write_mmd(phydev, MDIO_MMD_PCS, 0x8077, 0xa060);
-+ phy_write_mmd(phydev, MDIO_MMD_PCS, 0x8078, 0xc050);
-+ phy_write_mmd(phydev, MDIO_MMD_PCS, 0x807a, 0xc060);
-+ phy_write_mmd(phydev, MDIO_MMD_PCS, 0x807e, 0xb060);
-+
-+ return 0;
-+}
-+
-+static int qca808x_cable_test_get_pair_status(struct phy_device *phydev, u8 pair,
-+ u16 status)
-+{
-+ int length, result;
-+ u16 pair_code;
-+
-+ switch (pair) {
-+ case ETHTOOL_A_CABLE_PAIR_A:
-+ pair_code = FIELD_GET(QCA808X_CDT_CODE_PAIR_A, status);
-+ break;
-+ case ETHTOOL_A_CABLE_PAIR_B:
-+ pair_code = FIELD_GET(QCA808X_CDT_CODE_PAIR_B, status);
-+ break;
-+ case ETHTOOL_A_CABLE_PAIR_C:
-+ pair_code = FIELD_GET(QCA808X_CDT_CODE_PAIR_C, status);
-+ break;
-+ case ETHTOOL_A_CABLE_PAIR_D:
-+ pair_code = FIELD_GET(QCA808X_CDT_CODE_PAIR_D, status);
-+ break;
-+ default:
-+ return -EINVAL;
-+ }
-+
-+ result = qca808x_cable_test_result_trans(pair_code);
-+ ethnl_cable_test_result(phydev, pair, result);
-+
-+ if (qca808x_cdt_fault_length_valid(pair_code)) {
-+ length = qca808x_cdt_fault_length(phydev, pair, result);
-+ ethnl_cable_test_fault_length(phydev, pair, length);
-+ }
-+
-+ return 0;
-+}
-+
-+static int qca808x_cable_test_get_status(struct phy_device *phydev, bool *finished)
-+{
-+ int ret, val;
-+
-+ *finished = false;
-+
-+ val = QCA808X_CDT_ENABLE_TEST |
-+ QCA808X_CDT_LENGTH_UNIT;
-+ ret = at803x_cdt_start(phydev, val);
-+ if (ret)
-+ return ret;
-+
-+ ret = at803x_cdt_wait_for_completion(phydev, QCA808X_CDT_ENABLE_TEST);
-+ if (ret)
-+ return ret;
-+
-+ val = phy_read_mmd(phydev, MDIO_MMD_PCS, QCA808X_MMD3_CDT_STATUS);
-+ if (val < 0)
-+ return val;
-+
-+ ret = qca808x_cable_test_get_pair_status(phydev, ETHTOOL_A_CABLE_PAIR_A, val);
-+ if (ret)
-+ return ret;
-+
-+ ret = qca808x_cable_test_get_pair_status(phydev, ETHTOOL_A_CABLE_PAIR_B, val);
-+ if (ret)
-+ return ret;
-+
-+ ret = qca808x_cable_test_get_pair_status(phydev, ETHTOOL_A_CABLE_PAIR_C, val);
-+ if (ret)
-+ return ret;
-+
-+ ret = qca808x_cable_test_get_pair_status(phydev, ETHTOOL_A_CABLE_PAIR_D, val);
-+ if (ret)
-+ return ret;
-+
-+ *finished = true;
-+
-+ return 0;
-+}
-+
-+static int qca808x_get_features(struct phy_device *phydev)
-+{
-+ int ret;
-+
-+ ret = genphy_c45_pma_read_abilities(phydev);
-+ if (ret)
-+ return ret;
-+
-+ /* The autoneg ability is not existed in bit3 of MMD7.1,
-+ * but it is supported by qca808x PHY, so we add it here
-+ * manually.
-+ */
-+ linkmode_set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, phydev->supported);
-+
-+ /* As for the qca8081 1G version chip, the 2500baseT ability is also
-+ * existed in the bit0 of MMD1.21, we need to remove it manually if
-+ * it is the qca8081 1G chip according to the bit0 of MMD7.0x901d.
-+ */
-+ ret = phy_read_mmd(phydev, MDIO_MMD_AN, QCA808X_PHY_MMD7_CHIP_TYPE);
-+ if (ret < 0)
-+ return ret;
-+
-+ if (QCA808X_PHY_CHIP_TYPE_1G & ret)
-+ linkmode_clear_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, phydev->supported);
-+
-+ return 0;
-+}
-+
-+static int qca808x_config_aneg(struct phy_device *phydev)
-+{
-+ int phy_ctrl = 0;
-+ int ret;
-+
-+ ret = at803x_prepare_config_aneg(phydev);
-+ if (ret)
-+ return ret;
-+
-+ /* The reg MII_BMCR also needs to be configured for force mode, the
-+ * genphy_config_aneg is also needed.
-+ */
-+ if (phydev->autoneg == AUTONEG_DISABLE)
-+ genphy_c45_pma_setup_forced(phydev);
-+
-+ if (linkmode_test_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, phydev->advertising))
-+ phy_ctrl = MDIO_AN_10GBT_CTRL_ADV2_5G;
-+
-+ ret = phy_modify_mmd_changed(phydev, MDIO_MMD_AN, MDIO_AN_10GBT_CTRL,
-+ MDIO_AN_10GBT_CTRL_ADV2_5G, phy_ctrl);
-+ if (ret < 0)
-+ return ret;
-+
-+ return __genphy_config_aneg(phydev, ret);
-+}
-+
-+static void qca808x_link_change_notify(struct phy_device *phydev)
-+{
-+ /* Assert interface sgmii fifo on link down, deassert it on link up,
-+ * the interface device address is always phy address added by 1.
-+ */
-+ mdiobus_c45_modify_changed(phydev->mdio.bus, phydev->mdio.addr + 1,
-+ MDIO_MMD_PMAPMD, QCA8081_PHY_SERDES_MMD1_FIFO_CTRL,
-+ QCA8081_PHY_FIFO_RSTN,
-+ phydev->link ? QCA8081_PHY_FIFO_RSTN : 0);
-+}
-+
-+static int qca808x_led_parse_netdev(struct phy_device *phydev, unsigned long rules,
-+ u16 *offload_trigger)
-+{
-+ /* Parsing specific to netdev trigger */
-+ if (test_bit(TRIGGER_NETDEV_TX, &rules))
-+ *offload_trigger |= QCA808X_LED_TX_BLINK;
-+ if (test_bit(TRIGGER_NETDEV_RX, &rules))
-+ *offload_trigger |= QCA808X_LED_RX_BLINK;
-+ if (test_bit(TRIGGER_NETDEV_LINK_10, &rules))
-+ *offload_trigger |= QCA808X_LED_SPEED10_ON;
-+ if (test_bit(TRIGGER_NETDEV_LINK_100, &rules))
-+ *offload_trigger |= QCA808X_LED_SPEED100_ON;
-+ if (test_bit(TRIGGER_NETDEV_LINK_1000, &rules))
-+ *offload_trigger |= QCA808X_LED_SPEED1000_ON;
-+ if (test_bit(TRIGGER_NETDEV_LINK_2500, &rules))
-+ *offload_trigger |= QCA808X_LED_SPEED2500_ON;
-+ if (test_bit(TRIGGER_NETDEV_HALF_DUPLEX, &rules))
-+ *offload_trigger |= QCA808X_LED_HALF_DUPLEX_ON;
-+ if (test_bit(TRIGGER_NETDEV_FULL_DUPLEX, &rules))
-+ *offload_trigger |= QCA808X_LED_FULL_DUPLEX_ON;
-+
-+ if (rules && !*offload_trigger)
-+ return -EOPNOTSUPP;
-+
-+ /* Enable BLINK_CHECK_BYPASS by default to make the LED
-+ * blink even with duplex or speed mode not enabled.
-+ */
-+ *offload_trigger |= QCA808X_LED_BLINK_CHECK_BYPASS;
-+
-+ return 0;
-+}
-+
-+static int qca808x_led_hw_control_enable(struct phy_device *phydev, u8 index)
-+{
-+ u16 reg;
-+
-+ if (index > 2)
-+ return -EINVAL;
-+
-+ reg = QCA808X_MMD7_LED_FORCE_CTRL(index);
-+
-+ return phy_clear_bits_mmd(phydev, MDIO_MMD_AN, reg,
-+ QCA808X_LED_FORCE_EN);
-+}
-+
-+static int qca808x_led_hw_is_supported(struct phy_device *phydev, u8 index,
-+ unsigned long rules)
-+{
-+ u16 offload_trigger = 0;
-+
-+ if (index > 2)
-+ return -EINVAL;
-+
-+ return qca808x_led_parse_netdev(phydev, rules, &offload_trigger);
-+}
-+
-+static int qca808x_led_hw_control_set(struct phy_device *phydev, u8 index,
-+ unsigned long rules)
-+{
-+ u16 reg, offload_trigger = 0;
-+ int ret;
-+
-+ if (index > 2)
-+ return -EINVAL;
-+
-+ reg = QCA808X_MMD7_LED_CTRL(index);
-+
-+ ret = qca808x_led_parse_netdev(phydev, rules, &offload_trigger);
-+ if (ret)
-+ return ret;
-+
-+ ret = qca808x_led_hw_control_enable(phydev, index);
-+ if (ret)
-+ return ret;
-+
-+ return phy_modify_mmd(phydev, MDIO_MMD_AN, reg,
-+ QCA808X_LED_PATTERN_MASK,
-+ offload_trigger);
-+}
-+
-+static bool qca808x_led_hw_control_status(struct phy_device *phydev, u8 index)
-+{
-+ u16 reg;
-+ int val;
-+
-+ if (index > 2)
-+ return false;
-+
-+ reg = QCA808X_MMD7_LED_FORCE_CTRL(index);
-+
-+ val = phy_read_mmd(phydev, MDIO_MMD_AN, reg);
-+
-+ return !(val & QCA808X_LED_FORCE_EN);
-+}
-+
-+static int qca808x_led_hw_control_get(struct phy_device *phydev, u8 index,
-+ unsigned long *rules)
-+{
-+ u16 reg;
-+ int val;
-+
-+ if (index > 2)
-+ return -EINVAL;
-+
-+ /* Check if we have hw control enabled */
-+ if (qca808x_led_hw_control_status(phydev, index))
-+ return -EINVAL;
-+
-+ reg = QCA808X_MMD7_LED_CTRL(index);
-+
-+ val = phy_read_mmd(phydev, MDIO_MMD_AN, reg);
-+ if (val & QCA808X_LED_TX_BLINK)
-+ set_bit(TRIGGER_NETDEV_TX, rules);
-+ if (val & QCA808X_LED_RX_BLINK)
-+ set_bit(TRIGGER_NETDEV_RX, rules);
-+ if (val & QCA808X_LED_SPEED10_ON)
-+ set_bit(TRIGGER_NETDEV_LINK_10, rules);
-+ if (val & QCA808X_LED_SPEED100_ON)
-+ set_bit(TRIGGER_NETDEV_LINK_100, rules);
-+ if (val & QCA808X_LED_SPEED1000_ON)
-+ set_bit(TRIGGER_NETDEV_LINK_1000, rules);
-+ if (val & QCA808X_LED_SPEED2500_ON)
-+ set_bit(TRIGGER_NETDEV_LINK_2500, rules);
-+ if (val & QCA808X_LED_HALF_DUPLEX_ON)
-+ set_bit(TRIGGER_NETDEV_HALF_DUPLEX, rules);
-+ if (val & QCA808X_LED_FULL_DUPLEX_ON)
-+ set_bit(TRIGGER_NETDEV_FULL_DUPLEX, rules);
-+
-+ return 0;
-+}
-+
-+static int qca808x_led_hw_control_reset(struct phy_device *phydev, u8 index)
-+{
-+ u16 reg;
-+
-+ if (index > 2)
-+ return -EINVAL;
-+
-+ reg = QCA808X_MMD7_LED_CTRL(index);
-+
-+ return phy_clear_bits_mmd(phydev, MDIO_MMD_AN, reg,
-+ QCA808X_LED_PATTERN_MASK);
-+}
-+
-+static int qca808x_led_brightness_set(struct phy_device *phydev,
-+ u8 index, enum led_brightness value)
-+{
-+ u16 reg;
-+ int ret;
-+
-+ if (index > 2)
-+ return -EINVAL;
-+
-+ if (!value) {
-+ ret = qca808x_led_hw_control_reset(phydev, index);
-+ if (ret)
-+ return ret;
-+ }
-+
-+ reg = QCA808X_MMD7_LED_FORCE_CTRL(index);
-+
-+ return phy_modify_mmd(phydev, MDIO_MMD_AN, reg,
-+ QCA808X_LED_FORCE_EN | QCA808X_LED_FORCE_MODE_MASK,
-+ QCA808X_LED_FORCE_EN | value ? QCA808X_LED_FORCE_ON :
-+ QCA808X_LED_FORCE_OFF);
-+}
-+
-+static int qca808x_led_blink_set(struct phy_device *phydev, u8 index,
-+ unsigned long *delay_on,
-+ unsigned long *delay_off)
-+{
-+ int ret;
-+ u16 reg;
-+
-+ if (index > 2)
-+ return -EINVAL;
-+
-+ reg = QCA808X_MMD7_LED_FORCE_CTRL(index);
-+
-+ /* Set blink to 50% off, 50% on at 4Hz by default */
-+ ret = phy_modify_mmd(phydev, MDIO_MMD_AN, QCA808X_MMD7_LED_GLOBAL,
-+ QCA808X_LED_BLINK_FREQ_MASK | QCA808X_LED_BLINK_DUTY_MASK,
-+ QCA808X_LED_BLINK_FREQ_4HZ | QCA808X_LED_BLINK_DUTY_50_50);
-+ if (ret)
-+ return ret;
-+
-+ /* We use BLINK_1 for normal blinking */
-+ ret = phy_modify_mmd(phydev, MDIO_MMD_AN, reg,
-+ QCA808X_LED_FORCE_EN | QCA808X_LED_FORCE_MODE_MASK,
-+ QCA808X_LED_FORCE_EN | QCA808X_LED_FORCE_BLINK_1);
-+ if (ret)
-+ return ret;
-+
-+ /* We set blink to 4Hz, aka 250ms */
-+ *delay_on = 250 / 2;
-+ *delay_off = 250 / 2;
-+
-+ return 0;
-+}
-+
-+static int qca808x_led_polarity_set(struct phy_device *phydev, int index,
-+ unsigned long modes)
-+{
-+ struct at803x_priv *priv = phydev->priv;
-+ bool active_low = false;
-+ u32 mode;
-+
-+ for_each_set_bit(mode, &modes, __PHY_LED_MODES_NUM) {
-+ switch (mode) {
-+ case PHY_LED_ACTIVE_LOW:
-+ active_low = true;
-+ break;
-+ default:
-+ return -EINVAL;
-+ }
-+ }
-+
-+ /* PHY polarity is global and can't be set per LED.
-+ * To detect this, check if last requested polarity mode
-+ * match the new one.
-+ */
-+ if (priv->led_polarity_mode >= 0 &&
-+ priv->led_polarity_mode != active_low) {
-+ phydev_err(phydev, "PHY polarity is global. Mismatched polarity on different LED\n");
-+ return -EINVAL;
-+ }
-+
-+ /* Save the last PHY polarity mode */
-+ priv->led_polarity_mode = active_low;
-+
-+ return phy_modify_mmd(phydev, MDIO_MMD_AN,
-+ QCA808X_MMD7_LED_POLARITY_CTRL,
-+ QCA808X_LED_ACTIVE_HIGH,
-+ active_low ? 0 : QCA808X_LED_ACTIVE_HIGH);
-+}
-+
-+static struct phy_driver at803x_driver[] = {
-+{
-+ /* Qualcomm Atheros AR8035 */
-+ PHY_ID_MATCH_EXACT(ATH8035_PHY_ID),
-+ .name = "Qualcomm Atheros AR8035",
-+ .flags = PHY_POLL_CABLE_TEST,
-+ .probe = at8035_probe,
-+ .config_aneg = at803x_config_aneg,
-+ .config_init = at803x_config_init,
-+ .soft_reset = genphy_soft_reset,
-+ .set_wol = at803x_set_wol,
-+ .get_wol = at803x_get_wol,
-+ .suspend = at803x_suspend,
-+ .resume = at803x_resume,
-+ /* PHY_GBIT_FEATURES */
-+ .read_status = at803x_read_status,
-+ .config_intr = at803x_config_intr,
-+ .handle_interrupt = at803x_handle_interrupt,
-+ .get_tunable = at803x_get_tunable,
-+ .set_tunable = at803x_set_tunable,
-+ .cable_test_start = at8031_cable_test_start,
-+ .cable_test_get_status = at8031_cable_test_get_status,
-+}, {
-+ /* Qualcomm Atheros AR8030 */
-+ .phy_id = ATH8030_PHY_ID,
-+ .name = "Qualcomm Atheros AR8030",
-+ .phy_id_mask = AT8030_PHY_ID_MASK,
-+ .probe = at8035_probe,
-+ .config_init = at803x_config_init,
-+ .link_change_notify = at803x_link_change_notify,
-+ .set_wol = at803x_set_wol,
-+ .get_wol = at803x_get_wol,
-+ .suspend = at803x_suspend,
-+ .resume = at803x_resume,
-+ /* PHY_BASIC_FEATURES */
-+ .config_intr = at803x_config_intr,
-+ .handle_interrupt = at803x_handle_interrupt,
-+}, {
-+ /* Qualcomm Atheros AR8031/AR8033 */
-+ PHY_ID_MATCH_EXACT(ATH8031_PHY_ID),
-+ .name = "Qualcomm Atheros AR8031/AR8033",
-+ .flags = PHY_POLL_CABLE_TEST,
-+ .probe = at8031_probe,
-+ .config_init = at8031_config_init,
-+ .config_aneg = at803x_config_aneg,
-+ .soft_reset = genphy_soft_reset,
-+ .set_wol = at8031_set_wol,
-+ .get_wol = at803x_get_wol,
-+ .suspend = at803x_suspend,
-+ .resume = at803x_resume,
-+ .read_page = at803x_read_page,
-+ .write_page = at803x_write_page,
-+ .get_features = at803x_get_features,
-+ .read_status = at8031_read_status,
-+ .config_intr = at8031_config_intr,
-+ .handle_interrupt = at803x_handle_interrupt,
-+ .get_tunable = at803x_get_tunable,
-+ .set_tunable = at803x_set_tunable,
-+ .cable_test_start = at8031_cable_test_start,
-+ .cable_test_get_status = at8031_cable_test_get_status,
-+}, {
-+ /* Qualcomm Atheros AR8032 */
-+ PHY_ID_MATCH_EXACT(ATH8032_PHY_ID),
-+ .name = "Qualcomm Atheros AR8032",
-+ .probe = at803x_probe,
-+ .flags = PHY_POLL_CABLE_TEST,
-+ .config_init = at803x_config_init,
-+ .link_change_notify = at803x_link_change_notify,
-+ .suspend = at803x_suspend,
-+ .resume = at803x_resume,
-+ /* PHY_BASIC_FEATURES */
-+ .config_intr = at803x_config_intr,
-+ .handle_interrupt = at803x_handle_interrupt,
-+ .cable_test_start = at803x_cable_test_start,
-+ .cable_test_get_status = at8032_cable_test_get_status,
-+}, {
-+ /* ATHEROS AR9331 */
-+ PHY_ID_MATCH_EXACT(ATH9331_PHY_ID),
-+ .name = "Qualcomm Atheros AR9331 built-in PHY",
-+ .probe = at803x_probe,
-+ .suspend = at803x_suspend,
-+ .resume = at803x_resume,
-+ .flags = PHY_POLL_CABLE_TEST,
-+ /* PHY_BASIC_FEATURES */
-+ .config_intr = at803x_config_intr,
-+ .handle_interrupt = at803x_handle_interrupt,
-+ .cable_test_start = at803x_cable_test_start,
-+ .cable_test_get_status = at8032_cable_test_get_status,
-+ .read_status = at803x_read_status,
-+ .soft_reset = genphy_soft_reset,
-+ .config_aneg = at803x_config_aneg,
-+}, {
-+ /* Qualcomm Atheros QCA9561 */
-+ PHY_ID_MATCH_EXACT(QCA9561_PHY_ID),
-+ .name = "Qualcomm Atheros QCA9561 built-in PHY",
-+ .probe = at803x_probe,
-+ .suspend = at803x_suspend,
-+ .resume = at803x_resume,
-+ .flags = PHY_POLL_CABLE_TEST,
-+ /* PHY_BASIC_FEATURES */
-+ .config_intr = at803x_config_intr,
-+ .handle_interrupt = at803x_handle_interrupt,
-+ .cable_test_start = at803x_cable_test_start,
-+ .cable_test_get_status = at8032_cable_test_get_status,
-+ .read_status = at803x_read_status,
-+ .soft_reset = genphy_soft_reset,
-+ .config_aneg = at803x_config_aneg,
-+}, {
-+ /* QCA8337 */
-+ .phy_id = QCA8337_PHY_ID,
-+ .phy_id_mask = QCA8K_PHY_ID_MASK,
-+ .name = "Qualcomm Atheros 8337 internal PHY",
-+ /* PHY_GBIT_FEATURES */
-+ .probe = at803x_probe,
-+ .flags = PHY_IS_INTERNAL,
-+ .config_init = qca83xx_config_init,
-+ .soft_reset = genphy_soft_reset,
-+ .get_sset_count = qca83xx_get_sset_count,
-+ .get_strings = qca83xx_get_strings,
-+ .get_stats = qca83xx_get_stats,
-+ .suspend = qca8337_suspend,
-+ .resume = qca83xx_resume,
-+}, {
-+ /* QCA8327-A from switch QCA8327-AL1A */
-+ .phy_id = QCA8327_A_PHY_ID,
-+ .phy_id_mask = QCA8K_PHY_ID_MASK,
-+ .name = "Qualcomm Atheros 8327-A internal PHY",
-+ /* PHY_GBIT_FEATURES */
-+ .link_change_notify = qca83xx_link_change_notify,
-+ .probe = at803x_probe,
-+ .flags = PHY_IS_INTERNAL,
-+ .config_init = qca8327_config_init,
-+ .soft_reset = genphy_soft_reset,
-+ .get_sset_count = qca83xx_get_sset_count,
-+ .get_strings = qca83xx_get_strings,
-+ .get_stats = qca83xx_get_stats,
-+ .suspend = qca8327_suspend,
-+ .resume = qca83xx_resume,
-+}, {
-+ /* QCA8327-B from switch QCA8327-BL1A */
-+ .phy_id = QCA8327_B_PHY_ID,
-+ .phy_id_mask = QCA8K_PHY_ID_MASK,
-+ .name = "Qualcomm Atheros 8327-B internal PHY",
-+ /* PHY_GBIT_FEATURES */
-+ .link_change_notify = qca83xx_link_change_notify,
-+ .probe = at803x_probe,
-+ .flags = PHY_IS_INTERNAL,
-+ .config_init = qca8327_config_init,
-+ .soft_reset = genphy_soft_reset,
-+ .get_sset_count = qca83xx_get_sset_count,
-+ .get_strings = qca83xx_get_strings,
-+ .get_stats = qca83xx_get_stats,
-+ .suspend = qca8327_suspend,
-+ .resume = qca83xx_resume,
-+}, {
-+ /* Qualcomm QCA8081 */
-+ PHY_ID_MATCH_EXACT(QCA8081_PHY_ID),
-+ .name = "Qualcomm QCA8081",
-+ .flags = PHY_POLL_CABLE_TEST,
-+ .probe = at803x_probe,
-+ .config_intr = at803x_config_intr,
-+ .handle_interrupt = at803x_handle_interrupt,
-+ .get_tunable = at803x_get_tunable,
-+ .set_tunable = at803x_set_tunable,
-+ .set_wol = at803x_set_wol,
-+ .get_wol = at803x_get_wol,
-+ .get_features = qca808x_get_features,
-+ .config_aneg = qca808x_config_aneg,
-+ .suspend = genphy_suspend,
-+ .resume = genphy_resume,
-+ .read_status = qca808x_read_status,
-+ .config_init = qca808x_config_init,
-+ .soft_reset = qca808x_soft_reset,
-+ .cable_test_start = qca808x_cable_test_start,
-+ .cable_test_get_status = qca808x_cable_test_get_status,
-+ .link_change_notify = qca808x_link_change_notify,
-+ .led_brightness_set = qca808x_led_brightness_set,
-+ .led_blink_set = qca808x_led_blink_set,
-+ .led_hw_is_supported = qca808x_led_hw_is_supported,
-+ .led_hw_control_set = qca808x_led_hw_control_set,
-+ .led_hw_control_get = qca808x_led_hw_control_get,
-+ .led_polarity_set = qca808x_led_polarity_set,
-+}, };
-+
-+module_phy_driver(at803x_driver);
-+
-+static struct mdio_device_id __maybe_unused atheros_tbl[] = {
-+ { ATH8030_PHY_ID, AT8030_PHY_ID_MASK },
-+ { PHY_ID_MATCH_EXACT(ATH8031_PHY_ID) },
-+ { PHY_ID_MATCH_EXACT(ATH8032_PHY_ID) },
-+ { PHY_ID_MATCH_EXACT(ATH8035_PHY_ID) },
-+ { PHY_ID_MATCH_EXACT(ATH9331_PHY_ID) },
-+ { PHY_ID_MATCH_EXACT(QCA8337_PHY_ID) },
-+ { PHY_ID_MATCH_EXACT(QCA8327_A_PHY_ID) },
-+ { PHY_ID_MATCH_EXACT(QCA8327_B_PHY_ID) },
-+ { PHY_ID_MATCH_EXACT(QCA9561_PHY_ID) },
-+ { PHY_ID_MATCH_EXACT(QCA8081_PHY_ID) },
-+ { }
-+};
-+
-+MODULE_DEVICE_TABLE(mdio, atheros_tbl);
+++ /dev/null
-From 6fb760972c49490b03f3db2ad64cf30bdd28c54a Mon Sep 17 00:00:00 2001
-Date: Mon, 29 Jan 2024 15:15:20 +0100
-Subject: [PATCH 2/5] net: phy: qcom: create and move functions to shared
- library
-
-Create and move functions to shared library in preparation for qca83xx
-PHY Family to be detached from at803x driver.
-
-Only the shared defines are moved to the shared qcom.h header.
-
----
- drivers/net/phy/qcom/Kconfig | 4 ++
- drivers/net/phy/qcom/Makefile | 1 +
- drivers/net/phy/qcom/at803x.c | 69 +----------------------------
- drivers/net/phy/qcom/qcom-phy-lib.c | 53 ++++++++++++++++++++++
- drivers/net/phy/qcom/qcom.h | 34 ++++++++++++++
- 5 files changed, 94 insertions(+), 67 deletions(-)
- create mode 100644 drivers/net/phy/qcom/qcom-phy-lib.c
- create mode 100644 drivers/net/phy/qcom/qcom.h
-
---- a/drivers/net/phy/qcom/Kconfig
-+++ b/drivers/net/phy/qcom/Kconfig
-@@ -1,6 +1,10 @@
- # SPDX-License-Identifier: GPL-2.0-only
-+config QCOM_NET_PHYLIB
-+ tristate
-+
- config AT803X_PHY
- tristate "Qualcomm Atheros AR803X PHYs and QCA833x PHYs"
-+ select QCOM_NET_PHYLIB
- depends on REGULATOR
- help
- Currently supports the AR8030, AR8031, AR8033, AR8035 and internal
---- a/drivers/net/phy/qcom/Makefile
-+++ b/drivers/net/phy/qcom/Makefile
-@@ -1,2 +1,3 @@
- # SPDX-License-Identifier: GPL-2.0
-+obj-$(CONFIG_QCOM_NET_PHYLIB) += qcom-phy-lib.o
- obj-$(CONFIG_AT803X_PHY) += at803x.o
---- a/drivers/net/phy/qcom/at803x.c
-+++ b/drivers/net/phy/qcom/at803x.c
-@@ -22,6 +22,8 @@
- #include <linux/sfp.h>
- #include <dt-bindings/net/qca-ar803x.h>
-
-+#include "qcom.h"
-+
- #define AT803X_SPECIFIC_FUNCTION_CONTROL 0x10
- #define AT803X_SFC_ASSERT_CRS BIT(11)
- #define AT803X_SFC_FORCE_LINK BIT(10)
-@@ -84,9 +86,6 @@
- #define AT803X_REG_CHIP_CONFIG 0x1f
- #define AT803X_BT_BX_REG_SEL 0x8000
-
--#define AT803X_DEBUG_ADDR 0x1D
--#define AT803X_DEBUG_DATA 0x1E
--
- #define AT803X_MODE_CFG_MASK 0x0F
- #define AT803X_MODE_CFG_BASET_RGMII 0x00
- #define AT803X_MODE_CFG_BASET_SGMII 0x01
-@@ -103,19 +102,6 @@
- #define AT803X_PSSR 0x11 /*PHY-Specific Status Register*/
- #define AT803X_PSSR_MR_AN_COMPLETE 0x0200
-
--#define AT803X_DEBUG_ANALOG_TEST_CTRL 0x00
--#define QCA8327_DEBUG_MANU_CTRL_EN BIT(2)
--#define QCA8337_DEBUG_MANU_CTRL_EN GENMASK(3, 2)
--#define AT803X_DEBUG_RX_CLK_DLY_EN BIT(15)
--
--#define AT803X_DEBUG_SYSTEM_CTRL_MODE 0x05
--#define AT803X_DEBUG_TX_CLK_DLY_EN BIT(8)
--
--#define AT803X_DEBUG_REG_HIB_CTRL 0x0b
--#define AT803X_DEBUG_HIB_CTRL_SEL_RST_80U BIT(10)
--#define AT803X_DEBUG_HIB_CTRL_EN_ANY_CHANGE BIT(13)
--#define AT803X_DEBUG_HIB_CTRL_PS_HIB_EN BIT(15)
--
- #define AT803X_DEBUG_REG_3C 0x3C
-
- #define AT803X_DEBUG_REG_GREEN 0x3D
-@@ -393,18 +379,6 @@ MODULE_DESCRIPTION("Qualcomm Atheros AR8
- MODULE_AUTHOR("Matus Ujhelyi");
- MODULE_LICENSE("GPL");
-
--enum stat_access_type {
-- PHY,
-- MMD
--};
--
--struct at803x_hw_stat {
-- const char *string;
-- u8 reg;
-- u32 mask;
-- enum stat_access_type access_type;
--};
--
- static struct at803x_hw_stat qca83xx_hw_stats[] = {
- { "phy_idle_errors", 0xa, GENMASK(7, 0), PHY},
- { "phy_receive_errors", 0x15, GENMASK(15, 0), PHY},
-@@ -439,45 +413,6 @@ struct at803x_context {
- u16 led_control;
- };
-
--static int at803x_debug_reg_write(struct phy_device *phydev, u16 reg, u16 data)
--{
-- int ret;
--
-- ret = phy_write(phydev, AT803X_DEBUG_ADDR, reg);
-- if (ret < 0)
-- return ret;
--
-- return phy_write(phydev, AT803X_DEBUG_DATA, data);
--}
--
--static int at803x_debug_reg_read(struct phy_device *phydev, u16 reg)
--{
-- int ret;
--
-- ret = phy_write(phydev, AT803X_DEBUG_ADDR, reg);
-- if (ret < 0)
-- return ret;
--
-- return phy_read(phydev, AT803X_DEBUG_DATA);
--}
--
--static int at803x_debug_reg_mask(struct phy_device *phydev, u16 reg,
-- u16 clear, u16 set)
--{
-- u16 val;
-- int ret;
--
-- ret = at803x_debug_reg_read(phydev, reg);
-- if (ret < 0)
-- return ret;
--
-- val = ret & 0xffff;
-- val &= ~clear;
-- val |= set;
--
-- return phy_write(phydev, AT803X_DEBUG_DATA, val);
--}
--
- static int at803x_write_page(struct phy_device *phydev, int page)
- {
- int mask;
---- /dev/null
-+++ b/drivers/net/phy/qcom/qcom-phy-lib.c
-@@ -0,0 +1,53 @@
-+// SPDX-License-Identifier: GPL-2.0
-+
-+#include <linux/phy.h>
-+#include <linux/module.h>
-+
-+#include "qcom.h"
-+
-+MODULE_DESCRIPTION("Qualcomm PHY driver Common Functions");
-+MODULE_AUTHOR("Matus Ujhelyi");
-+MODULE_LICENSE("GPL");
-+
-+int at803x_debug_reg_read(struct phy_device *phydev, u16 reg)
-+{
-+ int ret;
-+
-+ ret = phy_write(phydev, AT803X_DEBUG_ADDR, reg);
-+ if (ret < 0)
-+ return ret;
-+
-+ return phy_read(phydev, AT803X_DEBUG_DATA);
-+}
-+EXPORT_SYMBOL_GPL(at803x_debug_reg_read);
-+
-+int at803x_debug_reg_mask(struct phy_device *phydev, u16 reg,
-+ u16 clear, u16 set)
-+{
-+ u16 val;
-+ int ret;
-+
-+ ret = at803x_debug_reg_read(phydev, reg);
-+ if (ret < 0)
-+ return ret;
-+
-+ val = ret & 0xffff;
-+ val &= ~clear;
-+ val |= set;
-+
-+ return phy_write(phydev, AT803X_DEBUG_DATA, val);
-+}
-+EXPORT_SYMBOL_GPL(at803x_debug_reg_mask);
-+
-+int at803x_debug_reg_write(struct phy_device *phydev, u16 reg, u16 data)
-+{
-+ int ret;
-+
-+ ret = phy_write(phydev, AT803X_DEBUG_ADDR, reg);
-+ if (ret < 0)
-+ return ret;
-+
-+ return phy_write(phydev, AT803X_DEBUG_DATA, data);
-+}
-+EXPORT_SYMBOL_GPL(at803x_debug_reg_write);
---- /dev/null
-+++ b/drivers/net/phy/qcom/qcom.h
-@@ -0,0 +1,34 @@
-+/* SPDX-License-Identifier: GPL-2.0 */
-+
-+#define AT803X_DEBUG_ADDR 0x1D
-+#define AT803X_DEBUG_DATA 0x1E
-+
-+#define AT803X_DEBUG_ANALOG_TEST_CTRL 0x00
-+#define QCA8327_DEBUG_MANU_CTRL_EN BIT(2)
-+#define QCA8337_DEBUG_MANU_CTRL_EN GENMASK(3, 2)
-+#define AT803X_DEBUG_RX_CLK_DLY_EN BIT(15)
-+
-+#define AT803X_DEBUG_SYSTEM_CTRL_MODE 0x05
-+#define AT803X_DEBUG_TX_CLK_DLY_EN BIT(8)
-+
-+#define AT803X_DEBUG_REG_HIB_CTRL 0x0b
-+#define AT803X_DEBUG_HIB_CTRL_SEL_RST_80U BIT(10)
-+#define AT803X_DEBUG_HIB_CTRL_EN_ANY_CHANGE BIT(13)
-+#define AT803X_DEBUG_HIB_CTRL_PS_HIB_EN BIT(15)
-+
-+enum stat_access_type {
-+ PHY,
-+ MMD
-+};
-+
-+struct at803x_hw_stat {
-+ const char *string;
-+ u8 reg;
-+ u32 mask;
-+ enum stat_access_type access_type;
-+};
-+
-+int at803x_debug_reg_read(struct phy_device *phydev, u16 reg);
-+int at803x_debug_reg_mask(struct phy_device *phydev, u16 reg,
-+ u16 clear, u16 set);
-+int at803x_debug_reg_write(struct phy_device *phydev, u16 reg, u16 data);
+++ /dev/null
-From 2e45d404d99d43bb7127b74b5dea8818df64996c Mon Sep 17 00:00:00 2001
-Date: Mon, 29 Jan 2024 15:15:21 +0100
-Subject: [PATCH 3/5] net: phy: qcom: deatch qca83xx PHY driver from at803x
-
-Deatch qca83xx PHY driver from at803x.
-
-The QCA83xx PHYs implement specific function and doesn't use generic
-at803x so it can be detached from the driver and moved to a dedicated
-one.
-
-Probe function and priv struct is reimplemented to allocate and use
-only the qca83xx specific data. Unused data from at803x PHY driver
-are dropped from at803x priv struct.
-
-This is to make slimmer PHY drivers instead of including lots of bloat
-that would never be used in specific SoC.
-
-A new Kconfig flag QCA83XX_PHY is introduced to compile the new
-introduced PHY driver.
-
-As the Kconfig name starts with Qualcomm the same order is kept.
-
----
- drivers/net/phy/qcom/Kconfig | 11 +-
- drivers/net/phy/qcom/Makefile | 1 +
- drivers/net/phy/qcom/at803x.c | 235 ----------------------------
- drivers/net/phy/qcom/qca83xx.c | 275 +++++++++++++++++++++++++++++++++
- 4 files changed, 284 insertions(+), 238 deletions(-)
- create mode 100644 drivers/net/phy/qcom/qca83xx.c
-
---- a/drivers/net/phy/qcom/Kconfig
-+++ b/drivers/net/phy/qcom/Kconfig
-@@ -3,9 +3,14 @@ config QCOM_NET_PHYLIB
- tristate
-
- config AT803X_PHY
-- tristate "Qualcomm Atheros AR803X PHYs and QCA833x PHYs"
-+ tristate "Qualcomm Atheros AR803X PHYs"
- select QCOM_NET_PHYLIB
- depends on REGULATOR
- help
-- Currently supports the AR8030, AR8031, AR8033, AR8035 and internal
-- QCA8337(Internal qca8k PHY) model
-+ Currently supports the AR8030, AR8031, AR8033, AR8035 model
-+
-+config QCA83XX_PHY
-+ tristate "Qualcomm Atheros QCA833x PHYs"
-+ select QCOM_NET_PHYLIB
-+ help
-+ Currently supports the internal QCA8337(Internal qca8k PHY) model
---- a/drivers/net/phy/qcom/Makefile
-+++ b/drivers/net/phy/qcom/Makefile
-@@ -1,3 +1,4 @@
- # SPDX-License-Identifier: GPL-2.0
- obj-$(CONFIG_QCOM_NET_PHYLIB) += qcom-phy-lib.o
- obj-$(CONFIG_AT803X_PHY) += at803x.o
-+obj-$(CONFIG_QCA83XX_PHY) += qca83xx.o
---- a/drivers/net/phy/qcom/at803x.c
-+++ b/drivers/net/phy/qcom/at803x.c
-@@ -102,17 +102,10 @@
- #define AT803X_PSSR 0x11 /*PHY-Specific Status Register*/
- #define AT803X_PSSR_MR_AN_COMPLETE 0x0200
-
--#define AT803X_DEBUG_REG_3C 0x3C
--
--#define AT803X_DEBUG_REG_GREEN 0x3D
--#define AT803X_DEBUG_GATE_CLK_IN1000 BIT(6)
--
- #define AT803X_DEBUG_REG_1F 0x1F
- #define AT803X_DEBUG_PLL_ON BIT(2)
- #define AT803X_DEBUG_RGMII_1V8 BIT(3)
-
--#define MDIO_AZ_DEBUG 0x800D
--
- /* AT803x supports either the XTAL input pad, an internal PLL or the
- * DSP as clock reference for the clock output pad. The XTAL reference
- * is only used for 25 MHz output, all other frequencies need the PLL.
-@@ -163,13 +156,7 @@
-
- #define QCA8081_PHY_ID 0x004dd101
-
--#define QCA8327_A_PHY_ID 0x004dd033
--#define QCA8327_B_PHY_ID 0x004dd034
--#define QCA8337_PHY_ID 0x004dd036
- #define QCA9561_PHY_ID 0x004dd042
--#define QCA8K_PHY_ID_MASK 0xffffffff
--
--#define QCA8K_DEVFLAGS_REVISION_MASK GENMASK(2, 0)
-
- #define AT803X_PAGE_FIBER 0
- #define AT803X_PAGE_COPPER 1
-@@ -379,12 +366,6 @@ MODULE_DESCRIPTION("Qualcomm Atheros AR8
- MODULE_AUTHOR("Matus Ujhelyi");
- MODULE_LICENSE("GPL");
-
--static struct at803x_hw_stat qca83xx_hw_stats[] = {
-- { "phy_idle_errors", 0xa, GENMASK(7, 0), PHY},
-- { "phy_receive_errors", 0x15, GENMASK(15, 0), PHY},
-- { "eee_wake_errors", 0x16, GENMASK(15, 0), MMD},
--};
--
- struct at803x_ss_mask {
- u16 speed_mask;
- u8 speed_shift;
-@@ -400,7 +381,6 @@ struct at803x_priv {
- bool is_1000basex;
- struct regulator_dev *vddio_rdev;
- struct regulator_dev *vddh_rdev;
-- u64 stats[ARRAY_SIZE(qca83xx_hw_stats)];
- int led_polarity_mode;
- };
-
-@@ -564,53 +544,6 @@ static void at803x_get_wol(struct phy_de
- wol->wolopts |= WAKE_MAGIC;
- }
-
--static int qca83xx_get_sset_count(struct phy_device *phydev)
--{
-- return ARRAY_SIZE(qca83xx_hw_stats);
--}
--
--static void qca83xx_get_strings(struct phy_device *phydev, u8 *data)
--{
-- int i;
--
-- for (i = 0; i < ARRAY_SIZE(qca83xx_hw_stats); i++) {
-- strscpy(data + i * ETH_GSTRING_LEN,
-- qca83xx_hw_stats[i].string, ETH_GSTRING_LEN);
-- }
--}
--
--static u64 qca83xx_get_stat(struct phy_device *phydev, int i)
--{
-- struct at803x_hw_stat stat = qca83xx_hw_stats[i];
-- struct at803x_priv *priv = phydev->priv;
-- int val;
-- u64 ret;
--
-- if (stat.access_type == MMD)
-- val = phy_read_mmd(phydev, MDIO_MMD_PCS, stat.reg);
-- else
-- val = phy_read(phydev, stat.reg);
--
-- if (val < 0) {
-- ret = U64_MAX;
-- } else {
-- val = val & stat.mask;
-- priv->stats[i] += val;
-- ret = priv->stats[i];
-- }
--
-- return ret;
--}
--
--static void qca83xx_get_stats(struct phy_device *phydev,
-- struct ethtool_stats *stats, u64 *data)
--{
-- int i;
--
-- for (i = 0; i < ARRAY_SIZE(qca83xx_hw_stats); i++)
-- data[i] = qca83xx_get_stat(phydev, i);
--}
--
- static int at803x_suspend(struct phy_device *phydev)
- {
- int value;
-@@ -1707,124 +1640,6 @@ static int at8035_probe(struct phy_devic
- return at8035_parse_dt(phydev);
- }
-
--static int qca83xx_config_init(struct phy_device *phydev)
--{
-- u8 switch_revision;
--
-- switch_revision = phydev->dev_flags & QCA8K_DEVFLAGS_REVISION_MASK;
--
-- switch (switch_revision) {
-- case 1:
-- /* For 100M waveform */
-- at803x_debug_reg_write(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL, 0x02ea);
-- /* Turn on Gigabit clock */
-- at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_GREEN, 0x68a0);
-- break;
--
-- case 2:
-- phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV, 0x0);
-- fallthrough;
-- case 4:
-- phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_AZ_DEBUG, 0x803f);
-- at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_GREEN, 0x6860);
-- at803x_debug_reg_write(phydev, AT803X_DEBUG_SYSTEM_CTRL_MODE, 0x2c46);
-- at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_3C, 0x6000);
-- break;
-- }
--
-- /* Following original QCA sourcecode set port to prefer master */
-- phy_set_bits(phydev, MII_CTRL1000, CTL1000_PREFER_MASTER);
--
-- return 0;
--}
--
--static int qca8327_config_init(struct phy_device *phydev)
--{
-- /* QCA8327 require DAC amplitude adjustment for 100m set to +6%.
-- * Disable on init and enable only with 100m speed following
-- * qca original source code.
-- */
-- at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL,
-- QCA8327_DEBUG_MANU_CTRL_EN, 0);
--
-- return qca83xx_config_init(phydev);
--}
--
--static void qca83xx_link_change_notify(struct phy_device *phydev)
--{
-- /* Set DAC Amplitude adjustment to +6% for 100m on link running */
-- if (phydev->state == PHY_RUNNING) {
-- if (phydev->speed == SPEED_100)
-- at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL,
-- QCA8327_DEBUG_MANU_CTRL_EN,
-- QCA8327_DEBUG_MANU_CTRL_EN);
-- } else {
-- /* Reset DAC Amplitude adjustment */
-- at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL,
-- QCA8327_DEBUG_MANU_CTRL_EN, 0);
-- }
--}
--
--static int qca83xx_resume(struct phy_device *phydev)
--{
-- int ret, val;
--
-- /* Skip reset if not suspended */
-- if (!phydev->suspended)
-- return 0;
--
-- /* Reinit the port, reset values set by suspend */
-- qca83xx_config_init(phydev);
--
-- /* Reset the port on port resume */
-- phy_set_bits(phydev, MII_BMCR, BMCR_RESET | BMCR_ANENABLE);
--
-- /* On resume from suspend the switch execute a reset and
-- * restart auto-negotiation. Wait for reset to complete.
-- */
-- ret = phy_read_poll_timeout(phydev, MII_BMCR, val, !(val & BMCR_RESET),
-- 50000, 600000, true);
-- if (ret)
-- return ret;
--
-- usleep_range(1000, 2000);
--
-- return 0;
--}
--
--static int qca83xx_suspend(struct phy_device *phydev)
--{
-- at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_GREEN,
-- AT803X_DEBUG_GATE_CLK_IN1000, 0);
--
-- at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_HIB_CTRL,
-- AT803X_DEBUG_HIB_CTRL_EN_ANY_CHANGE |
-- AT803X_DEBUG_HIB_CTRL_SEL_RST_80U, 0);
--
-- return 0;
--}
--
--static int qca8337_suspend(struct phy_device *phydev)
--{
-- /* Only QCA8337 support actual suspend. */
-- genphy_suspend(phydev);
--
-- return qca83xx_suspend(phydev);
--}
--
--static int qca8327_suspend(struct phy_device *phydev)
--{
-- u16 mask = 0;
--
-- /* QCA8327 cause port unreliability when phy suspend
-- * is set.
-- */
-- mask |= ~(BMCR_SPEED1000 | BMCR_FULLDPLX);
-- phy_modify(phydev, MII_BMCR, mask, 0);
--
-- return qca83xx_suspend(phydev);
--}
--
- static int qca808x_phy_fast_retrain_config(struct phy_device *phydev)
- {
- int ret;
-@@ -2599,53 +2414,6 @@ static struct phy_driver at803x_driver[]
- .soft_reset = genphy_soft_reset,
- .config_aneg = at803x_config_aneg,
- }, {
-- /* QCA8337 */
-- .phy_id = QCA8337_PHY_ID,
-- .phy_id_mask = QCA8K_PHY_ID_MASK,
-- .name = "Qualcomm Atheros 8337 internal PHY",
-- /* PHY_GBIT_FEATURES */
-- .probe = at803x_probe,
-- .flags = PHY_IS_INTERNAL,
-- .config_init = qca83xx_config_init,
-- .soft_reset = genphy_soft_reset,
-- .get_sset_count = qca83xx_get_sset_count,
-- .get_strings = qca83xx_get_strings,
-- .get_stats = qca83xx_get_stats,
-- .suspend = qca8337_suspend,
-- .resume = qca83xx_resume,
--}, {
-- /* QCA8327-A from switch QCA8327-AL1A */
-- .phy_id = QCA8327_A_PHY_ID,
-- .phy_id_mask = QCA8K_PHY_ID_MASK,
-- .name = "Qualcomm Atheros 8327-A internal PHY",
-- /* PHY_GBIT_FEATURES */
-- .link_change_notify = qca83xx_link_change_notify,
-- .probe = at803x_probe,
-- .flags = PHY_IS_INTERNAL,
-- .config_init = qca8327_config_init,
-- .soft_reset = genphy_soft_reset,
-- .get_sset_count = qca83xx_get_sset_count,
-- .get_strings = qca83xx_get_strings,
-- .get_stats = qca83xx_get_stats,
-- .suspend = qca8327_suspend,
-- .resume = qca83xx_resume,
--}, {
-- /* QCA8327-B from switch QCA8327-BL1A */
-- .phy_id = QCA8327_B_PHY_ID,
-- .phy_id_mask = QCA8K_PHY_ID_MASK,
-- .name = "Qualcomm Atheros 8327-B internal PHY",
-- /* PHY_GBIT_FEATURES */
-- .link_change_notify = qca83xx_link_change_notify,
-- .probe = at803x_probe,
-- .flags = PHY_IS_INTERNAL,
-- .config_init = qca8327_config_init,
-- .soft_reset = genphy_soft_reset,
-- .get_sset_count = qca83xx_get_sset_count,
-- .get_strings = qca83xx_get_strings,
-- .get_stats = qca83xx_get_stats,
-- .suspend = qca8327_suspend,
-- .resume = qca83xx_resume,
--}, {
- /* Qualcomm QCA8081 */
- PHY_ID_MATCH_EXACT(QCA8081_PHY_ID),
- .name = "Qualcomm QCA8081",
-@@ -2683,9 +2451,6 @@ static struct mdio_device_id __maybe_unu
- { PHY_ID_MATCH_EXACT(ATH8032_PHY_ID) },
- { PHY_ID_MATCH_EXACT(ATH8035_PHY_ID) },
- { PHY_ID_MATCH_EXACT(ATH9331_PHY_ID) },
-- { PHY_ID_MATCH_EXACT(QCA8337_PHY_ID) },
-- { PHY_ID_MATCH_EXACT(QCA8327_A_PHY_ID) },
-- { PHY_ID_MATCH_EXACT(QCA8327_B_PHY_ID) },
- { PHY_ID_MATCH_EXACT(QCA9561_PHY_ID) },
- { PHY_ID_MATCH_EXACT(QCA8081_PHY_ID) },
- { }
---- /dev/null
-+++ b/drivers/net/phy/qcom/qca83xx.c
-@@ -0,0 +1,275 @@
-+// SPDX-License-Identifier: GPL-2.0+
-+
-+#include <linux/phy.h>
-+#include <linux/module.h>
-+
-+#include "qcom.h"
-+
-+#define AT803X_DEBUG_REG_3C 0x3C
-+
-+#define AT803X_DEBUG_REG_GREEN 0x3D
-+#define AT803X_DEBUG_GATE_CLK_IN1000 BIT(6)
-+
-+#define MDIO_AZ_DEBUG 0x800D
-+
-+#define QCA8327_A_PHY_ID 0x004dd033
-+#define QCA8327_B_PHY_ID 0x004dd034
-+#define QCA8337_PHY_ID 0x004dd036
-+#define QCA8K_PHY_ID_MASK 0xffffffff
-+
-+#define QCA8K_DEVFLAGS_REVISION_MASK GENMASK(2, 0)
-+
-+static struct at803x_hw_stat qca83xx_hw_stats[] = {
-+ { "phy_idle_errors", 0xa, GENMASK(7, 0), PHY},
-+ { "phy_receive_errors", 0x15, GENMASK(15, 0), PHY},
-+ { "eee_wake_errors", 0x16, GENMASK(15, 0), MMD},
-+};
-+
-+struct qca83xx_priv {
-+ u64 stats[ARRAY_SIZE(qca83xx_hw_stats)];
-+};
-+
-+MODULE_DESCRIPTION("Qualcomm Atheros QCA83XX PHY driver");
-+MODULE_AUTHOR("Matus Ujhelyi");
-+MODULE_LICENSE("GPL");
-+
-+static int qca83xx_get_sset_count(struct phy_device *phydev)
-+{
-+ return ARRAY_SIZE(qca83xx_hw_stats);
-+}
-+
-+static void qca83xx_get_strings(struct phy_device *phydev, u8 *data)
-+{
-+ int i;
-+
-+ for (i = 0; i < ARRAY_SIZE(qca83xx_hw_stats); i++) {
-+ strscpy(data + i * ETH_GSTRING_LEN,
-+ qca83xx_hw_stats[i].string, ETH_GSTRING_LEN);
-+ }
-+}
-+
-+static u64 qca83xx_get_stat(struct phy_device *phydev, int i)
-+{
-+ struct at803x_hw_stat stat = qca83xx_hw_stats[i];
-+ struct qca83xx_priv *priv = phydev->priv;
-+ int val;
-+ u64 ret;
-+
-+ if (stat.access_type == MMD)
-+ val = phy_read_mmd(phydev, MDIO_MMD_PCS, stat.reg);
-+ else
-+ val = phy_read(phydev, stat.reg);
-+
-+ if (val < 0) {
-+ ret = U64_MAX;
-+ } else {
-+ val = val & stat.mask;
-+ priv->stats[i] += val;
-+ ret = priv->stats[i];
-+ }
-+
-+ return ret;
-+}
-+
-+static void qca83xx_get_stats(struct phy_device *phydev,
-+ struct ethtool_stats *stats, u64 *data)
-+{
-+ int i;
-+
-+ for (i = 0; i < ARRAY_SIZE(qca83xx_hw_stats); i++)
-+ data[i] = qca83xx_get_stat(phydev, i);
-+}
-+
-+static int qca83xx_probe(struct phy_device *phydev)
-+{
-+ struct device *dev = &phydev->mdio.dev;
-+ struct qca83xx_priv *priv;
-+
-+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
-+ if (!priv)
-+ return -ENOMEM;
-+
-+ phydev->priv = priv;
-+
-+ return 0;
-+}
-+
-+static int qca83xx_config_init(struct phy_device *phydev)
-+{
-+ u8 switch_revision;
-+
-+ switch_revision = phydev->dev_flags & QCA8K_DEVFLAGS_REVISION_MASK;
-+
-+ switch (switch_revision) {
-+ case 1:
-+ /* For 100M waveform */
-+ at803x_debug_reg_write(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL, 0x02ea);
-+ /* Turn on Gigabit clock */
-+ at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_GREEN, 0x68a0);
-+ break;
-+
-+ case 2:
-+ phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV, 0x0);
-+ fallthrough;
-+ case 4:
-+ phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_AZ_DEBUG, 0x803f);
-+ at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_GREEN, 0x6860);
-+ at803x_debug_reg_write(phydev, AT803X_DEBUG_SYSTEM_CTRL_MODE, 0x2c46);
-+ at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_3C, 0x6000);
-+ break;
-+ }
-+
-+ /* Following original QCA sourcecode set port to prefer master */
-+ phy_set_bits(phydev, MII_CTRL1000, CTL1000_PREFER_MASTER);
-+
-+ return 0;
-+}
-+
-+static int qca8327_config_init(struct phy_device *phydev)
-+{
-+ /* QCA8327 require DAC amplitude adjustment for 100m set to +6%.
-+ * Disable on init and enable only with 100m speed following
-+ * qca original source code.
-+ */
-+ at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL,
-+ QCA8327_DEBUG_MANU_CTRL_EN, 0);
-+
-+ return qca83xx_config_init(phydev);
-+}
-+
-+static void qca83xx_link_change_notify(struct phy_device *phydev)
-+{
-+ /* Set DAC Amplitude adjustment to +6% for 100m on link running */
-+ if (phydev->state == PHY_RUNNING) {
-+ if (phydev->speed == SPEED_100)
-+ at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL,
-+ QCA8327_DEBUG_MANU_CTRL_EN,
-+ QCA8327_DEBUG_MANU_CTRL_EN);
-+ } else {
-+ /* Reset DAC Amplitude adjustment */
-+ at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL,
-+ QCA8327_DEBUG_MANU_CTRL_EN, 0);
-+ }
-+}
-+
-+static int qca83xx_resume(struct phy_device *phydev)
-+{
-+ int ret, val;
-+
-+ /* Skip reset if not suspended */
-+ if (!phydev->suspended)
-+ return 0;
-+
-+ /* Reinit the port, reset values set by suspend */
-+ qca83xx_config_init(phydev);
-+
-+ /* Reset the port on port resume */
-+ phy_set_bits(phydev, MII_BMCR, BMCR_RESET | BMCR_ANENABLE);
-+
-+ /* On resume from suspend the switch execute a reset and
-+ * restart auto-negotiation. Wait for reset to complete.
-+ */
-+ ret = phy_read_poll_timeout(phydev, MII_BMCR, val, !(val & BMCR_RESET),
-+ 50000, 600000, true);
-+ if (ret)
-+ return ret;
-+
-+ usleep_range(1000, 2000);
-+
-+ return 0;
-+}
-+
-+static int qca83xx_suspend(struct phy_device *phydev)
-+{
-+ at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_GREEN,
-+ AT803X_DEBUG_GATE_CLK_IN1000, 0);
-+
-+ at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_HIB_CTRL,
-+ AT803X_DEBUG_HIB_CTRL_EN_ANY_CHANGE |
-+ AT803X_DEBUG_HIB_CTRL_SEL_RST_80U, 0);
-+
-+ return 0;
-+}
-+
-+static int qca8337_suspend(struct phy_device *phydev)
-+{
-+ /* Only QCA8337 support actual suspend. */
-+ genphy_suspend(phydev);
-+
-+ return qca83xx_suspend(phydev);
-+}
-+
-+static int qca8327_suspend(struct phy_device *phydev)
-+{
-+ u16 mask = 0;
-+
-+ /* QCA8327 cause port unreliability when phy suspend
-+ * is set.
-+ */
-+ mask |= ~(BMCR_SPEED1000 | BMCR_FULLDPLX);
-+ phy_modify(phydev, MII_BMCR, mask, 0);
-+
-+ return qca83xx_suspend(phydev);
-+}
-+
-+static struct phy_driver qca83xx_driver[] = {
-+{
-+ /* QCA8337 */
-+ .phy_id = QCA8337_PHY_ID,
-+ .phy_id_mask = QCA8K_PHY_ID_MASK,
-+ .name = "Qualcomm Atheros 8337 internal PHY",
-+ /* PHY_GBIT_FEATURES */
-+ .probe = qca83xx_probe,
-+ .flags = PHY_IS_INTERNAL,
-+ .config_init = qca83xx_config_init,
-+ .soft_reset = genphy_soft_reset,
-+ .get_sset_count = qca83xx_get_sset_count,
-+ .get_strings = qca83xx_get_strings,
-+ .get_stats = qca83xx_get_stats,
-+ .suspend = qca8337_suspend,
-+ .resume = qca83xx_resume,
-+}, {
-+ /* QCA8327-A from switch QCA8327-AL1A */
-+ .phy_id = QCA8327_A_PHY_ID,
-+ .phy_id_mask = QCA8K_PHY_ID_MASK,
-+ .name = "Qualcomm Atheros 8327-A internal PHY",
-+ /* PHY_GBIT_FEATURES */
-+ .link_change_notify = qca83xx_link_change_notify,
-+ .probe = qca83xx_probe,
-+ .flags = PHY_IS_INTERNAL,
-+ .config_init = qca8327_config_init,
-+ .soft_reset = genphy_soft_reset,
-+ .get_sset_count = qca83xx_get_sset_count,
-+ .get_strings = qca83xx_get_strings,
-+ .get_stats = qca83xx_get_stats,
-+ .suspend = qca8327_suspend,
-+ .resume = qca83xx_resume,
-+}, {
-+ /* QCA8327-B from switch QCA8327-BL1A */
-+ .phy_id = QCA8327_B_PHY_ID,
-+ .phy_id_mask = QCA8K_PHY_ID_MASK,
-+ .name = "Qualcomm Atheros 8327-B internal PHY",
-+ /* PHY_GBIT_FEATURES */
-+ .link_change_notify = qca83xx_link_change_notify,
-+ .probe = qca83xx_probe,
-+ .flags = PHY_IS_INTERNAL,
-+ .config_init = qca8327_config_init,
-+ .soft_reset = genphy_soft_reset,
-+ .get_sset_count = qca83xx_get_sset_count,
-+ .get_strings = qca83xx_get_strings,
-+ .get_stats = qca83xx_get_stats,
-+ .suspend = qca8327_suspend,
-+ .resume = qca83xx_resume,
-+}, };
-+
-+module_phy_driver(qca83xx_driver);
-+
-+static struct mdio_device_id __maybe_unused qca83xx_tbl[] = {
-+ { PHY_ID_MATCH_EXACT(QCA8337_PHY_ID) },
-+ { PHY_ID_MATCH_EXACT(QCA8327_A_PHY_ID) },
-+ { PHY_ID_MATCH_EXACT(QCA8327_B_PHY_ID) },
-+ { }
-+};
-+
-+MODULE_DEVICE_TABLE(mdio, qca83xx_tbl);
+++ /dev/null
-From 249d2b80e4db0e38503ed0ec2af6c7401bc099b9 Mon Sep 17 00:00:00 2001
-Date: Mon, 29 Jan 2024 15:15:22 +0100
-Subject: [PATCH 4/5] net: phy: qcom: move additional functions to shared
- library
-
-Move additional functions to shared library in preparation for qca808x
-PHY Family to be detached from at803x driver.
-
-Only the shared defines are moved to the shared qcom.h header.
-
----
- drivers/net/phy/qcom/at803x.c | 426 +---------------------------
- drivers/net/phy/qcom/qcom-phy-lib.c | 376 ++++++++++++++++++++++++
- drivers/net/phy/qcom/qcom.h | 86 ++++++
- 3 files changed, 463 insertions(+), 425 deletions(-)
-
---- a/drivers/net/phy/qcom/at803x.c
-+++ b/drivers/net/phy/qcom/at803x.c
-@@ -24,65 +24,11 @@
-
- #include "qcom.h"
-
--#define AT803X_SPECIFIC_FUNCTION_CONTROL 0x10
--#define AT803X_SFC_ASSERT_CRS BIT(11)
--#define AT803X_SFC_FORCE_LINK BIT(10)
--#define AT803X_SFC_MDI_CROSSOVER_MODE_M GENMASK(6, 5)
--#define AT803X_SFC_AUTOMATIC_CROSSOVER 0x3
--#define AT803X_SFC_MANUAL_MDIX 0x1
--#define AT803X_SFC_MANUAL_MDI 0x0
--#define AT803X_SFC_SQE_TEST BIT(2)
--#define AT803X_SFC_POLARITY_REVERSAL BIT(1)
--#define AT803X_SFC_DISABLE_JABBER BIT(0)
--
--#define AT803X_SPECIFIC_STATUS 0x11
--#define AT803X_SS_SPEED_MASK GENMASK(15, 14)
--#define AT803X_SS_SPEED_1000 2
--#define AT803X_SS_SPEED_100 1
--#define AT803X_SS_SPEED_10 0
--#define AT803X_SS_DUPLEX BIT(13)
--#define AT803X_SS_SPEED_DUPLEX_RESOLVED BIT(11)
--#define AT803X_SS_MDIX BIT(6)
--
--#define QCA808X_SS_SPEED_MASK GENMASK(9, 7)
--#define QCA808X_SS_SPEED_2500 4
--
--#define AT803X_INTR_ENABLE 0x12
--#define AT803X_INTR_ENABLE_AUTONEG_ERR BIT(15)
--#define AT803X_INTR_ENABLE_SPEED_CHANGED BIT(14)
--#define AT803X_INTR_ENABLE_DUPLEX_CHANGED BIT(13)
--#define AT803X_INTR_ENABLE_PAGE_RECEIVED BIT(12)
--#define AT803X_INTR_ENABLE_LINK_FAIL BIT(11)
--#define AT803X_INTR_ENABLE_LINK_SUCCESS BIT(10)
--#define AT803X_INTR_ENABLE_LINK_FAIL_BX BIT(8)
--#define AT803X_INTR_ENABLE_LINK_SUCCESS_BX BIT(7)
--#define AT803X_INTR_ENABLE_WIRESPEED_DOWNGRADE BIT(5)
--#define AT803X_INTR_ENABLE_POLARITY_CHANGED BIT(1)
--#define AT803X_INTR_ENABLE_WOL BIT(0)
--
--#define AT803X_INTR_STATUS 0x13
--
--#define AT803X_SMART_SPEED 0x14
--#define AT803X_SMART_SPEED_ENABLE BIT(5)
--#define AT803X_SMART_SPEED_RETRY_LIMIT_MASK GENMASK(4, 2)
--#define AT803X_SMART_SPEED_BYPASS_TIMER BIT(1)
--#define AT803X_CDT 0x16
--#define AT803X_CDT_MDI_PAIR_MASK GENMASK(9, 8)
--#define AT803X_CDT_ENABLE_TEST BIT(0)
--#define AT803X_CDT_STATUS 0x1c
--#define AT803X_CDT_STATUS_STAT_NORMAL 0
--#define AT803X_CDT_STATUS_STAT_SHORT 1
--#define AT803X_CDT_STATUS_STAT_OPEN 2
--#define AT803X_CDT_STATUS_STAT_FAIL 3
--#define AT803X_CDT_STATUS_STAT_MASK GENMASK(9, 8)
--#define AT803X_CDT_STATUS_DELTA_TIME_MASK GENMASK(7, 0)
- #define AT803X_LED_CONTROL 0x18
-
- #define AT803X_PHY_MMD3_WOL_CTRL 0x8012
- #define AT803X_WOL_EN BIT(5)
--#define AT803X_LOC_MAC_ADDR_0_15_OFFSET 0x804C
--#define AT803X_LOC_MAC_ADDR_16_31_OFFSET 0x804B
--#define AT803X_LOC_MAC_ADDR_32_47_OFFSET 0x804A
-+
- #define AT803X_REG_CHIP_CONFIG 0x1f
- #define AT803X_BT_BX_REG_SEL 0x8000
-
-@@ -138,10 +84,6 @@
- #define AT803X_CLK_OUT_STRENGTH_HALF 1
- #define AT803X_CLK_OUT_STRENGTH_QUARTER 2
-
--#define AT803X_DEFAULT_DOWNSHIFT 5
--#define AT803X_MIN_DOWNSHIFT 2
--#define AT803X_MAX_DOWNSHIFT 9
--
- #define AT803X_MMD3_SMARTEEE_CTL1 0x805b
- #define AT803X_MMD3_SMARTEEE_CTL2 0x805c
- #define AT803X_MMD3_SMARTEEE_CTL3 0x805d
-@@ -366,11 +308,6 @@ MODULE_DESCRIPTION("Qualcomm Atheros AR8
- MODULE_AUTHOR("Matus Ujhelyi");
- MODULE_LICENSE("GPL");
-
--struct at803x_ss_mask {
-- u16 speed_mask;
-- u8 speed_shift;
--};
--
- struct at803x_priv {
- int flags;
- u16 clk_25m_reg;
-@@ -470,80 +407,6 @@ static void at803x_context_restore(struc
- phy_write(phydev, AT803X_LED_CONTROL, context->led_control);
- }
-
--static int at803x_set_wol(struct phy_device *phydev,
-- struct ethtool_wolinfo *wol)
--{
-- int ret, irq_enabled;
--
-- if (wol->wolopts & WAKE_MAGIC) {
-- struct net_device *ndev = phydev->attached_dev;
-- const u8 *mac;
-- unsigned int i;
-- static const unsigned int offsets[] = {
-- AT803X_LOC_MAC_ADDR_32_47_OFFSET,
-- AT803X_LOC_MAC_ADDR_16_31_OFFSET,
-- AT803X_LOC_MAC_ADDR_0_15_OFFSET,
-- };
--
-- if (!ndev)
-- return -ENODEV;
--
-- mac = (const u8 *)ndev->dev_addr;
--
-- if (!is_valid_ether_addr(mac))
-- return -EINVAL;
--
-- for (i = 0; i < 3; i++)
-- phy_write_mmd(phydev, MDIO_MMD_PCS, offsets[i],
-- mac[(i * 2) + 1] | (mac[(i * 2)] << 8));
--
-- /* Enable WOL interrupt */
-- ret = phy_modify(phydev, AT803X_INTR_ENABLE, 0, AT803X_INTR_ENABLE_WOL);
-- if (ret)
-- return ret;
-- } else {
-- /* Disable WOL interrupt */
-- ret = phy_modify(phydev, AT803X_INTR_ENABLE, AT803X_INTR_ENABLE_WOL, 0);
-- if (ret)
-- return ret;
-- }
--
-- /* Clear WOL status */
-- ret = phy_read(phydev, AT803X_INTR_STATUS);
-- if (ret < 0)
-- return ret;
--
-- /* Check if there are other interrupts except for WOL triggered when PHY is
-- * in interrupt mode, only the interrupts enabled by AT803X_INTR_ENABLE can
-- * be passed up to the interrupt PIN.
-- */
-- irq_enabled = phy_read(phydev, AT803X_INTR_ENABLE);
-- if (irq_enabled < 0)
-- return irq_enabled;
--
-- irq_enabled &= ~AT803X_INTR_ENABLE_WOL;
-- if (ret & irq_enabled && !phy_polling_mode(phydev))
-- phy_trigger_machine(phydev);
--
-- return 0;
--}
--
--static void at803x_get_wol(struct phy_device *phydev,
-- struct ethtool_wolinfo *wol)
--{
-- int value;
--
-- wol->supported = WAKE_MAGIC;
-- wol->wolopts = 0;
--
-- value = phy_read(phydev, AT803X_INTR_ENABLE);
-- if (value < 0)
-- return;
--
-- if (value & AT803X_INTR_ENABLE_WOL)
-- wol->wolopts |= WAKE_MAGIC;
--}
--
- static int at803x_suspend(struct phy_device *phydev)
- {
- int value;
-@@ -816,73 +679,6 @@ static int at803x_config_init(struct phy
- return phy_modify(phydev, MII_ADVERTISE, MDIO_AN_CTRL1_XNP, 0);
- }
-
--static int at803x_ack_interrupt(struct phy_device *phydev)
--{
-- int err;
--
-- err = phy_read(phydev, AT803X_INTR_STATUS);
--
-- return (err < 0) ? err : 0;
--}
--
--static int at803x_config_intr(struct phy_device *phydev)
--{
-- int err;
-- int value;
--
-- value = phy_read(phydev, AT803X_INTR_ENABLE);
--
-- if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
-- /* Clear any pending interrupts */
-- err = at803x_ack_interrupt(phydev);
-- if (err)
-- return err;
--
-- value |= AT803X_INTR_ENABLE_AUTONEG_ERR;
-- value |= AT803X_INTR_ENABLE_SPEED_CHANGED;
-- value |= AT803X_INTR_ENABLE_DUPLEX_CHANGED;
-- value |= AT803X_INTR_ENABLE_LINK_FAIL;
-- value |= AT803X_INTR_ENABLE_LINK_SUCCESS;
--
-- err = phy_write(phydev, AT803X_INTR_ENABLE, value);
-- } else {
-- err = phy_write(phydev, AT803X_INTR_ENABLE, 0);
-- if (err)
-- return err;
--
-- /* Clear any pending interrupts */
-- err = at803x_ack_interrupt(phydev);
-- }
--
-- return err;
--}
--
--static irqreturn_t at803x_handle_interrupt(struct phy_device *phydev)
--{
-- int irq_status, int_enabled;
--
-- irq_status = phy_read(phydev, AT803X_INTR_STATUS);
-- if (irq_status < 0) {
-- phy_error(phydev);
-- return IRQ_NONE;
-- }
--
-- /* Read the current enabled interrupts */
-- int_enabled = phy_read(phydev, AT803X_INTR_ENABLE);
-- if (int_enabled < 0) {
-- phy_error(phydev);
-- return IRQ_NONE;
-- }
--
-- /* See if this was one of our enabled interrupts */
-- if (!(irq_status & int_enabled))
-- return IRQ_NONE;
--
-- phy_trigger_machine(phydev);
--
-- return IRQ_HANDLED;
--}
--
- static void at803x_link_change_notify(struct phy_device *phydev)
- {
- /*
-@@ -908,69 +704,6 @@ static void at803x_link_change_notify(st
- }
- }
-
--static int at803x_read_specific_status(struct phy_device *phydev,
-- struct at803x_ss_mask ss_mask)
--{
-- int ss;
--
-- /* Read the AT8035 PHY-Specific Status register, which indicates the
-- * speed and duplex that the PHY is actually using, irrespective of
-- * whether we are in autoneg mode or not.
-- */
-- ss = phy_read(phydev, AT803X_SPECIFIC_STATUS);
-- if (ss < 0)
-- return ss;
--
-- if (ss & AT803X_SS_SPEED_DUPLEX_RESOLVED) {
-- int sfc, speed;
--
-- sfc = phy_read(phydev, AT803X_SPECIFIC_FUNCTION_CONTROL);
-- if (sfc < 0)
-- return sfc;
--
-- speed = ss & ss_mask.speed_mask;
-- speed >>= ss_mask.speed_shift;
--
-- switch (speed) {
-- case AT803X_SS_SPEED_10:
-- phydev->speed = SPEED_10;
-- break;
-- case AT803X_SS_SPEED_100:
-- phydev->speed = SPEED_100;
-- break;
-- case AT803X_SS_SPEED_1000:
-- phydev->speed = SPEED_1000;
-- break;
-- case QCA808X_SS_SPEED_2500:
-- phydev->speed = SPEED_2500;
-- break;
-- }
-- if (ss & AT803X_SS_DUPLEX)
-- phydev->duplex = DUPLEX_FULL;
-- else
-- phydev->duplex = DUPLEX_HALF;
--
-- if (ss & AT803X_SS_MDIX)
-- phydev->mdix = ETH_TP_MDI_X;
-- else
-- phydev->mdix = ETH_TP_MDI;
--
-- switch (FIELD_GET(AT803X_SFC_MDI_CROSSOVER_MODE_M, sfc)) {
-- case AT803X_SFC_MANUAL_MDI:
-- phydev->mdix_ctrl = ETH_TP_MDI;
-- break;
-- case AT803X_SFC_MANUAL_MDIX:
-- phydev->mdix_ctrl = ETH_TP_MDI_X;
-- break;
-- case AT803X_SFC_AUTOMATIC_CROSSOVER:
-- phydev->mdix_ctrl = ETH_TP_MDI_AUTO;
-- break;
-- }
-- }
--
-- return 0;
--}
--
- static int at803x_read_status(struct phy_device *phydev)
- {
- struct at803x_ss_mask ss_mask = { 0 };
-@@ -1006,50 +739,6 @@ static int at803x_read_status(struct phy
- return 0;
- }
-
--static int at803x_config_mdix(struct phy_device *phydev, u8 ctrl)
--{
-- u16 val;
--
-- switch (ctrl) {
-- case ETH_TP_MDI:
-- val = AT803X_SFC_MANUAL_MDI;
-- break;
-- case ETH_TP_MDI_X:
-- val = AT803X_SFC_MANUAL_MDIX;
-- break;
-- case ETH_TP_MDI_AUTO:
-- val = AT803X_SFC_AUTOMATIC_CROSSOVER;
-- break;
-- default:
-- return 0;
-- }
--
-- return phy_modify_changed(phydev, AT803X_SPECIFIC_FUNCTION_CONTROL,
-- AT803X_SFC_MDI_CROSSOVER_MODE_M,
-- FIELD_PREP(AT803X_SFC_MDI_CROSSOVER_MODE_M, val));
--}
--
--static int at803x_prepare_config_aneg(struct phy_device *phydev)
--{
-- int ret;
--
-- ret = at803x_config_mdix(phydev, phydev->mdix_ctrl);
-- if (ret < 0)
-- return ret;
--
-- /* Changes of the midx bits are disruptive to the normal operation;
-- * therefore any changes to these registers must be followed by a
-- * software reset to take effect.
-- */
-- if (ret == 1) {
-- ret = genphy_soft_reset(phydev);
-- if (ret < 0)
-- return ret;
-- }
--
-- return 0;
--}
--
- static int at803x_config_aneg(struct phy_device *phydev)
- {
- struct at803x_priv *priv = phydev->priv;
-@@ -1065,80 +754,6 @@ static int at803x_config_aneg(struct phy
- return genphy_config_aneg(phydev);
- }
-
--static int at803x_get_downshift(struct phy_device *phydev, u8 *d)
--{
-- int val;
--
-- val = phy_read(phydev, AT803X_SMART_SPEED);
-- if (val < 0)
-- return val;
--
-- if (val & AT803X_SMART_SPEED_ENABLE)
-- *d = FIELD_GET(AT803X_SMART_SPEED_RETRY_LIMIT_MASK, val) + 2;
-- else
-- *d = DOWNSHIFT_DEV_DISABLE;
--
-- return 0;
--}
--
--static int at803x_set_downshift(struct phy_device *phydev, u8 cnt)
--{
-- u16 mask, set;
-- int ret;
--
-- switch (cnt) {
-- case DOWNSHIFT_DEV_DEFAULT_COUNT:
-- cnt = AT803X_DEFAULT_DOWNSHIFT;
-- fallthrough;
-- case AT803X_MIN_DOWNSHIFT ... AT803X_MAX_DOWNSHIFT:
-- set = AT803X_SMART_SPEED_ENABLE |
-- AT803X_SMART_SPEED_BYPASS_TIMER |
-- FIELD_PREP(AT803X_SMART_SPEED_RETRY_LIMIT_MASK, cnt - 2);
-- mask = AT803X_SMART_SPEED_RETRY_LIMIT_MASK;
-- break;
-- case DOWNSHIFT_DEV_DISABLE:
-- set = 0;
-- mask = AT803X_SMART_SPEED_ENABLE |
-- AT803X_SMART_SPEED_BYPASS_TIMER;
-- break;
-- default:
-- return -EINVAL;
-- }
--
-- ret = phy_modify_changed(phydev, AT803X_SMART_SPEED, mask, set);
--
-- /* After changing the smart speed settings, we need to perform a
-- * software reset, use phy_init_hw() to make sure we set the
-- * reapply any values which might got lost during software reset.
-- */
-- if (ret == 1)
-- ret = phy_init_hw(phydev);
--
-- return ret;
--}
--
--static int at803x_get_tunable(struct phy_device *phydev,
-- struct ethtool_tunable *tuna, void *data)
--{
-- switch (tuna->id) {
-- case ETHTOOL_PHY_DOWNSHIFT:
-- return at803x_get_downshift(phydev, data);
-- default:
-- return -EOPNOTSUPP;
-- }
--}
--
--static int at803x_set_tunable(struct phy_device *phydev,
-- struct ethtool_tunable *tuna, const void *data)
--{
-- switch (tuna->id) {
-- case ETHTOOL_PHY_DOWNSHIFT:
-- return at803x_set_downshift(phydev, *(const u8 *)data);
-- default:
-- return -EOPNOTSUPP;
-- }
--}
--
- static int at803x_cable_test_result_trans(u16 status)
- {
- switch (FIELD_GET(AT803X_CDT_STATUS_STAT_MASK, status)) {
-@@ -1170,45 +785,6 @@ static bool at803x_cdt_fault_length_vali
- return false;
- }
-
--static int at803x_cdt_fault_length(int dt)
--{
-- /* According to the datasheet the distance to the fault is
-- * DELTA_TIME * 0.824 meters.
-- *
-- * The author suspect the correct formula is:
-- *
-- * fault_distance = DELTA_TIME * (c * VF) / 125MHz / 2
-- *
-- * where c is the speed of light, VF is the velocity factor of
-- * the twisted pair cable, 125MHz the counter frequency and
-- * we need to divide by 2 because the hardware will measure the
-- * round trip time to the fault and back to the PHY.
-- *
-- * With a VF of 0.69 we get the factor 0.824 mentioned in the
-- * datasheet.
-- */
-- return (dt * 824) / 10;
--}
--
--static int at803x_cdt_start(struct phy_device *phydev,
-- u32 cdt_start)
--{
-- return phy_write(phydev, AT803X_CDT, cdt_start);
--}
--
--static int at803x_cdt_wait_for_completion(struct phy_device *phydev,
-- u32 cdt_en)
--{
-- int val, ret;
--
-- /* One test run takes about 25ms */
-- ret = phy_read_poll_timeout(phydev, AT803X_CDT, val,
-- !(val & cdt_en),
-- 30000, 100000, true);
--
-- return ret < 0 ? ret : 0;
--}
--
- static int at803x_cable_test_one_pair(struct phy_device *phydev, int pair)
- {
- static const int ethtool_pair[] = {
---- a/drivers/net/phy/qcom/qcom-phy-lib.c
-+++ b/drivers/net/phy/qcom/qcom-phy-lib.c
-@@ -3,6 +3,9 @@
- #include <linux/phy.h>
- #include <linux/module.h>
-
-+#include <linux/netdevice.h>
-+#include <linux/etherdevice.h>
-+
- #include "qcom.h"
-
- MODULE_DESCRIPTION("Qualcomm PHY driver Common Functions");
-@@ -51,3 +54,376 @@ int at803x_debug_reg_write(struct phy_de
- return phy_write(phydev, AT803X_DEBUG_DATA, data);
- }
- EXPORT_SYMBOL_GPL(at803x_debug_reg_write);
-+
-+int at803x_set_wol(struct phy_device *phydev,
-+ struct ethtool_wolinfo *wol)
-+{
-+ int ret, irq_enabled;
-+
-+ if (wol->wolopts & WAKE_MAGIC) {
-+ struct net_device *ndev = phydev->attached_dev;
-+ const u8 *mac;
-+ unsigned int i;
-+ static const unsigned int offsets[] = {
-+ AT803X_LOC_MAC_ADDR_32_47_OFFSET,
-+ AT803X_LOC_MAC_ADDR_16_31_OFFSET,
-+ AT803X_LOC_MAC_ADDR_0_15_OFFSET,
-+ };
-+
-+ if (!ndev)
-+ return -ENODEV;
-+
-+ mac = (const u8 *)ndev->dev_addr;
-+
-+ if (!is_valid_ether_addr(mac))
-+ return -EINVAL;
-+
-+ for (i = 0; i < 3; i++)
-+ phy_write_mmd(phydev, MDIO_MMD_PCS, offsets[i],
-+ mac[(i * 2) + 1] | (mac[(i * 2)] << 8));
-+
-+ /* Enable WOL interrupt */
-+ ret = phy_modify(phydev, AT803X_INTR_ENABLE, 0, AT803X_INTR_ENABLE_WOL);
-+ if (ret)
-+ return ret;
-+ } else {
-+ /* Disable WOL interrupt */
-+ ret = phy_modify(phydev, AT803X_INTR_ENABLE, AT803X_INTR_ENABLE_WOL, 0);
-+ if (ret)
-+ return ret;
-+ }
-+
-+ /* Clear WOL status */
-+ ret = phy_read(phydev, AT803X_INTR_STATUS);
-+ if (ret < 0)
-+ return ret;
-+
-+ /* Check if there are other interrupts except for WOL triggered when PHY is
-+ * in interrupt mode, only the interrupts enabled by AT803X_INTR_ENABLE can
-+ * be passed up to the interrupt PIN.
-+ */
-+ irq_enabled = phy_read(phydev, AT803X_INTR_ENABLE);
-+ if (irq_enabled < 0)
-+ return irq_enabled;
-+
-+ irq_enabled &= ~AT803X_INTR_ENABLE_WOL;
-+ if (ret & irq_enabled && !phy_polling_mode(phydev))
-+ phy_trigger_machine(phydev);
-+
-+ return 0;
-+}
-+EXPORT_SYMBOL_GPL(at803x_set_wol);
-+
-+void at803x_get_wol(struct phy_device *phydev,
-+ struct ethtool_wolinfo *wol)
-+{
-+ int value;
-+
-+ wol->supported = WAKE_MAGIC;
-+ wol->wolopts = 0;
-+
-+ value = phy_read(phydev, AT803X_INTR_ENABLE);
-+ if (value < 0)
-+ return;
-+
-+ if (value & AT803X_INTR_ENABLE_WOL)
-+ wol->wolopts |= WAKE_MAGIC;
-+}
-+EXPORT_SYMBOL_GPL(at803x_get_wol);
-+
-+int at803x_ack_interrupt(struct phy_device *phydev)
-+{
-+ int err;
-+
-+ err = phy_read(phydev, AT803X_INTR_STATUS);
-+
-+ return (err < 0) ? err : 0;
-+}
-+EXPORT_SYMBOL_GPL(at803x_ack_interrupt);
-+
-+int at803x_config_intr(struct phy_device *phydev)
-+{
-+ int err;
-+ int value;
-+
-+ value = phy_read(phydev, AT803X_INTR_ENABLE);
-+
-+ if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
-+ /* Clear any pending interrupts */
-+ err = at803x_ack_interrupt(phydev);
-+ if (err)
-+ return err;
-+
-+ value |= AT803X_INTR_ENABLE_AUTONEG_ERR;
-+ value |= AT803X_INTR_ENABLE_SPEED_CHANGED;
-+ value |= AT803X_INTR_ENABLE_DUPLEX_CHANGED;
-+ value |= AT803X_INTR_ENABLE_LINK_FAIL;
-+ value |= AT803X_INTR_ENABLE_LINK_SUCCESS;
-+
-+ err = phy_write(phydev, AT803X_INTR_ENABLE, value);
-+ } else {
-+ err = phy_write(phydev, AT803X_INTR_ENABLE, 0);
-+ if (err)
-+ return err;
-+
-+ /* Clear any pending interrupts */
-+ err = at803x_ack_interrupt(phydev);
-+ }
-+
-+ return err;
-+}
-+EXPORT_SYMBOL_GPL(at803x_config_intr);
-+
-+irqreturn_t at803x_handle_interrupt(struct phy_device *phydev)
-+{
-+ int irq_status, int_enabled;
-+
-+ irq_status = phy_read(phydev, AT803X_INTR_STATUS);
-+ if (irq_status < 0) {
-+ phy_error(phydev);
-+ return IRQ_NONE;
-+ }
-+
-+ /* Read the current enabled interrupts */
-+ int_enabled = phy_read(phydev, AT803X_INTR_ENABLE);
-+ if (int_enabled < 0) {
-+ phy_error(phydev);
-+ return IRQ_NONE;
-+ }
-+
-+ /* See if this was one of our enabled interrupts */
-+ if (!(irq_status & int_enabled))
-+ return IRQ_NONE;
-+
-+ phy_trigger_machine(phydev);
-+
-+ return IRQ_HANDLED;
-+}
-+EXPORT_SYMBOL_GPL(at803x_handle_interrupt);
-+
-+int at803x_read_specific_status(struct phy_device *phydev,
-+ struct at803x_ss_mask ss_mask)
-+{
-+ int ss;
-+
-+ /* Read the AT8035 PHY-Specific Status register, which indicates the
-+ * speed and duplex that the PHY is actually using, irrespective of
-+ * whether we are in autoneg mode or not.
-+ */
-+ ss = phy_read(phydev, AT803X_SPECIFIC_STATUS);
-+ if (ss < 0)
-+ return ss;
-+
-+ if (ss & AT803X_SS_SPEED_DUPLEX_RESOLVED) {
-+ int sfc, speed;
-+
-+ sfc = phy_read(phydev, AT803X_SPECIFIC_FUNCTION_CONTROL);
-+ if (sfc < 0)
-+ return sfc;
-+
-+ speed = ss & ss_mask.speed_mask;
-+ speed >>= ss_mask.speed_shift;
-+
-+ switch (speed) {
-+ case AT803X_SS_SPEED_10:
-+ phydev->speed = SPEED_10;
-+ break;
-+ case AT803X_SS_SPEED_100:
-+ phydev->speed = SPEED_100;
-+ break;
-+ case AT803X_SS_SPEED_1000:
-+ phydev->speed = SPEED_1000;
-+ break;
-+ case QCA808X_SS_SPEED_2500:
-+ phydev->speed = SPEED_2500;
-+ break;
-+ }
-+ if (ss & AT803X_SS_DUPLEX)
-+ phydev->duplex = DUPLEX_FULL;
-+ else
-+ phydev->duplex = DUPLEX_HALF;
-+
-+ if (ss & AT803X_SS_MDIX)
-+ phydev->mdix = ETH_TP_MDI_X;
-+ else
-+ phydev->mdix = ETH_TP_MDI;
-+
-+ switch (FIELD_GET(AT803X_SFC_MDI_CROSSOVER_MODE_M, sfc)) {
-+ case AT803X_SFC_MANUAL_MDI:
-+ phydev->mdix_ctrl = ETH_TP_MDI;
-+ break;
-+ case AT803X_SFC_MANUAL_MDIX:
-+ phydev->mdix_ctrl = ETH_TP_MDI_X;
-+ break;
-+ case AT803X_SFC_AUTOMATIC_CROSSOVER:
-+ phydev->mdix_ctrl = ETH_TP_MDI_AUTO;
-+ break;
-+ }
-+ }
-+
-+ return 0;
-+}
-+EXPORT_SYMBOL_GPL(at803x_read_specific_status);
-+
-+int at803x_config_mdix(struct phy_device *phydev, u8 ctrl)
-+{
-+ u16 val;
-+
-+ switch (ctrl) {
-+ case ETH_TP_MDI:
-+ val = AT803X_SFC_MANUAL_MDI;
-+ break;
-+ case ETH_TP_MDI_X:
-+ val = AT803X_SFC_MANUAL_MDIX;
-+ break;
-+ case ETH_TP_MDI_AUTO:
-+ val = AT803X_SFC_AUTOMATIC_CROSSOVER;
-+ break;
-+ default:
-+ return 0;
-+ }
-+
-+ return phy_modify_changed(phydev, AT803X_SPECIFIC_FUNCTION_CONTROL,
-+ AT803X_SFC_MDI_CROSSOVER_MODE_M,
-+ FIELD_PREP(AT803X_SFC_MDI_CROSSOVER_MODE_M, val));
-+}
-+EXPORT_SYMBOL_GPL(at803x_config_mdix);
-+
-+int at803x_prepare_config_aneg(struct phy_device *phydev)
-+{
-+ int ret;
-+
-+ ret = at803x_config_mdix(phydev, phydev->mdix_ctrl);
-+ if (ret < 0)
-+ return ret;
-+
-+ /* Changes of the midx bits are disruptive to the normal operation;
-+ * therefore any changes to these registers must be followed by a
-+ * software reset to take effect.
-+ */
-+ if (ret == 1) {
-+ ret = genphy_soft_reset(phydev);
-+ if (ret < 0)
-+ return ret;
-+ }
-+
-+ return 0;
-+}
-+EXPORT_SYMBOL_GPL(at803x_prepare_config_aneg);
-+
-+static int at803x_get_downshift(struct phy_device *phydev, u8 *d)
-+{
-+ int val;
-+
-+ val = phy_read(phydev, AT803X_SMART_SPEED);
-+ if (val < 0)
-+ return val;
-+
-+ if (val & AT803X_SMART_SPEED_ENABLE)
-+ *d = FIELD_GET(AT803X_SMART_SPEED_RETRY_LIMIT_MASK, val) + 2;
-+ else
-+ *d = DOWNSHIFT_DEV_DISABLE;
-+
-+ return 0;
-+}
-+
-+static int at803x_set_downshift(struct phy_device *phydev, u8 cnt)
-+{
-+ u16 mask, set;
-+ int ret;
-+
-+ switch (cnt) {
-+ case DOWNSHIFT_DEV_DEFAULT_COUNT:
-+ cnt = AT803X_DEFAULT_DOWNSHIFT;
-+ fallthrough;
-+ case AT803X_MIN_DOWNSHIFT ... AT803X_MAX_DOWNSHIFT:
-+ set = AT803X_SMART_SPEED_ENABLE |
-+ AT803X_SMART_SPEED_BYPASS_TIMER |
-+ FIELD_PREP(AT803X_SMART_SPEED_RETRY_LIMIT_MASK, cnt - 2);
-+ mask = AT803X_SMART_SPEED_RETRY_LIMIT_MASK;
-+ break;
-+ case DOWNSHIFT_DEV_DISABLE:
-+ set = 0;
-+ mask = AT803X_SMART_SPEED_ENABLE |
-+ AT803X_SMART_SPEED_BYPASS_TIMER;
-+ break;
-+ default:
-+ return -EINVAL;
-+ }
-+
-+ ret = phy_modify_changed(phydev, AT803X_SMART_SPEED, mask, set);
-+
-+ /* After changing the smart speed settings, we need to perform a
-+ * software reset, use phy_init_hw() to make sure we set the
-+ * reapply any values which might got lost during software reset.
-+ */
-+ if (ret == 1)
-+ ret = phy_init_hw(phydev);
-+
-+ return ret;
-+}
-+
-+int at803x_get_tunable(struct phy_device *phydev,
-+ struct ethtool_tunable *tuna, void *data)
-+{
-+ switch (tuna->id) {
-+ case ETHTOOL_PHY_DOWNSHIFT:
-+ return at803x_get_downshift(phydev, data);
-+ default:
-+ return -EOPNOTSUPP;
-+ }
-+}
-+EXPORT_SYMBOL_GPL(at803x_get_tunable);
-+
-+int at803x_set_tunable(struct phy_device *phydev,
-+ struct ethtool_tunable *tuna, const void *data)
-+{
-+ switch (tuna->id) {
-+ case ETHTOOL_PHY_DOWNSHIFT:
-+ return at803x_set_downshift(phydev, *(const u8 *)data);
-+ default:
-+ return -EOPNOTSUPP;
-+ }
-+}
-+EXPORT_SYMBOL_GPL(at803x_set_tunable);
-+
-+int at803x_cdt_fault_length(int dt)
-+{
-+ /* According to the datasheet the distance to the fault is
-+ * DELTA_TIME * 0.824 meters.
-+ *
-+ * The author suspect the correct formula is:
-+ *
-+ * fault_distance = DELTA_TIME * (c * VF) / 125MHz / 2
-+ *
-+ * where c is the speed of light, VF is the velocity factor of
-+ * the twisted pair cable, 125MHz the counter frequency and
-+ * we need to divide by 2 because the hardware will measure the
-+ * round trip time to the fault and back to the PHY.
-+ *
-+ * With a VF of 0.69 we get the factor 0.824 mentioned in the
-+ * datasheet.
-+ */
-+ return (dt * 824) / 10;
-+}
-+EXPORT_SYMBOL_GPL(at803x_cdt_fault_length);
-+
-+int at803x_cdt_start(struct phy_device *phydev, u32 cdt_start)
-+{
-+ return phy_write(phydev, AT803X_CDT, cdt_start);
-+}
-+EXPORT_SYMBOL_GPL(at803x_cdt_start);
-+
-+int at803x_cdt_wait_for_completion(struct phy_device *phydev,
-+ u32 cdt_en)
-+{
-+ int val, ret;
-+
-+ /* One test run takes about 25ms */
-+ ret = phy_read_poll_timeout(phydev, AT803X_CDT, val,
-+ !(val & cdt_en),
-+ 30000, 100000, true);
-+
-+ return ret < 0 ? ret : 0;
-+}
-+EXPORT_SYMBOL_GPL(at803x_cdt_wait_for_completion);
---- a/drivers/net/phy/qcom/qcom.h
-+++ b/drivers/net/phy/qcom/qcom.h
-@@ -1,5 +1,63 @@
- /* SPDX-License-Identifier: GPL-2.0 */
-
-+#define AT803X_SPECIFIC_FUNCTION_CONTROL 0x10
-+#define AT803X_SFC_ASSERT_CRS BIT(11)
-+#define AT803X_SFC_FORCE_LINK BIT(10)
-+#define AT803X_SFC_MDI_CROSSOVER_MODE_M GENMASK(6, 5)
-+#define AT803X_SFC_AUTOMATIC_CROSSOVER 0x3
-+#define AT803X_SFC_MANUAL_MDIX 0x1
-+#define AT803X_SFC_MANUAL_MDI 0x0
-+#define AT803X_SFC_SQE_TEST BIT(2)
-+#define AT803X_SFC_POLARITY_REVERSAL BIT(1)
-+#define AT803X_SFC_DISABLE_JABBER BIT(0)
-+
-+#define AT803X_SPECIFIC_STATUS 0x11
-+#define AT803X_SS_SPEED_MASK GENMASK(15, 14)
-+#define AT803X_SS_SPEED_1000 2
-+#define AT803X_SS_SPEED_100 1
-+#define AT803X_SS_SPEED_10 0
-+#define AT803X_SS_DUPLEX BIT(13)
-+#define AT803X_SS_SPEED_DUPLEX_RESOLVED BIT(11)
-+#define AT803X_SS_MDIX BIT(6)
-+
-+#define QCA808X_SS_SPEED_MASK GENMASK(9, 7)
-+#define QCA808X_SS_SPEED_2500 4
-+
-+#define AT803X_INTR_ENABLE 0x12
-+#define AT803X_INTR_ENABLE_AUTONEG_ERR BIT(15)
-+#define AT803X_INTR_ENABLE_SPEED_CHANGED BIT(14)
-+#define AT803X_INTR_ENABLE_DUPLEX_CHANGED BIT(13)
-+#define AT803X_INTR_ENABLE_PAGE_RECEIVED BIT(12)
-+#define AT803X_INTR_ENABLE_LINK_FAIL BIT(11)
-+#define AT803X_INTR_ENABLE_LINK_SUCCESS BIT(10)
-+#define AT803X_INTR_ENABLE_LINK_FAIL_BX BIT(8)
-+#define AT803X_INTR_ENABLE_LINK_SUCCESS_BX BIT(7)
-+#define AT803X_INTR_ENABLE_WIRESPEED_DOWNGRADE BIT(5)
-+#define AT803X_INTR_ENABLE_POLARITY_CHANGED BIT(1)
-+#define AT803X_INTR_ENABLE_WOL BIT(0)
-+
-+#define AT803X_INTR_STATUS 0x13
-+
-+#define AT803X_SMART_SPEED 0x14
-+#define AT803X_SMART_SPEED_ENABLE BIT(5)
-+#define AT803X_SMART_SPEED_RETRY_LIMIT_MASK GENMASK(4, 2)
-+#define AT803X_SMART_SPEED_BYPASS_TIMER BIT(1)
-+
-+#define AT803X_CDT 0x16
-+#define AT803X_CDT_MDI_PAIR_MASK GENMASK(9, 8)
-+#define AT803X_CDT_ENABLE_TEST BIT(0)
-+#define AT803X_CDT_STATUS 0x1c
-+#define AT803X_CDT_STATUS_STAT_NORMAL 0
-+#define AT803X_CDT_STATUS_STAT_SHORT 1
-+#define AT803X_CDT_STATUS_STAT_OPEN 2
-+#define AT803X_CDT_STATUS_STAT_FAIL 3
-+#define AT803X_CDT_STATUS_STAT_MASK GENMASK(9, 8)
-+#define AT803X_CDT_STATUS_DELTA_TIME_MASK GENMASK(7, 0)
-+
-+#define AT803X_LOC_MAC_ADDR_0_15_OFFSET 0x804C
-+#define AT803X_LOC_MAC_ADDR_16_31_OFFSET 0x804B
-+#define AT803X_LOC_MAC_ADDR_32_47_OFFSET 0x804A
-+
- #define AT803X_DEBUG_ADDR 0x1D
- #define AT803X_DEBUG_DATA 0x1E
-
-@@ -16,6 +74,10 @@
- #define AT803X_DEBUG_HIB_CTRL_EN_ANY_CHANGE BIT(13)
- #define AT803X_DEBUG_HIB_CTRL_PS_HIB_EN BIT(15)
-
-+#define AT803X_DEFAULT_DOWNSHIFT 5
-+#define AT803X_MIN_DOWNSHIFT 2
-+#define AT803X_MAX_DOWNSHIFT 9
-+
- enum stat_access_type {
- PHY,
- MMD
-@@ -28,7 +90,31 @@ struct at803x_hw_stat {
- enum stat_access_type access_type;
- };
-
-+struct at803x_ss_mask {
-+ u16 speed_mask;
-+ u8 speed_shift;
-+};
-+
- int at803x_debug_reg_read(struct phy_device *phydev, u16 reg);
- int at803x_debug_reg_mask(struct phy_device *phydev, u16 reg,
- u16 clear, u16 set);
- int at803x_debug_reg_write(struct phy_device *phydev, u16 reg, u16 data);
-+int at803x_set_wol(struct phy_device *phydev,
-+ struct ethtool_wolinfo *wol);
-+void at803x_get_wol(struct phy_device *phydev,
-+ struct ethtool_wolinfo *wol);
-+int at803x_ack_interrupt(struct phy_device *phydev);
-+int at803x_config_intr(struct phy_device *phydev);
-+irqreturn_t at803x_handle_interrupt(struct phy_device *phydev);
-+int at803x_read_specific_status(struct phy_device *phydev,
-+ struct at803x_ss_mask ss_mask);
-+int at803x_config_mdix(struct phy_device *phydev, u8 ctrl);
-+int at803x_prepare_config_aneg(struct phy_device *phydev);
-+int at803x_get_tunable(struct phy_device *phydev,
-+ struct ethtool_tunable *tuna, void *data);
-+int at803x_set_tunable(struct phy_device *phydev,
-+ struct ethtool_tunable *tuna, const void *data);
-+int at803x_cdt_fault_length(int dt);
-+int at803x_cdt_start(struct phy_device *phydev, u32 cdt_start);
-+int at803x_cdt_wait_for_completion(struct phy_device *phydev,
-+ u32 cdt_en);
+++ /dev/null
-From c89414adf2ec7cd9e7080c419aa5847f1db1009c Mon Sep 17 00:00:00 2001
-Date: Mon, 29 Jan 2024 15:15:23 +0100
-Subject: [PATCH 5/5] net: phy: qcom: detach qca808x PHY driver from at803x
-
-Almost all the QCA8081 PHY driver OPs are specific and only some of them
-use the generic at803x.
-
-To make the at803x code slimmer, move all the specific qca808x regs and
-functions to a dedicated PHY driver.
-
-Probe function and priv struct is reworked to allocate and use only the
-qca808x specific data. Unused data from at803x PHY driver are dropped
-from at803x priv struct.
-
-Also a new Kconfig is introduced QCA808X_PHY, to compile the newly
-introduced PHY driver for QCA8081 PHY.
-
-As the Kconfig name starts with Qualcomm the same order is kept.
-
----
- drivers/net/phy/qcom/Kconfig | 6 +
- drivers/net/phy/qcom/Makefile | 1 +
- drivers/net/phy/qcom/at803x.c | 897 +------------------------------
- drivers/net/phy/qcom/qca808x.c | 934 +++++++++++++++++++++++++++++++++
- 4 files changed, 942 insertions(+), 896 deletions(-)
- create mode 100644 drivers/net/phy/qcom/qca808x.c
-
---- a/drivers/net/phy/qcom/Kconfig
-+++ b/drivers/net/phy/qcom/Kconfig
-@@ -14,3 +14,9 @@ config QCA83XX_PHY
- select QCOM_NET_PHYLIB
- help
- Currently supports the internal QCA8337(Internal qca8k PHY) model
-+
-+config QCA808X_PHY
-+ tristate "Qualcomm QCA808x PHYs"
-+ select QCOM_NET_PHYLIB
-+ help
-+ Currently supports the QCA8081 model
---- a/drivers/net/phy/qcom/Makefile
-+++ b/drivers/net/phy/qcom/Makefile
-@@ -2,3 +2,4 @@
- obj-$(CONFIG_QCOM_NET_PHYLIB) += qcom-phy-lib.o
- obj-$(CONFIG_AT803X_PHY) += at803x.o
- obj-$(CONFIG_QCA83XX_PHY) += qca83xx.o
-+obj-$(CONFIG_QCA808X_PHY) += qca808x.o
---- a/drivers/net/phy/qcom/at803x.c
-+++ b/drivers/net/phy/qcom/at803x.c
-@@ -96,8 +96,6 @@
- #define ATH8035_PHY_ID 0x004dd072
- #define AT8030_PHY_ID_MASK 0xffffffef
-
--#define QCA8081_PHY_ID 0x004dd101
--
- #define QCA9561_PHY_ID 0x004dd042
-
- #define AT803X_PAGE_FIBER 0
-@@ -110,201 +108,7 @@
- /* disable hibernation mode */
- #define AT803X_DISABLE_HIBERNATION_MODE BIT(2)
-
--/* ADC threshold */
--#define QCA808X_PHY_DEBUG_ADC_THRESHOLD 0x2c80
--#define QCA808X_ADC_THRESHOLD_MASK GENMASK(7, 0)
--#define QCA808X_ADC_THRESHOLD_80MV 0
--#define QCA808X_ADC_THRESHOLD_100MV 0xf0
--#define QCA808X_ADC_THRESHOLD_200MV 0x0f
--#define QCA808X_ADC_THRESHOLD_300MV 0xff
--
--/* CLD control */
--#define QCA808X_PHY_MMD3_ADDR_CLD_CTRL7 0x8007
--#define QCA808X_8023AZ_AFE_CTRL_MASK GENMASK(8, 4)
--#define QCA808X_8023AZ_AFE_EN 0x90
--
--/* AZ control */
--#define QCA808X_PHY_MMD3_AZ_TRAINING_CTRL 0x8008
--#define QCA808X_MMD3_AZ_TRAINING_VAL 0x1c32
--
--#define QCA808X_PHY_MMD1_MSE_THRESHOLD_20DB 0x8014
--#define QCA808X_MSE_THRESHOLD_20DB_VALUE 0x529
--
--#define QCA808X_PHY_MMD1_MSE_THRESHOLD_17DB 0x800E
--#define QCA808X_MSE_THRESHOLD_17DB_VALUE 0x341
--
--#define QCA808X_PHY_MMD1_MSE_THRESHOLD_27DB 0x801E
--#define QCA808X_MSE_THRESHOLD_27DB_VALUE 0x419
--
--#define QCA808X_PHY_MMD1_MSE_THRESHOLD_28DB 0x8020
--#define QCA808X_MSE_THRESHOLD_28DB_VALUE 0x341
--
--#define QCA808X_PHY_MMD7_TOP_OPTION1 0x901c
--#define QCA808X_TOP_OPTION1_DATA 0x0
--
--#define QCA808X_PHY_MMD3_DEBUG_1 0xa100
--#define QCA808X_MMD3_DEBUG_1_VALUE 0x9203
--#define QCA808X_PHY_MMD3_DEBUG_2 0xa101
--#define QCA808X_MMD3_DEBUG_2_VALUE 0x48ad
--#define QCA808X_PHY_MMD3_DEBUG_3 0xa103
--#define QCA808X_MMD3_DEBUG_3_VALUE 0x1698
--#define QCA808X_PHY_MMD3_DEBUG_4 0xa105
--#define QCA808X_MMD3_DEBUG_4_VALUE 0x8001
--#define QCA808X_PHY_MMD3_DEBUG_5 0xa106
--#define QCA808X_MMD3_DEBUG_5_VALUE 0x1111
--#define QCA808X_PHY_MMD3_DEBUG_6 0xa011
--#define QCA808X_MMD3_DEBUG_6_VALUE 0x5f85
--
--/* master/slave seed config */
--#define QCA808X_PHY_DEBUG_LOCAL_SEED 9
--#define QCA808X_MASTER_SLAVE_SEED_ENABLE BIT(1)
--#define QCA808X_MASTER_SLAVE_SEED_CFG GENMASK(12, 2)
--#define QCA808X_MASTER_SLAVE_SEED_RANGE 0x32
--
--/* Hibernation yields lower power consumpiton in contrast with normal operation mode.
-- * when the copper cable is unplugged, the PHY enters into hibernation mode in about 10s.
-- */
--#define QCA808X_DBG_AN_TEST 0xb
--#define QCA808X_HIBERNATION_EN BIT(15)
--
--#define QCA808X_CDT_ENABLE_TEST BIT(15)
--#define QCA808X_CDT_INTER_CHECK_DIS BIT(13)
--#define QCA808X_CDT_STATUS BIT(11)
--#define QCA808X_CDT_LENGTH_UNIT BIT(10)
--
--#define QCA808X_MMD3_CDT_STATUS 0x8064
--#define QCA808X_MMD3_CDT_DIAG_PAIR_A 0x8065
--#define QCA808X_MMD3_CDT_DIAG_PAIR_B 0x8066
--#define QCA808X_MMD3_CDT_DIAG_PAIR_C 0x8067
--#define QCA808X_MMD3_CDT_DIAG_PAIR_D 0x8068
--#define QCA808X_CDT_DIAG_LENGTH_SAME_SHORT GENMASK(15, 8)
--#define QCA808X_CDT_DIAG_LENGTH_CROSS_SHORT GENMASK(7, 0)
--
--#define QCA808X_CDT_CODE_PAIR_A GENMASK(15, 12)
--#define QCA808X_CDT_CODE_PAIR_B GENMASK(11, 8)
--#define QCA808X_CDT_CODE_PAIR_C GENMASK(7, 4)
--#define QCA808X_CDT_CODE_PAIR_D GENMASK(3, 0)
--
--#define QCA808X_CDT_STATUS_STAT_TYPE GENMASK(1, 0)
--#define QCA808X_CDT_STATUS_STAT_FAIL FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_TYPE, 0)
--#define QCA808X_CDT_STATUS_STAT_NORMAL FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_TYPE, 1)
--#define QCA808X_CDT_STATUS_STAT_SAME_OPEN FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_TYPE, 2)
--#define QCA808X_CDT_STATUS_STAT_SAME_SHORT FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_TYPE, 3)
--
--#define QCA808X_CDT_STATUS_STAT_MDI GENMASK(3, 2)
--#define QCA808X_CDT_STATUS_STAT_MDI1 FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_MDI, 1)
--#define QCA808X_CDT_STATUS_STAT_MDI2 FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_MDI, 2)
--#define QCA808X_CDT_STATUS_STAT_MDI3 FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_MDI, 3)
--
--/* NORMAL are MDI with type set to 0 */
--#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_NORMAL QCA808X_CDT_STATUS_STAT_MDI1
--#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_OPEN (QCA808X_CDT_STATUS_STAT_SAME_OPEN |\
-- QCA808X_CDT_STATUS_STAT_MDI1)
--#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_SHORT (QCA808X_CDT_STATUS_STAT_SAME_SHORT |\
-- QCA808X_CDT_STATUS_STAT_MDI1)
--#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_NORMAL QCA808X_CDT_STATUS_STAT_MDI2
--#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_OPEN (QCA808X_CDT_STATUS_STAT_SAME_OPEN |\
-- QCA808X_CDT_STATUS_STAT_MDI2)
--#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_SHORT (QCA808X_CDT_STATUS_STAT_SAME_SHORT |\
-- QCA808X_CDT_STATUS_STAT_MDI2)
--#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_NORMAL QCA808X_CDT_STATUS_STAT_MDI3
--#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_OPEN (QCA808X_CDT_STATUS_STAT_SAME_OPEN |\
-- QCA808X_CDT_STATUS_STAT_MDI3)
--#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_SHORT (QCA808X_CDT_STATUS_STAT_SAME_SHORT |\
-- QCA808X_CDT_STATUS_STAT_MDI3)
--
--/* Added for reference of existence but should be handled by wait_for_completion already */
--#define QCA808X_CDT_STATUS_STAT_BUSY (BIT(1) | BIT(3))
--
--#define QCA808X_MMD7_LED_GLOBAL 0x8073
--#define QCA808X_LED_BLINK_1 GENMASK(11, 6)
--#define QCA808X_LED_BLINK_2 GENMASK(5, 0)
--/* Values are the same for both BLINK_1 and BLINK_2 */
--#define QCA808X_LED_BLINK_FREQ_MASK GENMASK(5, 3)
--#define QCA808X_LED_BLINK_FREQ_2HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x0)
--#define QCA808X_LED_BLINK_FREQ_4HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x1)
--#define QCA808X_LED_BLINK_FREQ_8HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x2)
--#define QCA808X_LED_BLINK_FREQ_16HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x3)
--#define QCA808X_LED_BLINK_FREQ_32HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x4)
--#define QCA808X_LED_BLINK_FREQ_64HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x5)
--#define QCA808X_LED_BLINK_FREQ_128HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x6)
--#define QCA808X_LED_BLINK_FREQ_256HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x7)
--#define QCA808X_LED_BLINK_DUTY_MASK GENMASK(2, 0)
--#define QCA808X_LED_BLINK_DUTY_50_50 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x0)
--#define QCA808X_LED_BLINK_DUTY_75_25 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x1)
--#define QCA808X_LED_BLINK_DUTY_25_75 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x2)
--#define QCA808X_LED_BLINK_DUTY_33_67 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x3)
--#define QCA808X_LED_BLINK_DUTY_67_33 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x4)
--#define QCA808X_LED_BLINK_DUTY_17_83 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x5)
--#define QCA808X_LED_BLINK_DUTY_83_17 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x6)
--#define QCA808X_LED_BLINK_DUTY_8_92 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x7)
--
--#define QCA808X_MMD7_LED2_CTRL 0x8074
--#define QCA808X_MMD7_LED2_FORCE_CTRL 0x8075
--#define QCA808X_MMD7_LED1_CTRL 0x8076
--#define QCA808X_MMD7_LED1_FORCE_CTRL 0x8077
--#define QCA808X_MMD7_LED0_CTRL 0x8078
--#define QCA808X_MMD7_LED_CTRL(x) (0x8078 - ((x) * 2))
--
--/* LED hw control pattern is the same for every LED */
--#define QCA808X_LED_PATTERN_MASK GENMASK(15, 0)
--#define QCA808X_LED_SPEED2500_ON BIT(15)
--#define QCA808X_LED_SPEED2500_BLINK BIT(14)
--/* Follow blink trigger even if duplex or speed condition doesn't match */
--#define QCA808X_LED_BLINK_CHECK_BYPASS BIT(13)
--#define QCA808X_LED_FULL_DUPLEX_ON BIT(12)
--#define QCA808X_LED_HALF_DUPLEX_ON BIT(11)
--#define QCA808X_LED_TX_BLINK BIT(10)
--#define QCA808X_LED_RX_BLINK BIT(9)
--#define QCA808X_LED_TX_ON_10MS BIT(8)
--#define QCA808X_LED_RX_ON_10MS BIT(7)
--#define QCA808X_LED_SPEED1000_ON BIT(6)
--#define QCA808X_LED_SPEED100_ON BIT(5)
--#define QCA808X_LED_SPEED10_ON BIT(4)
--#define QCA808X_LED_COLLISION_BLINK BIT(3)
--#define QCA808X_LED_SPEED1000_BLINK BIT(2)
--#define QCA808X_LED_SPEED100_BLINK BIT(1)
--#define QCA808X_LED_SPEED10_BLINK BIT(0)
--
--#define QCA808X_MMD7_LED0_FORCE_CTRL 0x8079
--#define QCA808X_MMD7_LED_FORCE_CTRL(x) (0x8079 - ((x) * 2))
--
--/* LED force ctrl is the same for every LED
-- * No documentation exist for this, not even internal one
-- * with NDA as QCOM gives only info about configuring
-- * hw control pattern rules and doesn't indicate any way
-- * to force the LED to specific mode.
-- * These define comes from reverse and testing and maybe
-- * lack of some info or some info are not entirely correct.
-- * For the basic LED control and hw control these finding
-- * are enough to support LED control in all the required APIs.
-- *
-- * On doing some comparison with implementation with qca807x,
-- * it was found that it's 1:1 equal to it and confirms all the
-- * reverse done. It was also found further specification with the
-- * force mode and the blink modes.
-- */
--#define QCA808X_LED_FORCE_EN BIT(15)
--#define QCA808X_LED_FORCE_MODE_MASK GENMASK(14, 13)
--#define QCA808X_LED_FORCE_BLINK_1 FIELD_PREP(QCA808X_LED_FORCE_MODE_MASK, 0x3)
--#define QCA808X_LED_FORCE_BLINK_2 FIELD_PREP(QCA808X_LED_FORCE_MODE_MASK, 0x2)
--#define QCA808X_LED_FORCE_ON FIELD_PREP(QCA808X_LED_FORCE_MODE_MASK, 0x1)
--#define QCA808X_LED_FORCE_OFF FIELD_PREP(QCA808X_LED_FORCE_MODE_MASK, 0x0)
--
--#define QCA808X_MMD7_LED_POLARITY_CTRL 0x901a
--/* QSDK sets by default 0x46 to this reg that sets BIT 6 for
-- * LED to active high. It's not clear what BIT 3 and BIT 4 does.
-- */
--#define QCA808X_LED_ACTIVE_HIGH BIT(6)
--
--/* QCA808X 1G chip type */
--#define QCA808X_PHY_MMD7_CHIP_TYPE 0x901d
--#define QCA808X_PHY_CHIP_TYPE_1G BIT(0)
--
--#define QCA8081_PHY_SERDES_MMD1_FIFO_CTRL 0x9072
--#define QCA8081_PHY_FIFO_RSTN BIT(11)
--
--MODULE_DESCRIPTION("Qualcomm Atheros AR803x and QCA808X PHY driver");
-+MODULE_DESCRIPTION("Qualcomm Atheros AR803x PHY driver");
- MODULE_AUTHOR("Matus Ujhelyi");
- MODULE_LICENSE("GPL");
-
-@@ -318,7 +122,6 @@ struct at803x_priv {
- bool is_1000basex;
- struct regulator_dev *vddio_rdev;
- struct regulator_dev *vddh_rdev;
-- int led_polarity_mode;
- };
-
- struct at803x_context {
-@@ -519,9 +322,6 @@ static int at803x_probe(struct phy_devic
- if (!priv)
- return -ENOMEM;
-
-- /* Init LED polarity mode to -1 */
-- priv->led_polarity_mode = -1;
--
- phydev->priv = priv;
-
- ret = at803x_parse_dt(phydev);
-@@ -1216,672 +1016,6 @@ static int at8035_probe(struct phy_devic
- return at8035_parse_dt(phydev);
- }
-
--static int qca808x_phy_fast_retrain_config(struct phy_device *phydev)
--{
-- int ret;
--
-- /* Enable fast retrain */
-- ret = genphy_c45_fast_retrain(phydev, true);
-- if (ret)
-- return ret;
--
-- phy_write_mmd(phydev, MDIO_MMD_AN, QCA808X_PHY_MMD7_TOP_OPTION1,
-- QCA808X_TOP_OPTION1_DATA);
-- phy_write_mmd(phydev, MDIO_MMD_PMAPMD, QCA808X_PHY_MMD1_MSE_THRESHOLD_20DB,
-- QCA808X_MSE_THRESHOLD_20DB_VALUE);
-- phy_write_mmd(phydev, MDIO_MMD_PMAPMD, QCA808X_PHY_MMD1_MSE_THRESHOLD_17DB,
-- QCA808X_MSE_THRESHOLD_17DB_VALUE);
-- phy_write_mmd(phydev, MDIO_MMD_PMAPMD, QCA808X_PHY_MMD1_MSE_THRESHOLD_27DB,
-- QCA808X_MSE_THRESHOLD_27DB_VALUE);
-- phy_write_mmd(phydev, MDIO_MMD_PMAPMD, QCA808X_PHY_MMD1_MSE_THRESHOLD_28DB,
-- QCA808X_MSE_THRESHOLD_28DB_VALUE);
-- phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_1,
-- QCA808X_MMD3_DEBUG_1_VALUE);
-- phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_4,
-- QCA808X_MMD3_DEBUG_4_VALUE);
-- phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_5,
-- QCA808X_MMD3_DEBUG_5_VALUE);
-- phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_3,
-- QCA808X_MMD3_DEBUG_3_VALUE);
-- phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_6,
-- QCA808X_MMD3_DEBUG_6_VALUE);
-- phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_2,
-- QCA808X_MMD3_DEBUG_2_VALUE);
--
-- return 0;
--}
--
--static int qca808x_phy_ms_seed_enable(struct phy_device *phydev, bool enable)
--{
-- u16 seed_value;
--
-- if (!enable)
-- return at803x_debug_reg_mask(phydev, QCA808X_PHY_DEBUG_LOCAL_SEED,
-- QCA808X_MASTER_SLAVE_SEED_ENABLE, 0);
--
-- seed_value = get_random_u32_below(QCA808X_MASTER_SLAVE_SEED_RANGE);
-- return at803x_debug_reg_mask(phydev, QCA808X_PHY_DEBUG_LOCAL_SEED,
-- QCA808X_MASTER_SLAVE_SEED_CFG | QCA808X_MASTER_SLAVE_SEED_ENABLE,
-- FIELD_PREP(QCA808X_MASTER_SLAVE_SEED_CFG, seed_value) |
-- QCA808X_MASTER_SLAVE_SEED_ENABLE);
--}
--
--static bool qca808x_is_prefer_master(struct phy_device *phydev)
--{
-- return (phydev->master_slave_get == MASTER_SLAVE_CFG_MASTER_FORCE) ||
-- (phydev->master_slave_get == MASTER_SLAVE_CFG_MASTER_PREFERRED);
--}
--
--static bool qca808x_has_fast_retrain_or_slave_seed(struct phy_device *phydev)
--{
-- return linkmode_test_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, phydev->supported);
--}
--
--static int qca808x_config_init(struct phy_device *phydev)
--{
-- int ret;
--
-- /* Active adc&vga on 802.3az for the link 1000M and 100M */
-- ret = phy_modify_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_ADDR_CLD_CTRL7,
-- QCA808X_8023AZ_AFE_CTRL_MASK, QCA808X_8023AZ_AFE_EN);
-- if (ret)
-- return ret;
--
-- /* Adjust the threshold on 802.3az for the link 1000M */
-- ret = phy_write_mmd(phydev, MDIO_MMD_PCS,
-- QCA808X_PHY_MMD3_AZ_TRAINING_CTRL,
-- QCA808X_MMD3_AZ_TRAINING_VAL);
-- if (ret)
-- return ret;
--
-- if (qca808x_has_fast_retrain_or_slave_seed(phydev)) {
-- /* Config the fast retrain for the link 2500M */
-- ret = qca808x_phy_fast_retrain_config(phydev);
-- if (ret)
-- return ret;
--
-- ret = genphy_read_master_slave(phydev);
-- if (ret < 0)
-- return ret;
--
-- if (!qca808x_is_prefer_master(phydev)) {
-- /* Enable seed and configure lower ramdom seed to make phy
-- * linked as slave mode.
-- */
-- ret = qca808x_phy_ms_seed_enable(phydev, true);
-- if (ret)
-- return ret;
-- }
-- }
--
-- /* Configure adc threshold as 100mv for the link 10M */
-- return at803x_debug_reg_mask(phydev, QCA808X_PHY_DEBUG_ADC_THRESHOLD,
-- QCA808X_ADC_THRESHOLD_MASK,
-- QCA808X_ADC_THRESHOLD_100MV);
--}
--
--static int qca808x_read_status(struct phy_device *phydev)
--{
-- struct at803x_ss_mask ss_mask = { 0 };
-- int ret;
--
-- ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_10GBT_STAT);
-- if (ret < 0)
-- return ret;
--
-- linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, phydev->lp_advertising,
-- ret & MDIO_AN_10GBT_STAT_LP2_5G);
--
-- ret = genphy_read_status(phydev);
-- if (ret)
-- return ret;
--
-- /* qca8081 takes the different bits for speed value from at803x */
-- ss_mask.speed_mask = QCA808X_SS_SPEED_MASK;
-- ss_mask.speed_shift = __bf_shf(QCA808X_SS_SPEED_MASK);
-- ret = at803x_read_specific_status(phydev, ss_mask);
-- if (ret < 0)
-- return ret;
--
-- if (phydev->link) {
-- if (phydev->speed == SPEED_2500)
-- phydev->interface = PHY_INTERFACE_MODE_2500BASEX;
-- else
-- phydev->interface = PHY_INTERFACE_MODE_SGMII;
-- } else {
-- /* generate seed as a lower random value to make PHY linked as SLAVE easily,
-- * except for master/slave configuration fault detected or the master mode
-- * preferred.
-- *
-- * the reason for not putting this code into the function link_change_notify is
-- * the corner case where the link partner is also the qca8081 PHY and the seed
-- * value is configured as the same value, the link can't be up and no link change
-- * occurs.
-- */
-- if (qca808x_has_fast_retrain_or_slave_seed(phydev)) {
-- if (phydev->master_slave_state == MASTER_SLAVE_STATE_ERR ||
-- qca808x_is_prefer_master(phydev)) {
-- qca808x_phy_ms_seed_enable(phydev, false);
-- } else {
-- qca808x_phy_ms_seed_enable(phydev, true);
-- }
-- }
-- }
--
-- return 0;
--}
--
--static int qca808x_soft_reset(struct phy_device *phydev)
--{
-- int ret;
--
-- ret = genphy_soft_reset(phydev);
-- if (ret < 0)
-- return ret;
--
-- if (qca808x_has_fast_retrain_or_slave_seed(phydev))
-- ret = qca808x_phy_ms_seed_enable(phydev, true);
--
-- return ret;
--}
--
--static bool qca808x_cdt_fault_length_valid(int cdt_code)
--{
-- switch (cdt_code) {
-- case QCA808X_CDT_STATUS_STAT_SAME_SHORT:
-- case QCA808X_CDT_STATUS_STAT_SAME_OPEN:
-- case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_NORMAL:
-- case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_OPEN:
-- case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_SHORT:
-- case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_NORMAL:
-- case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_OPEN:
-- case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_SHORT:
-- case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_NORMAL:
-- case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_OPEN:
-- case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_SHORT:
-- return true;
-- default:
-- return false;
-- }
--}
--
--static int qca808x_cable_test_result_trans(int cdt_code)
--{
-- switch (cdt_code) {
-- case QCA808X_CDT_STATUS_STAT_NORMAL:
-- return ETHTOOL_A_CABLE_RESULT_CODE_OK;
-- case QCA808X_CDT_STATUS_STAT_SAME_SHORT:
-- return ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT;
-- case QCA808X_CDT_STATUS_STAT_SAME_OPEN:
-- return ETHTOOL_A_CABLE_RESULT_CODE_OPEN;
-- case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_NORMAL:
-- case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_OPEN:
-- case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_SHORT:
-- case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_NORMAL:
-- case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_OPEN:
-- case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_SHORT:
-- case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_NORMAL:
-- case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_OPEN:
-- case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_SHORT:
-- return ETHTOOL_A_CABLE_RESULT_CODE_CROSS_SHORT;
-- case QCA808X_CDT_STATUS_STAT_FAIL:
-- default:
-- return ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC;
-- }
--}
--
--static int qca808x_cdt_fault_length(struct phy_device *phydev, int pair,
-- int result)
--{
-- int val;
-- u32 cdt_length_reg = 0;
--
-- switch (pair) {
-- case ETHTOOL_A_CABLE_PAIR_A:
-- cdt_length_reg = QCA808X_MMD3_CDT_DIAG_PAIR_A;
-- break;
-- case ETHTOOL_A_CABLE_PAIR_B:
-- cdt_length_reg = QCA808X_MMD3_CDT_DIAG_PAIR_B;
-- break;
-- case ETHTOOL_A_CABLE_PAIR_C:
-- cdt_length_reg = QCA808X_MMD3_CDT_DIAG_PAIR_C;
-- break;
-- case ETHTOOL_A_CABLE_PAIR_D:
-- cdt_length_reg = QCA808X_MMD3_CDT_DIAG_PAIR_D;
-- break;
-- default:
-- return -EINVAL;
-- }
--
-- val = phy_read_mmd(phydev, MDIO_MMD_PCS, cdt_length_reg);
-- if (val < 0)
-- return val;
--
-- if (result == ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT)
-- val = FIELD_GET(QCA808X_CDT_DIAG_LENGTH_SAME_SHORT, val);
-- else
-- val = FIELD_GET(QCA808X_CDT_DIAG_LENGTH_CROSS_SHORT, val);
--
-- return at803x_cdt_fault_length(val);
--}
--
--static int qca808x_cable_test_start(struct phy_device *phydev)
--{
-- int ret;
--
-- /* perform CDT with the following configs:
-- * 1. disable hibernation.
-- * 2. force PHY working in MDI mode.
-- * 3. for PHY working in 1000BaseT.
-- * 4. configure the threshold.
-- */
--
-- ret = at803x_debug_reg_mask(phydev, QCA808X_DBG_AN_TEST, QCA808X_HIBERNATION_EN, 0);
-- if (ret < 0)
-- return ret;
--
-- ret = at803x_config_mdix(phydev, ETH_TP_MDI);
-- if (ret < 0)
-- return ret;
--
-- /* Force 1000base-T needs to configure PMA/PMD and MII_BMCR */
-- phydev->duplex = DUPLEX_FULL;
-- phydev->speed = SPEED_1000;
-- ret = genphy_c45_pma_setup_forced(phydev);
-- if (ret < 0)
-- return ret;
--
-- ret = genphy_setup_forced(phydev);
-- if (ret < 0)
-- return ret;
--
-- /* configure the thresholds for open, short, pair ok test */
-- phy_write_mmd(phydev, MDIO_MMD_PCS, 0x8074, 0xc040);
-- phy_write_mmd(phydev, MDIO_MMD_PCS, 0x8076, 0xc040);
-- phy_write_mmd(phydev, MDIO_MMD_PCS, 0x8077, 0xa060);
-- phy_write_mmd(phydev, MDIO_MMD_PCS, 0x8078, 0xc050);
-- phy_write_mmd(phydev, MDIO_MMD_PCS, 0x807a, 0xc060);
-- phy_write_mmd(phydev, MDIO_MMD_PCS, 0x807e, 0xb060);
--
-- return 0;
--}
--
--static int qca808x_cable_test_get_pair_status(struct phy_device *phydev, u8 pair,
-- u16 status)
--{
-- int length, result;
-- u16 pair_code;
--
-- switch (pair) {
-- case ETHTOOL_A_CABLE_PAIR_A:
-- pair_code = FIELD_GET(QCA808X_CDT_CODE_PAIR_A, status);
-- break;
-- case ETHTOOL_A_CABLE_PAIR_B:
-- pair_code = FIELD_GET(QCA808X_CDT_CODE_PAIR_B, status);
-- break;
-- case ETHTOOL_A_CABLE_PAIR_C:
-- pair_code = FIELD_GET(QCA808X_CDT_CODE_PAIR_C, status);
-- break;
-- case ETHTOOL_A_CABLE_PAIR_D:
-- pair_code = FIELD_GET(QCA808X_CDT_CODE_PAIR_D, status);
-- break;
-- default:
-- return -EINVAL;
-- }
--
-- result = qca808x_cable_test_result_trans(pair_code);
-- ethnl_cable_test_result(phydev, pair, result);
--
-- if (qca808x_cdt_fault_length_valid(pair_code)) {
-- length = qca808x_cdt_fault_length(phydev, pair, result);
-- ethnl_cable_test_fault_length(phydev, pair, length);
-- }
--
-- return 0;
--}
--
--static int qca808x_cable_test_get_status(struct phy_device *phydev, bool *finished)
--{
-- int ret, val;
--
-- *finished = false;
--
-- val = QCA808X_CDT_ENABLE_TEST |
-- QCA808X_CDT_LENGTH_UNIT;
-- ret = at803x_cdt_start(phydev, val);
-- if (ret)
-- return ret;
--
-- ret = at803x_cdt_wait_for_completion(phydev, QCA808X_CDT_ENABLE_TEST);
-- if (ret)
-- return ret;
--
-- val = phy_read_mmd(phydev, MDIO_MMD_PCS, QCA808X_MMD3_CDT_STATUS);
-- if (val < 0)
-- return val;
--
-- ret = qca808x_cable_test_get_pair_status(phydev, ETHTOOL_A_CABLE_PAIR_A, val);
-- if (ret)
-- return ret;
--
-- ret = qca808x_cable_test_get_pair_status(phydev, ETHTOOL_A_CABLE_PAIR_B, val);
-- if (ret)
-- return ret;
--
-- ret = qca808x_cable_test_get_pair_status(phydev, ETHTOOL_A_CABLE_PAIR_C, val);
-- if (ret)
-- return ret;
--
-- ret = qca808x_cable_test_get_pair_status(phydev, ETHTOOL_A_CABLE_PAIR_D, val);
-- if (ret)
-- return ret;
--
-- *finished = true;
--
-- return 0;
--}
--
--static int qca808x_get_features(struct phy_device *phydev)
--{
-- int ret;
--
-- ret = genphy_c45_pma_read_abilities(phydev);
-- if (ret)
-- return ret;
--
-- /* The autoneg ability is not existed in bit3 of MMD7.1,
-- * but it is supported by qca808x PHY, so we add it here
-- * manually.
-- */
-- linkmode_set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, phydev->supported);
--
-- /* As for the qca8081 1G version chip, the 2500baseT ability is also
-- * existed in the bit0 of MMD1.21, we need to remove it manually if
-- * it is the qca8081 1G chip according to the bit0 of MMD7.0x901d.
-- */
-- ret = phy_read_mmd(phydev, MDIO_MMD_AN, QCA808X_PHY_MMD7_CHIP_TYPE);
-- if (ret < 0)
-- return ret;
--
-- if (QCA808X_PHY_CHIP_TYPE_1G & ret)
-- linkmode_clear_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, phydev->supported);
--
-- return 0;
--}
--
--static int qca808x_config_aneg(struct phy_device *phydev)
--{
-- int phy_ctrl = 0;
-- int ret;
--
-- ret = at803x_prepare_config_aneg(phydev);
-- if (ret)
-- return ret;
--
-- /* The reg MII_BMCR also needs to be configured for force mode, the
-- * genphy_config_aneg is also needed.
-- */
-- if (phydev->autoneg == AUTONEG_DISABLE)
-- genphy_c45_pma_setup_forced(phydev);
--
-- if (linkmode_test_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, phydev->advertising))
-- phy_ctrl = MDIO_AN_10GBT_CTRL_ADV2_5G;
--
-- ret = phy_modify_mmd_changed(phydev, MDIO_MMD_AN, MDIO_AN_10GBT_CTRL,
-- MDIO_AN_10GBT_CTRL_ADV2_5G, phy_ctrl);
-- if (ret < 0)
-- return ret;
--
-- return __genphy_config_aneg(phydev, ret);
--}
--
--static void qca808x_link_change_notify(struct phy_device *phydev)
--{
-- /* Assert interface sgmii fifo on link down, deassert it on link up,
-- * the interface device address is always phy address added by 1.
-- */
-- mdiobus_c45_modify_changed(phydev->mdio.bus, phydev->mdio.addr + 1,
-- MDIO_MMD_PMAPMD, QCA8081_PHY_SERDES_MMD1_FIFO_CTRL,
-- QCA8081_PHY_FIFO_RSTN,
-- phydev->link ? QCA8081_PHY_FIFO_RSTN : 0);
--}
--
--static int qca808x_led_parse_netdev(struct phy_device *phydev, unsigned long rules,
-- u16 *offload_trigger)
--{
-- /* Parsing specific to netdev trigger */
-- if (test_bit(TRIGGER_NETDEV_TX, &rules))
-- *offload_trigger |= QCA808X_LED_TX_BLINK;
-- if (test_bit(TRIGGER_NETDEV_RX, &rules))
-- *offload_trigger |= QCA808X_LED_RX_BLINK;
-- if (test_bit(TRIGGER_NETDEV_LINK_10, &rules))
-- *offload_trigger |= QCA808X_LED_SPEED10_ON;
-- if (test_bit(TRIGGER_NETDEV_LINK_100, &rules))
-- *offload_trigger |= QCA808X_LED_SPEED100_ON;
-- if (test_bit(TRIGGER_NETDEV_LINK_1000, &rules))
-- *offload_trigger |= QCA808X_LED_SPEED1000_ON;
-- if (test_bit(TRIGGER_NETDEV_LINK_2500, &rules))
-- *offload_trigger |= QCA808X_LED_SPEED2500_ON;
-- if (test_bit(TRIGGER_NETDEV_HALF_DUPLEX, &rules))
-- *offload_trigger |= QCA808X_LED_HALF_DUPLEX_ON;
-- if (test_bit(TRIGGER_NETDEV_FULL_DUPLEX, &rules))
-- *offload_trigger |= QCA808X_LED_FULL_DUPLEX_ON;
--
-- if (rules && !*offload_trigger)
-- return -EOPNOTSUPP;
--
-- /* Enable BLINK_CHECK_BYPASS by default to make the LED
-- * blink even with duplex or speed mode not enabled.
-- */
-- *offload_trigger |= QCA808X_LED_BLINK_CHECK_BYPASS;
--
-- return 0;
--}
--
--static int qca808x_led_hw_control_enable(struct phy_device *phydev, u8 index)
--{
-- u16 reg;
--
-- if (index > 2)
-- return -EINVAL;
--
-- reg = QCA808X_MMD7_LED_FORCE_CTRL(index);
--
-- return phy_clear_bits_mmd(phydev, MDIO_MMD_AN, reg,
-- QCA808X_LED_FORCE_EN);
--}
--
--static int qca808x_led_hw_is_supported(struct phy_device *phydev, u8 index,
-- unsigned long rules)
--{
-- u16 offload_trigger = 0;
--
-- if (index > 2)
-- return -EINVAL;
--
-- return qca808x_led_parse_netdev(phydev, rules, &offload_trigger);
--}
--
--static int qca808x_led_hw_control_set(struct phy_device *phydev, u8 index,
-- unsigned long rules)
--{
-- u16 reg, offload_trigger = 0;
-- int ret;
--
-- if (index > 2)
-- return -EINVAL;
--
-- reg = QCA808X_MMD7_LED_CTRL(index);
--
-- ret = qca808x_led_parse_netdev(phydev, rules, &offload_trigger);
-- if (ret)
-- return ret;
--
-- ret = qca808x_led_hw_control_enable(phydev, index);
-- if (ret)
-- return ret;
--
-- return phy_modify_mmd(phydev, MDIO_MMD_AN, reg,
-- QCA808X_LED_PATTERN_MASK,
-- offload_trigger);
--}
--
--static bool qca808x_led_hw_control_status(struct phy_device *phydev, u8 index)
--{
-- u16 reg;
-- int val;
--
-- if (index > 2)
-- return false;
--
-- reg = QCA808X_MMD7_LED_FORCE_CTRL(index);
--
-- val = phy_read_mmd(phydev, MDIO_MMD_AN, reg);
--
-- return !(val & QCA808X_LED_FORCE_EN);
--}
--
--static int qca808x_led_hw_control_get(struct phy_device *phydev, u8 index,
-- unsigned long *rules)
--{
-- u16 reg;
-- int val;
--
-- if (index > 2)
-- return -EINVAL;
--
-- /* Check if we have hw control enabled */
-- if (qca808x_led_hw_control_status(phydev, index))
-- return -EINVAL;
--
-- reg = QCA808X_MMD7_LED_CTRL(index);
--
-- val = phy_read_mmd(phydev, MDIO_MMD_AN, reg);
-- if (val & QCA808X_LED_TX_BLINK)
-- set_bit(TRIGGER_NETDEV_TX, rules);
-- if (val & QCA808X_LED_RX_BLINK)
-- set_bit(TRIGGER_NETDEV_RX, rules);
-- if (val & QCA808X_LED_SPEED10_ON)
-- set_bit(TRIGGER_NETDEV_LINK_10, rules);
-- if (val & QCA808X_LED_SPEED100_ON)
-- set_bit(TRIGGER_NETDEV_LINK_100, rules);
-- if (val & QCA808X_LED_SPEED1000_ON)
-- set_bit(TRIGGER_NETDEV_LINK_1000, rules);
-- if (val & QCA808X_LED_SPEED2500_ON)
-- set_bit(TRIGGER_NETDEV_LINK_2500, rules);
-- if (val & QCA808X_LED_HALF_DUPLEX_ON)
-- set_bit(TRIGGER_NETDEV_HALF_DUPLEX, rules);
-- if (val & QCA808X_LED_FULL_DUPLEX_ON)
-- set_bit(TRIGGER_NETDEV_FULL_DUPLEX, rules);
--
-- return 0;
--}
--
--static int qca808x_led_hw_control_reset(struct phy_device *phydev, u8 index)
--{
-- u16 reg;
--
-- if (index > 2)
-- return -EINVAL;
--
-- reg = QCA808X_MMD7_LED_CTRL(index);
--
-- return phy_clear_bits_mmd(phydev, MDIO_MMD_AN, reg,
-- QCA808X_LED_PATTERN_MASK);
--}
--
--static int qca808x_led_brightness_set(struct phy_device *phydev,
-- u8 index, enum led_brightness value)
--{
-- u16 reg;
-- int ret;
--
-- if (index > 2)
-- return -EINVAL;
--
-- if (!value) {
-- ret = qca808x_led_hw_control_reset(phydev, index);
-- if (ret)
-- return ret;
-- }
--
-- reg = QCA808X_MMD7_LED_FORCE_CTRL(index);
--
-- return phy_modify_mmd(phydev, MDIO_MMD_AN, reg,
-- QCA808X_LED_FORCE_EN | QCA808X_LED_FORCE_MODE_MASK,
-- QCA808X_LED_FORCE_EN | value ? QCA808X_LED_FORCE_ON :
-- QCA808X_LED_FORCE_OFF);
--}
--
--static int qca808x_led_blink_set(struct phy_device *phydev, u8 index,
-- unsigned long *delay_on,
-- unsigned long *delay_off)
--{
-- int ret;
-- u16 reg;
--
-- if (index > 2)
-- return -EINVAL;
--
-- reg = QCA808X_MMD7_LED_FORCE_CTRL(index);
--
-- /* Set blink to 50% off, 50% on at 4Hz by default */
-- ret = phy_modify_mmd(phydev, MDIO_MMD_AN, QCA808X_MMD7_LED_GLOBAL,
-- QCA808X_LED_BLINK_FREQ_MASK | QCA808X_LED_BLINK_DUTY_MASK,
-- QCA808X_LED_BLINK_FREQ_4HZ | QCA808X_LED_BLINK_DUTY_50_50);
-- if (ret)
-- return ret;
--
-- /* We use BLINK_1 for normal blinking */
-- ret = phy_modify_mmd(phydev, MDIO_MMD_AN, reg,
-- QCA808X_LED_FORCE_EN | QCA808X_LED_FORCE_MODE_MASK,
-- QCA808X_LED_FORCE_EN | QCA808X_LED_FORCE_BLINK_1);
-- if (ret)
-- return ret;
--
-- /* We set blink to 4Hz, aka 250ms */
-- *delay_on = 250 / 2;
-- *delay_off = 250 / 2;
--
-- return 0;
--}
--
--static int qca808x_led_polarity_set(struct phy_device *phydev, int index,
-- unsigned long modes)
--{
-- struct at803x_priv *priv = phydev->priv;
-- bool active_low = false;
-- u32 mode;
--
-- for_each_set_bit(mode, &modes, __PHY_LED_MODES_NUM) {
-- switch (mode) {
-- case PHY_LED_ACTIVE_LOW:
-- active_low = true;
-- break;
-- default:
-- return -EINVAL;
-- }
-- }
--
-- /* PHY polarity is global and can't be set per LED.
-- * To detect this, check if last requested polarity mode
-- * match the new one.
-- */
-- if (priv->led_polarity_mode >= 0 &&
-- priv->led_polarity_mode != active_low) {
-- phydev_err(phydev, "PHY polarity is global. Mismatched polarity on different LED\n");
-- return -EINVAL;
-- }
--
-- /* Save the last PHY polarity mode */
-- priv->led_polarity_mode = active_low;
--
-- return phy_modify_mmd(phydev, MDIO_MMD_AN,
-- QCA808X_MMD7_LED_POLARITY_CTRL,
-- QCA808X_LED_ACTIVE_HIGH,
-- active_low ? 0 : QCA808X_LED_ACTIVE_HIGH);
--}
--
- static struct phy_driver at803x_driver[] = {
- {
- /* Qualcomm Atheros AR8035 */
-@@ -1989,34 +1123,6 @@ static struct phy_driver at803x_driver[]
- .read_status = at803x_read_status,
- .soft_reset = genphy_soft_reset,
- .config_aneg = at803x_config_aneg,
--}, {
-- /* Qualcomm QCA8081 */
-- PHY_ID_MATCH_EXACT(QCA8081_PHY_ID),
-- .name = "Qualcomm QCA8081",
-- .flags = PHY_POLL_CABLE_TEST,
-- .probe = at803x_probe,
-- .config_intr = at803x_config_intr,
-- .handle_interrupt = at803x_handle_interrupt,
-- .get_tunable = at803x_get_tunable,
-- .set_tunable = at803x_set_tunable,
-- .set_wol = at803x_set_wol,
-- .get_wol = at803x_get_wol,
-- .get_features = qca808x_get_features,
-- .config_aneg = qca808x_config_aneg,
-- .suspend = genphy_suspend,
-- .resume = genphy_resume,
-- .read_status = qca808x_read_status,
-- .config_init = qca808x_config_init,
-- .soft_reset = qca808x_soft_reset,
-- .cable_test_start = qca808x_cable_test_start,
-- .cable_test_get_status = qca808x_cable_test_get_status,
-- .link_change_notify = qca808x_link_change_notify,
-- .led_brightness_set = qca808x_led_brightness_set,
-- .led_blink_set = qca808x_led_blink_set,
-- .led_hw_is_supported = qca808x_led_hw_is_supported,
-- .led_hw_control_set = qca808x_led_hw_control_set,
-- .led_hw_control_get = qca808x_led_hw_control_get,
-- .led_polarity_set = qca808x_led_polarity_set,
- }, };
-
- module_phy_driver(at803x_driver);
-@@ -2028,7 +1134,6 @@ static struct mdio_device_id __maybe_unu
- { PHY_ID_MATCH_EXACT(ATH8035_PHY_ID) },
- { PHY_ID_MATCH_EXACT(ATH9331_PHY_ID) },
- { PHY_ID_MATCH_EXACT(QCA9561_PHY_ID) },
-- { PHY_ID_MATCH_EXACT(QCA8081_PHY_ID) },
- { }
- };
-
---- /dev/null
-+++ b/drivers/net/phy/qcom/qca808x.c
-@@ -0,0 +1,934 @@
-+// SPDX-License-Identifier: GPL-2.0+
-+
-+#include <linux/phy.h>
-+#include <linux/module.h>
-+#include <linux/ethtool_netlink.h>
-+
-+#include "qcom.h"
-+
-+/* ADC threshold */
-+#define QCA808X_PHY_DEBUG_ADC_THRESHOLD 0x2c80
-+#define QCA808X_ADC_THRESHOLD_MASK GENMASK(7, 0)
-+#define QCA808X_ADC_THRESHOLD_80MV 0
-+#define QCA808X_ADC_THRESHOLD_100MV 0xf0
-+#define QCA808X_ADC_THRESHOLD_200MV 0x0f
-+#define QCA808X_ADC_THRESHOLD_300MV 0xff
-+
-+/* CLD control */
-+#define QCA808X_PHY_MMD3_ADDR_CLD_CTRL7 0x8007
-+#define QCA808X_8023AZ_AFE_CTRL_MASK GENMASK(8, 4)
-+#define QCA808X_8023AZ_AFE_EN 0x90
-+
-+/* AZ control */
-+#define QCA808X_PHY_MMD3_AZ_TRAINING_CTRL 0x8008
-+#define QCA808X_MMD3_AZ_TRAINING_VAL 0x1c32
-+
-+#define QCA808X_PHY_MMD1_MSE_THRESHOLD_20DB 0x8014
-+#define QCA808X_MSE_THRESHOLD_20DB_VALUE 0x529
-+
-+#define QCA808X_PHY_MMD1_MSE_THRESHOLD_17DB 0x800E
-+#define QCA808X_MSE_THRESHOLD_17DB_VALUE 0x341
-+
-+#define QCA808X_PHY_MMD1_MSE_THRESHOLD_27DB 0x801E
-+#define QCA808X_MSE_THRESHOLD_27DB_VALUE 0x419
-+
-+#define QCA808X_PHY_MMD1_MSE_THRESHOLD_28DB 0x8020
-+#define QCA808X_MSE_THRESHOLD_28DB_VALUE 0x341
-+
-+#define QCA808X_PHY_MMD7_TOP_OPTION1 0x901c
-+#define QCA808X_TOP_OPTION1_DATA 0x0
-+
-+#define QCA808X_PHY_MMD3_DEBUG_1 0xa100
-+#define QCA808X_MMD3_DEBUG_1_VALUE 0x9203
-+#define QCA808X_PHY_MMD3_DEBUG_2 0xa101
-+#define QCA808X_MMD3_DEBUG_2_VALUE 0x48ad
-+#define QCA808X_PHY_MMD3_DEBUG_3 0xa103
-+#define QCA808X_MMD3_DEBUG_3_VALUE 0x1698
-+#define QCA808X_PHY_MMD3_DEBUG_4 0xa105
-+#define QCA808X_MMD3_DEBUG_4_VALUE 0x8001
-+#define QCA808X_PHY_MMD3_DEBUG_5 0xa106
-+#define QCA808X_MMD3_DEBUG_5_VALUE 0x1111
-+#define QCA808X_PHY_MMD3_DEBUG_6 0xa011
-+#define QCA808X_MMD3_DEBUG_6_VALUE 0x5f85
-+
-+/* master/slave seed config */
-+#define QCA808X_PHY_DEBUG_LOCAL_SEED 9
-+#define QCA808X_MASTER_SLAVE_SEED_ENABLE BIT(1)
-+#define QCA808X_MASTER_SLAVE_SEED_CFG GENMASK(12, 2)
-+#define QCA808X_MASTER_SLAVE_SEED_RANGE 0x32
-+
-+/* Hibernation yields lower power consumpiton in contrast with normal operation mode.
-+ * when the copper cable is unplugged, the PHY enters into hibernation mode in about 10s.
-+ */
-+#define QCA808X_DBG_AN_TEST 0xb
-+#define QCA808X_HIBERNATION_EN BIT(15)
-+
-+#define QCA808X_CDT_ENABLE_TEST BIT(15)
-+#define QCA808X_CDT_INTER_CHECK_DIS BIT(13)
-+#define QCA808X_CDT_STATUS BIT(11)
-+#define QCA808X_CDT_LENGTH_UNIT BIT(10)
-+
-+#define QCA808X_MMD3_CDT_STATUS 0x8064
-+#define QCA808X_MMD3_CDT_DIAG_PAIR_A 0x8065
-+#define QCA808X_MMD3_CDT_DIAG_PAIR_B 0x8066
-+#define QCA808X_MMD3_CDT_DIAG_PAIR_C 0x8067
-+#define QCA808X_MMD3_CDT_DIAG_PAIR_D 0x8068
-+#define QCA808X_CDT_DIAG_LENGTH_SAME_SHORT GENMASK(15, 8)
-+#define QCA808X_CDT_DIAG_LENGTH_CROSS_SHORT GENMASK(7, 0)
-+
-+#define QCA808X_CDT_CODE_PAIR_A GENMASK(15, 12)
-+#define QCA808X_CDT_CODE_PAIR_B GENMASK(11, 8)
-+#define QCA808X_CDT_CODE_PAIR_C GENMASK(7, 4)
-+#define QCA808X_CDT_CODE_PAIR_D GENMASK(3, 0)
-+
-+#define QCA808X_CDT_STATUS_STAT_TYPE GENMASK(1, 0)
-+#define QCA808X_CDT_STATUS_STAT_FAIL FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_TYPE, 0)
-+#define QCA808X_CDT_STATUS_STAT_NORMAL FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_TYPE, 1)
-+#define QCA808X_CDT_STATUS_STAT_SAME_OPEN FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_TYPE, 2)
-+#define QCA808X_CDT_STATUS_STAT_SAME_SHORT FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_TYPE, 3)
-+
-+#define QCA808X_CDT_STATUS_STAT_MDI GENMASK(3, 2)
-+#define QCA808X_CDT_STATUS_STAT_MDI1 FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_MDI, 1)
-+#define QCA808X_CDT_STATUS_STAT_MDI2 FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_MDI, 2)
-+#define QCA808X_CDT_STATUS_STAT_MDI3 FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_MDI, 3)
-+
-+/* NORMAL are MDI with type set to 0 */
-+#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_NORMAL QCA808X_CDT_STATUS_STAT_MDI1
-+#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_OPEN (QCA808X_CDT_STATUS_STAT_SAME_OPEN |\
-+ QCA808X_CDT_STATUS_STAT_MDI1)
-+#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_SHORT (QCA808X_CDT_STATUS_STAT_SAME_SHORT |\
-+ QCA808X_CDT_STATUS_STAT_MDI1)
-+#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_NORMAL QCA808X_CDT_STATUS_STAT_MDI2
-+#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_OPEN (QCA808X_CDT_STATUS_STAT_SAME_OPEN |\
-+ QCA808X_CDT_STATUS_STAT_MDI2)
-+#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_SHORT (QCA808X_CDT_STATUS_STAT_SAME_SHORT |\
-+ QCA808X_CDT_STATUS_STAT_MDI2)
-+#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_NORMAL QCA808X_CDT_STATUS_STAT_MDI3
-+#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_OPEN (QCA808X_CDT_STATUS_STAT_SAME_OPEN |\
-+ QCA808X_CDT_STATUS_STAT_MDI3)
-+#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_SHORT (QCA808X_CDT_STATUS_STAT_SAME_SHORT |\
-+ QCA808X_CDT_STATUS_STAT_MDI3)
-+
-+/* Added for reference of existence but should be handled by wait_for_completion already */
-+#define QCA808X_CDT_STATUS_STAT_BUSY (BIT(1) | BIT(3))
-+
-+#define QCA808X_MMD7_LED_GLOBAL 0x8073
-+#define QCA808X_LED_BLINK_1 GENMASK(11, 6)
-+#define QCA808X_LED_BLINK_2 GENMASK(5, 0)
-+/* Values are the same for both BLINK_1 and BLINK_2 */
-+#define QCA808X_LED_BLINK_FREQ_MASK GENMASK(5, 3)
-+#define QCA808X_LED_BLINK_FREQ_2HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x0)
-+#define QCA808X_LED_BLINK_FREQ_4HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x1)
-+#define QCA808X_LED_BLINK_FREQ_8HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x2)
-+#define QCA808X_LED_BLINK_FREQ_16HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x3)
-+#define QCA808X_LED_BLINK_FREQ_32HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x4)
-+#define QCA808X_LED_BLINK_FREQ_64HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x5)
-+#define QCA808X_LED_BLINK_FREQ_128HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x6)
-+#define QCA808X_LED_BLINK_FREQ_256HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x7)
-+#define QCA808X_LED_BLINK_DUTY_MASK GENMASK(2, 0)
-+#define QCA808X_LED_BLINK_DUTY_50_50 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x0)
-+#define QCA808X_LED_BLINK_DUTY_75_25 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x1)
-+#define QCA808X_LED_BLINK_DUTY_25_75 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x2)
-+#define QCA808X_LED_BLINK_DUTY_33_67 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x3)
-+#define QCA808X_LED_BLINK_DUTY_67_33 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x4)
-+#define QCA808X_LED_BLINK_DUTY_17_83 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x5)
-+#define QCA808X_LED_BLINK_DUTY_83_17 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x6)
-+#define QCA808X_LED_BLINK_DUTY_8_92 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x7)
-+
-+#define QCA808X_MMD7_LED2_CTRL 0x8074
-+#define QCA808X_MMD7_LED2_FORCE_CTRL 0x8075
-+#define QCA808X_MMD7_LED1_CTRL 0x8076
-+#define QCA808X_MMD7_LED1_FORCE_CTRL 0x8077
-+#define QCA808X_MMD7_LED0_CTRL 0x8078
-+#define QCA808X_MMD7_LED_CTRL(x) (0x8078 - ((x) * 2))
-+
-+/* LED hw control pattern is the same for every LED */
-+#define QCA808X_LED_PATTERN_MASK GENMASK(15, 0)
-+#define QCA808X_LED_SPEED2500_ON BIT(15)
-+#define QCA808X_LED_SPEED2500_BLINK BIT(14)
-+/* Follow blink trigger even if duplex or speed condition doesn't match */
-+#define QCA808X_LED_BLINK_CHECK_BYPASS BIT(13)
-+#define QCA808X_LED_FULL_DUPLEX_ON BIT(12)
-+#define QCA808X_LED_HALF_DUPLEX_ON BIT(11)
-+#define QCA808X_LED_TX_BLINK BIT(10)
-+#define QCA808X_LED_RX_BLINK BIT(9)
-+#define QCA808X_LED_TX_ON_10MS BIT(8)
-+#define QCA808X_LED_RX_ON_10MS BIT(7)
-+#define QCA808X_LED_SPEED1000_ON BIT(6)
-+#define QCA808X_LED_SPEED100_ON BIT(5)
-+#define QCA808X_LED_SPEED10_ON BIT(4)
-+#define QCA808X_LED_COLLISION_BLINK BIT(3)
-+#define QCA808X_LED_SPEED1000_BLINK BIT(2)
-+#define QCA808X_LED_SPEED100_BLINK BIT(1)
-+#define QCA808X_LED_SPEED10_BLINK BIT(0)
-+
-+#define QCA808X_MMD7_LED0_FORCE_CTRL 0x8079
-+#define QCA808X_MMD7_LED_FORCE_CTRL(x) (0x8079 - ((x) * 2))
-+
-+/* LED force ctrl is the same for every LED
-+ * No documentation exist for this, not even internal one
-+ * with NDA as QCOM gives only info about configuring
-+ * hw control pattern rules and doesn't indicate any way
-+ * to force the LED to specific mode.
-+ * These define comes from reverse and testing and maybe
-+ * lack of some info or some info are not entirely correct.
-+ * For the basic LED control and hw control these finding
-+ * are enough to support LED control in all the required APIs.
-+ *
-+ * On doing some comparison with implementation with qca807x,
-+ * it was found that it's 1:1 equal to it and confirms all the
-+ * reverse done. It was also found further specification with the
-+ * force mode and the blink modes.
-+ */
-+#define QCA808X_LED_FORCE_EN BIT(15)
-+#define QCA808X_LED_FORCE_MODE_MASK GENMASK(14, 13)
-+#define QCA808X_LED_FORCE_BLINK_1 FIELD_PREP(QCA808X_LED_FORCE_MODE_MASK, 0x3)
-+#define QCA808X_LED_FORCE_BLINK_2 FIELD_PREP(QCA808X_LED_FORCE_MODE_MASK, 0x2)
-+#define QCA808X_LED_FORCE_ON FIELD_PREP(QCA808X_LED_FORCE_MODE_MASK, 0x1)
-+#define QCA808X_LED_FORCE_OFF FIELD_PREP(QCA808X_LED_FORCE_MODE_MASK, 0x0)
-+
-+#define QCA808X_MMD7_LED_POLARITY_CTRL 0x901a
-+/* QSDK sets by default 0x46 to this reg that sets BIT 6 for
-+ * LED to active high. It's not clear what BIT 3 and BIT 4 does.
-+ */
-+#define QCA808X_LED_ACTIVE_HIGH BIT(6)
-+
-+/* QCA808X 1G chip type */
-+#define QCA808X_PHY_MMD7_CHIP_TYPE 0x901d
-+#define QCA808X_PHY_CHIP_TYPE_1G BIT(0)
-+
-+#define QCA8081_PHY_SERDES_MMD1_FIFO_CTRL 0x9072
-+#define QCA8081_PHY_FIFO_RSTN BIT(11)
-+
-+#define QCA8081_PHY_ID 0x004dd101
-+
-+MODULE_DESCRIPTION("Qualcomm Atheros QCA808X PHY driver");
-+MODULE_AUTHOR("Matus Ujhelyi");
-+MODULE_LICENSE("GPL");
-+
-+struct qca808x_priv {
-+ int led_polarity_mode;
-+};
-+
-+static int qca808x_phy_fast_retrain_config(struct phy_device *phydev)
-+{
-+ int ret;
-+
-+ /* Enable fast retrain */
-+ ret = genphy_c45_fast_retrain(phydev, true);
-+ if (ret)
-+ return ret;
-+
-+ phy_write_mmd(phydev, MDIO_MMD_AN, QCA808X_PHY_MMD7_TOP_OPTION1,
-+ QCA808X_TOP_OPTION1_DATA);
-+ phy_write_mmd(phydev, MDIO_MMD_PMAPMD, QCA808X_PHY_MMD1_MSE_THRESHOLD_20DB,
-+ QCA808X_MSE_THRESHOLD_20DB_VALUE);
-+ phy_write_mmd(phydev, MDIO_MMD_PMAPMD, QCA808X_PHY_MMD1_MSE_THRESHOLD_17DB,
-+ QCA808X_MSE_THRESHOLD_17DB_VALUE);
-+ phy_write_mmd(phydev, MDIO_MMD_PMAPMD, QCA808X_PHY_MMD1_MSE_THRESHOLD_27DB,
-+ QCA808X_MSE_THRESHOLD_27DB_VALUE);
-+ phy_write_mmd(phydev, MDIO_MMD_PMAPMD, QCA808X_PHY_MMD1_MSE_THRESHOLD_28DB,
-+ QCA808X_MSE_THRESHOLD_28DB_VALUE);
-+ phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_1,
-+ QCA808X_MMD3_DEBUG_1_VALUE);
-+ phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_4,
-+ QCA808X_MMD3_DEBUG_4_VALUE);
-+ phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_5,
-+ QCA808X_MMD3_DEBUG_5_VALUE);
-+ phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_3,
-+ QCA808X_MMD3_DEBUG_3_VALUE);
-+ phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_6,
-+ QCA808X_MMD3_DEBUG_6_VALUE);
-+ phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_2,
-+ QCA808X_MMD3_DEBUG_2_VALUE);
-+
-+ return 0;
-+}
-+
-+static int qca808x_phy_ms_seed_enable(struct phy_device *phydev, bool enable)
-+{
-+ u16 seed_value;
-+
-+ if (!enable)
-+ return at803x_debug_reg_mask(phydev, QCA808X_PHY_DEBUG_LOCAL_SEED,
-+ QCA808X_MASTER_SLAVE_SEED_ENABLE, 0);
-+
-+ seed_value = get_random_u32_below(QCA808X_MASTER_SLAVE_SEED_RANGE);
-+ return at803x_debug_reg_mask(phydev, QCA808X_PHY_DEBUG_LOCAL_SEED,
-+ QCA808X_MASTER_SLAVE_SEED_CFG | QCA808X_MASTER_SLAVE_SEED_ENABLE,
-+ FIELD_PREP(QCA808X_MASTER_SLAVE_SEED_CFG, seed_value) |
-+ QCA808X_MASTER_SLAVE_SEED_ENABLE);
-+}
-+
-+static bool qca808x_is_prefer_master(struct phy_device *phydev)
-+{
-+ return (phydev->master_slave_get == MASTER_SLAVE_CFG_MASTER_FORCE) ||
-+ (phydev->master_slave_get == MASTER_SLAVE_CFG_MASTER_PREFERRED);
-+}
-+
-+static bool qca808x_has_fast_retrain_or_slave_seed(struct phy_device *phydev)
-+{
-+ return linkmode_test_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, phydev->supported);
-+}
-+
-+static int qca808x_probe(struct phy_device *phydev)
-+{
-+ struct device *dev = &phydev->mdio.dev;
-+ struct qca808x_priv *priv;
-+
-+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
-+ if (!priv)
-+ return -ENOMEM;
-+
-+ /* Init LED polarity mode to -1 */
-+ priv->led_polarity_mode = -1;
-+
-+ phydev->priv = priv;
-+
-+ return 0;
-+}
-+
-+static int qca808x_config_init(struct phy_device *phydev)
-+{
-+ int ret;
-+
-+ /* Active adc&vga on 802.3az for the link 1000M and 100M */
-+ ret = phy_modify_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_ADDR_CLD_CTRL7,
-+ QCA808X_8023AZ_AFE_CTRL_MASK, QCA808X_8023AZ_AFE_EN);
-+ if (ret)
-+ return ret;
-+
-+ /* Adjust the threshold on 802.3az for the link 1000M */
-+ ret = phy_write_mmd(phydev, MDIO_MMD_PCS,
-+ QCA808X_PHY_MMD3_AZ_TRAINING_CTRL,
-+ QCA808X_MMD3_AZ_TRAINING_VAL);
-+ if (ret)
-+ return ret;
-+
-+ if (qca808x_has_fast_retrain_or_slave_seed(phydev)) {
-+ /* Config the fast retrain for the link 2500M */
-+ ret = qca808x_phy_fast_retrain_config(phydev);
-+ if (ret)
-+ return ret;
-+
-+ ret = genphy_read_master_slave(phydev);
-+ if (ret < 0)
-+ return ret;
-+
-+ if (!qca808x_is_prefer_master(phydev)) {
-+ /* Enable seed and configure lower ramdom seed to make phy
-+ * linked as slave mode.
-+ */
-+ ret = qca808x_phy_ms_seed_enable(phydev, true);
-+ if (ret)
-+ return ret;
-+ }
-+ }
-+
-+ /* Configure adc threshold as 100mv for the link 10M */
-+ return at803x_debug_reg_mask(phydev, QCA808X_PHY_DEBUG_ADC_THRESHOLD,
-+ QCA808X_ADC_THRESHOLD_MASK,
-+ QCA808X_ADC_THRESHOLD_100MV);
-+}
-+
-+static int qca808x_read_status(struct phy_device *phydev)
-+{
-+ struct at803x_ss_mask ss_mask = { 0 };
-+ int ret;
-+
-+ ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_10GBT_STAT);
-+ if (ret < 0)
-+ return ret;
-+
-+ linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, phydev->lp_advertising,
-+ ret & MDIO_AN_10GBT_STAT_LP2_5G);
-+
-+ ret = genphy_read_status(phydev);
-+ if (ret)
-+ return ret;
-+
-+ /* qca8081 takes the different bits for speed value from at803x */
-+ ss_mask.speed_mask = QCA808X_SS_SPEED_MASK;
-+ ss_mask.speed_shift = __bf_shf(QCA808X_SS_SPEED_MASK);
-+ ret = at803x_read_specific_status(phydev, ss_mask);
-+ if (ret < 0)
-+ return ret;
-+
-+ if (phydev->link) {
-+ if (phydev->speed == SPEED_2500)
-+ phydev->interface = PHY_INTERFACE_MODE_2500BASEX;
-+ else
-+ phydev->interface = PHY_INTERFACE_MODE_SGMII;
-+ } else {
-+ /* generate seed as a lower random value to make PHY linked as SLAVE easily,
-+ * except for master/slave configuration fault detected or the master mode
-+ * preferred.
-+ *
-+ * the reason for not putting this code into the function link_change_notify is
-+ * the corner case where the link partner is also the qca8081 PHY and the seed
-+ * value is configured as the same value, the link can't be up and no link change
-+ * occurs.
-+ */
-+ if (qca808x_has_fast_retrain_or_slave_seed(phydev)) {
-+ if (phydev->master_slave_state == MASTER_SLAVE_STATE_ERR ||
-+ qca808x_is_prefer_master(phydev)) {
-+ qca808x_phy_ms_seed_enable(phydev, false);
-+ } else {
-+ qca808x_phy_ms_seed_enable(phydev, true);
-+ }
-+ }
-+ }
-+
-+ return 0;
-+}
-+
-+static int qca808x_soft_reset(struct phy_device *phydev)
-+{
-+ int ret;
-+
-+ ret = genphy_soft_reset(phydev);
-+ if (ret < 0)
-+ return ret;
-+
-+ if (qca808x_has_fast_retrain_or_slave_seed(phydev))
-+ ret = qca808x_phy_ms_seed_enable(phydev, true);
-+
-+ return ret;
-+}
-+
-+static bool qca808x_cdt_fault_length_valid(int cdt_code)
-+{
-+ switch (cdt_code) {
-+ case QCA808X_CDT_STATUS_STAT_SAME_SHORT:
-+ case QCA808X_CDT_STATUS_STAT_SAME_OPEN:
-+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_NORMAL:
-+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_OPEN:
-+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_SHORT:
-+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_NORMAL:
-+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_OPEN:
-+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_SHORT:
-+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_NORMAL:
-+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_OPEN:
-+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_SHORT:
-+ return true;
-+ default:
-+ return false;
-+ }
-+}
-+
-+static int qca808x_cable_test_result_trans(int cdt_code)
-+{
-+ switch (cdt_code) {
-+ case QCA808X_CDT_STATUS_STAT_NORMAL:
-+ return ETHTOOL_A_CABLE_RESULT_CODE_OK;
-+ case QCA808X_CDT_STATUS_STAT_SAME_SHORT:
-+ return ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT;
-+ case QCA808X_CDT_STATUS_STAT_SAME_OPEN:
-+ return ETHTOOL_A_CABLE_RESULT_CODE_OPEN;
-+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_NORMAL:
-+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_OPEN:
-+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_SHORT:
-+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_NORMAL:
-+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_OPEN:
-+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_SHORT:
-+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_NORMAL:
-+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_OPEN:
-+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_SHORT:
-+ return ETHTOOL_A_CABLE_RESULT_CODE_CROSS_SHORT;
-+ case QCA808X_CDT_STATUS_STAT_FAIL:
-+ default:
-+ return ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC;
-+ }
-+}
-+
-+static int qca808x_cdt_fault_length(struct phy_device *phydev, int pair,
-+ int result)
-+{
-+ int val;
-+ u32 cdt_length_reg = 0;
-+
-+ switch (pair) {
-+ case ETHTOOL_A_CABLE_PAIR_A:
-+ cdt_length_reg = QCA808X_MMD3_CDT_DIAG_PAIR_A;
-+ break;
-+ case ETHTOOL_A_CABLE_PAIR_B:
-+ cdt_length_reg = QCA808X_MMD3_CDT_DIAG_PAIR_B;
-+ break;
-+ case ETHTOOL_A_CABLE_PAIR_C:
-+ cdt_length_reg = QCA808X_MMD3_CDT_DIAG_PAIR_C;
-+ break;
-+ case ETHTOOL_A_CABLE_PAIR_D:
-+ cdt_length_reg = QCA808X_MMD3_CDT_DIAG_PAIR_D;
-+ break;
-+ default:
-+ return -EINVAL;
-+ }
-+
-+ val = phy_read_mmd(phydev, MDIO_MMD_PCS, cdt_length_reg);
-+ if (val < 0)
-+ return val;
-+
-+ if (result == ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT)
-+ val = FIELD_GET(QCA808X_CDT_DIAG_LENGTH_SAME_SHORT, val);
-+ else
-+ val = FIELD_GET(QCA808X_CDT_DIAG_LENGTH_CROSS_SHORT, val);
-+
-+ return at803x_cdt_fault_length(val);
-+}
-+
-+static int qca808x_cable_test_start(struct phy_device *phydev)
-+{
-+ int ret;
-+
-+ /* perform CDT with the following configs:
-+ * 1. disable hibernation.
-+ * 2. force PHY working in MDI mode.
-+ * 3. for PHY working in 1000BaseT.
-+ * 4. configure the threshold.
-+ */
-+
-+ ret = at803x_debug_reg_mask(phydev, QCA808X_DBG_AN_TEST, QCA808X_HIBERNATION_EN, 0);
-+ if (ret < 0)
-+ return ret;
-+
-+ ret = at803x_config_mdix(phydev, ETH_TP_MDI);
-+ if (ret < 0)
-+ return ret;
-+
-+ /* Force 1000base-T needs to configure PMA/PMD and MII_BMCR */
-+ phydev->duplex = DUPLEX_FULL;
-+ phydev->speed = SPEED_1000;
-+ ret = genphy_c45_pma_setup_forced(phydev);
-+ if (ret < 0)
-+ return ret;
-+
-+ ret = genphy_setup_forced(phydev);
-+ if (ret < 0)
-+ return ret;
-+
-+ /* configure the thresholds for open, short, pair ok test */
-+ phy_write_mmd(phydev, MDIO_MMD_PCS, 0x8074, 0xc040);
-+ phy_write_mmd(phydev, MDIO_MMD_PCS, 0x8076, 0xc040);
-+ phy_write_mmd(phydev, MDIO_MMD_PCS, 0x8077, 0xa060);
-+ phy_write_mmd(phydev, MDIO_MMD_PCS, 0x8078, 0xc050);
-+ phy_write_mmd(phydev, MDIO_MMD_PCS, 0x807a, 0xc060);
-+ phy_write_mmd(phydev, MDIO_MMD_PCS, 0x807e, 0xb060);
-+
-+ return 0;
-+}
-+
-+static int qca808x_cable_test_get_pair_status(struct phy_device *phydev, u8 pair,
-+ u16 status)
-+{
-+ int length, result;
-+ u16 pair_code;
-+
-+ switch (pair) {
-+ case ETHTOOL_A_CABLE_PAIR_A:
-+ pair_code = FIELD_GET(QCA808X_CDT_CODE_PAIR_A, status);
-+ break;
-+ case ETHTOOL_A_CABLE_PAIR_B:
-+ pair_code = FIELD_GET(QCA808X_CDT_CODE_PAIR_B, status);
-+ break;
-+ case ETHTOOL_A_CABLE_PAIR_C:
-+ pair_code = FIELD_GET(QCA808X_CDT_CODE_PAIR_C, status);
-+ break;
-+ case ETHTOOL_A_CABLE_PAIR_D:
-+ pair_code = FIELD_GET(QCA808X_CDT_CODE_PAIR_D, status);
-+ break;
-+ default:
-+ return -EINVAL;
-+ }
-+
-+ result = qca808x_cable_test_result_trans(pair_code);
-+ ethnl_cable_test_result(phydev, pair, result);
-+
-+ if (qca808x_cdt_fault_length_valid(pair_code)) {
-+ length = qca808x_cdt_fault_length(phydev, pair, result);
-+ ethnl_cable_test_fault_length(phydev, pair, length);
-+ }
-+
-+ return 0;
-+}
-+
-+static int qca808x_cable_test_get_status(struct phy_device *phydev, bool *finished)
-+{
-+ int ret, val;
-+
-+ *finished = false;
-+
-+ val = QCA808X_CDT_ENABLE_TEST |
-+ QCA808X_CDT_LENGTH_UNIT;
-+ ret = at803x_cdt_start(phydev, val);
-+ if (ret)
-+ return ret;
-+
-+ ret = at803x_cdt_wait_for_completion(phydev, QCA808X_CDT_ENABLE_TEST);
-+ if (ret)
-+ return ret;
-+
-+ val = phy_read_mmd(phydev, MDIO_MMD_PCS, QCA808X_MMD3_CDT_STATUS);
-+ if (val < 0)
-+ return val;
-+
-+ ret = qca808x_cable_test_get_pair_status(phydev, ETHTOOL_A_CABLE_PAIR_A, val);
-+ if (ret)
-+ return ret;
-+
-+ ret = qca808x_cable_test_get_pair_status(phydev, ETHTOOL_A_CABLE_PAIR_B, val);
-+ if (ret)
-+ return ret;
-+
-+ ret = qca808x_cable_test_get_pair_status(phydev, ETHTOOL_A_CABLE_PAIR_C, val);
-+ if (ret)
-+ return ret;
-+
-+ ret = qca808x_cable_test_get_pair_status(phydev, ETHTOOL_A_CABLE_PAIR_D, val);
-+ if (ret)
-+ return ret;
-+
-+ *finished = true;
-+
-+ return 0;
-+}
-+
-+static int qca808x_get_features(struct phy_device *phydev)
-+{
-+ int ret;
-+
-+ ret = genphy_c45_pma_read_abilities(phydev);
-+ if (ret)
-+ return ret;
-+
-+ /* The autoneg ability is not existed in bit3 of MMD7.1,
-+ * but it is supported by qca808x PHY, so we add it here
-+ * manually.
-+ */
-+ linkmode_set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, phydev->supported);
-+
-+ /* As for the qca8081 1G version chip, the 2500baseT ability is also
-+ * existed in the bit0 of MMD1.21, we need to remove it manually if
-+ * it is the qca8081 1G chip according to the bit0 of MMD7.0x901d.
-+ */
-+ ret = phy_read_mmd(phydev, MDIO_MMD_AN, QCA808X_PHY_MMD7_CHIP_TYPE);
-+ if (ret < 0)
-+ return ret;
-+
-+ if (QCA808X_PHY_CHIP_TYPE_1G & ret)
-+ linkmode_clear_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, phydev->supported);
-+
-+ return 0;
-+}
-+
-+static int qca808x_config_aneg(struct phy_device *phydev)
-+{
-+ int phy_ctrl = 0;
-+ int ret;
-+
-+ ret = at803x_prepare_config_aneg(phydev);
-+ if (ret)
-+ return ret;
-+
-+ /* The reg MII_BMCR also needs to be configured for force mode, the
-+ * genphy_config_aneg is also needed.
-+ */
-+ if (phydev->autoneg == AUTONEG_DISABLE)
-+ genphy_c45_pma_setup_forced(phydev);
-+
-+ if (linkmode_test_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, phydev->advertising))
-+ phy_ctrl = MDIO_AN_10GBT_CTRL_ADV2_5G;
-+
-+ ret = phy_modify_mmd_changed(phydev, MDIO_MMD_AN, MDIO_AN_10GBT_CTRL,
-+ MDIO_AN_10GBT_CTRL_ADV2_5G, phy_ctrl);
-+ if (ret < 0)
-+ return ret;
-+
-+ return __genphy_config_aneg(phydev, ret);
-+}
-+
-+static void qca808x_link_change_notify(struct phy_device *phydev)
-+{
-+ /* Assert interface sgmii fifo on link down, deassert it on link up,
-+ * the interface device address is always phy address added by 1.
-+ */
-+ mdiobus_c45_modify_changed(phydev->mdio.bus, phydev->mdio.addr + 1,
-+ MDIO_MMD_PMAPMD, QCA8081_PHY_SERDES_MMD1_FIFO_CTRL,
-+ QCA8081_PHY_FIFO_RSTN,
-+ phydev->link ? QCA8081_PHY_FIFO_RSTN : 0);
-+}
-+
-+static int qca808x_led_parse_netdev(struct phy_device *phydev, unsigned long rules,
-+ u16 *offload_trigger)
-+{
-+ /* Parsing specific to netdev trigger */
-+ if (test_bit(TRIGGER_NETDEV_TX, &rules))
-+ *offload_trigger |= QCA808X_LED_TX_BLINK;
-+ if (test_bit(TRIGGER_NETDEV_RX, &rules))
-+ *offload_trigger |= QCA808X_LED_RX_BLINK;
-+ if (test_bit(TRIGGER_NETDEV_LINK_10, &rules))
-+ *offload_trigger |= QCA808X_LED_SPEED10_ON;
-+ if (test_bit(TRIGGER_NETDEV_LINK_100, &rules))
-+ *offload_trigger |= QCA808X_LED_SPEED100_ON;
-+ if (test_bit(TRIGGER_NETDEV_LINK_1000, &rules))
-+ *offload_trigger |= QCA808X_LED_SPEED1000_ON;
-+ if (test_bit(TRIGGER_NETDEV_LINK_2500, &rules))
-+ *offload_trigger |= QCA808X_LED_SPEED2500_ON;
-+ if (test_bit(TRIGGER_NETDEV_HALF_DUPLEX, &rules))
-+ *offload_trigger |= QCA808X_LED_HALF_DUPLEX_ON;
-+ if (test_bit(TRIGGER_NETDEV_FULL_DUPLEX, &rules))
-+ *offload_trigger |= QCA808X_LED_FULL_DUPLEX_ON;
-+
-+ if (rules && !*offload_trigger)
-+ return -EOPNOTSUPP;
-+
-+ /* Enable BLINK_CHECK_BYPASS by default to make the LED
-+ * blink even with duplex or speed mode not enabled.
-+ */
-+ *offload_trigger |= QCA808X_LED_BLINK_CHECK_BYPASS;
-+
-+ return 0;
-+}
-+
-+static int qca808x_led_hw_control_enable(struct phy_device *phydev, u8 index)
-+{
-+ u16 reg;
-+
-+ if (index > 2)
-+ return -EINVAL;
-+
-+ reg = QCA808X_MMD7_LED_FORCE_CTRL(index);
-+
-+ return phy_clear_bits_mmd(phydev, MDIO_MMD_AN, reg,
-+ QCA808X_LED_FORCE_EN);
-+}
-+
-+static int qca808x_led_hw_is_supported(struct phy_device *phydev, u8 index,
-+ unsigned long rules)
-+{
-+ u16 offload_trigger = 0;
-+
-+ if (index > 2)
-+ return -EINVAL;
-+
-+ return qca808x_led_parse_netdev(phydev, rules, &offload_trigger);
-+}
-+
-+static int qca808x_led_hw_control_set(struct phy_device *phydev, u8 index,
-+ unsigned long rules)
-+{
-+ u16 reg, offload_trigger = 0;
-+ int ret;
-+
-+ if (index > 2)
-+ return -EINVAL;
-+
-+ reg = QCA808X_MMD7_LED_CTRL(index);
-+
-+ ret = qca808x_led_parse_netdev(phydev, rules, &offload_trigger);
-+ if (ret)
-+ return ret;
-+
-+ ret = qca808x_led_hw_control_enable(phydev, index);
-+ if (ret)
-+ return ret;
-+
-+ return phy_modify_mmd(phydev, MDIO_MMD_AN, reg,
-+ QCA808X_LED_PATTERN_MASK,
-+ offload_trigger);
-+}
-+
-+static bool qca808x_led_hw_control_status(struct phy_device *phydev, u8 index)
-+{
-+ u16 reg;
-+ int val;
-+
-+ if (index > 2)
-+ return false;
-+
-+ reg = QCA808X_MMD7_LED_FORCE_CTRL(index);
-+
-+ val = phy_read_mmd(phydev, MDIO_MMD_AN, reg);
-+
-+ return !(val & QCA808X_LED_FORCE_EN);
-+}
-+
-+static int qca808x_led_hw_control_get(struct phy_device *phydev, u8 index,
-+ unsigned long *rules)
-+{
-+ u16 reg;
-+ int val;
-+
-+ if (index > 2)
-+ return -EINVAL;
-+
-+ /* Check if we have hw control enabled */
-+ if (qca808x_led_hw_control_status(phydev, index))
-+ return -EINVAL;
-+
-+ reg = QCA808X_MMD7_LED_CTRL(index);
-+
-+ val = phy_read_mmd(phydev, MDIO_MMD_AN, reg);
-+ if (val & QCA808X_LED_TX_BLINK)
-+ set_bit(TRIGGER_NETDEV_TX, rules);
-+ if (val & QCA808X_LED_RX_BLINK)
-+ set_bit(TRIGGER_NETDEV_RX, rules);
-+ if (val & QCA808X_LED_SPEED10_ON)
-+ set_bit(TRIGGER_NETDEV_LINK_10, rules);
-+ if (val & QCA808X_LED_SPEED100_ON)
-+ set_bit(TRIGGER_NETDEV_LINK_100, rules);
-+ if (val & QCA808X_LED_SPEED1000_ON)
-+ set_bit(TRIGGER_NETDEV_LINK_1000, rules);
-+ if (val & QCA808X_LED_SPEED2500_ON)
-+ set_bit(TRIGGER_NETDEV_LINK_2500, rules);
-+ if (val & QCA808X_LED_HALF_DUPLEX_ON)
-+ set_bit(TRIGGER_NETDEV_HALF_DUPLEX, rules);
-+ if (val & QCA808X_LED_FULL_DUPLEX_ON)
-+ set_bit(TRIGGER_NETDEV_FULL_DUPLEX, rules);
-+
-+ return 0;
-+}
-+
-+static int qca808x_led_hw_control_reset(struct phy_device *phydev, u8 index)
-+{
-+ u16 reg;
-+
-+ if (index > 2)
-+ return -EINVAL;
-+
-+ reg = QCA808X_MMD7_LED_CTRL(index);
-+
-+ return phy_clear_bits_mmd(phydev, MDIO_MMD_AN, reg,
-+ QCA808X_LED_PATTERN_MASK);
-+}
-+
-+static int qca808x_led_brightness_set(struct phy_device *phydev,
-+ u8 index, enum led_brightness value)
-+{
-+ u16 reg;
-+ int ret;
-+
-+ if (index > 2)
-+ return -EINVAL;
-+
-+ if (!value) {
-+ ret = qca808x_led_hw_control_reset(phydev, index);
-+ if (ret)
-+ return ret;
-+ }
-+
-+ reg = QCA808X_MMD7_LED_FORCE_CTRL(index);
-+
-+ return phy_modify_mmd(phydev, MDIO_MMD_AN, reg,
-+ QCA808X_LED_FORCE_EN | QCA808X_LED_FORCE_MODE_MASK,
-+ QCA808X_LED_FORCE_EN | value ? QCA808X_LED_FORCE_ON :
-+ QCA808X_LED_FORCE_OFF);
-+}
-+
-+static int qca808x_led_blink_set(struct phy_device *phydev, u8 index,
-+ unsigned long *delay_on,
-+ unsigned long *delay_off)
-+{
-+ int ret;
-+ u16 reg;
-+
-+ if (index > 2)
-+ return -EINVAL;
-+
-+ reg = QCA808X_MMD7_LED_FORCE_CTRL(index);
-+
-+ /* Set blink to 50% off, 50% on at 4Hz by default */
-+ ret = phy_modify_mmd(phydev, MDIO_MMD_AN, QCA808X_MMD7_LED_GLOBAL,
-+ QCA808X_LED_BLINK_FREQ_MASK | QCA808X_LED_BLINK_DUTY_MASK,
-+ QCA808X_LED_BLINK_FREQ_4HZ | QCA808X_LED_BLINK_DUTY_50_50);
-+ if (ret)
-+ return ret;
-+
-+ /* We use BLINK_1 for normal blinking */
-+ ret = phy_modify_mmd(phydev, MDIO_MMD_AN, reg,
-+ QCA808X_LED_FORCE_EN | QCA808X_LED_FORCE_MODE_MASK,
-+ QCA808X_LED_FORCE_EN | QCA808X_LED_FORCE_BLINK_1);
-+ if (ret)
-+ return ret;
-+
-+ /* We set blink to 4Hz, aka 250ms */
-+ *delay_on = 250 / 2;
-+ *delay_off = 250 / 2;
-+
-+ return 0;
-+}
-+
-+static int qca808x_led_polarity_set(struct phy_device *phydev, int index,
-+ unsigned long modes)
-+{
-+ struct qca808x_priv *priv = phydev->priv;
-+ bool active_low = false;
-+ u32 mode;
-+
-+ for_each_set_bit(mode, &modes, __PHY_LED_MODES_NUM) {
-+ switch (mode) {
-+ case PHY_LED_ACTIVE_LOW:
-+ active_low = true;
-+ break;
-+ default:
-+ return -EINVAL;
-+ }
-+ }
-+
-+ /* PHY polarity is global and can't be set per LED.
-+ * To detect this, check if last requested polarity mode
-+ * match the new one.
-+ */
-+ if (priv->led_polarity_mode >= 0 &&
-+ priv->led_polarity_mode != active_low) {
-+ phydev_err(phydev, "PHY polarity is global. Mismatched polarity on different LED\n");
-+ return -EINVAL;
-+ }
-+
-+ /* Save the last PHY polarity mode */
-+ priv->led_polarity_mode = active_low;
-+
-+ return phy_modify_mmd(phydev, MDIO_MMD_AN,
-+ QCA808X_MMD7_LED_POLARITY_CTRL,
-+ QCA808X_LED_ACTIVE_HIGH,
-+ active_low ? 0 : QCA808X_LED_ACTIVE_HIGH);
-+}
-+
-+static struct phy_driver qca808x_driver[] = {
-+{
-+ /* Qualcomm QCA8081 */
-+ PHY_ID_MATCH_EXACT(QCA8081_PHY_ID),
-+ .name = "Qualcomm QCA8081",
-+ .flags = PHY_POLL_CABLE_TEST,
-+ .probe = qca808x_probe,
-+ .config_intr = at803x_config_intr,
-+ .handle_interrupt = at803x_handle_interrupt,
-+ .get_tunable = at803x_get_tunable,
-+ .set_tunable = at803x_set_tunable,
-+ .set_wol = at803x_set_wol,
-+ .get_wol = at803x_get_wol,
-+ .get_features = qca808x_get_features,
-+ .config_aneg = qca808x_config_aneg,
-+ .suspend = genphy_suspend,
-+ .resume = genphy_resume,
-+ .read_status = qca808x_read_status,
-+ .config_init = qca808x_config_init,
-+ .soft_reset = qca808x_soft_reset,
-+ .cable_test_start = qca808x_cable_test_start,
-+ .cable_test_get_status = qca808x_cable_test_get_status,
-+ .link_change_notify = qca808x_link_change_notify,
-+ .led_brightness_set = qca808x_led_brightness_set,
-+ .led_blink_set = qca808x_led_blink_set,
-+ .led_hw_is_supported = qca808x_led_hw_is_supported,
-+ .led_hw_control_set = qca808x_led_hw_control_set,
-+ .led_hw_control_get = qca808x_led_hw_control_get,
-+ .led_polarity_set = qca808x_led_polarity_set,
-+}, };
-+
-+module_phy_driver(qca808x_driver);
-+
-+static struct mdio_device_id __maybe_unused qca808x_tbl[] = {
-+ { PHY_ID_MATCH_EXACT(QCA8081_PHY_ID) },
-+ { }
-+};
-+
-+MODULE_DEVICE_TABLE(mdio, qca808x_tbl);
+++ /dev/null
-From ebb30ccbbdbd6fae5177b676da4f4ac92bb4f635 Mon Sep 17 00:00:00 2001
-Date: Fri, 15 Dec 2023 14:15:31 +0100
-Subject: [PATCH 1/4] net: phy: make addr type u8 in phy_package_shared struct
-
-Switch addr type in phy_package_shared struct to u8.
-
-The value is already checked to be non negative and to be less than
-PHY_MAX_ADDR, hence u8 is better suited than using int.
-
----
- include/linux/phy.h | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/include/linux/phy.h
-+++ b/include/linux/phy.h
-@@ -338,7 +338,7 @@ struct mdio_bus_stats {
- * phy_package_leave().
- */
- struct phy_package_shared {
-- int addr;
-+ u8 addr;
- refcount_t refcnt;
- unsigned long flags;
- size_t priv_size;
+++ /dev/null
-From 9eea577eb1155fe4a183bc5e7bf269b0b2e7a6ba Mon Sep 17 00:00:00 2001
-Date: Fri, 15 Dec 2023 14:15:32 +0100
-Subject: [PATCH 2/4] net: phy: extend PHY package API to support multiple
- global address
-
-Current API for PHY package are limited to single address to configure
-global settings for the PHY package.
-
-It was found that some PHY package (for example the qca807x, a PHY
-package that is shipped with a bundle of 5 PHY) requires multiple PHY
-address to configure global settings. An example scenario is a PHY that
-have a dedicated PHY for PSGMII/serdes calibrarion and have a specific
-PHY in the package where the global PHY mode is set and affects every
-other PHY in the package.
-
-Change the API in the following way:
-- Change phy_package_join() to take the base addr of the PHY package
- instead of the global PHY addr.
-- Make __/phy_package_write/read() require an additional arg that
- select what global PHY address to use by passing the offset from the
- base addr passed on phy_package_join().
-
-Each user of this API is updated to follow this new implementation
-following a pattern where an enum is defined to declare the offset of the
-addr.
-
-We also drop the check if shared is defined as any user of the
-phy_package_read/write is expected to use phy_package_join first. Misuse
-of this will correctly trigger a kernel panic for NULL pointer
-exception.
-
----
- drivers/net/phy/bcm54140.c | 16 ++++++--
- drivers/net/phy/mscc/mscc.h | 5 +++
- drivers/net/phy/mscc/mscc_main.c | 4 +-
- drivers/net/phy/phy_device.c | 35 +++++++++--------
- include/linux/phy.h | 64 +++++++++++++++++++++-----------
- 5 files changed, 80 insertions(+), 44 deletions(-)
-
---- a/drivers/net/phy/bcm54140.c
-+++ b/drivers/net/phy/bcm54140.c
-@@ -128,6 +128,10 @@
- #define BCM54140_DEFAULT_DOWNSHIFT 5
- #define BCM54140_MAX_DOWNSHIFT 9
-
-+enum bcm54140_global_phy {
-+ BCM54140_BASE_ADDR = 0,
-+};
-+
- struct bcm54140_priv {
- int port;
- int base_addr;
-@@ -429,11 +433,13 @@ static int bcm54140_base_read_rdb(struct
- int ret;
-
- phy_lock_mdio_bus(phydev);
-- ret = __phy_package_write(phydev, MII_BCM54XX_RDB_ADDR, rdb);
-+ ret = __phy_package_write(phydev, BCM54140_BASE_ADDR,
-+ MII_BCM54XX_RDB_ADDR, rdb);
- if (ret < 0)
- goto out;
-
-- ret = __phy_package_read(phydev, MII_BCM54XX_RDB_DATA);
-+ ret = __phy_package_read(phydev, BCM54140_BASE_ADDR,
-+ MII_BCM54XX_RDB_DATA);
-
- out:
- phy_unlock_mdio_bus(phydev);
-@@ -446,11 +452,13 @@ static int bcm54140_base_write_rdb(struc
- int ret;
-
- phy_lock_mdio_bus(phydev);
-- ret = __phy_package_write(phydev, MII_BCM54XX_RDB_ADDR, rdb);
-+ ret = __phy_package_write(phydev, BCM54140_BASE_ADDR,
-+ MII_BCM54XX_RDB_ADDR, rdb);
- if (ret < 0)
- goto out;
-
-- ret = __phy_package_write(phydev, MII_BCM54XX_RDB_DATA, val);
-+ ret = __phy_package_write(phydev, BCM54140_BASE_ADDR,
-+ MII_BCM54XX_RDB_DATA, val);
-
- out:
- phy_unlock_mdio_bus(phydev);
---- a/drivers/net/phy/mscc/mscc.h
-+++ b/drivers/net/phy/mscc/mscc.h
-@@ -428,6 +428,11 @@ struct vsc8531_private {
- * gpio_lock: used for PHC operations. Common for all PHYs as the load/save GPIO
- * is shared.
- */
-+
-+enum vsc85xx_global_phy {
-+ VSC88XX_BASE_ADDR = 0,
-+};
-+
- struct vsc85xx_shared_private {
- struct mutex gpio_lock;
- };
---- a/drivers/net/phy/mscc/mscc_main.c
-+++ b/drivers/net/phy/mscc/mscc_main.c
-@@ -711,7 +711,7 @@ int phy_base_write(struct phy_device *ph
- dump_stack();
- }
-
-- return __phy_package_write(phydev, regnum, val);
-+ return __phy_package_write(phydev, VSC88XX_BASE_ADDR, regnum, val);
- }
-
- /* phydev->bus->mdio_lock should be locked when using this function */
-@@ -722,7 +722,7 @@ int phy_base_read(struct phy_device *phy
- dump_stack();
- }
-
-- return __phy_package_read(phydev, regnum);
-+ return __phy_package_read(phydev, VSC88XX_BASE_ADDR, regnum);
- }
-
- u32 vsc85xx_csr_read(struct phy_device *phydev,
---- a/drivers/net/phy/phy_device.c
-+++ b/drivers/net/phy/phy_device.c
-@@ -1658,20 +1658,22 @@ EXPORT_SYMBOL_GPL(phy_driver_is_genphy_1
- /**
- * phy_package_join - join a common PHY group
- * @phydev: target phy_device struct
-- * @addr: cookie and PHY address for global register access
-+ * @base_addr: cookie and base PHY address of PHY package for offset
-+ * calculation of global register access
- * @priv_size: if non-zero allocate this amount of bytes for private data
- *
- * This joins a PHY group and provides a shared storage for all phydevs in
- * this group. This is intended to be used for packages which contain
- * more than one PHY, for example a quad PHY transceiver.
- *
-- * The addr parameter serves as a cookie which has to have the same value
-- * for all members of one group and as a PHY address to access generic
-- * registers of a PHY package. Usually, one of the PHY addresses of the
-- * different PHYs in the package provides access to these global registers.
-+ * The base_addr parameter serves as cookie which has to have the same values
-+ * for all members of one group and as the base PHY address of the PHY package
-+ * for offset calculation to access generic registers of a PHY package.
-+ * Usually, one of the PHY addresses of the different PHYs in the package
-+ * provides access to these global registers.
- * The address which is given here, will be used in the phy_package_read()
-- * and phy_package_write() convenience functions. If your PHY doesn't have
-- * global registers you can just pick any of the PHY addresses.
-+ * and phy_package_write() convenience functions as base and added to the
-+ * passed offset in those functions.
- *
- * This will set the shared pointer of the phydev to the shared storage.
- * If this is the first call for a this cookie the shared storage will be
-@@ -1681,17 +1683,17 @@ EXPORT_SYMBOL_GPL(phy_driver_is_genphy_1
- * Returns < 1 on error, 0 on success. Esp. calling phy_package_join()
- * with the same cookie but a different priv_size is an error.
- */
--int phy_package_join(struct phy_device *phydev, int addr, size_t priv_size)
-+int phy_package_join(struct phy_device *phydev, int base_addr, size_t priv_size)
- {
- struct mii_bus *bus = phydev->mdio.bus;
- struct phy_package_shared *shared;
- int ret;
-
-- if (addr < 0 || addr >= PHY_MAX_ADDR)
-+ if (base_addr < 0 || base_addr >= PHY_MAX_ADDR)
- return -EINVAL;
-
- mutex_lock(&bus->shared_lock);
-- shared = bus->shared[addr];
-+ shared = bus->shared[base_addr];
- if (!shared) {
- ret = -ENOMEM;
- shared = kzalloc(sizeof(*shared), GFP_KERNEL);
-@@ -1703,9 +1705,9 @@ int phy_package_join(struct phy_device *
- goto err_free;
- shared->priv_size = priv_size;
- }
-- shared->addr = addr;
-+ shared->base_addr = base_addr;
- refcount_set(&shared->refcnt, 1);
-- bus->shared[addr] = shared;
-+ bus->shared[base_addr] = shared;
- } else {
- ret = -EINVAL;
- if (priv_size && priv_size != shared->priv_size)
-@@ -1743,7 +1745,7 @@ void phy_package_leave(struct phy_device
- return;
-
- if (refcount_dec_and_mutex_lock(&shared->refcnt, &bus->shared_lock)) {
-- bus->shared[shared->addr] = NULL;
-+ bus->shared[shared->base_addr] = NULL;
- mutex_unlock(&bus->shared_lock);
- kfree(shared->priv);
- kfree(shared);
-@@ -1762,7 +1764,8 @@ static void devm_phy_package_leave(struc
- * devm_phy_package_join - resource managed phy_package_join()
- * @dev: device that is registering this PHY package
- * @phydev: target phy_device struct
-- * @addr: cookie and PHY address for global register access
-+ * @base_addr: cookie and base PHY address of PHY package for offset
-+ * calculation of global register access
- * @priv_size: if non-zero allocate this amount of bytes for private data
- *
- * Managed phy_package_join(). Shared storage fetched by this function,
-@@ -1770,7 +1773,7 @@ static void devm_phy_package_leave(struc
- * phy_package_join() for more information.
- */
- int devm_phy_package_join(struct device *dev, struct phy_device *phydev,
-- int addr, size_t priv_size)
-+ int base_addr, size_t priv_size)
- {
- struct phy_device **ptr;
- int ret;
-@@ -1780,7 +1783,7 @@ int devm_phy_package_join(struct device
- if (!ptr)
- return -ENOMEM;
-
-- ret = phy_package_join(phydev, addr, priv_size);
-+ ret = phy_package_join(phydev, base_addr, priv_size);
-
- if (!ret) {
- *ptr = phydev;
---- a/include/linux/phy.h
-+++ b/include/linux/phy.h
-@@ -327,7 +327,8 @@ struct mdio_bus_stats {
-
- /**
- * struct phy_package_shared - Shared information in PHY packages
-- * @addr: Common PHY address used to combine PHYs in one package
-+ * @base_addr: Base PHY address of PHY package used to combine PHYs
-+ * in one package and for offset calculation of phy_package_read/write
- * @refcnt: Number of PHYs connected to this shared data
- * @flags: Initialization of PHY package
- * @priv_size: Size of the shared private data @priv
-@@ -338,7 +339,7 @@ struct mdio_bus_stats {
- * phy_package_leave().
- */
- struct phy_package_shared {
-- u8 addr;
-+ u8 base_addr;
- refcount_t refcnt;
- unsigned long flags;
- size_t priv_size;
-@@ -2000,10 +2001,10 @@ int phy_ethtool_get_link_ksettings(struc
- int phy_ethtool_set_link_ksettings(struct net_device *ndev,
- const struct ethtool_link_ksettings *cmd);
- int phy_ethtool_nway_reset(struct net_device *ndev);
--int phy_package_join(struct phy_device *phydev, int addr, size_t priv_size);
-+int phy_package_join(struct phy_device *phydev, int base_addr, size_t priv_size);
- void phy_package_leave(struct phy_device *phydev);
- int devm_phy_package_join(struct device *dev, struct phy_device *phydev,
-- int addr, size_t priv_size);
-+ int base_addr, size_t priv_size);
-
- int __init mdio_bus_init(void);
- void mdio_bus_exit(void);
-@@ -2026,46 +2027,65 @@ int __phy_hwtstamp_set(struct phy_device
- struct kernel_hwtstamp_config *config,
- struct netlink_ext_ack *extack);
-
--static inline int phy_package_read(struct phy_device *phydev, u32 regnum)
-+static inline int phy_package_address(struct phy_device *phydev,
-+ unsigned int addr_offset)
- {
- struct phy_package_shared *shared = phydev->shared;
-+ u8 base_addr = shared->base_addr;
-
-- if (!shared)
-+ if (addr_offset >= PHY_MAX_ADDR - base_addr)
- return -EIO;
-
-- return mdiobus_read(phydev->mdio.bus, shared->addr, regnum);
-+ /* we know that addr will be in the range 0..31 and thus the
-+ * implicit cast to a signed int is not a problem.
-+ */
-+ return base_addr + addr_offset;
- }
-
--static inline int __phy_package_read(struct phy_device *phydev, u32 regnum)
-+static inline int phy_package_read(struct phy_device *phydev,
-+ unsigned int addr_offset, u32 regnum)
- {
-- struct phy_package_shared *shared = phydev->shared;
-+ int addr = phy_package_address(phydev, addr_offset);
-
-- if (!shared)
-- return -EIO;
-+ if (addr < 0)
-+ return addr;
-+
-+ return mdiobus_read(phydev->mdio.bus, addr, regnum);
-+}
-+
-+static inline int __phy_package_read(struct phy_device *phydev,
-+ unsigned int addr_offset, u32 regnum)
-+{
-+ int addr = phy_package_address(phydev, addr_offset);
-+
-+ if (addr < 0)
-+ return addr;
-
-- return __mdiobus_read(phydev->mdio.bus, shared->addr, regnum);
-+ return __mdiobus_read(phydev->mdio.bus, addr, regnum);
- }
-
- static inline int phy_package_write(struct phy_device *phydev,
-- u32 regnum, u16 val)
-+ unsigned int addr_offset, u32 regnum,
-+ u16 val)
- {
-- struct phy_package_shared *shared = phydev->shared;
-+ int addr = phy_package_address(phydev, addr_offset);
-
-- if (!shared)
-- return -EIO;
-+ if (addr < 0)
-+ return addr;
-
-- return mdiobus_write(phydev->mdio.bus, shared->addr, regnum, val);
-+ return mdiobus_write(phydev->mdio.bus, addr, regnum, val);
- }
-
- static inline int __phy_package_write(struct phy_device *phydev,
-- u32 regnum, u16 val)
-+ unsigned int addr_offset, u32 regnum,
-+ u16 val)
- {
-- struct phy_package_shared *shared = phydev->shared;
-+ int addr = phy_package_address(phydev, addr_offset);
-
-- if (!shared)
-- return -EIO;
-+ if (addr < 0)
-+ return addr;
-
-- return __mdiobus_write(phydev->mdio.bus, shared->addr, regnum, val);
-+ return __mdiobus_write(phydev->mdio.bus, addr, regnum, val);
- }
-
- static inline bool __phy_package_set_once(struct phy_device *phydev,
+++ /dev/null
-From 028672bd1d73cf65249a420c1de75e8d2acd2f6a Mon Sep 17 00:00:00 2001
-Date: Fri, 15 Dec 2023 14:15:33 +0100
-Subject: [PATCH 3/4] net: phy: restructure __phy_write/read_mmd to helper and
- phydev user
-
-Restructure phy_write_mmd and phy_read_mmd to implement generic helper
-for direct mdiobus access for mmd and use these helper for phydev user.
-
-This is needed in preparation of PHY package API that requires generic
-access to the mdiobus and are deatched from phydev struct but instead
-access them based on PHY package base_addr and offsets.
-
----
- drivers/net/phy/phy-core.c | 64 ++++++++++++++++++--------------------
- 1 file changed, 30 insertions(+), 34 deletions(-)
-
---- a/drivers/net/phy/phy-core.c
-+++ b/drivers/net/phy/phy-core.c
-@@ -540,6 +540,28 @@ static void mmd_phy_indirect(struct mii_
- devad | MII_MMD_CTRL_NOINCR);
- }
-
-+static int mmd_phy_read(struct mii_bus *bus, int phy_addr, bool is_c45,
-+ int devad, u32 regnum)
-+{
-+ if (is_c45)
-+ return __mdiobus_c45_read(bus, phy_addr, devad, regnum);
-+
-+ mmd_phy_indirect(bus, phy_addr, devad, regnum);
-+ /* Read the content of the MMD's selected register */
-+ return __mdiobus_read(bus, phy_addr, MII_MMD_DATA);
-+}
-+
-+static int mmd_phy_write(struct mii_bus *bus, int phy_addr, bool is_c45,
-+ int devad, u32 regnum, u16 val)
-+{
-+ if (is_c45)
-+ return __mdiobus_c45_write(bus, phy_addr, devad, regnum, val);
-+
-+ mmd_phy_indirect(bus, phy_addr, devad, regnum);
-+ /* Write the data into MMD's selected register */
-+ return __mdiobus_write(bus, phy_addr, MII_MMD_DATA, val);
-+}
-+
- /**
- * __phy_read_mmd - Convenience function for reading a register
- * from an MMD on a given PHY.
-@@ -551,26 +573,14 @@ static void mmd_phy_indirect(struct mii_
- */
- int __phy_read_mmd(struct phy_device *phydev, int devad, u32 regnum)
- {
-- int val;
--
- if (regnum > (u16)~0 || devad > 32)
- return -EINVAL;
-
-- if (phydev->drv && phydev->drv->read_mmd) {
-- val = phydev->drv->read_mmd(phydev, devad, regnum);
-- } else if (phydev->is_c45) {
-- val = __mdiobus_c45_read(phydev->mdio.bus, phydev->mdio.addr,
-- devad, regnum);
-- } else {
-- struct mii_bus *bus = phydev->mdio.bus;
-- int phy_addr = phydev->mdio.addr;
--
-- mmd_phy_indirect(bus, phy_addr, devad, regnum);
--
-- /* Read the content of the MMD's selected register */
-- val = __mdiobus_read(bus, phy_addr, MII_MMD_DATA);
-- }
-- return val;
-+ if (phydev->drv && phydev->drv->read_mmd)
-+ return phydev->drv->read_mmd(phydev, devad, regnum);
-+
-+ return mmd_phy_read(phydev->mdio.bus, phydev->mdio.addr,
-+ phydev->is_c45, devad, regnum);
- }
- EXPORT_SYMBOL(__phy_read_mmd);
-
-@@ -607,28 +617,14 @@ EXPORT_SYMBOL(phy_read_mmd);
- */
- int __phy_write_mmd(struct phy_device *phydev, int devad, u32 regnum, u16 val)
- {
-- int ret;
--
- if (regnum > (u16)~0 || devad > 32)
- return -EINVAL;
-
-- if (phydev->drv && phydev->drv->write_mmd) {
-- ret = phydev->drv->write_mmd(phydev, devad, regnum, val);
-- } else if (phydev->is_c45) {
-- ret = __mdiobus_c45_write(phydev->mdio.bus, phydev->mdio.addr,
-- devad, regnum, val);
-- } else {
-- struct mii_bus *bus = phydev->mdio.bus;
-- int phy_addr = phydev->mdio.addr;
-+ if (phydev->drv && phydev->drv->write_mmd)
-+ return phydev->drv->write_mmd(phydev, devad, regnum, val);
-
-- mmd_phy_indirect(bus, phy_addr, devad, regnum);
--
-- /* Write the data into MMD's selected register */
-- __mdiobus_write(bus, phy_addr, MII_MMD_DATA, val);
--
-- ret = 0;
-- }
-- return ret;
-+ return mmd_phy_write(phydev->mdio.bus, phydev->mdio.addr,
-+ phydev->is_c45, devad, regnum, val);
- }
- EXPORT_SYMBOL(__phy_write_mmd);
-
+++ /dev/null
-From d63710fc0f1a501fd75a7025e3070a96ffa1645f Mon Sep 17 00:00:00 2001
-Date: Fri, 15 Dec 2023 14:15:34 +0100
-Subject: [PATCH 4/4] net: phy: add support for PHY package MMD read/write
-
-Some PHY in PHY package may require to read/write MMD regs to correctly
-configure the PHY package.
-
-Add support for these additional required function in both lock and no
-lock variant.
-
-It's assumed that the entire PHY package is either C22 or C45. We use
-C22 or C45 way of writing/reading to mmd regs based on the passed phydev
-whether it's C22 or C45.
-
----
- drivers/net/phy/phy-core.c | 140 +++++++++++++++++++++++++++++++++++++
- include/linux/phy.h | 16 +++++
- 2 files changed, 156 insertions(+)
-
---- a/drivers/net/phy/phy-core.c
-+++ b/drivers/net/phy/phy-core.c
-@@ -651,6 +651,146 @@ int phy_write_mmd(struct phy_device *phy
- EXPORT_SYMBOL(phy_write_mmd);
-
- /**
-+ * __phy_package_read_mmd - read MMD reg relative to PHY package base addr
-+ * @phydev: The phy_device struct
-+ * @addr_offset: The offset to be added to PHY package base_addr
-+ * @devad: The MMD to read from
-+ * @regnum: The register on the MMD to read
-+ *
-+ * Convenience helper for reading a register of an MMD on a given PHY
-+ * using the PHY package base address. The base address is added to
-+ * the addr_offset value.
-+ *
-+ * Same calling rules as for __phy_read();
-+ *
-+ * NOTE: It's assumed that the entire PHY package is either C22 or C45.
-+ */
-+int __phy_package_read_mmd(struct phy_device *phydev,
-+ unsigned int addr_offset, int devad,
-+ u32 regnum)
-+{
-+ int addr = phy_package_address(phydev, addr_offset);
-+
-+ if (addr < 0)
-+ return addr;
-+
-+ if (regnum > (u16)~0 || devad > 32)
-+ return -EINVAL;
-+
-+ return mmd_phy_read(phydev->mdio.bus, addr, phydev->is_c45, devad,
-+ regnum);
-+}
-+EXPORT_SYMBOL(__phy_package_read_mmd);
-+
-+/**
-+ * phy_package_read_mmd - read MMD reg relative to PHY package base addr
-+ * @phydev: The phy_device struct
-+ * @addr_offset: The offset to be added to PHY package base_addr
-+ * @devad: The MMD to read from
-+ * @regnum: The register on the MMD to read
-+ *
-+ * Convenience helper for reading a register of an MMD on a given PHY
-+ * using the PHY package base address. The base address is added to
-+ * the addr_offset value.
-+ *
-+ * Same calling rules as for phy_read();
-+ *
-+ * NOTE: It's assumed that the entire PHY package is either C22 or C45.
-+ */
-+int phy_package_read_mmd(struct phy_device *phydev,
-+ unsigned int addr_offset, int devad,
-+ u32 regnum)
-+{
-+ int addr = phy_package_address(phydev, addr_offset);
-+ int val;
-+
-+ if (addr < 0)
-+ return addr;
-+
-+ if (regnum > (u16)~0 || devad > 32)
-+ return -EINVAL;
-+
-+ phy_lock_mdio_bus(phydev);
-+ val = mmd_phy_read(phydev->mdio.bus, addr, phydev->is_c45, devad,
-+ regnum);
-+ phy_unlock_mdio_bus(phydev);
-+
-+ return val;
-+}
-+EXPORT_SYMBOL(phy_package_read_mmd);
-+
-+/**
-+ * __phy_package_write_mmd - write MMD reg relative to PHY package base addr
-+ * @phydev: The phy_device struct
-+ * @addr_offset: The offset to be added to PHY package base_addr
-+ * @devad: The MMD to write to
-+ * @regnum: The register on the MMD to write
-+ * @val: value to write to @regnum
-+ *
-+ * Convenience helper for writing a register of an MMD on a given PHY
-+ * using the PHY package base address. The base address is added to
-+ * the addr_offset value.
-+ *
-+ * Same calling rules as for __phy_write();
-+ *
-+ * NOTE: It's assumed that the entire PHY package is either C22 or C45.
-+ */
-+int __phy_package_write_mmd(struct phy_device *phydev,
-+ unsigned int addr_offset, int devad,
-+ u32 regnum, u16 val)
-+{
-+ int addr = phy_package_address(phydev, addr_offset);
-+
-+ if (addr < 0)
-+ return addr;
-+
-+ if (regnum > (u16)~0 || devad > 32)
-+ return -EINVAL;
-+
-+ return mmd_phy_write(phydev->mdio.bus, addr, phydev->is_c45, devad,
-+ regnum, val);
-+}
-+EXPORT_SYMBOL(__phy_package_write_mmd);
-+
-+/**
-+ * phy_package_write_mmd - write MMD reg relative to PHY package base addr
-+ * @phydev: The phy_device struct
-+ * @addr_offset: The offset to be added to PHY package base_addr
-+ * @devad: The MMD to write to
-+ * @regnum: The register on the MMD to write
-+ * @val: value to write to @regnum
-+ *
-+ * Convenience helper for writing a register of an MMD on a given PHY
-+ * using the PHY package base address. The base address is added to
-+ * the addr_offset value.
-+ *
-+ * Same calling rules as for phy_write();
-+ *
-+ * NOTE: It's assumed that the entire PHY package is either C22 or C45.
-+ */
-+int phy_package_write_mmd(struct phy_device *phydev,
-+ unsigned int addr_offset, int devad,
-+ u32 regnum, u16 val)
-+{
-+ int addr = phy_package_address(phydev, addr_offset);
-+ int ret;
-+
-+ if (addr < 0)
-+ return addr;
-+
-+ if (regnum > (u16)~0 || devad > 32)
-+ return -EINVAL;
-+
-+ phy_lock_mdio_bus(phydev);
-+ ret = mmd_phy_write(phydev->mdio.bus, addr, phydev->is_c45, devad,
-+ regnum, val);
-+ phy_unlock_mdio_bus(phydev);
-+
-+ return ret;
-+}
-+EXPORT_SYMBOL(phy_package_write_mmd);
-+
-+/**
- * phy_modify_changed - Function for modifying a PHY register
- * @phydev: the phy_device struct
- * @regnum: register number to modify
---- a/include/linux/phy.h
-+++ b/include/linux/phy.h
-@@ -2088,6 +2088,22 @@ static inline int __phy_package_write(st
- return __mdiobus_write(phydev->mdio.bus, addr, regnum, val);
- }
-
-+int __phy_package_read_mmd(struct phy_device *phydev,
-+ unsigned int addr_offset, int devad,
-+ u32 regnum);
-+
-+int phy_package_read_mmd(struct phy_device *phydev,
-+ unsigned int addr_offset, int devad,
-+ u32 regnum);
-+
-+int __phy_package_write_mmd(struct phy_device *phydev,
-+ unsigned int addr_offset, int devad,
-+ u32 regnum, u16 val);
-+
-+int phy_package_write_mmd(struct phy_device *phydev,
-+ unsigned int addr_offset, int devad,
-+ u32 regnum, u16 val);
-+
- static inline bool __phy_package_set_once(struct phy_device *phydev,
- unsigned int b)
- {
+++ /dev/null
-From f2ec98566775dd4341ec1dcf93aa5859c60de826 Mon Sep 17 00:00:00 2001
-Date: Thu, 1 Feb 2024 14:46:00 +0100
-Subject: [PATCH 1/2] net: phy: qcom: qca808x: fix logic error in LED
- brightness set
-
-In switching to using phy_modify_mmd and a more short version of the
-LED ON/OFF condition in later revision, it was made a logic error where
-
-value ? QCA808X_LED_FORCE_ON : QCA808X_LED_FORCE_OFF is always true as
-value is always OR with QCA808X_LED_FORCE_EN due to missing ()
-resulting in the testing condition being QCA808X_LED_FORCE_EN | value.
-
-Add the () to apply the correct condition and restore correct
-functionality of the brightness ON/OFF.
-
-Fixes: 7196062b64ee ("net: phy: at803x: add LED support for qca808x")
----
- drivers/net/phy/qcom/qca808x.c | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
---- a/drivers/net/phy/qcom/qca808x.c
-+++ b/drivers/net/phy/qcom/qca808x.c
-@@ -820,8 +820,8 @@ static int qca808x_led_brightness_set(st
-
- return phy_modify_mmd(phydev, MDIO_MMD_AN, reg,
- QCA808X_LED_FORCE_EN | QCA808X_LED_FORCE_MODE_MASK,
-- QCA808X_LED_FORCE_EN | value ? QCA808X_LED_FORCE_ON :
-- QCA808X_LED_FORCE_OFF);
-+ QCA808X_LED_FORCE_EN | (value ? QCA808X_LED_FORCE_ON :
-+ QCA808X_LED_FORCE_OFF));
- }
-
- static int qca808x_led_blink_set(struct phy_device *phydev, u8 index,
+++ /dev/null
-From f203c8c77c7616c099647636f4c67d59a45fe8a2 Mon Sep 17 00:00:00 2001
-Date: Thu, 1 Feb 2024 14:46:01 +0100
-Subject: [PATCH 2/2] net: phy: qcom: qca808x: default to LED active High if
- not set
-
-qca808x PHY provide support for the led_polarity_set OP to configure
-and apply the active-low property but on PHY reset, the Active High bit
-is not set resulting in the LED driven as active-low.
-
-To fix this, check if active-low is not set in DT and enable Active High
-polarity by default to restore correct funcionality of the LED.
-
-Fixes: 7196062b64ee ("net: phy: at803x: add LED support for qca808x")
----
- drivers/net/phy/qcom/qca808x.c | 10 ++++++++++
- 1 file changed, 10 insertions(+)
-
---- a/drivers/net/phy/qcom/qca808x.c
-+++ b/drivers/net/phy/qcom/qca808x.c
-@@ -290,8 +290,18 @@ static int qca808x_probe(struct phy_devi
-
- static int qca808x_config_init(struct phy_device *phydev)
- {
-+ struct qca808x_priv *priv = phydev->priv;
- int ret;
-
-+ /* Default to LED Active High if active-low not in DT */
-+ if (priv->led_polarity_mode == -1) {
-+ ret = phy_set_bits_mmd(phydev, MDIO_MMD_AN,
-+ QCA808X_MMD7_LED_POLARITY_CTRL,
-+ QCA808X_LED_ACTIVE_HIGH);
-+ if (ret)
-+ return ret;
-+ }
-+
- /* Active adc&vga on 802.3az for the link 1000M and 100M */
- ret = phy_modify_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_ADDR_CLD_CTRL7,
- QCA808X_8023AZ_AFE_CTRL_MASK, QCA808X_8023AZ_AFE_EN);
+++ /dev/null
-From 385ef48f468696d6d172eb367656a3466fa0408d Mon Sep 17 00:00:00 2001
-Date: Tue, 6 Feb 2024 18:31:05 +0100
-Subject: [PATCH 02/10] net: phy: add support for scanning PHY in PHY packages
- nodes
-
-Add support for scanning PHY in PHY package nodes. PHY packages nodes
-are just container for actual PHY on the MDIO bus.
-
-Their PHY address defined in the PHY package node are absolute and
-reflect the address on the MDIO bus.
-
-mdio_bus.c and of_mdio.c is updated to now support and parse also
-PHY package subnode by checking if the node name match
-"ethernet-phy-package".
-
-As PHY package reg is mandatory and each PHY in the PHY package must
-have a reg, every invalid PHY Package node is ignored and will be
-skipped by the autoscan fallback.
-
----
- drivers/net/mdio/of_mdio.c | 79 +++++++++++++++++++++++++++-----------
- drivers/net/phy/mdio_bus.c | 44 +++++++++++++++++----
- 2 files changed, 92 insertions(+), 31 deletions(-)
-
---- a/drivers/net/mdio/of_mdio.c
-+++ b/drivers/net/mdio/of_mdio.c
-@@ -138,6 +138,53 @@ bool of_mdiobus_child_is_phy(struct devi
- }
- EXPORT_SYMBOL(of_mdiobus_child_is_phy);
-
-+static int __of_mdiobus_parse_phys(struct mii_bus *mdio, struct device_node *np,
-+ bool *scanphys)
-+{
-+ struct device_node *child;
-+ int addr, rc = 0;
-+
-+ /* Loop over the child nodes and register a phy_device for each phy */
-+ for_each_available_child_of_node(np, child) {
-+ if (of_node_name_eq(child, "ethernet-phy-package")) {
-+ /* Ignore invalid ethernet-phy-package node */
-+ if (!of_find_property(child, "reg", NULL))
-+ continue;
-+
-+ rc = __of_mdiobus_parse_phys(mdio, child, NULL);
-+ if (rc && rc != -ENODEV)
-+ goto exit;
-+
-+ continue;
-+ }
-+
-+ addr = of_mdio_parse_addr(&mdio->dev, child);
-+ if (addr < 0) {
-+ /* Skip scanning for invalid ethernet-phy-package node */
-+ if (scanphys)
-+ *scanphys = true;
-+ continue;
-+ }
-+
-+ if (of_mdiobus_child_is_phy(child))
-+ rc = of_mdiobus_register_phy(mdio, child, addr);
-+ else
-+ rc = of_mdiobus_register_device(mdio, child, addr);
-+
-+ if (rc == -ENODEV)
-+ dev_err(&mdio->dev,
-+ "MDIO device at address %d is missing.\n",
-+ addr);
-+ else if (rc)
-+ goto exit;
-+ }
-+
-+ return 0;
-+exit:
-+ of_node_put(child);
-+ return rc;
-+}
-+
- /**
- * __of_mdiobus_register - Register mii_bus and create PHYs from the device tree
- * @mdio: pointer to mii_bus structure
-@@ -179,33 +226,18 @@ int __of_mdiobus_register(struct mii_bus
- return rc;
-
- /* Loop over the child nodes and register a phy_device for each phy */
-- for_each_available_child_of_node(np, child) {
-- addr = of_mdio_parse_addr(&mdio->dev, child);
-- if (addr < 0) {
-- scanphys = true;
-- continue;
-- }
--
-- if (of_mdiobus_child_is_phy(child))
-- rc = of_mdiobus_register_phy(mdio, child, addr);
-- else
-- rc = of_mdiobus_register_device(mdio, child, addr);
--
-- if (rc == -ENODEV)
-- dev_err(&mdio->dev,
-- "MDIO device at address %d is missing.\n",
-- addr);
-- else if (rc)
-- goto unregister;
-- }
-+ rc = __of_mdiobus_parse_phys(mdio, np, &scanphys);
-+ if (rc)
-+ goto unregister;
-
- if (!scanphys)
- return 0;
-
- /* auto scan for PHYs with empty reg property */
- for_each_available_child_of_node(np, child) {
-- /* Skip PHYs with reg property set */
-- if (of_property_present(child, "reg"))
-+ /* Skip PHYs with reg property set or ethernet-phy-package node */
-+ if (of_property_present(child, "reg") ||
-+ of_node_name_eq(child, "ethernet-phy-package"))
- continue;
-
- for (addr = 0; addr < PHY_MAX_ADDR; addr++) {
-@@ -226,15 +258,16 @@ int __of_mdiobus_register(struct mii_bus
- if (!rc)
- break;
- if (rc != -ENODEV)
-- goto unregister;
-+ goto put_unregister;
- }
- }
- }
-
- return 0;
-
--unregister:
-+put_unregister:
- of_node_put(child);
-+unregister:
- mdiobus_unregister(mdio);
- return rc;
- }
---- a/drivers/net/phy/mdio_bus.c
-+++ b/drivers/net/phy/mdio_bus.c
-@@ -459,19 +459,34 @@ EXPORT_SYMBOL(of_mdio_find_bus);
- * found, set the of_node pointer for the mdio device. This allows
- * auto-probed phy devices to be supplied with information passed in
- * via DT.
-+ * If a PHY package is found, PHY is searched also there.
- */
--static void of_mdiobus_link_mdiodev(struct mii_bus *bus,
-- struct mdio_device *mdiodev)
-+static int of_mdiobus_find_phy(struct device *dev, struct mdio_device *mdiodev,
-+ struct device_node *np)
- {
-- struct device *dev = &mdiodev->dev;
- struct device_node *child;
-
-- if (dev->of_node || !bus->dev.of_node)
-- return;
--
-- for_each_available_child_of_node(bus->dev.of_node, child) {
-+ for_each_available_child_of_node(np, child) {
- int addr;
-
-+ if (of_node_name_eq(child, "ethernet-phy-package")) {
-+ /* Validate PHY package reg presence */
-+ if (!of_find_property(child, "reg", NULL)) {
-+ of_node_put(child);
-+ return -EINVAL;
-+ }
-+
-+ if (!of_mdiobus_find_phy(dev, mdiodev, child)) {
-+ /* The refcount for the PHY package will be
-+ * incremented later when PHY join the Package.
-+ */
-+ of_node_put(child);
-+ return 0;
-+ }
-+
-+ continue;
-+ }
-+
- addr = of_mdio_parse_addr(dev, child);
- if (addr < 0)
- continue;
-@@ -481,9 +496,22 @@ static void of_mdiobus_link_mdiodev(stru
- /* The refcount on "child" is passed to the mdio
- * device. Do _not_ use of_node_put(child) here.
- */
-- return;
-+ return 0;
- }
- }
-+
-+ return -ENODEV;
-+}
-+
-+static void of_mdiobus_link_mdiodev(struct mii_bus *bus,
-+ struct mdio_device *mdiodev)
-+{
-+ struct device *dev = &mdiodev->dev;
-+
-+ if (dev->of_node || !bus->dev.of_node)
-+ return;
-+
-+ of_mdiobus_find_phy(dev, mdiodev, bus->dev.of_node);
- }
- #else /* !IS_ENABLED(CONFIG_OF_MDIO) */
- static inline void of_mdiobus_link_mdiodev(struct mii_bus *mdio,
+++ /dev/null
-From 471e8fd3afcef5a9f9089f0bd21965ad9ba35c91 Mon Sep 17 00:00:00 2001
-Date: Tue, 6 Feb 2024 18:31:06 +0100
-Subject: [PATCH 03/10] net: phy: add devm/of_phy_package_join helper
-
-Add devm/of_phy_package_join helper to join PHYs in a PHY package. These
-are variant of the manual phy_package_join with the difference that
-these will use DT nodes to derive the base_addr instead of manually
-passing an hardcoded value.
-
-An additional value is added in phy_package_shared, "np" to reference
-the PHY package node pointer in specific PHY driver probe_once and
-config_init_once functions to make use of additional specific properties
-defined in the PHY package node in DT.
-
-The np value is filled only with of_phy_package_join if a valid PHY
-package node is found. A valid PHY package node must have the node name
-set to "ethernet-phy-package".
-
----
- drivers/net/phy/phy_device.c | 96 ++++++++++++++++++++++++++++++++++++
- include/linux/phy.h | 6 +++
- 2 files changed, 102 insertions(+)
-
---- a/drivers/net/phy/phy_device.c
-+++ b/drivers/net/phy/phy_device.c
-@@ -1706,6 +1706,7 @@ int phy_package_join(struct phy_device *
- shared->priv_size = priv_size;
- }
- shared->base_addr = base_addr;
-+ shared->np = NULL;
- refcount_set(&shared->refcnt, 1);
- bus->shared[base_addr] = shared;
- } else {
-@@ -1729,6 +1730,63 @@ err_unlock:
- EXPORT_SYMBOL_GPL(phy_package_join);
-
- /**
-+ * of_phy_package_join - join a common PHY group in PHY package
-+ * @phydev: target phy_device struct
-+ * @priv_size: if non-zero allocate this amount of bytes for private data
-+ *
-+ * This is a variant of phy_package_join for PHY package defined in DT.
-+ *
-+ * The parent node of the @phydev is checked as a valid PHY package node
-+ * structure (by matching the node name "ethernet-phy-package") and the
-+ * base_addr for the PHY package is passed to phy_package_join.
-+ *
-+ * With this configuration the shared struct will also have the np value
-+ * filled to use additional DT defined properties in PHY specific
-+ * probe_once and config_init_once PHY package OPs.
-+ *
-+ * Returns < 0 on error, 0 on success. Esp. calling phy_package_join()
-+ * with the same cookie but a different priv_size is an error. Or a parent
-+ * node is not detected or is not valid or doesn't match the expected node
-+ * name for PHY package.
-+ */
-+int of_phy_package_join(struct phy_device *phydev, size_t priv_size)
-+{
-+ struct device_node *node = phydev->mdio.dev.of_node;
-+ struct device_node *package_node;
-+ u32 base_addr;
-+ int ret;
-+
-+ if (!node)
-+ return -EINVAL;
-+
-+ package_node = of_get_parent(node);
-+ if (!package_node)
-+ return -EINVAL;
-+
-+ if (!of_node_name_eq(package_node, "ethernet-phy-package")) {
-+ ret = -EINVAL;
-+ goto exit;
-+ }
-+
-+ if (of_property_read_u32(package_node, "reg", &base_addr)) {
-+ ret = -EINVAL;
-+ goto exit;
-+ }
-+
-+ ret = phy_package_join(phydev, base_addr, priv_size);
-+ if (ret)
-+ goto exit;
-+
-+ phydev->shared->np = package_node;
-+
-+ return 0;
-+exit:
-+ of_node_put(package_node);
-+ return ret;
-+}
-+EXPORT_SYMBOL_GPL(of_phy_package_join);
-+
-+/**
- * phy_package_leave - leave a common PHY group
- * @phydev: target phy_device struct
- *
-@@ -1744,6 +1802,10 @@ void phy_package_leave(struct phy_device
- if (!shared)
- return;
-
-+ /* Decrease the node refcount on leave if present */
-+ if (shared->np)
-+ of_node_put(shared->np);
-+
- if (refcount_dec_and_mutex_lock(&shared->refcnt, &bus->shared_lock)) {
- bus->shared[shared->base_addr] = NULL;
- mutex_unlock(&bus->shared_lock);
-@@ -1797,6 +1859,40 @@ int devm_phy_package_join(struct device
- EXPORT_SYMBOL_GPL(devm_phy_package_join);
-
- /**
-+ * devm_of_phy_package_join - resource managed of_phy_package_join()
-+ * @dev: device that is registering this PHY package
-+ * @phydev: target phy_device struct
-+ * @priv_size: if non-zero allocate this amount of bytes for private data
-+ *
-+ * Managed of_phy_package_join(). Shared storage fetched by this function,
-+ * phy_package_leave() is automatically called on driver detach. See
-+ * of_phy_package_join() for more information.
-+ */
-+int devm_of_phy_package_join(struct device *dev, struct phy_device *phydev,
-+ size_t priv_size)
-+{
-+ struct phy_device **ptr;
-+ int ret;
-+
-+ ptr = devres_alloc(devm_phy_package_leave, sizeof(*ptr),
-+ GFP_KERNEL);
-+ if (!ptr)
-+ return -ENOMEM;
-+
-+ ret = of_phy_package_join(phydev, priv_size);
-+
-+ if (!ret) {
-+ *ptr = phydev;
-+ devres_add(dev, ptr);
-+ } else {
-+ devres_free(ptr);
-+ }
-+
-+ return ret;
-+}
-+EXPORT_SYMBOL_GPL(devm_of_phy_package_join);
-+
-+/**
- * phy_detach - detach a PHY device from its network device
- * @phydev: target phy_device struct
- *
---- a/include/linux/phy.h
-+++ b/include/linux/phy.h
-@@ -329,6 +329,7 @@ struct mdio_bus_stats {
- * struct phy_package_shared - Shared information in PHY packages
- * @base_addr: Base PHY address of PHY package used to combine PHYs
- * in one package and for offset calculation of phy_package_read/write
-+ * @np: Pointer to the Device Node if PHY package defined in DT
- * @refcnt: Number of PHYs connected to this shared data
- * @flags: Initialization of PHY package
- * @priv_size: Size of the shared private data @priv
-@@ -340,6 +341,8 @@ struct mdio_bus_stats {
- */
- struct phy_package_shared {
- u8 base_addr;
-+ /* With PHY package defined in DT this points to the PHY package node */
-+ struct device_node *np;
- refcount_t refcnt;
- unsigned long flags;
- size_t priv_size;
-@@ -2002,9 +2005,12 @@ int phy_ethtool_set_link_ksettings(struc
- const struct ethtool_link_ksettings *cmd);
- int phy_ethtool_nway_reset(struct net_device *ndev);
- int phy_package_join(struct phy_device *phydev, int base_addr, size_t priv_size);
-+int of_phy_package_join(struct phy_device *phydev, size_t priv_size);
- void phy_package_leave(struct phy_device *phydev);
- int devm_phy_package_join(struct device *dev, struct phy_device *phydev,
- int base_addr, size_t priv_size);
-+int devm_of_phy_package_join(struct device *dev, struct phy_device *phydev,
-+ size_t priv_size);
-
- int __init mdio_bus_init(void);
- void mdio_bus_exit(void);
+++ /dev/null
-From 737eb75a815f9c08dcbb6631db57f4f4b0540a5b Mon Sep 17 00:00:00 2001
-Date: Tue, 6 Feb 2024 18:31:07 +0100
-Subject: [PATCH 04/10] net: phy: qcom: move more function to shared library
-
-Move more function to shared library in preparation for introduction of
-new PHY Family qca807x that will make use of both functions from at803x
-and qca808x as it's a transition PHY with some implementation of at803x
-and some from the new qca808x.
-
----
- drivers/net/phy/qcom/at803x.c | 35 -----
- drivers/net/phy/qcom/qca808x.c | 205 ----------------------------
- drivers/net/phy/qcom/qcom-phy-lib.c | 193 ++++++++++++++++++++++++++
- drivers/net/phy/qcom/qcom.h | 51 +++++++
- 4 files changed, 244 insertions(+), 240 deletions(-)
-
---- a/drivers/net/phy/qcom/at803x.c
-+++ b/drivers/net/phy/qcom/at803x.c
-@@ -504,41 +504,6 @@ static void at803x_link_change_notify(st
- }
- }
-
--static int at803x_read_status(struct phy_device *phydev)
--{
-- struct at803x_ss_mask ss_mask = { 0 };
-- int err, old_link = phydev->link;
--
-- /* Update the link, but return if there was an error */
-- err = genphy_update_link(phydev);
-- if (err)
-- return err;
--
-- /* why bother the PHY if nothing can have changed */
-- if (phydev->autoneg == AUTONEG_ENABLE && old_link && phydev->link)
-- return 0;
--
-- phydev->speed = SPEED_UNKNOWN;
-- phydev->duplex = DUPLEX_UNKNOWN;
-- phydev->pause = 0;
-- phydev->asym_pause = 0;
--
-- err = genphy_read_lpa(phydev);
-- if (err < 0)
-- return err;
--
-- ss_mask.speed_mask = AT803X_SS_SPEED_MASK;
-- ss_mask.speed_shift = __bf_shf(AT803X_SS_SPEED_MASK);
-- err = at803x_read_specific_status(phydev, ss_mask);
-- if (err < 0)
-- return err;
--
-- if (phydev->autoneg == AUTONEG_ENABLE && phydev->autoneg_complete)
-- phy_resolve_aneg_pause(phydev);
--
-- return 0;
--}
--
- static int at803x_config_aneg(struct phy_device *phydev)
- {
- struct at803x_priv *priv = phydev->priv;
---- a/drivers/net/phy/qcom/qca808x.c
-+++ b/drivers/net/phy/qcom/qca808x.c
-@@ -2,7 +2,6 @@
-
- #include <linux/phy.h>
- #include <linux/module.h>
--#include <linux/ethtool_netlink.h>
-
- #include "qcom.h"
-
-@@ -63,55 +62,6 @@
- #define QCA808X_DBG_AN_TEST 0xb
- #define QCA808X_HIBERNATION_EN BIT(15)
-
--#define QCA808X_CDT_ENABLE_TEST BIT(15)
--#define QCA808X_CDT_INTER_CHECK_DIS BIT(13)
--#define QCA808X_CDT_STATUS BIT(11)
--#define QCA808X_CDT_LENGTH_UNIT BIT(10)
--
--#define QCA808X_MMD3_CDT_STATUS 0x8064
--#define QCA808X_MMD3_CDT_DIAG_PAIR_A 0x8065
--#define QCA808X_MMD3_CDT_DIAG_PAIR_B 0x8066
--#define QCA808X_MMD3_CDT_DIAG_PAIR_C 0x8067
--#define QCA808X_MMD3_CDT_DIAG_PAIR_D 0x8068
--#define QCA808X_CDT_DIAG_LENGTH_SAME_SHORT GENMASK(15, 8)
--#define QCA808X_CDT_DIAG_LENGTH_CROSS_SHORT GENMASK(7, 0)
--
--#define QCA808X_CDT_CODE_PAIR_A GENMASK(15, 12)
--#define QCA808X_CDT_CODE_PAIR_B GENMASK(11, 8)
--#define QCA808X_CDT_CODE_PAIR_C GENMASK(7, 4)
--#define QCA808X_CDT_CODE_PAIR_D GENMASK(3, 0)
--
--#define QCA808X_CDT_STATUS_STAT_TYPE GENMASK(1, 0)
--#define QCA808X_CDT_STATUS_STAT_FAIL FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_TYPE, 0)
--#define QCA808X_CDT_STATUS_STAT_NORMAL FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_TYPE, 1)
--#define QCA808X_CDT_STATUS_STAT_SAME_OPEN FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_TYPE, 2)
--#define QCA808X_CDT_STATUS_STAT_SAME_SHORT FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_TYPE, 3)
--
--#define QCA808X_CDT_STATUS_STAT_MDI GENMASK(3, 2)
--#define QCA808X_CDT_STATUS_STAT_MDI1 FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_MDI, 1)
--#define QCA808X_CDT_STATUS_STAT_MDI2 FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_MDI, 2)
--#define QCA808X_CDT_STATUS_STAT_MDI3 FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_MDI, 3)
--
--/* NORMAL are MDI with type set to 0 */
--#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_NORMAL QCA808X_CDT_STATUS_STAT_MDI1
--#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_OPEN (QCA808X_CDT_STATUS_STAT_SAME_OPEN |\
-- QCA808X_CDT_STATUS_STAT_MDI1)
--#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_SHORT (QCA808X_CDT_STATUS_STAT_SAME_SHORT |\
-- QCA808X_CDT_STATUS_STAT_MDI1)
--#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_NORMAL QCA808X_CDT_STATUS_STAT_MDI2
--#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_OPEN (QCA808X_CDT_STATUS_STAT_SAME_OPEN |\
-- QCA808X_CDT_STATUS_STAT_MDI2)
--#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_SHORT (QCA808X_CDT_STATUS_STAT_SAME_SHORT |\
-- QCA808X_CDT_STATUS_STAT_MDI2)
--#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_NORMAL QCA808X_CDT_STATUS_STAT_MDI3
--#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_OPEN (QCA808X_CDT_STATUS_STAT_SAME_OPEN |\
-- QCA808X_CDT_STATUS_STAT_MDI3)
--#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_SHORT (QCA808X_CDT_STATUS_STAT_SAME_SHORT |\
-- QCA808X_CDT_STATUS_STAT_MDI3)
--
--/* Added for reference of existence but should be handled by wait_for_completion already */
--#define QCA808X_CDT_STATUS_STAT_BUSY (BIT(1) | BIT(3))
--
- #define QCA808X_MMD7_LED_GLOBAL 0x8073
- #define QCA808X_LED_BLINK_1 GENMASK(11, 6)
- #define QCA808X_LED_BLINK_2 GENMASK(5, 0)
-@@ -406,86 +356,6 @@ static int qca808x_soft_reset(struct phy
- return ret;
- }
-
--static bool qca808x_cdt_fault_length_valid(int cdt_code)
--{
-- switch (cdt_code) {
-- case QCA808X_CDT_STATUS_STAT_SAME_SHORT:
-- case QCA808X_CDT_STATUS_STAT_SAME_OPEN:
-- case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_NORMAL:
-- case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_OPEN:
-- case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_SHORT:
-- case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_NORMAL:
-- case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_OPEN:
-- case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_SHORT:
-- case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_NORMAL:
-- case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_OPEN:
-- case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_SHORT:
-- return true;
-- default:
-- return false;
-- }
--}
--
--static int qca808x_cable_test_result_trans(int cdt_code)
--{
-- switch (cdt_code) {
-- case QCA808X_CDT_STATUS_STAT_NORMAL:
-- return ETHTOOL_A_CABLE_RESULT_CODE_OK;
-- case QCA808X_CDT_STATUS_STAT_SAME_SHORT:
-- return ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT;
-- case QCA808X_CDT_STATUS_STAT_SAME_OPEN:
-- return ETHTOOL_A_CABLE_RESULT_CODE_OPEN;
-- case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_NORMAL:
-- case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_OPEN:
-- case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_SHORT:
-- case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_NORMAL:
-- case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_OPEN:
-- case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_SHORT:
-- case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_NORMAL:
-- case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_OPEN:
-- case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_SHORT:
-- return ETHTOOL_A_CABLE_RESULT_CODE_CROSS_SHORT;
-- case QCA808X_CDT_STATUS_STAT_FAIL:
-- default:
-- return ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC;
-- }
--}
--
--static int qca808x_cdt_fault_length(struct phy_device *phydev, int pair,
-- int result)
--{
-- int val;
-- u32 cdt_length_reg = 0;
--
-- switch (pair) {
-- case ETHTOOL_A_CABLE_PAIR_A:
-- cdt_length_reg = QCA808X_MMD3_CDT_DIAG_PAIR_A;
-- break;
-- case ETHTOOL_A_CABLE_PAIR_B:
-- cdt_length_reg = QCA808X_MMD3_CDT_DIAG_PAIR_B;
-- break;
-- case ETHTOOL_A_CABLE_PAIR_C:
-- cdt_length_reg = QCA808X_MMD3_CDT_DIAG_PAIR_C;
-- break;
-- case ETHTOOL_A_CABLE_PAIR_D:
-- cdt_length_reg = QCA808X_MMD3_CDT_DIAG_PAIR_D;
-- break;
-- default:
-- return -EINVAL;
-- }
--
-- val = phy_read_mmd(phydev, MDIO_MMD_PCS, cdt_length_reg);
-- if (val < 0)
-- return val;
--
-- if (result == ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT)
-- val = FIELD_GET(QCA808X_CDT_DIAG_LENGTH_SAME_SHORT, val);
-- else
-- val = FIELD_GET(QCA808X_CDT_DIAG_LENGTH_CROSS_SHORT, val);
--
-- return at803x_cdt_fault_length(val);
--}
--
- static int qca808x_cable_test_start(struct phy_device *phydev)
- {
- int ret;
-@@ -526,81 +396,6 @@ static int qca808x_cable_test_start(stru
-
- return 0;
- }
--
--static int qca808x_cable_test_get_pair_status(struct phy_device *phydev, u8 pair,
-- u16 status)
--{
-- int length, result;
-- u16 pair_code;
--
-- switch (pair) {
-- case ETHTOOL_A_CABLE_PAIR_A:
-- pair_code = FIELD_GET(QCA808X_CDT_CODE_PAIR_A, status);
-- break;
-- case ETHTOOL_A_CABLE_PAIR_B:
-- pair_code = FIELD_GET(QCA808X_CDT_CODE_PAIR_B, status);
-- break;
-- case ETHTOOL_A_CABLE_PAIR_C:
-- pair_code = FIELD_GET(QCA808X_CDT_CODE_PAIR_C, status);
-- break;
-- case ETHTOOL_A_CABLE_PAIR_D:
-- pair_code = FIELD_GET(QCA808X_CDT_CODE_PAIR_D, status);
-- break;
-- default:
-- return -EINVAL;
-- }
--
-- result = qca808x_cable_test_result_trans(pair_code);
-- ethnl_cable_test_result(phydev, pair, result);
--
-- if (qca808x_cdt_fault_length_valid(pair_code)) {
-- length = qca808x_cdt_fault_length(phydev, pair, result);
-- ethnl_cable_test_fault_length(phydev, pair, length);
-- }
--
-- return 0;
--}
--
--static int qca808x_cable_test_get_status(struct phy_device *phydev, bool *finished)
--{
-- int ret, val;
--
-- *finished = false;
--
-- val = QCA808X_CDT_ENABLE_TEST |
-- QCA808X_CDT_LENGTH_UNIT;
-- ret = at803x_cdt_start(phydev, val);
-- if (ret)
-- return ret;
--
-- ret = at803x_cdt_wait_for_completion(phydev, QCA808X_CDT_ENABLE_TEST);
-- if (ret)
-- return ret;
--
-- val = phy_read_mmd(phydev, MDIO_MMD_PCS, QCA808X_MMD3_CDT_STATUS);
-- if (val < 0)
-- return val;
--
-- ret = qca808x_cable_test_get_pair_status(phydev, ETHTOOL_A_CABLE_PAIR_A, val);
-- if (ret)
-- return ret;
--
-- ret = qca808x_cable_test_get_pair_status(phydev, ETHTOOL_A_CABLE_PAIR_B, val);
-- if (ret)
-- return ret;
--
-- ret = qca808x_cable_test_get_pair_status(phydev, ETHTOOL_A_CABLE_PAIR_C, val);
-- if (ret)
-- return ret;
--
-- ret = qca808x_cable_test_get_pair_status(phydev, ETHTOOL_A_CABLE_PAIR_D, val);
-- if (ret)
-- return ret;
--
-- *finished = true;
--
-- return 0;
--}
-
- static int qca808x_get_features(struct phy_device *phydev)
- {
---- a/drivers/net/phy/qcom/qcom-phy-lib.c
-+++ b/drivers/net/phy/qcom/qcom-phy-lib.c
-@@ -5,6 +5,7 @@
-
- #include <linux/netdevice.h>
- #include <linux/etherdevice.h>
-+#include <linux/ethtool_netlink.h>
-
- #include "qcom.h"
-
-@@ -311,6 +312,42 @@ int at803x_prepare_config_aneg(struct ph
- }
- EXPORT_SYMBOL_GPL(at803x_prepare_config_aneg);
-
-+int at803x_read_status(struct phy_device *phydev)
-+{
-+ struct at803x_ss_mask ss_mask = { 0 };
-+ int err, old_link = phydev->link;
-+
-+ /* Update the link, but return if there was an error */
-+ err = genphy_update_link(phydev);
-+ if (err)
-+ return err;
-+
-+ /* why bother the PHY if nothing can have changed */
-+ if (phydev->autoneg == AUTONEG_ENABLE && old_link && phydev->link)
-+ return 0;
-+
-+ phydev->speed = SPEED_UNKNOWN;
-+ phydev->duplex = DUPLEX_UNKNOWN;
-+ phydev->pause = 0;
-+ phydev->asym_pause = 0;
-+
-+ err = genphy_read_lpa(phydev);
-+ if (err < 0)
-+ return err;
-+
-+ ss_mask.speed_mask = AT803X_SS_SPEED_MASK;
-+ ss_mask.speed_shift = __bf_shf(AT803X_SS_SPEED_MASK);
-+ err = at803x_read_specific_status(phydev, ss_mask);
-+ if (err < 0)
-+ return err;
-+
-+ if (phydev->autoneg == AUTONEG_ENABLE && phydev->autoneg_complete)
-+ phy_resolve_aneg_pause(phydev);
-+
-+ return 0;
-+}
-+EXPORT_SYMBOL_GPL(at803x_read_status);
-+
- static int at803x_get_downshift(struct phy_device *phydev, u8 *d)
- {
- int val;
-@@ -427,3 +464,159 @@ int at803x_cdt_wait_for_completion(struc
- return ret < 0 ? ret : 0;
- }
- EXPORT_SYMBOL_GPL(at803x_cdt_wait_for_completion);
-+
-+static bool qca808x_cdt_fault_length_valid(int cdt_code)
-+{
-+ switch (cdt_code) {
-+ case QCA808X_CDT_STATUS_STAT_SAME_SHORT:
-+ case QCA808X_CDT_STATUS_STAT_SAME_OPEN:
-+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_NORMAL:
-+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_OPEN:
-+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_SHORT:
-+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_NORMAL:
-+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_OPEN:
-+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_SHORT:
-+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_NORMAL:
-+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_OPEN:
-+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_SHORT:
-+ return true;
-+ default:
-+ return false;
-+ }
-+}
-+
-+static int qca808x_cable_test_result_trans(int cdt_code)
-+{
-+ switch (cdt_code) {
-+ case QCA808X_CDT_STATUS_STAT_NORMAL:
-+ return ETHTOOL_A_CABLE_RESULT_CODE_OK;
-+ case QCA808X_CDT_STATUS_STAT_SAME_SHORT:
-+ return ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT;
-+ case QCA808X_CDT_STATUS_STAT_SAME_OPEN:
-+ return ETHTOOL_A_CABLE_RESULT_CODE_OPEN;
-+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_NORMAL:
-+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_OPEN:
-+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_SHORT:
-+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_NORMAL:
-+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_OPEN:
-+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_SHORT:
-+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_NORMAL:
-+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_OPEN:
-+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_SHORT:
-+ return ETHTOOL_A_CABLE_RESULT_CODE_CROSS_SHORT;
-+ case QCA808X_CDT_STATUS_STAT_FAIL:
-+ default:
-+ return ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC;
-+ }
-+}
-+
-+static int qca808x_cdt_fault_length(struct phy_device *phydev, int pair,
-+ int result)
-+{
-+ int val;
-+ u32 cdt_length_reg = 0;
-+
-+ switch (pair) {
-+ case ETHTOOL_A_CABLE_PAIR_A:
-+ cdt_length_reg = QCA808X_MMD3_CDT_DIAG_PAIR_A;
-+ break;
-+ case ETHTOOL_A_CABLE_PAIR_B:
-+ cdt_length_reg = QCA808X_MMD3_CDT_DIAG_PAIR_B;
-+ break;
-+ case ETHTOOL_A_CABLE_PAIR_C:
-+ cdt_length_reg = QCA808X_MMD3_CDT_DIAG_PAIR_C;
-+ break;
-+ case ETHTOOL_A_CABLE_PAIR_D:
-+ cdt_length_reg = QCA808X_MMD3_CDT_DIAG_PAIR_D;
-+ break;
-+ default:
-+ return -EINVAL;
-+ }
-+
-+ val = phy_read_mmd(phydev, MDIO_MMD_PCS, cdt_length_reg);
-+ if (val < 0)
-+ return val;
-+
-+ if (result == ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT)
-+ val = FIELD_GET(QCA808X_CDT_DIAG_LENGTH_SAME_SHORT, val);
-+ else
-+ val = FIELD_GET(QCA808X_CDT_DIAG_LENGTH_CROSS_SHORT, val);
-+
-+ return at803x_cdt_fault_length(val);
-+}
-+
-+static int qca808x_cable_test_get_pair_status(struct phy_device *phydev, u8 pair,
-+ u16 status)
-+{
-+ int length, result;
-+ u16 pair_code;
-+
-+ switch (pair) {
-+ case ETHTOOL_A_CABLE_PAIR_A:
-+ pair_code = FIELD_GET(QCA808X_CDT_CODE_PAIR_A, status);
-+ break;
-+ case ETHTOOL_A_CABLE_PAIR_B:
-+ pair_code = FIELD_GET(QCA808X_CDT_CODE_PAIR_B, status);
-+ break;
-+ case ETHTOOL_A_CABLE_PAIR_C:
-+ pair_code = FIELD_GET(QCA808X_CDT_CODE_PAIR_C, status);
-+ break;
-+ case ETHTOOL_A_CABLE_PAIR_D:
-+ pair_code = FIELD_GET(QCA808X_CDT_CODE_PAIR_D, status);
-+ break;
-+ default:
-+ return -EINVAL;
-+ }
-+
-+ result = qca808x_cable_test_result_trans(pair_code);
-+ ethnl_cable_test_result(phydev, pair, result);
-+
-+ if (qca808x_cdt_fault_length_valid(pair_code)) {
-+ length = qca808x_cdt_fault_length(phydev, pair, result);
-+ ethnl_cable_test_fault_length(phydev, pair, length);
-+ }
-+
-+ return 0;
-+}
-+
-+int qca808x_cable_test_get_status(struct phy_device *phydev, bool *finished)
-+{
-+ int ret, val;
-+
-+ *finished = false;
-+
-+ val = QCA808X_CDT_ENABLE_TEST |
-+ QCA808X_CDT_LENGTH_UNIT;
-+ ret = at803x_cdt_start(phydev, val);
-+ if (ret)
-+ return ret;
-+
-+ ret = at803x_cdt_wait_for_completion(phydev, QCA808X_CDT_ENABLE_TEST);
-+ if (ret)
-+ return ret;
-+
-+ val = phy_read_mmd(phydev, MDIO_MMD_PCS, QCA808X_MMD3_CDT_STATUS);
-+ if (val < 0)
-+ return val;
-+
-+ ret = qca808x_cable_test_get_pair_status(phydev, ETHTOOL_A_CABLE_PAIR_A, val);
-+ if (ret)
-+ return ret;
-+
-+ ret = qca808x_cable_test_get_pair_status(phydev, ETHTOOL_A_CABLE_PAIR_B, val);
-+ if (ret)
-+ return ret;
-+
-+ ret = qca808x_cable_test_get_pair_status(phydev, ETHTOOL_A_CABLE_PAIR_C, val);
-+ if (ret)
-+ return ret;
-+
-+ ret = qca808x_cable_test_get_pair_status(phydev, ETHTOOL_A_CABLE_PAIR_D, val);
-+ if (ret)
-+ return ret;
-+
-+ *finished = true;
-+
-+ return 0;
-+}
-+EXPORT_SYMBOL_GPL(qca808x_cable_test_get_status);
---- a/drivers/net/phy/qcom/qcom.h
-+++ b/drivers/net/phy/qcom/qcom.h
-@@ -54,6 +54,55 @@
- #define AT803X_CDT_STATUS_STAT_MASK GENMASK(9, 8)
- #define AT803X_CDT_STATUS_DELTA_TIME_MASK GENMASK(7, 0)
-
-+#define QCA808X_CDT_ENABLE_TEST BIT(15)
-+#define QCA808X_CDT_INTER_CHECK_DIS BIT(13)
-+#define QCA808X_CDT_STATUS BIT(11)
-+#define QCA808X_CDT_LENGTH_UNIT BIT(10)
-+
-+#define QCA808X_MMD3_CDT_STATUS 0x8064
-+#define QCA808X_MMD3_CDT_DIAG_PAIR_A 0x8065
-+#define QCA808X_MMD3_CDT_DIAG_PAIR_B 0x8066
-+#define QCA808X_MMD3_CDT_DIAG_PAIR_C 0x8067
-+#define QCA808X_MMD3_CDT_DIAG_PAIR_D 0x8068
-+#define QCA808X_CDT_DIAG_LENGTH_SAME_SHORT GENMASK(15, 8)
-+#define QCA808X_CDT_DIAG_LENGTH_CROSS_SHORT GENMASK(7, 0)
-+
-+#define QCA808X_CDT_CODE_PAIR_A GENMASK(15, 12)
-+#define QCA808X_CDT_CODE_PAIR_B GENMASK(11, 8)
-+#define QCA808X_CDT_CODE_PAIR_C GENMASK(7, 4)
-+#define QCA808X_CDT_CODE_PAIR_D GENMASK(3, 0)
-+
-+#define QCA808X_CDT_STATUS_STAT_TYPE GENMASK(1, 0)
-+#define QCA808X_CDT_STATUS_STAT_FAIL FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_TYPE, 0)
-+#define QCA808X_CDT_STATUS_STAT_NORMAL FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_TYPE, 1)
-+#define QCA808X_CDT_STATUS_STAT_SAME_OPEN FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_TYPE, 2)
-+#define QCA808X_CDT_STATUS_STAT_SAME_SHORT FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_TYPE, 3)
-+
-+#define QCA808X_CDT_STATUS_STAT_MDI GENMASK(3, 2)
-+#define QCA808X_CDT_STATUS_STAT_MDI1 FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_MDI, 1)
-+#define QCA808X_CDT_STATUS_STAT_MDI2 FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_MDI, 2)
-+#define QCA808X_CDT_STATUS_STAT_MDI3 FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_MDI, 3)
-+
-+/* NORMAL are MDI with type set to 0 */
-+#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_NORMAL QCA808X_CDT_STATUS_STAT_MDI1
-+#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_OPEN (QCA808X_CDT_STATUS_STAT_SAME_OPEN |\
-+ QCA808X_CDT_STATUS_STAT_MDI1)
-+#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_SHORT (QCA808X_CDT_STATUS_STAT_SAME_SHORT |\
-+ QCA808X_CDT_STATUS_STAT_MDI1)
-+#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_NORMAL QCA808X_CDT_STATUS_STAT_MDI2
-+#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_OPEN (QCA808X_CDT_STATUS_STAT_SAME_OPEN |\
-+ QCA808X_CDT_STATUS_STAT_MDI2)
-+#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_SHORT (QCA808X_CDT_STATUS_STAT_SAME_SHORT |\
-+ QCA808X_CDT_STATUS_STAT_MDI2)
-+#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_NORMAL QCA808X_CDT_STATUS_STAT_MDI3
-+#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_OPEN (QCA808X_CDT_STATUS_STAT_SAME_OPEN |\
-+ QCA808X_CDT_STATUS_STAT_MDI3)
-+#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_SHORT (QCA808X_CDT_STATUS_STAT_SAME_SHORT |\
-+ QCA808X_CDT_STATUS_STAT_MDI3)
-+
-+/* Added for reference of existence but should be handled by wait_for_completion already */
-+#define QCA808X_CDT_STATUS_STAT_BUSY (BIT(1) | BIT(3))
-+
- #define AT803X_LOC_MAC_ADDR_0_15_OFFSET 0x804C
- #define AT803X_LOC_MAC_ADDR_16_31_OFFSET 0x804B
- #define AT803X_LOC_MAC_ADDR_32_47_OFFSET 0x804A
-@@ -110,6 +159,7 @@ int at803x_read_specific_status(struct p
- struct at803x_ss_mask ss_mask);
- int at803x_config_mdix(struct phy_device *phydev, u8 ctrl);
- int at803x_prepare_config_aneg(struct phy_device *phydev);
-+int at803x_read_status(struct phy_device *phydev);
- int at803x_get_tunable(struct phy_device *phydev,
- struct ethtool_tunable *tuna, void *data);
- int at803x_set_tunable(struct phy_device *phydev,
-@@ -118,3 +168,4 @@ int at803x_cdt_fault_length(int dt);
- int at803x_cdt_start(struct phy_device *phydev, u32 cdt_start);
- int at803x_cdt_wait_for_completion(struct phy_device *phydev,
- u32 cdt_en);
-+int qca808x_cable_test_get_status(struct phy_device *phydev, bool *finished);
+++ /dev/null
-From 9b1d5e055508393561e26bd1720f4c2639b03b1a Mon Sep 17 00:00:00 2001
-Date: Tue, 6 Feb 2024 18:31:09 +0100
-Subject: [PATCH 06/10] net: phy: provide whether link has changed in
- c37_read_status
-
-Some PHY driver might require additional regs call after
-genphy_c37_read_status() is called.
-
-Expand genphy_c37_read_status to provide a bool wheather the link has
-changed or not to permit PHY driver to skip additional regs call if
-nothing has changed.
-
-Every user of genphy_c37_read_status() is updated with the new
-additional bool.
-
----
- drivers/net/phy/broadcom.c | 3 ++-
- drivers/net/phy/phy_device.c | 11 +++++++++--
- drivers/net/phy/qcom/at803x.c | 3 ++-
- include/linux/phy.h | 2 +-
- 4 files changed, 14 insertions(+), 5 deletions(-)
-
---- a/drivers/net/phy/broadcom.c
-+++ b/drivers/net/phy/broadcom.c
-@@ -665,10 +665,11 @@ static int bcm54616s_config_aneg(struct
- static int bcm54616s_read_status(struct phy_device *phydev)
- {
- struct bcm54616s_phy_priv *priv = phydev->priv;
-+ bool changed;
- int err;
-
- if (priv->mode_1000bx_en)
-- err = genphy_c37_read_status(phydev);
-+ err = genphy_c37_read_status(phydev, &changed);
- else
- err = genphy_read_status(phydev);
-
---- a/drivers/net/phy/phy_device.c
-+++ b/drivers/net/phy/phy_device.c
-@@ -2617,12 +2617,15 @@ EXPORT_SYMBOL(genphy_read_status);
- /**
- * genphy_c37_read_status - check the link status and update current link state
- * @phydev: target phy_device struct
-+ * @changed: pointer where to store if link changed
- *
- * Description: Check the link, then figure out the current state
- * by comparing what we advertise with what the link partner
- * advertises. This function is for Clause 37 1000Base-X mode.
-+ *
-+ * If link has changed, @changed is set to true, false otherwise.
- */
--int genphy_c37_read_status(struct phy_device *phydev)
-+int genphy_c37_read_status(struct phy_device *phydev, bool *changed)
- {
- int lpa, err, old_link = phydev->link;
-
-@@ -2632,9 +2635,13 @@ int genphy_c37_read_status(struct phy_de
- return err;
-
- /* why bother the PHY if nothing can have changed */
-- if (phydev->autoneg == AUTONEG_ENABLE && old_link && phydev->link)
-+ if (phydev->autoneg == AUTONEG_ENABLE && old_link && phydev->link) {
-+ *changed = false;
- return 0;
-+ }
-
-+ /* Signal link has changed */
-+ *changed = true;
- phydev->duplex = DUPLEX_UNKNOWN;
- phydev->pause = 0;
- phydev->asym_pause = 0;
---- a/drivers/net/phy/qcom/at803x.c
-+++ b/drivers/net/phy/qcom/at803x.c
-@@ -912,9 +912,10 @@ static int at8031_config_intr(struct phy
- static int at8031_read_status(struct phy_device *phydev)
- {
- struct at803x_priv *priv = phydev->priv;
-+ bool changed;
-
- if (priv->is_1000basex)
-- return genphy_c37_read_status(phydev);
-+ return genphy_c37_read_status(phydev, &changed);
-
- return at803x_read_status(phydev);
- }
---- a/include/linux/phy.h
-+++ b/include/linux/phy.h
-@@ -1880,7 +1880,7 @@ int genphy_write_mmd_unsupported(struct
-
- /* Clause 37 */
- int genphy_c37_config_aneg(struct phy_device *phydev);
--int genphy_c37_read_status(struct phy_device *phydev);
-+int genphy_c37_read_status(struct phy_device *phydev, bool *changed);
-
- /* Clause 45 PHY */
- int genphy_c45_restart_aneg(struct phy_device *phydev);
+++ /dev/null
-From d1cb613efbd3cd7d0c000167816beb3f248f5eb8 Mon Sep 17 00:00:00 2001
-Date: Tue, 6 Feb 2024 18:31:10 +0100
-Subject: [PATCH 07/10] net: phy: qcom: add support for QCA807x PHY Family
-
-This adds driver for the Qualcomm QCA8072 and QCA8075 PHY-s.
-
-They are 2 or 5 port IEEE 802.3 clause 22 compliant 10BASE-Te,
-100BASE-TX and 1000BASE-T PHY-s.
-
-They feature 2 SerDes, one for PSGMII or QSGMII connection with
-MAC, while second one is SGMII for connection to MAC or fiber.
-
-Both models have a combo port that supports 1000BASE-X and
-100BASE-FX fiber.
-
-PHY package can be configured in 3 mode following this table:
-
- First Serdes mode Second Serdes mode
-Option 1 PSGMII for copper Disabled
- ports 0-4
-Option 2 PSGMII for copper 1000BASE-X / 100BASE-FX
- ports 0-4
-Option 3 QSGMII for copper SGMII for
- ports 0-3 copper port 4
-
-Each PHY inside of QCA807x series has 4 digitally controlled
-output only pins that natively drive LED-s.
-But some vendors used these to driver generic LED-s controlled
-by userspace, so lets enable registering each PHY as GPIO
-controller and add driver for it.
-
-These are commonly used in Qualcomm IPQ40xx, IPQ60xx and IPQ807x
-boards.
-
----
- drivers/net/phy/qcom/Kconfig | 8 +
- drivers/net/phy/qcom/Makefile | 1 +
- drivers/net/phy/qcom/qca807x.c | 597 +++++++++++++++++++++++++++++++++
- 3 files changed, 606 insertions(+)
- create mode 100644 drivers/net/phy/qcom/qca807x.c
-
---- a/drivers/net/phy/qcom/Kconfig
-+++ b/drivers/net/phy/qcom/Kconfig
-@@ -20,3 +20,11 @@ config QCA808X_PHY
- select QCOM_NET_PHYLIB
- help
- Currently supports the QCA8081 model
-+
-+config QCA807X_PHY
-+ tristate "Qualcomm QCA807x PHYs"
-+ select QCOM_NET_PHYLIB
-+ depends on OF_MDIO
-+ help
-+ Currently supports the Qualcomm QCA8072, QCA8075 and the PSGMII
-+ control PHY.
---- a/drivers/net/phy/qcom/Makefile
-+++ b/drivers/net/phy/qcom/Makefile
-@@ -3,3 +3,4 @@ obj-$(CONFIG_QCOM_NET_PHYLIB) += qcom-ph
- obj-$(CONFIG_AT803X_PHY) += at803x.o
- obj-$(CONFIG_QCA83XX_PHY) += qca83xx.o
- obj-$(CONFIG_QCA808X_PHY) += qca808x.o
-+obj-$(CONFIG_QCA807X_PHY) += qca807x.o
---- /dev/null
-+++ b/drivers/net/phy/qcom/qca807x.c
-@@ -0,0 +1,597 @@
-+// SPDX-License-Identifier: GPL-2.0-or-later
-+/*
-+ * Copyright (c) 2023 Sartura Ltd.
-+ *
-+ *
-+ * Qualcomm QCA8072 and QCA8075 PHY driver
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/of.h>
-+#include <linux/phy.h>
-+#include <linux/bitfield.h>
-+#include <linux/gpio/driver.h>
-+#include <linux/sfp.h>
-+
-+#include "qcom.h"
-+
-+#define QCA807X_CHIP_CONFIGURATION 0x1f
-+#define QCA807X_BT_BX_REG_SEL BIT(15)
-+#define QCA807X_BT_BX_REG_SEL_FIBER 0
-+#define QCA807X_BT_BX_REG_SEL_COPPER 1
-+#define QCA807X_CHIP_CONFIGURATION_MODE_CFG_MASK GENMASK(3, 0)
-+#define QCA807X_CHIP_CONFIGURATION_MODE_QSGMII_SGMII 4
-+#define QCA807X_CHIP_CONFIGURATION_MODE_PSGMII_FIBER 3
-+#define QCA807X_CHIP_CONFIGURATION_MODE_PSGMII_ALL_COPPER 0
-+
-+#define QCA807X_MEDIA_SELECT_STATUS 0x1a
-+#define QCA807X_MEDIA_DETECTED_COPPER BIT(5)
-+#define QCA807X_MEDIA_DETECTED_1000_BASE_X BIT(4)
-+#define QCA807X_MEDIA_DETECTED_100_BASE_FX BIT(3)
-+
-+#define QCA807X_MMD7_FIBER_MODE_AUTO_DETECTION 0x807e
-+#define QCA807X_MMD7_FIBER_MODE_AUTO_DETECTION_EN BIT(0)
-+
-+#define QCA807X_MMD7_1000BASE_T_POWER_SAVE_PER_CABLE_LENGTH 0x801a
-+#define QCA807X_CONTROL_DAC_MASK GENMASK(2, 0)
-+/* List of tweaks enabled by this bit:
-+ * - With both FULL amplitude and FULL bias current: bias current
-+ * is set to half.
-+ * - With only DSP amplitude: bias current is set to half and
-+ * is set to 1/4 with cable < 10m.
-+ * - With DSP bias current (included both DSP amplitude and
-+ * DSP bias current): bias current is half the detected current
-+ * with cable < 10m.
-+ */
-+#define QCA807X_CONTROL_DAC_BIAS_CURRENT_TWEAK BIT(2)
-+#define QCA807X_CONTROL_DAC_DSP_BIAS_CURRENT BIT(1)
-+#define QCA807X_CONTROL_DAC_DSP_AMPLITUDE BIT(0)
-+
-+#define QCA807X_MMD7_LED_100N_1 0x8074
-+#define QCA807X_MMD7_LED_100N_2 0x8075
-+#define QCA807X_MMD7_LED_1000N_1 0x8076
-+#define QCA807X_MMD7_LED_1000N_2 0x8077
-+
-+#define QCA807X_MMD7_LED_CTRL(x) (0x8074 + ((x) * 2))
-+#define QCA807X_MMD7_LED_FORCE_CTRL(x) (0x8075 + ((x) * 2))
-+
-+#define QCA807X_GPIO_FORCE_EN BIT(15)
-+#define QCA807X_GPIO_FORCE_MODE_MASK GENMASK(14, 13)
-+
-+#define QCA807X_FUNCTION_CONTROL 0x10
-+#define QCA807X_FC_MDI_CROSSOVER_MODE_MASK GENMASK(6, 5)
-+#define QCA807X_FC_MDI_CROSSOVER_AUTO 3
-+#define QCA807X_FC_MDI_CROSSOVER_MANUAL_MDIX 1
-+#define QCA807X_FC_MDI_CROSSOVER_MANUAL_MDI 0
-+
-+/* PQSGMII Analog PHY specific */
-+#define PQSGMII_CTRL_REG 0x0
-+#define PQSGMII_ANALOG_SW_RESET BIT(6)
-+#define PQSGMII_DRIVE_CONTROL_1 0xb
-+#define PQSGMII_TX_DRIVER_MASK GENMASK(7, 4)
-+#define PQSGMII_TX_DRIVER_140MV 0x0
-+#define PQSGMII_TX_DRIVER_160MV 0x1
-+#define PQSGMII_TX_DRIVER_180MV 0x2
-+#define PQSGMII_TX_DRIVER_200MV 0x3
-+#define PQSGMII_TX_DRIVER_220MV 0x4
-+#define PQSGMII_TX_DRIVER_240MV 0x5
-+#define PQSGMII_TX_DRIVER_260MV 0x6
-+#define PQSGMII_TX_DRIVER_280MV 0x7
-+#define PQSGMII_TX_DRIVER_300MV 0x8
-+#define PQSGMII_TX_DRIVER_320MV 0x9
-+#define PQSGMII_TX_DRIVER_400MV 0xa
-+#define PQSGMII_TX_DRIVER_500MV 0xb
-+#define PQSGMII_TX_DRIVER_600MV 0xc
-+#define PQSGMII_MODE_CTRL 0x6d
-+#define PQSGMII_MODE_CTRL_AZ_WORKAROUND_MASK BIT(0)
-+#define PQSGMII_MMD3_SERDES_CONTROL 0x805a
-+
-+#define PHY_ID_QCA8072 0x004dd0b2
-+#define PHY_ID_QCA8075 0x004dd0b1
-+
-+#define QCA807X_COMBO_ADDR_OFFSET 4
-+#define QCA807X_PQSGMII_ADDR_OFFSET 5
-+#define SERDES_RESET_SLEEP 100
-+
-+enum qca807x_global_phy {
-+ QCA807X_COMBO_ADDR = 4,
-+ QCA807X_PQSGMII_ADDR = 5,
-+};
-+
-+struct qca807x_shared_priv {
-+ unsigned int package_mode;
-+ u32 tx_drive_strength;
-+};
-+
-+struct qca807x_gpio_priv {
-+ struct phy_device *phy;
-+};
-+
-+struct qca807x_priv {
-+ bool dac_full_amplitude;
-+ bool dac_full_bias_current;
-+ bool dac_disable_bias_current_tweak;
-+};
-+
-+static int qca807x_cable_test_start(struct phy_device *phydev)
-+{
-+ /* we do all the (time consuming) work later */
-+ return 0;
-+}
-+
-+#ifdef CONFIG_GPIOLIB
-+static int qca807x_gpio_get_direction(struct gpio_chip *gc, unsigned int offset)
-+{
-+ return GPIO_LINE_DIRECTION_OUT;
-+}
-+
-+static int qca807x_gpio_get(struct gpio_chip *gc, unsigned int offset)
-+{
-+ struct qca807x_gpio_priv *priv = gpiochip_get_data(gc);
-+ u16 reg;
-+ int val;
-+
-+ reg = QCA807X_MMD7_LED_FORCE_CTRL(offset);
-+ val = phy_read_mmd(priv->phy, MDIO_MMD_AN, reg);
-+
-+ return FIELD_GET(QCA807X_GPIO_FORCE_MODE_MASK, val);
-+}
-+
-+static void qca807x_gpio_set(struct gpio_chip *gc, unsigned int offset, int value)
-+{
-+ struct qca807x_gpio_priv *priv = gpiochip_get_data(gc);
-+ u16 reg;
-+ int val;
-+
-+ reg = QCA807X_MMD7_LED_FORCE_CTRL(offset);
-+
-+ val = phy_read_mmd(priv->phy, MDIO_MMD_AN, reg);
-+ val &= ~QCA807X_GPIO_FORCE_MODE_MASK;
-+ val |= QCA807X_GPIO_FORCE_EN;
-+ val |= FIELD_PREP(QCA807X_GPIO_FORCE_MODE_MASK, value);
-+
-+ phy_write_mmd(priv->phy, MDIO_MMD_AN, reg, val);
-+}
-+
-+static int qca807x_gpio_dir_out(struct gpio_chip *gc, unsigned int offset, int value)
-+{
-+ qca807x_gpio_set(gc, offset, value);
-+
-+ return 0;
-+}
-+
-+static int qca807x_gpio(struct phy_device *phydev)
-+{
-+ struct device *dev = &phydev->mdio.dev;
-+ struct qca807x_gpio_priv *priv;
-+ struct gpio_chip *gc;
-+
-+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
-+ if (!priv)
-+ return -ENOMEM;
-+
-+ priv->phy = phydev;
-+
-+ gc = devm_kzalloc(dev, sizeof(*gc), GFP_KERNEL);
-+ if (!gc)
-+ return -ENOMEM;
-+
-+ gc->label = dev_name(dev);
-+ gc->base = -1;
-+ gc->ngpio = 2;
-+ gc->parent = dev;
-+ gc->owner = THIS_MODULE;
-+ gc->can_sleep = true;
-+ gc->get_direction = qca807x_gpio_get_direction;
-+ gc->direction_output = qca807x_gpio_dir_out;
-+ gc->get = qca807x_gpio_get;
-+ gc->set = qca807x_gpio_set;
-+
-+ return devm_gpiochip_add_data(dev, gc, priv);
-+}
-+#endif
-+
-+static int qca807x_read_fiber_status(struct phy_device *phydev)
-+{
-+ bool changed;
-+ int ss, err;
-+
-+ err = genphy_c37_read_status(phydev, &changed);
-+ if (err || !changed)
-+ return err;
-+
-+ /* Read the QCA807x PHY-Specific Status register fiber page,
-+ * which indicates the speed and duplex that the PHY is actually
-+ * using, irrespective of whether we are in autoneg mode or not.
-+ */
-+ ss = phy_read(phydev, AT803X_SPECIFIC_STATUS);
-+ if (ss < 0)
-+ return ss;
-+
-+ phydev->speed = SPEED_UNKNOWN;
-+ phydev->duplex = DUPLEX_UNKNOWN;
-+ if (ss & AT803X_SS_SPEED_DUPLEX_RESOLVED) {
-+ switch (FIELD_GET(AT803X_SS_SPEED_MASK, ss)) {
-+ case AT803X_SS_SPEED_100:
-+ phydev->speed = SPEED_100;
-+ break;
-+ case AT803X_SS_SPEED_1000:
-+ phydev->speed = SPEED_1000;
-+ break;
-+ }
-+
-+ if (ss & AT803X_SS_DUPLEX)
-+ phydev->duplex = DUPLEX_FULL;
-+ else
-+ phydev->duplex = DUPLEX_HALF;
-+ }
-+
-+ return 0;
-+}
-+
-+static int qca807x_read_status(struct phy_device *phydev)
-+{
-+ if (linkmode_test_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, phydev->supported)) {
-+ switch (phydev->port) {
-+ case PORT_FIBRE:
-+ return qca807x_read_fiber_status(phydev);
-+ case PORT_TP:
-+ return at803x_read_status(phydev);
-+ default:
-+ return -EINVAL;
-+ }
-+ }
-+
-+ return at803x_read_status(phydev);
-+}
-+
-+static int qca807x_phy_package_probe_once(struct phy_device *phydev)
-+{
-+ struct phy_package_shared *shared = phydev->shared;
-+ struct qca807x_shared_priv *priv = shared->priv;
-+ unsigned int tx_drive_strength;
-+ const char *package_mode_name;
-+
-+ /* Default to 600mw if not defined */
-+ if (of_property_read_u32(shared->np, "qcom,tx-drive-strength-milliwatt",
-+ &tx_drive_strength))
-+ tx_drive_strength = 600;
-+
-+ switch (tx_drive_strength) {
-+ case 140:
-+ priv->tx_drive_strength = PQSGMII_TX_DRIVER_140MV;
-+ break;
-+ case 160:
-+ priv->tx_drive_strength = PQSGMII_TX_DRIVER_160MV;
-+ break;
-+ case 180:
-+ priv->tx_drive_strength = PQSGMII_TX_DRIVER_180MV;
-+ break;
-+ case 200:
-+ priv->tx_drive_strength = PQSGMII_TX_DRIVER_200MV;
-+ break;
-+ case 220:
-+ priv->tx_drive_strength = PQSGMII_TX_DRIVER_220MV;
-+ break;
-+ case 240:
-+ priv->tx_drive_strength = PQSGMII_TX_DRIVER_240MV;
-+ break;
-+ case 260:
-+ priv->tx_drive_strength = PQSGMII_TX_DRIVER_260MV;
-+ break;
-+ case 280:
-+ priv->tx_drive_strength = PQSGMII_TX_DRIVER_280MV;
-+ break;
-+ case 300:
-+ priv->tx_drive_strength = PQSGMII_TX_DRIVER_300MV;
-+ break;
-+ case 320:
-+ priv->tx_drive_strength = PQSGMII_TX_DRIVER_320MV;
-+ break;
-+ case 400:
-+ priv->tx_drive_strength = PQSGMII_TX_DRIVER_400MV;
-+ break;
-+ case 500:
-+ priv->tx_drive_strength = PQSGMII_TX_DRIVER_500MV;
-+ break;
-+ case 600:
-+ priv->tx_drive_strength = PQSGMII_TX_DRIVER_600MV;
-+ break;
-+ default:
-+ return -EINVAL;
-+ }
-+
-+ priv->package_mode = PHY_INTERFACE_MODE_NA;
-+ if (!of_property_read_string(shared->np, "qcom,package-mode",
-+ &package_mode_name)) {
-+ if (!strcasecmp(package_mode_name,
-+ phy_modes(PHY_INTERFACE_MODE_PSGMII)))
-+ priv->package_mode = PHY_INTERFACE_MODE_PSGMII;
-+ else if (!strcasecmp(package_mode_name,
-+ phy_modes(PHY_INTERFACE_MODE_QSGMII)))
-+ priv->package_mode = PHY_INTERFACE_MODE_QSGMII;
-+ else
-+ return -EINVAL;
-+ }
-+
-+ return 0;
-+}
-+
-+static int qca807x_phy_package_config_init_once(struct phy_device *phydev)
-+{
-+ struct phy_package_shared *shared = phydev->shared;
-+ struct qca807x_shared_priv *priv = shared->priv;
-+ int val, ret;
-+
-+ phy_lock_mdio_bus(phydev);
-+
-+ /* Set correct PHY package mode */
-+ val = __phy_package_read(phydev, QCA807X_COMBO_ADDR,
-+ QCA807X_CHIP_CONFIGURATION);
-+ val &= ~QCA807X_CHIP_CONFIGURATION_MODE_CFG_MASK;
-+ /* package_mode can be QSGMII or PSGMII and we validate
-+ * this in probe_once.
-+ * With package_mode to NA, we default to PSGMII.
-+ */
-+ switch (priv->package_mode) {
-+ case PHY_INTERFACE_MODE_QSGMII:
-+ val |= QCA807X_CHIP_CONFIGURATION_MODE_QSGMII_SGMII;
-+ break;
-+ case PHY_INTERFACE_MODE_PSGMII:
-+ default:
-+ val |= QCA807X_CHIP_CONFIGURATION_MODE_PSGMII_ALL_COPPER;
-+ }
-+ ret = __phy_package_write(phydev, QCA807X_COMBO_ADDR,
-+ QCA807X_CHIP_CONFIGURATION, val);
-+ if (ret)
-+ goto exit;
-+
-+ /* After mode change Serdes reset is required */
-+ val = __phy_package_read(phydev, QCA807X_PQSGMII_ADDR,
-+ PQSGMII_CTRL_REG);
-+ val &= ~PQSGMII_ANALOG_SW_RESET;
-+ ret = __phy_package_write(phydev, QCA807X_PQSGMII_ADDR,
-+ PQSGMII_CTRL_REG, val);
-+ if (ret)
-+ goto exit;
-+
-+ msleep(SERDES_RESET_SLEEP);
-+
-+ val = __phy_package_read(phydev, QCA807X_PQSGMII_ADDR,
-+ PQSGMII_CTRL_REG);
-+ val |= PQSGMII_ANALOG_SW_RESET;
-+ ret = __phy_package_write(phydev, QCA807X_PQSGMII_ADDR,
-+ PQSGMII_CTRL_REG, val);
-+ if (ret)
-+ goto exit;
-+
-+ /* Workaround to enable AZ transmitting ability */
-+ val = __phy_package_read_mmd(phydev, QCA807X_PQSGMII_ADDR,
-+ MDIO_MMD_PMAPMD, PQSGMII_MODE_CTRL);
-+ val &= ~PQSGMII_MODE_CTRL_AZ_WORKAROUND_MASK;
-+ ret = __phy_package_write_mmd(phydev, QCA807X_PQSGMII_ADDR,
-+ MDIO_MMD_PMAPMD, PQSGMII_MODE_CTRL, val);
-+ if (ret)
-+ goto exit;
-+
-+ /* Set PQSGMII TX AMP strength */
-+ val = __phy_package_read(phydev, QCA807X_PQSGMII_ADDR,
-+ PQSGMII_DRIVE_CONTROL_1);
-+ val &= ~PQSGMII_TX_DRIVER_MASK;
-+ val |= FIELD_PREP(PQSGMII_TX_DRIVER_MASK, priv->tx_drive_strength);
-+ ret = __phy_package_write(phydev, QCA807X_PQSGMII_ADDR,
-+ PQSGMII_DRIVE_CONTROL_1, val);
-+ if (ret)
-+ goto exit;
-+
-+ /* Prevent PSGMII going into hibernation via PSGMII self test */
-+ val = __phy_package_read_mmd(phydev, QCA807X_COMBO_ADDR,
-+ MDIO_MMD_PCS, PQSGMII_MMD3_SERDES_CONTROL);
-+ val &= ~BIT(1);
-+ ret = __phy_package_write_mmd(phydev, QCA807X_COMBO_ADDR,
-+ MDIO_MMD_PCS, PQSGMII_MMD3_SERDES_CONTROL, val);
-+
-+exit:
-+ phy_unlock_mdio_bus(phydev);
-+
-+ return ret;
-+}
-+
-+static int qca807x_sfp_insert(void *upstream, const struct sfp_eeprom_id *id)
-+{
-+ struct phy_device *phydev = upstream;
-+ __ETHTOOL_DECLARE_LINK_MODE_MASK(support) = { 0, };
-+ phy_interface_t iface;
-+ int ret;
-+ DECLARE_PHY_INTERFACE_MASK(interfaces);
-+
-+ sfp_parse_support(phydev->sfp_bus, id, support, interfaces);
-+ iface = sfp_select_interface(phydev->sfp_bus, support);
-+
-+ dev_info(&phydev->mdio.dev, "%s SFP module inserted\n", phy_modes(iface));
-+
-+ switch (iface) {
-+ case PHY_INTERFACE_MODE_1000BASEX:
-+ case PHY_INTERFACE_MODE_100BASEX:
-+ /* Set PHY mode to PSGMII combo (1/4 copper + combo ports) mode */
-+ ret = phy_modify(phydev,
-+ QCA807X_CHIP_CONFIGURATION,
-+ QCA807X_CHIP_CONFIGURATION_MODE_CFG_MASK,
-+ QCA807X_CHIP_CONFIGURATION_MODE_PSGMII_FIBER);
-+ /* Enable fiber mode autodection (1000Base-X or 100Base-FX) */
-+ ret = phy_set_bits_mmd(phydev,
-+ MDIO_MMD_AN,
-+ QCA807X_MMD7_FIBER_MODE_AUTO_DETECTION,
-+ QCA807X_MMD7_FIBER_MODE_AUTO_DETECTION_EN);
-+ /* Select fiber page */
-+ ret = phy_clear_bits(phydev,
-+ QCA807X_CHIP_CONFIGURATION,
-+ QCA807X_BT_BX_REG_SEL);
-+
-+ phydev->port = PORT_FIBRE;
-+ break;
-+ default:
-+ dev_err(&phydev->mdio.dev, "Incompatible SFP module inserted\n");
-+ return -EINVAL;
-+ }
-+
-+ return ret;
-+}
-+
-+static void qca807x_sfp_remove(void *upstream)
-+{
-+ struct phy_device *phydev = upstream;
-+
-+ /* Select copper page */
-+ phy_set_bits(phydev,
-+ QCA807X_CHIP_CONFIGURATION,
-+ QCA807X_BT_BX_REG_SEL);
-+
-+ phydev->port = PORT_TP;
-+}
-+
-+static const struct sfp_upstream_ops qca807x_sfp_ops = {
-+ .attach = phy_sfp_attach,
-+ .detach = phy_sfp_detach,
-+ .module_insert = qca807x_sfp_insert,
-+ .module_remove = qca807x_sfp_remove,
-+};
-+
-+static int qca807x_probe(struct phy_device *phydev)
-+{
-+ struct device_node *node = phydev->mdio.dev.of_node;
-+ struct qca807x_shared_priv *shared_priv;
-+ struct device *dev = &phydev->mdio.dev;
-+ struct phy_package_shared *shared;
-+ struct qca807x_priv *priv;
-+ int ret;
-+
-+ ret = devm_of_phy_package_join(dev, phydev, sizeof(*shared_priv));
-+ if (ret)
-+ return ret;
-+
-+ if (phy_package_probe_once(phydev)) {
-+ ret = qca807x_phy_package_probe_once(phydev);
-+ if (ret)
-+ return ret;
-+ }
-+
-+ shared = phydev->shared;
-+ shared_priv = shared->priv;
-+
-+ /* Make sure PHY follow PHY package mode if enforced */
-+ if (shared_priv->package_mode != PHY_INTERFACE_MODE_NA &&
-+ phydev->interface != shared_priv->package_mode)
-+ return -EINVAL;
-+
-+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
-+ if (!priv)
-+ return -ENOMEM;
-+
-+ priv->dac_full_amplitude = of_property_read_bool(node, "qcom,dac-full-amplitude");
-+ priv->dac_full_bias_current = of_property_read_bool(node, "qcom,dac-full-bias-current");
-+ priv->dac_disable_bias_current_tweak = of_property_read_bool(node,
-+ "qcom,dac-disable-bias-current-tweak");
-+
-+ if (IS_ENABLED(CONFIG_GPIOLIB)) {
-+ /* Do not register a GPIO controller unless flagged for it */
-+ if (of_property_read_bool(node, "gpio-controller")) {
-+ ret = qca807x_gpio(phydev);
-+ if (ret)
-+ return ret;
-+ }
-+ }
-+
-+ /* Attach SFP bus on combo port*/
-+ if (phy_read(phydev, QCA807X_CHIP_CONFIGURATION)) {
-+ ret = phy_sfp_probe(phydev, &qca807x_sfp_ops);
-+ if (ret)
-+ return ret;
-+ linkmode_set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, phydev->supported);
-+ linkmode_set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, phydev->advertising);
-+ }
-+
-+ phydev->priv = priv;
-+
-+ return 0;
-+}
-+
-+static int qca807x_config_init(struct phy_device *phydev)
-+{
-+ struct qca807x_priv *priv = phydev->priv;
-+ u16 control_dac;
-+ int ret;
-+
-+ if (phy_package_init_once(phydev)) {
-+ ret = qca807x_phy_package_config_init_once(phydev);
-+ if (ret)
-+ return ret;
-+ }
-+
-+ control_dac = phy_read_mmd(phydev, MDIO_MMD_AN,
-+ QCA807X_MMD7_1000BASE_T_POWER_SAVE_PER_CABLE_LENGTH);
-+ control_dac &= ~QCA807X_CONTROL_DAC_MASK;
-+ if (!priv->dac_full_amplitude)
-+ control_dac |= QCA807X_CONTROL_DAC_DSP_AMPLITUDE;
-+ if (!priv->dac_full_amplitude)
-+ control_dac |= QCA807X_CONTROL_DAC_DSP_BIAS_CURRENT;
-+ if (!priv->dac_disable_bias_current_tweak)
-+ control_dac |= QCA807X_CONTROL_DAC_BIAS_CURRENT_TWEAK;
-+ return phy_write_mmd(phydev, MDIO_MMD_AN,
-+ QCA807X_MMD7_1000BASE_T_POWER_SAVE_PER_CABLE_LENGTH,
-+ control_dac);
-+}
-+
-+static struct phy_driver qca807x_drivers[] = {
-+ {
-+ PHY_ID_MATCH_EXACT(PHY_ID_QCA8072),
-+ .name = "Qualcomm QCA8072",
-+ .flags = PHY_POLL_CABLE_TEST,
-+ /* PHY_GBIT_FEATURES */
-+ .probe = qca807x_probe,
-+ .config_init = qca807x_config_init,
-+ .read_status = qca807x_read_status,
-+ .config_intr = at803x_config_intr,
-+ .handle_interrupt = at803x_handle_interrupt,
-+ .soft_reset = genphy_soft_reset,
-+ .get_tunable = at803x_get_tunable,
-+ .set_tunable = at803x_set_tunable,
-+ .resume = genphy_resume,
-+ .suspend = genphy_suspend,
-+ .cable_test_start = qca807x_cable_test_start,
-+ .cable_test_get_status = qca808x_cable_test_get_status,
-+ },
-+ {
-+ PHY_ID_MATCH_EXACT(PHY_ID_QCA8075),
-+ .name = "Qualcomm QCA8075",
-+ .flags = PHY_POLL_CABLE_TEST,
-+ /* PHY_GBIT_FEATURES */
-+ .probe = qca807x_probe,
-+ .config_init = qca807x_config_init,
-+ .read_status = qca807x_read_status,
-+ .config_intr = at803x_config_intr,
-+ .handle_interrupt = at803x_handle_interrupt,
-+ .soft_reset = genphy_soft_reset,
-+ .get_tunable = at803x_get_tunable,
-+ .set_tunable = at803x_set_tunable,
-+ .resume = genphy_resume,
-+ .suspend = genphy_suspend,
-+ .cable_test_start = qca807x_cable_test_start,
-+ .cable_test_get_status = qca808x_cable_test_get_status,
-+ },
-+};
-+module_phy_driver(qca807x_drivers);
-+
-+static struct mdio_device_id __maybe_unused qca807x_tbl[] = {
-+ { PHY_ID_MATCH_EXACT(PHY_ID_QCA8072) },
-+ { PHY_ID_MATCH_EXACT(PHY_ID_QCA8075) },
-+ { }
-+};
-+
-+MODULE_DESCRIPTION("Qualcomm QCA807x PHY driver");
-+MODULE_DEVICE_TABLE(mdio, qca807x_tbl);
-+MODULE_LICENSE("GPL");
+++ /dev/null
-From ee9d9807bee0e6af8ca2a4db6f0d1dc0e5b41f44 Mon Sep 17 00:00:00 2001
-Date: Tue, 6 Feb 2024 18:31:11 +0100
-Subject: [PATCH 08/10] net: phy: qcom: move common qca808x LED define to
- shared header
-
-The LED implementation of qca808x and qca807x is the same but qca807x
-supports also Fiber port and have different hw control bits for Fiber
-port.
-
-In preparation for qca807x introduction, move all the common define to
-shared header.
-
----
- drivers/net/phy/qcom/qca808x.c | 65 ----------------------------------
- drivers/net/phy/qcom/qcom.h | 65 ++++++++++++++++++++++++++++++++++
- 2 files changed, 65 insertions(+), 65 deletions(-)
-
---- a/drivers/net/phy/qcom/qca808x.c
-+++ b/drivers/net/phy/qcom/qca808x.c
-@@ -62,29 +62,6 @@
- #define QCA808X_DBG_AN_TEST 0xb
- #define QCA808X_HIBERNATION_EN BIT(15)
-
--#define QCA808X_MMD7_LED_GLOBAL 0x8073
--#define QCA808X_LED_BLINK_1 GENMASK(11, 6)
--#define QCA808X_LED_BLINK_2 GENMASK(5, 0)
--/* Values are the same for both BLINK_1 and BLINK_2 */
--#define QCA808X_LED_BLINK_FREQ_MASK GENMASK(5, 3)
--#define QCA808X_LED_BLINK_FREQ_2HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x0)
--#define QCA808X_LED_BLINK_FREQ_4HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x1)
--#define QCA808X_LED_BLINK_FREQ_8HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x2)
--#define QCA808X_LED_BLINK_FREQ_16HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x3)
--#define QCA808X_LED_BLINK_FREQ_32HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x4)
--#define QCA808X_LED_BLINK_FREQ_64HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x5)
--#define QCA808X_LED_BLINK_FREQ_128HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x6)
--#define QCA808X_LED_BLINK_FREQ_256HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x7)
--#define QCA808X_LED_BLINK_DUTY_MASK GENMASK(2, 0)
--#define QCA808X_LED_BLINK_DUTY_50_50 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x0)
--#define QCA808X_LED_BLINK_DUTY_75_25 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x1)
--#define QCA808X_LED_BLINK_DUTY_25_75 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x2)
--#define QCA808X_LED_BLINK_DUTY_33_67 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x3)
--#define QCA808X_LED_BLINK_DUTY_67_33 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x4)
--#define QCA808X_LED_BLINK_DUTY_17_83 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x5)
--#define QCA808X_LED_BLINK_DUTY_83_17 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x6)
--#define QCA808X_LED_BLINK_DUTY_8_92 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x7)
--
- #define QCA808X_MMD7_LED2_CTRL 0x8074
- #define QCA808X_MMD7_LED2_FORCE_CTRL 0x8075
- #define QCA808X_MMD7_LED1_CTRL 0x8076
-@@ -92,51 +69,9 @@
- #define QCA808X_MMD7_LED0_CTRL 0x8078
- #define QCA808X_MMD7_LED_CTRL(x) (0x8078 - ((x) * 2))
-
--/* LED hw control pattern is the same for every LED */
--#define QCA808X_LED_PATTERN_MASK GENMASK(15, 0)
--#define QCA808X_LED_SPEED2500_ON BIT(15)
--#define QCA808X_LED_SPEED2500_BLINK BIT(14)
--/* Follow blink trigger even if duplex or speed condition doesn't match */
--#define QCA808X_LED_BLINK_CHECK_BYPASS BIT(13)
--#define QCA808X_LED_FULL_DUPLEX_ON BIT(12)
--#define QCA808X_LED_HALF_DUPLEX_ON BIT(11)
--#define QCA808X_LED_TX_BLINK BIT(10)
--#define QCA808X_LED_RX_BLINK BIT(9)
--#define QCA808X_LED_TX_ON_10MS BIT(8)
--#define QCA808X_LED_RX_ON_10MS BIT(7)
--#define QCA808X_LED_SPEED1000_ON BIT(6)
--#define QCA808X_LED_SPEED100_ON BIT(5)
--#define QCA808X_LED_SPEED10_ON BIT(4)
--#define QCA808X_LED_COLLISION_BLINK BIT(3)
--#define QCA808X_LED_SPEED1000_BLINK BIT(2)
--#define QCA808X_LED_SPEED100_BLINK BIT(1)
--#define QCA808X_LED_SPEED10_BLINK BIT(0)
--
- #define QCA808X_MMD7_LED0_FORCE_CTRL 0x8079
- #define QCA808X_MMD7_LED_FORCE_CTRL(x) (0x8079 - ((x) * 2))
-
--/* LED force ctrl is the same for every LED
-- * No documentation exist for this, not even internal one
-- * with NDA as QCOM gives only info about configuring
-- * hw control pattern rules and doesn't indicate any way
-- * to force the LED to specific mode.
-- * These define comes from reverse and testing and maybe
-- * lack of some info or some info are not entirely correct.
-- * For the basic LED control and hw control these finding
-- * are enough to support LED control in all the required APIs.
-- *
-- * On doing some comparison with implementation with qca807x,
-- * it was found that it's 1:1 equal to it and confirms all the
-- * reverse done. It was also found further specification with the
-- * force mode and the blink modes.
-- */
--#define QCA808X_LED_FORCE_EN BIT(15)
--#define QCA808X_LED_FORCE_MODE_MASK GENMASK(14, 13)
--#define QCA808X_LED_FORCE_BLINK_1 FIELD_PREP(QCA808X_LED_FORCE_MODE_MASK, 0x3)
--#define QCA808X_LED_FORCE_BLINK_2 FIELD_PREP(QCA808X_LED_FORCE_MODE_MASK, 0x2)
--#define QCA808X_LED_FORCE_ON FIELD_PREP(QCA808X_LED_FORCE_MODE_MASK, 0x1)
--#define QCA808X_LED_FORCE_OFF FIELD_PREP(QCA808X_LED_FORCE_MODE_MASK, 0x0)
--
- #define QCA808X_MMD7_LED_POLARITY_CTRL 0x901a
- /* QSDK sets by default 0x46 to this reg that sets BIT 6 for
- * LED to active high. It's not clear what BIT 3 and BIT 4 does.
---- a/drivers/net/phy/qcom/qcom.h
-+++ b/drivers/net/phy/qcom/qcom.h
-@@ -103,6 +103,71 @@
- /* Added for reference of existence but should be handled by wait_for_completion already */
- #define QCA808X_CDT_STATUS_STAT_BUSY (BIT(1) | BIT(3))
-
-+#define QCA808X_MMD7_LED_GLOBAL 0x8073
-+#define QCA808X_LED_BLINK_1 GENMASK(11, 6)
-+#define QCA808X_LED_BLINK_2 GENMASK(5, 0)
-+/* Values are the same for both BLINK_1 and BLINK_2 */
-+#define QCA808X_LED_BLINK_FREQ_MASK GENMASK(5, 3)
-+#define QCA808X_LED_BLINK_FREQ_2HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x0)
-+#define QCA808X_LED_BLINK_FREQ_4HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x1)
-+#define QCA808X_LED_BLINK_FREQ_8HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x2)
-+#define QCA808X_LED_BLINK_FREQ_16HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x3)
-+#define QCA808X_LED_BLINK_FREQ_32HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x4)
-+#define QCA808X_LED_BLINK_FREQ_64HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x5)
-+#define QCA808X_LED_BLINK_FREQ_128HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x6)
-+#define QCA808X_LED_BLINK_FREQ_256HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x7)
-+#define QCA808X_LED_BLINK_DUTY_MASK GENMASK(2, 0)
-+#define QCA808X_LED_BLINK_DUTY_50_50 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x0)
-+#define QCA808X_LED_BLINK_DUTY_75_25 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x1)
-+#define QCA808X_LED_BLINK_DUTY_25_75 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x2)
-+#define QCA808X_LED_BLINK_DUTY_33_67 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x3)
-+#define QCA808X_LED_BLINK_DUTY_67_33 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x4)
-+#define QCA808X_LED_BLINK_DUTY_17_83 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x5)
-+#define QCA808X_LED_BLINK_DUTY_83_17 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x6)
-+#define QCA808X_LED_BLINK_DUTY_8_92 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x7)
-+
-+/* LED hw control pattern is the same for every LED */
-+#define QCA808X_LED_PATTERN_MASK GENMASK(15, 0)
-+#define QCA808X_LED_SPEED2500_ON BIT(15)
-+#define QCA808X_LED_SPEED2500_BLINK BIT(14)
-+/* Follow blink trigger even if duplex or speed condition doesn't match */
-+#define QCA808X_LED_BLINK_CHECK_BYPASS BIT(13)
-+#define QCA808X_LED_FULL_DUPLEX_ON BIT(12)
-+#define QCA808X_LED_HALF_DUPLEX_ON BIT(11)
-+#define QCA808X_LED_TX_BLINK BIT(10)
-+#define QCA808X_LED_RX_BLINK BIT(9)
-+#define QCA808X_LED_TX_ON_10MS BIT(8)
-+#define QCA808X_LED_RX_ON_10MS BIT(7)
-+#define QCA808X_LED_SPEED1000_ON BIT(6)
-+#define QCA808X_LED_SPEED100_ON BIT(5)
-+#define QCA808X_LED_SPEED10_ON BIT(4)
-+#define QCA808X_LED_COLLISION_BLINK BIT(3)
-+#define QCA808X_LED_SPEED1000_BLINK BIT(2)
-+#define QCA808X_LED_SPEED100_BLINK BIT(1)
-+#define QCA808X_LED_SPEED10_BLINK BIT(0)
-+
-+/* LED force ctrl is the same for every LED
-+ * No documentation exist for this, not even internal one
-+ * with NDA as QCOM gives only info about configuring
-+ * hw control pattern rules and doesn't indicate any way
-+ * to force the LED to specific mode.
-+ * These define comes from reverse and testing and maybe
-+ * lack of some info or some info are not entirely correct.
-+ * For the basic LED control and hw control these finding
-+ * are enough to support LED control in all the required APIs.
-+ *
-+ * On doing some comparison with implementation with qca807x,
-+ * it was found that it's 1:1 equal to it and confirms all the
-+ * reverse done. It was also found further specification with the
-+ * force mode and the blink modes.
-+ */
-+#define QCA808X_LED_FORCE_EN BIT(15)
-+#define QCA808X_LED_FORCE_MODE_MASK GENMASK(14, 13)
-+#define QCA808X_LED_FORCE_BLINK_1 FIELD_PREP(QCA808X_LED_FORCE_MODE_MASK, 0x3)
-+#define QCA808X_LED_FORCE_BLINK_2 FIELD_PREP(QCA808X_LED_FORCE_MODE_MASK, 0x2)
-+#define QCA808X_LED_FORCE_ON FIELD_PREP(QCA808X_LED_FORCE_MODE_MASK, 0x1)
-+#define QCA808X_LED_FORCE_OFF FIELD_PREP(QCA808X_LED_FORCE_MODE_MASK, 0x0)
-+
- #define AT803X_LOC_MAC_ADDR_0_15_OFFSET 0x804C
- #define AT803X_LOC_MAC_ADDR_16_31_OFFSET 0x804B
- #define AT803X_LOC_MAC_ADDR_32_47_OFFSET 0x804A
+++ /dev/null
-From 47b930d0dd437af927145dba50a2e2ea1ba97c67 Mon Sep 17 00:00:00 2001
-Date: Tue, 6 Feb 2024 18:31:12 +0100
-Subject: [PATCH 09/10] net: phy: qcom: generalize some qca808x LED functions
-
-Generalize some qca808x LED functions in preparation for qca807x LED
-support.
-
-The LED implementation of qca808x and qca807x is the same but qca807x
-supports also Fiber port and have different hw control bits for Fiber
-port. To limit code duplication introduce micro functions that takes reg
-instead of LED index to tweak all the supported LED modes.
-
----
- drivers/net/phy/qcom/qca808x.c | 38 +++-----------------
- drivers/net/phy/qcom/qcom-phy-lib.c | 54 +++++++++++++++++++++++++++++
- drivers/net/phy/qcom/qcom.h | 7 ++++
- 3 files changed, 65 insertions(+), 34 deletions(-)
-
---- a/drivers/net/phy/qcom/qca808x.c
-+++ b/drivers/net/phy/qcom/qca808x.c
-@@ -437,9 +437,7 @@ static int qca808x_led_hw_control_enable
- return -EINVAL;
-
- reg = QCA808X_MMD7_LED_FORCE_CTRL(index);
--
-- return phy_clear_bits_mmd(phydev, MDIO_MMD_AN, reg,
-- QCA808X_LED_FORCE_EN);
-+ return qca808x_led_reg_hw_control_enable(phydev, reg);
- }
-
- static int qca808x_led_hw_is_supported(struct phy_device *phydev, u8 index,
-@@ -480,16 +478,12 @@ static int qca808x_led_hw_control_set(st
- static bool qca808x_led_hw_control_status(struct phy_device *phydev, u8 index)
- {
- u16 reg;
-- int val;
-
- if (index > 2)
- return false;
-
- reg = QCA808X_MMD7_LED_FORCE_CTRL(index);
--
-- val = phy_read_mmd(phydev, MDIO_MMD_AN, reg);
--
-- return !(val & QCA808X_LED_FORCE_EN);
-+ return qca808x_led_reg_hw_control_status(phydev, reg);
- }
-
- static int qca808x_led_hw_control_get(struct phy_device *phydev, u8 index,
-@@ -557,44 +551,20 @@ static int qca808x_led_brightness_set(st
- }
-
- reg = QCA808X_MMD7_LED_FORCE_CTRL(index);
--
-- return phy_modify_mmd(phydev, MDIO_MMD_AN, reg,
-- QCA808X_LED_FORCE_EN | QCA808X_LED_FORCE_MODE_MASK,
-- QCA808X_LED_FORCE_EN | (value ? QCA808X_LED_FORCE_ON :
-- QCA808X_LED_FORCE_OFF));
-+ return qca808x_led_reg_brightness_set(phydev, reg, value);
- }
-
- static int qca808x_led_blink_set(struct phy_device *phydev, u8 index,
- unsigned long *delay_on,
- unsigned long *delay_off)
- {
-- int ret;
- u16 reg;
-
- if (index > 2)
- return -EINVAL;
-
- reg = QCA808X_MMD7_LED_FORCE_CTRL(index);
--
-- /* Set blink to 50% off, 50% on at 4Hz by default */
-- ret = phy_modify_mmd(phydev, MDIO_MMD_AN, QCA808X_MMD7_LED_GLOBAL,
-- QCA808X_LED_BLINK_FREQ_MASK | QCA808X_LED_BLINK_DUTY_MASK,
-- QCA808X_LED_BLINK_FREQ_4HZ | QCA808X_LED_BLINK_DUTY_50_50);
-- if (ret)
-- return ret;
--
-- /* We use BLINK_1 for normal blinking */
-- ret = phy_modify_mmd(phydev, MDIO_MMD_AN, reg,
-- QCA808X_LED_FORCE_EN | QCA808X_LED_FORCE_MODE_MASK,
-- QCA808X_LED_FORCE_EN | QCA808X_LED_FORCE_BLINK_1);
-- if (ret)
-- return ret;
--
-- /* We set blink to 4Hz, aka 250ms */
-- *delay_on = 250 / 2;
-- *delay_off = 250 / 2;
--
-- return 0;
-+ return qca808x_led_reg_blink_set(phydev, reg, delay_on, delay_off);
- }
-
- static int qca808x_led_polarity_set(struct phy_device *phydev, int index,
---- a/drivers/net/phy/qcom/qcom-phy-lib.c
-+++ b/drivers/net/phy/qcom/qcom-phy-lib.c
-@@ -620,3 +620,57 @@ int qca808x_cable_test_get_status(struct
- return 0;
- }
- EXPORT_SYMBOL_GPL(qca808x_cable_test_get_status);
-+
-+int qca808x_led_reg_hw_control_enable(struct phy_device *phydev, u16 reg)
-+{
-+ return phy_clear_bits_mmd(phydev, MDIO_MMD_AN, reg,
-+ QCA808X_LED_FORCE_EN);
-+}
-+EXPORT_SYMBOL_GPL(qca808x_led_reg_hw_control_enable);
-+
-+bool qca808x_led_reg_hw_control_status(struct phy_device *phydev, u16 reg)
-+{
-+ int val;
-+
-+ val = phy_read_mmd(phydev, MDIO_MMD_AN, reg);
-+ return !(val & QCA808X_LED_FORCE_EN);
-+}
-+EXPORT_SYMBOL_GPL(qca808x_led_reg_hw_control_status);
-+
-+int qca808x_led_reg_brightness_set(struct phy_device *phydev,
-+ u16 reg, enum led_brightness value)
-+{
-+ return phy_modify_mmd(phydev, MDIO_MMD_AN, reg,
-+ QCA808X_LED_FORCE_EN | QCA808X_LED_FORCE_MODE_MASK,
-+ QCA808X_LED_FORCE_EN | (value ? QCA808X_LED_FORCE_ON :
-+ QCA808X_LED_FORCE_OFF));
-+}
-+EXPORT_SYMBOL_GPL(qca808x_led_reg_brightness_set);
-+
-+int qca808x_led_reg_blink_set(struct phy_device *phydev, u16 reg,
-+ unsigned long *delay_on,
-+ unsigned long *delay_off)
-+{
-+ int ret;
-+
-+ /* Set blink to 50% off, 50% on at 4Hz by default */
-+ ret = phy_modify_mmd(phydev, MDIO_MMD_AN, QCA808X_MMD7_LED_GLOBAL,
-+ QCA808X_LED_BLINK_FREQ_MASK | QCA808X_LED_BLINK_DUTY_MASK,
-+ QCA808X_LED_BLINK_FREQ_4HZ | QCA808X_LED_BLINK_DUTY_50_50);
-+ if (ret)
-+ return ret;
-+
-+ /* We use BLINK_1 for normal blinking */
-+ ret = phy_modify_mmd(phydev, MDIO_MMD_AN, reg,
-+ QCA808X_LED_FORCE_EN | QCA808X_LED_FORCE_MODE_MASK,
-+ QCA808X_LED_FORCE_EN | QCA808X_LED_FORCE_BLINK_1);
-+ if (ret)
-+ return ret;
-+
-+ /* We set blink to 4Hz, aka 250ms */
-+ *delay_on = 250 / 2;
-+ *delay_off = 250 / 2;
-+
-+ return 0;
-+}
-+EXPORT_SYMBOL_GPL(qca808x_led_reg_blink_set);
---- a/drivers/net/phy/qcom/qcom.h
-+++ b/drivers/net/phy/qcom/qcom.h
-@@ -234,3 +234,10 @@ int at803x_cdt_start(struct phy_device *
- int at803x_cdt_wait_for_completion(struct phy_device *phydev,
- u32 cdt_en);
- int qca808x_cable_test_get_status(struct phy_device *phydev, bool *finished);
-+int qca808x_led_reg_hw_control_enable(struct phy_device *phydev, u16 reg);
-+bool qca808x_led_reg_hw_control_status(struct phy_device *phydev, u16 reg);
-+int qca808x_led_reg_brightness_set(struct phy_device *phydev,
-+ u16 reg, enum led_brightness value);
-+int qca808x_led_reg_blink_set(struct phy_device *phydev, u16 reg,
-+ unsigned long *delay_on,
-+ unsigned long *delay_off);
+++ /dev/null
-From f508a226b517a6a8afd78a317de46bc83e3e3d51 Mon Sep 17 00:00:00 2001
-Date: Tue, 6 Feb 2024 18:31:13 +0100
-Subject: [PATCH 10/10] net: phy: qca807x: add support for configurable LED
-
-QCA8072/5 have up to 2 LEDs attached for PHY.
-
-LEDs can be configured to be ON/hw blink or be set to HW control.
-
-Hw blink mode is set to blink at 4Hz or 250ms.
-
-PHY can support both copper (TP) or fiber (FIBRE) kind and supports
-different HW control modes based on the port type.
-
-HW control modes supported for netdev trigger for copper ports are:
-- LINK_10
-- LINK_100
-- LINK_1000
-- TX
-- RX
-- FULL_DUPLEX
-- HALF_DUPLEX
-
-HW control modes supported for netdev trigger for fiber ports are:
-- LINK_100
-- LINK_1000
-- TX
-- RX
-- FULL_DUPLEX
-- HALF_DUPLEX
-
-LED support conflicts with GPIO controller feature and must be disabled
-if gpio-controller is used for the PHY.
-
----
- drivers/net/phy/qcom/qca807x.c | 256 ++++++++++++++++++++++++++++++++-
- 1 file changed, 254 insertions(+), 2 deletions(-)
-
---- a/drivers/net/phy/qcom/qca807x.c
-+++ b/drivers/net/phy/qcom/qca807x.c
-@@ -57,8 +57,18 @@
- #define QCA807X_MMD7_LED_CTRL(x) (0x8074 + ((x) * 2))
- #define QCA807X_MMD7_LED_FORCE_CTRL(x) (0x8075 + ((x) * 2))
-
--#define QCA807X_GPIO_FORCE_EN BIT(15)
--#define QCA807X_GPIO_FORCE_MODE_MASK GENMASK(14, 13)
-+/* LED hw control pattern for fiber port */
-+#define QCA807X_LED_FIBER_PATTERN_MASK GENMASK(11, 1)
-+#define QCA807X_LED_FIBER_TXACT_BLK_EN BIT(10)
-+#define QCA807X_LED_FIBER_RXACT_BLK_EN BIT(9)
-+#define QCA807X_LED_FIBER_FDX_ON_EN BIT(6)
-+#define QCA807X_LED_FIBER_HDX_ON_EN BIT(5)
-+#define QCA807X_LED_FIBER_1000BX_ON_EN BIT(2)
-+#define QCA807X_LED_FIBER_100FX_ON_EN BIT(1)
-+
-+/* Some device repurpose the LED as GPIO out */
-+#define QCA807X_GPIO_FORCE_EN QCA808X_LED_FORCE_EN
-+#define QCA807X_GPIO_FORCE_MODE_MASK QCA808X_LED_FORCE_MODE_MASK
-
- #define QCA807X_FUNCTION_CONTROL 0x10
- #define QCA807X_FC_MDI_CROSSOVER_MODE_MASK GENMASK(6, 5)
-@@ -121,6 +131,233 @@ static int qca807x_cable_test_start(stru
- return 0;
- }
-
-+static int qca807x_led_parse_netdev(struct phy_device *phydev, unsigned long rules,
-+ u16 *offload_trigger)
-+{
-+ /* Parsing specific to netdev trigger */
-+ switch (phydev->port) {
-+ case PORT_TP:
-+ if (test_bit(TRIGGER_NETDEV_TX, &rules))
-+ *offload_trigger |= QCA808X_LED_TX_BLINK;
-+ if (test_bit(TRIGGER_NETDEV_RX, &rules))
-+ *offload_trigger |= QCA808X_LED_RX_BLINK;
-+ if (test_bit(TRIGGER_NETDEV_LINK_10, &rules))
-+ *offload_trigger |= QCA808X_LED_SPEED10_ON;
-+ if (test_bit(TRIGGER_NETDEV_LINK_100, &rules))
-+ *offload_trigger |= QCA808X_LED_SPEED100_ON;
-+ if (test_bit(TRIGGER_NETDEV_LINK_1000, &rules))
-+ *offload_trigger |= QCA808X_LED_SPEED1000_ON;
-+ if (test_bit(TRIGGER_NETDEV_HALF_DUPLEX, &rules))
-+ *offload_trigger |= QCA808X_LED_HALF_DUPLEX_ON;
-+ if (test_bit(TRIGGER_NETDEV_FULL_DUPLEX, &rules))
-+ *offload_trigger |= QCA808X_LED_FULL_DUPLEX_ON;
-+ break;
-+ case PORT_FIBRE:
-+ if (test_bit(TRIGGER_NETDEV_TX, &rules))
-+ *offload_trigger |= QCA807X_LED_FIBER_TXACT_BLK_EN;
-+ if (test_bit(TRIGGER_NETDEV_RX, &rules))
-+ *offload_trigger |= QCA807X_LED_FIBER_RXACT_BLK_EN;
-+ if (test_bit(TRIGGER_NETDEV_LINK_100, &rules))
-+ *offload_trigger |= QCA807X_LED_FIBER_100FX_ON_EN;
-+ if (test_bit(TRIGGER_NETDEV_LINK_1000, &rules))
-+ *offload_trigger |= QCA807X_LED_FIBER_1000BX_ON_EN;
-+ if (test_bit(TRIGGER_NETDEV_HALF_DUPLEX, &rules))
-+ *offload_trigger |= QCA807X_LED_FIBER_HDX_ON_EN;
-+ if (test_bit(TRIGGER_NETDEV_FULL_DUPLEX, &rules))
-+ *offload_trigger |= QCA807X_LED_FIBER_FDX_ON_EN;
-+ break;
-+ default:
-+ return -EOPNOTSUPP;
-+ }
-+
-+ if (rules && !*offload_trigger)
-+ return -EOPNOTSUPP;
-+
-+ return 0;
-+}
-+
-+static int qca807x_led_hw_control_enable(struct phy_device *phydev, u8 index)
-+{
-+ u16 reg;
-+
-+ if (index > 1)
-+ return -EINVAL;
-+
-+ reg = QCA807X_MMD7_LED_FORCE_CTRL(index);
-+ return qca808x_led_reg_hw_control_enable(phydev, reg);
-+}
-+
-+static int qca807x_led_hw_is_supported(struct phy_device *phydev, u8 index,
-+ unsigned long rules)
-+{
-+ u16 offload_trigger = 0;
-+
-+ if (index > 1)
-+ return -EINVAL;
-+
-+ return qca807x_led_parse_netdev(phydev, rules, &offload_trigger);
-+}
-+
-+static int qca807x_led_hw_control_set(struct phy_device *phydev, u8 index,
-+ unsigned long rules)
-+{
-+ u16 reg, mask, offload_trigger = 0;
-+ int ret;
-+
-+ if (index > 1)
-+ return -EINVAL;
-+
-+ ret = qca807x_led_parse_netdev(phydev, rules, &offload_trigger);
-+ if (ret)
-+ return ret;
-+
-+ ret = qca807x_led_hw_control_enable(phydev, index);
-+ if (ret)
-+ return ret;
-+
-+ switch (phydev->port) {
-+ case PORT_TP:
-+ reg = QCA807X_MMD7_LED_CTRL(index);
-+ mask = QCA808X_LED_PATTERN_MASK;
-+ break;
-+ case PORT_FIBRE:
-+ /* HW control pattern bits are in LED FORCE reg */
-+ reg = QCA807X_MMD7_LED_FORCE_CTRL(index);
-+ mask = QCA807X_LED_FIBER_PATTERN_MASK;
-+ break;
-+ default:
-+ return -EINVAL;
-+ }
-+
-+ return phy_modify_mmd(phydev, MDIO_MMD_AN, reg, mask,
-+ offload_trigger);
-+}
-+
-+static bool qca807x_led_hw_control_status(struct phy_device *phydev, u8 index)
-+{
-+ u16 reg;
-+
-+ if (index > 1)
-+ return false;
-+
-+ reg = QCA807X_MMD7_LED_FORCE_CTRL(index);
-+ return qca808x_led_reg_hw_control_status(phydev, reg);
-+}
-+
-+static int qca807x_led_hw_control_get(struct phy_device *phydev, u8 index,
-+ unsigned long *rules)
-+{
-+ u16 reg;
-+ int val;
-+
-+ if (index > 1)
-+ return -EINVAL;
-+
-+ /* Check if we have hw control enabled */
-+ if (qca807x_led_hw_control_status(phydev, index))
-+ return -EINVAL;
-+
-+ /* Parsing specific to netdev trigger */
-+ switch (phydev->port) {
-+ case PORT_TP:
-+ reg = QCA807X_MMD7_LED_CTRL(index);
-+ val = phy_read_mmd(phydev, MDIO_MMD_AN, reg);
-+ if (val & QCA808X_LED_TX_BLINK)
-+ set_bit(TRIGGER_NETDEV_TX, rules);
-+ if (val & QCA808X_LED_RX_BLINK)
-+ set_bit(TRIGGER_NETDEV_RX, rules);
-+ if (val & QCA808X_LED_SPEED10_ON)
-+ set_bit(TRIGGER_NETDEV_LINK_10, rules);
-+ if (val & QCA808X_LED_SPEED100_ON)
-+ set_bit(TRIGGER_NETDEV_LINK_100, rules);
-+ if (val & QCA808X_LED_SPEED1000_ON)
-+ set_bit(TRIGGER_NETDEV_LINK_1000, rules);
-+ if (val & QCA808X_LED_HALF_DUPLEX_ON)
-+ set_bit(TRIGGER_NETDEV_HALF_DUPLEX, rules);
-+ if (val & QCA808X_LED_FULL_DUPLEX_ON)
-+ set_bit(TRIGGER_NETDEV_FULL_DUPLEX, rules);
-+ break;
-+ case PORT_FIBRE:
-+ /* HW control pattern bits are in LED FORCE reg */
-+ reg = QCA807X_MMD7_LED_FORCE_CTRL(index);
-+ val = phy_read_mmd(phydev, MDIO_MMD_AN, reg);
-+ if (val & QCA807X_LED_FIBER_TXACT_BLK_EN)
-+ set_bit(TRIGGER_NETDEV_TX, rules);
-+ if (val & QCA807X_LED_FIBER_RXACT_BLK_EN)
-+ set_bit(TRIGGER_NETDEV_RX, rules);
-+ if (val & QCA807X_LED_FIBER_100FX_ON_EN)
-+ set_bit(TRIGGER_NETDEV_LINK_100, rules);
-+ if (val & QCA807X_LED_FIBER_1000BX_ON_EN)
-+ set_bit(TRIGGER_NETDEV_LINK_1000, rules);
-+ if (val & QCA807X_LED_FIBER_HDX_ON_EN)
-+ set_bit(TRIGGER_NETDEV_HALF_DUPLEX, rules);
-+ if (val & QCA807X_LED_FIBER_FDX_ON_EN)
-+ set_bit(TRIGGER_NETDEV_FULL_DUPLEX, rules);
-+ break;
-+ default:
-+ return -EINVAL;
-+ }
-+
-+ return 0;
-+}
-+
-+static int qca807x_led_hw_control_reset(struct phy_device *phydev, u8 index)
-+{
-+ u16 reg, mask;
-+
-+ if (index > 1)
-+ return -EINVAL;
-+
-+ switch (phydev->port) {
-+ case PORT_TP:
-+ reg = QCA807X_MMD7_LED_CTRL(index);
-+ mask = QCA808X_LED_PATTERN_MASK;
-+ break;
-+ case PORT_FIBRE:
-+ /* HW control pattern bits are in LED FORCE reg */
-+ reg = QCA807X_MMD7_LED_FORCE_CTRL(index);
-+ mask = QCA807X_LED_FIBER_PATTERN_MASK;
-+ break;
-+ default:
-+ return -EINVAL;
-+ }
-+
-+ return phy_clear_bits_mmd(phydev, MDIO_MMD_AN, reg, mask);
-+}
-+
-+static int qca807x_led_brightness_set(struct phy_device *phydev,
-+ u8 index, enum led_brightness value)
-+{
-+ u16 reg;
-+ int ret;
-+
-+ if (index > 1)
-+ return -EINVAL;
-+
-+ /* If we are setting off the LED reset any hw control rule */
-+ if (!value) {
-+ ret = qca807x_led_hw_control_reset(phydev, index);
-+ if (ret)
-+ return ret;
-+ }
-+
-+ reg = QCA807X_MMD7_LED_FORCE_CTRL(index);
-+ return qca808x_led_reg_brightness_set(phydev, reg, value);
-+}
-+
-+static int qca807x_led_blink_set(struct phy_device *phydev, u8 index,
-+ unsigned long *delay_on,
-+ unsigned long *delay_off)
-+{
-+ u16 reg;
-+
-+ if (index > 1)
-+ return -EINVAL;
-+
-+ reg = QCA807X_MMD7_LED_FORCE_CTRL(index);
-+ return qca808x_led_reg_blink_set(phydev, reg, delay_on, delay_off);
-+}
-+
- #ifdef CONFIG_GPIOLIB
- static int qca807x_gpio_get_direction(struct gpio_chip *gc, unsigned int offset)
- {
-@@ -496,6 +733,16 @@ static int qca807x_probe(struct phy_devi
- "qcom,dac-disable-bias-current-tweak");
-
- if (IS_ENABLED(CONFIG_GPIOLIB)) {
-+ /* Make sure we don't have mixed leds node and gpio-controller
-+ * to prevent registering leds and having gpio-controller usage
-+ * conflicting with them.
-+ */
-+ if (of_find_property(node, "leds", NULL) &&
-+ of_find_property(node, "gpio-controller", NULL)) {
-+ phydev_err(phydev, "Invalid property detected. LEDs and gpio-controller are mutually exclusive.");
-+ return -EINVAL;
-+ }
-+
- /* Do not register a GPIO controller unless flagged for it */
- if (of_property_read_bool(node, "gpio-controller")) {
- ret = qca807x_gpio(phydev);
-@@ -580,6 +827,11 @@ static struct phy_driver qca807x_drivers
- .suspend = genphy_suspend,
- .cable_test_start = qca807x_cable_test_start,
- .cable_test_get_status = qca808x_cable_test_get_status,
-+ .led_brightness_set = qca807x_led_brightness_set,
-+ .led_blink_set = qca807x_led_blink_set,
-+ .led_hw_is_supported = qca807x_led_hw_is_supported,
-+ .led_hw_control_set = qca807x_led_hw_control_set,
-+ .led_hw_control_get = qca807x_led_hw_control_get,
- },
- };
- module_phy_driver(qca807x_drivers);
+++ /dev/null
-From 3be0d950b62852a693182cb678948f481de02825 Mon Sep 17 00:00:00 2001
-Date: Mon, 12 Feb 2024 12:49:34 +0100
-Subject: [PATCH] net: phy: qca807x: move interface mode check to
- .config_init_once
-
-Currently, we are checking whether the PHY package mode matches the
-individual PHY interface modes at PHY package probe time, but at that time
-we only know the PHY package mode and not the individual PHY interface
-modes as of_get_phy_mode() that populates it will only get called once the
-netdev to which PHY-s are attached to is being probed and thus this check
-will always fail and return -EINVAL.
-
-So, lets move this check to .config_init_once as at that point individual
-PHY interface modes should be populated.
-
-Fixes: d1cb613efbd3 ("net: phy: qcom: add support for QCA807x PHY Family")
----
- drivers/net/phy/qcom/qca807x.c | 10 +++++-----
- 1 file changed, 5 insertions(+), 5 deletions(-)
-
---- a/drivers/net/phy/qcom/qca807x.c
-+++ b/drivers/net/phy/qcom/qca807x.c
-@@ -562,6 +562,11 @@ static int qca807x_phy_package_config_in
- struct qca807x_shared_priv *priv = shared->priv;
- int val, ret;
-
-+ /* Make sure PHY follow PHY package mode if enforced */
-+ if (priv->package_mode != PHY_INTERFACE_MODE_NA &&
-+ phydev->interface != priv->package_mode)
-+ return -EINVAL;
-+
- phy_lock_mdio_bus(phydev);
-
- /* Set correct PHY package mode */
-@@ -718,11 +723,6 @@ static int qca807x_probe(struct phy_devi
- shared = phydev->shared;
- shared_priv = shared->priv;
-
-- /* Make sure PHY follow PHY package mode if enforced */
-- if (shared_priv->package_mode != PHY_INTERFACE_MODE_NA &&
-- phydev->interface != shared_priv->package_mode)
-- return -EINVAL;
--
- priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
- if (!priv)
- return -ENOMEM;
+++ /dev/null
-From 6a4aee277740d04ac0fd54cfa17cc28261932ddc Mon Sep 17 00:00:00 2001
-Date: Mon, 25 Mar 2024 20:06:19 +0100
-Subject: [PATCH] net: phy: qcom: at803x: fix kernel panic with at8031_probe
-
-On reworking and splitting the at803x driver, in splitting function of
-at803x PHYs it was added a NULL dereference bug where priv is referenced
-before it's actually allocated and then is tried to write to for the
-is_1000basex and is_fiber variables in the case of at8031, writing on
-the wrong address.
-
-Fix this by correctly setting priv local variable only after
-at803x_probe is called and actually allocates priv in the phydev struct.
-
-Fixes: 25d2ba94005f ("net: phy: at803x: move specific at8031 probe mode check to dedicated probe")
----
- drivers/net/phy/qcom/at803x.c | 4 +++-
- 1 file changed, 3 insertions(+), 1 deletion(-)
-
---- a/drivers/net/phy/qcom/at803x.c
-+++ b/drivers/net/phy/qcom/at803x.c
-@@ -797,7 +797,7 @@ static int at8031_parse_dt(struct phy_de
-
- static int at8031_probe(struct phy_device *phydev)
- {
-- struct at803x_priv *priv = phydev->priv;
-+ struct at803x_priv *priv;
- int mode_cfg;
- int ccr;
- int ret;
-@@ -806,6 +806,8 @@ static int at8031_probe(struct phy_devic
- if (ret)
- return ret;
-
-+ priv = phydev->priv;
-+
- /* Only supported on AR8031/AR8033, the AR8030/AR8035 use strapping
- * options.
- */
+++ /dev/null
-From bdce82e960d1205d118662f575cec39379984e34 Mon Sep 17 00:00:00 2001
-Date: Wed, 31 Jan 2024 03:26:04 +0100
-Subject: [PATCH] net: mdio: ipq4019: add support for clock-frequency property
-
-The IPQ4019 MDIO internally divide the clock feed by AHB based on the
-MDIO_MODE reg. On reset or power up, the default value for the
-divider is 0xff that reflect the divider set to /256.
-
-This makes the MDC run at a very low rate, that is, considering AHB is
-always fixed to 100Mhz, a value of 390KHz.
-
-This hasn't have been a problem as MDIO wasn't used for time sensitive
-operation, it is now that on IPQ807x is usually mounted with PHY that
-requires MDIO to load their firmware (example Aquantia PHY).
-
-To handle this problem and permit to set the correct designed MDC
-frequency for the SoC add support for the standard "clock-frequency"
-property for the MDIO node.
-
-The divider supports value from /1 to /256 and the common value are to
-set it to /16 to reflect 6.25Mhz or to /8 on newer platform to reflect
-12.5Mhz.
-
-To scan if the requested rate is supported by the divider, loop with
-each supported divider and stop when the requested rate match the final
-rate with the current divider. An error is returned if the rate doesn't
-match any value.
-
-On MDIO reset, the divider is restored to the requested value to prevent
-any kind of downclocking caused by the divider reverting to a default
-value.
-
-To follow 802.3 spec of 2.5MHz of default value, if divider is set at
-/256 and "clock-frequency" is not set in DT, assume nobody set the
-divider and try to find the closest MDC rate to 2.5MHz. (in the case of
-AHB set to 100MHz, it's 1.5625MHz)
-
-While at is also document other bits of the MDIO_MODE reg to have a
-clear idea of what is actually applied there.
-
-Documentation of some BITs is skipped as they are marked as reserved and
-their usage is not clear (RES 11:9 GENPHY 16:13 RES1 19:17)
-
----
- drivers/net/mdio/mdio-ipq4019.c | 109 ++++++++++++++++++++++++++++++--
- 1 file changed, 103 insertions(+), 6 deletions(-)
-
---- a/drivers/net/mdio/mdio-ipq4019.c
-+++ b/drivers/net/mdio/mdio-ipq4019.c
-@@ -14,6 +14,20 @@
- #include <linux/clk.h>
-
- #define MDIO_MODE_REG 0x40
-+#define MDIO_MODE_MDC_MODE BIT(12)
-+/* 0 = Clause 22, 1 = Clause 45 */
-+#define MDIO_MODE_C45 BIT(8)
-+#define MDIO_MODE_DIV_MASK GENMASK(7, 0)
-+#define MDIO_MODE_DIV(x) FIELD_PREP(MDIO_MODE_DIV_MASK, (x) - 1)
-+#define MDIO_MODE_DIV_1 0x0
-+#define MDIO_MODE_DIV_2 0x1
-+#define MDIO_MODE_DIV_4 0x3
-+#define MDIO_MODE_DIV_8 0x7
-+#define MDIO_MODE_DIV_16 0xf
-+#define MDIO_MODE_DIV_32 0x1f
-+#define MDIO_MODE_DIV_64 0x3f
-+#define MDIO_MODE_DIV_128 0x7f
-+#define MDIO_MODE_DIV_256 0xff
- #define MDIO_ADDR_REG 0x44
- #define MDIO_DATA_WRITE_REG 0x48
- #define MDIO_DATA_READ_REG 0x4c
-@@ -26,9 +40,6 @@
- #define MDIO_CMD_ACCESS_CODE_C45_WRITE 1
- #define MDIO_CMD_ACCESS_CODE_C45_READ 2
-
--/* 0 = Clause 22, 1 = Clause 45 */
--#define MDIO_MODE_C45 BIT(8)
--
- #define IPQ4019_MDIO_TIMEOUT 10000
- #define IPQ4019_MDIO_SLEEP 10
-
-@@ -41,6 +52,7 @@ struct ipq4019_mdio_data {
- void __iomem *membase;
- void __iomem *eth_ldo_rdy;
- struct clk *mdio_clk;
-+ unsigned int mdc_rate;
- };
-
- static int ipq4019_mdio_wait_busy(struct mii_bus *bus)
-@@ -203,6 +215,38 @@ static int ipq4019_mdio_write_c22(struct
- return 0;
- }
-
-+static int ipq4019_mdio_set_div(struct ipq4019_mdio_data *priv)
-+{
-+ unsigned long ahb_rate;
-+ int div;
-+ u32 val;
-+
-+ /* If we don't have a clock for AHB use the fixed value */
-+ ahb_rate = IPQ_MDIO_CLK_RATE;
-+ if (priv->mdio_clk)
-+ ahb_rate = clk_get_rate(priv->mdio_clk);
-+
-+ /* MDC rate is ahb_rate/(MDIO_MODE_DIV + 1)
-+ * While supported, internal documentation doesn't
-+ * assure correct functionality of the MDIO bus
-+ * with divider of 1, 2 or 4.
-+ */
-+ for (div = 8; div <= 256; div *= 2) {
-+ /* The requested rate is supported by the div */
-+ if (priv->mdc_rate == DIV_ROUND_UP(ahb_rate, div)) {
-+ val = readl(priv->membase + MDIO_MODE_REG);
-+ val &= ~MDIO_MODE_DIV_MASK;
-+ val |= MDIO_MODE_DIV(div);
-+ writel(val, priv->membase + MDIO_MODE_REG);
-+
-+ return 0;
-+ }
-+ }
-+
-+ /* The requested rate is not supported */
-+ return -EINVAL;
-+}
-+
- static int ipq_mdio_reset(struct mii_bus *bus)
- {
- struct ipq4019_mdio_data *priv = bus->priv;
-@@ -225,10 +269,58 @@ static int ipq_mdio_reset(struct mii_bus
- return ret;
-
- ret = clk_prepare_enable(priv->mdio_clk);
-- if (ret == 0)
-- mdelay(10);
-+ if (ret)
-+ return ret;
-+
-+ mdelay(10);
-
-- return ret;
-+ /* Restore MDC rate */
-+ return ipq4019_mdio_set_div(priv);
-+}
-+
-+static void ipq4019_mdio_select_mdc_rate(struct platform_device *pdev,
-+ struct ipq4019_mdio_data *priv)
-+{
-+ unsigned long ahb_rate;
-+ int div;
-+ u32 val;
-+
-+ /* MDC rate defined in DT, we don't have to decide a default value */
-+ if (!of_property_read_u32(pdev->dev.of_node, "clock-frequency",
-+ &priv->mdc_rate))
-+ return;
-+
-+ /* If we don't have a clock for AHB use the fixed value */
-+ ahb_rate = IPQ_MDIO_CLK_RATE;
-+ if (priv->mdio_clk)
-+ ahb_rate = clk_get_rate(priv->mdio_clk);
-+
-+ /* Check what is the current div set */
-+ val = readl(priv->membase + MDIO_MODE_REG);
-+ div = FIELD_GET(MDIO_MODE_DIV_MASK, val);
-+
-+ /* div is not set to the default value of /256
-+ * Probably someone changed that (bootloader, other drivers)
-+ * Keep this and don't overwrite it.
-+ */
-+ if (div != MDIO_MODE_DIV_256) {
-+ priv->mdc_rate = DIV_ROUND_UP(ahb_rate, div + 1);
-+ return;
-+ }
-+
-+ /* If div is /256 assume nobody have set this value and
-+ * try to find one MDC rate that is close the 802.3 spec of
-+ * 2.5MHz
-+ */
-+ for (div = 256; div >= 8; div /= 2) {
-+ /* Stop as soon as we found a divider that
-+ * reached the closest value to 2.5MHz
-+ */
-+ if (DIV_ROUND_UP(ahb_rate, div) > 2500000)
-+ break;
-+
-+ priv->mdc_rate = DIV_ROUND_UP(ahb_rate, div);
-+ }
- }
-
- static int ipq4019_mdio_probe(struct platform_device *pdev)
-@@ -252,6 +344,11 @@ static int ipq4019_mdio_probe(struct pla
- if (IS_ERR(priv->mdio_clk))
- return PTR_ERR(priv->mdio_clk);
-
-+ ipq4019_mdio_select_mdc_rate(pdev, priv);
-+ ret = ipq4019_mdio_set_div(priv);
-+ if (ret)
-+ return ret;
-+
- /* The platform resource is provided on the chipset IPQ5018 */
- /* This resource is optional */
- res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+++ /dev/null
-From 7edce370d87a23e8ed46af5b76a9fef1e341b67b Mon Sep 17 00:00:00 2001
-Date: Tue, 28 Nov 2023 14:59:28 +0100
-Subject: [PATCH] net: phy: aquantia: drop wrong endianness conversion for addr
- and CRC
-
-On further testing on BE target with kernel test robot, it was notice
-that the endianness conversion for addr and CRC in fw_load_memory was
-wrong.
-
-Drop the cpu_to_le32 conversion for addr load as it's not needed.
-
-Use get_unaligned_le32 instead of get_unaligned for FW data word load to
-correctly convert data in the correct order to follow system endian.
-
-Also drop the cpu_to_be32 for CRC calculation as it's wrong and would
-cause different CRC on BE system.
-The loaded word is swapped internally and MAILBOX calculates the CRC on
-the swapped word. To correctly calculate the CRC to be later matched
-with the one from MAILBOX, use an u8 struct and swap the word there to
-keep the same order on both LE and BE for crc_ccitt_false function.
-Also add additional comments on how the CRC verification for the loaded
-section works.
-
-CRC is calculated as we load the section and verified with the MAILBOX
-only after the entire section is loaded to skip additional slowdown by
-loop the section data again.
-
-Fixes: e93984ebc1c8 ("net: phy: aquantia: add firmware load support")
----
- drivers/net/phy/aquantia/aquantia_firmware.c | 24 ++++++++++++--------
- 1 file changed, 14 insertions(+), 10 deletions(-)
-
---- a/drivers/net/phy/aquantia/aquantia_firmware.c
-+++ b/drivers/net/phy/aquantia/aquantia_firmware.c
-@@ -93,9 +93,6 @@ static int aqr_fw_load_memory(struct phy
- u16 crc = 0, up_crc;
- size_t pos;
-
-- /* PHY expect addr in LE */
-- addr = (__force u32)cpu_to_le32(addr);
--
- phy_write_mmd(phydev, MDIO_MMD_VEND1,
- VEND1_GLOBAL_MAILBOX_INTERFACE1,
- VEND1_GLOBAL_MAILBOX_INTERFACE1_CRC_RESET);
-@@ -110,10 +107,11 @@ static int aqr_fw_load_memory(struct phy
- * If a firmware that is not word aligned is found, please report upstream.
- */
- for (pos = 0; pos < len; pos += sizeof(u32)) {
-+ u8 crc_data[4];
- u32 word;
-
- /* FW data is always stored in little-endian */
-- word = get_unaligned((const u32 *)(data + pos));
-+ word = get_unaligned_le32((const u32 *)(data + pos));
-
- phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLOBAL_MAILBOX_INTERFACE5,
- VEND1_GLOBAL_MAILBOX_INTERFACE5_MSW_DATA(word));
-@@ -124,15 +122,21 @@ static int aqr_fw_load_memory(struct phy
- VEND1_GLOBAL_MAILBOX_INTERFACE1_EXECUTE |
- VEND1_GLOBAL_MAILBOX_INTERFACE1_WRITE);
-
-- /* calculate CRC as we load data to the mailbox.
-- * We convert word to big-endian as PHY is BE and mailbox will
-- * return a BE CRC.
-+ /* Word is swapped internally and MAILBOX CRC is calculated
-+ * using big-endian order. Mimic what the PHY does to have a
-+ * matching CRC...
- */
-- word = (__force u32)cpu_to_be32(word);
-- crc = crc_ccitt_false(crc, (u8 *)&word, sizeof(word));
-- }
-+ crc_data[0] = word >> 24;
-+ crc_data[1] = word >> 16;
-+ crc_data[2] = word >> 8;
-+ crc_data[3] = word;
-
-+ /* ...calculate CRC as we load data... */
-+ crc = crc_ccitt_false(crc, crc_data, sizeof(crc_data));
-+ }
-+ /* ...gets CRC from MAILBOX after we have loaded the entire section... */
- up_crc = phy_read_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLOBAL_MAILBOX_INTERFACE2);
-+ /* ...and make sure it does match our calculated CRC */
- if (crc != up_crc) {
- phydev_err(phydev, "CRC mismatch: calculated 0x%04x PHY 0x%04x\n",
- crc, up_crc);
+++ /dev/null
-From 27c42e925323b975a64429e313b0cf5c0c02a411 Mon Sep 17 00:00:00 2001
-Date: Mon, 25 Mar 2024 21:19:48 +0530
-Subject: dt-bindings: arm: qcom,ids: Add SoC ID for IPQ5321
-
-Add the ID for the Qualcomm IPQ5321 SoC.
-
----
- include/dt-bindings/arm/qcom,ids.h | 1 +
- 1 file changed, 1 insertion(+)
-
-(limited to 'include/dt-bindings/arm/qcom,ids.h')
-
---- a/include/dt-bindings/arm/qcom,ids.h
-+++ b/include/dt-bindings/arm/qcom,ids.h
-@@ -260,6 +260,7 @@
- #define QCOM_ID_IPQ5312 594
- #define QCOM_ID_IPQ5302 595
- #define QCOM_ID_IPQ5300 624
-+#define QCOM_ID_IPQ5321 650
-
- /*
- * The board type and revision information, used by Qualcomm bootloaders and
+++ /dev/null
-From cb77d0ad460e2c97a00c02ed78afdf45476e5e5f Mon Sep 17 00:00:00 2001
-Date: Wed, 31 Jan 2024 03:27:29 +0100
-Subject: [PATCH] arm64: dts: qcom: ipq8074: add clock-frequency to MDIO node
-
-Add clock-frequency to MDIO node to set the MDC rate to 6.25Mhz instead
-of using the default value of 390KHz from MDIO default divider.
-
----
- arch/arm64/boot/dts/qcom/ipq8074.dtsi | 2 ++
- 1 file changed, 2 insertions(+)
-
---- a/arch/arm64/boot/dts/qcom/ipq8074.dtsi
-+++ b/arch/arm64/boot/dts/qcom/ipq8074.dtsi
-@@ -275,6 +275,8 @@
- clocks = <&gcc GCC_MDIO_AHB_CLK>;
- clock-names = "gcc_mdio_ahb_clk";
-
-+ clock-frequency = <6250000>;
-+
- status = "disabled";
- };
-
+++ /dev/null
-From e184e8609f8c1cd9fef703f667245b6ebd89c2ed Mon Sep 17 00:00:00 2001
-Date: Tue, 3 Oct 2023 14:34:24 +0100
-Subject: [PATCH] net: sfp: re-implement ignoring the hardware TX_FAULT signal
-
-Re-implement how we ignore the hardware TX_FAULT signal. Rather than
-having a separate boolean for this, use a bitmask of the hardware
-signals that we wish to ignore. This gives more flexibility in the
-future to ignore other signals such as RX_LOS.
-
----
- drivers/net/phy/sfp.c | 16 ++++++++--------
- 1 file changed, 8 insertions(+), 8 deletions(-)
-
---- a/drivers/net/phy/sfp.c
-+++ b/drivers/net/phy/sfp.c
-@@ -257,6 +257,7 @@ struct sfp {
- unsigned int state_hw_drive;
- unsigned int state_hw_mask;
- unsigned int state_soft_mask;
-+ unsigned int state_ignore_mask;
- unsigned int state;
-
- struct delayed_work poll;
-@@ -280,7 +281,6 @@ struct sfp {
- unsigned int rs_state_mask;
-
- bool have_a2;
-- bool tx_fault_ignore;
-
- const struct sfp_quirk *quirk;
-
-@@ -347,7 +347,7 @@ static void sfp_fixup_long_startup(struc
-
- static void sfp_fixup_ignore_tx_fault(struct sfp *sfp)
- {
-- sfp->tx_fault_ignore = true;
-+ sfp->state_ignore_mask |= SFP_F_TX_FAULT;
- }
-
- // For 10GBASE-T short-reach modules
-@@ -798,7 +798,8 @@ static void sfp_soft_start_poll(struct s
-
- mutex_lock(&sfp->st_mutex);
- // Poll the soft state for hardware pins we want to ignore
-- sfp->state_soft_mask = ~sfp->state_hw_mask & mask;
-+ sfp->state_soft_mask = ~sfp->state_hw_mask & ~sfp->state_ignore_mask &
-+ mask;
-
- if (sfp->state_soft_mask & (SFP_F_LOS | SFP_F_TX_FAULT) &&
- !sfp->need_poll)
-@@ -2323,7 +2324,7 @@ static int sfp_sm_mod_probe(struct sfp *
- sfp->module_t_start_up = T_START_UP;
- sfp->module_t_wait = T_WAIT;
-
-- sfp->tx_fault_ignore = false;
-+ sfp->state_ignore_mask = 0;
-
- if (sfp->id.base.extended_cc == SFF8024_ECC_10GBASE_T_SFI ||
- sfp->id.base.extended_cc == SFF8024_ECC_10GBASE_T_SR ||
-@@ -2346,6 +2347,8 @@ static int sfp_sm_mod_probe(struct sfp *
-
- if (sfp->quirk && sfp->quirk->fixup)
- sfp->quirk->fixup(sfp);
-+
-+ sfp->state_hw_mask &= ~sfp->state_ignore_mask;
- mutex_unlock(&sfp->st_mutex);
-
- return 0;
-@@ -2846,10 +2849,7 @@ static void sfp_check_state(struct sfp *
- mutex_lock(&sfp->st_mutex);
- state = sfp_get_state(sfp);
- changed = state ^ sfp->state;
-- if (sfp->tx_fault_ignore)
-- changed &= SFP_F_PRESENT | SFP_F_LOS;
-- else
-- changed &= SFP_F_PRESENT | SFP_F_LOS | SFP_F_TX_FAULT;
-+ changed &= SFP_F_PRESENT | SFP_F_LOS | SFP_F_TX_FAULT;
-
- for (i = 0; i < GPIO_MAX; i++)
- if (changed & BIT(i))
+++ /dev/null
-From 380b50ae3a04222334a3779b3787eba844b1177f Mon Sep 17 00:00:00 2001
-Date: Thu, 16 Nov 2023 20:32:31 +0100
-Subject: net: phy: broadcom: Wire suspend/resume for BCM54612E
-
-The BCM54612E ethernet PHY supports IDDQ-SR.
-Therefore wire-up the suspend and resume callbacks
-to point to bcm54xx_suspend() and bcm54xx_resume().
-
----
- drivers/net/phy/broadcom.c | 2 ++
- 1 file changed, 2 insertions(+)
-
---- a/drivers/net/phy/broadcom.c
-+++ b/drivers/net/phy/broadcom.c
-@@ -1061,6 +1061,8 @@ static struct phy_driver broadcom_driver
- .handle_interrupt = bcm_phy_handle_interrupt,
- .link_change_notify = bcm54xx_link_change_notify,
- .led_brightness_set = bcm_phy_led_brightness_set,
-+ .suspend = bcm54xx_suspend,
-+ .resume = bcm54xx_resume,
- }, {
- .phy_id = PHY_ID_BCM54616S,
- .phy_id_mask = 0xfffffff0,
+++ /dev/null
-From abb45a2477f533cd4aab3085defdff131e2e8c4f Mon Sep 17 00:00:00 2001
-Date: Mon, 6 May 2024 14:32:46 +0200
-Subject: [PATCH] net: stmmac: dwmac-ipq806x: account for rgmii-txid/rxid/id
- phy-mode
-
-Currently the ipq806x dwmac driver is almost always used attached to the
-CPU port of a switch and phy-mode was always set to "rgmii" or "sgmii".
-
-Some device came up with a special configuration where the PHY is
-directly attached to the GMAC port and in those case phy-mode needs to
-be set to "rgmii-id" to make the PHY correctly work and receive packets.
-
-Since the driver supports only "rgmii" and "sgmii" mode, when "rgmii-id"
-(or variants) mode is set, the mode is rejected and probe fails.
-
-Add support also for these phy-modes to correctly setup PHYs that requires
-delay applied to tx/rx.
-
----
- drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c | 12 ++++++++++++
- 1 file changed, 12 insertions(+)
-
---- a/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c
-+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c
-@@ -171,6 +171,9 @@ static int ipq806x_gmac_set_speed(struct
-
- switch (gmac->phy_mode) {
- case PHY_INTERFACE_MODE_RGMII:
-+ case PHY_INTERFACE_MODE_RGMII_ID:
-+ case PHY_INTERFACE_MODE_RGMII_RXID:
-+ case PHY_INTERFACE_MODE_RGMII_TXID:
- div = get_clk_div_rgmii(gmac, speed);
- clk_bits = NSS_COMMON_CLK_GATE_RGMII_RX_EN(gmac->id) |
- NSS_COMMON_CLK_GATE_RGMII_TX_EN(gmac->id);
-@@ -412,6 +415,9 @@ static int ipq806x_gmac_probe(struct pla
- val |= NSS_COMMON_GMAC_CTL_CSYS_REQ;
- switch (gmac->phy_mode) {
- case PHY_INTERFACE_MODE_RGMII:
-+ case PHY_INTERFACE_MODE_RGMII_ID:
-+ case PHY_INTERFACE_MODE_RGMII_RXID:
-+ case PHY_INTERFACE_MODE_RGMII_TXID:
- val |= NSS_COMMON_GMAC_CTL_PHY_IFACE_SEL;
- break;
- case PHY_INTERFACE_MODE_SGMII:
-@@ -427,6 +433,9 @@ static int ipq806x_gmac_probe(struct pla
- val &= ~(1 << NSS_COMMON_CLK_SRC_CTRL_OFFSET(gmac->id));
- switch (gmac->phy_mode) {
- case PHY_INTERFACE_MODE_RGMII:
-+ case PHY_INTERFACE_MODE_RGMII_ID:
-+ case PHY_INTERFACE_MODE_RGMII_RXID:
-+ case PHY_INTERFACE_MODE_RGMII_TXID:
- val |= NSS_COMMON_CLK_SRC_CTRL_RGMII(gmac->id) <<
- NSS_COMMON_CLK_SRC_CTRL_OFFSET(gmac->id);
- break;
-@@ -444,6 +453,9 @@ static int ipq806x_gmac_probe(struct pla
- val |= NSS_COMMON_CLK_GATE_PTP_EN(gmac->id);
- switch (gmac->phy_mode) {
- case PHY_INTERFACE_MODE_RGMII:
-+ case PHY_INTERFACE_MODE_RGMII_ID:
-+ case PHY_INTERFACE_MODE_RGMII_RXID:
-+ case PHY_INTERFACE_MODE_RGMII_TXID:
- val |= NSS_COMMON_CLK_GATE_RGMII_RX_EN(gmac->id) |
- NSS_COMMON_CLK_GATE_RGMII_TX_EN(gmac->id);
- break;
+++ /dev/null
-From b544223bec9f710256543eadc1b8b8344f80d665 Mon Sep 17 00:00:00 2001
-Date: Thu, 17 Oct 2024 11:22:11 +0800
-Subject: [PATCH 1/3] net: phy: mediatek-ge-soc: Fix coding style
-
-This patch fixes spelling errors, re-arrange vars with
-reverse Xmas tree and remove unnecessary parens in
-mediatek-ge-soc.c.
-
----
- drivers/net/phy/mediatek-ge-soc.c | 36 ++++++++++++++++---------------
- 1 file changed, 19 insertions(+), 17 deletions(-)
-
---- a/drivers/net/phy/mediatek-ge-soc.c
-+++ b/drivers/net/phy/mediatek-ge-soc.c
-@@ -408,16 +408,17 @@ static int tx_offset_cal_efuse(struct ph
-
- static int tx_amp_fill_result(struct phy_device *phydev, u16 *buf)
- {
-- int i;
-- int bias[16] = {};
-- const int vals_9461[16] = { 7, 1, 4, 7,
-- 7, 1, 4, 7,
-- 7, 1, 4, 7,
-- 7, 1, 4, 7 };
- const int vals_9481[16] = { 10, 6, 6, 10,
- 10, 6, 6, 10,
- 10, 6, 6, 10,
- 10, 6, 6, 10 };
-+ const int vals_9461[16] = { 7, 1, 4, 7,
-+ 7, 1, 4, 7,
-+ 7, 1, 4, 7,
-+ 7, 1, 4, 7 };
-+ int bias[16] = {};
-+ int i;
-+
- switch (phydev->drv->phy_id) {
- case MTK_GPHY_ID_MT7981:
- /* We add some calibration to efuse values
-@@ -1069,10 +1070,10 @@ static int start_cal(struct phy_device *
-
- static int mt798x_phy_calibration(struct phy_device *phydev)
- {
-+ struct nvmem_cell *cell;
- int ret = 0;
-- u32 *buf;
- size_t len;
-- struct nvmem_cell *cell;
-+ u32 *buf;
-
- cell = nvmem_cell_get(&phydev->mdio.dev, "phy-cal-data");
- if (IS_ERR(cell)) {
-@@ -1210,14 +1211,15 @@ static int mt798x_phy_led_brightness_set
- return mt798x_phy_hw_led_on_set(phydev, index, (value != LED_OFF));
- }
-
--static const unsigned long supported_triggers = (BIT(TRIGGER_NETDEV_FULL_DUPLEX) |
-- BIT(TRIGGER_NETDEV_HALF_DUPLEX) |
-- BIT(TRIGGER_NETDEV_LINK) |
-- BIT(TRIGGER_NETDEV_LINK_10) |
-- BIT(TRIGGER_NETDEV_LINK_100) |
-- BIT(TRIGGER_NETDEV_LINK_1000) |
-- BIT(TRIGGER_NETDEV_RX) |
-- BIT(TRIGGER_NETDEV_TX));
-+static const unsigned long supported_triggers =
-+ BIT(TRIGGER_NETDEV_FULL_DUPLEX) |
-+ BIT(TRIGGER_NETDEV_HALF_DUPLEX) |
-+ BIT(TRIGGER_NETDEV_LINK) |
-+ BIT(TRIGGER_NETDEV_LINK_10) |
-+ BIT(TRIGGER_NETDEV_LINK_100) |
-+ BIT(TRIGGER_NETDEV_LINK_1000) |
-+ BIT(TRIGGER_NETDEV_RX) |
-+ BIT(TRIGGER_NETDEV_TX);
-
- static int mt798x_phy_led_hw_is_supported(struct phy_device *phydev, u8 index,
- unsigned long rules)
-@@ -1415,7 +1417,7 @@ static int mt7988_phy_probe_shared(struc
- * LED_C and LED_D respectively. At the same time those pins are used to
- * bootstrap configuration of the reference clock source (LED_A),
- * DRAM DDRx16b x2/x1 (LED_B) and boot device (LED_C, LED_D).
-- * In practise this is done using a LED and a resistor pulling the pin
-+ * In practice this is done using a LED and a resistor pulling the pin
- * either to GND or to VIO.
- * The detected value at boot time is accessible at run-time using the
- * TPBANK0 register located in the gpio base of the pinctrl, in order
+++ /dev/null
-From b0f90a863ca5030fd074426b2b5095ef93f2c5bf Mon Sep 17 00:00:00 2001
-Date: Thu, 17 Oct 2024 11:22:12 +0800
-Subject: [PATCH 2/3] net: phy: mediatek-ge-soc: Shrink line wrapping to 80
- characters
-
-This patch shrinks line wrapping to 80 chars. Also, in
-tx_amp_fill_result(), use FIELD_PREP() to prettify code.
-
----
- drivers/net/phy/mediatek-ge-soc.c | 125 +++++++++++++++++++++---------
- 1 file changed, 88 insertions(+), 37 deletions(-)
-
---- a/drivers/net/phy/mediatek-ge-soc.c
-+++ b/drivers/net/phy/mediatek-ge-soc.c
-@@ -342,7 +342,8 @@ static int cal_cycle(struct phy_device *
- ret = phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND1,
- MTK_PHY_RG_AD_CAL_CLK, reg_val,
- reg_val & MTK_PHY_DA_CAL_CLK, 500,
-- ANALOG_INTERNAL_OPERATION_MAX_US, false);
-+ ANALOG_INTERNAL_OPERATION_MAX_US,
-+ false);
- if (ret) {
- phydev_err(phydev, "Calibration cycle timeout\n");
- return ret;
-@@ -441,40 +442,72 @@ static int tx_amp_fill_result(struct phy
- }
-
- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TXVLD_DA_RG,
-- MTK_PHY_DA_TX_I2MPB_A_GBE_MASK, (buf[0] + bias[0]) << 10);
-+ MTK_PHY_DA_TX_I2MPB_A_GBE_MASK,
-+ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_A_GBE_MASK,
-+ buf[0] + bias[0]));
- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TXVLD_DA_RG,
-- MTK_PHY_DA_TX_I2MPB_A_TBT_MASK, buf[0] + bias[1]);
-+ MTK_PHY_DA_TX_I2MPB_A_TBT_MASK,
-+ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_A_TBT_MASK,
-+ buf[0] + bias[1]));
- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_A2,
-- MTK_PHY_DA_TX_I2MPB_A_HBT_MASK, (buf[0] + bias[2]) << 10);
-+ MTK_PHY_DA_TX_I2MPB_A_HBT_MASK,
-+ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_A_HBT_MASK,
-+ buf[0] + bias[2]));
- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_A2,
-- MTK_PHY_DA_TX_I2MPB_A_TST_MASK, buf[0] + bias[3]);
-+ MTK_PHY_DA_TX_I2MPB_A_TST_MASK,
-+ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_A_TST_MASK,
-+ buf[0] + bias[3]));
-
- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B1,
-- MTK_PHY_DA_TX_I2MPB_B_GBE_MASK, (buf[1] + bias[4]) << 8);
-+ MTK_PHY_DA_TX_I2MPB_B_GBE_MASK,
-+ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_B_GBE_MASK,
-+ buf[1] + bias[4]));
- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B1,
-- MTK_PHY_DA_TX_I2MPB_B_TBT_MASK, buf[1] + bias[5]);
-+ MTK_PHY_DA_TX_I2MPB_B_TBT_MASK,
-+ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_B_TBT_MASK,
-+ buf[1] + bias[5]));
- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B2,
-- MTK_PHY_DA_TX_I2MPB_B_HBT_MASK, (buf[1] + bias[6]) << 8);
-+ MTK_PHY_DA_TX_I2MPB_B_HBT_MASK,
-+ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_B_HBT_MASK,
-+ buf[1] + bias[6]));
- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B2,
-- MTK_PHY_DA_TX_I2MPB_B_TST_MASK, buf[1] + bias[7]);
-+ MTK_PHY_DA_TX_I2MPB_B_TST_MASK,
-+ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_B_TST_MASK,
-+ buf[1] + bias[7]));
-
- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C1,
-- MTK_PHY_DA_TX_I2MPB_C_GBE_MASK, (buf[2] + bias[8]) << 8);
-+ MTK_PHY_DA_TX_I2MPB_C_GBE_MASK,
-+ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_C_GBE_MASK,
-+ buf[2] + bias[8]));
- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C1,
-- MTK_PHY_DA_TX_I2MPB_C_TBT_MASK, buf[2] + bias[9]);
-+ MTK_PHY_DA_TX_I2MPB_C_TBT_MASK,
-+ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_C_TBT_MASK,
-+ buf[2] + bias[9]));
- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C2,
-- MTK_PHY_DA_TX_I2MPB_C_HBT_MASK, (buf[2] + bias[10]) << 8);
-+ MTK_PHY_DA_TX_I2MPB_C_HBT_MASK,
-+ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_C_HBT_MASK,
-+ buf[2] + bias[10]));
- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C2,
-- MTK_PHY_DA_TX_I2MPB_C_TST_MASK, buf[2] + bias[11]);
-+ MTK_PHY_DA_TX_I2MPB_C_TST_MASK,
-+ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_C_TST_MASK,
-+ buf[2] + bias[11]));
-
- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D1,
-- MTK_PHY_DA_TX_I2MPB_D_GBE_MASK, (buf[3] + bias[12]) << 8);
-+ MTK_PHY_DA_TX_I2MPB_D_GBE_MASK,
-+ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_D_GBE_MASK,
-+ buf[3] + bias[12]));
- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D1,
-- MTK_PHY_DA_TX_I2MPB_D_TBT_MASK, buf[3] + bias[13]);
-+ MTK_PHY_DA_TX_I2MPB_D_TBT_MASK,
-+ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_D_TBT_MASK,
-+ buf[3] + bias[13]));
- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D2,
-- MTK_PHY_DA_TX_I2MPB_D_HBT_MASK, (buf[3] + bias[14]) << 8);
-+ MTK_PHY_DA_TX_I2MPB_D_HBT_MASK,
-+ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_D_HBT_MASK,
-+ buf[3] + bias[14]));
- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D2,
-- MTK_PHY_DA_TX_I2MPB_D_TST_MASK, buf[3] + bias[15]);
-+ MTK_PHY_DA_TX_I2MPB_D_TST_MASK,
-+ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_D_TST_MASK,
-+ buf[3] + bias[15]));
-
- return 0;
- }
-@@ -663,7 +696,8 @@ static int tx_vcm_cal_sw(struct phy_devi
- goto restore;
-
- /* We calibrate TX-VCM in different logic. Check upper index and then
-- * lower index. If this calibration is valid, apply lower index's result.
-+ * lower index. If this calibration is valid, apply lower index's
-+ * result.
- */
- ret = upper_ret - lower_ret;
- if (ret == 1) {
-@@ -692,7 +726,8 @@ static int tx_vcm_cal_sw(struct phy_devi
- } else if (upper_idx == TXRESERVE_MAX && upper_ret == 0 &&
- lower_ret == 0) {
- ret = 0;
-- phydev_warn(phydev, "TX-VCM SW cal result at high margin 0x%x\n",
-+ phydev_warn(phydev,
-+ "TX-VCM SW cal result at high margin 0x%x\n",
- upper_idx);
- } else {
- ret = -EINVAL;
-@@ -796,7 +831,8 @@ static void mt7981_phy_finetune(struct p
-
- /* TR_OPEN_LOOP_EN = 1, lpf_x_average = 9 */
- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG234,
-- MTK_PHY_TR_OPEN_LOOP_EN_MASK | MTK_PHY_LPF_X_AVERAGE_MASK,
-+ MTK_PHY_TR_OPEN_LOOP_EN_MASK |
-+ MTK_PHY_LPF_X_AVERAGE_MASK,
- BIT(0) | FIELD_PREP(MTK_PHY_LPF_X_AVERAGE_MASK, 0x9));
-
- /* rg_tr_lpf_cnt_val = 512 */
-@@ -865,7 +901,8 @@ static void mt7988_phy_finetune(struct p
-
- /* TR_OPEN_LOOP_EN = 1, lpf_x_average = 10 */
- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG234,
-- MTK_PHY_TR_OPEN_LOOP_EN_MASK | MTK_PHY_LPF_X_AVERAGE_MASK,
-+ MTK_PHY_TR_OPEN_LOOP_EN_MASK |
-+ MTK_PHY_LPF_X_AVERAGE_MASK,
- BIT(0) | FIELD_PREP(MTK_PHY_LPF_X_AVERAGE_MASK, 0xa));
-
- /* rg_tr_lpf_cnt_val = 1023 */
-@@ -977,7 +1014,8 @@ static void mt798x_phy_eee(struct phy_de
- phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
-
- phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_3);
-- __phy_modify(phydev, MTK_PHY_LPI_REG_14, MTK_PHY_LPI_WAKE_TIMER_1000_MASK,
-+ __phy_modify(phydev, MTK_PHY_LPI_REG_14,
-+ MTK_PHY_LPI_WAKE_TIMER_1000_MASK,
- FIELD_PREP(MTK_PHY_LPI_WAKE_TIMER_1000_MASK, 0x19c));
-
- __phy_modify(phydev, MTK_PHY_LPI_REG_1c, MTK_PHY_SMI_DET_ON_THRESH_MASK,
-@@ -987,7 +1025,8 @@ static void mt798x_phy_eee(struct phy_de
- phy_modify_mmd(phydev, MDIO_MMD_VEND1,
- MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG122,
- MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK,
-- FIELD_PREP(MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK, 0xff));
-+ FIELD_PREP(MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK,
-+ 0xff));
- }
-
- static int cal_sw(struct phy_device *phydev, enum CAL_ITEM cal_item,
-@@ -1147,7 +1186,8 @@ static int mt798x_phy_hw_led_on_set(stru
- (index ? 16 : 0), &priv->led_state);
- if (changed)
- return phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ?
-- MTK_PHY_LED1_ON_CTRL : MTK_PHY_LED0_ON_CTRL,
-+ MTK_PHY_LED1_ON_CTRL :
-+ MTK_PHY_LED0_ON_CTRL,
- MTK_PHY_LED_ON_MASK,
- on ? MTK_PHY_LED_ON_FORCE_ON : 0);
- else
-@@ -1157,7 +1197,8 @@ static int mt798x_phy_hw_led_on_set(stru
- static int mt798x_phy_hw_led_blink_set(struct phy_device *phydev, u8 index,
- bool blinking)
- {
-- unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK + (index ? 16 : 0);
-+ unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK +
-+ (index ? 16 : 0);
- struct mtk_socphy_priv *priv = phydev->priv;
- bool changed;
-
-@@ -1170,8 +1211,10 @@ static int mt798x_phy_hw_led_blink_set(s
- (index ? 16 : 0), &priv->led_state);
- if (changed)
- return phy_write_mmd(phydev, MDIO_MMD_VEND2, index ?
-- MTK_PHY_LED1_BLINK_CTRL : MTK_PHY_LED0_BLINK_CTRL,
-- blinking ? MTK_PHY_LED_BLINK_FORCE_BLINK : 0);
-+ MTK_PHY_LED1_BLINK_CTRL :
-+ MTK_PHY_LED0_BLINK_CTRL,
-+ blinking ?
-+ MTK_PHY_LED_BLINK_FORCE_BLINK : 0);
- else
- return 0;
- }
-@@ -1237,7 +1280,8 @@ static int mt798x_phy_led_hw_is_supporte
- static int mt798x_phy_led_hw_control_get(struct phy_device *phydev, u8 index,
- unsigned long *rules)
- {
-- unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK + (index ? 16 : 0);
-+ unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK +
-+ (index ? 16 : 0);
- unsigned int bit_netdev = MTK_PHY_LED_STATE_NETDEV + (index ? 16 : 0);
- unsigned int bit_on = MTK_PHY_LED_STATE_FORCE_ON + (index ? 16 : 0);
- struct mtk_socphy_priv *priv = phydev->priv;
-@@ -1258,8 +1302,8 @@ static int mt798x_phy_led_hw_control_get
- if (blink < 0)
- return -EIO;
-
-- if ((on & (MTK_PHY_LED_ON_LINK | MTK_PHY_LED_ON_FDX | MTK_PHY_LED_ON_HDX |
-- MTK_PHY_LED_ON_LINKDOWN)) ||
-+ if ((on & (MTK_PHY_LED_ON_LINK | MTK_PHY_LED_ON_FDX |
-+ MTK_PHY_LED_ON_HDX | MTK_PHY_LED_ON_LINKDOWN)) ||
- (blink & (MTK_PHY_LED_BLINK_RX | MTK_PHY_LED_BLINK_TX)))
- set_bit(bit_netdev, &priv->led_state);
- else
-@@ -1333,17 +1377,23 @@ static int mt798x_phy_led_hw_control_set
-
- if (rules & BIT(TRIGGER_NETDEV_RX)) {
- blink |= (on & MTK_PHY_LED_ON_LINK) ?
-- (((on & MTK_PHY_LED_ON_LINK10) ? MTK_PHY_LED_BLINK_10RX : 0) |
-- ((on & MTK_PHY_LED_ON_LINK100) ? MTK_PHY_LED_BLINK_100RX : 0) |
-- ((on & MTK_PHY_LED_ON_LINK1000) ? MTK_PHY_LED_BLINK_1000RX : 0)) :
-+ (((on & MTK_PHY_LED_ON_LINK10) ?
-+ MTK_PHY_LED_BLINK_10RX : 0) |
-+ ((on & MTK_PHY_LED_ON_LINK100) ?
-+ MTK_PHY_LED_BLINK_100RX : 0) |
-+ ((on & MTK_PHY_LED_ON_LINK1000) ?
-+ MTK_PHY_LED_BLINK_1000RX : 0)) :
- MTK_PHY_LED_BLINK_RX;
- }
-
- if (rules & BIT(TRIGGER_NETDEV_TX)) {
- blink |= (on & MTK_PHY_LED_ON_LINK) ?
-- (((on & MTK_PHY_LED_ON_LINK10) ? MTK_PHY_LED_BLINK_10TX : 0) |
-- ((on & MTK_PHY_LED_ON_LINK100) ? MTK_PHY_LED_BLINK_100TX : 0) |
-- ((on & MTK_PHY_LED_ON_LINK1000) ? MTK_PHY_LED_BLINK_1000TX : 0)) :
-+ (((on & MTK_PHY_LED_ON_LINK10) ?
-+ MTK_PHY_LED_BLINK_10TX : 0) |
-+ ((on & MTK_PHY_LED_ON_LINK100) ?
-+ MTK_PHY_LED_BLINK_100TX : 0) |
-+ ((on & MTK_PHY_LED_ON_LINK1000) ?
-+ MTK_PHY_LED_BLINK_1000TX : 0)) :
- MTK_PHY_LED_BLINK_TX;
- }
-
-@@ -1400,7 +1450,8 @@ static int mt7988_phy_fix_leds_polaritie
- /* Only now setup pinctrl to avoid bogus blinking */
- pinctrl = devm_pinctrl_get_select(&phydev->mdio.dev, "gbe-led");
- if (IS_ERR(pinctrl))
-- dev_err(&phydev->mdio.bus->dev, "Failed to setup PHY LED pinctrl\n");
-+ dev_err(&phydev->mdio.bus->dev,
-+ "Failed to setup PHY LED pinctrl\n");
-
- return 0;
- }
+++ /dev/null
-From 93a610c00ffd8b9c7c108039d894ddd5193b147e Mon Sep 17 00:00:00 2001
-Date: Thu, 17 Oct 2024 11:22:13 +0800
-Subject: [PATCH 3/3] net: phy: mediatek-ge-soc: Propagate error code correctly
- in cal_cycle()
-
-This patch propagates error code correctly in cal_cycle()
-and improve with FIELD_GET().
-
----
- drivers/net/phy/mediatek-ge-soc.c | 8 +++++---
- 1 file changed, 5 insertions(+), 3 deletions(-)
-
---- a/drivers/net/phy/mediatek-ge-soc.c
-+++ b/drivers/net/phy/mediatek-ge-soc.c
-@@ -110,7 +110,7 @@
- #define MTK_PHY_CR_TX_AMP_OFFSET_D_MASK GENMASK(6, 0)
-
- #define MTK_PHY_RG_AD_CAL_COMP 0x17a
--#define MTK_PHY_AD_CAL_COMP_OUT_SHIFT (8)
-+#define MTK_PHY_AD_CAL_COMP_OUT_MASK GENMASK(8, 8)
-
- #define MTK_PHY_RG_AD_CAL_CLK 0x17b
- #define MTK_PHY_DA_CAL_CLK BIT(0)
-@@ -351,8 +351,10 @@ static int cal_cycle(struct phy_device *
-
- phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_AD_CALIN,
- MTK_PHY_DA_CALIN_FLAG);
-- ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_AD_CAL_COMP) >>
-- MTK_PHY_AD_CAL_COMP_OUT_SHIFT;
-+ ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_AD_CAL_COMP);
-+ if (ret < 0)
-+ return ret;
-+ ret = FIELD_GET(MTK_PHY_AD_CAL_COMP_OUT_MASK, ret);
- phydev_dbg(phydev, "cal_val: 0x%x, ret: %d\n", cal_val, ret);
-
- return ret;
+++ /dev/null
-From 4c452f7ea86212934ae896842847d1671e13a18b Mon Sep 17 00:00:00 2001
-Date: Sat, 9 Nov 2024 00:34:51 +0800
-Subject: [PATCH] net: phy: mediatek: Re-organize MediaTek ethernet phy drivers
-
-Re-organize MediaTek ethernet phy driver files and get ready to integrate
-some common functions and add new 2.5G phy driver.
-mtk-ge.c: MT7530 Gphy on MT7621 & MT7531 Gphy
-mtk-ge-soc.c: Built-in Gphy on MT7981 & Built-in switch Gphy on MT7988
-mtk-2p5ge.c: Planned for built-in 2.5G phy on MT7988
-
----
- MAINTAINERS | 4 ++--
- drivers/net/phy/Kconfig | 17 +-------------
- drivers/net/phy/Makefile | 3 +--
- drivers/net/phy/mediatek/Kconfig | 22 +++++++++++++++++++
- drivers/net/phy/mediatek/Makefile | 3 +++
- .../mtk-ge-soc.c} | 0
- .../phy/{mediatek-ge.c => mediatek/mtk-ge.c} | 0
- 7 files changed, 29 insertions(+), 20 deletions(-)
- create mode 100644 drivers/net/phy/mediatek/Kconfig
- create mode 100644 drivers/net/phy/mediatek/Makefile
- rename drivers/net/phy/{mediatek-ge-soc.c => mediatek/mtk-ge-soc.c} (100%)
- rename drivers/net/phy/{mediatek-ge.c => mediatek/mtk-ge.c} (100%)
-
---- a/drivers/net/phy/Kconfig
-+++ b/drivers/net/phy/Kconfig
-@@ -234,22 +234,7 @@ config MAXLINEAR_GPHY
- Support for the Maxlinear GPY115, GPY211, GPY212, GPY215,
- GPY241, GPY245 PHYs.
-
--config MEDIATEK_GE_PHY
-- tristate "MediaTek Gigabit Ethernet PHYs"
-- help
-- Supports the MediaTek Gigabit Ethernet PHYs.
--
--config MEDIATEK_GE_SOC_PHY
-- tristate "MediaTek SoC Ethernet PHYs"
-- depends on (ARM64 && ARCH_MEDIATEK) || COMPILE_TEST
-- depends on NVMEM_MTK_EFUSE
-- help
-- Supports MediaTek SoC built-in Gigabit Ethernet PHYs.
--
-- Include support for built-in Ethernet PHYs which are present in
-- the MT7981 and MT7988 SoCs. These PHYs need calibration data
-- present in the SoCs efuse and will dynamically calibrate VCM
-- (common-mode voltage) during startup.
-+source "drivers/net/phy/mediatek/Kconfig"
-
- config MICREL_PHY
- tristate "Micrel PHYs"
---- a/drivers/net/phy/Makefile
-+++ b/drivers/net/phy/Makefile
-@@ -66,8 +66,7 @@ obj-$(CONFIG_MARVELL_PHY) += marvell.o
- obj-$(CONFIG_MARVELL_88Q2XXX_PHY) += marvell-88q2xxx.o
- obj-$(CONFIG_MARVELL_88X2222_PHY) += marvell-88x2222.o
- obj-$(CONFIG_MAXLINEAR_GPHY) += mxl-gpy.o
--obj-$(CONFIG_MEDIATEK_GE_PHY) += mediatek-ge.o
--obj-$(CONFIG_MEDIATEK_GE_SOC_PHY) += mediatek-ge-soc.o
-+obj-y += mediatek/
- obj-$(CONFIG_MESON_GXL_PHY) += meson-gxl.o
- obj-$(CONFIG_MICREL_KS8995MA) += spi_ks8995.o
- obj-$(CONFIG_MICREL_PHY) += micrel.o
---- /dev/null
-+++ b/drivers/net/phy/mediatek/Kconfig
-@@ -0,0 +1,22 @@
-+# SPDX-License-Identifier: GPL-2.0-only
-+config MEDIATEK_GE_PHY
-+ tristate "MediaTek Gigabit Ethernet PHYs"
-+ help
-+ Supports the MediaTek non-built-in Gigabit Ethernet PHYs.
-+
-+ Non-built-in Gigabit Ethernet PHYs include mt7530/mt7531.
-+ You may find mt7530 inside mt7621. This driver shares some
-+ common operations with MediaTek SoC built-in Gigabit
-+ Ethernet PHYs.
-+
-+config MEDIATEK_GE_SOC_PHY
-+ tristate "MediaTek SoC Ethernet PHYs"
-+ depends on (ARM64 && ARCH_MEDIATEK) || COMPILE_TEST
-+ depends on NVMEM_MTK_EFUSE
-+ help
-+ Supports MediaTek SoC built-in Gigabit Ethernet PHYs.
-+
-+ Include support for built-in Ethernet PHYs which are present in
-+ the MT7981 and MT7988 SoCs. These PHYs need calibration data
-+ present in the SoCs efuse and will dynamically calibrate VCM
-+ (common-mode voltage) during startup.
---- /dev/null
-+++ b/drivers/net/phy/mediatek/Makefile
-@@ -0,0 +1,3 @@
-+# SPDX-License-Identifier: GPL-2.0
-+obj-$(CONFIG_MEDIATEK_GE_PHY) += mtk-ge.o
-+obj-$(CONFIG_MEDIATEK_GE_SOC_PHY) += mtk-ge-soc.o
---- a/drivers/net/phy/mediatek-ge-soc.c
-+++ /dev/null
-@@ -1,1610 +0,0 @@
--// SPDX-License-Identifier: GPL-2.0+
--#include <linux/bitfield.h>
--#include <linux/bitmap.h>
--#include <linux/mfd/syscon.h>
--#include <linux/module.h>
--#include <linux/nvmem-consumer.h>
--#include <linux/pinctrl/consumer.h>
--#include <linux/phy.h>
--#include <linux/regmap.h>
--
--#define MTK_GPHY_ID_MT7981 0x03a29461
--#define MTK_GPHY_ID_MT7988 0x03a29481
--
--#define MTK_EXT_PAGE_ACCESS 0x1f
--#define MTK_PHY_PAGE_STANDARD 0x0000
--#define MTK_PHY_PAGE_EXTENDED_3 0x0003
--
--#define MTK_PHY_LPI_REG_14 0x14
--#define MTK_PHY_LPI_WAKE_TIMER_1000_MASK GENMASK(8, 0)
--
--#define MTK_PHY_LPI_REG_1c 0x1c
--#define MTK_PHY_SMI_DET_ON_THRESH_MASK GENMASK(13, 8)
--
--#define MTK_PHY_PAGE_EXTENDED_2A30 0x2a30
--#define MTK_PHY_PAGE_EXTENDED_52B5 0x52b5
--
--#define ANALOG_INTERNAL_OPERATION_MAX_US 20
--#define TXRESERVE_MIN 0
--#define TXRESERVE_MAX 7
--
--#define MTK_PHY_ANARG_RG 0x10
--#define MTK_PHY_TCLKOFFSET_MASK GENMASK(12, 8)
--
--/* Registers on MDIO_MMD_VEND1 */
--#define MTK_PHY_TXVLD_DA_RG 0x12
--#define MTK_PHY_DA_TX_I2MPB_A_GBE_MASK GENMASK(15, 10)
--#define MTK_PHY_DA_TX_I2MPB_A_TBT_MASK GENMASK(5, 0)
--
--#define MTK_PHY_TX_I2MPB_TEST_MODE_A2 0x16
--#define MTK_PHY_DA_TX_I2MPB_A_HBT_MASK GENMASK(15, 10)
--#define MTK_PHY_DA_TX_I2MPB_A_TST_MASK GENMASK(5, 0)
--
--#define MTK_PHY_TX_I2MPB_TEST_MODE_B1 0x17
--#define MTK_PHY_DA_TX_I2MPB_B_GBE_MASK GENMASK(13, 8)
--#define MTK_PHY_DA_TX_I2MPB_B_TBT_MASK GENMASK(5, 0)
--
--#define MTK_PHY_TX_I2MPB_TEST_MODE_B2 0x18
--#define MTK_PHY_DA_TX_I2MPB_B_HBT_MASK GENMASK(13, 8)
--#define MTK_PHY_DA_TX_I2MPB_B_TST_MASK GENMASK(5, 0)
--
--#define MTK_PHY_TX_I2MPB_TEST_MODE_C1 0x19
--#define MTK_PHY_DA_TX_I2MPB_C_GBE_MASK GENMASK(13, 8)
--#define MTK_PHY_DA_TX_I2MPB_C_TBT_MASK GENMASK(5, 0)
--
--#define MTK_PHY_TX_I2MPB_TEST_MODE_C2 0x20
--#define MTK_PHY_DA_TX_I2MPB_C_HBT_MASK GENMASK(13, 8)
--#define MTK_PHY_DA_TX_I2MPB_C_TST_MASK GENMASK(5, 0)
--
--#define MTK_PHY_TX_I2MPB_TEST_MODE_D1 0x21
--#define MTK_PHY_DA_TX_I2MPB_D_GBE_MASK GENMASK(13, 8)
--#define MTK_PHY_DA_TX_I2MPB_D_TBT_MASK GENMASK(5, 0)
--
--#define MTK_PHY_TX_I2MPB_TEST_MODE_D2 0x22
--#define MTK_PHY_DA_TX_I2MPB_D_HBT_MASK GENMASK(13, 8)
--#define MTK_PHY_DA_TX_I2MPB_D_TST_MASK GENMASK(5, 0)
--
--#define MTK_PHY_RXADC_CTRL_RG7 0xc6
--#define MTK_PHY_DA_AD_BUF_BIAS_LP_MASK GENMASK(9, 8)
--
--#define MTK_PHY_RXADC_CTRL_RG9 0xc8
--#define MTK_PHY_DA_RX_PSBN_TBT_MASK GENMASK(14, 12)
--#define MTK_PHY_DA_RX_PSBN_HBT_MASK GENMASK(10, 8)
--#define MTK_PHY_DA_RX_PSBN_GBE_MASK GENMASK(6, 4)
--#define MTK_PHY_DA_RX_PSBN_LP_MASK GENMASK(2, 0)
--
--#define MTK_PHY_LDO_OUTPUT_V 0xd7
--
--#define MTK_PHY_RG_ANA_CAL_RG0 0xdb
--#define MTK_PHY_RG_CAL_CKINV BIT(12)
--#define MTK_PHY_RG_ANA_CALEN BIT(8)
--#define MTK_PHY_RG_ZCALEN_A BIT(0)
--
--#define MTK_PHY_RG_ANA_CAL_RG1 0xdc
--#define MTK_PHY_RG_ZCALEN_B BIT(12)
--#define MTK_PHY_RG_ZCALEN_C BIT(8)
--#define MTK_PHY_RG_ZCALEN_D BIT(4)
--#define MTK_PHY_RG_TXVOS_CALEN BIT(0)
--
--#define MTK_PHY_RG_ANA_CAL_RG5 0xe0
--#define MTK_PHY_RG_REXT_TRIM_MASK GENMASK(13, 8)
--
--#define MTK_PHY_RG_TX_FILTER 0xfe
--
--#define MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG120 0x120
--#define MTK_PHY_LPI_SIG_EN_LO_THRESH1000_MASK GENMASK(12, 8)
--#define MTK_PHY_LPI_SIG_EN_HI_THRESH1000_MASK GENMASK(4, 0)
--
--#define MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG122 0x122
--#define MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK GENMASK(7, 0)
--
--#define MTK_PHY_RG_TESTMUX_ADC_CTRL 0x144
--#define MTK_PHY_RG_TXEN_DIG_MASK GENMASK(5, 5)
--
--#define MTK_PHY_RG_CR_TX_AMP_OFFSET_A_B 0x172
--#define MTK_PHY_CR_TX_AMP_OFFSET_A_MASK GENMASK(13, 8)
--#define MTK_PHY_CR_TX_AMP_OFFSET_B_MASK GENMASK(6, 0)
--
--#define MTK_PHY_RG_CR_TX_AMP_OFFSET_C_D 0x173
--#define MTK_PHY_CR_TX_AMP_OFFSET_C_MASK GENMASK(13, 8)
--#define MTK_PHY_CR_TX_AMP_OFFSET_D_MASK GENMASK(6, 0)
--
--#define MTK_PHY_RG_AD_CAL_COMP 0x17a
--#define MTK_PHY_AD_CAL_COMP_OUT_MASK GENMASK(8, 8)
--
--#define MTK_PHY_RG_AD_CAL_CLK 0x17b
--#define MTK_PHY_DA_CAL_CLK BIT(0)
--
--#define MTK_PHY_RG_AD_CALIN 0x17c
--#define MTK_PHY_DA_CALIN_FLAG BIT(0)
--
--#define MTK_PHY_RG_DASN_DAC_IN0_A 0x17d
--#define MTK_PHY_DASN_DAC_IN0_A_MASK GENMASK(9, 0)
--
--#define MTK_PHY_RG_DASN_DAC_IN0_B 0x17e
--#define MTK_PHY_DASN_DAC_IN0_B_MASK GENMASK(9, 0)
--
--#define MTK_PHY_RG_DASN_DAC_IN0_C 0x17f
--#define MTK_PHY_DASN_DAC_IN0_C_MASK GENMASK(9, 0)
--
--#define MTK_PHY_RG_DASN_DAC_IN0_D 0x180
--#define MTK_PHY_DASN_DAC_IN0_D_MASK GENMASK(9, 0)
--
--#define MTK_PHY_RG_DASN_DAC_IN1_A 0x181
--#define MTK_PHY_DASN_DAC_IN1_A_MASK GENMASK(9, 0)
--
--#define MTK_PHY_RG_DASN_DAC_IN1_B 0x182
--#define MTK_PHY_DASN_DAC_IN1_B_MASK GENMASK(9, 0)
--
--#define MTK_PHY_RG_DASN_DAC_IN1_C 0x183
--#define MTK_PHY_DASN_DAC_IN1_C_MASK GENMASK(9, 0)
--
--#define MTK_PHY_RG_DASN_DAC_IN1_D 0x184
--#define MTK_PHY_DASN_DAC_IN1_D_MASK GENMASK(9, 0)
--
--#define MTK_PHY_RG_DEV1E_REG19b 0x19b
--#define MTK_PHY_BYPASS_DSP_LPI_READY BIT(8)
--
--#define MTK_PHY_RG_LP_IIR2_K1_L 0x22a
--#define MTK_PHY_RG_LP_IIR2_K1_U 0x22b
--#define MTK_PHY_RG_LP_IIR2_K2_L 0x22c
--#define MTK_PHY_RG_LP_IIR2_K2_U 0x22d
--#define MTK_PHY_RG_LP_IIR2_K3_L 0x22e
--#define MTK_PHY_RG_LP_IIR2_K3_U 0x22f
--#define MTK_PHY_RG_LP_IIR2_K4_L 0x230
--#define MTK_PHY_RG_LP_IIR2_K4_U 0x231
--#define MTK_PHY_RG_LP_IIR2_K5_L 0x232
--#define MTK_PHY_RG_LP_IIR2_K5_U 0x233
--
--#define MTK_PHY_RG_DEV1E_REG234 0x234
--#define MTK_PHY_TR_OPEN_LOOP_EN_MASK GENMASK(0, 0)
--#define MTK_PHY_LPF_X_AVERAGE_MASK GENMASK(7, 4)
--#define MTK_PHY_TR_LP_IIR_EEE_EN BIT(12)
--
--#define MTK_PHY_RG_LPF_CNT_VAL 0x235
--
--#define MTK_PHY_RG_DEV1E_REG238 0x238
--#define MTK_PHY_LPI_SLV_SEND_TX_TIMER_MASK GENMASK(8, 0)
--#define MTK_PHY_LPI_SLV_SEND_TX_EN BIT(12)
--
--#define MTK_PHY_RG_DEV1E_REG239 0x239
--#define MTK_PHY_LPI_SEND_LOC_TIMER_MASK GENMASK(8, 0)
--#define MTK_PHY_LPI_TXPCS_LOC_RCV BIT(12)
--
--#define MTK_PHY_RG_DEV1E_REG27C 0x27c
--#define MTK_PHY_VGASTATE_FFE_THR_ST1_MASK GENMASK(12, 8)
--#define MTK_PHY_RG_DEV1E_REG27D 0x27d
--#define MTK_PHY_VGASTATE_FFE_THR_ST2_MASK GENMASK(4, 0)
--
--#define MTK_PHY_RG_DEV1E_REG2C7 0x2c7
--#define MTK_PHY_MAX_GAIN_MASK GENMASK(4, 0)
--#define MTK_PHY_MIN_GAIN_MASK GENMASK(12, 8)
--
--#define MTK_PHY_RG_DEV1E_REG2D1 0x2d1
--#define MTK_PHY_VCO_SLICER_THRESH_BITS_HIGH_EEE_MASK GENMASK(7, 0)
--#define MTK_PHY_LPI_SKIP_SD_SLV_TR BIT(8)
--#define MTK_PHY_LPI_TR_READY BIT(9)
--#define MTK_PHY_LPI_VCO_EEE_STG0_EN BIT(10)
--
--#define MTK_PHY_RG_DEV1E_REG323 0x323
--#define MTK_PHY_EEE_WAKE_MAS_INT_DC BIT(0)
--#define MTK_PHY_EEE_WAKE_SLV_INT_DC BIT(4)
--
--#define MTK_PHY_RG_DEV1E_REG324 0x324
--#define MTK_PHY_SMI_DETCNT_MAX_MASK GENMASK(5, 0)
--#define MTK_PHY_SMI_DET_MAX_EN BIT(8)
--
--#define MTK_PHY_RG_DEV1E_REG326 0x326
--#define MTK_PHY_LPI_MODE_SD_ON BIT(0)
--#define MTK_PHY_RESET_RANDUPD_CNT BIT(1)
--#define MTK_PHY_TREC_UPDATE_ENAB_CLR BIT(2)
--#define MTK_PHY_LPI_QUIT_WAIT_DFE_SIG_DET_OFF BIT(4)
--#define MTK_PHY_TR_READY_SKIP_AFE_WAKEUP BIT(5)
--
--#define MTK_PHY_LDO_PUMP_EN_PAIRAB 0x502
--#define MTK_PHY_LDO_PUMP_EN_PAIRCD 0x503
--
--#define MTK_PHY_DA_TX_R50_PAIR_A 0x53d
--#define MTK_PHY_DA_TX_R50_PAIR_B 0x53e
--#define MTK_PHY_DA_TX_R50_PAIR_C 0x53f
--#define MTK_PHY_DA_TX_R50_PAIR_D 0x540
--
--/* Registers on MDIO_MMD_VEND2 */
--#define MTK_PHY_LED0_ON_CTRL 0x24
--#define MTK_PHY_LED1_ON_CTRL 0x26
--#define MTK_PHY_LED_ON_MASK GENMASK(6, 0)
--#define MTK_PHY_LED_ON_LINK1000 BIT(0)
--#define MTK_PHY_LED_ON_LINK100 BIT(1)
--#define MTK_PHY_LED_ON_LINK10 BIT(2)
--#define MTK_PHY_LED_ON_LINK (MTK_PHY_LED_ON_LINK10 |\
-- MTK_PHY_LED_ON_LINK100 |\
-- MTK_PHY_LED_ON_LINK1000)
--#define MTK_PHY_LED_ON_LINKDOWN BIT(3)
--#define MTK_PHY_LED_ON_FDX BIT(4) /* Full duplex */
--#define MTK_PHY_LED_ON_HDX BIT(5) /* Half duplex */
--#define MTK_PHY_LED_ON_FORCE_ON BIT(6)
--#define MTK_PHY_LED_ON_POLARITY BIT(14)
--#define MTK_PHY_LED_ON_ENABLE BIT(15)
--
--#define MTK_PHY_LED0_BLINK_CTRL 0x25
--#define MTK_PHY_LED1_BLINK_CTRL 0x27
--#define MTK_PHY_LED_BLINK_1000TX BIT(0)
--#define MTK_PHY_LED_BLINK_1000RX BIT(1)
--#define MTK_PHY_LED_BLINK_100TX BIT(2)
--#define MTK_PHY_LED_BLINK_100RX BIT(3)
--#define MTK_PHY_LED_BLINK_10TX BIT(4)
--#define MTK_PHY_LED_BLINK_10RX BIT(5)
--#define MTK_PHY_LED_BLINK_RX (MTK_PHY_LED_BLINK_10RX |\
-- MTK_PHY_LED_BLINK_100RX |\
-- MTK_PHY_LED_BLINK_1000RX)
--#define MTK_PHY_LED_BLINK_TX (MTK_PHY_LED_BLINK_10TX |\
-- MTK_PHY_LED_BLINK_100TX |\
-- MTK_PHY_LED_BLINK_1000TX)
--#define MTK_PHY_LED_BLINK_COLLISION BIT(6)
--#define MTK_PHY_LED_BLINK_RX_CRC_ERR BIT(7)
--#define MTK_PHY_LED_BLINK_RX_IDLE_ERR BIT(8)
--#define MTK_PHY_LED_BLINK_FORCE_BLINK BIT(9)
--
--#define MTK_PHY_LED1_DEFAULT_POLARITIES BIT(1)
--
--#define MTK_PHY_RG_BG_RASEL 0x115
--#define MTK_PHY_RG_BG_RASEL_MASK GENMASK(2, 0)
--
--/* 'boottrap' register reflecting the configuration of the 4 PHY LEDs */
--#define RG_GPIO_MISC_TPBANK0 0x6f0
--#define RG_GPIO_MISC_TPBANK0_BOOTMODE GENMASK(11, 8)
--
--/* These macro privides efuse parsing for internal phy. */
--#define EFS_DA_TX_I2MPB_A(x) (((x) >> 0) & GENMASK(5, 0))
--#define EFS_DA_TX_I2MPB_B(x) (((x) >> 6) & GENMASK(5, 0))
--#define EFS_DA_TX_I2MPB_C(x) (((x) >> 12) & GENMASK(5, 0))
--#define EFS_DA_TX_I2MPB_D(x) (((x) >> 18) & GENMASK(5, 0))
--#define EFS_DA_TX_AMP_OFFSET_A(x) (((x) >> 24) & GENMASK(5, 0))
--
--#define EFS_DA_TX_AMP_OFFSET_B(x) (((x) >> 0) & GENMASK(5, 0))
--#define EFS_DA_TX_AMP_OFFSET_C(x) (((x) >> 6) & GENMASK(5, 0))
--#define EFS_DA_TX_AMP_OFFSET_D(x) (((x) >> 12) & GENMASK(5, 0))
--#define EFS_DA_TX_R50_A(x) (((x) >> 18) & GENMASK(5, 0))
--#define EFS_DA_TX_R50_B(x) (((x) >> 24) & GENMASK(5, 0))
--
--#define EFS_DA_TX_R50_C(x) (((x) >> 0) & GENMASK(5, 0))
--#define EFS_DA_TX_R50_D(x) (((x) >> 6) & GENMASK(5, 0))
--
--#define EFS_RG_BG_RASEL(x) (((x) >> 4) & GENMASK(2, 0))
--#define EFS_RG_REXT_TRIM(x) (((x) >> 7) & GENMASK(5, 0))
--
--enum {
-- NO_PAIR,
-- PAIR_A,
-- PAIR_B,
-- PAIR_C,
-- PAIR_D,
--};
--
--enum calibration_mode {
-- EFUSE_K,
-- SW_K
--};
--
--enum CAL_ITEM {
-- REXT,
-- TX_OFFSET,
-- TX_AMP,
-- TX_R50,
-- TX_VCM
--};
--
--enum CAL_MODE {
-- EFUSE_M,
-- SW_M
--};
--
--#define MTK_PHY_LED_STATE_FORCE_ON 0
--#define MTK_PHY_LED_STATE_FORCE_BLINK 1
--#define MTK_PHY_LED_STATE_NETDEV 2
--
--struct mtk_socphy_priv {
-- unsigned long led_state;
--};
--
--struct mtk_socphy_shared {
-- u32 boottrap;
-- struct mtk_socphy_priv priv[4];
--};
--
--static int mtk_socphy_read_page(struct phy_device *phydev)
--{
-- return __phy_read(phydev, MTK_EXT_PAGE_ACCESS);
--}
--
--static int mtk_socphy_write_page(struct phy_device *phydev, int page)
--{
-- return __phy_write(phydev, MTK_EXT_PAGE_ACCESS, page);
--}
--
--/* One calibration cycle consists of:
-- * 1.Set DA_CALIN_FLAG high to start calibration. Keep it high
-- * until AD_CAL_COMP is ready to output calibration result.
-- * 2.Wait until DA_CAL_CLK is available.
-- * 3.Fetch AD_CAL_COMP_OUT.
-- */
--static int cal_cycle(struct phy_device *phydev, int devad,
-- u32 regnum, u16 mask, u16 cal_val)
--{
-- int reg_val;
-- int ret;
--
-- phy_modify_mmd(phydev, devad, regnum,
-- mask, cal_val);
-- phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_AD_CALIN,
-- MTK_PHY_DA_CALIN_FLAG);
--
-- ret = phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND1,
-- MTK_PHY_RG_AD_CAL_CLK, reg_val,
-- reg_val & MTK_PHY_DA_CAL_CLK, 500,
-- ANALOG_INTERNAL_OPERATION_MAX_US,
-- false);
-- if (ret) {
-- phydev_err(phydev, "Calibration cycle timeout\n");
-- return ret;
-- }
--
-- phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_AD_CALIN,
-- MTK_PHY_DA_CALIN_FLAG);
-- ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_AD_CAL_COMP);
-- if (ret < 0)
-- return ret;
-- ret = FIELD_GET(MTK_PHY_AD_CAL_COMP_OUT_MASK, ret);
-- phydev_dbg(phydev, "cal_val: 0x%x, ret: %d\n", cal_val, ret);
--
-- return ret;
--}
--
--static int rext_fill_result(struct phy_device *phydev, u16 *buf)
--{
-- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG5,
-- MTK_PHY_RG_REXT_TRIM_MASK, buf[0] << 8);
-- phy_modify_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_RG_BG_RASEL,
-- MTK_PHY_RG_BG_RASEL_MASK, buf[1]);
--
-- return 0;
--}
--
--static int rext_cal_efuse(struct phy_device *phydev, u32 *buf)
--{
-- u16 rext_cal_val[2];
--
-- rext_cal_val[0] = EFS_RG_REXT_TRIM(buf[3]);
-- rext_cal_val[1] = EFS_RG_BG_RASEL(buf[3]);
-- rext_fill_result(phydev, rext_cal_val);
--
-- return 0;
--}
--
--static int tx_offset_fill_result(struct phy_device *phydev, u16 *buf)
--{
-- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_CR_TX_AMP_OFFSET_A_B,
-- MTK_PHY_CR_TX_AMP_OFFSET_A_MASK, buf[0] << 8);
-- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_CR_TX_AMP_OFFSET_A_B,
-- MTK_PHY_CR_TX_AMP_OFFSET_B_MASK, buf[1]);
-- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_CR_TX_AMP_OFFSET_C_D,
-- MTK_PHY_CR_TX_AMP_OFFSET_C_MASK, buf[2] << 8);
-- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_CR_TX_AMP_OFFSET_C_D,
-- MTK_PHY_CR_TX_AMP_OFFSET_D_MASK, buf[3]);
--
-- return 0;
--}
--
--static int tx_offset_cal_efuse(struct phy_device *phydev, u32 *buf)
--{
-- u16 tx_offset_cal_val[4];
--
-- tx_offset_cal_val[0] = EFS_DA_TX_AMP_OFFSET_A(buf[0]);
-- tx_offset_cal_val[1] = EFS_DA_TX_AMP_OFFSET_B(buf[1]);
-- tx_offset_cal_val[2] = EFS_DA_TX_AMP_OFFSET_C(buf[1]);
-- tx_offset_cal_val[3] = EFS_DA_TX_AMP_OFFSET_D(buf[1]);
--
-- tx_offset_fill_result(phydev, tx_offset_cal_val);
--
-- return 0;
--}
--
--static int tx_amp_fill_result(struct phy_device *phydev, u16 *buf)
--{
-- const int vals_9481[16] = { 10, 6, 6, 10,
-- 10, 6, 6, 10,
-- 10, 6, 6, 10,
-- 10, 6, 6, 10 };
-- const int vals_9461[16] = { 7, 1, 4, 7,
-- 7, 1, 4, 7,
-- 7, 1, 4, 7,
-- 7, 1, 4, 7 };
-- int bias[16] = {};
-- int i;
--
-- switch (phydev->drv->phy_id) {
-- case MTK_GPHY_ID_MT7981:
-- /* We add some calibration to efuse values
-- * due to board level influence.
-- * GBE: +7, TBT: +1, HBT: +4, TST: +7
-- */
-- memcpy(bias, (const void *)vals_9461, sizeof(bias));
-- break;
-- case MTK_GPHY_ID_MT7988:
-- memcpy(bias, (const void *)vals_9481, sizeof(bias));
-- break;
-- }
--
-- /* Prevent overflow */
-- for (i = 0; i < 12; i++) {
-- if (buf[i >> 2] + bias[i] > 63) {
-- buf[i >> 2] = 63;
-- bias[i] = 0;
-- }
-- }
--
-- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TXVLD_DA_RG,
-- MTK_PHY_DA_TX_I2MPB_A_GBE_MASK,
-- FIELD_PREP(MTK_PHY_DA_TX_I2MPB_A_GBE_MASK,
-- buf[0] + bias[0]));
-- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TXVLD_DA_RG,
-- MTK_PHY_DA_TX_I2MPB_A_TBT_MASK,
-- FIELD_PREP(MTK_PHY_DA_TX_I2MPB_A_TBT_MASK,
-- buf[0] + bias[1]));
-- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_A2,
-- MTK_PHY_DA_TX_I2MPB_A_HBT_MASK,
-- FIELD_PREP(MTK_PHY_DA_TX_I2MPB_A_HBT_MASK,
-- buf[0] + bias[2]));
-- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_A2,
-- MTK_PHY_DA_TX_I2MPB_A_TST_MASK,
-- FIELD_PREP(MTK_PHY_DA_TX_I2MPB_A_TST_MASK,
-- buf[0] + bias[3]));
--
-- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B1,
-- MTK_PHY_DA_TX_I2MPB_B_GBE_MASK,
-- FIELD_PREP(MTK_PHY_DA_TX_I2MPB_B_GBE_MASK,
-- buf[1] + bias[4]));
-- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B1,
-- MTK_PHY_DA_TX_I2MPB_B_TBT_MASK,
-- FIELD_PREP(MTK_PHY_DA_TX_I2MPB_B_TBT_MASK,
-- buf[1] + bias[5]));
-- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B2,
-- MTK_PHY_DA_TX_I2MPB_B_HBT_MASK,
-- FIELD_PREP(MTK_PHY_DA_TX_I2MPB_B_HBT_MASK,
-- buf[1] + bias[6]));
-- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B2,
-- MTK_PHY_DA_TX_I2MPB_B_TST_MASK,
-- FIELD_PREP(MTK_PHY_DA_TX_I2MPB_B_TST_MASK,
-- buf[1] + bias[7]));
--
-- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C1,
-- MTK_PHY_DA_TX_I2MPB_C_GBE_MASK,
-- FIELD_PREP(MTK_PHY_DA_TX_I2MPB_C_GBE_MASK,
-- buf[2] + bias[8]));
-- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C1,
-- MTK_PHY_DA_TX_I2MPB_C_TBT_MASK,
-- FIELD_PREP(MTK_PHY_DA_TX_I2MPB_C_TBT_MASK,
-- buf[2] + bias[9]));
-- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C2,
-- MTK_PHY_DA_TX_I2MPB_C_HBT_MASK,
-- FIELD_PREP(MTK_PHY_DA_TX_I2MPB_C_HBT_MASK,
-- buf[2] + bias[10]));
-- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C2,
-- MTK_PHY_DA_TX_I2MPB_C_TST_MASK,
-- FIELD_PREP(MTK_PHY_DA_TX_I2MPB_C_TST_MASK,
-- buf[2] + bias[11]));
--
-- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D1,
-- MTK_PHY_DA_TX_I2MPB_D_GBE_MASK,
-- FIELD_PREP(MTK_PHY_DA_TX_I2MPB_D_GBE_MASK,
-- buf[3] + bias[12]));
-- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D1,
-- MTK_PHY_DA_TX_I2MPB_D_TBT_MASK,
-- FIELD_PREP(MTK_PHY_DA_TX_I2MPB_D_TBT_MASK,
-- buf[3] + bias[13]));
-- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D2,
-- MTK_PHY_DA_TX_I2MPB_D_HBT_MASK,
-- FIELD_PREP(MTK_PHY_DA_TX_I2MPB_D_HBT_MASK,
-- buf[3] + bias[14]));
-- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D2,
-- MTK_PHY_DA_TX_I2MPB_D_TST_MASK,
-- FIELD_PREP(MTK_PHY_DA_TX_I2MPB_D_TST_MASK,
-- buf[3] + bias[15]));
--
-- return 0;
--}
--
--static int tx_amp_cal_efuse(struct phy_device *phydev, u32 *buf)
--{
-- u16 tx_amp_cal_val[4];
--
-- tx_amp_cal_val[0] = EFS_DA_TX_I2MPB_A(buf[0]);
-- tx_amp_cal_val[1] = EFS_DA_TX_I2MPB_B(buf[0]);
-- tx_amp_cal_val[2] = EFS_DA_TX_I2MPB_C(buf[0]);
-- tx_amp_cal_val[3] = EFS_DA_TX_I2MPB_D(buf[0]);
-- tx_amp_fill_result(phydev, tx_amp_cal_val);
--
-- return 0;
--}
--
--static int tx_r50_fill_result(struct phy_device *phydev, u16 tx_r50_cal_val,
-- u8 txg_calen_x)
--{
-- int bias = 0;
-- u16 reg, val;
--
-- if (phydev->drv->phy_id == MTK_GPHY_ID_MT7988)
-- bias = -1;
--
-- val = clamp_val(bias + tx_r50_cal_val, 0, 63);
--
-- switch (txg_calen_x) {
-- case PAIR_A:
-- reg = MTK_PHY_DA_TX_R50_PAIR_A;
-- break;
-- case PAIR_B:
-- reg = MTK_PHY_DA_TX_R50_PAIR_B;
-- break;
-- case PAIR_C:
-- reg = MTK_PHY_DA_TX_R50_PAIR_C;
-- break;
-- case PAIR_D:
-- reg = MTK_PHY_DA_TX_R50_PAIR_D;
-- break;
-- default:
-- return -EINVAL;
-- }
--
-- phy_write_mmd(phydev, MDIO_MMD_VEND1, reg, val | val << 8);
--
-- return 0;
--}
--
--static int tx_r50_cal_efuse(struct phy_device *phydev, u32 *buf,
-- u8 txg_calen_x)
--{
-- u16 tx_r50_cal_val;
--
-- switch (txg_calen_x) {
-- case PAIR_A:
-- tx_r50_cal_val = EFS_DA_TX_R50_A(buf[1]);
-- break;
-- case PAIR_B:
-- tx_r50_cal_val = EFS_DA_TX_R50_B(buf[1]);
-- break;
-- case PAIR_C:
-- tx_r50_cal_val = EFS_DA_TX_R50_C(buf[2]);
-- break;
-- case PAIR_D:
-- tx_r50_cal_val = EFS_DA_TX_R50_D(buf[2]);
-- break;
-- default:
-- return -EINVAL;
-- }
-- tx_r50_fill_result(phydev, tx_r50_cal_val, txg_calen_x);
--
-- return 0;
--}
--
--static int tx_vcm_cal_sw(struct phy_device *phydev, u8 rg_txreserve_x)
--{
-- u8 lower_idx, upper_idx, txreserve_val;
-- u8 lower_ret, upper_ret;
-- int ret;
--
-- phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0,
-- MTK_PHY_RG_ANA_CALEN);
-- phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0,
-- MTK_PHY_RG_CAL_CKINV);
-- phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1,
-- MTK_PHY_RG_TXVOS_CALEN);
--
-- switch (rg_txreserve_x) {
-- case PAIR_A:
-- phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
-- MTK_PHY_RG_DASN_DAC_IN0_A,
-- MTK_PHY_DASN_DAC_IN0_A_MASK);
-- phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
-- MTK_PHY_RG_DASN_DAC_IN1_A,
-- MTK_PHY_DASN_DAC_IN1_A_MASK);
-- phy_set_bits_mmd(phydev, MDIO_MMD_VEND1,
-- MTK_PHY_RG_ANA_CAL_RG0,
-- MTK_PHY_RG_ZCALEN_A);
-- break;
-- case PAIR_B:
-- phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
-- MTK_PHY_RG_DASN_DAC_IN0_B,
-- MTK_PHY_DASN_DAC_IN0_B_MASK);
-- phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
-- MTK_PHY_RG_DASN_DAC_IN1_B,
-- MTK_PHY_DASN_DAC_IN1_B_MASK);
-- phy_set_bits_mmd(phydev, MDIO_MMD_VEND1,
-- MTK_PHY_RG_ANA_CAL_RG1,
-- MTK_PHY_RG_ZCALEN_B);
-- break;
-- case PAIR_C:
-- phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
-- MTK_PHY_RG_DASN_DAC_IN0_C,
-- MTK_PHY_DASN_DAC_IN0_C_MASK);
-- phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
-- MTK_PHY_RG_DASN_DAC_IN1_C,
-- MTK_PHY_DASN_DAC_IN1_C_MASK);
-- phy_set_bits_mmd(phydev, MDIO_MMD_VEND1,
-- MTK_PHY_RG_ANA_CAL_RG1,
-- MTK_PHY_RG_ZCALEN_C);
-- break;
-- case PAIR_D:
-- phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
-- MTK_PHY_RG_DASN_DAC_IN0_D,
-- MTK_PHY_DASN_DAC_IN0_D_MASK);
-- phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
-- MTK_PHY_RG_DASN_DAC_IN1_D,
-- MTK_PHY_DASN_DAC_IN1_D_MASK);
-- phy_set_bits_mmd(phydev, MDIO_MMD_VEND1,
-- MTK_PHY_RG_ANA_CAL_RG1,
-- MTK_PHY_RG_ZCALEN_D);
-- break;
-- default:
-- ret = -EINVAL;
-- goto restore;
-- }
--
-- lower_idx = TXRESERVE_MIN;
-- upper_idx = TXRESERVE_MAX;
--
-- phydev_dbg(phydev, "Start TX-VCM SW cal.\n");
-- while ((upper_idx - lower_idx) > 1) {
-- txreserve_val = DIV_ROUND_CLOSEST(lower_idx + upper_idx, 2);
-- ret = cal_cycle(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG9,
-- MTK_PHY_DA_RX_PSBN_TBT_MASK |
-- MTK_PHY_DA_RX_PSBN_HBT_MASK |
-- MTK_PHY_DA_RX_PSBN_GBE_MASK |
-- MTK_PHY_DA_RX_PSBN_LP_MASK,
-- txreserve_val << 12 | txreserve_val << 8 |
-- txreserve_val << 4 | txreserve_val);
-- if (ret == 1) {
-- upper_idx = txreserve_val;
-- upper_ret = ret;
-- } else if (ret == 0) {
-- lower_idx = txreserve_val;
-- lower_ret = ret;
-- } else {
-- goto restore;
-- }
-- }
--
-- if (lower_idx == TXRESERVE_MIN) {
-- lower_ret = cal_cycle(phydev, MDIO_MMD_VEND1,
-- MTK_PHY_RXADC_CTRL_RG9,
-- MTK_PHY_DA_RX_PSBN_TBT_MASK |
-- MTK_PHY_DA_RX_PSBN_HBT_MASK |
-- MTK_PHY_DA_RX_PSBN_GBE_MASK |
-- MTK_PHY_DA_RX_PSBN_LP_MASK,
-- lower_idx << 12 | lower_idx << 8 |
-- lower_idx << 4 | lower_idx);
-- ret = lower_ret;
-- } else if (upper_idx == TXRESERVE_MAX) {
-- upper_ret = cal_cycle(phydev, MDIO_MMD_VEND1,
-- MTK_PHY_RXADC_CTRL_RG9,
-- MTK_PHY_DA_RX_PSBN_TBT_MASK |
-- MTK_PHY_DA_RX_PSBN_HBT_MASK |
-- MTK_PHY_DA_RX_PSBN_GBE_MASK |
-- MTK_PHY_DA_RX_PSBN_LP_MASK,
-- upper_idx << 12 | upper_idx << 8 |
-- upper_idx << 4 | upper_idx);
-- ret = upper_ret;
-- }
-- if (ret < 0)
-- goto restore;
--
-- /* We calibrate TX-VCM in different logic. Check upper index and then
-- * lower index. If this calibration is valid, apply lower index's
-- * result.
-- */
-- ret = upper_ret - lower_ret;
-- if (ret == 1) {
-- ret = 0;
-- /* Make sure we use upper_idx in our calibration system */
-- cal_cycle(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG9,
-- MTK_PHY_DA_RX_PSBN_TBT_MASK |
-- MTK_PHY_DA_RX_PSBN_HBT_MASK |
-- MTK_PHY_DA_RX_PSBN_GBE_MASK |
-- MTK_PHY_DA_RX_PSBN_LP_MASK,
-- upper_idx << 12 | upper_idx << 8 |
-- upper_idx << 4 | upper_idx);
-- phydev_dbg(phydev, "TX-VCM SW cal result: 0x%x\n", upper_idx);
-- } else if (lower_idx == TXRESERVE_MIN && upper_ret == 1 &&
-- lower_ret == 1) {
-- ret = 0;
-- cal_cycle(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG9,
-- MTK_PHY_DA_RX_PSBN_TBT_MASK |
-- MTK_PHY_DA_RX_PSBN_HBT_MASK |
-- MTK_PHY_DA_RX_PSBN_GBE_MASK |
-- MTK_PHY_DA_RX_PSBN_LP_MASK,
-- lower_idx << 12 | lower_idx << 8 |
-- lower_idx << 4 | lower_idx);
-- phydev_warn(phydev, "TX-VCM SW cal result at low margin 0x%x\n",
-- lower_idx);
-- } else if (upper_idx == TXRESERVE_MAX && upper_ret == 0 &&
-- lower_ret == 0) {
-- ret = 0;
-- phydev_warn(phydev,
-- "TX-VCM SW cal result at high margin 0x%x\n",
-- upper_idx);
-- } else {
-- ret = -EINVAL;
-- }
--
--restore:
-- phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0,
-- MTK_PHY_RG_ANA_CALEN);
-- phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1,
-- MTK_PHY_RG_TXVOS_CALEN);
-- phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0,
-- MTK_PHY_RG_ZCALEN_A);
-- phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1,
-- MTK_PHY_RG_ZCALEN_B | MTK_PHY_RG_ZCALEN_C |
-- MTK_PHY_RG_ZCALEN_D);
--
-- return ret;
--}
--
--static void mt798x_phy_common_finetune(struct phy_device *phydev)
--{
-- phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
-- /* SlvDSPreadyTime = 24, MasDSPreadyTime = 24 */
-- __phy_write(phydev, 0x11, 0xc71);
-- __phy_write(phydev, 0x12, 0xc);
-- __phy_write(phydev, 0x10, 0x8fae);
--
-- /* EnabRandUpdTrig = 1 */
-- __phy_write(phydev, 0x11, 0x2f00);
-- __phy_write(phydev, 0x12, 0xe);
-- __phy_write(phydev, 0x10, 0x8fb0);
--
-- /* NormMseLoThresh = 85 */
-- __phy_write(phydev, 0x11, 0x55a0);
-- __phy_write(phydev, 0x12, 0x0);
-- __phy_write(phydev, 0x10, 0x83aa);
--
-- /* FfeUpdGainForce = 1(Enable), FfeUpdGainForceVal = 4 */
-- __phy_write(phydev, 0x11, 0x240);
-- __phy_write(phydev, 0x12, 0x0);
-- __phy_write(phydev, 0x10, 0x9680);
--
-- /* TrFreeze = 0 (mt7988 default) */
-- __phy_write(phydev, 0x11, 0x0);
-- __phy_write(phydev, 0x12, 0x0);
-- __phy_write(phydev, 0x10, 0x9686);
--
-- /* SSTrKp100 = 5 */
-- /* SSTrKf100 = 6 */
-- /* SSTrKp1000Mas = 5 */
-- /* SSTrKf1000Mas = 6 */
-- /* SSTrKp1000Slv = 5 */
-- /* SSTrKf1000Slv = 6 */
-- __phy_write(phydev, 0x11, 0xbaef);
-- __phy_write(phydev, 0x12, 0x2e);
-- __phy_write(phydev, 0x10, 0x968c);
-- phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
--}
--
--static void mt7981_phy_finetune(struct phy_device *phydev)
--{
-- u16 val[8] = { 0x01ce, 0x01c1,
-- 0x020f, 0x0202,
-- 0x03d0, 0x03c0,
-- 0x0013, 0x0005 };
-- int i, k;
--
-- /* 100M eye finetune:
-- * Keep middle level of TX MLT3 shapper as default.
-- * Only change TX MLT3 overshoot level here.
-- */
-- for (k = 0, i = 1; i < 12; i++) {
-- if (i % 3 == 0)
-- continue;
-- phy_write_mmd(phydev, MDIO_MMD_VEND1, i, val[k++]);
-- }
--
-- phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
-- /* ResetSyncOffset = 6 */
-- __phy_write(phydev, 0x11, 0x600);
-- __phy_write(phydev, 0x12, 0x0);
-- __phy_write(phydev, 0x10, 0x8fc0);
--
-- /* VgaDecRate = 1 */
-- __phy_write(phydev, 0x11, 0x4c2a);
-- __phy_write(phydev, 0x12, 0x3e);
-- __phy_write(phydev, 0x10, 0x8fa4);
--
-- /* MrvlTrFix100Kp = 3, MrvlTrFix100Kf = 2,
-- * MrvlTrFix1000Kp = 3, MrvlTrFix1000Kf = 2
-- */
-- __phy_write(phydev, 0x11, 0xd10a);
-- __phy_write(phydev, 0x12, 0x34);
-- __phy_write(phydev, 0x10, 0x8f82);
--
-- /* VcoSlicerThreshBitsHigh */
-- __phy_write(phydev, 0x11, 0x5555);
-- __phy_write(phydev, 0x12, 0x55);
-- __phy_write(phydev, 0x10, 0x8ec0);
-- phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
--
-- /* TR_OPEN_LOOP_EN = 1, lpf_x_average = 9 */
-- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG234,
-- MTK_PHY_TR_OPEN_LOOP_EN_MASK |
-- MTK_PHY_LPF_X_AVERAGE_MASK,
-- BIT(0) | FIELD_PREP(MTK_PHY_LPF_X_AVERAGE_MASK, 0x9));
--
-- /* rg_tr_lpf_cnt_val = 512 */
-- phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LPF_CNT_VAL, 0x200);
--
-- /* IIR2 related */
-- phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K1_L, 0x82);
-- phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K1_U, 0x0);
-- phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K2_L, 0x103);
-- phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K2_U, 0x0);
-- phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K3_L, 0x82);
-- phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K3_U, 0x0);
-- phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K4_L, 0xd177);
-- phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K4_U, 0x3);
-- phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K5_L, 0x2c82);
-- phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K5_U, 0xe);
--
-- /* FFE peaking */
-- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG27C,
-- MTK_PHY_VGASTATE_FFE_THR_ST1_MASK, 0x1b << 8);
-- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG27D,
-- MTK_PHY_VGASTATE_FFE_THR_ST2_MASK, 0x1e);
--
-- /* Disable LDO pump */
-- phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_LDO_PUMP_EN_PAIRAB, 0x0);
-- phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_LDO_PUMP_EN_PAIRCD, 0x0);
-- /* Adjust LDO output voltage */
-- phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_LDO_OUTPUT_V, 0x2222);
--}
--
--static void mt7988_phy_finetune(struct phy_device *phydev)
--{
-- u16 val[12] = { 0x0187, 0x01cd, 0x01c8, 0x0182,
-- 0x020d, 0x0206, 0x0384, 0x03d0,
-- 0x03c6, 0x030a, 0x0011, 0x0005 };
-- int i;
--
-- /* Set default MLT3 shaper first */
-- for (i = 0; i < 12; i++)
-- phy_write_mmd(phydev, MDIO_MMD_VEND1, i, val[i]);
--
-- /* TCT finetune */
-- phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_TX_FILTER, 0x5);
--
-- phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
-- /* ResetSyncOffset = 5 */
-- __phy_write(phydev, 0x11, 0x500);
-- __phy_write(phydev, 0x12, 0x0);
-- __phy_write(phydev, 0x10, 0x8fc0);
--
-- /* VgaDecRate is 1 at default on mt7988 */
--
-- /* MrvlTrFix100Kp = 6, MrvlTrFix100Kf = 7,
-- * MrvlTrFix1000Kp = 6, MrvlTrFix1000Kf = 7
-- */
-- __phy_write(phydev, 0x11, 0xb90a);
-- __phy_write(phydev, 0x12, 0x6f);
-- __phy_write(phydev, 0x10, 0x8f82);
--
-- /* RemAckCntLimitCtrl = 1 */
-- __phy_write(phydev, 0x11, 0xfbba);
-- __phy_write(phydev, 0x12, 0xc3);
-- __phy_write(phydev, 0x10, 0x87f8);
--
-- phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
--
-- /* TR_OPEN_LOOP_EN = 1, lpf_x_average = 10 */
-- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG234,
-- MTK_PHY_TR_OPEN_LOOP_EN_MASK |
-- MTK_PHY_LPF_X_AVERAGE_MASK,
-- BIT(0) | FIELD_PREP(MTK_PHY_LPF_X_AVERAGE_MASK, 0xa));
--
-- /* rg_tr_lpf_cnt_val = 1023 */
-- phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LPF_CNT_VAL, 0x3ff);
--}
--
--static void mt798x_phy_eee(struct phy_device *phydev)
--{
-- phy_modify_mmd(phydev, MDIO_MMD_VEND1,
-- MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG120,
-- MTK_PHY_LPI_SIG_EN_LO_THRESH1000_MASK |
-- MTK_PHY_LPI_SIG_EN_HI_THRESH1000_MASK,
-- FIELD_PREP(MTK_PHY_LPI_SIG_EN_LO_THRESH1000_MASK, 0x0) |
-- FIELD_PREP(MTK_PHY_LPI_SIG_EN_HI_THRESH1000_MASK, 0x14));
--
-- phy_modify_mmd(phydev, MDIO_MMD_VEND1,
-- MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG122,
-- MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK,
-- FIELD_PREP(MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK,
-- 0xff));
--
-- phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
-- MTK_PHY_RG_TESTMUX_ADC_CTRL,
-- MTK_PHY_RG_TXEN_DIG_MASK);
--
-- phy_set_bits_mmd(phydev, MDIO_MMD_VEND1,
-- MTK_PHY_RG_DEV1E_REG19b, MTK_PHY_BYPASS_DSP_LPI_READY);
--
-- phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
-- MTK_PHY_RG_DEV1E_REG234, MTK_PHY_TR_LP_IIR_EEE_EN);
--
-- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG238,
-- MTK_PHY_LPI_SLV_SEND_TX_TIMER_MASK |
-- MTK_PHY_LPI_SLV_SEND_TX_EN,
-- FIELD_PREP(MTK_PHY_LPI_SLV_SEND_TX_TIMER_MASK, 0x120));
--
-- /* Keep MTK_PHY_LPI_SEND_LOC_TIMER as 375 */
-- phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG239,
-- MTK_PHY_LPI_TXPCS_LOC_RCV);
--
-- /* This also fixes some IoT issues, such as CH340 */
-- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG2C7,
-- MTK_PHY_MAX_GAIN_MASK | MTK_PHY_MIN_GAIN_MASK,
-- FIELD_PREP(MTK_PHY_MAX_GAIN_MASK, 0x8) |
-- FIELD_PREP(MTK_PHY_MIN_GAIN_MASK, 0x13));
--
-- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG2D1,
-- MTK_PHY_VCO_SLICER_THRESH_BITS_HIGH_EEE_MASK,
-- FIELD_PREP(MTK_PHY_VCO_SLICER_THRESH_BITS_HIGH_EEE_MASK,
-- 0x33) |
-- MTK_PHY_LPI_SKIP_SD_SLV_TR | MTK_PHY_LPI_TR_READY |
-- MTK_PHY_LPI_VCO_EEE_STG0_EN);
--
-- phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG323,
-- MTK_PHY_EEE_WAKE_MAS_INT_DC |
-- MTK_PHY_EEE_WAKE_SLV_INT_DC);
--
-- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG324,
-- MTK_PHY_SMI_DETCNT_MAX_MASK,
-- FIELD_PREP(MTK_PHY_SMI_DETCNT_MAX_MASK, 0x3f) |
-- MTK_PHY_SMI_DET_MAX_EN);
--
-- phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG326,
-- MTK_PHY_LPI_MODE_SD_ON | MTK_PHY_RESET_RANDUPD_CNT |
-- MTK_PHY_TREC_UPDATE_ENAB_CLR |
-- MTK_PHY_LPI_QUIT_WAIT_DFE_SIG_DET_OFF |
-- MTK_PHY_TR_READY_SKIP_AFE_WAKEUP);
--
-- phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
-- /* Regsigdet_sel_1000 = 0 */
-- __phy_write(phydev, 0x11, 0xb);
-- __phy_write(phydev, 0x12, 0x0);
-- __phy_write(phydev, 0x10, 0x9690);
--
-- /* REG_EEE_st2TrKf1000 = 2 */
-- __phy_write(phydev, 0x11, 0x114f);
-- __phy_write(phydev, 0x12, 0x2);
-- __phy_write(phydev, 0x10, 0x969a);
--
-- /* RegEEE_slv_wake_tr_timer_tar = 6, RegEEE_slv_remtx_timer_tar = 20 */
-- __phy_write(phydev, 0x11, 0x3028);
-- __phy_write(phydev, 0x12, 0x0);
-- __phy_write(phydev, 0x10, 0x969e);
--
-- /* RegEEE_slv_wake_int_timer_tar = 8 */
-- __phy_write(phydev, 0x11, 0x5010);
-- __phy_write(phydev, 0x12, 0x0);
-- __phy_write(phydev, 0x10, 0x96a0);
--
-- /* RegEEE_trfreeze_timer2 = 586 */
-- __phy_write(phydev, 0x11, 0x24a);
-- __phy_write(phydev, 0x12, 0x0);
-- __phy_write(phydev, 0x10, 0x96a8);
--
-- /* RegEEE100Stg1_tar = 16 */
-- __phy_write(phydev, 0x11, 0x3210);
-- __phy_write(phydev, 0x12, 0x0);
-- __phy_write(phydev, 0x10, 0x96b8);
--
-- /* REGEEE_wake_slv_tr_wait_dfesigdet_en = 0 */
-- __phy_write(phydev, 0x11, 0x1463);
-- __phy_write(phydev, 0x12, 0x0);
-- __phy_write(phydev, 0x10, 0x96ca);
--
-- /* DfeTailEnableVgaThresh1000 = 27 */
-- __phy_write(phydev, 0x11, 0x36);
-- __phy_write(phydev, 0x12, 0x0);
-- __phy_write(phydev, 0x10, 0x8f80);
-- phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
--
-- phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_3);
-- __phy_modify(phydev, MTK_PHY_LPI_REG_14,
-- MTK_PHY_LPI_WAKE_TIMER_1000_MASK,
-- FIELD_PREP(MTK_PHY_LPI_WAKE_TIMER_1000_MASK, 0x19c));
--
-- __phy_modify(phydev, MTK_PHY_LPI_REG_1c, MTK_PHY_SMI_DET_ON_THRESH_MASK,
-- FIELD_PREP(MTK_PHY_SMI_DET_ON_THRESH_MASK, 0xc));
-- phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
--
-- phy_modify_mmd(phydev, MDIO_MMD_VEND1,
-- MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG122,
-- MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK,
-- FIELD_PREP(MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK,
-- 0xff));
--}
--
--static int cal_sw(struct phy_device *phydev, enum CAL_ITEM cal_item,
-- u8 start_pair, u8 end_pair)
--{
-- u8 pair_n;
-- int ret;
--
-- for (pair_n = start_pair; pair_n <= end_pair; pair_n++) {
-- /* TX_OFFSET & TX_AMP have no SW calibration. */
-- switch (cal_item) {
-- case TX_VCM:
-- ret = tx_vcm_cal_sw(phydev, pair_n);
-- break;
-- default:
-- return -EINVAL;
-- }
-- if (ret)
-- return ret;
-- }
-- return 0;
--}
--
--static int cal_efuse(struct phy_device *phydev, enum CAL_ITEM cal_item,
-- u8 start_pair, u8 end_pair, u32 *buf)
--{
-- u8 pair_n;
-- int ret;
--
-- for (pair_n = start_pair; pair_n <= end_pair; pair_n++) {
-- /* TX_VCM has no efuse calibration. */
-- switch (cal_item) {
-- case REXT:
-- ret = rext_cal_efuse(phydev, buf);
-- break;
-- case TX_OFFSET:
-- ret = tx_offset_cal_efuse(phydev, buf);
-- break;
-- case TX_AMP:
-- ret = tx_amp_cal_efuse(phydev, buf);
-- break;
-- case TX_R50:
-- ret = tx_r50_cal_efuse(phydev, buf, pair_n);
-- break;
-- default:
-- return -EINVAL;
-- }
-- if (ret)
-- return ret;
-- }
--
-- return 0;
--}
--
--static int start_cal(struct phy_device *phydev, enum CAL_ITEM cal_item,
-- enum CAL_MODE cal_mode, u8 start_pair,
-- u8 end_pair, u32 *buf)
--{
-- int ret;
--
-- switch (cal_mode) {
-- case EFUSE_M:
-- ret = cal_efuse(phydev, cal_item, start_pair,
-- end_pair, buf);
-- break;
-- case SW_M:
-- ret = cal_sw(phydev, cal_item, start_pair, end_pair);
-- break;
-- default:
-- return -EINVAL;
-- }
--
-- if (ret) {
-- phydev_err(phydev, "cal %d failed\n", cal_item);
-- return -EIO;
-- }
--
-- return 0;
--}
--
--static int mt798x_phy_calibration(struct phy_device *phydev)
--{
-- struct nvmem_cell *cell;
-- int ret = 0;
-- size_t len;
-- u32 *buf;
--
-- cell = nvmem_cell_get(&phydev->mdio.dev, "phy-cal-data");
-- if (IS_ERR(cell)) {
-- if (PTR_ERR(cell) == -EPROBE_DEFER)
-- return PTR_ERR(cell);
-- return 0;
-- }
--
-- buf = (u32 *)nvmem_cell_read(cell, &len);
-- if (IS_ERR(buf))
-- return PTR_ERR(buf);
-- nvmem_cell_put(cell);
--
-- if (!buf[0] || !buf[1] || !buf[2] || !buf[3] || len < 4 * sizeof(u32)) {
-- phydev_err(phydev, "invalid efuse data\n");
-- ret = -EINVAL;
-- goto out;
-- }
--
-- ret = start_cal(phydev, REXT, EFUSE_M, NO_PAIR, NO_PAIR, buf);
-- if (ret)
-- goto out;
-- ret = start_cal(phydev, TX_OFFSET, EFUSE_M, NO_PAIR, NO_PAIR, buf);
-- if (ret)
-- goto out;
-- ret = start_cal(phydev, TX_AMP, EFUSE_M, NO_PAIR, NO_PAIR, buf);
-- if (ret)
-- goto out;
-- ret = start_cal(phydev, TX_R50, EFUSE_M, PAIR_A, PAIR_D, buf);
-- if (ret)
-- goto out;
-- ret = start_cal(phydev, TX_VCM, SW_M, PAIR_A, PAIR_A, buf);
-- if (ret)
-- goto out;
--
--out:
-- kfree(buf);
-- return ret;
--}
--
--static int mt798x_phy_config_init(struct phy_device *phydev)
--{
-- switch (phydev->drv->phy_id) {
-- case MTK_GPHY_ID_MT7981:
-- mt7981_phy_finetune(phydev);
-- break;
-- case MTK_GPHY_ID_MT7988:
-- mt7988_phy_finetune(phydev);
-- break;
-- }
--
-- mt798x_phy_common_finetune(phydev);
-- mt798x_phy_eee(phydev);
--
-- return mt798x_phy_calibration(phydev);
--}
--
--static int mt798x_phy_hw_led_on_set(struct phy_device *phydev, u8 index,
-- bool on)
--{
-- unsigned int bit_on = MTK_PHY_LED_STATE_FORCE_ON + (index ? 16 : 0);
-- struct mtk_socphy_priv *priv = phydev->priv;
-- bool changed;
--
-- if (on)
-- changed = !test_and_set_bit(bit_on, &priv->led_state);
-- else
-- changed = !!test_and_clear_bit(bit_on, &priv->led_state);
--
-- changed |= !!test_and_clear_bit(MTK_PHY_LED_STATE_NETDEV +
-- (index ? 16 : 0), &priv->led_state);
-- if (changed)
-- return phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ?
-- MTK_PHY_LED1_ON_CTRL :
-- MTK_PHY_LED0_ON_CTRL,
-- MTK_PHY_LED_ON_MASK,
-- on ? MTK_PHY_LED_ON_FORCE_ON : 0);
-- else
-- return 0;
--}
--
--static int mt798x_phy_hw_led_blink_set(struct phy_device *phydev, u8 index,
-- bool blinking)
--{
-- unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK +
-- (index ? 16 : 0);
-- struct mtk_socphy_priv *priv = phydev->priv;
-- bool changed;
--
-- if (blinking)
-- changed = !test_and_set_bit(bit_blink, &priv->led_state);
-- else
-- changed = !!test_and_clear_bit(bit_blink, &priv->led_state);
--
-- changed |= !!test_bit(MTK_PHY_LED_STATE_NETDEV +
-- (index ? 16 : 0), &priv->led_state);
-- if (changed)
-- return phy_write_mmd(phydev, MDIO_MMD_VEND2, index ?
-- MTK_PHY_LED1_BLINK_CTRL :
-- MTK_PHY_LED0_BLINK_CTRL,
-- blinking ?
-- MTK_PHY_LED_BLINK_FORCE_BLINK : 0);
-- else
-- return 0;
--}
--
--static int mt798x_phy_led_blink_set(struct phy_device *phydev, u8 index,
-- unsigned long *delay_on,
-- unsigned long *delay_off)
--{
-- bool blinking = false;
-- int err = 0;
--
-- if (index > 1)
-- return -EINVAL;
--
-- if (delay_on && delay_off && (*delay_on > 0) && (*delay_off > 0)) {
-- blinking = true;
-- *delay_on = 50;
-- *delay_off = 50;
-- }
--
-- err = mt798x_phy_hw_led_blink_set(phydev, index, blinking);
-- if (err)
-- return err;
--
-- return mt798x_phy_hw_led_on_set(phydev, index, false);
--}
--
--static int mt798x_phy_led_brightness_set(struct phy_device *phydev,
-- u8 index, enum led_brightness value)
--{
-- int err;
--
-- err = mt798x_phy_hw_led_blink_set(phydev, index, false);
-- if (err)
-- return err;
--
-- return mt798x_phy_hw_led_on_set(phydev, index, (value != LED_OFF));
--}
--
--static const unsigned long supported_triggers =
-- BIT(TRIGGER_NETDEV_FULL_DUPLEX) |
-- BIT(TRIGGER_NETDEV_HALF_DUPLEX) |
-- BIT(TRIGGER_NETDEV_LINK) |
-- BIT(TRIGGER_NETDEV_LINK_10) |
-- BIT(TRIGGER_NETDEV_LINK_100) |
-- BIT(TRIGGER_NETDEV_LINK_1000) |
-- BIT(TRIGGER_NETDEV_RX) |
-- BIT(TRIGGER_NETDEV_TX);
--
--static int mt798x_phy_led_hw_is_supported(struct phy_device *phydev, u8 index,
-- unsigned long rules)
--{
-- if (index > 1)
-- return -EINVAL;
--
-- /* All combinations of the supported triggers are allowed */
-- if (rules & ~supported_triggers)
-- return -EOPNOTSUPP;
--
-- return 0;
--};
--
--static int mt798x_phy_led_hw_control_get(struct phy_device *phydev, u8 index,
-- unsigned long *rules)
--{
-- unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK +
-- (index ? 16 : 0);
-- unsigned int bit_netdev = MTK_PHY_LED_STATE_NETDEV + (index ? 16 : 0);
-- unsigned int bit_on = MTK_PHY_LED_STATE_FORCE_ON + (index ? 16 : 0);
-- struct mtk_socphy_priv *priv = phydev->priv;
-- int on, blink;
--
-- if (index > 1)
-- return -EINVAL;
--
-- on = phy_read_mmd(phydev, MDIO_MMD_VEND2,
-- index ? MTK_PHY_LED1_ON_CTRL : MTK_PHY_LED0_ON_CTRL);
--
-- if (on < 0)
-- return -EIO;
--
-- blink = phy_read_mmd(phydev, MDIO_MMD_VEND2,
-- index ? MTK_PHY_LED1_BLINK_CTRL :
-- MTK_PHY_LED0_BLINK_CTRL);
-- if (blink < 0)
-- return -EIO;
--
-- if ((on & (MTK_PHY_LED_ON_LINK | MTK_PHY_LED_ON_FDX |
-- MTK_PHY_LED_ON_HDX | MTK_PHY_LED_ON_LINKDOWN)) ||
-- (blink & (MTK_PHY_LED_BLINK_RX | MTK_PHY_LED_BLINK_TX)))
-- set_bit(bit_netdev, &priv->led_state);
-- else
-- clear_bit(bit_netdev, &priv->led_state);
--
-- if (on & MTK_PHY_LED_ON_FORCE_ON)
-- set_bit(bit_on, &priv->led_state);
-- else
-- clear_bit(bit_on, &priv->led_state);
--
-- if (blink & MTK_PHY_LED_BLINK_FORCE_BLINK)
-- set_bit(bit_blink, &priv->led_state);
-- else
-- clear_bit(bit_blink, &priv->led_state);
--
-- if (!rules)
-- return 0;
--
-- if (on & MTK_PHY_LED_ON_LINK)
-- *rules |= BIT(TRIGGER_NETDEV_LINK);
--
-- if (on & MTK_PHY_LED_ON_LINK10)
-- *rules |= BIT(TRIGGER_NETDEV_LINK_10);
--
-- if (on & MTK_PHY_LED_ON_LINK100)
-- *rules |= BIT(TRIGGER_NETDEV_LINK_100);
--
-- if (on & MTK_PHY_LED_ON_LINK1000)
-- *rules |= BIT(TRIGGER_NETDEV_LINK_1000);
--
-- if (on & MTK_PHY_LED_ON_FDX)
-- *rules |= BIT(TRIGGER_NETDEV_FULL_DUPLEX);
--
-- if (on & MTK_PHY_LED_ON_HDX)
-- *rules |= BIT(TRIGGER_NETDEV_HALF_DUPLEX);
--
-- if (blink & MTK_PHY_LED_BLINK_RX)
-- *rules |= BIT(TRIGGER_NETDEV_RX);
--
-- if (blink & MTK_PHY_LED_BLINK_TX)
-- *rules |= BIT(TRIGGER_NETDEV_TX);
--
-- return 0;
--};
--
--static int mt798x_phy_led_hw_control_set(struct phy_device *phydev, u8 index,
-- unsigned long rules)
--{
-- unsigned int bit_netdev = MTK_PHY_LED_STATE_NETDEV + (index ? 16 : 0);
-- struct mtk_socphy_priv *priv = phydev->priv;
-- u16 on = 0, blink = 0;
-- int ret;
--
-- if (index > 1)
-- return -EINVAL;
--
-- if (rules & BIT(TRIGGER_NETDEV_FULL_DUPLEX))
-- on |= MTK_PHY_LED_ON_FDX;
--
-- if (rules & BIT(TRIGGER_NETDEV_HALF_DUPLEX))
-- on |= MTK_PHY_LED_ON_HDX;
--
-- if (rules & (BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_LINK)))
-- on |= MTK_PHY_LED_ON_LINK10;
--
-- if (rules & (BIT(TRIGGER_NETDEV_LINK_100) | BIT(TRIGGER_NETDEV_LINK)))
-- on |= MTK_PHY_LED_ON_LINK100;
--
-- if (rules & (BIT(TRIGGER_NETDEV_LINK_1000) | BIT(TRIGGER_NETDEV_LINK)))
-- on |= MTK_PHY_LED_ON_LINK1000;
--
-- if (rules & BIT(TRIGGER_NETDEV_RX)) {
-- blink |= (on & MTK_PHY_LED_ON_LINK) ?
-- (((on & MTK_PHY_LED_ON_LINK10) ?
-- MTK_PHY_LED_BLINK_10RX : 0) |
-- ((on & MTK_PHY_LED_ON_LINK100) ?
-- MTK_PHY_LED_BLINK_100RX : 0) |
-- ((on & MTK_PHY_LED_ON_LINK1000) ?
-- MTK_PHY_LED_BLINK_1000RX : 0)) :
-- MTK_PHY_LED_BLINK_RX;
-- }
--
-- if (rules & BIT(TRIGGER_NETDEV_TX)) {
-- blink |= (on & MTK_PHY_LED_ON_LINK) ?
-- (((on & MTK_PHY_LED_ON_LINK10) ?
-- MTK_PHY_LED_BLINK_10TX : 0) |
-- ((on & MTK_PHY_LED_ON_LINK100) ?
-- MTK_PHY_LED_BLINK_100TX : 0) |
-- ((on & MTK_PHY_LED_ON_LINK1000) ?
-- MTK_PHY_LED_BLINK_1000TX : 0)) :
-- MTK_PHY_LED_BLINK_TX;
-- }
--
-- if (blink || on)
-- set_bit(bit_netdev, &priv->led_state);
-- else
-- clear_bit(bit_netdev, &priv->led_state);
--
-- ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ?
-- MTK_PHY_LED1_ON_CTRL :
-- MTK_PHY_LED0_ON_CTRL,
-- MTK_PHY_LED_ON_FDX |
-- MTK_PHY_LED_ON_HDX |
-- MTK_PHY_LED_ON_LINK,
-- on);
--
-- if (ret)
-- return ret;
--
-- return phy_write_mmd(phydev, MDIO_MMD_VEND2, index ?
-- MTK_PHY_LED1_BLINK_CTRL :
-- MTK_PHY_LED0_BLINK_CTRL, blink);
--};
--
--static bool mt7988_phy_led_get_polarity(struct phy_device *phydev, int led_num)
--{
-- struct mtk_socphy_shared *priv = phydev->shared->priv;
-- u32 polarities;
--
-- if (led_num == 0)
-- polarities = ~(priv->boottrap);
-- else
-- polarities = MTK_PHY_LED1_DEFAULT_POLARITIES;
--
-- if (polarities & BIT(phydev->mdio.addr))
-- return true;
--
-- return false;
--}
--
--static int mt7988_phy_fix_leds_polarities(struct phy_device *phydev)
--{
-- struct pinctrl *pinctrl;
-- int index;
--
-- /* Setup LED polarity according to bootstrap use of LED pins */
-- for (index = 0; index < 2; ++index)
-- phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ?
-- MTK_PHY_LED1_ON_CTRL : MTK_PHY_LED0_ON_CTRL,
-- MTK_PHY_LED_ON_POLARITY,
-- mt7988_phy_led_get_polarity(phydev, index) ?
-- MTK_PHY_LED_ON_POLARITY : 0);
--
-- /* Only now setup pinctrl to avoid bogus blinking */
-- pinctrl = devm_pinctrl_get_select(&phydev->mdio.dev, "gbe-led");
-- if (IS_ERR(pinctrl))
-- dev_err(&phydev->mdio.bus->dev,
-- "Failed to setup PHY LED pinctrl\n");
--
-- return 0;
--}
--
--static int mt7988_phy_probe_shared(struct phy_device *phydev)
--{
-- struct device_node *np = dev_of_node(&phydev->mdio.bus->dev);
-- struct mtk_socphy_shared *shared = phydev->shared->priv;
-- struct regmap *regmap;
-- u32 reg;
-- int ret;
--
-- /* The LED0 of the 4 PHYs in MT7988 are wired to SoC pins LED_A, LED_B,
-- * LED_C and LED_D respectively. At the same time those pins are used to
-- * bootstrap configuration of the reference clock source (LED_A),
-- * DRAM DDRx16b x2/x1 (LED_B) and boot device (LED_C, LED_D).
-- * In practice this is done using a LED and a resistor pulling the pin
-- * either to GND or to VIO.
-- * The detected value at boot time is accessible at run-time using the
-- * TPBANK0 register located in the gpio base of the pinctrl, in order
-- * to read it here it needs to be referenced by a phandle called
-- * 'mediatek,pio' in the MDIO bus hosting the PHY.
-- * The 4 bits in TPBANK0 are kept as package shared data and are used to
-- * set LED polarity for each of the LED0.
-- */
-- regmap = syscon_regmap_lookup_by_phandle(np, "mediatek,pio");
-- if (IS_ERR(regmap))
-- return PTR_ERR(regmap);
--
-- ret = regmap_read(regmap, RG_GPIO_MISC_TPBANK0, ®);
-- if (ret)
-- return ret;
--
-- shared->boottrap = FIELD_GET(RG_GPIO_MISC_TPBANK0_BOOTMODE, reg);
--
-- return 0;
--}
--
--static void mt798x_phy_leds_state_init(struct phy_device *phydev)
--{
-- int i;
--
-- for (i = 0; i < 2; ++i)
-- mt798x_phy_led_hw_control_get(phydev, i, NULL);
--}
--
--static int mt7988_phy_probe(struct phy_device *phydev)
--{
-- struct mtk_socphy_shared *shared;
-- struct mtk_socphy_priv *priv;
-- int err;
--
-- if (phydev->mdio.addr > 3)
-- return -EINVAL;
--
-- err = devm_phy_package_join(&phydev->mdio.dev, phydev, 0,
-- sizeof(struct mtk_socphy_shared));
-- if (err)
-- return err;
--
-- if (phy_package_probe_once(phydev)) {
-- err = mt7988_phy_probe_shared(phydev);
-- if (err)
-- return err;
-- }
--
-- shared = phydev->shared->priv;
-- priv = &shared->priv[phydev->mdio.addr];
--
-- phydev->priv = priv;
--
-- mt798x_phy_leds_state_init(phydev);
--
-- err = mt7988_phy_fix_leds_polarities(phydev);
-- if (err)
-- return err;
--
-- /* Disable TX power saving at probing to:
-- * 1. Meet common mode compliance test criteria
-- * 2. Make sure that TX-VCM calibration works fine
-- */
-- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG7,
-- MTK_PHY_DA_AD_BUF_BIAS_LP_MASK, 0x3 << 8);
--
-- return mt798x_phy_calibration(phydev);
--}
--
--static int mt7981_phy_probe(struct phy_device *phydev)
--{
-- struct mtk_socphy_priv *priv;
--
-- priv = devm_kzalloc(&phydev->mdio.dev, sizeof(struct mtk_socphy_priv),
-- GFP_KERNEL);
-- if (!priv)
-- return -ENOMEM;
--
-- phydev->priv = priv;
--
-- mt798x_phy_leds_state_init(phydev);
--
-- return mt798x_phy_calibration(phydev);
--}
--
--static struct phy_driver mtk_socphy_driver[] = {
-- {
-- PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7981),
-- .name = "MediaTek MT7981 PHY",
-- .config_init = mt798x_phy_config_init,
-- .config_intr = genphy_no_config_intr,
-- .handle_interrupt = genphy_handle_interrupt_no_ack,
-- .probe = mt7981_phy_probe,
-- .suspend = genphy_suspend,
-- .resume = genphy_resume,
-- .read_page = mtk_socphy_read_page,
-- .write_page = mtk_socphy_write_page,
-- .led_blink_set = mt798x_phy_led_blink_set,
-- .led_brightness_set = mt798x_phy_led_brightness_set,
-- .led_hw_is_supported = mt798x_phy_led_hw_is_supported,
-- .led_hw_control_set = mt798x_phy_led_hw_control_set,
-- .led_hw_control_get = mt798x_phy_led_hw_control_get,
-- },
-- {
-- PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7988),
-- .name = "MediaTek MT7988 PHY",
-- .config_init = mt798x_phy_config_init,
-- .config_intr = genphy_no_config_intr,
-- .handle_interrupt = genphy_handle_interrupt_no_ack,
-- .probe = mt7988_phy_probe,
-- .suspend = genphy_suspend,
-- .resume = genphy_resume,
-- .read_page = mtk_socphy_read_page,
-- .write_page = mtk_socphy_write_page,
-- .led_blink_set = mt798x_phy_led_blink_set,
-- .led_brightness_set = mt798x_phy_led_brightness_set,
-- .led_hw_is_supported = mt798x_phy_led_hw_is_supported,
-- .led_hw_control_set = mt798x_phy_led_hw_control_set,
-- .led_hw_control_get = mt798x_phy_led_hw_control_get,
-- },
--};
--
--module_phy_driver(mtk_socphy_driver);
--
--static struct mdio_device_id __maybe_unused mtk_socphy_tbl[] = {
-- { PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7981) },
-- { PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7988) },
-- { }
--};
--
--MODULE_DESCRIPTION("MediaTek SoC Gigabit Ethernet PHY driver");
--MODULE_LICENSE("GPL");
--
--MODULE_DEVICE_TABLE(mdio, mtk_socphy_tbl);
---- a/drivers/net/phy/mediatek-ge.c
-+++ /dev/null
-@@ -1,114 +0,0 @@
--// SPDX-License-Identifier: GPL-2.0+
--#include <linux/bitfield.h>
--#include <linux/module.h>
--#include <linux/phy.h>
--
--#define MTK_EXT_PAGE_ACCESS 0x1f
--#define MTK_PHY_PAGE_STANDARD 0x0000
--#define MTK_PHY_PAGE_EXTENDED 0x0001
--#define MTK_PHY_PAGE_EXTENDED_2 0x0002
--#define MTK_PHY_PAGE_EXTENDED_3 0x0003
--#define MTK_PHY_PAGE_EXTENDED_2A30 0x2a30
--#define MTK_PHY_PAGE_EXTENDED_52B5 0x52b5
--
--static int mtk_gephy_read_page(struct phy_device *phydev)
--{
-- return __phy_read(phydev, MTK_EXT_PAGE_ACCESS);
--}
--
--static int mtk_gephy_write_page(struct phy_device *phydev, int page)
--{
-- return __phy_write(phydev, MTK_EXT_PAGE_ACCESS, page);
--}
--
--static void mtk_gephy_config_init(struct phy_device *phydev)
--{
-- /* Disable EEE */
-- phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV, 0);
--
-- /* Enable HW auto downshift */
-- phy_modify_paged(phydev, MTK_PHY_PAGE_EXTENDED, 0x14, 0, BIT(4));
--
-- /* Increase SlvDPSready time */
-- phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
-- __phy_write(phydev, 0x10, 0xafae);
-- __phy_write(phydev, 0x12, 0x2f);
-- __phy_write(phydev, 0x10, 0x8fae);
-- phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
--
-- /* Adjust 100_mse_threshold */
-- phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x123, 0xffff);
--
-- /* Disable mcc */
-- phy_write_mmd(phydev, MDIO_MMD_VEND1, 0xa6, 0x300);
--}
--
--static int mt7530_phy_config_init(struct phy_device *phydev)
--{
-- mtk_gephy_config_init(phydev);
--
-- /* Increase post_update_timer */
-- phy_write_paged(phydev, MTK_PHY_PAGE_EXTENDED_3, 0x11, 0x4b);
--
-- return 0;
--}
--
--static int mt7531_phy_config_init(struct phy_device *phydev)
--{
-- mtk_gephy_config_init(phydev);
--
-- /* PHY link down power saving enable */
-- phy_set_bits(phydev, 0x17, BIT(4));
-- phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, 0xc6, 0x300);
--
-- /* Set TX Pair delay selection */
-- phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x13, 0x404);
-- phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x14, 0x404);
--
-- return 0;
--}
--
--static struct phy_driver mtk_gephy_driver[] = {
-- {
-- PHY_ID_MATCH_EXACT(0x03a29412),
-- .name = "MediaTek MT7530 PHY",
-- .config_init = mt7530_phy_config_init,
-- /* Interrupts are handled by the switch, not the PHY
-- * itself.
-- */
-- .config_intr = genphy_no_config_intr,
-- .handle_interrupt = genphy_handle_interrupt_no_ack,
-- .suspend = genphy_suspend,
-- .resume = genphy_resume,
-- .read_page = mtk_gephy_read_page,
-- .write_page = mtk_gephy_write_page,
-- },
-- {
-- PHY_ID_MATCH_EXACT(0x03a29441),
-- .name = "MediaTek MT7531 PHY",
-- .config_init = mt7531_phy_config_init,
-- /* Interrupts are handled by the switch, not the PHY
-- * itself.
-- */
-- .config_intr = genphy_no_config_intr,
-- .handle_interrupt = genphy_handle_interrupt_no_ack,
-- .suspend = genphy_suspend,
-- .resume = genphy_resume,
-- .read_page = mtk_gephy_read_page,
-- .write_page = mtk_gephy_write_page,
-- },
--};
--
--module_phy_driver(mtk_gephy_driver);
--
--static struct mdio_device_id __maybe_unused mtk_gephy_tbl[] = {
-- { PHY_ID_MATCH_EXACT(0x03a29441) },
-- { PHY_ID_MATCH_EXACT(0x03a29412) },
-- { }
--};
--
--MODULE_DESCRIPTION("MediaTek Gigabit Ethernet PHY driver");
--MODULE_LICENSE("GPL");
--
--MODULE_DEVICE_TABLE(mdio, mtk_gephy_tbl);
---- /dev/null
-+++ b/drivers/net/phy/mediatek/mtk-ge-soc.c
-@@ -0,0 +1,1610 @@
-+// SPDX-License-Identifier: GPL-2.0+
-+#include <linux/bitfield.h>
-+#include <linux/bitmap.h>
-+#include <linux/mfd/syscon.h>
-+#include <linux/module.h>
-+#include <linux/nvmem-consumer.h>
-+#include <linux/pinctrl/consumer.h>
-+#include <linux/phy.h>
-+#include <linux/regmap.h>
-+
-+#define MTK_GPHY_ID_MT7981 0x03a29461
-+#define MTK_GPHY_ID_MT7988 0x03a29481
-+
-+#define MTK_EXT_PAGE_ACCESS 0x1f
-+#define MTK_PHY_PAGE_STANDARD 0x0000
-+#define MTK_PHY_PAGE_EXTENDED_3 0x0003
-+
-+#define MTK_PHY_LPI_REG_14 0x14
-+#define MTK_PHY_LPI_WAKE_TIMER_1000_MASK GENMASK(8, 0)
-+
-+#define MTK_PHY_LPI_REG_1c 0x1c
-+#define MTK_PHY_SMI_DET_ON_THRESH_MASK GENMASK(13, 8)
-+
-+#define MTK_PHY_PAGE_EXTENDED_2A30 0x2a30
-+#define MTK_PHY_PAGE_EXTENDED_52B5 0x52b5
-+
-+#define ANALOG_INTERNAL_OPERATION_MAX_US 20
-+#define TXRESERVE_MIN 0
-+#define TXRESERVE_MAX 7
-+
-+#define MTK_PHY_ANARG_RG 0x10
-+#define MTK_PHY_TCLKOFFSET_MASK GENMASK(12, 8)
-+
-+/* Registers on MDIO_MMD_VEND1 */
-+#define MTK_PHY_TXVLD_DA_RG 0x12
-+#define MTK_PHY_DA_TX_I2MPB_A_GBE_MASK GENMASK(15, 10)
-+#define MTK_PHY_DA_TX_I2MPB_A_TBT_MASK GENMASK(5, 0)
-+
-+#define MTK_PHY_TX_I2MPB_TEST_MODE_A2 0x16
-+#define MTK_PHY_DA_TX_I2MPB_A_HBT_MASK GENMASK(15, 10)
-+#define MTK_PHY_DA_TX_I2MPB_A_TST_MASK GENMASK(5, 0)
-+
-+#define MTK_PHY_TX_I2MPB_TEST_MODE_B1 0x17
-+#define MTK_PHY_DA_TX_I2MPB_B_GBE_MASK GENMASK(13, 8)
-+#define MTK_PHY_DA_TX_I2MPB_B_TBT_MASK GENMASK(5, 0)
-+
-+#define MTK_PHY_TX_I2MPB_TEST_MODE_B2 0x18
-+#define MTK_PHY_DA_TX_I2MPB_B_HBT_MASK GENMASK(13, 8)
-+#define MTK_PHY_DA_TX_I2MPB_B_TST_MASK GENMASK(5, 0)
-+
-+#define MTK_PHY_TX_I2MPB_TEST_MODE_C1 0x19
-+#define MTK_PHY_DA_TX_I2MPB_C_GBE_MASK GENMASK(13, 8)
-+#define MTK_PHY_DA_TX_I2MPB_C_TBT_MASK GENMASK(5, 0)
-+
-+#define MTK_PHY_TX_I2MPB_TEST_MODE_C2 0x20
-+#define MTK_PHY_DA_TX_I2MPB_C_HBT_MASK GENMASK(13, 8)
-+#define MTK_PHY_DA_TX_I2MPB_C_TST_MASK GENMASK(5, 0)
-+
-+#define MTK_PHY_TX_I2MPB_TEST_MODE_D1 0x21
-+#define MTK_PHY_DA_TX_I2MPB_D_GBE_MASK GENMASK(13, 8)
-+#define MTK_PHY_DA_TX_I2MPB_D_TBT_MASK GENMASK(5, 0)
-+
-+#define MTK_PHY_TX_I2MPB_TEST_MODE_D2 0x22
-+#define MTK_PHY_DA_TX_I2MPB_D_HBT_MASK GENMASK(13, 8)
-+#define MTK_PHY_DA_TX_I2MPB_D_TST_MASK GENMASK(5, 0)
-+
-+#define MTK_PHY_RXADC_CTRL_RG7 0xc6
-+#define MTK_PHY_DA_AD_BUF_BIAS_LP_MASK GENMASK(9, 8)
-+
-+#define MTK_PHY_RXADC_CTRL_RG9 0xc8
-+#define MTK_PHY_DA_RX_PSBN_TBT_MASK GENMASK(14, 12)
-+#define MTK_PHY_DA_RX_PSBN_HBT_MASK GENMASK(10, 8)
-+#define MTK_PHY_DA_RX_PSBN_GBE_MASK GENMASK(6, 4)
-+#define MTK_PHY_DA_RX_PSBN_LP_MASK GENMASK(2, 0)
-+
-+#define MTK_PHY_LDO_OUTPUT_V 0xd7
-+
-+#define MTK_PHY_RG_ANA_CAL_RG0 0xdb
-+#define MTK_PHY_RG_CAL_CKINV BIT(12)
-+#define MTK_PHY_RG_ANA_CALEN BIT(8)
-+#define MTK_PHY_RG_ZCALEN_A BIT(0)
-+
-+#define MTK_PHY_RG_ANA_CAL_RG1 0xdc
-+#define MTK_PHY_RG_ZCALEN_B BIT(12)
-+#define MTK_PHY_RG_ZCALEN_C BIT(8)
-+#define MTK_PHY_RG_ZCALEN_D BIT(4)
-+#define MTK_PHY_RG_TXVOS_CALEN BIT(0)
-+
-+#define MTK_PHY_RG_ANA_CAL_RG5 0xe0
-+#define MTK_PHY_RG_REXT_TRIM_MASK GENMASK(13, 8)
-+
-+#define MTK_PHY_RG_TX_FILTER 0xfe
-+
-+#define MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG120 0x120
-+#define MTK_PHY_LPI_SIG_EN_LO_THRESH1000_MASK GENMASK(12, 8)
-+#define MTK_PHY_LPI_SIG_EN_HI_THRESH1000_MASK GENMASK(4, 0)
-+
-+#define MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG122 0x122
-+#define MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK GENMASK(7, 0)
-+
-+#define MTK_PHY_RG_TESTMUX_ADC_CTRL 0x144
-+#define MTK_PHY_RG_TXEN_DIG_MASK GENMASK(5, 5)
-+
-+#define MTK_PHY_RG_CR_TX_AMP_OFFSET_A_B 0x172
-+#define MTK_PHY_CR_TX_AMP_OFFSET_A_MASK GENMASK(13, 8)
-+#define MTK_PHY_CR_TX_AMP_OFFSET_B_MASK GENMASK(6, 0)
-+
-+#define MTK_PHY_RG_CR_TX_AMP_OFFSET_C_D 0x173
-+#define MTK_PHY_CR_TX_AMP_OFFSET_C_MASK GENMASK(13, 8)
-+#define MTK_PHY_CR_TX_AMP_OFFSET_D_MASK GENMASK(6, 0)
-+
-+#define MTK_PHY_RG_AD_CAL_COMP 0x17a
-+#define MTK_PHY_AD_CAL_COMP_OUT_MASK GENMASK(8, 8)
-+
-+#define MTK_PHY_RG_AD_CAL_CLK 0x17b
-+#define MTK_PHY_DA_CAL_CLK BIT(0)
-+
-+#define MTK_PHY_RG_AD_CALIN 0x17c
-+#define MTK_PHY_DA_CALIN_FLAG BIT(0)
-+
-+#define MTK_PHY_RG_DASN_DAC_IN0_A 0x17d
-+#define MTK_PHY_DASN_DAC_IN0_A_MASK GENMASK(9, 0)
-+
-+#define MTK_PHY_RG_DASN_DAC_IN0_B 0x17e
-+#define MTK_PHY_DASN_DAC_IN0_B_MASK GENMASK(9, 0)
-+
-+#define MTK_PHY_RG_DASN_DAC_IN0_C 0x17f
-+#define MTK_PHY_DASN_DAC_IN0_C_MASK GENMASK(9, 0)
-+
-+#define MTK_PHY_RG_DASN_DAC_IN0_D 0x180
-+#define MTK_PHY_DASN_DAC_IN0_D_MASK GENMASK(9, 0)
-+
-+#define MTK_PHY_RG_DASN_DAC_IN1_A 0x181
-+#define MTK_PHY_DASN_DAC_IN1_A_MASK GENMASK(9, 0)
-+
-+#define MTK_PHY_RG_DASN_DAC_IN1_B 0x182
-+#define MTK_PHY_DASN_DAC_IN1_B_MASK GENMASK(9, 0)
-+
-+#define MTK_PHY_RG_DASN_DAC_IN1_C 0x183
-+#define MTK_PHY_DASN_DAC_IN1_C_MASK GENMASK(9, 0)
-+
-+#define MTK_PHY_RG_DASN_DAC_IN1_D 0x184
-+#define MTK_PHY_DASN_DAC_IN1_D_MASK GENMASK(9, 0)
-+
-+#define MTK_PHY_RG_DEV1E_REG19b 0x19b
-+#define MTK_PHY_BYPASS_DSP_LPI_READY BIT(8)
-+
-+#define MTK_PHY_RG_LP_IIR2_K1_L 0x22a
-+#define MTK_PHY_RG_LP_IIR2_K1_U 0x22b
-+#define MTK_PHY_RG_LP_IIR2_K2_L 0x22c
-+#define MTK_PHY_RG_LP_IIR2_K2_U 0x22d
-+#define MTK_PHY_RG_LP_IIR2_K3_L 0x22e
-+#define MTK_PHY_RG_LP_IIR2_K3_U 0x22f
-+#define MTK_PHY_RG_LP_IIR2_K4_L 0x230
-+#define MTK_PHY_RG_LP_IIR2_K4_U 0x231
-+#define MTK_PHY_RG_LP_IIR2_K5_L 0x232
-+#define MTK_PHY_RG_LP_IIR2_K5_U 0x233
-+
-+#define MTK_PHY_RG_DEV1E_REG234 0x234
-+#define MTK_PHY_TR_OPEN_LOOP_EN_MASK GENMASK(0, 0)
-+#define MTK_PHY_LPF_X_AVERAGE_MASK GENMASK(7, 4)
-+#define MTK_PHY_TR_LP_IIR_EEE_EN BIT(12)
-+
-+#define MTK_PHY_RG_LPF_CNT_VAL 0x235
-+
-+#define MTK_PHY_RG_DEV1E_REG238 0x238
-+#define MTK_PHY_LPI_SLV_SEND_TX_TIMER_MASK GENMASK(8, 0)
-+#define MTK_PHY_LPI_SLV_SEND_TX_EN BIT(12)
-+
-+#define MTK_PHY_RG_DEV1E_REG239 0x239
-+#define MTK_PHY_LPI_SEND_LOC_TIMER_MASK GENMASK(8, 0)
-+#define MTK_PHY_LPI_TXPCS_LOC_RCV BIT(12)
-+
-+#define MTK_PHY_RG_DEV1E_REG27C 0x27c
-+#define MTK_PHY_VGASTATE_FFE_THR_ST1_MASK GENMASK(12, 8)
-+#define MTK_PHY_RG_DEV1E_REG27D 0x27d
-+#define MTK_PHY_VGASTATE_FFE_THR_ST2_MASK GENMASK(4, 0)
-+
-+#define MTK_PHY_RG_DEV1E_REG2C7 0x2c7
-+#define MTK_PHY_MAX_GAIN_MASK GENMASK(4, 0)
-+#define MTK_PHY_MIN_GAIN_MASK GENMASK(12, 8)
-+
-+#define MTK_PHY_RG_DEV1E_REG2D1 0x2d1
-+#define MTK_PHY_VCO_SLICER_THRESH_BITS_HIGH_EEE_MASK GENMASK(7, 0)
-+#define MTK_PHY_LPI_SKIP_SD_SLV_TR BIT(8)
-+#define MTK_PHY_LPI_TR_READY BIT(9)
-+#define MTK_PHY_LPI_VCO_EEE_STG0_EN BIT(10)
-+
-+#define MTK_PHY_RG_DEV1E_REG323 0x323
-+#define MTK_PHY_EEE_WAKE_MAS_INT_DC BIT(0)
-+#define MTK_PHY_EEE_WAKE_SLV_INT_DC BIT(4)
-+
-+#define MTK_PHY_RG_DEV1E_REG324 0x324
-+#define MTK_PHY_SMI_DETCNT_MAX_MASK GENMASK(5, 0)
-+#define MTK_PHY_SMI_DET_MAX_EN BIT(8)
-+
-+#define MTK_PHY_RG_DEV1E_REG326 0x326
-+#define MTK_PHY_LPI_MODE_SD_ON BIT(0)
-+#define MTK_PHY_RESET_RANDUPD_CNT BIT(1)
-+#define MTK_PHY_TREC_UPDATE_ENAB_CLR BIT(2)
-+#define MTK_PHY_LPI_QUIT_WAIT_DFE_SIG_DET_OFF BIT(4)
-+#define MTK_PHY_TR_READY_SKIP_AFE_WAKEUP BIT(5)
-+
-+#define MTK_PHY_LDO_PUMP_EN_PAIRAB 0x502
-+#define MTK_PHY_LDO_PUMP_EN_PAIRCD 0x503
-+
-+#define MTK_PHY_DA_TX_R50_PAIR_A 0x53d
-+#define MTK_PHY_DA_TX_R50_PAIR_B 0x53e
-+#define MTK_PHY_DA_TX_R50_PAIR_C 0x53f
-+#define MTK_PHY_DA_TX_R50_PAIR_D 0x540
-+
-+/* Registers on MDIO_MMD_VEND2 */
-+#define MTK_PHY_LED0_ON_CTRL 0x24
-+#define MTK_PHY_LED1_ON_CTRL 0x26
-+#define MTK_PHY_LED_ON_MASK GENMASK(6, 0)
-+#define MTK_PHY_LED_ON_LINK1000 BIT(0)
-+#define MTK_PHY_LED_ON_LINK100 BIT(1)
-+#define MTK_PHY_LED_ON_LINK10 BIT(2)
-+#define MTK_PHY_LED_ON_LINK (MTK_PHY_LED_ON_LINK10 |\
-+ MTK_PHY_LED_ON_LINK100 |\
-+ MTK_PHY_LED_ON_LINK1000)
-+#define MTK_PHY_LED_ON_LINKDOWN BIT(3)
-+#define MTK_PHY_LED_ON_FDX BIT(4) /* Full duplex */
-+#define MTK_PHY_LED_ON_HDX BIT(5) /* Half duplex */
-+#define MTK_PHY_LED_ON_FORCE_ON BIT(6)
-+#define MTK_PHY_LED_ON_POLARITY BIT(14)
-+#define MTK_PHY_LED_ON_ENABLE BIT(15)
-+
-+#define MTK_PHY_LED0_BLINK_CTRL 0x25
-+#define MTK_PHY_LED1_BLINK_CTRL 0x27
-+#define MTK_PHY_LED_BLINK_1000TX BIT(0)
-+#define MTK_PHY_LED_BLINK_1000RX BIT(1)
-+#define MTK_PHY_LED_BLINK_100TX BIT(2)
-+#define MTK_PHY_LED_BLINK_100RX BIT(3)
-+#define MTK_PHY_LED_BLINK_10TX BIT(4)
-+#define MTK_PHY_LED_BLINK_10RX BIT(5)
-+#define MTK_PHY_LED_BLINK_RX (MTK_PHY_LED_BLINK_10RX |\
-+ MTK_PHY_LED_BLINK_100RX |\
-+ MTK_PHY_LED_BLINK_1000RX)
-+#define MTK_PHY_LED_BLINK_TX (MTK_PHY_LED_BLINK_10TX |\
-+ MTK_PHY_LED_BLINK_100TX |\
-+ MTK_PHY_LED_BLINK_1000TX)
-+#define MTK_PHY_LED_BLINK_COLLISION BIT(6)
-+#define MTK_PHY_LED_BLINK_RX_CRC_ERR BIT(7)
-+#define MTK_PHY_LED_BLINK_RX_IDLE_ERR BIT(8)
-+#define MTK_PHY_LED_BLINK_FORCE_BLINK BIT(9)
-+
-+#define MTK_PHY_LED1_DEFAULT_POLARITIES BIT(1)
-+
-+#define MTK_PHY_RG_BG_RASEL 0x115
-+#define MTK_PHY_RG_BG_RASEL_MASK GENMASK(2, 0)
-+
-+/* 'boottrap' register reflecting the configuration of the 4 PHY LEDs */
-+#define RG_GPIO_MISC_TPBANK0 0x6f0
-+#define RG_GPIO_MISC_TPBANK0_BOOTMODE GENMASK(11, 8)
-+
-+/* These macro privides efuse parsing for internal phy. */
-+#define EFS_DA_TX_I2MPB_A(x) (((x) >> 0) & GENMASK(5, 0))
-+#define EFS_DA_TX_I2MPB_B(x) (((x) >> 6) & GENMASK(5, 0))
-+#define EFS_DA_TX_I2MPB_C(x) (((x) >> 12) & GENMASK(5, 0))
-+#define EFS_DA_TX_I2MPB_D(x) (((x) >> 18) & GENMASK(5, 0))
-+#define EFS_DA_TX_AMP_OFFSET_A(x) (((x) >> 24) & GENMASK(5, 0))
-+
-+#define EFS_DA_TX_AMP_OFFSET_B(x) (((x) >> 0) & GENMASK(5, 0))
-+#define EFS_DA_TX_AMP_OFFSET_C(x) (((x) >> 6) & GENMASK(5, 0))
-+#define EFS_DA_TX_AMP_OFFSET_D(x) (((x) >> 12) & GENMASK(5, 0))
-+#define EFS_DA_TX_R50_A(x) (((x) >> 18) & GENMASK(5, 0))
-+#define EFS_DA_TX_R50_B(x) (((x) >> 24) & GENMASK(5, 0))
-+
-+#define EFS_DA_TX_R50_C(x) (((x) >> 0) & GENMASK(5, 0))
-+#define EFS_DA_TX_R50_D(x) (((x) >> 6) & GENMASK(5, 0))
-+
-+#define EFS_RG_BG_RASEL(x) (((x) >> 4) & GENMASK(2, 0))
-+#define EFS_RG_REXT_TRIM(x) (((x) >> 7) & GENMASK(5, 0))
-+
-+enum {
-+ NO_PAIR,
-+ PAIR_A,
-+ PAIR_B,
-+ PAIR_C,
-+ PAIR_D,
-+};
-+
-+enum calibration_mode {
-+ EFUSE_K,
-+ SW_K
-+};
-+
-+enum CAL_ITEM {
-+ REXT,
-+ TX_OFFSET,
-+ TX_AMP,
-+ TX_R50,
-+ TX_VCM
-+};
-+
-+enum CAL_MODE {
-+ EFUSE_M,
-+ SW_M
-+};
-+
-+#define MTK_PHY_LED_STATE_FORCE_ON 0
-+#define MTK_PHY_LED_STATE_FORCE_BLINK 1
-+#define MTK_PHY_LED_STATE_NETDEV 2
-+
-+struct mtk_socphy_priv {
-+ unsigned long led_state;
-+};
-+
-+struct mtk_socphy_shared {
-+ u32 boottrap;
-+ struct mtk_socphy_priv priv[4];
-+};
-+
-+static int mtk_socphy_read_page(struct phy_device *phydev)
-+{
-+ return __phy_read(phydev, MTK_EXT_PAGE_ACCESS);
-+}
-+
-+static int mtk_socphy_write_page(struct phy_device *phydev, int page)
-+{
-+ return __phy_write(phydev, MTK_EXT_PAGE_ACCESS, page);
-+}
-+
-+/* One calibration cycle consists of:
-+ * 1.Set DA_CALIN_FLAG high to start calibration. Keep it high
-+ * until AD_CAL_COMP is ready to output calibration result.
-+ * 2.Wait until DA_CAL_CLK is available.
-+ * 3.Fetch AD_CAL_COMP_OUT.
-+ */
-+static int cal_cycle(struct phy_device *phydev, int devad,
-+ u32 regnum, u16 mask, u16 cal_val)
-+{
-+ int reg_val;
-+ int ret;
-+
-+ phy_modify_mmd(phydev, devad, regnum,
-+ mask, cal_val);
-+ phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_AD_CALIN,
-+ MTK_PHY_DA_CALIN_FLAG);
-+
-+ ret = phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND1,
-+ MTK_PHY_RG_AD_CAL_CLK, reg_val,
-+ reg_val & MTK_PHY_DA_CAL_CLK, 500,
-+ ANALOG_INTERNAL_OPERATION_MAX_US,
-+ false);
-+ if (ret) {
-+ phydev_err(phydev, "Calibration cycle timeout\n");
-+ return ret;
-+ }
-+
-+ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_AD_CALIN,
-+ MTK_PHY_DA_CALIN_FLAG);
-+ ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_AD_CAL_COMP);
-+ if (ret < 0)
-+ return ret;
-+ ret = FIELD_GET(MTK_PHY_AD_CAL_COMP_OUT_MASK, ret);
-+ phydev_dbg(phydev, "cal_val: 0x%x, ret: %d\n", cal_val, ret);
-+
-+ return ret;
-+}
-+
-+static int rext_fill_result(struct phy_device *phydev, u16 *buf)
-+{
-+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG5,
-+ MTK_PHY_RG_REXT_TRIM_MASK, buf[0] << 8);
-+ phy_modify_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_RG_BG_RASEL,
-+ MTK_PHY_RG_BG_RASEL_MASK, buf[1]);
-+
-+ return 0;
-+}
-+
-+static int rext_cal_efuse(struct phy_device *phydev, u32 *buf)
-+{
-+ u16 rext_cal_val[2];
-+
-+ rext_cal_val[0] = EFS_RG_REXT_TRIM(buf[3]);
-+ rext_cal_val[1] = EFS_RG_BG_RASEL(buf[3]);
-+ rext_fill_result(phydev, rext_cal_val);
-+
-+ return 0;
-+}
-+
-+static int tx_offset_fill_result(struct phy_device *phydev, u16 *buf)
-+{
-+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_CR_TX_AMP_OFFSET_A_B,
-+ MTK_PHY_CR_TX_AMP_OFFSET_A_MASK, buf[0] << 8);
-+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_CR_TX_AMP_OFFSET_A_B,
-+ MTK_PHY_CR_TX_AMP_OFFSET_B_MASK, buf[1]);
-+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_CR_TX_AMP_OFFSET_C_D,
-+ MTK_PHY_CR_TX_AMP_OFFSET_C_MASK, buf[2] << 8);
-+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_CR_TX_AMP_OFFSET_C_D,
-+ MTK_PHY_CR_TX_AMP_OFFSET_D_MASK, buf[3]);
-+
-+ return 0;
-+}
-+
-+static int tx_offset_cal_efuse(struct phy_device *phydev, u32 *buf)
-+{
-+ u16 tx_offset_cal_val[4];
-+
-+ tx_offset_cal_val[0] = EFS_DA_TX_AMP_OFFSET_A(buf[0]);
-+ tx_offset_cal_val[1] = EFS_DA_TX_AMP_OFFSET_B(buf[1]);
-+ tx_offset_cal_val[2] = EFS_DA_TX_AMP_OFFSET_C(buf[1]);
-+ tx_offset_cal_val[3] = EFS_DA_TX_AMP_OFFSET_D(buf[1]);
-+
-+ tx_offset_fill_result(phydev, tx_offset_cal_val);
-+
-+ return 0;
-+}
-+
-+static int tx_amp_fill_result(struct phy_device *phydev, u16 *buf)
-+{
-+ const int vals_9481[16] = { 10, 6, 6, 10,
-+ 10, 6, 6, 10,
-+ 10, 6, 6, 10,
-+ 10, 6, 6, 10 };
-+ const int vals_9461[16] = { 7, 1, 4, 7,
-+ 7, 1, 4, 7,
-+ 7, 1, 4, 7,
-+ 7, 1, 4, 7 };
-+ int bias[16] = {};
-+ int i;
-+
-+ switch (phydev->drv->phy_id) {
-+ case MTK_GPHY_ID_MT7981:
-+ /* We add some calibration to efuse values
-+ * due to board level influence.
-+ * GBE: +7, TBT: +1, HBT: +4, TST: +7
-+ */
-+ memcpy(bias, (const void *)vals_9461, sizeof(bias));
-+ break;
-+ case MTK_GPHY_ID_MT7988:
-+ memcpy(bias, (const void *)vals_9481, sizeof(bias));
-+ break;
-+ }
-+
-+ /* Prevent overflow */
-+ for (i = 0; i < 12; i++) {
-+ if (buf[i >> 2] + bias[i] > 63) {
-+ buf[i >> 2] = 63;
-+ bias[i] = 0;
-+ }
-+ }
-+
-+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TXVLD_DA_RG,
-+ MTK_PHY_DA_TX_I2MPB_A_GBE_MASK,
-+ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_A_GBE_MASK,
-+ buf[0] + bias[0]));
-+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TXVLD_DA_RG,
-+ MTK_PHY_DA_TX_I2MPB_A_TBT_MASK,
-+ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_A_TBT_MASK,
-+ buf[0] + bias[1]));
-+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_A2,
-+ MTK_PHY_DA_TX_I2MPB_A_HBT_MASK,
-+ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_A_HBT_MASK,
-+ buf[0] + bias[2]));
-+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_A2,
-+ MTK_PHY_DA_TX_I2MPB_A_TST_MASK,
-+ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_A_TST_MASK,
-+ buf[0] + bias[3]));
-+
-+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B1,
-+ MTK_PHY_DA_TX_I2MPB_B_GBE_MASK,
-+ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_B_GBE_MASK,
-+ buf[1] + bias[4]));
-+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B1,
-+ MTK_PHY_DA_TX_I2MPB_B_TBT_MASK,
-+ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_B_TBT_MASK,
-+ buf[1] + bias[5]));
-+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B2,
-+ MTK_PHY_DA_TX_I2MPB_B_HBT_MASK,
-+ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_B_HBT_MASK,
-+ buf[1] + bias[6]));
-+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B2,
-+ MTK_PHY_DA_TX_I2MPB_B_TST_MASK,
-+ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_B_TST_MASK,
-+ buf[1] + bias[7]));
-+
-+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C1,
-+ MTK_PHY_DA_TX_I2MPB_C_GBE_MASK,
-+ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_C_GBE_MASK,
-+ buf[2] + bias[8]));
-+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C1,
-+ MTK_PHY_DA_TX_I2MPB_C_TBT_MASK,
-+ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_C_TBT_MASK,
-+ buf[2] + bias[9]));
-+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C2,
-+ MTK_PHY_DA_TX_I2MPB_C_HBT_MASK,
-+ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_C_HBT_MASK,
-+ buf[2] + bias[10]));
-+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C2,
-+ MTK_PHY_DA_TX_I2MPB_C_TST_MASK,
-+ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_C_TST_MASK,
-+ buf[2] + bias[11]));
-+
-+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D1,
-+ MTK_PHY_DA_TX_I2MPB_D_GBE_MASK,
-+ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_D_GBE_MASK,
-+ buf[3] + bias[12]));
-+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D1,
-+ MTK_PHY_DA_TX_I2MPB_D_TBT_MASK,
-+ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_D_TBT_MASK,
-+ buf[3] + bias[13]));
-+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D2,
-+ MTK_PHY_DA_TX_I2MPB_D_HBT_MASK,
-+ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_D_HBT_MASK,
-+ buf[3] + bias[14]));
-+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D2,
-+ MTK_PHY_DA_TX_I2MPB_D_TST_MASK,
-+ FIELD_PREP(MTK_PHY_DA_TX_I2MPB_D_TST_MASK,
-+ buf[3] + bias[15]));
-+
-+ return 0;
-+}
-+
-+static int tx_amp_cal_efuse(struct phy_device *phydev, u32 *buf)
-+{
-+ u16 tx_amp_cal_val[4];
-+
-+ tx_amp_cal_val[0] = EFS_DA_TX_I2MPB_A(buf[0]);
-+ tx_amp_cal_val[1] = EFS_DA_TX_I2MPB_B(buf[0]);
-+ tx_amp_cal_val[2] = EFS_DA_TX_I2MPB_C(buf[0]);
-+ tx_amp_cal_val[3] = EFS_DA_TX_I2MPB_D(buf[0]);
-+ tx_amp_fill_result(phydev, tx_amp_cal_val);
-+
-+ return 0;
-+}
-+
-+static int tx_r50_fill_result(struct phy_device *phydev, u16 tx_r50_cal_val,
-+ u8 txg_calen_x)
-+{
-+ int bias = 0;
-+ u16 reg, val;
-+
-+ if (phydev->drv->phy_id == MTK_GPHY_ID_MT7988)
-+ bias = -1;
-+
-+ val = clamp_val(bias + tx_r50_cal_val, 0, 63);
-+
-+ switch (txg_calen_x) {
-+ case PAIR_A:
-+ reg = MTK_PHY_DA_TX_R50_PAIR_A;
-+ break;
-+ case PAIR_B:
-+ reg = MTK_PHY_DA_TX_R50_PAIR_B;
-+ break;
-+ case PAIR_C:
-+ reg = MTK_PHY_DA_TX_R50_PAIR_C;
-+ break;
-+ case PAIR_D:
-+ reg = MTK_PHY_DA_TX_R50_PAIR_D;
-+ break;
-+ default:
-+ return -EINVAL;
-+ }
-+
-+ phy_write_mmd(phydev, MDIO_MMD_VEND1, reg, val | val << 8);
-+
-+ return 0;
-+}
-+
-+static int tx_r50_cal_efuse(struct phy_device *phydev, u32 *buf,
-+ u8 txg_calen_x)
-+{
-+ u16 tx_r50_cal_val;
-+
-+ switch (txg_calen_x) {
-+ case PAIR_A:
-+ tx_r50_cal_val = EFS_DA_TX_R50_A(buf[1]);
-+ break;
-+ case PAIR_B:
-+ tx_r50_cal_val = EFS_DA_TX_R50_B(buf[1]);
-+ break;
-+ case PAIR_C:
-+ tx_r50_cal_val = EFS_DA_TX_R50_C(buf[2]);
-+ break;
-+ case PAIR_D:
-+ tx_r50_cal_val = EFS_DA_TX_R50_D(buf[2]);
-+ break;
-+ default:
-+ return -EINVAL;
-+ }
-+ tx_r50_fill_result(phydev, tx_r50_cal_val, txg_calen_x);
-+
-+ return 0;
-+}
-+
-+static int tx_vcm_cal_sw(struct phy_device *phydev, u8 rg_txreserve_x)
-+{
-+ u8 lower_idx, upper_idx, txreserve_val;
-+ u8 lower_ret, upper_ret;
-+ int ret;
-+
-+ phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0,
-+ MTK_PHY_RG_ANA_CALEN);
-+ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0,
-+ MTK_PHY_RG_CAL_CKINV);
-+ phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1,
-+ MTK_PHY_RG_TXVOS_CALEN);
-+
-+ switch (rg_txreserve_x) {
-+ case PAIR_A:
-+ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
-+ MTK_PHY_RG_DASN_DAC_IN0_A,
-+ MTK_PHY_DASN_DAC_IN0_A_MASK);
-+ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
-+ MTK_PHY_RG_DASN_DAC_IN1_A,
-+ MTK_PHY_DASN_DAC_IN1_A_MASK);
-+ phy_set_bits_mmd(phydev, MDIO_MMD_VEND1,
-+ MTK_PHY_RG_ANA_CAL_RG0,
-+ MTK_PHY_RG_ZCALEN_A);
-+ break;
-+ case PAIR_B:
-+ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
-+ MTK_PHY_RG_DASN_DAC_IN0_B,
-+ MTK_PHY_DASN_DAC_IN0_B_MASK);
-+ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
-+ MTK_PHY_RG_DASN_DAC_IN1_B,
-+ MTK_PHY_DASN_DAC_IN1_B_MASK);
-+ phy_set_bits_mmd(phydev, MDIO_MMD_VEND1,
-+ MTK_PHY_RG_ANA_CAL_RG1,
-+ MTK_PHY_RG_ZCALEN_B);
-+ break;
-+ case PAIR_C:
-+ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
-+ MTK_PHY_RG_DASN_DAC_IN0_C,
-+ MTK_PHY_DASN_DAC_IN0_C_MASK);
-+ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
-+ MTK_PHY_RG_DASN_DAC_IN1_C,
-+ MTK_PHY_DASN_DAC_IN1_C_MASK);
-+ phy_set_bits_mmd(phydev, MDIO_MMD_VEND1,
-+ MTK_PHY_RG_ANA_CAL_RG1,
-+ MTK_PHY_RG_ZCALEN_C);
-+ break;
-+ case PAIR_D:
-+ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
-+ MTK_PHY_RG_DASN_DAC_IN0_D,
-+ MTK_PHY_DASN_DAC_IN0_D_MASK);
-+ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
-+ MTK_PHY_RG_DASN_DAC_IN1_D,
-+ MTK_PHY_DASN_DAC_IN1_D_MASK);
-+ phy_set_bits_mmd(phydev, MDIO_MMD_VEND1,
-+ MTK_PHY_RG_ANA_CAL_RG1,
-+ MTK_PHY_RG_ZCALEN_D);
-+ break;
-+ default:
-+ ret = -EINVAL;
-+ goto restore;
-+ }
-+
-+ lower_idx = TXRESERVE_MIN;
-+ upper_idx = TXRESERVE_MAX;
-+
-+ phydev_dbg(phydev, "Start TX-VCM SW cal.\n");
-+ while ((upper_idx - lower_idx) > 1) {
-+ txreserve_val = DIV_ROUND_CLOSEST(lower_idx + upper_idx, 2);
-+ ret = cal_cycle(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG9,
-+ MTK_PHY_DA_RX_PSBN_TBT_MASK |
-+ MTK_PHY_DA_RX_PSBN_HBT_MASK |
-+ MTK_PHY_DA_RX_PSBN_GBE_MASK |
-+ MTK_PHY_DA_RX_PSBN_LP_MASK,
-+ txreserve_val << 12 | txreserve_val << 8 |
-+ txreserve_val << 4 | txreserve_val);
-+ if (ret == 1) {
-+ upper_idx = txreserve_val;
-+ upper_ret = ret;
-+ } else if (ret == 0) {
-+ lower_idx = txreserve_val;
-+ lower_ret = ret;
-+ } else {
-+ goto restore;
-+ }
-+ }
-+
-+ if (lower_idx == TXRESERVE_MIN) {
-+ lower_ret = cal_cycle(phydev, MDIO_MMD_VEND1,
-+ MTK_PHY_RXADC_CTRL_RG9,
-+ MTK_PHY_DA_RX_PSBN_TBT_MASK |
-+ MTK_PHY_DA_RX_PSBN_HBT_MASK |
-+ MTK_PHY_DA_RX_PSBN_GBE_MASK |
-+ MTK_PHY_DA_RX_PSBN_LP_MASK,
-+ lower_idx << 12 | lower_idx << 8 |
-+ lower_idx << 4 | lower_idx);
-+ ret = lower_ret;
-+ } else if (upper_idx == TXRESERVE_MAX) {
-+ upper_ret = cal_cycle(phydev, MDIO_MMD_VEND1,
-+ MTK_PHY_RXADC_CTRL_RG9,
-+ MTK_PHY_DA_RX_PSBN_TBT_MASK |
-+ MTK_PHY_DA_RX_PSBN_HBT_MASK |
-+ MTK_PHY_DA_RX_PSBN_GBE_MASK |
-+ MTK_PHY_DA_RX_PSBN_LP_MASK,
-+ upper_idx << 12 | upper_idx << 8 |
-+ upper_idx << 4 | upper_idx);
-+ ret = upper_ret;
-+ }
-+ if (ret < 0)
-+ goto restore;
-+
-+ /* We calibrate TX-VCM in different logic. Check upper index and then
-+ * lower index. If this calibration is valid, apply lower index's
-+ * result.
-+ */
-+ ret = upper_ret - lower_ret;
-+ if (ret == 1) {
-+ ret = 0;
-+ /* Make sure we use upper_idx in our calibration system */
-+ cal_cycle(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG9,
-+ MTK_PHY_DA_RX_PSBN_TBT_MASK |
-+ MTK_PHY_DA_RX_PSBN_HBT_MASK |
-+ MTK_PHY_DA_RX_PSBN_GBE_MASK |
-+ MTK_PHY_DA_RX_PSBN_LP_MASK,
-+ upper_idx << 12 | upper_idx << 8 |
-+ upper_idx << 4 | upper_idx);
-+ phydev_dbg(phydev, "TX-VCM SW cal result: 0x%x\n", upper_idx);
-+ } else if (lower_idx == TXRESERVE_MIN && upper_ret == 1 &&
-+ lower_ret == 1) {
-+ ret = 0;
-+ cal_cycle(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG9,
-+ MTK_PHY_DA_RX_PSBN_TBT_MASK |
-+ MTK_PHY_DA_RX_PSBN_HBT_MASK |
-+ MTK_PHY_DA_RX_PSBN_GBE_MASK |
-+ MTK_PHY_DA_RX_PSBN_LP_MASK,
-+ lower_idx << 12 | lower_idx << 8 |
-+ lower_idx << 4 | lower_idx);
-+ phydev_warn(phydev, "TX-VCM SW cal result at low margin 0x%x\n",
-+ lower_idx);
-+ } else if (upper_idx == TXRESERVE_MAX && upper_ret == 0 &&
-+ lower_ret == 0) {
-+ ret = 0;
-+ phydev_warn(phydev,
-+ "TX-VCM SW cal result at high margin 0x%x\n",
-+ upper_idx);
-+ } else {
-+ ret = -EINVAL;
-+ }
-+
-+restore:
-+ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0,
-+ MTK_PHY_RG_ANA_CALEN);
-+ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1,
-+ MTK_PHY_RG_TXVOS_CALEN);
-+ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0,
-+ MTK_PHY_RG_ZCALEN_A);
-+ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1,
-+ MTK_PHY_RG_ZCALEN_B | MTK_PHY_RG_ZCALEN_C |
-+ MTK_PHY_RG_ZCALEN_D);
-+
-+ return ret;
-+}
-+
-+static void mt798x_phy_common_finetune(struct phy_device *phydev)
-+{
-+ phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
-+ /* SlvDSPreadyTime = 24, MasDSPreadyTime = 24 */
-+ __phy_write(phydev, 0x11, 0xc71);
-+ __phy_write(phydev, 0x12, 0xc);
-+ __phy_write(phydev, 0x10, 0x8fae);
-+
-+ /* EnabRandUpdTrig = 1 */
-+ __phy_write(phydev, 0x11, 0x2f00);
-+ __phy_write(phydev, 0x12, 0xe);
-+ __phy_write(phydev, 0x10, 0x8fb0);
-+
-+ /* NormMseLoThresh = 85 */
-+ __phy_write(phydev, 0x11, 0x55a0);
-+ __phy_write(phydev, 0x12, 0x0);
-+ __phy_write(phydev, 0x10, 0x83aa);
-+
-+ /* FfeUpdGainForce = 1(Enable), FfeUpdGainForceVal = 4 */
-+ __phy_write(phydev, 0x11, 0x240);
-+ __phy_write(phydev, 0x12, 0x0);
-+ __phy_write(phydev, 0x10, 0x9680);
-+
-+ /* TrFreeze = 0 (mt7988 default) */
-+ __phy_write(phydev, 0x11, 0x0);
-+ __phy_write(phydev, 0x12, 0x0);
-+ __phy_write(phydev, 0x10, 0x9686);
-+
-+ /* SSTrKp100 = 5 */
-+ /* SSTrKf100 = 6 */
-+ /* SSTrKp1000Mas = 5 */
-+ /* SSTrKf1000Mas = 6 */
-+ /* SSTrKp1000Slv = 5 */
-+ /* SSTrKf1000Slv = 6 */
-+ __phy_write(phydev, 0x11, 0xbaef);
-+ __phy_write(phydev, 0x12, 0x2e);
-+ __phy_write(phydev, 0x10, 0x968c);
-+ phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
-+}
-+
-+static void mt7981_phy_finetune(struct phy_device *phydev)
-+{
-+ u16 val[8] = { 0x01ce, 0x01c1,
-+ 0x020f, 0x0202,
-+ 0x03d0, 0x03c0,
-+ 0x0013, 0x0005 };
-+ int i, k;
-+
-+ /* 100M eye finetune:
-+ * Keep middle level of TX MLT3 shapper as default.
-+ * Only change TX MLT3 overshoot level here.
-+ */
-+ for (k = 0, i = 1; i < 12; i++) {
-+ if (i % 3 == 0)
-+ continue;
-+ phy_write_mmd(phydev, MDIO_MMD_VEND1, i, val[k++]);
-+ }
-+
-+ phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
-+ /* ResetSyncOffset = 6 */
-+ __phy_write(phydev, 0x11, 0x600);
-+ __phy_write(phydev, 0x12, 0x0);
-+ __phy_write(phydev, 0x10, 0x8fc0);
-+
-+ /* VgaDecRate = 1 */
-+ __phy_write(phydev, 0x11, 0x4c2a);
-+ __phy_write(phydev, 0x12, 0x3e);
-+ __phy_write(phydev, 0x10, 0x8fa4);
-+
-+ /* MrvlTrFix100Kp = 3, MrvlTrFix100Kf = 2,
-+ * MrvlTrFix1000Kp = 3, MrvlTrFix1000Kf = 2
-+ */
-+ __phy_write(phydev, 0x11, 0xd10a);
-+ __phy_write(phydev, 0x12, 0x34);
-+ __phy_write(phydev, 0x10, 0x8f82);
-+
-+ /* VcoSlicerThreshBitsHigh */
-+ __phy_write(phydev, 0x11, 0x5555);
-+ __phy_write(phydev, 0x12, 0x55);
-+ __phy_write(phydev, 0x10, 0x8ec0);
-+ phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
-+
-+ /* TR_OPEN_LOOP_EN = 1, lpf_x_average = 9 */
-+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG234,
-+ MTK_PHY_TR_OPEN_LOOP_EN_MASK |
-+ MTK_PHY_LPF_X_AVERAGE_MASK,
-+ BIT(0) | FIELD_PREP(MTK_PHY_LPF_X_AVERAGE_MASK, 0x9));
-+
-+ /* rg_tr_lpf_cnt_val = 512 */
-+ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LPF_CNT_VAL, 0x200);
-+
-+ /* IIR2 related */
-+ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K1_L, 0x82);
-+ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K1_U, 0x0);
-+ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K2_L, 0x103);
-+ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K2_U, 0x0);
-+ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K3_L, 0x82);
-+ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K3_U, 0x0);
-+ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K4_L, 0xd177);
-+ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K4_U, 0x3);
-+ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K5_L, 0x2c82);
-+ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K5_U, 0xe);
-+
-+ /* FFE peaking */
-+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG27C,
-+ MTK_PHY_VGASTATE_FFE_THR_ST1_MASK, 0x1b << 8);
-+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG27D,
-+ MTK_PHY_VGASTATE_FFE_THR_ST2_MASK, 0x1e);
-+
-+ /* Disable LDO pump */
-+ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_LDO_PUMP_EN_PAIRAB, 0x0);
-+ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_LDO_PUMP_EN_PAIRCD, 0x0);
-+ /* Adjust LDO output voltage */
-+ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_LDO_OUTPUT_V, 0x2222);
-+}
-+
-+static void mt7988_phy_finetune(struct phy_device *phydev)
-+{
-+ u16 val[12] = { 0x0187, 0x01cd, 0x01c8, 0x0182,
-+ 0x020d, 0x0206, 0x0384, 0x03d0,
-+ 0x03c6, 0x030a, 0x0011, 0x0005 };
-+ int i;
-+
-+ /* Set default MLT3 shaper first */
-+ for (i = 0; i < 12; i++)
-+ phy_write_mmd(phydev, MDIO_MMD_VEND1, i, val[i]);
-+
-+ /* TCT finetune */
-+ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_TX_FILTER, 0x5);
-+
-+ phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
-+ /* ResetSyncOffset = 5 */
-+ __phy_write(phydev, 0x11, 0x500);
-+ __phy_write(phydev, 0x12, 0x0);
-+ __phy_write(phydev, 0x10, 0x8fc0);
-+
-+ /* VgaDecRate is 1 at default on mt7988 */
-+
-+ /* MrvlTrFix100Kp = 6, MrvlTrFix100Kf = 7,
-+ * MrvlTrFix1000Kp = 6, MrvlTrFix1000Kf = 7
-+ */
-+ __phy_write(phydev, 0x11, 0xb90a);
-+ __phy_write(phydev, 0x12, 0x6f);
-+ __phy_write(phydev, 0x10, 0x8f82);
-+
-+ /* RemAckCntLimitCtrl = 1 */
-+ __phy_write(phydev, 0x11, 0xfbba);
-+ __phy_write(phydev, 0x12, 0xc3);
-+ __phy_write(phydev, 0x10, 0x87f8);
-+
-+ phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
-+
-+ /* TR_OPEN_LOOP_EN = 1, lpf_x_average = 10 */
-+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG234,
-+ MTK_PHY_TR_OPEN_LOOP_EN_MASK |
-+ MTK_PHY_LPF_X_AVERAGE_MASK,
-+ BIT(0) | FIELD_PREP(MTK_PHY_LPF_X_AVERAGE_MASK, 0xa));
-+
-+ /* rg_tr_lpf_cnt_val = 1023 */
-+ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LPF_CNT_VAL, 0x3ff);
-+}
-+
-+static void mt798x_phy_eee(struct phy_device *phydev)
-+{
-+ phy_modify_mmd(phydev, MDIO_MMD_VEND1,
-+ MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG120,
-+ MTK_PHY_LPI_SIG_EN_LO_THRESH1000_MASK |
-+ MTK_PHY_LPI_SIG_EN_HI_THRESH1000_MASK,
-+ FIELD_PREP(MTK_PHY_LPI_SIG_EN_LO_THRESH1000_MASK, 0x0) |
-+ FIELD_PREP(MTK_PHY_LPI_SIG_EN_HI_THRESH1000_MASK, 0x14));
-+
-+ phy_modify_mmd(phydev, MDIO_MMD_VEND1,
-+ MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG122,
-+ MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK,
-+ FIELD_PREP(MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK,
-+ 0xff));
-+
-+ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
-+ MTK_PHY_RG_TESTMUX_ADC_CTRL,
-+ MTK_PHY_RG_TXEN_DIG_MASK);
-+
-+ phy_set_bits_mmd(phydev, MDIO_MMD_VEND1,
-+ MTK_PHY_RG_DEV1E_REG19b, MTK_PHY_BYPASS_DSP_LPI_READY);
-+
-+ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
-+ MTK_PHY_RG_DEV1E_REG234, MTK_PHY_TR_LP_IIR_EEE_EN);
-+
-+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG238,
-+ MTK_PHY_LPI_SLV_SEND_TX_TIMER_MASK |
-+ MTK_PHY_LPI_SLV_SEND_TX_EN,
-+ FIELD_PREP(MTK_PHY_LPI_SLV_SEND_TX_TIMER_MASK, 0x120));
-+
-+ /* Keep MTK_PHY_LPI_SEND_LOC_TIMER as 375 */
-+ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG239,
-+ MTK_PHY_LPI_TXPCS_LOC_RCV);
-+
-+ /* This also fixes some IoT issues, such as CH340 */
-+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG2C7,
-+ MTK_PHY_MAX_GAIN_MASK | MTK_PHY_MIN_GAIN_MASK,
-+ FIELD_PREP(MTK_PHY_MAX_GAIN_MASK, 0x8) |
-+ FIELD_PREP(MTK_PHY_MIN_GAIN_MASK, 0x13));
-+
-+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG2D1,
-+ MTK_PHY_VCO_SLICER_THRESH_BITS_HIGH_EEE_MASK,
-+ FIELD_PREP(MTK_PHY_VCO_SLICER_THRESH_BITS_HIGH_EEE_MASK,
-+ 0x33) |
-+ MTK_PHY_LPI_SKIP_SD_SLV_TR | MTK_PHY_LPI_TR_READY |
-+ MTK_PHY_LPI_VCO_EEE_STG0_EN);
-+
-+ phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG323,
-+ MTK_PHY_EEE_WAKE_MAS_INT_DC |
-+ MTK_PHY_EEE_WAKE_SLV_INT_DC);
-+
-+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG324,
-+ MTK_PHY_SMI_DETCNT_MAX_MASK,
-+ FIELD_PREP(MTK_PHY_SMI_DETCNT_MAX_MASK, 0x3f) |
-+ MTK_PHY_SMI_DET_MAX_EN);
-+
-+ phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG326,
-+ MTK_PHY_LPI_MODE_SD_ON | MTK_PHY_RESET_RANDUPD_CNT |
-+ MTK_PHY_TREC_UPDATE_ENAB_CLR |
-+ MTK_PHY_LPI_QUIT_WAIT_DFE_SIG_DET_OFF |
-+ MTK_PHY_TR_READY_SKIP_AFE_WAKEUP);
-+
-+ phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
-+ /* Regsigdet_sel_1000 = 0 */
-+ __phy_write(phydev, 0x11, 0xb);
-+ __phy_write(phydev, 0x12, 0x0);
-+ __phy_write(phydev, 0x10, 0x9690);
-+
-+ /* REG_EEE_st2TrKf1000 = 2 */
-+ __phy_write(phydev, 0x11, 0x114f);
-+ __phy_write(phydev, 0x12, 0x2);
-+ __phy_write(phydev, 0x10, 0x969a);
-+
-+ /* RegEEE_slv_wake_tr_timer_tar = 6, RegEEE_slv_remtx_timer_tar = 20 */
-+ __phy_write(phydev, 0x11, 0x3028);
-+ __phy_write(phydev, 0x12, 0x0);
-+ __phy_write(phydev, 0x10, 0x969e);
-+
-+ /* RegEEE_slv_wake_int_timer_tar = 8 */
-+ __phy_write(phydev, 0x11, 0x5010);
-+ __phy_write(phydev, 0x12, 0x0);
-+ __phy_write(phydev, 0x10, 0x96a0);
-+
-+ /* RegEEE_trfreeze_timer2 = 586 */
-+ __phy_write(phydev, 0x11, 0x24a);
-+ __phy_write(phydev, 0x12, 0x0);
-+ __phy_write(phydev, 0x10, 0x96a8);
-+
-+ /* RegEEE100Stg1_tar = 16 */
-+ __phy_write(phydev, 0x11, 0x3210);
-+ __phy_write(phydev, 0x12, 0x0);
-+ __phy_write(phydev, 0x10, 0x96b8);
-+
-+ /* REGEEE_wake_slv_tr_wait_dfesigdet_en = 0 */
-+ __phy_write(phydev, 0x11, 0x1463);
-+ __phy_write(phydev, 0x12, 0x0);
-+ __phy_write(phydev, 0x10, 0x96ca);
-+
-+ /* DfeTailEnableVgaThresh1000 = 27 */
-+ __phy_write(phydev, 0x11, 0x36);
-+ __phy_write(phydev, 0x12, 0x0);
-+ __phy_write(phydev, 0x10, 0x8f80);
-+ phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
-+
-+ phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_3);
-+ __phy_modify(phydev, MTK_PHY_LPI_REG_14,
-+ MTK_PHY_LPI_WAKE_TIMER_1000_MASK,
-+ FIELD_PREP(MTK_PHY_LPI_WAKE_TIMER_1000_MASK, 0x19c));
-+
-+ __phy_modify(phydev, MTK_PHY_LPI_REG_1c, MTK_PHY_SMI_DET_ON_THRESH_MASK,
-+ FIELD_PREP(MTK_PHY_SMI_DET_ON_THRESH_MASK, 0xc));
-+ phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
-+
-+ phy_modify_mmd(phydev, MDIO_MMD_VEND1,
-+ MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG122,
-+ MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK,
-+ FIELD_PREP(MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK,
-+ 0xff));
-+}
-+
-+static int cal_sw(struct phy_device *phydev, enum CAL_ITEM cal_item,
-+ u8 start_pair, u8 end_pair)
-+{
-+ u8 pair_n;
-+ int ret;
-+
-+ for (pair_n = start_pair; pair_n <= end_pair; pair_n++) {
-+ /* TX_OFFSET & TX_AMP have no SW calibration. */
-+ switch (cal_item) {
-+ case TX_VCM:
-+ ret = tx_vcm_cal_sw(phydev, pair_n);
-+ break;
-+ default:
-+ return -EINVAL;
-+ }
-+ if (ret)
-+ return ret;
-+ }
-+ return 0;
-+}
-+
-+static int cal_efuse(struct phy_device *phydev, enum CAL_ITEM cal_item,
-+ u8 start_pair, u8 end_pair, u32 *buf)
-+{
-+ u8 pair_n;
-+ int ret;
-+
-+ for (pair_n = start_pair; pair_n <= end_pair; pair_n++) {
-+ /* TX_VCM has no efuse calibration. */
-+ switch (cal_item) {
-+ case REXT:
-+ ret = rext_cal_efuse(phydev, buf);
-+ break;
-+ case TX_OFFSET:
-+ ret = tx_offset_cal_efuse(phydev, buf);
-+ break;
-+ case TX_AMP:
-+ ret = tx_amp_cal_efuse(phydev, buf);
-+ break;
-+ case TX_R50:
-+ ret = tx_r50_cal_efuse(phydev, buf, pair_n);
-+ break;
-+ default:
-+ return -EINVAL;
-+ }
-+ if (ret)
-+ return ret;
-+ }
-+
-+ return 0;
-+}
-+
-+static int start_cal(struct phy_device *phydev, enum CAL_ITEM cal_item,
-+ enum CAL_MODE cal_mode, u8 start_pair,
-+ u8 end_pair, u32 *buf)
-+{
-+ int ret;
-+
-+ switch (cal_mode) {
-+ case EFUSE_M:
-+ ret = cal_efuse(phydev, cal_item, start_pair,
-+ end_pair, buf);
-+ break;
-+ case SW_M:
-+ ret = cal_sw(phydev, cal_item, start_pair, end_pair);
-+ break;
-+ default:
-+ return -EINVAL;
-+ }
-+
-+ if (ret) {
-+ phydev_err(phydev, "cal %d failed\n", cal_item);
-+ return -EIO;
-+ }
-+
-+ return 0;
-+}
-+
-+static int mt798x_phy_calibration(struct phy_device *phydev)
-+{
-+ struct nvmem_cell *cell;
-+ int ret = 0;
-+ size_t len;
-+ u32 *buf;
-+
-+ cell = nvmem_cell_get(&phydev->mdio.dev, "phy-cal-data");
-+ if (IS_ERR(cell)) {
-+ if (PTR_ERR(cell) == -EPROBE_DEFER)
-+ return PTR_ERR(cell);
-+ return 0;
-+ }
-+
-+ buf = (u32 *)nvmem_cell_read(cell, &len);
-+ if (IS_ERR(buf))
-+ return PTR_ERR(buf);
-+ nvmem_cell_put(cell);
-+
-+ if (!buf[0] || !buf[1] || !buf[2] || !buf[3] || len < 4 * sizeof(u32)) {
-+ phydev_err(phydev, "invalid efuse data\n");
-+ ret = -EINVAL;
-+ goto out;
-+ }
-+
-+ ret = start_cal(phydev, REXT, EFUSE_M, NO_PAIR, NO_PAIR, buf);
-+ if (ret)
-+ goto out;
-+ ret = start_cal(phydev, TX_OFFSET, EFUSE_M, NO_PAIR, NO_PAIR, buf);
-+ if (ret)
-+ goto out;
-+ ret = start_cal(phydev, TX_AMP, EFUSE_M, NO_PAIR, NO_PAIR, buf);
-+ if (ret)
-+ goto out;
-+ ret = start_cal(phydev, TX_R50, EFUSE_M, PAIR_A, PAIR_D, buf);
-+ if (ret)
-+ goto out;
-+ ret = start_cal(phydev, TX_VCM, SW_M, PAIR_A, PAIR_A, buf);
-+ if (ret)
-+ goto out;
-+
-+out:
-+ kfree(buf);
-+ return ret;
-+}
-+
-+static int mt798x_phy_config_init(struct phy_device *phydev)
-+{
-+ switch (phydev->drv->phy_id) {
-+ case MTK_GPHY_ID_MT7981:
-+ mt7981_phy_finetune(phydev);
-+ break;
-+ case MTK_GPHY_ID_MT7988:
-+ mt7988_phy_finetune(phydev);
-+ break;
-+ }
-+
-+ mt798x_phy_common_finetune(phydev);
-+ mt798x_phy_eee(phydev);
-+
-+ return mt798x_phy_calibration(phydev);
-+}
-+
-+static int mt798x_phy_hw_led_on_set(struct phy_device *phydev, u8 index,
-+ bool on)
-+{
-+ unsigned int bit_on = MTK_PHY_LED_STATE_FORCE_ON + (index ? 16 : 0);
-+ struct mtk_socphy_priv *priv = phydev->priv;
-+ bool changed;
-+
-+ if (on)
-+ changed = !test_and_set_bit(bit_on, &priv->led_state);
-+ else
-+ changed = !!test_and_clear_bit(bit_on, &priv->led_state);
-+
-+ changed |= !!test_and_clear_bit(MTK_PHY_LED_STATE_NETDEV +
-+ (index ? 16 : 0), &priv->led_state);
-+ if (changed)
-+ return phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ?
-+ MTK_PHY_LED1_ON_CTRL :
-+ MTK_PHY_LED0_ON_CTRL,
-+ MTK_PHY_LED_ON_MASK,
-+ on ? MTK_PHY_LED_ON_FORCE_ON : 0);
-+ else
-+ return 0;
-+}
-+
-+static int mt798x_phy_hw_led_blink_set(struct phy_device *phydev, u8 index,
-+ bool blinking)
-+{
-+ unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK +
-+ (index ? 16 : 0);
-+ struct mtk_socphy_priv *priv = phydev->priv;
-+ bool changed;
-+
-+ if (blinking)
-+ changed = !test_and_set_bit(bit_blink, &priv->led_state);
-+ else
-+ changed = !!test_and_clear_bit(bit_blink, &priv->led_state);
-+
-+ changed |= !!test_bit(MTK_PHY_LED_STATE_NETDEV +
-+ (index ? 16 : 0), &priv->led_state);
-+ if (changed)
-+ return phy_write_mmd(phydev, MDIO_MMD_VEND2, index ?
-+ MTK_PHY_LED1_BLINK_CTRL :
-+ MTK_PHY_LED0_BLINK_CTRL,
-+ blinking ?
-+ MTK_PHY_LED_BLINK_FORCE_BLINK : 0);
-+ else
-+ return 0;
-+}
-+
-+static int mt798x_phy_led_blink_set(struct phy_device *phydev, u8 index,
-+ unsigned long *delay_on,
-+ unsigned long *delay_off)
-+{
-+ bool blinking = false;
-+ int err = 0;
-+
-+ if (index > 1)
-+ return -EINVAL;
-+
-+ if (delay_on && delay_off && (*delay_on > 0) && (*delay_off > 0)) {
-+ blinking = true;
-+ *delay_on = 50;
-+ *delay_off = 50;
-+ }
-+
-+ err = mt798x_phy_hw_led_blink_set(phydev, index, blinking);
-+ if (err)
-+ return err;
-+
-+ return mt798x_phy_hw_led_on_set(phydev, index, false);
-+}
-+
-+static int mt798x_phy_led_brightness_set(struct phy_device *phydev,
-+ u8 index, enum led_brightness value)
-+{
-+ int err;
-+
-+ err = mt798x_phy_hw_led_blink_set(phydev, index, false);
-+ if (err)
-+ return err;
-+
-+ return mt798x_phy_hw_led_on_set(phydev, index, (value != LED_OFF));
-+}
-+
-+static const unsigned long supported_triggers =
-+ BIT(TRIGGER_NETDEV_FULL_DUPLEX) |
-+ BIT(TRIGGER_NETDEV_HALF_DUPLEX) |
-+ BIT(TRIGGER_NETDEV_LINK) |
-+ BIT(TRIGGER_NETDEV_LINK_10) |
-+ BIT(TRIGGER_NETDEV_LINK_100) |
-+ BIT(TRIGGER_NETDEV_LINK_1000) |
-+ BIT(TRIGGER_NETDEV_RX) |
-+ BIT(TRIGGER_NETDEV_TX);
-+
-+static int mt798x_phy_led_hw_is_supported(struct phy_device *phydev, u8 index,
-+ unsigned long rules)
-+{
-+ if (index > 1)
-+ return -EINVAL;
-+
-+ /* All combinations of the supported triggers are allowed */
-+ if (rules & ~supported_triggers)
-+ return -EOPNOTSUPP;
-+
-+ return 0;
-+};
-+
-+static int mt798x_phy_led_hw_control_get(struct phy_device *phydev, u8 index,
-+ unsigned long *rules)
-+{
-+ unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK +
-+ (index ? 16 : 0);
-+ unsigned int bit_netdev = MTK_PHY_LED_STATE_NETDEV + (index ? 16 : 0);
-+ unsigned int bit_on = MTK_PHY_LED_STATE_FORCE_ON + (index ? 16 : 0);
-+ struct mtk_socphy_priv *priv = phydev->priv;
-+ int on, blink;
-+
-+ if (index > 1)
-+ return -EINVAL;
-+
-+ on = phy_read_mmd(phydev, MDIO_MMD_VEND2,
-+ index ? MTK_PHY_LED1_ON_CTRL : MTK_PHY_LED0_ON_CTRL);
-+
-+ if (on < 0)
-+ return -EIO;
-+
-+ blink = phy_read_mmd(phydev, MDIO_MMD_VEND2,
-+ index ? MTK_PHY_LED1_BLINK_CTRL :
-+ MTK_PHY_LED0_BLINK_CTRL);
-+ if (blink < 0)
-+ return -EIO;
-+
-+ if ((on & (MTK_PHY_LED_ON_LINK | MTK_PHY_LED_ON_FDX |
-+ MTK_PHY_LED_ON_HDX | MTK_PHY_LED_ON_LINKDOWN)) ||
-+ (blink & (MTK_PHY_LED_BLINK_RX | MTK_PHY_LED_BLINK_TX)))
-+ set_bit(bit_netdev, &priv->led_state);
-+ else
-+ clear_bit(bit_netdev, &priv->led_state);
-+
-+ if (on & MTK_PHY_LED_ON_FORCE_ON)
-+ set_bit(bit_on, &priv->led_state);
-+ else
-+ clear_bit(bit_on, &priv->led_state);
-+
-+ if (blink & MTK_PHY_LED_BLINK_FORCE_BLINK)
-+ set_bit(bit_blink, &priv->led_state);
-+ else
-+ clear_bit(bit_blink, &priv->led_state);
-+
-+ if (!rules)
-+ return 0;
-+
-+ if (on & MTK_PHY_LED_ON_LINK)
-+ *rules |= BIT(TRIGGER_NETDEV_LINK);
-+
-+ if (on & MTK_PHY_LED_ON_LINK10)
-+ *rules |= BIT(TRIGGER_NETDEV_LINK_10);
-+
-+ if (on & MTK_PHY_LED_ON_LINK100)
-+ *rules |= BIT(TRIGGER_NETDEV_LINK_100);
-+
-+ if (on & MTK_PHY_LED_ON_LINK1000)
-+ *rules |= BIT(TRIGGER_NETDEV_LINK_1000);
-+
-+ if (on & MTK_PHY_LED_ON_FDX)
-+ *rules |= BIT(TRIGGER_NETDEV_FULL_DUPLEX);
-+
-+ if (on & MTK_PHY_LED_ON_HDX)
-+ *rules |= BIT(TRIGGER_NETDEV_HALF_DUPLEX);
-+
-+ if (blink & MTK_PHY_LED_BLINK_RX)
-+ *rules |= BIT(TRIGGER_NETDEV_RX);
-+
-+ if (blink & MTK_PHY_LED_BLINK_TX)
-+ *rules |= BIT(TRIGGER_NETDEV_TX);
-+
-+ return 0;
-+};
-+
-+static int mt798x_phy_led_hw_control_set(struct phy_device *phydev, u8 index,
-+ unsigned long rules)
-+{
-+ unsigned int bit_netdev = MTK_PHY_LED_STATE_NETDEV + (index ? 16 : 0);
-+ struct mtk_socphy_priv *priv = phydev->priv;
-+ u16 on = 0, blink = 0;
-+ int ret;
-+
-+ if (index > 1)
-+ return -EINVAL;
-+
-+ if (rules & BIT(TRIGGER_NETDEV_FULL_DUPLEX))
-+ on |= MTK_PHY_LED_ON_FDX;
-+
-+ if (rules & BIT(TRIGGER_NETDEV_HALF_DUPLEX))
-+ on |= MTK_PHY_LED_ON_HDX;
-+
-+ if (rules & (BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_LINK)))
-+ on |= MTK_PHY_LED_ON_LINK10;
-+
-+ if (rules & (BIT(TRIGGER_NETDEV_LINK_100) | BIT(TRIGGER_NETDEV_LINK)))
-+ on |= MTK_PHY_LED_ON_LINK100;
-+
-+ if (rules & (BIT(TRIGGER_NETDEV_LINK_1000) | BIT(TRIGGER_NETDEV_LINK)))
-+ on |= MTK_PHY_LED_ON_LINK1000;
-+
-+ if (rules & BIT(TRIGGER_NETDEV_RX)) {
-+ blink |= (on & MTK_PHY_LED_ON_LINK) ?
-+ (((on & MTK_PHY_LED_ON_LINK10) ?
-+ MTK_PHY_LED_BLINK_10RX : 0) |
-+ ((on & MTK_PHY_LED_ON_LINK100) ?
-+ MTK_PHY_LED_BLINK_100RX : 0) |
-+ ((on & MTK_PHY_LED_ON_LINK1000) ?
-+ MTK_PHY_LED_BLINK_1000RX : 0)) :
-+ MTK_PHY_LED_BLINK_RX;
-+ }
-+
-+ if (rules & BIT(TRIGGER_NETDEV_TX)) {
-+ blink |= (on & MTK_PHY_LED_ON_LINK) ?
-+ (((on & MTK_PHY_LED_ON_LINK10) ?
-+ MTK_PHY_LED_BLINK_10TX : 0) |
-+ ((on & MTK_PHY_LED_ON_LINK100) ?
-+ MTK_PHY_LED_BLINK_100TX : 0) |
-+ ((on & MTK_PHY_LED_ON_LINK1000) ?
-+ MTK_PHY_LED_BLINK_1000TX : 0)) :
-+ MTK_PHY_LED_BLINK_TX;
-+ }
-+
-+ if (blink || on)
-+ set_bit(bit_netdev, &priv->led_state);
-+ else
-+ clear_bit(bit_netdev, &priv->led_state);
-+
-+ ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ?
-+ MTK_PHY_LED1_ON_CTRL :
-+ MTK_PHY_LED0_ON_CTRL,
-+ MTK_PHY_LED_ON_FDX |
-+ MTK_PHY_LED_ON_HDX |
-+ MTK_PHY_LED_ON_LINK,
-+ on);
-+
-+ if (ret)
-+ return ret;
-+
-+ return phy_write_mmd(phydev, MDIO_MMD_VEND2, index ?
-+ MTK_PHY_LED1_BLINK_CTRL :
-+ MTK_PHY_LED0_BLINK_CTRL, blink);
-+};
-+
-+static bool mt7988_phy_led_get_polarity(struct phy_device *phydev, int led_num)
-+{
-+ struct mtk_socphy_shared *priv = phydev->shared->priv;
-+ u32 polarities;
-+
-+ if (led_num == 0)
-+ polarities = ~(priv->boottrap);
-+ else
-+ polarities = MTK_PHY_LED1_DEFAULT_POLARITIES;
-+
-+ if (polarities & BIT(phydev->mdio.addr))
-+ return true;
-+
-+ return false;
-+}
-+
-+static int mt7988_phy_fix_leds_polarities(struct phy_device *phydev)
-+{
-+ struct pinctrl *pinctrl;
-+ int index;
-+
-+ /* Setup LED polarity according to bootstrap use of LED pins */
-+ for (index = 0; index < 2; ++index)
-+ phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ?
-+ MTK_PHY_LED1_ON_CTRL : MTK_PHY_LED0_ON_CTRL,
-+ MTK_PHY_LED_ON_POLARITY,
-+ mt7988_phy_led_get_polarity(phydev, index) ?
-+ MTK_PHY_LED_ON_POLARITY : 0);
-+
-+ /* Only now setup pinctrl to avoid bogus blinking */
-+ pinctrl = devm_pinctrl_get_select(&phydev->mdio.dev, "gbe-led");
-+ if (IS_ERR(pinctrl))
-+ dev_err(&phydev->mdio.bus->dev,
-+ "Failed to setup PHY LED pinctrl\n");
-+
-+ return 0;
-+}
-+
-+static int mt7988_phy_probe_shared(struct phy_device *phydev)
-+{
-+ struct device_node *np = dev_of_node(&phydev->mdio.bus->dev);
-+ struct mtk_socphy_shared *shared = phydev->shared->priv;
-+ struct regmap *regmap;
-+ u32 reg;
-+ int ret;
-+
-+ /* The LED0 of the 4 PHYs in MT7988 are wired to SoC pins LED_A, LED_B,
-+ * LED_C and LED_D respectively. At the same time those pins are used to
-+ * bootstrap configuration of the reference clock source (LED_A),
-+ * DRAM DDRx16b x2/x1 (LED_B) and boot device (LED_C, LED_D).
-+ * In practice this is done using a LED and a resistor pulling the pin
-+ * either to GND or to VIO.
-+ * The detected value at boot time is accessible at run-time using the
-+ * TPBANK0 register located in the gpio base of the pinctrl, in order
-+ * to read it here it needs to be referenced by a phandle called
-+ * 'mediatek,pio' in the MDIO bus hosting the PHY.
-+ * The 4 bits in TPBANK0 are kept as package shared data and are used to
-+ * set LED polarity for each of the LED0.
-+ */
-+ regmap = syscon_regmap_lookup_by_phandle(np, "mediatek,pio");
-+ if (IS_ERR(regmap))
-+ return PTR_ERR(regmap);
-+
-+ ret = regmap_read(regmap, RG_GPIO_MISC_TPBANK0, ®);
-+ if (ret)
-+ return ret;
-+
-+ shared->boottrap = FIELD_GET(RG_GPIO_MISC_TPBANK0_BOOTMODE, reg);
-+
-+ return 0;
-+}
-+
-+static void mt798x_phy_leds_state_init(struct phy_device *phydev)
-+{
-+ int i;
-+
-+ for (i = 0; i < 2; ++i)
-+ mt798x_phy_led_hw_control_get(phydev, i, NULL);
-+}
-+
-+static int mt7988_phy_probe(struct phy_device *phydev)
-+{
-+ struct mtk_socphy_shared *shared;
-+ struct mtk_socphy_priv *priv;
-+ int err;
-+
-+ if (phydev->mdio.addr > 3)
-+ return -EINVAL;
-+
-+ err = devm_phy_package_join(&phydev->mdio.dev, phydev, 0,
-+ sizeof(struct mtk_socphy_shared));
-+ if (err)
-+ return err;
-+
-+ if (phy_package_probe_once(phydev)) {
-+ err = mt7988_phy_probe_shared(phydev);
-+ if (err)
-+ return err;
-+ }
-+
-+ shared = phydev->shared->priv;
-+ priv = &shared->priv[phydev->mdio.addr];
-+
-+ phydev->priv = priv;
-+
-+ mt798x_phy_leds_state_init(phydev);
-+
-+ err = mt7988_phy_fix_leds_polarities(phydev);
-+ if (err)
-+ return err;
-+
-+ /* Disable TX power saving at probing to:
-+ * 1. Meet common mode compliance test criteria
-+ * 2. Make sure that TX-VCM calibration works fine
-+ */
-+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG7,
-+ MTK_PHY_DA_AD_BUF_BIAS_LP_MASK, 0x3 << 8);
-+
-+ return mt798x_phy_calibration(phydev);
-+}
-+
-+static int mt7981_phy_probe(struct phy_device *phydev)
-+{
-+ struct mtk_socphy_priv *priv;
-+
-+ priv = devm_kzalloc(&phydev->mdio.dev, sizeof(struct mtk_socphy_priv),
-+ GFP_KERNEL);
-+ if (!priv)
-+ return -ENOMEM;
-+
-+ phydev->priv = priv;
-+
-+ mt798x_phy_leds_state_init(phydev);
-+
-+ return mt798x_phy_calibration(phydev);
-+}
-+
-+static struct phy_driver mtk_socphy_driver[] = {
-+ {
-+ PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7981),
-+ .name = "MediaTek MT7981 PHY",
-+ .config_init = mt798x_phy_config_init,
-+ .config_intr = genphy_no_config_intr,
-+ .handle_interrupt = genphy_handle_interrupt_no_ack,
-+ .probe = mt7981_phy_probe,
-+ .suspend = genphy_suspend,
-+ .resume = genphy_resume,
-+ .read_page = mtk_socphy_read_page,
-+ .write_page = mtk_socphy_write_page,
-+ .led_blink_set = mt798x_phy_led_blink_set,
-+ .led_brightness_set = mt798x_phy_led_brightness_set,
-+ .led_hw_is_supported = mt798x_phy_led_hw_is_supported,
-+ .led_hw_control_set = mt798x_phy_led_hw_control_set,
-+ .led_hw_control_get = mt798x_phy_led_hw_control_get,
-+ },
-+ {
-+ PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7988),
-+ .name = "MediaTek MT7988 PHY",
-+ .config_init = mt798x_phy_config_init,
-+ .config_intr = genphy_no_config_intr,
-+ .handle_interrupt = genphy_handle_interrupt_no_ack,
-+ .probe = mt7988_phy_probe,
-+ .suspend = genphy_suspend,
-+ .resume = genphy_resume,
-+ .read_page = mtk_socphy_read_page,
-+ .write_page = mtk_socphy_write_page,
-+ .led_blink_set = mt798x_phy_led_blink_set,
-+ .led_brightness_set = mt798x_phy_led_brightness_set,
-+ .led_hw_is_supported = mt798x_phy_led_hw_is_supported,
-+ .led_hw_control_set = mt798x_phy_led_hw_control_set,
-+ .led_hw_control_get = mt798x_phy_led_hw_control_get,
-+ },
-+};
-+
-+module_phy_driver(mtk_socphy_driver);
-+
-+static struct mdio_device_id __maybe_unused mtk_socphy_tbl[] = {
-+ { PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7981) },
-+ { PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7988) },
-+ { }
-+};
-+
-+MODULE_DESCRIPTION("MediaTek SoC Gigabit Ethernet PHY driver");
-+MODULE_LICENSE("GPL");
-+
-+MODULE_DEVICE_TABLE(mdio, mtk_socphy_tbl);
---- /dev/null
-+++ b/drivers/net/phy/mediatek/mtk-ge.c
-@@ -0,0 +1,114 @@
-+// SPDX-License-Identifier: GPL-2.0+
-+#include <linux/bitfield.h>
-+#include <linux/module.h>
-+#include <linux/phy.h>
-+
-+#define MTK_EXT_PAGE_ACCESS 0x1f
-+#define MTK_PHY_PAGE_STANDARD 0x0000
-+#define MTK_PHY_PAGE_EXTENDED 0x0001
-+#define MTK_PHY_PAGE_EXTENDED_2 0x0002
-+#define MTK_PHY_PAGE_EXTENDED_3 0x0003
-+#define MTK_PHY_PAGE_EXTENDED_2A30 0x2a30
-+#define MTK_PHY_PAGE_EXTENDED_52B5 0x52b5
-+
-+static int mtk_gephy_read_page(struct phy_device *phydev)
-+{
-+ return __phy_read(phydev, MTK_EXT_PAGE_ACCESS);
-+}
-+
-+static int mtk_gephy_write_page(struct phy_device *phydev, int page)
-+{
-+ return __phy_write(phydev, MTK_EXT_PAGE_ACCESS, page);
-+}
-+
-+static void mtk_gephy_config_init(struct phy_device *phydev)
-+{
-+ /* Disable EEE */
-+ phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV, 0);
-+
-+ /* Enable HW auto downshift */
-+ phy_modify_paged(phydev, MTK_PHY_PAGE_EXTENDED, 0x14, 0, BIT(4));
-+
-+ /* Increase SlvDPSready time */
-+ phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
-+ __phy_write(phydev, 0x10, 0xafae);
-+ __phy_write(phydev, 0x12, 0x2f);
-+ __phy_write(phydev, 0x10, 0x8fae);
-+ phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
-+
-+ /* Adjust 100_mse_threshold */
-+ phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x123, 0xffff);
-+
-+ /* Disable mcc */
-+ phy_write_mmd(phydev, MDIO_MMD_VEND1, 0xa6, 0x300);
-+}
-+
-+static int mt7530_phy_config_init(struct phy_device *phydev)
-+{
-+ mtk_gephy_config_init(phydev);
-+
-+ /* Increase post_update_timer */
-+ phy_write_paged(phydev, MTK_PHY_PAGE_EXTENDED_3, 0x11, 0x4b);
-+
-+ return 0;
-+}
-+
-+static int mt7531_phy_config_init(struct phy_device *phydev)
-+{
-+ mtk_gephy_config_init(phydev);
-+
-+ /* PHY link down power saving enable */
-+ phy_set_bits(phydev, 0x17, BIT(4));
-+ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, 0xc6, 0x300);
-+
-+ /* Set TX Pair delay selection */
-+ phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x13, 0x404);
-+ phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x14, 0x404);
-+
-+ return 0;
-+}
-+
-+static struct phy_driver mtk_gephy_driver[] = {
-+ {
-+ PHY_ID_MATCH_EXACT(0x03a29412),
-+ .name = "MediaTek MT7530 PHY",
-+ .config_init = mt7530_phy_config_init,
-+ /* Interrupts are handled by the switch, not the PHY
-+ * itself.
-+ */
-+ .config_intr = genphy_no_config_intr,
-+ .handle_interrupt = genphy_handle_interrupt_no_ack,
-+ .suspend = genphy_suspend,
-+ .resume = genphy_resume,
-+ .read_page = mtk_gephy_read_page,
-+ .write_page = mtk_gephy_write_page,
-+ },
-+ {
-+ PHY_ID_MATCH_EXACT(0x03a29441),
-+ .name = "MediaTek MT7531 PHY",
-+ .config_init = mt7531_phy_config_init,
-+ /* Interrupts are handled by the switch, not the PHY
-+ * itself.
-+ */
-+ .config_intr = genphy_no_config_intr,
-+ .handle_interrupt = genphy_handle_interrupt_no_ack,
-+ .suspend = genphy_suspend,
-+ .resume = genphy_resume,
-+ .read_page = mtk_gephy_read_page,
-+ .write_page = mtk_gephy_write_page,
-+ },
-+};
-+
-+module_phy_driver(mtk_gephy_driver);
-+
-+static struct mdio_device_id __maybe_unused mtk_gephy_tbl[] = {
-+ { PHY_ID_MATCH_EXACT(0x03a29441) },
-+ { PHY_ID_MATCH_EXACT(0x03a29412) },
-+ { }
-+};
-+
-+MODULE_DESCRIPTION("MediaTek Gigabit Ethernet PHY driver");
-+MODULE_LICENSE("GPL");
-+
-+MODULE_DEVICE_TABLE(mdio, mtk_gephy_tbl);
+++ /dev/null
-From 7f9c320c98dbca18934afa80306015eb71c05a6c Mon Sep 17 00:00:00 2001
-Date: Sat, 9 Nov 2024 00:34:52 +0800
-Subject: [PATCH] net: phy: mediatek: Move LED helper functions into mtk phy
- lib
-
-This patch creates mtk-phy-lib.c & mtk-phy.h and integrates mtk-ge-soc.c's
-LED helper functions so that we can use those helper functions in other
-MTK's ethernet phy driver.
-
----
- MAINTAINERS | 2 +
- drivers/net/phy/mediatek/Kconfig | 4 +
- drivers/net/phy/mediatek/Makefile | 1 +
- drivers/net/phy/mediatek/mtk-ge-soc.c | 280 +++----------------------
- drivers/net/phy/mediatek/mtk-phy-lib.c | 254 ++++++++++++++++++++++
- drivers/net/phy/mediatek/mtk.h | 86 ++++++++
- 6 files changed, 372 insertions(+), 255 deletions(-)
- create mode 100644 drivers/net/phy/mediatek/mtk-phy-lib.c
- create mode 100644 drivers/net/phy/mediatek/mtk.h
-
---- a/drivers/net/phy/mediatek/Kconfig
-+++ b/drivers/net/phy/mediatek/Kconfig
-@@ -1,4 +1,7 @@
- # SPDX-License-Identifier: GPL-2.0-only
-+config MTK_NET_PHYLIB
-+ tristate
-+
- config MEDIATEK_GE_PHY
- tristate "MediaTek Gigabit Ethernet PHYs"
- help
-@@ -13,6 +16,7 @@ config MEDIATEK_GE_SOC_PHY
- tristate "MediaTek SoC Ethernet PHYs"
- depends on (ARM64 && ARCH_MEDIATEK) || COMPILE_TEST
- depends on NVMEM_MTK_EFUSE
-+ select MTK_NET_PHYLIB
- help
- Supports MediaTek SoC built-in Gigabit Ethernet PHYs.
-
---- a/drivers/net/phy/mediatek/Makefile
-+++ b/drivers/net/phy/mediatek/Makefile
-@@ -1,3 +1,4 @@
- # SPDX-License-Identifier: GPL-2.0
-+obj-$(CONFIG_MTK_NET_PHYLIB) += mtk-phy-lib.o
- obj-$(CONFIG_MEDIATEK_GE_PHY) += mtk-ge.o
- obj-$(CONFIG_MEDIATEK_GE_SOC_PHY) += mtk-ge-soc.o
---- a/drivers/net/phy/mediatek/mtk-ge-soc.c
-+++ b/drivers/net/phy/mediatek/mtk-ge-soc.c
-@@ -8,6 +8,8 @@
- #include <linux/phy.h>
- #include <linux/regmap.h>
-
-+#include "mtk.h"
-+
- #define MTK_GPHY_ID_MT7981 0x03a29461
- #define MTK_GPHY_ID_MT7988 0x03a29481
-
-@@ -210,41 +212,6 @@
- #define MTK_PHY_DA_TX_R50_PAIR_D 0x540
-
- /* Registers on MDIO_MMD_VEND2 */
--#define MTK_PHY_LED0_ON_CTRL 0x24
--#define MTK_PHY_LED1_ON_CTRL 0x26
--#define MTK_PHY_LED_ON_MASK GENMASK(6, 0)
--#define MTK_PHY_LED_ON_LINK1000 BIT(0)
--#define MTK_PHY_LED_ON_LINK100 BIT(1)
--#define MTK_PHY_LED_ON_LINK10 BIT(2)
--#define MTK_PHY_LED_ON_LINK (MTK_PHY_LED_ON_LINK10 |\
-- MTK_PHY_LED_ON_LINK100 |\
-- MTK_PHY_LED_ON_LINK1000)
--#define MTK_PHY_LED_ON_LINKDOWN BIT(3)
--#define MTK_PHY_LED_ON_FDX BIT(4) /* Full duplex */
--#define MTK_PHY_LED_ON_HDX BIT(5) /* Half duplex */
--#define MTK_PHY_LED_ON_FORCE_ON BIT(6)
--#define MTK_PHY_LED_ON_POLARITY BIT(14)
--#define MTK_PHY_LED_ON_ENABLE BIT(15)
--
--#define MTK_PHY_LED0_BLINK_CTRL 0x25
--#define MTK_PHY_LED1_BLINK_CTRL 0x27
--#define MTK_PHY_LED_BLINK_1000TX BIT(0)
--#define MTK_PHY_LED_BLINK_1000RX BIT(1)
--#define MTK_PHY_LED_BLINK_100TX BIT(2)
--#define MTK_PHY_LED_BLINK_100RX BIT(3)
--#define MTK_PHY_LED_BLINK_10TX BIT(4)
--#define MTK_PHY_LED_BLINK_10RX BIT(5)
--#define MTK_PHY_LED_BLINK_RX (MTK_PHY_LED_BLINK_10RX |\
-- MTK_PHY_LED_BLINK_100RX |\
-- MTK_PHY_LED_BLINK_1000RX)
--#define MTK_PHY_LED_BLINK_TX (MTK_PHY_LED_BLINK_10TX |\
-- MTK_PHY_LED_BLINK_100TX |\
-- MTK_PHY_LED_BLINK_1000TX)
--#define MTK_PHY_LED_BLINK_COLLISION BIT(6)
--#define MTK_PHY_LED_BLINK_RX_CRC_ERR BIT(7)
--#define MTK_PHY_LED_BLINK_RX_IDLE_ERR BIT(8)
--#define MTK_PHY_LED_BLINK_FORCE_BLINK BIT(9)
--
- #define MTK_PHY_LED1_DEFAULT_POLARITIES BIT(1)
-
- #define MTK_PHY_RG_BG_RASEL 0x115
-@@ -299,14 +266,6 @@ enum CAL_MODE {
- SW_M
- };
-
--#define MTK_PHY_LED_STATE_FORCE_ON 0
--#define MTK_PHY_LED_STATE_FORCE_BLINK 1
--#define MTK_PHY_LED_STATE_NETDEV 2
--
--struct mtk_socphy_priv {
-- unsigned long led_state;
--};
--
- struct mtk_socphy_shared {
- u32 boottrap;
- struct mtk_socphy_priv priv[4];
-@@ -1172,76 +1131,23 @@ static int mt798x_phy_config_init(struct
- return mt798x_phy_calibration(phydev);
- }
-
--static int mt798x_phy_hw_led_on_set(struct phy_device *phydev, u8 index,
-- bool on)
--{
-- unsigned int bit_on = MTK_PHY_LED_STATE_FORCE_ON + (index ? 16 : 0);
-- struct mtk_socphy_priv *priv = phydev->priv;
-- bool changed;
--
-- if (on)
-- changed = !test_and_set_bit(bit_on, &priv->led_state);
-- else
-- changed = !!test_and_clear_bit(bit_on, &priv->led_state);
--
-- changed |= !!test_and_clear_bit(MTK_PHY_LED_STATE_NETDEV +
-- (index ? 16 : 0), &priv->led_state);
-- if (changed)
-- return phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ?
-- MTK_PHY_LED1_ON_CTRL :
-- MTK_PHY_LED0_ON_CTRL,
-- MTK_PHY_LED_ON_MASK,
-- on ? MTK_PHY_LED_ON_FORCE_ON : 0);
-- else
-- return 0;
--}
--
--static int mt798x_phy_hw_led_blink_set(struct phy_device *phydev, u8 index,
-- bool blinking)
--{
-- unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK +
-- (index ? 16 : 0);
-- struct mtk_socphy_priv *priv = phydev->priv;
-- bool changed;
--
-- if (blinking)
-- changed = !test_and_set_bit(bit_blink, &priv->led_state);
-- else
-- changed = !!test_and_clear_bit(bit_blink, &priv->led_state);
--
-- changed |= !!test_bit(MTK_PHY_LED_STATE_NETDEV +
-- (index ? 16 : 0), &priv->led_state);
-- if (changed)
-- return phy_write_mmd(phydev, MDIO_MMD_VEND2, index ?
-- MTK_PHY_LED1_BLINK_CTRL :
-- MTK_PHY_LED0_BLINK_CTRL,
-- blinking ?
-- MTK_PHY_LED_BLINK_FORCE_BLINK : 0);
-- else
-- return 0;
--}
--
- static int mt798x_phy_led_blink_set(struct phy_device *phydev, u8 index,
- unsigned long *delay_on,
- unsigned long *delay_off)
- {
- bool blinking = false;
-- int err = 0;
--
-- if (index > 1)
-- return -EINVAL;
-+ int err;
-
-- if (delay_on && delay_off && (*delay_on > 0) && (*delay_off > 0)) {
-- blinking = true;
-- *delay_on = 50;
-- *delay_off = 50;
-- }
-+ err = mtk_phy_led_num_dly_cfg(index, delay_on, delay_off, &blinking);
-+ if (err < 0)
-+ return err;
-
-- err = mt798x_phy_hw_led_blink_set(phydev, index, blinking);
-+ err = mtk_phy_hw_led_blink_set(phydev, index, blinking);
- if (err)
- return err;
-
-- return mt798x_phy_hw_led_on_set(phydev, index, false);
-+ return mtk_phy_hw_led_on_set(phydev, index, MTK_GPHY_LED_ON_MASK,
-+ false);
- }
-
- static int mt798x_phy_led_brightness_set(struct phy_device *phydev,
-@@ -1249,11 +1155,12 @@ static int mt798x_phy_led_brightness_set
- {
- int err;
-
-- err = mt798x_phy_hw_led_blink_set(phydev, index, false);
-+ err = mtk_phy_hw_led_blink_set(phydev, index, false);
- if (err)
- return err;
-
-- return mt798x_phy_hw_led_on_set(phydev, index, (value != LED_OFF));
-+ return mtk_phy_hw_led_on_set(phydev, index, MTK_GPHY_LED_ON_MASK,
-+ (value != LED_OFF));
- }
-
- static const unsigned long supported_triggers =
-@@ -1269,155 +1176,26 @@ static const unsigned long supported_tri
- static int mt798x_phy_led_hw_is_supported(struct phy_device *phydev, u8 index,
- unsigned long rules)
- {
-- if (index > 1)
-- return -EINVAL;
--
-- /* All combinations of the supported triggers are allowed */
-- if (rules & ~supported_triggers)
-- return -EOPNOTSUPP;
--
-- return 0;
--};
-+ return mtk_phy_led_hw_is_supported(phydev, index, rules,
-+ supported_triggers);
-+}
-
- static int mt798x_phy_led_hw_control_get(struct phy_device *phydev, u8 index,
- unsigned long *rules)
- {
-- unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK +
-- (index ? 16 : 0);
-- unsigned int bit_netdev = MTK_PHY_LED_STATE_NETDEV + (index ? 16 : 0);
-- unsigned int bit_on = MTK_PHY_LED_STATE_FORCE_ON + (index ? 16 : 0);
-- struct mtk_socphy_priv *priv = phydev->priv;
-- int on, blink;
--
-- if (index > 1)
-- return -EINVAL;
--
-- on = phy_read_mmd(phydev, MDIO_MMD_VEND2,
-- index ? MTK_PHY_LED1_ON_CTRL : MTK_PHY_LED0_ON_CTRL);
--
-- if (on < 0)
-- return -EIO;
--
-- blink = phy_read_mmd(phydev, MDIO_MMD_VEND2,
-- index ? MTK_PHY_LED1_BLINK_CTRL :
-- MTK_PHY_LED0_BLINK_CTRL);
-- if (blink < 0)
-- return -EIO;
--
-- if ((on & (MTK_PHY_LED_ON_LINK | MTK_PHY_LED_ON_FDX |
-- MTK_PHY_LED_ON_HDX | MTK_PHY_LED_ON_LINKDOWN)) ||
-- (blink & (MTK_PHY_LED_BLINK_RX | MTK_PHY_LED_BLINK_TX)))
-- set_bit(bit_netdev, &priv->led_state);
-- else
-- clear_bit(bit_netdev, &priv->led_state);
--
-- if (on & MTK_PHY_LED_ON_FORCE_ON)
-- set_bit(bit_on, &priv->led_state);
-- else
-- clear_bit(bit_on, &priv->led_state);
--
-- if (blink & MTK_PHY_LED_BLINK_FORCE_BLINK)
-- set_bit(bit_blink, &priv->led_state);
-- else
-- clear_bit(bit_blink, &priv->led_state);
--
-- if (!rules)
-- return 0;
--
-- if (on & MTK_PHY_LED_ON_LINK)
-- *rules |= BIT(TRIGGER_NETDEV_LINK);
--
-- if (on & MTK_PHY_LED_ON_LINK10)
-- *rules |= BIT(TRIGGER_NETDEV_LINK_10);
--
-- if (on & MTK_PHY_LED_ON_LINK100)
-- *rules |= BIT(TRIGGER_NETDEV_LINK_100);
--
-- if (on & MTK_PHY_LED_ON_LINK1000)
-- *rules |= BIT(TRIGGER_NETDEV_LINK_1000);
--
-- if (on & MTK_PHY_LED_ON_FDX)
-- *rules |= BIT(TRIGGER_NETDEV_FULL_DUPLEX);
--
-- if (on & MTK_PHY_LED_ON_HDX)
-- *rules |= BIT(TRIGGER_NETDEV_HALF_DUPLEX);
--
-- if (blink & MTK_PHY_LED_BLINK_RX)
-- *rules |= BIT(TRIGGER_NETDEV_RX);
--
-- if (blink & MTK_PHY_LED_BLINK_TX)
-- *rules |= BIT(TRIGGER_NETDEV_TX);
--
-- return 0;
-+ return mtk_phy_led_hw_ctrl_get(phydev, index, rules,
-+ MTK_GPHY_LED_ON_SET,
-+ MTK_GPHY_LED_RX_BLINK_SET,
-+ MTK_GPHY_LED_TX_BLINK_SET);
- };
-
- static int mt798x_phy_led_hw_control_set(struct phy_device *phydev, u8 index,
- unsigned long rules)
- {
-- unsigned int bit_netdev = MTK_PHY_LED_STATE_NETDEV + (index ? 16 : 0);
-- struct mtk_socphy_priv *priv = phydev->priv;
-- u16 on = 0, blink = 0;
-- int ret;
--
-- if (index > 1)
-- return -EINVAL;
--
-- if (rules & BIT(TRIGGER_NETDEV_FULL_DUPLEX))
-- on |= MTK_PHY_LED_ON_FDX;
--
-- if (rules & BIT(TRIGGER_NETDEV_HALF_DUPLEX))
-- on |= MTK_PHY_LED_ON_HDX;
--
-- if (rules & (BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_LINK)))
-- on |= MTK_PHY_LED_ON_LINK10;
--
-- if (rules & (BIT(TRIGGER_NETDEV_LINK_100) | BIT(TRIGGER_NETDEV_LINK)))
-- on |= MTK_PHY_LED_ON_LINK100;
--
-- if (rules & (BIT(TRIGGER_NETDEV_LINK_1000) | BIT(TRIGGER_NETDEV_LINK)))
-- on |= MTK_PHY_LED_ON_LINK1000;
--
-- if (rules & BIT(TRIGGER_NETDEV_RX)) {
-- blink |= (on & MTK_PHY_LED_ON_LINK) ?
-- (((on & MTK_PHY_LED_ON_LINK10) ?
-- MTK_PHY_LED_BLINK_10RX : 0) |
-- ((on & MTK_PHY_LED_ON_LINK100) ?
-- MTK_PHY_LED_BLINK_100RX : 0) |
-- ((on & MTK_PHY_LED_ON_LINK1000) ?
-- MTK_PHY_LED_BLINK_1000RX : 0)) :
-- MTK_PHY_LED_BLINK_RX;
-- }
--
-- if (rules & BIT(TRIGGER_NETDEV_TX)) {
-- blink |= (on & MTK_PHY_LED_ON_LINK) ?
-- (((on & MTK_PHY_LED_ON_LINK10) ?
-- MTK_PHY_LED_BLINK_10TX : 0) |
-- ((on & MTK_PHY_LED_ON_LINK100) ?
-- MTK_PHY_LED_BLINK_100TX : 0) |
-- ((on & MTK_PHY_LED_ON_LINK1000) ?
-- MTK_PHY_LED_BLINK_1000TX : 0)) :
-- MTK_PHY_LED_BLINK_TX;
-- }
--
-- if (blink || on)
-- set_bit(bit_netdev, &priv->led_state);
-- else
-- clear_bit(bit_netdev, &priv->led_state);
--
-- ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ?
-- MTK_PHY_LED1_ON_CTRL :
-- MTK_PHY_LED0_ON_CTRL,
-- MTK_PHY_LED_ON_FDX |
-- MTK_PHY_LED_ON_HDX |
-- MTK_PHY_LED_ON_LINK,
-- on);
--
-- if (ret)
-- return ret;
--
-- return phy_write_mmd(phydev, MDIO_MMD_VEND2, index ?
-- MTK_PHY_LED1_BLINK_CTRL :
-- MTK_PHY_LED0_BLINK_CTRL, blink);
-+ return mtk_phy_led_hw_ctrl_set(phydev, index, rules,
-+ MTK_GPHY_LED_ON_SET,
-+ MTK_GPHY_LED_RX_BLINK_SET,
-+ MTK_GPHY_LED_TX_BLINK_SET);
- };
-
- static bool mt7988_phy_led_get_polarity(struct phy_device *phydev, int led_num)
-@@ -1492,14 +1270,6 @@ static int mt7988_phy_probe_shared(struc
- return 0;
- }
-
--static void mt798x_phy_leds_state_init(struct phy_device *phydev)
--{
-- int i;
--
-- for (i = 0; i < 2; ++i)
-- mt798x_phy_led_hw_control_get(phydev, i, NULL);
--}
--
- static int mt7988_phy_probe(struct phy_device *phydev)
- {
- struct mtk_socphy_shared *shared;
-@@ -1525,7 +1295,7 @@ static int mt7988_phy_probe(struct phy_d
-
- phydev->priv = priv;
-
-- mt798x_phy_leds_state_init(phydev);
-+ mtk_phy_leds_state_init(phydev);
-
- err = mt7988_phy_fix_leds_polarities(phydev);
- if (err)
-@@ -1552,7 +1322,7 @@ static int mt7981_phy_probe(struct phy_d
-
- phydev->priv = priv;
-
-- mt798x_phy_leds_state_init(phydev);
-+ mtk_phy_leds_state_init(phydev);
-
- return mt798x_phy_calibration(phydev);
- }
---- /dev/null
-+++ b/drivers/net/phy/mediatek/mtk-phy-lib.c
-@@ -0,0 +1,254 @@
-+// SPDX-License-Identifier: GPL-2.0
-+#include <linux/phy.h>
-+#include <linux/module.h>
-+
-+#include <linux/netdevice.h>
-+
-+#include "mtk.h"
-+
-+int mtk_phy_led_hw_is_supported(struct phy_device *phydev, u8 index,
-+ unsigned long rules,
-+ unsigned long supported_triggers)
-+{
-+ if (index > 1)
-+ return -EINVAL;
-+
-+ /* All combinations of the supported triggers are allowed */
-+ if (rules & ~supported_triggers)
-+ return -EOPNOTSUPP;
-+
-+ return 0;
-+}
-+EXPORT_SYMBOL_GPL(mtk_phy_led_hw_is_supported);
-+
-+int mtk_phy_led_hw_ctrl_get(struct phy_device *phydev, u8 index,
-+ unsigned long *rules, u16 on_set,
-+ u16 rx_blink_set, u16 tx_blink_set)
-+{
-+ unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK +
-+ (index ? 16 : 0);
-+ unsigned int bit_netdev = MTK_PHY_LED_STATE_NETDEV + (index ? 16 : 0);
-+ unsigned int bit_on = MTK_PHY_LED_STATE_FORCE_ON + (index ? 16 : 0);
-+ struct mtk_socphy_priv *priv = phydev->priv;
-+ int on, blink;
-+
-+ if (index > 1)
-+ return -EINVAL;
-+
-+ on = phy_read_mmd(phydev, MDIO_MMD_VEND2,
-+ index ? MTK_PHY_LED1_ON_CTRL : MTK_PHY_LED0_ON_CTRL);
-+
-+ if (on < 0)
-+ return -EIO;
-+
-+ blink = phy_read_mmd(phydev, MDIO_MMD_VEND2,
-+ index ? MTK_PHY_LED1_BLINK_CTRL :
-+ MTK_PHY_LED0_BLINK_CTRL);
-+ if (blink < 0)
-+ return -EIO;
-+
-+ if ((on & (on_set | MTK_PHY_LED_ON_FDX |
-+ MTK_PHY_LED_ON_HDX | MTK_PHY_LED_ON_LINKDOWN)) ||
-+ (blink & (rx_blink_set | tx_blink_set)))
-+ set_bit(bit_netdev, &priv->led_state);
-+ else
-+ clear_bit(bit_netdev, &priv->led_state);
-+
-+ if (on & MTK_PHY_LED_ON_FORCE_ON)
-+ set_bit(bit_on, &priv->led_state);
-+ else
-+ clear_bit(bit_on, &priv->led_state);
-+
-+ if (blink & MTK_PHY_LED_BLINK_FORCE_BLINK)
-+ set_bit(bit_blink, &priv->led_state);
-+ else
-+ clear_bit(bit_blink, &priv->led_state);
-+
-+ if (!rules)
-+ return 0;
-+
-+ if (on & on_set)
-+ *rules |= BIT(TRIGGER_NETDEV_LINK);
-+
-+ if (on & MTK_PHY_LED_ON_LINK10)
-+ *rules |= BIT(TRIGGER_NETDEV_LINK_10);
-+
-+ if (on & MTK_PHY_LED_ON_LINK100)
-+ *rules |= BIT(TRIGGER_NETDEV_LINK_100);
-+
-+ if (on & MTK_PHY_LED_ON_LINK1000)
-+ *rules |= BIT(TRIGGER_NETDEV_LINK_1000);
-+
-+ if (on & MTK_PHY_LED_ON_LINK2500)
-+ *rules |= BIT(TRIGGER_NETDEV_LINK_2500);
-+
-+ if (on & MTK_PHY_LED_ON_FDX)
-+ *rules |= BIT(TRIGGER_NETDEV_FULL_DUPLEX);
-+
-+ if (on & MTK_PHY_LED_ON_HDX)
-+ *rules |= BIT(TRIGGER_NETDEV_HALF_DUPLEX);
-+
-+ if (blink & rx_blink_set)
-+ *rules |= BIT(TRIGGER_NETDEV_RX);
-+
-+ if (blink & tx_blink_set)
-+ *rules |= BIT(TRIGGER_NETDEV_TX);
-+
-+ return 0;
-+}
-+EXPORT_SYMBOL_GPL(mtk_phy_led_hw_ctrl_get);
-+
-+int mtk_phy_led_hw_ctrl_set(struct phy_device *phydev, u8 index,
-+ unsigned long rules, u16 on_set,
-+ u16 rx_blink_set, u16 tx_blink_set)
-+{
-+ unsigned int bit_netdev = MTK_PHY_LED_STATE_NETDEV + (index ? 16 : 0);
-+ struct mtk_socphy_priv *priv = phydev->priv;
-+ u16 on = 0, blink = 0;
-+ int ret;
-+
-+ if (index > 1)
-+ return -EINVAL;
-+
-+ if (rules & BIT(TRIGGER_NETDEV_FULL_DUPLEX))
-+ on |= MTK_PHY_LED_ON_FDX;
-+
-+ if (rules & BIT(TRIGGER_NETDEV_HALF_DUPLEX))
-+ on |= MTK_PHY_LED_ON_HDX;
-+
-+ if (rules & (BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_LINK)))
-+ on |= MTK_PHY_LED_ON_LINK10;
-+
-+ if (rules & (BIT(TRIGGER_NETDEV_LINK_100) | BIT(TRIGGER_NETDEV_LINK)))
-+ on |= MTK_PHY_LED_ON_LINK100;
-+
-+ if (rules & (BIT(TRIGGER_NETDEV_LINK_1000) | BIT(TRIGGER_NETDEV_LINK)))
-+ on |= MTK_PHY_LED_ON_LINK1000;
-+
-+ if (rules & (BIT(TRIGGER_NETDEV_LINK_2500) | BIT(TRIGGER_NETDEV_LINK)))
-+ on |= MTK_PHY_LED_ON_LINK2500;
-+
-+ if (rules & BIT(TRIGGER_NETDEV_RX)) {
-+ blink |= (on & on_set) ?
-+ (((on & MTK_PHY_LED_ON_LINK10) ?
-+ MTK_PHY_LED_BLINK_10RX : 0) |
-+ ((on & MTK_PHY_LED_ON_LINK100) ?
-+ MTK_PHY_LED_BLINK_100RX : 0) |
-+ ((on & MTK_PHY_LED_ON_LINK1000) ?
-+ MTK_PHY_LED_BLINK_1000RX : 0) |
-+ ((on & MTK_PHY_LED_ON_LINK2500) ?
-+ MTK_PHY_LED_BLINK_2500RX : 0)) :
-+ rx_blink_set;
-+ }
-+
-+ if (rules & BIT(TRIGGER_NETDEV_TX)) {
-+ blink |= (on & on_set) ?
-+ (((on & MTK_PHY_LED_ON_LINK10) ?
-+ MTK_PHY_LED_BLINK_10TX : 0) |
-+ ((on & MTK_PHY_LED_ON_LINK100) ?
-+ MTK_PHY_LED_BLINK_100TX : 0) |
-+ ((on & MTK_PHY_LED_ON_LINK1000) ?
-+ MTK_PHY_LED_BLINK_1000TX : 0) |
-+ ((on & MTK_PHY_LED_ON_LINK2500) ?
-+ MTK_PHY_LED_BLINK_2500TX : 0)) :
-+ tx_blink_set;
-+ }
-+
-+ if (blink || on)
-+ set_bit(bit_netdev, &priv->led_state);
-+ else
-+ clear_bit(bit_netdev, &priv->led_state);
-+
-+ ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ?
-+ MTK_PHY_LED1_ON_CTRL : MTK_PHY_LED0_ON_CTRL,
-+ MTK_PHY_LED_ON_FDX | MTK_PHY_LED_ON_HDX | on_set,
-+ on);
-+
-+ if (ret)
-+ return ret;
-+
-+ return phy_write_mmd(phydev, MDIO_MMD_VEND2, index ?
-+ MTK_PHY_LED1_BLINK_CTRL :
-+ MTK_PHY_LED0_BLINK_CTRL, blink);
-+}
-+EXPORT_SYMBOL_GPL(mtk_phy_led_hw_ctrl_set);
-+
-+int mtk_phy_led_num_dly_cfg(u8 index, unsigned long *delay_on,
-+ unsigned long *delay_off, bool *blinking)
-+{
-+ if (index > 1)
-+ return -EINVAL;
-+
-+ if (delay_on && delay_off && (*delay_on > 0) && (*delay_off > 0)) {
-+ *blinking = true;
-+ *delay_on = 50;
-+ *delay_off = 50;
-+ }
-+
-+ return 0;
-+}
-+EXPORT_SYMBOL_GPL(mtk_phy_led_num_dly_cfg);
-+
-+int mtk_phy_hw_led_on_set(struct phy_device *phydev, u8 index,
-+ u16 led_on_mask, bool on)
-+{
-+ unsigned int bit_on = MTK_PHY_LED_STATE_FORCE_ON + (index ? 16 : 0);
-+ struct mtk_socphy_priv *priv = phydev->priv;
-+ bool changed;
-+
-+ if (on)
-+ changed = !test_and_set_bit(bit_on, &priv->led_state);
-+ else
-+ changed = !!test_and_clear_bit(bit_on, &priv->led_state);
-+
-+ changed |= !!test_and_clear_bit(MTK_PHY_LED_STATE_NETDEV +
-+ (index ? 16 : 0), &priv->led_state);
-+ if (changed)
-+ return phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ?
-+ MTK_PHY_LED1_ON_CTRL :
-+ MTK_PHY_LED0_ON_CTRL,
-+ led_on_mask,
-+ on ? MTK_PHY_LED_ON_FORCE_ON : 0);
-+ else
-+ return 0;
-+}
-+EXPORT_SYMBOL_GPL(mtk_phy_hw_led_on_set);
-+
-+int mtk_phy_hw_led_blink_set(struct phy_device *phydev, u8 index, bool blinking)
-+{
-+ unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK +
-+ (index ? 16 : 0);
-+ struct mtk_socphy_priv *priv = phydev->priv;
-+ bool changed;
-+
-+ if (blinking)
-+ changed = !test_and_set_bit(bit_blink, &priv->led_state);
-+ else
-+ changed = !!test_and_clear_bit(bit_blink, &priv->led_state);
-+
-+ changed |= !!test_bit(MTK_PHY_LED_STATE_NETDEV +
-+ (index ? 16 : 0), &priv->led_state);
-+ if (changed)
-+ return phy_write_mmd(phydev, MDIO_MMD_VEND2, index ?
-+ MTK_PHY_LED1_BLINK_CTRL :
-+ MTK_PHY_LED0_BLINK_CTRL,
-+ blinking ?
-+ MTK_PHY_LED_BLINK_FORCE_BLINK : 0);
-+ else
-+ return 0;
-+}
-+EXPORT_SYMBOL_GPL(mtk_phy_hw_led_blink_set);
-+
-+void mtk_phy_leds_state_init(struct phy_device *phydev)
-+{
-+ int i;
-+
-+ for (i = 0; i < 2; ++i)
-+ phydev->drv->led_hw_control_get(phydev, i, NULL);
-+}
-+EXPORT_SYMBOL_GPL(mtk_phy_leds_state_init);
-+
-+MODULE_DESCRIPTION("MediaTek Ethernet PHY driver common");
-+MODULE_LICENSE("GPL");
---- /dev/null
-+++ b/drivers/net/phy/mediatek/mtk.h
-@@ -0,0 +1,86 @@
-+/* SPDX-License-Identifier: GPL-2.0
-+ *
-+ * Common definition for Mediatek Ethernet PHYs
-+ * Copyright (c) 2024 MediaTek Inc.
-+ */
-+
-+#ifndef _MTK_EPHY_H_
-+#define _MTK_EPHY_H_
-+
-+#define MTK_EXT_PAGE_ACCESS 0x1f
-+
-+/* Registers on MDIO_MMD_VEND2 */
-+#define MTK_PHY_LED0_ON_CTRL 0x24
-+#define MTK_PHY_LED1_ON_CTRL 0x26
-+#define MTK_GPHY_LED_ON_MASK GENMASK(6, 0)
-+#define MTK_2P5GPHY_LED_ON_MASK GENMASK(7, 0)
-+#define MTK_PHY_LED_ON_LINK1000 BIT(0)
-+#define MTK_PHY_LED_ON_LINK100 BIT(1)
-+#define MTK_PHY_LED_ON_LINK10 BIT(2)
-+#define MTK_PHY_LED_ON_LINKDOWN BIT(3)
-+#define MTK_PHY_LED_ON_FDX BIT(4) /* Full duplex */
-+#define MTK_PHY_LED_ON_HDX BIT(5) /* Half duplex */
-+#define MTK_PHY_LED_ON_FORCE_ON BIT(6)
-+#define MTK_PHY_LED_ON_LINK2500 BIT(7)
-+#define MTK_PHY_LED_ON_POLARITY BIT(14)
-+#define MTK_PHY_LED_ON_ENABLE BIT(15)
-+
-+#define MTK_PHY_LED0_BLINK_CTRL 0x25
-+#define MTK_PHY_LED1_BLINK_CTRL 0x27
-+#define MTK_PHY_LED_BLINK_1000TX BIT(0)
-+#define MTK_PHY_LED_BLINK_1000RX BIT(1)
-+#define MTK_PHY_LED_BLINK_100TX BIT(2)
-+#define MTK_PHY_LED_BLINK_100RX BIT(3)
-+#define MTK_PHY_LED_BLINK_10TX BIT(4)
-+#define MTK_PHY_LED_BLINK_10RX BIT(5)
-+#define MTK_PHY_LED_BLINK_COLLISION BIT(6)
-+#define MTK_PHY_LED_BLINK_RX_CRC_ERR BIT(7)
-+#define MTK_PHY_LED_BLINK_RX_IDLE_ERR BIT(8)
-+#define MTK_PHY_LED_BLINK_FORCE_BLINK BIT(9)
-+#define MTK_PHY_LED_BLINK_2500TX BIT(10)
-+#define MTK_PHY_LED_BLINK_2500RX BIT(11)
-+
-+#define MTK_GPHY_LED_ON_SET (MTK_PHY_LED_ON_LINK1000 | \
-+ MTK_PHY_LED_ON_LINK100 | \
-+ MTK_PHY_LED_ON_LINK10)
-+#define MTK_GPHY_LED_RX_BLINK_SET (MTK_PHY_LED_BLINK_1000RX | \
-+ MTK_PHY_LED_BLINK_100RX | \
-+ MTK_PHY_LED_BLINK_10RX)
-+#define MTK_GPHY_LED_TX_BLINK_SET (MTK_PHY_LED_BLINK_1000RX | \
-+ MTK_PHY_LED_BLINK_100RX | \
-+ MTK_PHY_LED_BLINK_10RX)
-+
-+#define MTK_2P5GPHY_LED_ON_SET (MTK_PHY_LED_ON_LINK2500 | \
-+ MTK_GPHY_LED_ON_SET)
-+#define MTK_2P5GPHY_LED_RX_BLINK_SET (MTK_PHY_LED_BLINK_2500RX | \
-+ MTK_GPHY_LED_RX_BLINK_SET)
-+#define MTK_2P5GPHY_LED_TX_BLINK_SET (MTK_PHY_LED_BLINK_2500RX | \
-+ MTK_GPHY_LED_TX_BLINK_SET)
-+
-+#define MTK_PHY_LED_STATE_FORCE_ON 0
-+#define MTK_PHY_LED_STATE_FORCE_BLINK 1
-+#define MTK_PHY_LED_STATE_NETDEV 2
-+
-+struct mtk_socphy_priv {
-+ unsigned long led_state;
-+};
-+
-+int mtk_phy_led_hw_is_supported(struct phy_device *phydev, u8 index,
-+ unsigned long rules,
-+ unsigned long supported_triggers);
-+int mtk_phy_led_hw_ctrl_set(struct phy_device *phydev, u8 index,
-+ unsigned long rules, u16 on_set,
-+ u16 rx_blink_set, u16 tx_blink_set);
-+int mtk_phy_led_hw_ctrl_get(struct phy_device *phydev, u8 index,
-+ unsigned long *rules, u16 on_set,
-+ u16 rx_blink_set, u16 tx_blink_set);
-+int mtk_phy_led_num_dly_cfg(u8 index, unsigned long *delay_on,
-+ unsigned long *delay_off, bool *blinking);
-+int mtk_phy_hw_led_on_set(struct phy_device *phydev, u8 index,
-+ u16 led_on_mask, bool on);
-+int mtk_phy_hw_led_blink_set(struct phy_device *phydev, u8 index,
-+ bool blinking);
-+void mtk_phy_leds_state_init(struct phy_device *phydev);
-+
-+#endif /* _MTK_EPHY_H_ */
+++ /dev/null
-From 3cb1a3c9cbaaadaf91437374b96ec72256c40db2 Mon Sep 17 00:00:00 2001
-Date: Sat, 9 Nov 2024 00:34:54 +0800
-Subject: [PATCH] net: phy: mediatek: Integrate read/write page helper
- functions
-
-This patch integrates read/write page helper functions as MTK phy lib.
-They are basically the same in mtk-ge.c & mtk-ge-soc.c.
-
----
- drivers/net/phy/mediatek/Kconfig | 1 +
- drivers/net/phy/mediatek/mtk-ge-soc.c | 18 ++++--------------
- drivers/net/phy/mediatek/mtk-ge.c | 20 ++++++--------------
- drivers/net/phy/mediatek/mtk-phy-lib.c | 12 ++++++++++++
- drivers/net/phy/mediatek/mtk.h | 3 +++
- 5 files changed, 26 insertions(+), 28 deletions(-)
-
---- a/drivers/net/phy/mediatek/Kconfig
-+++ b/drivers/net/phy/mediatek/Kconfig
-@@ -4,6 +4,7 @@ config MTK_NET_PHYLIB
-
- config MEDIATEK_GE_PHY
- tristate "MediaTek Gigabit Ethernet PHYs"
-+ select MTK_NET_PHYLIB
- help
- Supports the MediaTek non-built-in Gigabit Ethernet PHYs.
-
---- a/drivers/net/phy/mediatek/mtk-ge-soc.c
-+++ b/drivers/net/phy/mediatek/mtk-ge-soc.c
-@@ -271,16 +271,6 @@ struct mtk_socphy_shared {
- struct mtk_socphy_priv priv[4];
- };
-
--static int mtk_socphy_read_page(struct phy_device *phydev)
--{
-- return __phy_read(phydev, MTK_EXT_PAGE_ACCESS);
--}
--
--static int mtk_socphy_write_page(struct phy_device *phydev, int page)
--{
-- return __phy_write(phydev, MTK_EXT_PAGE_ACCESS, page);
--}
--
- /* One calibration cycle consists of:
- * 1.Set DA_CALIN_FLAG high to start calibration. Keep it high
- * until AD_CAL_COMP is ready to output calibration result.
-@@ -1337,8 +1327,8 @@ static struct phy_driver mtk_socphy_driv
- .probe = mt7981_phy_probe,
- .suspend = genphy_suspend,
- .resume = genphy_resume,
-- .read_page = mtk_socphy_read_page,
-- .write_page = mtk_socphy_write_page,
-+ .read_page = mtk_phy_read_page,
-+ .write_page = mtk_phy_write_page,
- .led_blink_set = mt798x_phy_led_blink_set,
- .led_brightness_set = mt798x_phy_led_brightness_set,
- .led_hw_is_supported = mt798x_phy_led_hw_is_supported,
-@@ -1354,8 +1344,8 @@ static struct phy_driver mtk_socphy_driv
- .probe = mt7988_phy_probe,
- .suspend = genphy_suspend,
- .resume = genphy_resume,
-- .read_page = mtk_socphy_read_page,
-- .write_page = mtk_socphy_write_page,
-+ .read_page = mtk_phy_read_page,
-+ .write_page = mtk_phy_write_page,
- .led_blink_set = mt798x_phy_led_blink_set,
- .led_brightness_set = mt798x_phy_led_brightness_set,
- .led_hw_is_supported = mt798x_phy_led_hw_is_supported,
---- a/drivers/net/phy/mediatek/mtk-ge.c
-+++ b/drivers/net/phy/mediatek/mtk-ge.c
-@@ -3,6 +3,8 @@
- #include <linux/module.h>
- #include <linux/phy.h>
-
-+#include "mtk.h"
-+
- #define MTK_EXT_PAGE_ACCESS 0x1f
- #define MTK_PHY_PAGE_STANDARD 0x0000
- #define MTK_PHY_PAGE_EXTENDED 0x0001
-@@ -11,16 +13,6 @@
- #define MTK_PHY_PAGE_EXTENDED_2A30 0x2a30
- #define MTK_PHY_PAGE_EXTENDED_52B5 0x52b5
-
--static int mtk_gephy_read_page(struct phy_device *phydev)
--{
-- return __phy_read(phydev, MTK_EXT_PAGE_ACCESS);
--}
--
--static int mtk_gephy_write_page(struct phy_device *phydev, int page)
--{
-- return __phy_write(phydev, MTK_EXT_PAGE_ACCESS, page);
--}
--
- static void mtk_gephy_config_init(struct phy_device *phydev)
- {
- /* Disable EEE */
-@@ -80,8 +72,8 @@ static struct phy_driver mtk_gephy_drive
- .handle_interrupt = genphy_handle_interrupt_no_ack,
- .suspend = genphy_suspend,
- .resume = genphy_resume,
-- .read_page = mtk_gephy_read_page,
-- .write_page = mtk_gephy_write_page,
-+ .read_page = mtk_phy_read_page,
-+ .write_page = mtk_phy_write_page,
- },
- {
- PHY_ID_MATCH_EXACT(0x03a29441),
-@@ -94,8 +86,8 @@ static struct phy_driver mtk_gephy_drive
- .handle_interrupt = genphy_handle_interrupt_no_ack,
- .suspend = genphy_suspend,
- .resume = genphy_resume,
-- .read_page = mtk_gephy_read_page,
-- .write_page = mtk_gephy_write_page,
-+ .read_page = mtk_phy_read_page,
-+ .write_page = mtk_phy_write_page,
- },
- };
-
---- a/drivers/net/phy/mediatek/mtk-phy-lib.c
-+++ b/drivers/net/phy/mediatek/mtk-phy-lib.c
-@@ -6,6 +6,18 @@
-
- #include "mtk.h"
-
-+int mtk_phy_read_page(struct phy_device *phydev)
-+{
-+ return __phy_read(phydev, MTK_EXT_PAGE_ACCESS);
-+}
-+EXPORT_SYMBOL_GPL(mtk_phy_read_page);
-+
-+int mtk_phy_write_page(struct phy_device *phydev, int page)
-+{
-+ return __phy_write(phydev, MTK_EXT_PAGE_ACCESS, page);
-+}
-+EXPORT_SYMBOL_GPL(mtk_phy_write_page);
-+
- int mtk_phy_led_hw_is_supported(struct phy_device *phydev, u8 index,
- unsigned long rules,
- unsigned long supported_triggers)
---- a/drivers/net/phy/mediatek/mtk.h
-+++ b/drivers/net/phy/mediatek/mtk.h
-@@ -66,6 +66,9 @@ struct mtk_socphy_priv {
- unsigned long led_state;
- };
-
-+int mtk_phy_read_page(struct phy_device *phydev);
-+int mtk_phy_write_page(struct phy_device *phydev, int page);
-+
- int mtk_phy_led_hw_is_supported(struct phy_device *phydev, u8 index,
- unsigned long rules,
- unsigned long supported_triggers);
+++ /dev/null
-From 219cecbb3e864685a1f08bcb79ce07d9bc4f506e Mon Sep 17 00:00:00 2001
-Date: Sat, 9 Nov 2024 00:34:55 +0800
-Subject: [PATCH] net: phy: mediatek: add MT7530 & MT7531's PHY ID macros
-
-This patch adds MT7530 & MT7531's PHY ID macros in mtk-ge.c so that
-it follows the same rule of mtk-ge-soc.c.
-
----
- drivers/net/phy/mediatek/mtk-ge.c | 11 +++++++----
- 1 file changed, 7 insertions(+), 4 deletions(-)
-
---- a/drivers/net/phy/mediatek/mtk-ge.c
-+++ b/drivers/net/phy/mediatek/mtk-ge.c
-@@ -5,6 +5,9 @@
-
- #include "mtk.h"
-
-+#define MTK_GPHY_ID_MT7530 0x03a29412
-+#define MTK_GPHY_ID_MT7531 0x03a29441
-+
- #define MTK_EXT_PAGE_ACCESS 0x1f
- #define MTK_PHY_PAGE_STANDARD 0x0000
- #define MTK_PHY_PAGE_EXTENDED 0x0001
-@@ -62,7 +65,7 @@ static int mt7531_phy_config_init(struct
-
- static struct phy_driver mtk_gephy_driver[] = {
- {
-- PHY_ID_MATCH_EXACT(0x03a29412),
-+ PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7530),
- .name = "MediaTek MT7530 PHY",
- .config_init = mt7530_phy_config_init,
- /* Interrupts are handled by the switch, not the PHY
-@@ -76,7 +79,7 @@ static struct phy_driver mtk_gephy_drive
- .write_page = mtk_phy_write_page,
- },
- {
-- PHY_ID_MATCH_EXACT(0x03a29441),
-+ PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7531),
- .name = "MediaTek MT7531 PHY",
- .config_init = mt7531_phy_config_init,
- /* Interrupts are handled by the switch, not the PHY
-@@ -94,8 +97,8 @@ static struct phy_driver mtk_gephy_drive
- module_phy_driver(mtk_gephy_driver);
-
- static struct mdio_device_id __maybe_unused mtk_gephy_tbl[] = {
-- { PHY_ID_MATCH_EXACT(0x03a29441) },
-- { PHY_ID_MATCH_EXACT(0x03a29412) },
-+ { PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7530) },
-+ { PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7531) },
- { }
- };
-
+++ /dev/null
-From 2f435137a0484f11b47554281091ef4908f8cb31 Mon Sep 17 00:00:00 2001
-Date: Thu, 13 Feb 2025 16:05:49 +0800
-Subject: [PATCH 1/5] net: phy: mediatek: Change to more meaningful macros
-
-Replace magic number with more meaningful macros in mtk-ge.c.
-Also, move some common macros into mtk-phy-lib.c.
-
----
- drivers/net/phy/mediatek/mtk-ge-soc.c | 1 -
- drivers/net/phy/mediatek/mtk-ge.c | 71 +++++++++++++++++++++------
- drivers/net/phy/mediatek/mtk.h | 2 +
- 3 files changed, 57 insertions(+), 17 deletions(-)
-
---- a/drivers/net/phy/mediatek/mtk-ge-soc.c
-+++ b/drivers/net/phy/mediatek/mtk-ge-soc.c
-@@ -24,7 +24,6 @@
- #define MTK_PHY_SMI_DET_ON_THRESH_MASK GENMASK(13, 8)
-
- #define MTK_PHY_PAGE_EXTENDED_2A30 0x2a30
--#define MTK_PHY_PAGE_EXTENDED_52B5 0x52b5
-
- #define ANALOG_INTERNAL_OPERATION_MAX_US 20
- #define TXRESERVE_MIN 0
---- a/drivers/net/phy/mediatek/mtk-ge.c
-+++ b/drivers/net/phy/mediatek/mtk-ge.c
-@@ -8,13 +8,31 @@
- #define MTK_GPHY_ID_MT7530 0x03a29412
- #define MTK_GPHY_ID_MT7531 0x03a29441
-
--#define MTK_EXT_PAGE_ACCESS 0x1f
--#define MTK_PHY_PAGE_STANDARD 0x0000
--#define MTK_PHY_PAGE_EXTENDED 0x0001
--#define MTK_PHY_PAGE_EXTENDED_2 0x0002
--#define MTK_PHY_PAGE_EXTENDED_3 0x0003
--#define MTK_PHY_PAGE_EXTENDED_2A30 0x2a30
--#define MTK_PHY_PAGE_EXTENDED_52B5 0x52b5
-+#define MTK_PHY_PAGE_EXTENDED_1 0x0001
-+#define MTK_PHY_AUX_CTRL_AND_STATUS 0x14
-+#define MTK_PHY_ENABLE_DOWNSHIFT BIT(4)
-+
-+#define MTK_PHY_PAGE_EXTENDED_2 0x0002
-+#define MTK_PHY_PAGE_EXTENDED_3 0x0003
-+#define MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG11 0x11
-+
-+#define MTK_PHY_PAGE_EXTENDED_2A30 0x2a30
-+
-+/* Registers on MDIO_MMD_VEND1 */
-+#define MTK_PHY_GBE_MODE_TX_DELAY_SEL 0x13
-+#define MTK_PHY_TEST_MODE_TX_DELAY_SEL 0x14
-+#define MTK_TX_DELAY_PAIR_B_MASK GENMASK(10, 8)
-+#define MTK_TX_DELAY_PAIR_D_MASK GENMASK(2, 0)
-+
-+#define MTK_PHY_MCC_CTRL_AND_TX_POWER_CTRL 0xa6
-+#define MTK_MCC_NEARECHO_OFFSET_MASK GENMASK(15, 8)
-+
-+#define MTK_PHY_RXADC_CTRL_RG7 0xc6
-+#define MTK_PHY_DA_AD_BUF_BIAS_LP_MASK GENMASK(9, 8)
-+
-+#define MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG123 0x123
-+#define MTK_PHY_LPI_NORM_MSE_LO_THRESH100_MASK GENMASK(15, 8)
-+#define MTK_PHY_LPI_NORM_MSE_HI_THRESH100_MASK GENMASK(7, 0)
-
- static void mtk_gephy_config_init(struct phy_device *phydev)
- {
-@@ -22,7 +40,9 @@ static void mtk_gephy_config_init(struct
- phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV, 0);
-
- /* Enable HW auto downshift */
-- phy_modify_paged(phydev, MTK_PHY_PAGE_EXTENDED, 0x14, 0, BIT(4));
-+ phy_modify_paged(phydev, MTK_PHY_PAGE_EXTENDED_1,
-+ MTK_PHY_AUX_CTRL_AND_STATUS,
-+ 0, MTK_PHY_ENABLE_DOWNSHIFT);
-
- /* Increase SlvDPSready time */
- phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
-@@ -32,10 +52,20 @@ static void mtk_gephy_config_init(struct
- phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
-
- /* Adjust 100_mse_threshold */
-- phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x123, 0xffff);
--
-- /* Disable mcc */
-- phy_write_mmd(phydev, MDIO_MMD_VEND1, 0xa6, 0x300);
-+ phy_modify_mmd(phydev, MDIO_MMD_VEND1,
-+ MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG123,
-+ MTK_PHY_LPI_NORM_MSE_LO_THRESH100_MASK |
-+ MTK_PHY_LPI_NORM_MSE_HI_THRESH100_MASK,
-+ FIELD_PREP(MTK_PHY_LPI_NORM_MSE_LO_THRESH100_MASK,
-+ 0xff) |
-+ FIELD_PREP(MTK_PHY_LPI_NORM_MSE_HI_THRESH100_MASK,
-+ 0xff));
-+
-+ /* If echo time is narrower than 0x3, it will be regarded as noise */
-+ phy_modify_mmd(phydev, MDIO_MMD_VEND1,
-+ MTK_PHY_MCC_CTRL_AND_TX_POWER_CTRL,
-+ MTK_MCC_NEARECHO_OFFSET_MASK,
-+ FIELD_PREP(MTK_MCC_NEARECHO_OFFSET_MASK, 0x3));
- }
-
- static int mt7530_phy_config_init(struct phy_device *phydev)
-@@ -43,7 +73,8 @@ static int mt7530_phy_config_init(struct
- mtk_gephy_config_init(phydev);
-
- /* Increase post_update_timer */
-- phy_write_paged(phydev, MTK_PHY_PAGE_EXTENDED_3, 0x11, 0x4b);
-+ phy_write_paged(phydev, MTK_PHY_PAGE_EXTENDED_3,
-+ MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG11, 0x4b);
-
- return 0;
- }
-@@ -54,11 +85,19 @@ static int mt7531_phy_config_init(struct
-
- /* PHY link down power saving enable */
- phy_set_bits(phydev, 0x17, BIT(4));
-- phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, 0xc6, 0x300);
-+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG7,
-+ MTK_PHY_DA_AD_BUF_BIAS_LP_MASK,
-+ FIELD_PREP(MTK_PHY_DA_AD_BUF_BIAS_LP_MASK, 0x3));
-
- /* Set TX Pair delay selection */
-- phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x13, 0x404);
-- phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x14, 0x404);
-+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_GBE_MODE_TX_DELAY_SEL,
-+ MTK_TX_DELAY_PAIR_B_MASK | MTK_TX_DELAY_PAIR_D_MASK,
-+ FIELD_PREP(MTK_TX_DELAY_PAIR_B_MASK, 0x4) |
-+ FIELD_PREP(MTK_TX_DELAY_PAIR_D_MASK, 0x4));
-+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TEST_MODE_TX_DELAY_SEL,
-+ MTK_TX_DELAY_PAIR_B_MASK | MTK_TX_DELAY_PAIR_D_MASK,
-+ FIELD_PREP(MTK_TX_DELAY_PAIR_B_MASK, 0x4) |
-+ FIELD_PREP(MTK_TX_DELAY_PAIR_D_MASK, 0x4));
-
- return 0;
- }
---- a/drivers/net/phy/mediatek/mtk.h
-+++ b/drivers/net/phy/mediatek/mtk.h
-@@ -9,6 +9,8 @@
- #define _MTK_EPHY_H_
-
- #define MTK_EXT_PAGE_ACCESS 0x1f
-+#define MTK_PHY_PAGE_STANDARD 0x0000
-+#define MTK_PHY_PAGE_EXTENDED_52B5 0x52b5
-
- /* Registers on MDIO_MMD_VEND2 */
- #define MTK_PHY_LED0_ON_CTRL 0x24
+++ /dev/null
-From afa08fde7c4780ea5556d9d4df6c1daa38ba0d6b Mon Sep 17 00:00:00 2001
-Date: Thu, 13 Feb 2025 16:05:50 +0800
-Subject: [PATCH 2/5] net: phy: mediatek: Add token ring access helper
- functions in mtk-phy-lib
-
-This patch adds TR(token ring) manipulations and adds correct
-macro names for those magic numbers. TR is a way to access
-proprietary registers on page 52b5. Use these helper functions
-so we can see which fields we're going to modify/set/clear.
-
-TR functions with __* prefix mean that the operations inside
-aren't wrapped by page select/restore functions.
-
-This patch doesn't really change registers' settings but just
-enhances readability and maintainability.
-
----
- drivers/net/phy/mediatek/mtk-ge-soc.c | 231 +++++++++++++++++--------
- drivers/net/phy/mediatek/mtk-ge.c | 11 +-
- drivers/net/phy/mediatek/mtk-phy-lib.c | 63 +++++++
- drivers/net/phy/mediatek/mtk.h | 5 +
- 4 files changed, 230 insertions(+), 80 deletions(-)
-
---- a/drivers/net/phy/mediatek/mtk-ge-soc.c
-+++ b/drivers/net/phy/mediatek/mtk-ge-soc.c
-@@ -25,6 +25,90 @@
-
- #define MTK_PHY_PAGE_EXTENDED_2A30 0x2a30
-
-+/* Registers on Token Ring debug nodes */
-+/* ch_addr = 0x0, node_addr = 0x7, data_addr = 0x15 */
-+/* NormMseLoThresh */
-+#define NORMAL_MSE_LO_THRESH_MASK GENMASK(15, 8)
-+
-+/* ch_addr = 0x0, node_addr = 0xf, data_addr = 0x3c */
-+/* RemAckCntLimitCtrl */
-+#define REMOTE_ACK_COUNT_LIMIT_CTRL_MASK GENMASK(2, 1)
-+
-+/* ch_addr = 0x1, node_addr = 0xd, data_addr = 0x20 */
-+/* VcoSlicerThreshBitsHigh */
-+#define VCO_SLICER_THRESH_HIGH_MASK GENMASK(23, 0)
-+
-+/* ch_addr = 0x1, node_addr = 0xf, data_addr = 0x0 */
-+/* DfeTailEnableVgaThresh1000 */
-+#define DFE_TAIL_EANBLE_VGA_TRHESH_1000 GENMASK(5, 1)
-+
-+/* ch_addr = 0x1, node_addr = 0xf, data_addr = 0x1 */
-+/* MrvlTrFix100Kp */
-+#define MRVL_TR_FIX_100KP_MASK GENMASK(22, 20)
-+/* MrvlTrFix100Kf */
-+#define MRVL_TR_FIX_100KF_MASK GENMASK(19, 17)
-+/* MrvlTrFix1000Kp */
-+#define MRVL_TR_FIX_1000KP_MASK GENMASK(16, 14)
-+/* MrvlTrFix1000Kf */
-+#define MRVL_TR_FIX_1000KF_MASK GENMASK(13, 11)
-+
-+/* ch_addr = 0x1, node_addr = 0xf, data_addr = 0x12 */
-+/* VgaDecRate */
-+#define VGA_DECIMATION_RATE_MASK GENMASK(8, 5)
-+
-+/* ch_addr = 0x1, node_addr = 0xf, data_addr = 0x17 */
-+/* SlvDSPreadyTime */
-+#define SLAVE_DSP_READY_TIME_MASK GENMASK(22, 15)
-+/* MasDSPreadyTime */
-+#define MASTER_DSP_READY_TIME_MASK GENMASK(14, 7)
-+
-+/* ch_addr = 0x1, node_addr = 0xf, data_addr = 0x20 */
-+/* ResetSyncOffset */
-+#define RESET_SYNC_OFFSET_MASK GENMASK(11, 8)
-+
-+/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x0 */
-+/* FfeUpdGainForceVal */
-+#define FFE_UPDATE_GAIN_FORCE_VAL_MASK GENMASK(9, 7)
-+/* FfeUpdGainForce */
-+#define FFE_UPDATE_GAIN_FORCE BIT(6)
-+
-+/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x6 */
-+/* SS: Steady-state, KP: Proportional Gain */
-+/* SSTrKp100 */
-+#define SS_TR_KP100_MASK GENMASK(21, 19)
-+/* SSTrKf100 */
-+#define SS_TR_KF100_MASK GENMASK(18, 16)
-+/* SSTrKp1000Mas */
-+#define SS_TR_KP1000_MASTER_MASK GENMASK(15, 13)
-+/* SSTrKf1000Mas */
-+#define SS_TR_KF1000_MASTER_MASK GENMASK(12, 10)
-+/* SSTrKp1000Slv */
-+#define SS_TR_KP1000_SLAVE_MASK GENMASK(9, 7)
-+/* SSTrKf1000Slv */
-+#define SS_TR_KF1000_SLAVE_MASK GENMASK(6, 4)
-+
-+/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0xd */
-+/* RegEEE_st2TrKf1000 */
-+#define EEE1000_STAGE2_TR_KF_MASK GENMASK(13, 11)
-+
-+/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0xf */
-+/* RegEEE_slv_waketr_timer_tar */
-+#define SLAVE_WAKETR_TIMER_MASK GENMASK(20, 11)
-+/* RegEEE_slv_remtx_timer_tar */
-+#define SLAVE_REMTX_TIMER_MASK GENMASK(10, 1)
-+
-+/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x10 */
-+/* RegEEE_slv_wake_int_timer_tar */
-+#define SLAVE_WAKEINT_TIMER_MASK GENMASK(10, 1)
-+
-+/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x14 */
-+/* RegEEE_trfreeze_timer2 */
-+#define TR_FREEZE_TIMER2_MASK GENMASK(9, 0)
-+
-+/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x1c */
-+/* RegEEE100Stg1_tar */
-+#define EEE100_LPSYNC_STAGE1_UPDATE_TIMER_MASK GENMASK(8, 0)
-+
- #define ANALOG_INTERNAL_OPERATION_MAX_US 20
- #define TXRESERVE_MIN 0
- #define TXRESERVE_MAX 7
-@@ -700,40 +784,41 @@ restore:
- static void mt798x_phy_common_finetune(struct phy_device *phydev)
- {
- phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
-- /* SlvDSPreadyTime = 24, MasDSPreadyTime = 24 */
-- __phy_write(phydev, 0x11, 0xc71);
-- __phy_write(phydev, 0x12, 0xc);
-- __phy_write(phydev, 0x10, 0x8fae);
-+ __mtk_tr_modify(phydev, 0x1, 0xf, 0x17,
-+ SLAVE_DSP_READY_TIME_MASK | MASTER_DSP_READY_TIME_MASK,
-+ FIELD_PREP(SLAVE_DSP_READY_TIME_MASK, 0x18) |
-+ FIELD_PREP(MASTER_DSP_READY_TIME_MASK, 0x18));
-
- /* EnabRandUpdTrig = 1 */
- __phy_write(phydev, 0x11, 0x2f00);
- __phy_write(phydev, 0x12, 0xe);
- __phy_write(phydev, 0x10, 0x8fb0);
-
-- /* NormMseLoThresh = 85 */
-- __phy_write(phydev, 0x11, 0x55a0);
-- __phy_write(phydev, 0x12, 0x0);
-- __phy_write(phydev, 0x10, 0x83aa);
--
-- /* FfeUpdGainForce = 1(Enable), FfeUpdGainForceVal = 4 */
-- __phy_write(phydev, 0x11, 0x240);
-- __phy_write(phydev, 0x12, 0x0);
-- __phy_write(phydev, 0x10, 0x9680);
-+ __mtk_tr_modify(phydev, 0x0, 0x7, 0x15,
-+ NORMAL_MSE_LO_THRESH_MASK,
-+ FIELD_PREP(NORMAL_MSE_LO_THRESH_MASK, 0x55));
-+
-+ __mtk_tr_modify(phydev, 0x2, 0xd, 0x0,
-+ FFE_UPDATE_GAIN_FORCE_VAL_MASK,
-+ FIELD_PREP(FFE_UPDATE_GAIN_FORCE_VAL_MASK, 0x4) |
-+ FFE_UPDATE_GAIN_FORCE);
-
- /* TrFreeze = 0 (mt7988 default) */
- __phy_write(phydev, 0x11, 0x0);
- __phy_write(phydev, 0x12, 0x0);
- __phy_write(phydev, 0x10, 0x9686);
-
-- /* SSTrKp100 = 5 */
-- /* SSTrKf100 = 6 */
-- /* SSTrKp1000Mas = 5 */
-- /* SSTrKf1000Mas = 6 */
-- /* SSTrKp1000Slv = 5 */
-- /* SSTrKf1000Slv = 6 */
-- __phy_write(phydev, 0x11, 0xbaef);
-- __phy_write(phydev, 0x12, 0x2e);
-- __phy_write(phydev, 0x10, 0x968c);
-+ __mtk_tr_modify(phydev, 0x2, 0xd, 0x6,
-+ SS_TR_KP100_MASK | SS_TR_KF100_MASK |
-+ SS_TR_KP1000_MASTER_MASK | SS_TR_KF1000_MASTER_MASK |
-+ SS_TR_KP1000_SLAVE_MASK | SS_TR_KF1000_SLAVE_MASK,
-+ FIELD_PREP(SS_TR_KP100_MASK, 0x5) |
-+ FIELD_PREP(SS_TR_KF100_MASK, 0x6) |
-+ FIELD_PREP(SS_TR_KP1000_MASTER_MASK, 0x5) |
-+ FIELD_PREP(SS_TR_KF1000_MASTER_MASK, 0x6) |
-+ FIELD_PREP(SS_TR_KP1000_SLAVE_MASK, 0x5) |
-+ FIELD_PREP(SS_TR_KF1000_SLAVE_MASK, 0x6));
-+
- phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
- }
-
-@@ -756,27 +841,29 @@ static void mt7981_phy_finetune(struct p
- }
-
- phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
-- /* ResetSyncOffset = 6 */
-- __phy_write(phydev, 0x11, 0x600);
-- __phy_write(phydev, 0x12, 0x0);
-- __phy_write(phydev, 0x10, 0x8fc0);
--
-- /* VgaDecRate = 1 */
-- __phy_write(phydev, 0x11, 0x4c2a);
-- __phy_write(phydev, 0x12, 0x3e);
-- __phy_write(phydev, 0x10, 0x8fa4);
-+ __mtk_tr_modify(phydev, 0x1, 0xf, 0x20,
-+ RESET_SYNC_OFFSET_MASK,
-+ FIELD_PREP(RESET_SYNC_OFFSET_MASK, 0x6));
-+
-+ __mtk_tr_modify(phydev, 0x1, 0xf, 0x12,
-+ VGA_DECIMATION_RATE_MASK,
-+ FIELD_PREP(VGA_DECIMATION_RATE_MASK, 0x1));
-
- /* MrvlTrFix100Kp = 3, MrvlTrFix100Kf = 2,
- * MrvlTrFix1000Kp = 3, MrvlTrFix1000Kf = 2
- */
-- __phy_write(phydev, 0x11, 0xd10a);
-- __phy_write(phydev, 0x12, 0x34);
-- __phy_write(phydev, 0x10, 0x8f82);
-+ __mtk_tr_modify(phydev, 0x1, 0xf, 0x1,
-+ MRVL_TR_FIX_100KP_MASK | MRVL_TR_FIX_100KF_MASK |
-+ MRVL_TR_FIX_1000KP_MASK | MRVL_TR_FIX_1000KF_MASK,
-+ FIELD_PREP(MRVL_TR_FIX_100KP_MASK, 0x3) |
-+ FIELD_PREP(MRVL_TR_FIX_100KF_MASK, 0x2) |
-+ FIELD_PREP(MRVL_TR_FIX_1000KP_MASK, 0x3) |
-+ FIELD_PREP(MRVL_TR_FIX_1000KF_MASK, 0x2));
-
- /* VcoSlicerThreshBitsHigh */
-- __phy_write(phydev, 0x11, 0x5555);
-- __phy_write(phydev, 0x12, 0x55);
-- __phy_write(phydev, 0x10, 0x8ec0);
-+ __mtk_tr_modify(phydev, 0x1, 0xd, 0x20,
-+ VCO_SLICER_THRESH_HIGH_MASK,
-+ FIELD_PREP(VCO_SLICER_THRESH_HIGH_MASK, 0x555555));
- phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
-
- /* TR_OPEN_LOOP_EN = 1, lpf_x_average = 9 */
-@@ -828,25 +915,23 @@ static void mt7988_phy_finetune(struct p
- phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_TX_FILTER, 0x5);
-
- phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
-- /* ResetSyncOffset = 5 */
-- __phy_write(phydev, 0x11, 0x500);
-- __phy_write(phydev, 0x12, 0x0);
-- __phy_write(phydev, 0x10, 0x8fc0);
-+ __mtk_tr_modify(phydev, 0x1, 0xf, 0x20,
-+ RESET_SYNC_OFFSET_MASK,
-+ FIELD_PREP(RESET_SYNC_OFFSET_MASK, 0x5));
-
- /* VgaDecRate is 1 at default on mt7988 */
-
-- /* MrvlTrFix100Kp = 6, MrvlTrFix100Kf = 7,
-- * MrvlTrFix1000Kp = 6, MrvlTrFix1000Kf = 7
-- */
-- __phy_write(phydev, 0x11, 0xb90a);
-- __phy_write(phydev, 0x12, 0x6f);
-- __phy_write(phydev, 0x10, 0x8f82);
--
-- /* RemAckCntLimitCtrl = 1 */
-- __phy_write(phydev, 0x11, 0xfbba);
-- __phy_write(phydev, 0x12, 0xc3);
-- __phy_write(phydev, 0x10, 0x87f8);
--
-+ __mtk_tr_modify(phydev, 0x1, 0xf, 0x1,
-+ MRVL_TR_FIX_100KP_MASK | MRVL_TR_FIX_100KF_MASK |
-+ MRVL_TR_FIX_1000KP_MASK | MRVL_TR_FIX_1000KF_MASK,
-+ FIELD_PREP(MRVL_TR_FIX_100KP_MASK, 0x6) |
-+ FIELD_PREP(MRVL_TR_FIX_100KF_MASK, 0x7) |
-+ FIELD_PREP(MRVL_TR_FIX_1000KP_MASK, 0x6) |
-+ FIELD_PREP(MRVL_TR_FIX_1000KF_MASK, 0x7));
-+
-+ __mtk_tr_modify(phydev, 0x0, 0xf, 0x3c,
-+ REMOTE_ACK_COUNT_LIMIT_CTRL_MASK,
-+ FIELD_PREP(REMOTE_ACK_COUNT_LIMIT_CTRL_MASK, 0x1));
- phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
-
- /* TR_OPEN_LOOP_EN = 1, lpf_x_average = 10 */
-@@ -927,40 +1012,36 @@ static void mt798x_phy_eee(struct phy_de
- __phy_write(phydev, 0x12, 0x0);
- __phy_write(phydev, 0x10, 0x9690);
-
-- /* REG_EEE_st2TrKf1000 = 2 */
-- __phy_write(phydev, 0x11, 0x114f);
-- __phy_write(phydev, 0x12, 0x2);
-- __phy_write(phydev, 0x10, 0x969a);
--
-- /* RegEEE_slv_wake_tr_timer_tar = 6, RegEEE_slv_remtx_timer_tar = 20 */
-- __phy_write(phydev, 0x11, 0x3028);
-- __phy_write(phydev, 0x12, 0x0);
-- __phy_write(phydev, 0x10, 0x969e);
--
-- /* RegEEE_slv_wake_int_timer_tar = 8 */
-- __phy_write(phydev, 0x11, 0x5010);
-- __phy_write(phydev, 0x12, 0x0);
-- __phy_write(phydev, 0x10, 0x96a0);
--
-- /* RegEEE_trfreeze_timer2 = 586 */
-- __phy_write(phydev, 0x11, 0x24a);
-- __phy_write(phydev, 0x12, 0x0);
-- __phy_write(phydev, 0x10, 0x96a8);
--
-- /* RegEEE100Stg1_tar = 16 */
-- __phy_write(phydev, 0x11, 0x3210);
-- __phy_write(phydev, 0x12, 0x0);
-- __phy_write(phydev, 0x10, 0x96b8);
-+ __mtk_tr_modify(phydev, 0x2, 0xd, 0xd,
-+ EEE1000_STAGE2_TR_KF_MASK,
-+ FIELD_PREP(EEE1000_STAGE2_TR_KF_MASK, 0x2));
-+
-+ __mtk_tr_modify(phydev, 0x2, 0xd, 0xf,
-+ SLAVE_WAKETR_TIMER_MASK | SLAVE_REMTX_TIMER_MASK,
-+ FIELD_PREP(SLAVE_WAKETR_TIMER_MASK, 0x6) |
-+ FIELD_PREP(SLAVE_REMTX_TIMER_MASK, 0x14));
-+
-+ __mtk_tr_modify(phydev, 0x2, 0xd, 0x10,
-+ SLAVE_WAKEINT_TIMER_MASK,
-+ FIELD_PREP(SLAVE_WAKEINT_TIMER_MASK, 0x8));
-+
-+ __mtk_tr_modify(phydev, 0x2, 0xd, 0x14,
-+ TR_FREEZE_TIMER2_MASK,
-+ FIELD_PREP(TR_FREEZE_TIMER2_MASK, 0x24a));
-+
-+ __mtk_tr_modify(phydev, 0x2, 0xd, 0x1c,
-+ EEE100_LPSYNC_STAGE1_UPDATE_TIMER_MASK,
-+ FIELD_PREP(EEE100_LPSYNC_STAGE1_UPDATE_TIMER_MASK,
-+ 0x10));
-
- /* REGEEE_wake_slv_tr_wait_dfesigdet_en = 0 */
- __phy_write(phydev, 0x11, 0x1463);
- __phy_write(phydev, 0x12, 0x0);
- __phy_write(phydev, 0x10, 0x96ca);
-
-- /* DfeTailEnableVgaThresh1000 = 27 */
-- __phy_write(phydev, 0x11, 0x36);
-- __phy_write(phydev, 0x12, 0x0);
-- __phy_write(phydev, 0x10, 0x8f80);
-+ __mtk_tr_modify(phydev, 0x1, 0xf, 0x0,
-+ DFE_TAIL_EANBLE_VGA_TRHESH_1000,
-+ FIELD_PREP(DFE_TAIL_EANBLE_VGA_TRHESH_1000, 0x1b));
- phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
-
- phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_3);
---- a/drivers/net/phy/mediatek/mtk-ge.c
-+++ b/drivers/net/phy/mediatek/mtk-ge.c
-@@ -18,6 +18,10 @@
-
- #define MTK_PHY_PAGE_EXTENDED_2A30 0x2a30
-
-+/* Registers on Token Ring debug nodes */
-+/* ch_addr = 0x1, node_addr = 0xf, data_addr = 0x17 */
-+#define SLAVE_DSP_READY_TIME_MASK GENMASK(22, 15)
-+
- /* Registers on MDIO_MMD_VEND1 */
- #define MTK_PHY_GBE_MODE_TX_DELAY_SEL 0x13
- #define MTK_PHY_TEST_MODE_TX_DELAY_SEL 0x14
-@@ -45,11 +49,8 @@ static void mtk_gephy_config_init(struct
- 0, MTK_PHY_ENABLE_DOWNSHIFT);
-
- /* Increase SlvDPSready time */
-- phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
-- __phy_write(phydev, 0x10, 0xafae);
-- __phy_write(phydev, 0x12, 0x2f);
-- __phy_write(phydev, 0x10, 0x8fae);
-- phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
-+ mtk_tr_modify(phydev, 0x1, 0xf, 0x17, SLAVE_DSP_READY_TIME_MASK,
-+ FIELD_PREP(SLAVE_DSP_READY_TIME_MASK, 0x5e));
-
- /* Adjust 100_mse_threshold */
- phy_modify_mmd(phydev, MDIO_MMD_VEND1,
---- a/drivers/net/phy/mediatek/mtk-phy-lib.c
-+++ b/drivers/net/phy/mediatek/mtk-phy-lib.c
-@@ -6,6 +6,69 @@
-
- #include "mtk.h"
-
-+/* Difference between functions with mtk_tr* and __mtk_tr* prefixes is
-+ * mtk_tr* functions: wrapped by page switching operations
-+ * __mtk_tr* functions: no page switching operations
-+ */
-+
-+static void __mtk_tr_access(struct phy_device *phydev, bool read, u8 ch_addr,
-+ u8 node_addr, u8 data_addr)
-+{
-+ u16 tr_cmd = BIT(15); /* bit 14 & 0 are reserved */
-+
-+ if (read)
-+ tr_cmd |= BIT(13);
-+
-+ tr_cmd |= (((ch_addr & 0x3) << 11) |
-+ ((node_addr & 0xf) << 7) |
-+ ((data_addr & 0x3f) << 1));
-+ dev_dbg(&phydev->mdio.dev, "tr_cmd: 0x%x\n", tr_cmd);
-+ __phy_write(phydev, 0x10, tr_cmd);
-+}
-+
-+static void __mtk_tr_read(struct phy_device *phydev, u8 ch_addr, u8 node_addr,
-+ u8 data_addr, u16 *tr_high, u16 *tr_low)
-+{
-+ __mtk_tr_access(phydev, true, ch_addr, node_addr, data_addr);
-+ *tr_low = __phy_read(phydev, 0x11);
-+ *tr_high = __phy_read(phydev, 0x12);
-+ dev_dbg(&phydev->mdio.dev, "tr_high read: 0x%x, tr_low read: 0x%x\n",
-+ *tr_high, *tr_low);
-+}
-+
-+static void __mtk_tr_write(struct phy_device *phydev, u8 ch_addr, u8 node_addr,
-+ u8 data_addr, u32 tr_data)
-+{
-+ __phy_write(phydev, 0x11, tr_data & 0xffff);
-+ __phy_write(phydev, 0x12, tr_data >> 16);
-+ dev_dbg(&phydev->mdio.dev, "tr_high write: 0x%x, tr_low write: 0x%x\n",
-+ tr_data >> 16, tr_data & 0xffff);
-+ __mtk_tr_access(phydev, false, ch_addr, node_addr, data_addr);
-+}
-+
-+void __mtk_tr_modify(struct phy_device *phydev, u8 ch_addr, u8 node_addr,
-+ u8 data_addr, u32 mask, u32 set)
-+{
-+ u32 tr_data;
-+ u16 tr_high;
-+ u16 tr_low;
-+
-+ __mtk_tr_read(phydev, ch_addr, node_addr, data_addr, &tr_high, &tr_low);
-+ tr_data = (tr_high << 16) | tr_low;
-+ tr_data = (tr_data & ~mask) | set;
-+ __mtk_tr_write(phydev, ch_addr, node_addr, data_addr, tr_data);
-+}
-+EXPORT_SYMBOL_GPL(__mtk_tr_modify);
-+
-+void mtk_tr_modify(struct phy_device *phydev, u8 ch_addr, u8 node_addr,
-+ u8 data_addr, u32 mask, u32 set)
-+{
-+ phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
-+ __mtk_tr_modify(phydev, ch_addr, node_addr, data_addr, mask, set);
-+ phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
-+}
-+EXPORT_SYMBOL_GPL(mtk_tr_modify);
-+
- int mtk_phy_read_page(struct phy_device *phydev)
- {
- return __phy_read(phydev, MTK_EXT_PAGE_ACCESS);
---- a/drivers/net/phy/mediatek/mtk.h
-+++ b/drivers/net/phy/mediatek/mtk.h
-@@ -68,6 +68,11 @@ struct mtk_socphy_priv {
- unsigned long led_state;
- };
-
-+void __mtk_tr_modify(struct phy_device *phydev, u8 ch_addr, u8 node_addr,
-+ u8 data_addr, u32 mask, u32 set);
-+void mtk_tr_modify(struct phy_device *phydev, u8 ch_addr, u8 node_addr,
-+ u8 data_addr, u32 mask, u32 set);
-+
- int mtk_phy_read_page(struct phy_device *phydev);
- int mtk_phy_write_page(struct phy_device *phydev, int page);
-
+++ /dev/null
-From 40d33d6d3c90eb104c66e05cdc00db61268c93f9 Mon Sep 17 00:00:00 2001
-Date: Thu, 13 Feb 2025 16:05:51 +0800
-Subject: [PATCH 3/5] net: phy: mediatek: Add token ring set bit operation
- support
-
-Previously in mtk-ge-soc.c, we set some register bits via token
-ring, which were implemented in three __phy_write().
-Now we can do the same thing via __mtk_tr_set_bits() helper.
-
----
- drivers/net/phy/mediatek/mtk-ge-soc.c | 10 ++++++----
- drivers/net/phy/mediatek/mtk-phy-lib.c | 7 +++++++
- drivers/net/phy/mediatek/mtk.h | 2 ++
- 3 files changed, 15 insertions(+), 4 deletions(-)
-
---- a/drivers/net/phy/mediatek/mtk-ge-soc.c
-+++ b/drivers/net/phy/mediatek/mtk-ge-soc.c
-@@ -62,6 +62,10 @@
- /* MasDSPreadyTime */
- #define MASTER_DSP_READY_TIME_MASK GENMASK(14, 7)
-
-+/* ch_addr = 0x1, node_addr = 0xf, data_addr = 0x18 */
-+/* EnabRandUpdTrig */
-+#define ENABLE_RANDOM_UPDOWN_COUNTER_TRIGGER BIT(8)
-+
- /* ch_addr = 0x1, node_addr = 0xf, data_addr = 0x20 */
- /* ResetSyncOffset */
- #define RESET_SYNC_OFFSET_MASK GENMASK(11, 8)
-@@ -789,10 +793,8 @@ static void mt798x_phy_common_finetune(s
- FIELD_PREP(SLAVE_DSP_READY_TIME_MASK, 0x18) |
- FIELD_PREP(MASTER_DSP_READY_TIME_MASK, 0x18));
-
-- /* EnabRandUpdTrig = 1 */
-- __phy_write(phydev, 0x11, 0x2f00);
-- __phy_write(phydev, 0x12, 0xe);
-- __phy_write(phydev, 0x10, 0x8fb0);
-+ __mtk_tr_set_bits(phydev, 0x1, 0xf, 0x18,
-+ ENABLE_RANDOM_UPDOWN_COUNTER_TRIGGER);
-
- __mtk_tr_modify(phydev, 0x0, 0x7, 0x15,
- NORMAL_MSE_LO_THRESH_MASK,
---- a/drivers/net/phy/mediatek/mtk-phy-lib.c
-+++ b/drivers/net/phy/mediatek/mtk-phy-lib.c
-@@ -69,6 +69,13 @@ void mtk_tr_modify(struct phy_device *ph
- }
- EXPORT_SYMBOL_GPL(mtk_tr_modify);
-
-+void __mtk_tr_set_bits(struct phy_device *phydev, u8 ch_addr, u8 node_addr,
-+ u8 data_addr, u32 set)
-+{
-+ __mtk_tr_modify(phydev, ch_addr, node_addr, data_addr, 0, set);
-+}
-+EXPORT_SYMBOL_GPL(__mtk_tr_set_bits);
-+
- int mtk_phy_read_page(struct phy_device *phydev)
- {
- return __phy_read(phydev, MTK_EXT_PAGE_ACCESS);
---- a/drivers/net/phy/mediatek/mtk.h
-+++ b/drivers/net/phy/mediatek/mtk.h
-@@ -72,6 +72,8 @@ void __mtk_tr_modify(struct phy_device *
- u8 data_addr, u32 mask, u32 set);
- void mtk_tr_modify(struct phy_device *phydev, u8 ch_addr, u8 node_addr,
- u8 data_addr, u32 mask, u32 set);
-+void __mtk_tr_set_bits(struct phy_device *phydev, u8 ch_addr, u8 node_addr,
-+ u8 data_addr, u32 set);
-
- int mtk_phy_read_page(struct phy_device *phydev);
- int mtk_phy_write_page(struct phy_device *phydev, int page);
+++ /dev/null
-From 4786eff288bcc77a5dbc2be2308f46f70e58600d Mon Sep 17 00:00:00 2001
-Date: Thu, 13 Feb 2025 16:05:52 +0800
-Subject: [PATCH 4/5] net: phy: mediatek: Add token ring clear bit operation
- support
-
-Similar to __mtk_tr_set_bits() support. Previously in mtk-ge-soc.c,
-we clear some register bits via token ring, which were also implemented
-in three __phy_write(). Now we can do the same thing via
-__mtk_tr_clr_bits() helper.
-
----
- drivers/net/phy/mediatek/mtk-ge-soc.c | 30 +++++++++++++++-----------
- drivers/net/phy/mediatek/mtk-phy-lib.c | 7 ++++++
- drivers/net/phy/mediatek/mtk.h | 2 ++
- 3 files changed, 27 insertions(+), 12 deletions(-)
-
---- a/drivers/net/phy/mediatek/mtk-ge-soc.c
-+++ b/drivers/net/phy/mediatek/mtk-ge-soc.c
-@@ -76,6 +76,10 @@
- /* FfeUpdGainForce */
- #define FFE_UPDATE_GAIN_FORCE BIT(6)
-
-+/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x3 */
-+/* TrFreeze */
-+#define TR_FREEZE_MASK GENMASK(11, 0)
-+
- /* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x6 */
- /* SS: Steady-state, KP: Proportional Gain */
- /* SSTrKp100 */
-@@ -91,6 +95,11 @@
- /* SSTrKf1000Slv */
- #define SS_TR_KF1000_SLAVE_MASK GENMASK(6, 4)
-
-+/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x8 */
-+/* clear this bit if wanna select from AFE */
-+/* Regsigdet_sel_1000 */
-+#define EEE1000_SELECT_SIGNAL_DETECTION_FROM_DFE BIT(4)
-+
- /* ch_addr = 0x2, node_addr = 0xd, data_addr = 0xd */
- /* RegEEE_st2TrKf1000 */
- #define EEE1000_STAGE2_TR_KF_MASK GENMASK(13, 11)
-@@ -113,6 +122,10 @@
- /* RegEEE100Stg1_tar */
- #define EEE100_LPSYNC_STAGE1_UPDATE_TIMER_MASK GENMASK(8, 0)
-
-+/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x25 */
-+/* REGEEE_wake_slv_tr_wait_dfesigdet_en */
-+#define WAKE_SLAVE_TR_WAIT_DFE_DETECTION_EN BIT(11)
-+
- #define ANALOG_INTERNAL_OPERATION_MAX_US 20
- #define TXRESERVE_MIN 0
- #define TXRESERVE_MAX 7
-@@ -805,10 +818,7 @@ static void mt798x_phy_common_finetune(s
- FIELD_PREP(FFE_UPDATE_GAIN_FORCE_VAL_MASK, 0x4) |
- FFE_UPDATE_GAIN_FORCE);
-
-- /* TrFreeze = 0 (mt7988 default) */
-- __phy_write(phydev, 0x11, 0x0);
-- __phy_write(phydev, 0x12, 0x0);
-- __phy_write(phydev, 0x10, 0x9686);
-+ __mtk_tr_clr_bits(phydev, 0x2, 0xd, 0x3, TR_FREEZE_MASK);
-
- __mtk_tr_modify(phydev, 0x2, 0xd, 0x6,
- SS_TR_KP100_MASK | SS_TR_KF100_MASK |
-@@ -1009,10 +1019,8 @@ static void mt798x_phy_eee(struct phy_de
- MTK_PHY_TR_READY_SKIP_AFE_WAKEUP);
-
- phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
-- /* Regsigdet_sel_1000 = 0 */
-- __phy_write(phydev, 0x11, 0xb);
-- __phy_write(phydev, 0x12, 0x0);
-- __phy_write(phydev, 0x10, 0x9690);
-+ __mtk_tr_clr_bits(phydev, 0x2, 0xd, 0x8,
-+ EEE1000_SELECT_SIGNAL_DETECTION_FROM_DFE);
-
- __mtk_tr_modify(phydev, 0x2, 0xd, 0xd,
- EEE1000_STAGE2_TR_KF_MASK,
-@@ -1036,10 +1044,8 @@ static void mt798x_phy_eee(struct phy_de
- FIELD_PREP(EEE100_LPSYNC_STAGE1_UPDATE_TIMER_MASK,
- 0x10));
-
-- /* REGEEE_wake_slv_tr_wait_dfesigdet_en = 0 */
-- __phy_write(phydev, 0x11, 0x1463);
-- __phy_write(phydev, 0x12, 0x0);
-- __phy_write(phydev, 0x10, 0x96ca);
-+ __mtk_tr_clr_bits(phydev, 0x2, 0xd, 0x25,
-+ WAKE_SLAVE_TR_WAIT_DFE_DETECTION_EN);
-
- __mtk_tr_modify(phydev, 0x1, 0xf, 0x0,
- DFE_TAIL_EANBLE_VGA_TRHESH_1000,
---- a/drivers/net/phy/mediatek/mtk-phy-lib.c
-+++ b/drivers/net/phy/mediatek/mtk-phy-lib.c
-@@ -76,6 +76,13 @@ void __mtk_tr_set_bits(struct phy_device
- }
- EXPORT_SYMBOL_GPL(__mtk_tr_set_bits);
-
-+void __mtk_tr_clr_bits(struct phy_device *phydev, u8 ch_addr, u8 node_addr,
-+ u8 data_addr, u32 clr)
-+{
-+ __mtk_tr_modify(phydev, ch_addr, node_addr, data_addr, clr, 0);
-+}
-+EXPORT_SYMBOL_GPL(__mtk_tr_clr_bits);
-+
- int mtk_phy_read_page(struct phy_device *phydev)
- {
- return __phy_read(phydev, MTK_EXT_PAGE_ACCESS);
---- a/drivers/net/phy/mediatek/mtk.h
-+++ b/drivers/net/phy/mediatek/mtk.h
-@@ -74,6 +74,8 @@ void mtk_tr_modify(struct phy_device *ph
- u8 data_addr, u32 mask, u32 set);
- void __mtk_tr_set_bits(struct phy_device *phydev, u8 ch_addr, u8 node_addr,
- u8 data_addr, u32 set);
-+void __mtk_tr_clr_bits(struct phy_device *phydev, u8 ch_addr, u8 node_addr,
-+ u8 data_addr, u32 clr);
-
- int mtk_phy_read_page(struct phy_device *phydev);
- int mtk_phy_write_page(struct phy_device *phydev, int page);
+++ /dev/null
-From be378ebd6cfb8e369d4aa03a551e594d00debda5 Mon Sep 17 00:00:00 2001
-Date: Thu, 13 Feb 2025 16:05:53 +0800
-Subject: [PATCH 5/5] net: phy: mediatek: Move some macros to phy-lib for later
- use
-
-Move some macros to phy-lib because MediaTek's 2.5G built-in
-ethernet PHY will also use them.
-
----
- drivers/net/phy/mediatek/mtk-ge.c | 4 ----
- drivers/net/phy/mediatek/mtk.h | 4 ++++
- 2 files changed, 4 insertions(+), 4 deletions(-)
-
---- a/drivers/net/phy/mediatek/mtk-ge.c
-+++ b/drivers/net/phy/mediatek/mtk-ge.c
-@@ -8,10 +8,6 @@
- #define MTK_GPHY_ID_MT7530 0x03a29412
- #define MTK_GPHY_ID_MT7531 0x03a29441
-
--#define MTK_PHY_PAGE_EXTENDED_1 0x0001
--#define MTK_PHY_AUX_CTRL_AND_STATUS 0x14
--#define MTK_PHY_ENABLE_DOWNSHIFT BIT(4)
--
- #define MTK_PHY_PAGE_EXTENDED_2 0x0002
- #define MTK_PHY_PAGE_EXTENDED_3 0x0003
- #define MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG11 0x11
---- a/drivers/net/phy/mediatek/mtk.h
-+++ b/drivers/net/phy/mediatek/mtk.h
-@@ -8,7 +8,11 @@
- #ifndef _MTK_EPHY_H_
- #define _MTK_EPHY_H_
-
-+#define MTK_PHY_AUX_CTRL_AND_STATUS 0x14
-+#define MTK_PHY_ENABLE_DOWNSHIFT BIT(4)
-+
- #define MTK_EXT_PAGE_ACCESS 0x1f
-+#define MTK_PHY_PAGE_EXTENDED_1 0x0001
- #define MTK_PHY_PAGE_STANDARD 0x0000
- #define MTK_PHY_PAGE_EXTENDED_52B5 0x52b5
-
+++ /dev/null
-From e5566162af8b9690e096d2e6089e4ed955a0d13d Mon Sep 17 00:00:00 2001
-Date: Thu, 10 Apr 2025 12:04:03 +0200
-Subject: [PATCH 1/2] net: phy: mediatek: permit to compile test GE SOC PHY
- driver
-
-When commit 462a3daad679 ("net: phy: mediatek: fix compile-test
-dependencies") fixed the dependency, it should have also introduced
-an or on COMPILE_TEST to permit this driver to be compile-tested even if
-NVMEM_MTK_EFUSE wasn't selected. The driver makes use of NVMEM API that
-are always compiled (return error) so the driver can actually be
-compiled even without that config.
-
-Fix and simplify the dependency condition of this kernel config.
-
-Fixes: 462a3daad679 ("net: phy: mediatek: fix compile-test dependencies")
----
- drivers/net/phy/mediatek/Kconfig | 3 +--
- 1 file changed, 1 insertion(+), 2 deletions(-)
-
---- a/drivers/net/phy/mediatek/Kconfig
-+++ b/drivers/net/phy/mediatek/Kconfig
-@@ -15,8 +15,7 @@ config MEDIATEK_GE_PHY
-
- config MEDIATEK_GE_SOC_PHY
- tristate "MediaTek SoC Ethernet PHYs"
-- depends on (ARM64 && ARCH_MEDIATEK) || COMPILE_TEST
-- depends on NVMEM_MTK_EFUSE
-+ depends on (ARM64 && ARCH_MEDIATEK && NVMEM_MTK_EFUSE) || COMPILE_TEST
- select MTK_NET_PHYLIB
- help
- Supports MediaTek SoC built-in Gigabit Ethernet PHYs.
+++ /dev/null
-From 5d0fad48d2dec175ecb999974b94203c577973ef Mon Sep 17 00:00:00 2001
-Date: Wed, 8 May 2024 11:43:34 +0100
-Subject: [PATCH] net: ethernet: mediatek: split tx and rx fields in
- mtk_soc_data struct
-
-Split tx and rx fields in mtk_soc_data struct. This is a preliminary
-patch to roll back to ADMAv1 for MT7986 and MT7981 SoC in order to fix a
-hw hang if the device receives a corrupted packet when using ADMAv2.0.
-
-Fixes: 197c9e9b17b1 ("net: ethernet: mtk_eth_soc: introduce support for mt7986 chipset")
-Link: https://lore.kernel.org/r/70a799b1f060ec2f57883e88ccb420ac0fb0abb5.1715164770.git.daniel@makrotopia.org
----
- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 210 ++++++++++++--------
- drivers/net/ethernet/mediatek/mtk_eth_soc.h | 29 +--
- 2 files changed, 139 insertions(+), 100 deletions(-)
-
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -1138,7 +1138,7 @@ static int mtk_init_fq_dma(struct mtk_et
- eth->scratch_ring = eth->sram_base;
- else
- eth->scratch_ring = dma_alloc_coherent(eth->dma_dev,
-- cnt * soc->txrx.txd_size,
-+ cnt * soc->tx.desc_size,
- ð->phy_scratch_ring,
- GFP_KERNEL);
- if (unlikely(!eth->scratch_ring))
-@@ -1154,16 +1154,16 @@ static int mtk_init_fq_dma(struct mtk_et
- if (unlikely(dma_mapping_error(eth->dma_dev, dma_addr)))
- return -ENOMEM;
-
-- phy_ring_tail = eth->phy_scratch_ring + soc->txrx.txd_size * (cnt - 1);
-+ phy_ring_tail = eth->phy_scratch_ring + soc->tx.desc_size * (cnt - 1);
-
- for (i = 0; i < cnt; i++) {
- struct mtk_tx_dma_v2 *txd;
-
-- txd = eth->scratch_ring + i * soc->txrx.txd_size;
-+ txd = eth->scratch_ring + i * soc->tx.desc_size;
- txd->txd1 = dma_addr + i * MTK_QDMA_PAGE_SIZE;
- if (i < cnt - 1)
- txd->txd2 = eth->phy_scratch_ring +
-- (i + 1) * soc->txrx.txd_size;
-+ (i + 1) * soc->tx.desc_size;
-
- txd->txd3 = TX_DMA_PLEN0(MTK_QDMA_PAGE_SIZE);
- txd->txd4 = 0;
-@@ -1412,7 +1412,7 @@ static int mtk_tx_map(struct sk_buff *sk
- if (itxd == ring->last_free)
- return -ENOMEM;
-
-- itx_buf = mtk_desc_to_tx_buf(ring, itxd, soc->txrx.txd_size);
-+ itx_buf = mtk_desc_to_tx_buf(ring, itxd, soc->tx.desc_size);
- memset(itx_buf, 0, sizeof(*itx_buf));
-
- txd_info.addr = dma_map_single(eth->dma_dev, skb->data, txd_info.size,
-@@ -1453,7 +1453,7 @@ static int mtk_tx_map(struct sk_buff *sk
-
- memset(&txd_info, 0, sizeof(struct mtk_tx_dma_desc_info));
- txd_info.size = min_t(unsigned int, frag_size,
-- soc->txrx.dma_max_len);
-+ soc->tx.dma_max_len);
- txd_info.qid = queue;
- txd_info.last = i == skb_shinfo(skb)->nr_frags - 1 &&
- !(frag_size - txd_info.size);
-@@ -1466,7 +1466,7 @@ static int mtk_tx_map(struct sk_buff *sk
- mtk_tx_set_dma_desc(dev, txd, &txd_info);
-
- tx_buf = mtk_desc_to_tx_buf(ring, txd,
-- soc->txrx.txd_size);
-+ soc->tx.desc_size);
- if (new_desc)
- memset(tx_buf, 0, sizeof(*tx_buf));
- tx_buf->data = (void *)MTK_DMA_DUMMY_DESC;
-@@ -1509,7 +1509,7 @@ static int mtk_tx_map(struct sk_buff *sk
- } else {
- int next_idx;
-
-- next_idx = NEXT_DESP_IDX(txd_to_idx(ring, txd, soc->txrx.txd_size),
-+ next_idx = NEXT_DESP_IDX(txd_to_idx(ring, txd, soc->tx.desc_size),
- ring->dma_size);
- mtk_w32(eth, next_idx, MT7628_TX_CTX_IDX0);
- }
-@@ -1518,7 +1518,7 @@ static int mtk_tx_map(struct sk_buff *sk
-
- err_dma:
- do {
-- tx_buf = mtk_desc_to_tx_buf(ring, itxd, soc->txrx.txd_size);
-+ tx_buf = mtk_desc_to_tx_buf(ring, itxd, soc->tx.desc_size);
-
- /* unmap dma */
- mtk_tx_unmap(eth, tx_buf, NULL, false);
-@@ -1543,7 +1543,7 @@ static int mtk_cal_txd_req(struct mtk_et
- for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
- frag = &skb_shinfo(skb)->frags[i];
- nfrags += DIV_ROUND_UP(skb_frag_size(frag),
-- eth->soc->txrx.dma_max_len);
-+ eth->soc->tx.dma_max_len);
- }
- } else {
- nfrags += skb_shinfo(skb)->nr_frags;
-@@ -1658,7 +1658,7 @@ static struct mtk_rx_ring *mtk_get_rx_ri
-
- ring = ð->rx_ring[i];
- idx = NEXT_DESP_IDX(ring->calc_idx, ring->dma_size);
-- rxd = ring->dma + idx * eth->soc->txrx.rxd_size;
-+ rxd = ring->dma + idx * eth->soc->rx.desc_size;
- if (rxd->rxd2 & RX_DMA_DONE) {
- ring->calc_idx_update = true;
- return ring;
-@@ -1826,7 +1826,7 @@ static int mtk_xdp_submit_frame(struct m
- }
- htxd = txd;
-
-- tx_buf = mtk_desc_to_tx_buf(ring, txd, soc->txrx.txd_size);
-+ tx_buf = mtk_desc_to_tx_buf(ring, txd, soc->tx.desc_size);
- memset(tx_buf, 0, sizeof(*tx_buf));
- htx_buf = tx_buf;
-
-@@ -1845,7 +1845,7 @@ static int mtk_xdp_submit_frame(struct m
- goto unmap;
-
- tx_buf = mtk_desc_to_tx_buf(ring, txd,
-- soc->txrx.txd_size);
-+ soc->tx.desc_size);
- memset(tx_buf, 0, sizeof(*tx_buf));
- n_desc++;
- }
-@@ -1883,7 +1883,7 @@ static int mtk_xdp_submit_frame(struct m
- } else {
- int idx;
-
-- idx = txd_to_idx(ring, txd, soc->txrx.txd_size);
-+ idx = txd_to_idx(ring, txd, soc->tx.desc_size);
- mtk_w32(eth, NEXT_DESP_IDX(idx, ring->dma_size),
- MT7628_TX_CTX_IDX0);
- }
-@@ -1894,7 +1894,7 @@ static int mtk_xdp_submit_frame(struct m
-
- unmap:
- while (htxd != txd) {
-- tx_buf = mtk_desc_to_tx_buf(ring, htxd, soc->txrx.txd_size);
-+ tx_buf = mtk_desc_to_tx_buf(ring, htxd, soc->tx.desc_size);
- mtk_tx_unmap(eth, tx_buf, NULL, false);
-
- htxd->txd3 = TX_DMA_LS0 | TX_DMA_OWNER_CPU;
-@@ -2025,7 +2025,7 @@ static int mtk_poll_rx(struct napi_struc
- goto rx_done;
-
- idx = NEXT_DESP_IDX(ring->calc_idx, ring->dma_size);
-- rxd = ring->dma + idx * eth->soc->txrx.rxd_size;
-+ rxd = ring->dma + idx * eth->soc->rx.desc_size;
- data = ring->data[idx];
-
- if (!mtk_rx_get_desc(eth, &trxd, rxd))
-@@ -2160,7 +2160,7 @@ static int mtk_poll_rx(struct napi_struc
- rxdcsum = &trxd.rxd4;
- }
-
-- if (*rxdcsum & eth->soc->txrx.rx_dma_l4_valid)
-+ if (*rxdcsum & eth->soc->rx.dma_l4_valid)
- skb->ip_summed = CHECKSUM_UNNECESSARY;
- else
- skb_checksum_none_assert(skb);
-@@ -2288,7 +2288,7 @@ static int mtk_poll_tx_qdma(struct mtk_e
- break;
-
- tx_buf = mtk_desc_to_tx_buf(ring, desc,
-- eth->soc->txrx.txd_size);
-+ eth->soc->tx.desc_size);
- if (!tx_buf->data)
- break;
-
-@@ -2339,7 +2339,7 @@ static int mtk_poll_tx_pdma(struct mtk_e
- }
- mtk_tx_unmap(eth, tx_buf, &bq, true);
-
-- desc = ring->dma + cpu * eth->soc->txrx.txd_size;
-+ desc = ring->dma + cpu * eth->soc->tx.desc_size;
- ring->last_free = desc;
- atomic_inc(&ring->free_count);
-
-@@ -2429,7 +2429,7 @@ static int mtk_napi_rx(struct napi_struc
- do {
- int rx_done;
-
-- mtk_w32(eth, eth->soc->txrx.rx_irq_done_mask,
-+ mtk_w32(eth, eth->soc->rx.irq_done_mask,
- reg_map->pdma.irq_status);
- rx_done = mtk_poll_rx(napi, budget - rx_done_total, eth);
- rx_done_total += rx_done;
-@@ -2445,10 +2445,10 @@ static int mtk_napi_rx(struct napi_struc
- return budget;
-
- } while (mtk_r32(eth, reg_map->pdma.irq_status) &
-- eth->soc->txrx.rx_irq_done_mask);
-+ eth->soc->rx.irq_done_mask);
-
- if (napi_complete_done(napi, rx_done_total))
-- mtk_rx_irq_enable(eth, eth->soc->txrx.rx_irq_done_mask);
-+ mtk_rx_irq_enable(eth, eth->soc->rx.irq_done_mask);
-
- return rx_done_total;
- }
-@@ -2457,7 +2457,7 @@ static int mtk_tx_alloc(struct mtk_eth *
- {
- const struct mtk_soc_data *soc = eth->soc;
- struct mtk_tx_ring *ring = ð->tx_ring;
-- int i, sz = soc->txrx.txd_size;
-+ int i, sz = soc->tx.desc_size;
- struct mtk_tx_dma_v2 *txd;
- int ring_size;
- u32 ofs, val;
-@@ -2580,14 +2580,14 @@ static void mtk_tx_clean(struct mtk_eth
- }
- if (!MTK_HAS_CAPS(soc->caps, MTK_SRAM) && ring->dma) {
- dma_free_coherent(eth->dma_dev,
-- ring->dma_size * soc->txrx.txd_size,
-+ ring->dma_size * soc->tx.desc_size,
- ring->dma, ring->phys);
- ring->dma = NULL;
- }
-
- if (ring->dma_pdma) {
- dma_free_coherent(eth->dma_dev,
-- ring->dma_size * soc->txrx.txd_size,
-+ ring->dma_size * soc->tx.desc_size,
- ring->dma_pdma, ring->phys_pdma);
- ring->dma_pdma = NULL;
- }
-@@ -2642,15 +2642,15 @@ static int mtk_rx_alloc(struct mtk_eth *
- if (!MTK_HAS_CAPS(eth->soc->caps, MTK_SRAM) ||
- rx_flag != MTK_RX_FLAGS_NORMAL) {
- ring->dma = dma_alloc_coherent(eth->dma_dev,
-- rx_dma_size * eth->soc->txrx.rxd_size,
-- &ring->phys, GFP_KERNEL);
-+ rx_dma_size * eth->soc->rx.desc_size,
-+ &ring->phys, GFP_KERNEL);
- } else {
- struct mtk_tx_ring *tx_ring = ð->tx_ring;
-
- ring->dma = tx_ring->dma + tx_ring_size *
-- eth->soc->txrx.txd_size * (ring_no + 1);
-+ eth->soc->tx.desc_size * (ring_no + 1);
- ring->phys = tx_ring->phys + tx_ring_size *
-- eth->soc->txrx.txd_size * (ring_no + 1);
-+ eth->soc->tx.desc_size * (ring_no + 1);
- }
-
- if (!ring->dma)
-@@ -2661,7 +2661,7 @@ static int mtk_rx_alloc(struct mtk_eth *
- dma_addr_t dma_addr;
- void *data;
-
-- rxd = ring->dma + i * eth->soc->txrx.rxd_size;
-+ rxd = ring->dma + i * eth->soc->rx.desc_size;
- if (ring->page_pool) {
- data = mtk_page_pool_get_buff(ring->page_pool,
- &dma_addr, GFP_KERNEL);
-@@ -2752,7 +2752,7 @@ static void mtk_rx_clean(struct mtk_eth
- if (!ring->data[i])
- continue;
-
-- rxd = ring->dma + i * eth->soc->txrx.rxd_size;
-+ rxd = ring->dma + i * eth->soc->rx.desc_size;
- if (!rxd->rxd1)
- continue;
-
-@@ -2769,7 +2769,7 @@ static void mtk_rx_clean(struct mtk_eth
-
- if (!in_sram && ring->dma) {
- dma_free_coherent(eth->dma_dev,
-- ring->dma_size * eth->soc->txrx.rxd_size,
-+ ring->dma_size * eth->soc->rx.desc_size,
- ring->dma, ring->phys);
- ring->dma = NULL;
- }
-@@ -3140,7 +3140,7 @@ static void mtk_dma_free(struct mtk_eth
-
- if (!MTK_HAS_CAPS(soc->caps, MTK_SRAM) && eth->scratch_ring) {
- dma_free_coherent(eth->dma_dev,
-- MTK_QDMA_RING_SIZE * soc->txrx.txd_size,
-+ MTK_QDMA_RING_SIZE * soc->tx.desc_size,
- eth->scratch_ring, eth->phy_scratch_ring);
- eth->scratch_ring = NULL;
- eth->phy_scratch_ring = 0;
-@@ -3190,7 +3190,7 @@ static irqreturn_t mtk_handle_irq_rx(int
-
- eth->rx_events++;
- if (likely(napi_schedule_prep(ð->rx_napi))) {
-- mtk_rx_irq_disable(eth, eth->soc->txrx.rx_irq_done_mask);
-+ mtk_rx_irq_disable(eth, eth->soc->rx.irq_done_mask);
- __napi_schedule(ð->rx_napi);
- }
-
-@@ -3216,9 +3216,9 @@ static irqreturn_t mtk_handle_irq(int ir
- const struct mtk_reg_map *reg_map = eth->soc->reg_map;
-
- if (mtk_r32(eth, reg_map->pdma.irq_mask) &
-- eth->soc->txrx.rx_irq_done_mask) {
-+ eth->soc->rx.irq_done_mask) {
- if (mtk_r32(eth, reg_map->pdma.irq_status) &
-- eth->soc->txrx.rx_irq_done_mask)
-+ eth->soc->rx.irq_done_mask)
- mtk_handle_irq_rx(irq, _eth);
- }
- if (mtk_r32(eth, reg_map->tx_irq_mask) & MTK_TX_DONE_INT) {
-@@ -3236,10 +3236,10 @@ static void mtk_poll_controller(struct n
- struct mtk_eth *eth = mac->hw;
-
- mtk_tx_irq_disable(eth, MTK_TX_DONE_INT);
-- mtk_rx_irq_disable(eth, eth->soc->txrx.rx_irq_done_mask);
-+ mtk_rx_irq_disable(eth, eth->soc->rx.irq_done_mask);
- mtk_handle_irq_rx(eth->irq[2], dev);
- mtk_tx_irq_enable(eth, MTK_TX_DONE_INT);
-- mtk_rx_irq_enable(eth, eth->soc->txrx.rx_irq_done_mask);
-+ mtk_rx_irq_enable(eth, eth->soc->rx.irq_done_mask);
- }
- #endif
-
-@@ -3403,7 +3403,7 @@ static int mtk_open(struct net_device *d
- napi_enable(ð->tx_napi);
- napi_enable(ð->rx_napi);
- mtk_tx_irq_enable(eth, MTK_TX_DONE_INT);
-- mtk_rx_irq_enable(eth, soc->txrx.rx_irq_done_mask);
-+ mtk_rx_irq_enable(eth, soc->rx.irq_done_mask);
- refcount_set(ð->dma_refcnt, 1);
- }
- else
-@@ -3487,7 +3487,7 @@ static int mtk_stop(struct net_device *d
- mtk_gdm_config(eth, MTK_GDMA_DROP_ALL);
-
- mtk_tx_irq_disable(eth, MTK_TX_DONE_INT);
-- mtk_rx_irq_disable(eth, eth->soc->txrx.rx_irq_done_mask);
-+ mtk_rx_irq_disable(eth, eth->soc->rx.irq_done_mask);
- napi_disable(ð->tx_napi);
- napi_disable(ð->rx_napi);
-
-@@ -3963,9 +3963,9 @@ static int mtk_hw_init(struct mtk_eth *e
-
- /* FE int grouping */
- mtk_w32(eth, MTK_TX_DONE_INT, reg_map->pdma.int_grp);
-- mtk_w32(eth, eth->soc->txrx.rx_irq_done_mask, reg_map->pdma.int_grp + 4);
-+ mtk_w32(eth, eth->soc->rx.irq_done_mask, reg_map->pdma.int_grp + 4);
- mtk_w32(eth, MTK_TX_DONE_INT, reg_map->qdma.int_grp);
-- mtk_w32(eth, eth->soc->txrx.rx_irq_done_mask, reg_map->qdma.int_grp + 4);
-+ mtk_w32(eth, eth->soc->rx.irq_done_mask, reg_map->qdma.int_grp + 4);
- mtk_w32(eth, 0x21021000, MTK_FE_INT_GRP);
-
- if (mtk_is_netsys_v3_or_greater(eth)) {
-@@ -5073,11 +5073,15 @@ static const struct mtk_soc_data mt2701_
- .required_clks = MT7623_CLKS_BITMAP,
- .required_pctl = true,
- .version = 1,
-- .txrx = {
-- .txd_size = sizeof(struct mtk_tx_dma),
-- .rxd_size = sizeof(struct mtk_rx_dma),
-- .rx_irq_done_mask = MTK_RX_DONE_INT,
-- .rx_dma_l4_valid = RX_DMA_L4_VALID,
-+ .tx = {
-+ .desc_size = sizeof(struct mtk_tx_dma),
-+ .dma_max_len = MTK_TX_DMA_BUF_LEN,
-+ .dma_len_offset = 16,
-+ },
-+ .rx = {
-+ .desc_size = sizeof(struct mtk_rx_dma),
-+ .irq_done_mask = MTK_RX_DONE_INT,
-+ .dma_l4_valid = RX_DMA_L4_VALID,
- .dma_max_len = MTK_TX_DMA_BUF_LEN,
- .dma_len_offset = 16,
- },
-@@ -5093,11 +5097,15 @@ static const struct mtk_soc_data mt7621_
- .offload_version = 1,
- .hash_offset = 2,
- .foe_entry_size = MTK_FOE_ENTRY_V1_SIZE,
-- .txrx = {
-- .txd_size = sizeof(struct mtk_tx_dma),
-- .rxd_size = sizeof(struct mtk_rx_dma),
-- .rx_irq_done_mask = MTK_RX_DONE_INT,
-- .rx_dma_l4_valid = RX_DMA_L4_VALID,
-+ .tx = {
-+ .desc_size = sizeof(struct mtk_tx_dma),
-+ .dma_max_len = MTK_TX_DMA_BUF_LEN,
-+ .dma_len_offset = 16,
-+ },
-+ .rx = {
-+ .desc_size = sizeof(struct mtk_rx_dma),
-+ .irq_done_mask = MTK_RX_DONE_INT,
-+ .dma_l4_valid = RX_DMA_L4_VALID,
- .dma_max_len = MTK_TX_DMA_BUF_LEN,
- .dma_len_offset = 16,
- },
-@@ -5115,11 +5123,15 @@ static const struct mtk_soc_data mt7622_
- .hash_offset = 2,
- .has_accounting = true,
- .foe_entry_size = MTK_FOE_ENTRY_V1_SIZE,
-- .txrx = {
-- .txd_size = sizeof(struct mtk_tx_dma),
-- .rxd_size = sizeof(struct mtk_rx_dma),
-- .rx_irq_done_mask = MTK_RX_DONE_INT,
-- .rx_dma_l4_valid = RX_DMA_L4_VALID,
-+ .tx = {
-+ .desc_size = sizeof(struct mtk_tx_dma),
-+ .dma_max_len = MTK_TX_DMA_BUF_LEN,
-+ .dma_len_offset = 16,
-+ },
-+ .rx = {
-+ .desc_size = sizeof(struct mtk_rx_dma),
-+ .irq_done_mask = MTK_RX_DONE_INT,
-+ .dma_l4_valid = RX_DMA_L4_VALID,
- .dma_max_len = MTK_TX_DMA_BUF_LEN,
- .dma_len_offset = 16,
- },
-@@ -5136,11 +5148,15 @@ static const struct mtk_soc_data mt7623_
- .hash_offset = 2,
- .foe_entry_size = MTK_FOE_ENTRY_V1_SIZE,
- .disable_pll_modes = true,
-- .txrx = {
-- .txd_size = sizeof(struct mtk_tx_dma),
-- .rxd_size = sizeof(struct mtk_rx_dma),
-- .rx_irq_done_mask = MTK_RX_DONE_INT,
-- .rx_dma_l4_valid = RX_DMA_L4_VALID,
-+ .tx = {
-+ .desc_size = sizeof(struct mtk_tx_dma),
-+ .dma_max_len = MTK_TX_DMA_BUF_LEN,
-+ .dma_len_offset = 16,
-+ },
-+ .rx = {
-+ .desc_size = sizeof(struct mtk_rx_dma),
-+ .irq_done_mask = MTK_RX_DONE_INT,
-+ .dma_l4_valid = RX_DMA_L4_VALID,
- .dma_max_len = MTK_TX_DMA_BUF_LEN,
- .dma_len_offset = 16,
- },
-@@ -5155,11 +5171,15 @@ static const struct mtk_soc_data mt7629_
- .required_pctl = false,
- .has_accounting = true,
- .version = 1,
-- .txrx = {
-- .txd_size = sizeof(struct mtk_tx_dma),
-- .rxd_size = sizeof(struct mtk_rx_dma),
-- .rx_irq_done_mask = MTK_RX_DONE_INT,
-- .rx_dma_l4_valid = RX_DMA_L4_VALID,
-+ .tx = {
-+ .desc_size = sizeof(struct mtk_tx_dma),
-+ .dma_max_len = MTK_TX_DMA_BUF_LEN,
-+ .dma_len_offset = 16,
-+ },
-+ .rx = {
-+ .desc_size = sizeof(struct mtk_rx_dma),
-+ .irq_done_mask = MTK_RX_DONE_INT,
-+ .dma_l4_valid = RX_DMA_L4_VALID,
- .dma_max_len = MTK_TX_DMA_BUF_LEN,
- .dma_len_offset = 16,
- },
-@@ -5177,11 +5197,15 @@ static const struct mtk_soc_data mt7981_
- .hash_offset = 4,
- .has_accounting = true,
- .foe_entry_size = MTK_FOE_ENTRY_V2_SIZE,
-- .txrx = {
-- .txd_size = sizeof(struct mtk_tx_dma_v2),
-- .rxd_size = sizeof(struct mtk_rx_dma_v2),
-- .rx_irq_done_mask = MTK_RX_DONE_INT_V2,
-- .rx_dma_l4_valid = RX_DMA_L4_VALID_V2,
-+ .tx = {
-+ .desc_size = sizeof(struct mtk_tx_dma_v2),
-+ .dma_max_len = MTK_TX_DMA_BUF_LEN_V2,
-+ .dma_len_offset = 8,
-+ },
-+ .rx = {
-+ .desc_size = sizeof(struct mtk_rx_dma_v2),
-+ .irq_done_mask = MTK_RX_DONE_INT_V2,
-+ .dma_l4_valid = RX_DMA_L4_VALID_V2,
- .dma_max_len = MTK_TX_DMA_BUF_LEN_V2,
- .dma_len_offset = 8,
- },
-@@ -5199,11 +5223,15 @@ static const struct mtk_soc_data mt7986_
- .hash_offset = 4,
- .has_accounting = true,
- .foe_entry_size = MTK_FOE_ENTRY_V2_SIZE,
-- .txrx = {
-- .txd_size = sizeof(struct mtk_tx_dma_v2),
-- .rxd_size = sizeof(struct mtk_rx_dma_v2),
-- .rx_irq_done_mask = MTK_RX_DONE_INT_V2,
-- .rx_dma_l4_valid = RX_DMA_L4_VALID_V2,
-+ .tx = {
-+ .desc_size = sizeof(struct mtk_tx_dma_v2),
-+ .dma_max_len = MTK_TX_DMA_BUF_LEN_V2,
-+ .dma_len_offset = 8,
-+ },
-+ .rx = {
-+ .desc_size = sizeof(struct mtk_rx_dma_v2),
-+ .irq_done_mask = MTK_RX_DONE_INT_V2,
-+ .dma_l4_valid = RX_DMA_L4_VALID_V2,
- .dma_max_len = MTK_TX_DMA_BUF_LEN_V2,
- .dma_len_offset = 8,
- },
-@@ -5221,11 +5249,15 @@ static const struct mtk_soc_data mt7988_
- .hash_offset = 4,
- .has_accounting = true,
- .foe_entry_size = MTK_FOE_ENTRY_V3_SIZE,
-- .txrx = {
-- .txd_size = sizeof(struct mtk_tx_dma_v2),
-- .rxd_size = sizeof(struct mtk_rx_dma_v2),
-- .rx_irq_done_mask = MTK_RX_DONE_INT_V2,
-- .rx_dma_l4_valid = RX_DMA_L4_VALID_V2,
-+ .tx = {
-+ .desc_size = sizeof(struct mtk_tx_dma_v2),
-+ .dma_max_len = MTK_TX_DMA_BUF_LEN_V2,
-+ .dma_len_offset = 8,
-+ },
-+ .rx = {
-+ .desc_size = sizeof(struct mtk_rx_dma_v2),
-+ .irq_done_mask = MTK_RX_DONE_INT_V2,
-+ .dma_l4_valid = RX_DMA_L4_VALID_V2,
- .dma_max_len = MTK_TX_DMA_BUF_LEN_V2,
- .dma_len_offset = 8,
- },
-@@ -5238,11 +5270,15 @@ static const struct mtk_soc_data rt5350_
- .required_clks = MT7628_CLKS_BITMAP,
- .required_pctl = false,
- .version = 1,
-- .txrx = {
-- .txd_size = sizeof(struct mtk_tx_dma),
-- .rxd_size = sizeof(struct mtk_rx_dma),
-- .rx_irq_done_mask = MTK_RX_DONE_INT,
-- .rx_dma_l4_valid = RX_DMA_L4_VALID_PDMA,
-+ .tx = {
-+ .desc_size = sizeof(struct mtk_tx_dma),
-+ .dma_max_len = MTK_TX_DMA_BUF_LEN,
-+ .dma_len_offset = 16,
-+ },
-+ .rx = {
-+ .desc_size = sizeof(struct mtk_rx_dma),
-+ .irq_done_mask = MTK_RX_DONE_INT,
-+ .dma_l4_valid = RX_DMA_L4_VALID_PDMA,
- .dma_max_len = MTK_TX_DMA_BUF_LEN,
- .dma_len_offset = 16,
- },
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-@@ -335,8 +335,8 @@
- /* QDMA descriptor txd3 */
- #define TX_DMA_OWNER_CPU BIT(31)
- #define TX_DMA_LS0 BIT(30)
--#define TX_DMA_PLEN0(x) (((x) & eth->soc->txrx.dma_max_len) << eth->soc->txrx.dma_len_offset)
--#define TX_DMA_PLEN1(x) ((x) & eth->soc->txrx.dma_max_len)
-+#define TX_DMA_PLEN0(x) (((x) & eth->soc->tx.dma_max_len) << eth->soc->tx.dma_len_offset)
-+#define TX_DMA_PLEN1(x) ((x) & eth->soc->tx.dma_max_len)
- #define TX_DMA_SWC BIT(14)
- #define TX_DMA_PQID GENMASK(3, 0)
- #define TX_DMA_ADDR64_MASK GENMASK(3, 0)
-@@ -356,8 +356,8 @@
- /* QDMA descriptor rxd2 */
- #define RX_DMA_DONE BIT(31)
- #define RX_DMA_LSO BIT(30)
--#define RX_DMA_PREP_PLEN0(x) (((x) & eth->soc->txrx.dma_max_len) << eth->soc->txrx.dma_len_offset)
--#define RX_DMA_GET_PLEN0(x) (((x) >> eth->soc->txrx.dma_len_offset) & eth->soc->txrx.dma_max_len)
-+#define RX_DMA_PREP_PLEN0(x) (((x) & eth->soc->rx.dma_max_len) << eth->soc->rx.dma_len_offset)
-+#define RX_DMA_GET_PLEN0(x) (((x) >> eth->soc->rx.dma_len_offset) & eth->soc->rx.dma_max_len)
- #define RX_DMA_VTAG BIT(15)
- #define RX_DMA_ADDR64_MASK GENMASK(3, 0)
- #if IS_ENABLED(CONFIG_64BIT)
-@@ -1161,10 +1161,9 @@ struct mtk_reg_map {
- * @foe_entry_size Foe table entry size.
- * @has_accounting Bool indicating support for accounting of
- * offloaded flows.
-- * @txd_size Tx DMA descriptor size.
-- * @rxd_size Rx DMA descriptor size.
-- * @rx_irq_done_mask Rx irq done register mask.
-- * @rx_dma_l4_valid Rx DMA valid register mask.
-+ * @desc_size Tx/Rx DMA descriptor size.
-+ * @irq_done_mask Rx irq done register mask.
-+ * @dma_l4_valid Rx DMA valid register mask.
- * @dma_max_len Max DMA tx/rx buffer length.
- * @dma_len_offset Tx/Rx DMA length field offset.
- */
-@@ -1182,13 +1181,17 @@ struct mtk_soc_data {
- bool has_accounting;
- bool disable_pll_modes;
- struct {
-- u32 txd_size;
-- u32 rxd_size;
-- u32 rx_irq_done_mask;
-- u32 rx_dma_l4_valid;
-+ u32 desc_size;
- u32 dma_max_len;
- u32 dma_len_offset;
-- } txrx;
-+ } tx;
-+ struct {
-+ u32 desc_size;
-+ u32 irq_done_mask;
-+ u32 dma_l4_valid;
-+ u32 dma_max_len;
-+ u32 dma_len_offset;
-+ } rx;
- };
-
- #define MTK_DMA_MONITOR_TIMEOUT msecs_to_jiffies(1000)
+++ /dev/null
-From 4d572e867bdb372bb4add39a0fa495c6a9c9a8da Mon Sep 17 00:00:00 2001
-Date: Wed, 8 May 2024 11:43:56 +0100
-Subject: [PATCH] net: ethernet: mediatek: use ADMAv1 instead of ADMAv2.0 on
- MT7981 and MT7986
-
-ADMAv2.0 is plagued by RX hangs which can't easily detected and happen upon
-receival of a corrupted Ethernet frame.
-
-Use ADMAv1 instead which is also still present and usable, and doesn't
-suffer from that problem.
-
-Fixes: 197c9e9b17b1 ("net: ethernet: mtk_eth_soc: introduce support for mt7986 chipset")
-Link: https://lore.kernel.org/r/57cef74bbd0c243366ad1ff4221e3f72f437ec80.1715164770.git.daniel@makrotopia.org
----
- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 46 ++++++++++-----------
- 1 file changed, 23 insertions(+), 23 deletions(-)
-
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -110,16 +110,16 @@ static const struct mtk_reg_map mt7986_r
- .tx_irq_mask = 0x461c,
- .tx_irq_status = 0x4618,
- .pdma = {
-- .rx_ptr = 0x6100,
-- .rx_cnt_cfg = 0x6104,
-- .pcrx_ptr = 0x6108,
-- .glo_cfg = 0x6204,
-- .rst_idx = 0x6208,
-- .delay_irq = 0x620c,
-- .irq_status = 0x6220,
-- .irq_mask = 0x6228,
-- .adma_rx_dbg0 = 0x6238,
-- .int_grp = 0x6250,
-+ .rx_ptr = 0x4100,
-+ .rx_cnt_cfg = 0x4104,
-+ .pcrx_ptr = 0x4108,
-+ .glo_cfg = 0x4204,
-+ .rst_idx = 0x4208,
-+ .delay_irq = 0x420c,
-+ .irq_status = 0x4220,
-+ .irq_mask = 0x4228,
-+ .adma_rx_dbg0 = 0x4238,
-+ .int_grp = 0x4250,
- },
- .qdma = {
- .qtx_cfg = 0x4400,
-@@ -1106,7 +1106,7 @@ static bool mtk_rx_get_desc(struct mtk_e
- rxd->rxd1 = READ_ONCE(dma_rxd->rxd1);
- rxd->rxd3 = READ_ONCE(dma_rxd->rxd3);
- rxd->rxd4 = READ_ONCE(dma_rxd->rxd4);
-- if (mtk_is_netsys_v2_or_greater(eth)) {
-+ if (mtk_is_netsys_v3_or_greater(eth)) {
- rxd->rxd5 = READ_ONCE(dma_rxd->rxd5);
- rxd->rxd6 = READ_ONCE(dma_rxd->rxd6);
- }
-@@ -2032,7 +2032,7 @@ static int mtk_poll_rx(struct napi_struc
- break;
-
- /* find out which mac the packet come from. values start at 1 */
-- if (mtk_is_netsys_v2_or_greater(eth)) {
-+ if (mtk_is_netsys_v3_or_greater(eth)) {
- u32 val = RX_DMA_GET_SPORT_V2(trxd.rxd5);
-
- switch (val) {
-@@ -2144,7 +2144,7 @@ static int mtk_poll_rx(struct napi_struc
- skb->dev = netdev;
- bytes += skb->len;
-
-- if (mtk_is_netsys_v2_or_greater(eth)) {
-+ if (mtk_is_netsys_v3_or_greater(eth)) {
- reason = FIELD_GET(MTK_RXD5_PPE_CPU_REASON, trxd.rxd5);
- hash = trxd.rxd5 & MTK_RXD5_FOE_ENTRY;
- if (hash != MTK_RXD5_FOE_ENTRY)
-@@ -2698,7 +2698,7 @@ static int mtk_rx_alloc(struct mtk_eth *
-
- rxd->rxd3 = 0;
- rxd->rxd4 = 0;
-- if (mtk_is_netsys_v2_or_greater(eth)) {
-+ if (mtk_is_netsys_v3_or_greater(eth)) {
- rxd->rxd5 = 0;
- rxd->rxd6 = 0;
- rxd->rxd7 = 0;
-@@ -3909,7 +3909,7 @@ static int mtk_hw_init(struct mtk_eth *e
- else
- mtk_hw_reset(eth);
-
-- if (mtk_is_netsys_v2_or_greater(eth)) {
-+ if (mtk_is_netsys_v3_or_greater(eth)) {
- /* Set FE to PDMAv2 if necessary */
- val = mtk_r32(eth, MTK_FE_GLO_MISC);
- mtk_w32(eth, val | BIT(4), MTK_FE_GLO_MISC);
-@@ -5203,11 +5203,11 @@ static const struct mtk_soc_data mt7981_
- .dma_len_offset = 8,
- },
- .rx = {
-- .desc_size = sizeof(struct mtk_rx_dma_v2),
-- .irq_done_mask = MTK_RX_DONE_INT_V2,
-+ .desc_size = sizeof(struct mtk_rx_dma),
-+ .irq_done_mask = MTK_RX_DONE_INT,
- .dma_l4_valid = RX_DMA_L4_VALID_V2,
-- .dma_max_len = MTK_TX_DMA_BUF_LEN_V2,
-- .dma_len_offset = 8,
-+ .dma_max_len = MTK_TX_DMA_BUF_LEN,
-+ .dma_len_offset = 16,
- },
- };
-
-@@ -5229,11 +5229,11 @@ static const struct mtk_soc_data mt7986_
- .dma_len_offset = 8,
- },
- .rx = {
-- .desc_size = sizeof(struct mtk_rx_dma_v2),
-- .irq_done_mask = MTK_RX_DONE_INT_V2,
-+ .desc_size = sizeof(struct mtk_rx_dma),
-+ .irq_done_mask = MTK_RX_DONE_INT,
- .dma_l4_valid = RX_DMA_L4_VALID_V2,
-- .dma_max_len = MTK_TX_DMA_BUF_LEN_V2,
-- .dma_len_offset = 8,
-+ .dma_max_len = MTK_TX_DMA_BUF_LEN,
-+ .dma_len_offset = 16,
- },
- };
-
+++ /dev/null
-Date: Tue, 12 Sep 2023 10:22:56 +0200
-Subject: [PATCH] net: ethernet: mtk_eth_soc: rely on mtk_pse_port definitions
- in mtk_flow_set_output_device
-
-Similar to ethernet ports, rely on mtk_pse_port definitions for
-pse wdma ports as well.
-
-Link: https://lore.kernel.org/r/b86bdb717e963e3246c1dec5f736c810703cf056.1694506814.git.lorenzo@kernel.org
----
-
---- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
-+++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
-@@ -200,10 +200,10 @@ mtk_flow_set_output_device(struct mtk_et
- if (mtk_is_netsys_v2_or_greater(eth)) {
- switch (info.wdma_idx) {
- case 0:
-- pse_port = 8;
-+ pse_port = PSE_WDMA0_PORT;
- break;
- case 1:
-- pse_port = 9;
-+ pse_port = PSE_WDMA1_PORT;
- break;
- default:
- return -EINVAL;
+++ /dev/null
-Date: Wed, 13 Sep 2023 20:42:47 +0200
-Subject: [PATCH] net: ethernet: mtk_wed: do not assume offload callbacks are
- always set
-
-Check if wlan.offload_enable and wlan.offload_disable callbacks are set
-in mtk_wed_flow_add/mtk_wed_flow_remove since mt7996 will not rely
-on them.
-
----
-
---- a/drivers/net/ethernet/mediatek/mtk_wed.c
-+++ b/drivers/net/ethernet/mediatek/mtk_wed.c
-@@ -1709,19 +1709,20 @@ mtk_wed_irq_set_mask(struct mtk_wed_devi
- int mtk_wed_flow_add(int index)
- {
- struct mtk_wed_hw *hw = hw_list[index];
-- int ret;
-+ int ret = 0;
-
-- if (!hw || !hw->wed_dev)
-- return -ENODEV;
-+ mutex_lock(&hw_lock);
-
-- if (hw->num_flows) {
-- hw->num_flows++;
-- return 0;
-+ if (!hw || !hw->wed_dev) {
-+ ret = -ENODEV;
-+ goto out;
- }
-
-- mutex_lock(&hw_lock);
-- if (!hw->wed_dev) {
-- ret = -ENODEV;
-+ if (!hw->wed_dev->wlan.offload_enable)
-+ goto out;
-+
-+ if (hw->num_flows) {
-+ hw->num_flows++;
- goto out;
- }
-
-@@ -1740,14 +1741,15 @@ void mtk_wed_flow_remove(int index)
- {
- struct mtk_wed_hw *hw = hw_list[index];
-
-- if (!hw)
-- return;
-+ mutex_lock(&hw_lock);
-
-- if (--hw->num_flows)
-- return;
-+ if (!hw || !hw->wed_dev)
-+ goto out;
-
-- mutex_lock(&hw_lock);
-- if (!hw->wed_dev)
-+ if (!hw->wed_dev->wlan.offload_disable)
-+ goto out;
-+
-+ if (--hw->num_flows)
- goto out;
-
- hw->wed_dev->wlan.offload_disable(hw->wed_dev);
+++ /dev/null
-Date: Mon, 18 Sep 2023 12:29:05 +0200
-Subject: [PATCH] net: ethernet: mtk_wed: introduce versioning utility routines
-
-Similar to mtk_eth_soc, introduce the following wed versioning
-utility routines:
-- mtk_wed_is_v1
-- mtk_wed_is_v2
-
-This is a preliminary patch to introduce WED support for MT7988 SoC
-
----
-
---- a/drivers/net/ethernet/mediatek/mtk_wed.c
-+++ b/drivers/net/ethernet/mediatek/mtk_wed.c
-@@ -278,7 +278,7 @@ mtk_wed_assign(struct mtk_wed_device *de
- if (!hw->wed_dev)
- goto out;
-
-- if (hw->version == 1)
-+ if (mtk_wed_is_v1(hw))
- return NULL;
-
- /* MT7986 WED devices do not have any pcie slot restrictions */
-@@ -359,7 +359,7 @@ mtk_wed_tx_buffer_alloc(struct mtk_wed_d
- desc->buf0 = cpu_to_le32(buf_phys);
- desc->buf1 = cpu_to_le32(buf_phys + txd_size);
-
-- if (dev->hw->version == 1)
-+ if (mtk_wed_is_v1(dev->hw))
- ctrl = FIELD_PREP(MTK_WDMA_DESC_CTRL_LEN0, txd_size) |
- FIELD_PREP(MTK_WDMA_DESC_CTRL_LEN1,
- MTK_WED_BUF_SIZE - txd_size) |
-@@ -498,7 +498,7 @@ mtk_wed_set_ext_int(struct mtk_wed_devic
- {
- u32 mask = MTK_WED_EXT_INT_STATUS_ERROR_MASK;
-
-- if (dev->hw->version == 1)
-+ if (mtk_wed_is_v1(dev->hw))
- mask |= MTK_WED_EXT_INT_STATUS_TX_DRV_R_RESP_ERR;
- else
- mask |= MTK_WED_EXT_INT_STATUS_RX_FBUF_LO_TH |
-@@ -577,7 +577,7 @@ mtk_wed_dma_disable(struct mtk_wed_devic
- MTK_WDMA_GLO_CFG_RX_INFO1_PRERES |
- MTK_WDMA_GLO_CFG_RX_INFO2_PRERES);
-
-- if (dev->hw->version == 1) {
-+ if (mtk_wed_is_v1(dev->hw)) {
- regmap_write(dev->hw->mirror, dev->hw->index * 4, 0);
- wdma_clr(dev, MTK_WDMA_GLO_CFG,
- MTK_WDMA_GLO_CFG_RX_INFO3_PRERES);
-@@ -606,7 +606,7 @@ mtk_wed_stop(struct mtk_wed_device *dev)
- wdma_w32(dev, MTK_WDMA_INT_MASK, 0);
- wdma_w32(dev, MTK_WDMA_INT_GRP2, 0);
-
-- if (dev->hw->version == 1)
-+ if (mtk_wed_is_v1(dev->hw))
- return;
-
- wed_w32(dev, MTK_WED_EXT_INT_MASK1, 0);
-@@ -624,7 +624,7 @@ mtk_wed_deinit(struct mtk_wed_device *de
- MTK_WED_CTRL_WED_TX_BM_EN |
- MTK_WED_CTRL_WED_TX_FREE_AGENT_EN);
-
-- if (dev->hw->version == 1)
-+ if (mtk_wed_is_v1(dev->hw))
- return;
-
- wed_clr(dev, MTK_WED_CTRL,
-@@ -730,7 +730,7 @@ mtk_wed_bus_init(struct mtk_wed_device *
- static void
- mtk_wed_set_wpdma(struct mtk_wed_device *dev)
- {
-- if (dev->hw->version == 1) {
-+ if (mtk_wed_is_v1(dev->hw)) {
- wed_w32(dev, MTK_WED_WPDMA_CFG_BASE, dev->wlan.wpdma_phys);
- } else {
- mtk_wed_bus_init(dev);
-@@ -761,7 +761,7 @@ mtk_wed_hw_init_early(struct mtk_wed_dev
- MTK_WED_WDMA_GLO_CFG_IDLE_DMAD_SUPPLY;
- wed_m32(dev, MTK_WED_WDMA_GLO_CFG, mask, set);
-
-- if (dev->hw->version == 1) {
-+ if (mtk_wed_is_v1(dev->hw)) {
- u32 offset = dev->hw->index ? 0x04000400 : 0;
-
- wdma_set(dev, MTK_WDMA_GLO_CFG,
-@@ -934,7 +934,7 @@ mtk_wed_hw_init(struct mtk_wed_device *d
-
- wed_w32(dev, MTK_WED_TX_BM_BUF_LEN, MTK_WED_PKT_SIZE);
-
-- if (dev->hw->version == 1) {
-+ if (mtk_wed_is_v1(dev->hw)) {
- wed_w32(dev, MTK_WED_TX_BM_TKID,
- FIELD_PREP(MTK_WED_TX_BM_TKID_START,
- dev->wlan.token_start) |
-@@ -967,7 +967,7 @@ mtk_wed_hw_init(struct mtk_wed_device *d
-
- mtk_wed_reset(dev, MTK_WED_RESET_TX_BM);
-
-- if (dev->hw->version == 1) {
-+ if (mtk_wed_is_v1(dev->hw)) {
- wed_set(dev, MTK_WED_CTRL,
- MTK_WED_CTRL_WED_TX_BM_EN |
- MTK_WED_CTRL_WED_TX_FREE_AGENT_EN);
-@@ -1217,7 +1217,7 @@ mtk_wed_reset_dma(struct mtk_wed_device
- }
-
- dev->init_done = false;
-- if (dev->hw->version == 1)
-+ if (mtk_wed_is_v1(dev->hw))
- return;
-
- if (!busy) {
-@@ -1343,7 +1343,7 @@ mtk_wed_configure_irq(struct mtk_wed_dev
- MTK_WED_CTRL_WED_TX_BM_EN |
- MTK_WED_CTRL_WED_TX_FREE_AGENT_EN);
-
-- if (dev->hw->version == 1) {
-+ if (mtk_wed_is_v1(dev->hw)) {
- wed_w32(dev, MTK_WED_PCIE_INT_TRIGGER,
- MTK_WED_PCIE_INT_TRIGGER_STATUS);
-
-@@ -1416,7 +1416,7 @@ mtk_wed_dma_enable(struct mtk_wed_device
- MTK_WDMA_GLO_CFG_RX_INFO1_PRERES |
- MTK_WDMA_GLO_CFG_RX_INFO2_PRERES);
-
-- if (dev->hw->version == 1) {
-+ if (mtk_wed_is_v1(dev->hw)) {
- wdma_set(dev, MTK_WDMA_GLO_CFG,
- MTK_WDMA_GLO_CFG_RX_INFO3_PRERES);
- } else {
-@@ -1465,7 +1465,7 @@ mtk_wed_start(struct mtk_wed_device *dev
-
- mtk_wed_set_ext_int(dev, true);
-
-- if (dev->hw->version == 1) {
-+ if (mtk_wed_is_v1(dev->hw)) {
- u32 val = dev->wlan.wpdma_phys | MTK_PCIE_MIRROR_MAP_EN |
- FIELD_PREP(MTK_PCIE_MIRROR_MAP_WED_ID,
- dev->hw->index);
-@@ -1550,7 +1550,7 @@ mtk_wed_attach(struct mtk_wed_device *de
- }
-
- mtk_wed_hw_init_early(dev);
-- if (hw->version == 1) {
-+ if (mtk_wed_is_v1(hw)) {
- regmap_update_bits(hw->hifsys, HIFSYS_DMA_AG_MAP,
- BIT(hw->index), 0);
- } else {
-@@ -1618,7 +1618,7 @@ static int
- mtk_wed_txfree_ring_setup(struct mtk_wed_device *dev, void __iomem *regs)
- {
- struct mtk_wed_ring *ring = &dev->txfree_ring;
-- int i, index = dev->hw->version == 1;
-+ int i, index = mtk_wed_is_v1(dev->hw);
-
- /*
- * For txfree event handling, the same DMA ring is shared between WED
-@@ -1676,7 +1676,7 @@ mtk_wed_irq_get(struct mtk_wed_device *d
- {
- u32 val, ext_mask = MTK_WED_EXT_INT_STATUS_ERROR_MASK;
-
-- if (dev->hw->version == 1)
-+ if (mtk_wed_is_v1(dev->hw))
- ext_mask |= MTK_WED_EXT_INT_STATUS_TX_DRV_R_RESP_ERR;
- else
- ext_mask |= MTK_WED_EXT_INT_STATUS_RX_FBUF_LO_TH |
-@@ -1842,7 +1842,7 @@ mtk_wed_setup_tc(struct mtk_wed_device *
- {
- struct mtk_wed_hw *hw = wed->hw;
-
-- if (hw->version < 2)
-+ if (mtk_wed_is_v1(hw))
- return -EOPNOTSUPP;
-
- switch (type) {
-@@ -1915,9 +1915,9 @@ void mtk_wed_add_hw(struct device_node *
- hw->wdma = wdma;
- hw->index = index;
- hw->irq = irq;
-- hw->version = mtk_is_netsys_v1(eth) ? 1 : 2;
-+ hw->version = eth->soc->version;
-
-- if (hw->version == 1) {
-+ if (mtk_wed_is_v1(hw)) {
- hw->mirror = syscon_regmap_lookup_by_phandle(eth_np,
- "mediatek,pcie-mirror");
- hw->hifsys = syscon_regmap_lookup_by_phandle(eth_np,
---- a/drivers/net/ethernet/mediatek/mtk_wed.h
-+++ b/drivers/net/ethernet/mediatek/mtk_wed.h
-@@ -40,6 +40,16 @@ struct mtk_wdma_info {
- };
-
- #ifdef CONFIG_NET_MEDIATEK_SOC_WED
-+static inline bool mtk_wed_is_v1(struct mtk_wed_hw *hw)
-+{
-+ return hw->version == 1;
-+}
-+
-+static inline bool mtk_wed_is_v2(struct mtk_wed_hw *hw)
-+{
-+ return hw->version == 2;
-+}
-+
- static inline void
- wed_w32(struct mtk_wed_device *dev, u32 reg, u32 val)
- {
---- a/drivers/net/ethernet/mediatek/mtk_wed_debugfs.c
-+++ b/drivers/net/ethernet/mediatek/mtk_wed_debugfs.c
-@@ -261,7 +261,7 @@ void mtk_wed_hw_add_debugfs(struct mtk_w
- debugfs_create_u32("regidx", 0600, dir, &hw->debugfs_reg);
- debugfs_create_file_unsafe("regval", 0600, dir, hw, &fops_regval);
- debugfs_create_file_unsafe("txinfo", 0400, dir, hw, &wed_txinfo_fops);
-- if (hw->version != 1)
-+ if (!mtk_wed_is_v1(hw))
- debugfs_create_file_unsafe("rxinfo", 0400, dir, hw,
- &wed_rxinfo_fops);
- }
---- a/drivers/net/ethernet/mediatek/mtk_wed_mcu.c
-+++ b/drivers/net/ethernet/mediatek/mtk_wed_mcu.c
-@@ -207,7 +207,7 @@ int mtk_wed_mcu_msg_update(struct mtk_we
- {
- struct mtk_wed_wo *wo = dev->hw->wed_wo;
-
-- if (dev->hw->version == 1)
-+ if (mtk_wed_is_v1(dev->hw))
- return 0;
-
- if (WARN_ON(!wo))
+++ /dev/null
-Date: Mon, 18 Sep 2023 12:29:06 +0200
-Subject: [PATCH] net: ethernet: mtk_wed: do not configure rx offload if not
- supported
-
-Check if rx offload is supported running mtk_wed_get_rx_capa routine
-before configuring it. This is a preliminary patch to introduce Wireless
-Ethernet Dispatcher (WED) support for MT7988 SoC.
-
----
-
---- a/drivers/net/ethernet/mediatek/mtk_wed.c
-+++ b/drivers/net/ethernet/mediatek/mtk_wed.c
-@@ -606,7 +606,7 @@ mtk_wed_stop(struct mtk_wed_device *dev)
- wdma_w32(dev, MTK_WDMA_INT_MASK, 0);
- wdma_w32(dev, MTK_WDMA_INT_GRP2, 0);
-
-- if (mtk_wed_is_v1(dev->hw))
-+ if (!mtk_wed_get_rx_capa(dev))
- return;
-
- wed_w32(dev, MTK_WED_EXT_INT_MASK1, 0);
-@@ -732,16 +732,21 @@ mtk_wed_set_wpdma(struct mtk_wed_device
- {
- if (mtk_wed_is_v1(dev->hw)) {
- wed_w32(dev, MTK_WED_WPDMA_CFG_BASE, dev->wlan.wpdma_phys);
-- } else {
-- mtk_wed_bus_init(dev);
--
-- wed_w32(dev, MTK_WED_WPDMA_CFG_BASE, dev->wlan.wpdma_int);
-- wed_w32(dev, MTK_WED_WPDMA_CFG_INT_MASK, dev->wlan.wpdma_mask);
-- wed_w32(dev, MTK_WED_WPDMA_CFG_TX, dev->wlan.wpdma_tx);
-- wed_w32(dev, MTK_WED_WPDMA_CFG_TX_FREE, dev->wlan.wpdma_txfree);
-- wed_w32(dev, MTK_WED_WPDMA_RX_GLO_CFG, dev->wlan.wpdma_rx_glo);
-- wed_w32(dev, MTK_WED_WPDMA_RX_RING, dev->wlan.wpdma_rx);
-+ return;
- }
-+
-+ mtk_wed_bus_init(dev);
-+
-+ wed_w32(dev, MTK_WED_WPDMA_CFG_BASE, dev->wlan.wpdma_int);
-+ wed_w32(dev, MTK_WED_WPDMA_CFG_INT_MASK, dev->wlan.wpdma_mask);
-+ wed_w32(dev, MTK_WED_WPDMA_CFG_TX, dev->wlan.wpdma_tx);
-+ wed_w32(dev, MTK_WED_WPDMA_CFG_TX_FREE, dev->wlan.wpdma_txfree);
-+
-+ if (!mtk_wed_get_rx_capa(dev))
-+ return;
-+
-+ wed_w32(dev, MTK_WED_WPDMA_RX_GLO_CFG, dev->wlan.wpdma_rx_glo);
-+ wed_w32(dev, MTK_WED_WPDMA_RX_RING, dev->wlan.wpdma_rx);
- }
-
- static void
-@@ -973,15 +978,17 @@ mtk_wed_hw_init(struct mtk_wed_device *d
- MTK_WED_CTRL_WED_TX_FREE_AGENT_EN);
- } else {
- wed_clr(dev, MTK_WED_TX_TKID_CTRL, MTK_WED_TX_TKID_CTRL_PAUSE);
-- /* rx hw init */
-- wed_w32(dev, MTK_WED_WPDMA_RX_D_RST_IDX,
-- MTK_WED_WPDMA_RX_D_RST_CRX_IDX |
-- MTK_WED_WPDMA_RX_D_RST_DRV_IDX);
-- wed_w32(dev, MTK_WED_WPDMA_RX_D_RST_IDX, 0);
--
-- mtk_wed_rx_buffer_hw_init(dev);
-- mtk_wed_rro_hw_init(dev);
-- mtk_wed_route_qm_hw_init(dev);
-+ if (mtk_wed_get_rx_capa(dev)) {
-+ /* rx hw init */
-+ wed_w32(dev, MTK_WED_WPDMA_RX_D_RST_IDX,
-+ MTK_WED_WPDMA_RX_D_RST_CRX_IDX |
-+ MTK_WED_WPDMA_RX_D_RST_DRV_IDX);
-+ wed_w32(dev, MTK_WED_WPDMA_RX_D_RST_IDX, 0);
-+
-+ mtk_wed_rx_buffer_hw_init(dev);
-+ mtk_wed_rro_hw_init(dev);
-+ mtk_wed_route_qm_hw_init(dev);
-+ }
- }
-
- wed_clr(dev, MTK_WED_TX_BM_CTRL, MTK_WED_TX_BM_CTRL_PAUSE);
-@@ -1353,8 +1360,6 @@ mtk_wed_configure_irq(struct mtk_wed_dev
-
- wed_clr(dev, MTK_WED_WDMA_INT_CTRL, wdma_mask);
- } else {
-- wdma_mask |= FIELD_PREP(MTK_WDMA_INT_MASK_TX_DONE,
-- GENMASK(1, 0));
- /* initail tx interrupt trigger */
- wed_w32(dev, MTK_WED_WPDMA_INT_CTRL_TX,
- MTK_WED_WPDMA_INT_CTRL_TX0_DONE_EN |
-@@ -1373,15 +1378,20 @@ mtk_wed_configure_irq(struct mtk_wed_dev
- FIELD_PREP(MTK_WED_WPDMA_INT_CTRL_TX_FREE_DONE_TRIG,
- dev->wlan.txfree_tbit));
-
-- wed_w32(dev, MTK_WED_WPDMA_INT_CTRL_RX,
-- MTK_WED_WPDMA_INT_CTRL_RX0_EN |
-- MTK_WED_WPDMA_INT_CTRL_RX0_CLR |
-- MTK_WED_WPDMA_INT_CTRL_RX1_EN |
-- MTK_WED_WPDMA_INT_CTRL_RX1_CLR |
-- FIELD_PREP(MTK_WED_WPDMA_INT_CTRL_RX0_DONE_TRIG,
-- dev->wlan.rx_tbit[0]) |
-- FIELD_PREP(MTK_WED_WPDMA_INT_CTRL_RX1_DONE_TRIG,
-- dev->wlan.rx_tbit[1]));
-+ if (mtk_wed_get_rx_capa(dev)) {
-+ wed_w32(dev, MTK_WED_WPDMA_INT_CTRL_RX,
-+ MTK_WED_WPDMA_INT_CTRL_RX0_EN |
-+ MTK_WED_WPDMA_INT_CTRL_RX0_CLR |
-+ MTK_WED_WPDMA_INT_CTRL_RX1_EN |
-+ MTK_WED_WPDMA_INT_CTRL_RX1_CLR |
-+ FIELD_PREP(MTK_WED_WPDMA_INT_CTRL_RX0_DONE_TRIG,
-+ dev->wlan.rx_tbit[0]) |
-+ FIELD_PREP(MTK_WED_WPDMA_INT_CTRL_RX1_DONE_TRIG,
-+ dev->wlan.rx_tbit[1]));
-+
-+ wdma_mask |= FIELD_PREP(MTK_WDMA_INT_MASK_TX_DONE,
-+ GENMASK(1, 0));
-+ }
-
- wed_w32(dev, MTK_WED_WDMA_INT_CLR, wdma_mask);
- wed_set(dev, MTK_WED_WDMA_INT_CTRL,
-@@ -1400,6 +1410,8 @@ mtk_wed_configure_irq(struct mtk_wed_dev
- static void
- mtk_wed_dma_enable(struct mtk_wed_device *dev)
- {
-+ int i;
-+
- wed_set(dev, MTK_WED_WPDMA_INT_CTRL, MTK_WED_WPDMA_INT_CTRL_SUBRT_ADV);
-
- wed_set(dev, MTK_WED_GLO_CFG,
-@@ -1419,33 +1431,33 @@ mtk_wed_dma_enable(struct mtk_wed_device
- if (mtk_wed_is_v1(dev->hw)) {
- wdma_set(dev, MTK_WDMA_GLO_CFG,
- MTK_WDMA_GLO_CFG_RX_INFO3_PRERES);
-- } else {
-- int i;
-+ return;
-+ }
-
-- wed_set(dev, MTK_WED_WPDMA_CTRL,
-- MTK_WED_WPDMA_CTRL_SDL1_FIXED);
-+ wed_set(dev, MTK_WED_WPDMA_CTRL,
-+ MTK_WED_WPDMA_CTRL_SDL1_FIXED);
-+ wed_set(dev, MTK_WED_WPDMA_GLO_CFG,
-+ MTK_WED_WPDMA_GLO_CFG_RX_DRV_R0_PKT_PROC |
-+ MTK_WED_WPDMA_GLO_CFG_RX_DRV_R0_CRX_SYNC);
-+ wed_clr(dev, MTK_WED_WPDMA_GLO_CFG,
-+ MTK_WED_WPDMA_GLO_CFG_TX_TKID_KEEP |
-+ MTK_WED_WPDMA_GLO_CFG_TX_DMAD_DW3_PREV);
-
-- wed_set(dev, MTK_WED_WDMA_GLO_CFG,
-- MTK_WED_WDMA_GLO_CFG_TX_DRV_EN |
-- MTK_WED_WDMA_GLO_CFG_TX_DDONE_CHK);
-+ if (!mtk_wed_get_rx_capa(dev))
-+ return;
-
-- wed_set(dev, MTK_WED_WPDMA_GLO_CFG,
-- MTK_WED_WPDMA_GLO_CFG_RX_DRV_R0_PKT_PROC |
-- MTK_WED_WPDMA_GLO_CFG_RX_DRV_R0_CRX_SYNC);
--
-- wed_clr(dev, MTK_WED_WPDMA_GLO_CFG,
-- MTK_WED_WPDMA_GLO_CFG_TX_TKID_KEEP |
-- MTK_WED_WPDMA_GLO_CFG_TX_DMAD_DW3_PREV);
-+ wed_set(dev, MTK_WED_WDMA_GLO_CFG,
-+ MTK_WED_WDMA_GLO_CFG_TX_DRV_EN |
-+ MTK_WED_WDMA_GLO_CFG_TX_DDONE_CHK);
-
-- wed_set(dev, MTK_WED_WPDMA_RX_D_GLO_CFG,
-- MTK_WED_WPDMA_RX_D_RX_DRV_EN |
-- FIELD_PREP(MTK_WED_WPDMA_RX_D_RXD_READ_LEN, 0x18) |
-- FIELD_PREP(MTK_WED_WPDMA_RX_D_INIT_PHASE_RXEN_SEL,
-- 0x2));
-+ wed_set(dev, MTK_WED_WPDMA_RX_D_GLO_CFG,
-+ MTK_WED_WPDMA_RX_D_RX_DRV_EN |
-+ FIELD_PREP(MTK_WED_WPDMA_RX_D_RXD_READ_LEN, 0x18) |
-+ FIELD_PREP(MTK_WED_WPDMA_RX_D_INIT_PHASE_RXEN_SEL,
-+ 0x2));
-
-- for (i = 0; i < MTK_WED_RX_QUEUES; i++)
-- mtk_wed_check_wfdma_rx_fill(dev, i);
-- }
-+ for (i = 0; i < MTK_WED_RX_QUEUES; i++)
-+ mtk_wed_check_wfdma_rx_fill(dev, i);
- }
-
- static void
-@@ -1472,7 +1484,7 @@ mtk_wed_start(struct mtk_wed_device *dev
-
- val |= BIT(0) | (BIT(1) * !!dev->hw->index);
- regmap_write(dev->hw->mirror, dev->hw->index * 4, val);
-- } else {
-+ } else if (mtk_wed_get_rx_capa(dev)) {
- /* driver set mid ready and only once */
- wed_w32(dev, MTK_WED_EXT_INT_MASK1,
- MTK_WED_EXT_INT_STATUS_WPDMA_MID_RDY);
-@@ -1484,7 +1496,6 @@ mtk_wed_start(struct mtk_wed_device *dev
-
- if (mtk_wed_rro_cfg(dev))
- return;
--
- }
-
- mtk_wed_set_512_support(dev, dev->wlan.wcid_512);
-@@ -1550,13 +1561,14 @@ mtk_wed_attach(struct mtk_wed_device *de
- }
-
- mtk_wed_hw_init_early(dev);
-- if (mtk_wed_is_v1(hw)) {
-+ if (mtk_wed_is_v1(hw))
- regmap_update_bits(hw->hifsys, HIFSYS_DMA_AG_MAP,
- BIT(hw->index), 0);
-- } else {
-+ else
- dev->rev_id = wed_r32(dev, MTK_WED_REV_ID);
-+
-+ if (mtk_wed_get_rx_capa(dev))
- ret = mtk_wed_wo_init(hw);
-- }
- out:
- if (ret) {
- dev_err(dev->hw->dev, "failed to attach wed device\n");
---- a/drivers/net/ethernet/mediatek/mtk_wed_mcu.c
-+++ b/drivers/net/ethernet/mediatek/mtk_wed_mcu.c
-@@ -207,7 +207,7 @@ int mtk_wed_mcu_msg_update(struct mtk_we
- {
- struct mtk_wed_wo *wo = dev->hw->wed_wo;
-
-- if (mtk_wed_is_v1(dev->hw))
-+ if (!mtk_wed_get_rx_capa(dev))
- return 0;
-
- if (WARN_ON(!wo))
+++ /dev/null
-Date: Mon, 18 Sep 2023 12:29:07 +0200
-Subject: [PATCH] net: ethernet: mtk_wed: rename mtk_rxbm_desc in
- mtk_wed_bm_desc
-
-Rename mtk_rxbm_desc structure in mtk_wed_bm_desc since it will be used
-even on tx side by MT7988 SoC.
-
----
-
---- a/drivers/net/ethernet/mediatek/mtk_wed.c
-+++ b/drivers/net/ethernet/mediatek/mtk_wed.c
-@@ -422,7 +422,7 @@ free_pagelist:
- static int
- mtk_wed_rx_buffer_alloc(struct mtk_wed_device *dev)
- {
-- struct mtk_rxbm_desc *desc;
-+ struct mtk_wed_bm_desc *desc;
- dma_addr_t desc_phys;
-
- dev->rx_buf_ring.size = dev->wlan.rx_nbuf;
-@@ -442,7 +442,7 @@ mtk_wed_rx_buffer_alloc(struct mtk_wed_d
- static void
- mtk_wed_free_rx_buffer(struct mtk_wed_device *dev)
- {
-- struct mtk_rxbm_desc *desc = dev->rx_buf_ring.desc;
-+ struct mtk_wed_bm_desc *desc = dev->rx_buf_ring.desc;
-
- if (!desc)
- return;
---- a/include/linux/soc/mediatek/mtk_wed.h
-+++ b/include/linux/soc/mediatek/mtk_wed.h
-@@ -45,7 +45,7 @@ enum mtk_wed_wo_cmd {
- MTK_WED_WO_CMD_WED_END
- };
-
--struct mtk_rxbm_desc {
-+struct mtk_wed_bm_desc {
- __le32 buf0;
- __le32 token;
- } __packed __aligned(4);
-@@ -104,7 +104,7 @@ struct mtk_wed_device {
-
- struct {
- int size;
-- struct mtk_rxbm_desc *desc;
-+ struct mtk_wed_bm_desc *desc;
- dma_addr_t desc_phys;
- } rx_buf_ring;
-
+++ /dev/null
-Date: Mon, 18 Sep 2023 12:29:08 +0200
-Subject: [PATCH] net: ethernet: mtk_wed: introduce mtk_wed_buf structure
-
-Introduce mtk_wed_buf structure to store both virtual and physical
-addresses allocated in mtk_wed_tx_buffer_alloc() routine. This is a
-preliminary patch to add WED support for MT7988 SoC since it relies on a
-different dma descriptor layout not storing page dma addresses.
-
----
-
---- a/drivers/net/ethernet/mediatek/mtk_wed.c
-+++ b/drivers/net/ethernet/mediatek/mtk_wed.c
-@@ -300,9 +300,9 @@ out:
- static int
- mtk_wed_tx_buffer_alloc(struct mtk_wed_device *dev)
- {
-+ struct mtk_wed_buf *page_list;
- struct mtk_wdma_desc *desc;
- dma_addr_t desc_phys;
-- void **page_list;
- int token = dev->wlan.token_start;
- int ring_size;
- int n_pages;
-@@ -343,7 +343,8 @@ mtk_wed_tx_buffer_alloc(struct mtk_wed_d
- return -ENOMEM;
- }
-
-- page_list[page_idx++] = page;
-+ page_list[page_idx].p = page;
-+ page_list[page_idx++].phy_addr = page_phys;
- dma_sync_single_for_cpu(dev->hw->dev, page_phys, PAGE_SIZE,
- DMA_BIDIRECTIONAL);
-
-@@ -387,8 +388,8 @@ mtk_wed_tx_buffer_alloc(struct mtk_wed_d
- static void
- mtk_wed_free_tx_buffer(struct mtk_wed_device *dev)
- {
-+ struct mtk_wed_buf *page_list = dev->tx_buf_ring.pages;
- struct mtk_wdma_desc *desc = dev->tx_buf_ring.desc;
-- void **page_list = dev->tx_buf_ring.pages;
- int page_idx;
- int i;
-
-@@ -400,13 +401,12 @@ mtk_wed_free_tx_buffer(struct mtk_wed_de
-
- for (i = 0, page_idx = 0; i < dev->tx_buf_ring.size;
- i += MTK_WED_BUF_PER_PAGE) {
-- void *page = page_list[page_idx++];
-- dma_addr_t buf_addr;
-+ dma_addr_t buf_addr = page_list[page_idx].phy_addr;
-+ void *page = page_list[page_idx++].p;
-
- if (!page)
- break;
-
-- buf_addr = le32_to_cpu(desc[i].buf0);
- dma_unmap_page(dev->hw->dev, buf_addr, PAGE_SIZE,
- DMA_BIDIRECTIONAL);
- __free_page(page);
---- a/include/linux/soc/mediatek/mtk_wed.h
-+++ b/include/linux/soc/mediatek/mtk_wed.h
-@@ -76,6 +76,11 @@ struct mtk_wed_wo_rx_stats {
- __le32 rx_drop_cnt;
- };
-
-+struct mtk_wed_buf {
-+ void *p;
-+ dma_addr_t phy_addr;
-+};
-+
- struct mtk_wed_device {
- #ifdef CONFIG_NET_MEDIATEK_SOC_WED
- const struct mtk_wed_ops *ops;
-@@ -97,7 +102,7 @@ struct mtk_wed_device {
-
- struct {
- int size;
-- void **pages;
-+ struct mtk_wed_buf *pages;
- struct mtk_wdma_desc *desc;
- dma_addr_t desc_phys;
- } tx_buf_ring;
+++ /dev/null
-Date: Mon, 18 Sep 2023 12:29:09 +0200
-Subject: [PATCH] net: ethernet: mtk_wed: move mem_region array out of
- mtk_wed_mcu_load_firmware
-
-Remove mtk_wed_wo_memory_region boot structure in mtk_wed_wo.
-This is a preliminary patch to introduce WED support for MT7988 SoC.
-
----
-
---- a/drivers/net/ethernet/mediatek/mtk_wed_mcu.c
-+++ b/drivers/net/ethernet/mediatek/mtk_wed_mcu.c
-@@ -16,14 +16,30 @@
- #include "mtk_wed_wo.h"
- #include "mtk_wed.h"
-
-+static struct mtk_wed_wo_memory_region mem_region[] = {
-+ [MTK_WED_WO_REGION_EMI] = {
-+ .name = "wo-emi",
-+ },
-+ [MTK_WED_WO_REGION_ILM] = {
-+ .name = "wo-ilm",
-+ },
-+ [MTK_WED_WO_REGION_DATA] = {
-+ .name = "wo-data",
-+ .shared = true,
-+ },
-+ [MTK_WED_WO_REGION_BOOT] = {
-+ .name = "wo-boot",
-+ },
-+};
-+
- static u32 wo_r32(struct mtk_wed_wo *wo, u32 reg)
- {
-- return readl(wo->boot.addr + reg);
-+ return readl(mem_region[MTK_WED_WO_REGION_BOOT].addr + reg);
- }
-
- static void wo_w32(struct mtk_wed_wo *wo, u32 reg, u32 val)
- {
-- writel(val, wo->boot.addr + reg);
-+ writel(val, mem_region[MTK_WED_WO_REGION_BOOT].addr + reg);
- }
-
- static struct sk_buff *
-@@ -294,18 +310,6 @@ next:
- static int
- mtk_wed_mcu_load_firmware(struct mtk_wed_wo *wo)
- {
-- static struct mtk_wed_wo_memory_region mem_region[] = {
-- [MTK_WED_WO_REGION_EMI] = {
-- .name = "wo-emi",
-- },
-- [MTK_WED_WO_REGION_ILM] = {
-- .name = "wo-ilm",
-- },
-- [MTK_WED_WO_REGION_DATA] = {
-- .name = "wo-data",
-- .shared = true,
-- },
-- };
- const struct mtk_wed_fw_trailer *trailer;
- const struct firmware *fw;
- const char *fw_name;
-@@ -319,11 +323,6 @@ mtk_wed_mcu_load_firmware(struct mtk_wed
- return ret;
- }
-
-- wo->boot.name = "wo-boot";
-- ret = mtk_wed_get_memory_region(wo, &wo->boot);
-- if (ret)
-- return ret;
--
- /* set dummy cr */
- wed_w32(wo->hw->wed_dev, MTK_WED_SCR0 + 4 * MTK_WED_DUMMY_CR_FWDL,
- wo->hw->index + 1);
---- a/drivers/net/ethernet/mediatek/mtk_wed_wo.h
-+++ b/drivers/net/ethernet/mediatek/mtk_wed_wo.h
-@@ -228,7 +228,6 @@ struct mtk_wed_wo_queue {
-
- struct mtk_wed_wo {
- struct mtk_wed_hw *hw;
-- struct mtk_wed_wo_memory_region boot;
-
- struct mtk_wed_wo_queue q_tx;
- struct mtk_wed_wo_queue q_rx;
+++ /dev/null
-Date: Mon, 18 Sep 2023 12:29:10 +0200
-Subject: [PATCH] net: ethernet: mtk_wed: make memory region optional
-
-Make mtk_wed_wo_memory_region optionals.
-This is a preliminary patch to introduce Wireless Ethernet Dispatcher
-support for MT7988 SoC since MT7988 WED fw image will have a different
-layout.
-
----
-
---- a/drivers/net/ethernet/mediatek/mtk_wed_mcu.c
-+++ b/drivers/net/ethernet/mediatek/mtk_wed_mcu.c
-@@ -234,19 +234,13 @@ int mtk_wed_mcu_msg_update(struct mtk_we
- }
-
- static int
--mtk_wed_get_memory_region(struct mtk_wed_wo *wo,
-+mtk_wed_get_memory_region(struct mtk_wed_hw *hw, int index,
- struct mtk_wed_wo_memory_region *region)
- {
- struct reserved_mem *rmem;
- struct device_node *np;
-- int index;
-
-- index = of_property_match_string(wo->hw->node, "memory-region-names",
-- region->name);
-- if (index < 0)
-- return index;
--
-- np = of_parse_phandle(wo->hw->node, "memory-region", index);
-+ np = of_parse_phandle(hw->node, "memory-region", index);
- if (!np)
- return -ENODEV;
-
-@@ -258,7 +252,7 @@ mtk_wed_get_memory_region(struct mtk_wed
-
- region->phy_addr = rmem->base;
- region->size = rmem->size;
-- region->addr = devm_ioremap(wo->hw->dev, region->phy_addr, region->size);
-+ region->addr = devm_ioremap(hw->dev, region->phy_addr, region->size);
-
- return !region->addr ? -EINVAL : 0;
- }
-@@ -271,6 +265,9 @@ mtk_wed_mcu_run_firmware(struct mtk_wed_
- const struct mtk_wed_fw_trailer *trailer;
- const struct mtk_wed_fw_region *fw_region;
-
-+ if (!region->phy_addr || !region->size)
-+ return 0;
-+
- trailer_ptr = fw->data + fw->size - sizeof(*trailer);
- trailer = (const struct mtk_wed_fw_trailer *)trailer_ptr;
- region_ptr = trailer_ptr - trailer->num_region * sizeof(*fw_region);
-@@ -318,7 +315,13 @@ mtk_wed_mcu_load_firmware(struct mtk_wed
-
- /* load firmware region metadata */
- for (i = 0; i < ARRAY_SIZE(mem_region); i++) {
-- ret = mtk_wed_get_memory_region(wo, &mem_region[i]);
-+ int index = of_property_match_string(wo->hw->node,
-+ "memory-region-names",
-+ mem_region[i].name);
-+ if (index < 0)
-+ continue;
-+
-+ ret = mtk_wed_get_memory_region(wo->hw, index, &mem_region[i]);
- if (ret)
- return ret;
- }
+++ /dev/null
-Date: Mon, 18 Sep 2023 12:29:12 +0200
-Subject: [PATCH] net: ethernet: mtk_wed: add mtk_wed_soc_data structure
-
-Introduce mtk_wed_soc_data utility structure to contain per-SoC
-definitions.
-
----
-
---- a/drivers/net/ethernet/mediatek/mtk_wed.c
-+++ b/drivers/net/ethernet/mediatek/mtk_wed.c
-@@ -49,6 +49,26 @@ struct mtk_wed_flow_block_priv {
- struct net_device *dev;
- };
-
-+static const struct mtk_wed_soc_data mt7622_data = {
-+ .regmap = {
-+ .tx_bm_tkid = 0x088,
-+ .wpdma_rx_ring0 = 0x770,
-+ .reset_idx_tx_mask = GENMASK(3, 0),
-+ .reset_idx_rx_mask = GENMASK(17, 16),
-+ },
-+ .wdma_desc_size = sizeof(struct mtk_wdma_desc),
-+};
-+
-+static const struct mtk_wed_soc_data mt7986_data = {
-+ .regmap = {
-+ .tx_bm_tkid = 0x0c8,
-+ .wpdma_rx_ring0 = 0x770,
-+ .reset_idx_tx_mask = GENMASK(1, 0),
-+ .reset_idx_rx_mask = GENMASK(7, 6),
-+ },
-+ .wdma_desc_size = 2 * sizeof(struct mtk_wdma_desc),
-+};
-+
- static void
- wed_m32(struct mtk_wed_device *dev, u32 reg, u32 mask, u32 val)
- {
-@@ -746,7 +766,7 @@ mtk_wed_set_wpdma(struct mtk_wed_device
- return;
-
- wed_w32(dev, MTK_WED_WPDMA_RX_GLO_CFG, dev->wlan.wpdma_rx_glo);
-- wed_w32(dev, MTK_WED_WPDMA_RX_RING, dev->wlan.wpdma_rx);
-+ wed_w32(dev, dev->hw->soc->regmap.wpdma_rx_ring0, dev->wlan.wpdma_rx);
- }
-
- static void
-@@ -940,22 +960,10 @@ mtk_wed_hw_init(struct mtk_wed_device *d
- wed_w32(dev, MTK_WED_TX_BM_BUF_LEN, MTK_WED_PKT_SIZE);
-
- if (mtk_wed_is_v1(dev->hw)) {
-- wed_w32(dev, MTK_WED_TX_BM_TKID,
-- FIELD_PREP(MTK_WED_TX_BM_TKID_START,
-- dev->wlan.token_start) |
-- FIELD_PREP(MTK_WED_TX_BM_TKID_END,
-- dev->wlan.token_start +
-- dev->wlan.nbuf - 1));
- wed_w32(dev, MTK_WED_TX_BM_DYN_THR,
- FIELD_PREP(MTK_WED_TX_BM_DYN_THR_LO, 1) |
- MTK_WED_TX_BM_DYN_THR_HI);
- } else {
-- wed_w32(dev, MTK_WED_TX_BM_TKID_V2,
-- FIELD_PREP(MTK_WED_TX_BM_TKID_START,
-- dev->wlan.token_start) |
-- FIELD_PREP(MTK_WED_TX_BM_TKID_END,
-- dev->wlan.token_start +
-- dev->wlan.nbuf - 1));
- wed_w32(dev, MTK_WED_TX_BM_DYN_THR,
- FIELD_PREP(MTK_WED_TX_BM_DYN_THR_LO_V2, 0) |
- MTK_WED_TX_BM_DYN_THR_HI_V2);
-@@ -970,6 +978,11 @@ mtk_wed_hw_init(struct mtk_wed_device *d
- MTK_WED_TX_TKID_DYN_THR_HI);
- }
-
-+ wed_w32(dev, dev->hw->soc->regmap.tx_bm_tkid,
-+ FIELD_PREP(MTK_WED_TX_BM_TKID_START, dev->wlan.token_start) |
-+ FIELD_PREP(MTK_WED_TX_BM_TKID_END,
-+ dev->wlan.token_start + dev->wlan.nbuf - 1));
-+
- mtk_wed_reset(dev, MTK_WED_RESET_TX_BM);
-
- if (mtk_wed_is_v1(dev->hw)) {
-@@ -1104,13 +1117,8 @@ mtk_wed_rx_reset(struct mtk_wed_device *
- if (ret) {
- mtk_wed_reset(dev, MTK_WED_RESET_WED_RX_DMA);
- } else {
-- struct mtk_eth *eth = dev->hw->eth;
--
-- if (mtk_is_netsys_v2_or_greater(eth))
-- wed_set(dev, MTK_WED_RESET_IDX,
-- MTK_WED_RESET_IDX_RX_V2);
-- else
-- wed_set(dev, MTK_WED_RESET_IDX, MTK_WED_RESET_IDX_RX);
-+ wed_set(dev, MTK_WED_RESET_IDX,
-+ dev->hw->soc->regmap.reset_idx_rx_mask);
- wed_w32(dev, MTK_WED_RESET_IDX, 0);
- }
-
-@@ -1163,7 +1171,8 @@ mtk_wed_reset_dma(struct mtk_wed_device
- if (busy) {
- mtk_wed_reset(dev, MTK_WED_RESET_WED_TX_DMA);
- } else {
-- wed_w32(dev, MTK_WED_RESET_IDX, MTK_WED_RESET_IDX_TX);
-+ wed_w32(dev, MTK_WED_RESET_IDX,
-+ dev->hw->soc->regmap.reset_idx_tx_mask);
- wed_w32(dev, MTK_WED_RESET_IDX, 0);
- }
-
-@@ -1255,7 +1264,6 @@ static int
- mtk_wed_wdma_rx_ring_setup(struct mtk_wed_device *dev, int idx, int size,
- bool reset)
- {
-- u32 desc_size = sizeof(struct mtk_wdma_desc) * dev->hw->version;
- struct mtk_wed_ring *wdma;
-
- if (idx >= ARRAY_SIZE(dev->rx_wdma))
-@@ -1263,7 +1271,7 @@ mtk_wed_wdma_rx_ring_setup(struct mtk_we
-
- wdma = &dev->rx_wdma[idx];
- if (!reset && mtk_wed_ring_alloc(dev, wdma, MTK_WED_WDMA_RING_SIZE,
-- desc_size, true))
-+ dev->hw->soc->wdma_desc_size, true))
- return -ENOMEM;
-
- wdma_w32(dev, MTK_WDMA_RING_RX(idx) + MTK_WED_RING_OFS_BASE,
-@@ -1284,7 +1292,6 @@ static int
- mtk_wed_wdma_tx_ring_setup(struct mtk_wed_device *dev, int idx, int size,
- bool reset)
- {
-- u32 desc_size = sizeof(struct mtk_wdma_desc) * dev->hw->version;
- struct mtk_wed_ring *wdma;
-
- if (idx >= ARRAY_SIZE(dev->tx_wdma))
-@@ -1292,7 +1299,7 @@ mtk_wed_wdma_tx_ring_setup(struct mtk_we
-
- wdma = &dev->tx_wdma[idx];
- if (!reset && mtk_wed_ring_alloc(dev, wdma, MTK_WED_WDMA_RING_SIZE,
-- desc_size, true))
-+ dev->hw->soc->wdma_desc_size, true))
- return -ENOMEM;
-
- wdma_w32(dev, MTK_WDMA_RING_TX(idx) + MTK_WED_RING_OFS_BASE,
-@@ -1929,7 +1936,12 @@ void mtk_wed_add_hw(struct device_node *
- hw->irq = irq;
- hw->version = eth->soc->version;
-
-- if (mtk_wed_is_v1(hw)) {
-+ switch (hw->version) {
-+ case 2:
-+ hw->soc = &mt7986_data;
-+ break;
-+ default:
-+ case 1:
- hw->mirror = syscon_regmap_lookup_by_phandle(eth_np,
- "mediatek,pcie-mirror");
- hw->hifsys = syscon_regmap_lookup_by_phandle(eth_np,
-@@ -1943,6 +1955,8 @@ void mtk_wed_add_hw(struct device_node *
- regmap_write(hw->mirror, 0, 0);
- regmap_write(hw->mirror, 4, 0);
- }
-+ hw->soc = &mt7622_data;
-+ break;
- }
-
- mtk_wed_hw_add_debugfs(hw);
---- a/drivers/net/ethernet/mediatek/mtk_wed.h
-+++ b/drivers/net/ethernet/mediatek/mtk_wed.h
-@@ -12,7 +12,18 @@
- struct mtk_eth;
- struct mtk_wed_wo;
-
-+struct mtk_wed_soc_data {
-+ struct {
-+ u32 tx_bm_tkid;
-+ u32 wpdma_rx_ring0;
-+ u32 reset_idx_tx_mask;
-+ u32 reset_idx_rx_mask;
-+ } regmap;
-+ u32 wdma_desc_size;
-+};
-+
- struct mtk_wed_hw {
-+ const struct mtk_wed_soc_data *soc;
- struct device_node *node;
- struct mtk_eth *eth;
- struct regmap *regs;
---- a/drivers/net/ethernet/mediatek/mtk_wed_regs.h
-+++ b/drivers/net/ethernet/mediatek/mtk_wed_regs.h
-@@ -100,8 +100,6 @@ struct mtk_wdma_desc {
-
- #define MTK_WED_TX_BM_BASE 0x084
-
--#define MTK_WED_TX_BM_TKID 0x088
--#define MTK_WED_TX_BM_TKID_V2 0x0c8
- #define MTK_WED_TX_BM_TKID_START GENMASK(15, 0)
- #define MTK_WED_TX_BM_TKID_END GENMASK(31, 16)
-
-@@ -160,9 +158,6 @@ struct mtk_wdma_desc {
- #define MTK_WED_GLO_CFG_RX_2B_OFFSET BIT(31)
-
- #define MTK_WED_RESET_IDX 0x20c
--#define MTK_WED_RESET_IDX_TX GENMASK(3, 0)
--#define MTK_WED_RESET_IDX_RX GENMASK(17, 16)
--#define MTK_WED_RESET_IDX_RX_V2 GENMASK(7, 6)
- #define MTK_WED_RESET_WPDMA_IDX_RX GENMASK(31, 30)
-
- #define MTK_WED_TX_MIB(_n) (0x2a0 + (_n) * 4)
-@@ -286,7 +281,6 @@ struct mtk_wdma_desc {
- #define MTK_WED_WPDMA_RX_D_RST_DRV_IDX GENMASK(25, 24)
-
- #define MTK_WED_WPDMA_RX_GLO_CFG 0x76c
--#define MTK_WED_WPDMA_RX_RING 0x770
-
- #define MTK_WED_WPDMA_RX_D_MIB(_n) (0x774 + (_n) * 4)
- #define MTK_WED_WPDMA_RX_D_PROCESSED_MIB(_n) (0x784 + (_n) * 4)
+++ /dev/null
-Date: Mon, 18 Sep 2023 12:29:13 +0200
-Subject: [PATCH] net: ethernet: mtk_wed: introduce WED support for MT7988
-
-Similar to MT7986 and MT7622, enable Wireless Ethernet Ditpatcher for
-MT7988 in order to offload traffic forwarded from LAN/WLAN to WLAN/LAN
-
----
-
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -197,6 +197,7 @@ static const struct mtk_reg_map mt7988_r
- .wdma_base = {
- [0] = 0x4800,
- [1] = 0x4c00,
-+ [2] = 0x5000,
- },
- .pse_iq_sta = 0x0180,
- .pse_oq_sta = 0x01a0,
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-@@ -1140,7 +1140,7 @@ struct mtk_reg_map {
- u32 gdm1_cnt;
- u32 gdma_to_ppe;
- u32 ppe_base;
-- u32 wdma_base[2];
-+ u32 wdma_base[3];
- u32 pse_iq_sta;
- u32 pse_oq_sta;
- };
---- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
-+++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
-@@ -205,6 +205,9 @@ mtk_flow_set_output_device(struct mtk_et
- case 1:
- pse_port = PSE_WDMA1_PORT;
- break;
-+ case 2:
-+ pse_port = PSE_WDMA2_PORT;
-+ break;
- default:
- return -EINVAL;
- }
---- a/drivers/net/ethernet/mediatek/mtk_wed.c
-+++ b/drivers/net/ethernet/mediatek/mtk_wed.c
-@@ -17,17 +17,19 @@
- #include <net/flow_offload.h>
- #include <net/pkt_cls.h>
- #include "mtk_eth_soc.h"
--#include "mtk_wed_regs.h"
- #include "mtk_wed.h"
- #include "mtk_ppe.h"
- #include "mtk_wed_wo.h"
-
- #define MTK_PCIE_BASE(n) (0x1a143000 + (n) * 0x2000)
-
--#define MTK_WED_PKT_SIZE 1900
-+#define MTK_WED_PKT_SIZE 1920
- #define MTK_WED_BUF_SIZE 2048
-+#define MTK_WED_PAGE_BUF_SIZE 128
- #define MTK_WED_BUF_PER_PAGE (PAGE_SIZE / 2048)
-+#define MTK_WED_RX_PAGE_BUF_PER_PAGE (PAGE_SIZE / 128)
- #define MTK_WED_RX_RING_SIZE 1536
-+#define MTK_WED_RX_PG_BM_CNT 8192
-
- #define MTK_WED_TX_RING_SIZE 2048
- #define MTK_WED_WDMA_RING_SIZE 1024
-@@ -41,7 +43,10 @@
- #define MTK_WED_RRO_QUE_CNT 8192
- #define MTK_WED_MIOD_ENTRY_CNT 128
-
--static struct mtk_wed_hw *hw_list[2];
-+#define MTK_WED_TX_BM_DMA_SIZE 65536
-+#define MTK_WED_TX_BM_PKT_CNT 32768
-+
-+static struct mtk_wed_hw *hw_list[3];
- static DEFINE_MUTEX(hw_lock);
-
- struct mtk_wed_flow_block_priv {
-@@ -56,6 +61,7 @@ static const struct mtk_wed_soc_data mt7
- .reset_idx_tx_mask = GENMASK(3, 0),
- .reset_idx_rx_mask = GENMASK(17, 16),
- },
-+ .tx_ring_desc_size = sizeof(struct mtk_wdma_desc),
- .wdma_desc_size = sizeof(struct mtk_wdma_desc),
- };
-
-@@ -66,6 +72,18 @@ static const struct mtk_wed_soc_data mt7
- .reset_idx_tx_mask = GENMASK(1, 0),
- .reset_idx_rx_mask = GENMASK(7, 6),
- },
-+ .tx_ring_desc_size = sizeof(struct mtk_wdma_desc),
-+ .wdma_desc_size = 2 * sizeof(struct mtk_wdma_desc),
-+};
-+
-+static const struct mtk_wed_soc_data mt7988_data = {
-+ .regmap = {
-+ .tx_bm_tkid = 0x0c8,
-+ .wpdma_rx_ring0 = 0x7d0,
-+ .reset_idx_tx_mask = GENMASK(1, 0),
-+ .reset_idx_rx_mask = GENMASK(7, 6),
-+ },
-+ .tx_ring_desc_size = sizeof(struct mtk_wed_bm_desc),
- .wdma_desc_size = 2 * sizeof(struct mtk_wdma_desc),
- };
-
-@@ -320,33 +338,38 @@ out:
- static int
- mtk_wed_tx_buffer_alloc(struct mtk_wed_device *dev)
- {
-+ u32 desc_size = dev->hw->soc->tx_ring_desc_size;
-+ int i, page_idx = 0, n_pages, ring_size;
-+ int token = dev->wlan.token_start;
- struct mtk_wed_buf *page_list;
-- struct mtk_wdma_desc *desc;
- dma_addr_t desc_phys;
-- int token = dev->wlan.token_start;
-- int ring_size;
-- int n_pages;
-- int i, page_idx;
-+ void *desc_ptr;
-
-- ring_size = dev->wlan.nbuf & ~(MTK_WED_BUF_PER_PAGE - 1);
-- n_pages = ring_size / MTK_WED_BUF_PER_PAGE;
-+ if (!mtk_wed_is_v3_or_greater(dev->hw)) {
-+ ring_size = dev->wlan.nbuf & ~(MTK_WED_BUF_PER_PAGE - 1);
-+ dev->tx_buf_ring.size = ring_size;
-+ } else {
-+ dev->tx_buf_ring.size = MTK_WED_TX_BM_DMA_SIZE;
-+ ring_size = MTK_WED_TX_BM_PKT_CNT;
-+ }
-+ n_pages = dev->tx_buf_ring.size / MTK_WED_BUF_PER_PAGE;
-
- page_list = kcalloc(n_pages, sizeof(*page_list), GFP_KERNEL);
- if (!page_list)
- return -ENOMEM;
-
-- dev->tx_buf_ring.size = ring_size;
- dev->tx_buf_ring.pages = page_list;
-
-- desc = dma_alloc_coherent(dev->hw->dev, ring_size * sizeof(*desc),
-- &desc_phys, GFP_KERNEL);
-- if (!desc)
-+ desc_ptr = dma_alloc_coherent(dev->hw->dev,
-+ dev->tx_buf_ring.size * desc_size,
-+ &desc_phys, GFP_KERNEL);
-+ if (!desc_ptr)
- return -ENOMEM;
-
-- dev->tx_buf_ring.desc = desc;
-+ dev->tx_buf_ring.desc = desc_ptr;
- dev->tx_buf_ring.desc_phys = desc_phys;
-
-- for (i = 0, page_idx = 0; i < ring_size; i += MTK_WED_BUF_PER_PAGE) {
-+ for (i = 0; i < ring_size; i += MTK_WED_BUF_PER_PAGE) {
- dma_addr_t page_phys, buf_phys;
- struct page *page;
- void *buf;
-@@ -372,28 +395,31 @@ mtk_wed_tx_buffer_alloc(struct mtk_wed_d
- buf_phys = page_phys;
-
- for (s = 0; s < MTK_WED_BUF_PER_PAGE; s++) {
-- u32 txd_size;
-- u32 ctrl;
--
-- txd_size = dev->wlan.init_buf(buf, buf_phys, token++);
-+ struct mtk_wdma_desc *desc = desc_ptr;
-
- desc->buf0 = cpu_to_le32(buf_phys);
-- desc->buf1 = cpu_to_le32(buf_phys + txd_size);
-+ if (!mtk_wed_is_v3_or_greater(dev->hw)) {
-+ u32 txd_size, ctrl;
-
-- if (mtk_wed_is_v1(dev->hw))
-- ctrl = FIELD_PREP(MTK_WDMA_DESC_CTRL_LEN0, txd_size) |
-- FIELD_PREP(MTK_WDMA_DESC_CTRL_LEN1,
-- MTK_WED_BUF_SIZE - txd_size) |
-- MTK_WDMA_DESC_CTRL_LAST_SEG1;
-- else
-- ctrl = FIELD_PREP(MTK_WDMA_DESC_CTRL_LEN0, txd_size) |
-- FIELD_PREP(MTK_WDMA_DESC_CTRL_LEN1_V2,
-- MTK_WED_BUF_SIZE - txd_size) |
-- MTK_WDMA_DESC_CTRL_LAST_SEG0;
-- desc->ctrl = cpu_to_le32(ctrl);
-- desc->info = 0;
-- desc++;
-+ txd_size = dev->wlan.init_buf(buf, buf_phys,
-+ token++);
-+ desc->buf1 = cpu_to_le32(buf_phys + txd_size);
-+ ctrl = FIELD_PREP(MTK_WDMA_DESC_CTRL_LEN0, txd_size);
-+ if (mtk_wed_is_v1(dev->hw))
-+ ctrl |= MTK_WDMA_DESC_CTRL_LAST_SEG1 |
-+ FIELD_PREP(MTK_WDMA_DESC_CTRL_LEN1,
-+ MTK_WED_BUF_SIZE - txd_size);
-+ else
-+ ctrl |= MTK_WDMA_DESC_CTRL_LAST_SEG0 |
-+ FIELD_PREP(MTK_WDMA_DESC_CTRL_LEN1_V2,
-+ MTK_WED_BUF_SIZE - txd_size);
-+ desc->ctrl = cpu_to_le32(ctrl);
-+ desc->info = 0;
-+ } else {
-+ desc->ctrl = cpu_to_le32(token << 16);
-+ }
-
-+ desc_ptr += desc_size;
- buf += MTK_WED_BUF_SIZE;
- buf_phys += MTK_WED_BUF_SIZE;
- }
-@@ -409,31 +435,31 @@ static void
- mtk_wed_free_tx_buffer(struct mtk_wed_device *dev)
- {
- struct mtk_wed_buf *page_list = dev->tx_buf_ring.pages;
-- struct mtk_wdma_desc *desc = dev->tx_buf_ring.desc;
-- int page_idx;
-- int i;
-+ struct mtk_wed_hw *hw = dev->hw;
-+ int i, page_idx = 0;
-
- if (!page_list)
- return;
-
-- if (!desc)
-+ if (!dev->tx_buf_ring.desc)
- goto free_pagelist;
-
-- for (i = 0, page_idx = 0; i < dev->tx_buf_ring.size;
-- i += MTK_WED_BUF_PER_PAGE) {
-- dma_addr_t buf_addr = page_list[page_idx].phy_addr;
-+ for (i = 0; i < dev->tx_buf_ring.size; i += MTK_WED_BUF_PER_PAGE) {
-+ dma_addr_t page_phy = page_list[page_idx].phy_addr;
- void *page = page_list[page_idx++].p;
-
- if (!page)
- break;
-
-- dma_unmap_page(dev->hw->dev, buf_addr, PAGE_SIZE,
-+ dma_unmap_page(dev->hw->dev, page_phy, PAGE_SIZE,
- DMA_BIDIRECTIONAL);
- __free_page(page);
- }
-
-- dma_free_coherent(dev->hw->dev, dev->tx_buf_ring.size * sizeof(*desc),
-- desc, dev->tx_buf_ring.desc_phys);
-+ dma_free_coherent(dev->hw->dev,
-+ dev->tx_buf_ring.size * hw->soc->tx_ring_desc_size,
-+ dev->tx_buf_ring.desc,
-+ dev->tx_buf_ring.desc_phys);
-
- free_pagelist:
- kfree(page_list);
-@@ -518,13 +544,23 @@ mtk_wed_set_ext_int(struct mtk_wed_devic
- {
- u32 mask = MTK_WED_EXT_INT_STATUS_ERROR_MASK;
-
-- if (mtk_wed_is_v1(dev->hw))
-+ switch (dev->hw->version) {
-+ case 1:
- mask |= MTK_WED_EXT_INT_STATUS_TX_DRV_R_RESP_ERR;
-- else
-+ break;
-+ case 2:
- mask |= MTK_WED_EXT_INT_STATUS_RX_FBUF_LO_TH |
- MTK_WED_EXT_INT_STATUS_RX_FBUF_HI_TH |
- MTK_WED_EXT_INT_STATUS_RX_DRV_COHERENT |
- MTK_WED_EXT_INT_STATUS_TX_DMA_W_RESP_ERR;
-+ break;
-+ case 3:
-+ mask = MTK_WED_EXT_INT_STATUS_RX_DRV_COHERENT |
-+ MTK_WED_EXT_INT_STATUS_TKID_WO_PYLD;
-+ break;
-+ default:
-+ break;
-+ }
-
- if (!dev->hw->num_flows)
- mask &= ~MTK_WED_EXT_INT_STATUS_TKID_WO_PYLD;
-@@ -536,6 +572,9 @@ mtk_wed_set_ext_int(struct mtk_wed_devic
- static void
- mtk_wed_set_512_support(struct mtk_wed_device *dev, bool enable)
- {
-+ if (!mtk_wed_is_v2(dev->hw))
-+ return;
-+
- if (enable) {
- wed_w32(dev, MTK_WED_TXDP_CTRL, MTK_WED_TXDP_DW9_OVERWR);
- wed_w32(dev, MTK_WED_TXP_DW1,
-@@ -610,6 +649,14 @@ mtk_wed_dma_disable(struct mtk_wed_devic
- MTK_WED_WPDMA_RX_D_RX_DRV_EN);
- wed_clr(dev, MTK_WED_WDMA_GLO_CFG,
- MTK_WED_WDMA_GLO_CFG_TX_DDONE_CHK);
-+
-+ if (mtk_wed_is_v3_or_greater(dev->hw) &&
-+ mtk_wed_get_rx_capa(dev)) {
-+ wdma_clr(dev, MTK_WDMA_PREF_TX_CFG,
-+ MTK_WDMA_PREF_TX_CFG_PREF_EN);
-+ wdma_clr(dev, MTK_WDMA_PREF_RX_CFG,
-+ MTK_WDMA_PREF_RX_CFG_PREF_EN);
-+ }
- }
-
- mtk_wed_set_512_support(dev, false);
-@@ -651,6 +698,14 @@ mtk_wed_deinit(struct mtk_wed_device *de
- MTK_WED_CTRL_RX_ROUTE_QM_EN |
- MTK_WED_CTRL_WED_RX_BM_EN |
- MTK_WED_CTRL_RX_RRO_QM_EN);
-+
-+ if (mtk_wed_is_v3_or_greater(dev->hw)) {
-+ wed_clr(dev, MTK_WED_CTRL, MTK_WED_CTRL_TX_AMSDU_EN);
-+ wed_clr(dev, MTK_WED_RESET, MTK_WED_RESET_TX_AMSDU);
-+ wed_clr(dev, MTK_WED_PCIE_INT_CTRL,
-+ MTK_WED_PCIE_INT_CTRL_MSK_EN_POLA |
-+ MTK_WED_PCIE_INT_CTRL_MSK_IRQ_FILTER);
-+ }
- }
-
- static void
-@@ -700,21 +755,37 @@ mtk_wed_detach(struct mtk_wed_device *de
- mutex_unlock(&hw_lock);
- }
-
--#define PCIE_BASE_ADDR0 0x11280000
- static void
- mtk_wed_bus_init(struct mtk_wed_device *dev)
- {
- switch (dev->wlan.bus_type) {
- case MTK_WED_BUS_PCIE: {
- struct device_node *np = dev->hw->eth->dev->of_node;
-- struct regmap *regs;
-
-- regs = syscon_regmap_lookup_by_phandle(np,
-- "mediatek,wed-pcie");
-- if (IS_ERR(regs))
-- break;
-+ if (mtk_wed_is_v2(dev->hw)) {
-+ struct regmap *regs;
-+
-+ regs = syscon_regmap_lookup_by_phandle(np,
-+ "mediatek,wed-pcie");
-+ if (IS_ERR(regs))
-+ break;
-
-- regmap_update_bits(regs, 0, BIT(0), BIT(0));
-+ regmap_update_bits(regs, 0, BIT(0), BIT(0));
-+ }
-+
-+ if (dev->wlan.msi) {
-+ wed_w32(dev, MTK_WED_PCIE_CFG_INTM,
-+ dev->hw->pcie_base | 0xc08);
-+ wed_w32(dev, MTK_WED_PCIE_CFG_BASE,
-+ dev->hw->pcie_base | 0xc04);
-+ wed_w32(dev, MTK_WED_PCIE_INT_TRIGGER, BIT(8));
-+ } else {
-+ wed_w32(dev, MTK_WED_PCIE_CFG_INTM,
-+ dev->hw->pcie_base | 0x180);
-+ wed_w32(dev, MTK_WED_PCIE_CFG_BASE,
-+ dev->hw->pcie_base | 0x184);
-+ wed_w32(dev, MTK_WED_PCIE_INT_TRIGGER, BIT(24));
-+ }
-
- wed_w32(dev, MTK_WED_PCIE_INT_CTRL,
- FIELD_PREP(MTK_WED_PCIE_INT_CTRL_POLL_EN, 2));
-@@ -722,19 +793,9 @@ mtk_wed_bus_init(struct mtk_wed_device *
- /* pcie interrupt control: pola/source selection */
- wed_set(dev, MTK_WED_PCIE_INT_CTRL,
- MTK_WED_PCIE_INT_CTRL_MSK_EN_POLA |
-- FIELD_PREP(MTK_WED_PCIE_INT_CTRL_SRC_SEL, 1));
-- wed_r32(dev, MTK_WED_PCIE_INT_CTRL);
--
-- wed_w32(dev, MTK_WED_PCIE_CFG_INTM, PCIE_BASE_ADDR0 | 0x180);
-- wed_w32(dev, MTK_WED_PCIE_CFG_BASE, PCIE_BASE_ADDR0 | 0x184);
--
-- /* pcie interrupt status trigger register */
-- wed_w32(dev, MTK_WED_PCIE_INT_TRIGGER, BIT(24));
-- wed_r32(dev, MTK_WED_PCIE_INT_TRIGGER);
--
-- /* pola setting */
-- wed_set(dev, MTK_WED_PCIE_INT_CTRL,
-- MTK_WED_PCIE_INT_CTRL_MSK_EN_POLA);
-+ MTK_WED_PCIE_INT_CTRL_MSK_IRQ_FILTER |
-+ FIELD_PREP(MTK_WED_PCIE_INT_CTRL_SRC_SEL,
-+ dev->hw->index));
- break;
- }
- case MTK_WED_BUS_AXI:
-@@ -772,18 +833,19 @@ mtk_wed_set_wpdma(struct mtk_wed_device
- static void
- mtk_wed_hw_init_early(struct mtk_wed_device *dev)
- {
-- u32 mask, set;
-+ u32 set = FIELD_PREP(MTK_WED_WDMA_GLO_CFG_BT_SIZE, 2);
-+ u32 mask = MTK_WED_WDMA_GLO_CFG_BT_SIZE;
-
- mtk_wed_deinit(dev);
- mtk_wed_reset(dev, MTK_WED_RESET_WED);
- mtk_wed_set_wpdma(dev);
-
-- mask = MTK_WED_WDMA_GLO_CFG_BT_SIZE |
-- MTK_WED_WDMA_GLO_CFG_DYNAMIC_DMAD_RECYCLE |
-- MTK_WED_WDMA_GLO_CFG_RX_DIS_FSM_AUTO_IDLE;
-- set = FIELD_PREP(MTK_WED_WDMA_GLO_CFG_BT_SIZE, 2) |
-- MTK_WED_WDMA_GLO_CFG_DYNAMIC_SKIP_DMAD_PREP |
-- MTK_WED_WDMA_GLO_CFG_IDLE_DMAD_SUPPLY;
-+ if (!mtk_wed_is_v3_or_greater(dev->hw)) {
-+ mask |= MTK_WED_WDMA_GLO_CFG_DYNAMIC_DMAD_RECYCLE |
-+ MTK_WED_WDMA_GLO_CFG_RX_DIS_FSM_AUTO_IDLE;
-+ set |= MTK_WED_WDMA_GLO_CFG_DYNAMIC_SKIP_DMAD_PREP |
-+ MTK_WED_WDMA_GLO_CFG_IDLE_DMAD_SUPPLY;
-+ }
- wed_m32(dev, MTK_WED_WDMA_GLO_CFG, mask, set);
-
- if (mtk_wed_is_v1(dev->hw)) {
-@@ -931,11 +993,18 @@ mtk_wed_route_qm_hw_init(struct mtk_wed_
- }
-
- /* configure RX_ROUTE_QM */
-- wed_clr(dev, MTK_WED_RTQM_GLO_CFG, MTK_WED_RTQM_Q_RST);
-- wed_clr(dev, MTK_WED_RTQM_GLO_CFG, MTK_WED_RTQM_TXDMAD_FPORT);
-- wed_set(dev, MTK_WED_RTQM_GLO_CFG,
-- FIELD_PREP(MTK_WED_RTQM_TXDMAD_FPORT, 0x3 + dev->hw->index));
-- wed_clr(dev, MTK_WED_RTQM_GLO_CFG, MTK_WED_RTQM_Q_RST);
-+ if (mtk_wed_is_v2(dev->hw)) {
-+ wed_clr(dev, MTK_WED_RTQM_GLO_CFG, MTK_WED_RTQM_Q_RST);
-+ wed_clr(dev, MTK_WED_RTQM_GLO_CFG, MTK_WED_RTQM_TXDMAD_FPORT);
-+ wed_set(dev, MTK_WED_RTQM_GLO_CFG,
-+ FIELD_PREP(MTK_WED_RTQM_TXDMAD_FPORT,
-+ 0x3 + dev->hw->index));
-+ wed_clr(dev, MTK_WED_RTQM_GLO_CFG, MTK_WED_RTQM_Q_RST);
-+ } else {
-+ wed_set(dev, MTK_WED_RTQM_ENQ_CFG0,
-+ FIELD_PREP(MTK_WED_RTQM_ENQ_CFG_TXDMAD_FPORT,
-+ 0x3 + dev->hw->index));
-+ }
- /* enable RX_ROUTE_QM */
- wed_set(dev, MTK_WED_CTRL, MTK_WED_CTRL_RX_ROUTE_QM_EN);
- }
-@@ -948,22 +1017,30 @@ mtk_wed_hw_init(struct mtk_wed_device *d
-
- dev->init_done = true;
- mtk_wed_set_ext_int(dev, false);
-- wed_w32(dev, MTK_WED_TX_BM_CTRL,
-- MTK_WED_TX_BM_CTRL_PAUSE |
-- FIELD_PREP(MTK_WED_TX_BM_CTRL_VLD_GRP_NUM,
-- dev->tx_buf_ring.size / 128) |
-- FIELD_PREP(MTK_WED_TX_BM_CTRL_RSV_GRP_NUM,
-- MTK_WED_TX_RING_SIZE / 256));
-
- wed_w32(dev, MTK_WED_TX_BM_BASE, dev->tx_buf_ring.desc_phys);
--
- wed_w32(dev, MTK_WED_TX_BM_BUF_LEN, MTK_WED_PKT_SIZE);
-
- if (mtk_wed_is_v1(dev->hw)) {
-+ wed_w32(dev, MTK_WED_TX_BM_CTRL,
-+ MTK_WED_TX_BM_CTRL_PAUSE |
-+ FIELD_PREP(MTK_WED_TX_BM_CTRL_VLD_GRP_NUM,
-+ dev->tx_buf_ring.size / 128) |
-+ FIELD_PREP(MTK_WED_TX_BM_CTRL_RSV_GRP_NUM,
-+ MTK_WED_TX_RING_SIZE / 256));
- wed_w32(dev, MTK_WED_TX_BM_DYN_THR,
- FIELD_PREP(MTK_WED_TX_BM_DYN_THR_LO, 1) |
- MTK_WED_TX_BM_DYN_THR_HI);
-- } else {
-+ } else if (mtk_wed_is_v2(dev->hw)) {
-+ wed_w32(dev, MTK_WED_TX_BM_CTRL,
-+ MTK_WED_TX_BM_CTRL_PAUSE |
-+ FIELD_PREP(MTK_WED_TX_BM_CTRL_VLD_GRP_NUM,
-+ dev->tx_buf_ring.size / 128) |
-+ FIELD_PREP(MTK_WED_TX_BM_CTRL_RSV_GRP_NUM,
-+ MTK_WED_TX_RING_SIZE / 256));
-+ wed_w32(dev, MTK_WED_TX_TKID_DYN_THR,
-+ FIELD_PREP(MTK_WED_TX_TKID_DYN_THR_LO, 0) |
-+ MTK_WED_TX_TKID_DYN_THR_HI);
- wed_w32(dev, MTK_WED_TX_BM_DYN_THR,
- FIELD_PREP(MTK_WED_TX_BM_DYN_THR_LO_V2, 0) |
- MTK_WED_TX_BM_DYN_THR_HI_V2);
-@@ -973,9 +1050,6 @@ mtk_wed_hw_init(struct mtk_wed_device *d
- dev->tx_buf_ring.size / 128) |
- FIELD_PREP(MTK_WED_TX_TKID_CTRL_RSV_GRP_NUM,
- dev->tx_buf_ring.size / 128));
-- wed_w32(dev, MTK_WED_TX_TKID_DYN_THR,
-- FIELD_PREP(MTK_WED_TX_TKID_DYN_THR_LO, 0) |
-- MTK_WED_TX_TKID_DYN_THR_HI);
- }
-
- wed_w32(dev, dev->hw->soc->regmap.tx_bm_tkid,
-@@ -985,26 +1059,62 @@ mtk_wed_hw_init(struct mtk_wed_device *d
-
- mtk_wed_reset(dev, MTK_WED_RESET_TX_BM);
-
-+ if (mtk_wed_is_v3_or_greater(dev->hw)) {
-+ /* switch to new bm architecture */
-+ wed_clr(dev, MTK_WED_TX_BM_CTRL,
-+ MTK_WED_TX_BM_CTRL_LEGACY_EN);
-+
-+ wed_w32(dev, MTK_WED_TX_TKID_CTRL,
-+ MTK_WED_TX_TKID_CTRL_PAUSE |
-+ FIELD_PREP(MTK_WED_TX_TKID_CTRL_VLD_GRP_NUM_V3,
-+ dev->wlan.nbuf / 128) |
-+ FIELD_PREP(MTK_WED_TX_TKID_CTRL_RSV_GRP_NUM_V3,
-+ dev->wlan.nbuf / 128));
-+ /* return SKBID + SDP back to bm */
-+ wed_set(dev, MTK_WED_TX_TKID_CTRL,
-+ MTK_WED_TX_TKID_CTRL_FREE_FORMAT);
-+
-+ wed_w32(dev, MTK_WED_TX_BM_INIT_PTR,
-+ MTK_WED_TX_BM_PKT_CNT |
-+ MTK_WED_TX_BM_INIT_SW_TAIL_IDX);
-+ }
-+
- if (mtk_wed_is_v1(dev->hw)) {
- wed_set(dev, MTK_WED_CTRL,
- MTK_WED_CTRL_WED_TX_BM_EN |
- MTK_WED_CTRL_WED_TX_FREE_AGENT_EN);
-- } else {
-- wed_clr(dev, MTK_WED_TX_TKID_CTRL, MTK_WED_TX_TKID_CTRL_PAUSE);
-- if (mtk_wed_get_rx_capa(dev)) {
-- /* rx hw init */
-- wed_w32(dev, MTK_WED_WPDMA_RX_D_RST_IDX,
-- MTK_WED_WPDMA_RX_D_RST_CRX_IDX |
-- MTK_WED_WPDMA_RX_D_RST_DRV_IDX);
-- wed_w32(dev, MTK_WED_WPDMA_RX_D_RST_IDX, 0);
--
-- mtk_wed_rx_buffer_hw_init(dev);
-- mtk_wed_rro_hw_init(dev);
-- mtk_wed_route_qm_hw_init(dev);
-- }
-+ } else if (mtk_wed_get_rx_capa(dev)) {
-+ /* rx hw init */
-+ wed_w32(dev, MTK_WED_WPDMA_RX_D_RST_IDX,
-+ MTK_WED_WPDMA_RX_D_RST_CRX_IDX |
-+ MTK_WED_WPDMA_RX_D_RST_DRV_IDX);
-+ wed_w32(dev, MTK_WED_WPDMA_RX_D_RST_IDX, 0);
-+
-+ /* reset prefetch index of ring */
-+ wed_set(dev, MTK_WED_WPDMA_RX_D_PREF_RX0_SIDX,
-+ MTK_WED_WPDMA_RX_D_PREF_SIDX_IDX_CLR);
-+ wed_clr(dev, MTK_WED_WPDMA_RX_D_PREF_RX0_SIDX,
-+ MTK_WED_WPDMA_RX_D_PREF_SIDX_IDX_CLR);
-+
-+ wed_set(dev, MTK_WED_WPDMA_RX_D_PREF_RX1_SIDX,
-+ MTK_WED_WPDMA_RX_D_PREF_SIDX_IDX_CLR);
-+ wed_clr(dev, MTK_WED_WPDMA_RX_D_PREF_RX1_SIDX,
-+ MTK_WED_WPDMA_RX_D_PREF_SIDX_IDX_CLR);
-+
-+ /* reset prefetch FIFO of ring */
-+ wed_set(dev, MTK_WED_WPDMA_RX_D_PREF_FIFO_CFG,
-+ MTK_WED_WPDMA_RX_D_PREF_FIFO_CFG_R0_CLR |
-+ MTK_WED_WPDMA_RX_D_PREF_FIFO_CFG_R1_CLR);
-+ wed_w32(dev, MTK_WED_WPDMA_RX_D_PREF_FIFO_CFG, 0);
-+
-+ mtk_wed_rx_buffer_hw_init(dev);
-+ mtk_wed_rro_hw_init(dev);
-+ mtk_wed_route_qm_hw_init(dev);
- }
-
- wed_clr(dev, MTK_WED_TX_BM_CTRL, MTK_WED_TX_BM_CTRL_PAUSE);
-+ if (!mtk_wed_is_v1(dev->hw))
-+ wed_clr(dev, MTK_WED_TX_TKID_CTRL, MTK_WED_TX_TKID_CTRL_PAUSE);
- }
-
- static void
-@@ -1302,6 +1412,24 @@ mtk_wed_wdma_tx_ring_setup(struct mtk_we
- dev->hw->soc->wdma_desc_size, true))
- return -ENOMEM;
-
-+ if (mtk_wed_is_v3_or_greater(dev->hw)) {
-+ struct mtk_wdma_desc *desc = wdma->desc;
-+ int i;
-+
-+ for (i = 0; i < MTK_WED_WDMA_RING_SIZE; i++) {
-+ desc->buf0 = 0;
-+ desc->ctrl = cpu_to_le32(MTK_WDMA_DESC_CTRL_DMA_DONE);
-+ desc->buf1 = 0;
-+ desc->info = cpu_to_le32(MTK_WDMA_TXD0_DESC_INFO_DMA_DONE);
-+ desc++;
-+ desc->buf0 = 0;
-+ desc->ctrl = cpu_to_le32(MTK_WDMA_DESC_CTRL_DMA_DONE);
-+ desc->buf1 = 0;
-+ desc->info = cpu_to_le32(MTK_WDMA_TXD1_DESC_INFO_DMA_DONE);
-+ desc++;
-+ }
-+ }
-+
- wdma_w32(dev, MTK_WDMA_RING_TX(idx) + MTK_WED_RING_OFS_BASE,
- wdma->desc_phys);
- wdma_w32(dev, MTK_WDMA_RING_TX(idx) + MTK_WED_RING_OFS_COUNT,
-@@ -1367,6 +1495,9 @@ mtk_wed_configure_irq(struct mtk_wed_dev
-
- wed_clr(dev, MTK_WED_WDMA_INT_CTRL, wdma_mask);
- } else {
-+ if (mtk_wed_is_v3_or_greater(dev->hw))
-+ wed_set(dev, MTK_WED_CTRL, MTK_WED_CTRL_TX_TKID_ALI_EN);
-+
- /* initail tx interrupt trigger */
- wed_w32(dev, MTK_WED_WPDMA_INT_CTRL_TX,
- MTK_WED_WPDMA_INT_CTRL_TX0_DONE_EN |
-@@ -1419,33 +1550,60 @@ mtk_wed_dma_enable(struct mtk_wed_device
- {
- int i;
-
-- wed_set(dev, MTK_WED_WPDMA_INT_CTRL, MTK_WED_WPDMA_INT_CTRL_SUBRT_ADV);
-+ if (!mtk_wed_is_v3_or_greater(dev->hw)) {
-+ wed_set(dev, MTK_WED_WPDMA_INT_CTRL,
-+ MTK_WED_WPDMA_INT_CTRL_SUBRT_ADV);
-+ wed_set(dev, MTK_WED_WPDMA_GLO_CFG,
-+ MTK_WED_WPDMA_GLO_CFG_TX_DRV_EN |
-+ MTK_WED_WPDMA_GLO_CFG_RX_DRV_EN);
-+ wdma_set(dev, MTK_WDMA_GLO_CFG,
-+ MTK_WDMA_GLO_CFG_TX_DMA_EN |
-+ MTK_WDMA_GLO_CFG_RX_INFO1_PRERES |
-+ MTK_WDMA_GLO_CFG_RX_INFO2_PRERES);
-+ wed_set(dev, MTK_WED_WPDMA_CTRL, MTK_WED_WPDMA_CTRL_SDL1_FIXED);
-+ } else {
-+ wed_set(dev, MTK_WED_WPDMA_GLO_CFG,
-+ MTK_WED_WPDMA_GLO_CFG_TX_DRV_EN |
-+ MTK_WED_WPDMA_GLO_CFG_RX_DRV_EN |
-+ MTK_WED_WPDMA_GLO_CFG_RX_DDONE2_WR);
-+ wdma_set(dev, MTK_WDMA_GLO_CFG, MTK_WDMA_GLO_CFG_TX_DMA_EN);
-+ }
-
- wed_set(dev, MTK_WED_GLO_CFG,
- MTK_WED_GLO_CFG_TX_DMA_EN |
- MTK_WED_GLO_CFG_RX_DMA_EN);
-- wed_set(dev, MTK_WED_WPDMA_GLO_CFG,
-- MTK_WED_WPDMA_GLO_CFG_TX_DRV_EN |
-- MTK_WED_WPDMA_GLO_CFG_RX_DRV_EN);
-+
- wed_set(dev, MTK_WED_WDMA_GLO_CFG,
- MTK_WED_WDMA_GLO_CFG_RX_DRV_EN);
-
-- wdma_set(dev, MTK_WDMA_GLO_CFG,
-- MTK_WDMA_GLO_CFG_TX_DMA_EN |
-- MTK_WDMA_GLO_CFG_RX_INFO1_PRERES |
-- MTK_WDMA_GLO_CFG_RX_INFO2_PRERES);
--
- if (mtk_wed_is_v1(dev->hw)) {
- wdma_set(dev, MTK_WDMA_GLO_CFG,
- MTK_WDMA_GLO_CFG_RX_INFO3_PRERES);
- return;
- }
-
-- wed_set(dev, MTK_WED_WPDMA_CTRL,
-- MTK_WED_WPDMA_CTRL_SDL1_FIXED);
- wed_set(dev, MTK_WED_WPDMA_GLO_CFG,
- MTK_WED_WPDMA_GLO_CFG_RX_DRV_R0_PKT_PROC |
- MTK_WED_WPDMA_GLO_CFG_RX_DRV_R0_CRX_SYNC);
-+
-+ if (mtk_wed_is_v3_or_greater(dev->hw)) {
-+ wed_set(dev, MTK_WED_WDMA_RX_PREF_CFG,
-+ FIELD_PREP(MTK_WED_WDMA_RX_PREF_BURST_SIZE, 0x10) |
-+ FIELD_PREP(MTK_WED_WDMA_RX_PREF_LOW_THRES, 0x8));
-+ wed_clr(dev, MTK_WED_WDMA_RX_PREF_CFG,
-+ MTK_WED_WDMA_RX_PREF_DDONE2_EN);
-+ wed_set(dev, MTK_WED_WDMA_RX_PREF_CFG, MTK_WED_WDMA_RX_PREF_EN);
-+
-+ wed_clr(dev, MTK_WED_WPDMA_GLO_CFG,
-+ MTK_WED_WPDMA_GLO_CFG_TX_DDONE_CHK_LAST);
-+ wed_set(dev, MTK_WED_WPDMA_GLO_CFG,
-+ MTK_WED_WPDMA_GLO_CFG_TX_DDONE_CHK |
-+ MTK_WED_WPDMA_GLO_CFG_RX_DRV_EVENT_PKT_FMT_CHK |
-+ MTK_WED_WPDMA_GLO_CFG_RX_DRV_UNS_VER_FORCE_4);
-+
-+ wdma_set(dev, MTK_WDMA_PREF_RX_CFG, MTK_WDMA_PREF_RX_CFG_PREF_EN);
-+ }
-+
- wed_clr(dev, MTK_WED_WPDMA_GLO_CFG,
- MTK_WED_WPDMA_GLO_CFG_TX_TKID_KEEP |
- MTK_WED_WPDMA_GLO_CFG_TX_DMAD_DW3_PREV);
-@@ -1457,11 +1615,22 @@ mtk_wed_dma_enable(struct mtk_wed_device
- MTK_WED_WDMA_GLO_CFG_TX_DRV_EN |
- MTK_WED_WDMA_GLO_CFG_TX_DDONE_CHK);
-
-+ wed_clr(dev, MTK_WED_WPDMA_RX_D_GLO_CFG, MTK_WED_WPDMA_RX_D_RXD_READ_LEN);
- wed_set(dev, MTK_WED_WPDMA_RX_D_GLO_CFG,
- MTK_WED_WPDMA_RX_D_RX_DRV_EN |
- FIELD_PREP(MTK_WED_WPDMA_RX_D_RXD_READ_LEN, 0x18) |
-- FIELD_PREP(MTK_WED_WPDMA_RX_D_INIT_PHASE_RXEN_SEL,
-- 0x2));
-+ FIELD_PREP(MTK_WED_WPDMA_RX_D_INIT_PHASE_RXEN_SEL, 0x2));
-+
-+ if (mtk_wed_is_v3_or_greater(dev->hw)) {
-+ wed_set(dev, MTK_WED_WPDMA_RX_D_PREF_CFG,
-+ MTK_WED_WPDMA_RX_D_PREF_EN |
-+ FIELD_PREP(MTK_WED_WPDMA_RX_D_PREF_BURST_SIZE, 0x10) |
-+ FIELD_PREP(MTK_WED_WPDMA_RX_D_PREF_LOW_THRES, 0x8));
-+
-+ wed_set(dev, MTK_WED_RRO_RX_D_CFG(2), MTK_WED_RRO_RX_D_DRV_EN);
-+ wdma_set(dev, MTK_WDMA_PREF_TX_CFG, MTK_WDMA_PREF_TX_CFG_PREF_EN);
-+ wdma_set(dev, MTK_WDMA_WRBK_TX_CFG, MTK_WDMA_WRBK_TX_CFG_WRBK_EN);
-+ }
-
- for (i = 0; i < MTK_WED_RX_QUEUES; i++)
- mtk_wed_check_wfdma_rx_fill(dev, i);
-@@ -1501,6 +1670,12 @@ mtk_wed_start(struct mtk_wed_device *dev
- wed_r32(dev, MTK_WED_EXT_INT_MASK1);
- wed_r32(dev, MTK_WED_EXT_INT_MASK2);
-
-+ if (mtk_wed_is_v3_or_greater(dev->hw)) {
-+ wed_w32(dev, MTK_WED_EXT_INT_MASK3,
-+ MTK_WED_EXT_INT_STATUS_WPDMA_MID_RDY);
-+ wed_r32(dev, MTK_WED_EXT_INT_MASK3);
-+ }
-+
- if (mtk_wed_rro_cfg(dev))
- return;
- }
-@@ -1552,6 +1727,7 @@ mtk_wed_attach(struct mtk_wed_device *de
- dev->irq = hw->irq;
- dev->wdma_idx = hw->index;
- dev->version = hw->version;
-+ dev->hw->pcie_base = mtk_wed_get_pcie_base(dev);
-
- if (hw->eth->dma_dev == hw->eth->dev &&
- of_dma_is_coherent(hw->eth->dev->of_node))
-@@ -1619,6 +1795,23 @@ mtk_wed_tx_ring_setup(struct mtk_wed_dev
- ring->reg_base = MTK_WED_RING_TX(idx);
- ring->wpdma = regs;
-
-+ if (mtk_wed_is_v3_or_greater(dev->hw) && idx == 1) {
-+ /* reset prefetch index */
-+ wed_set(dev, MTK_WED_WDMA_RX_PREF_CFG,
-+ MTK_WED_WDMA_RX_PREF_RX0_SIDX_CLR |
-+ MTK_WED_WDMA_RX_PREF_RX1_SIDX_CLR);
-+
-+ wed_clr(dev, MTK_WED_WDMA_RX_PREF_CFG,
-+ MTK_WED_WDMA_RX_PREF_RX0_SIDX_CLR |
-+ MTK_WED_WDMA_RX_PREF_RX1_SIDX_CLR);
-+
-+ /* reset prefetch FIFO */
-+ wed_w32(dev, MTK_WED_WDMA_RX_PREF_FIFO_CFG,
-+ MTK_WED_WDMA_RX_PREF_FIFO_RX0_CLR |
-+ MTK_WED_WDMA_RX_PREF_FIFO_RX1_CLR);
-+ wed_w32(dev, MTK_WED_WDMA_RX_PREF_FIFO_CFG, 0);
-+ }
-+
- /* WED -> WPDMA */
- wpdma_tx_w32(dev, idx, MTK_WED_RING_OFS_BASE, ring->desc_phys);
- wpdma_tx_w32(dev, idx, MTK_WED_RING_OFS_COUNT, MTK_WED_TX_RING_SIZE);
-@@ -1693,15 +1886,13 @@ mtk_wed_rx_ring_setup(struct mtk_wed_dev
- static u32
- mtk_wed_irq_get(struct mtk_wed_device *dev, u32 mask)
- {
-- u32 val, ext_mask = MTK_WED_EXT_INT_STATUS_ERROR_MASK;
-+ u32 val, ext_mask;
-
-- if (mtk_wed_is_v1(dev->hw))
-- ext_mask |= MTK_WED_EXT_INT_STATUS_TX_DRV_R_RESP_ERR;
-+ if (mtk_wed_is_v3_or_greater(dev->hw))
-+ ext_mask = MTK_WED_EXT_INT_STATUS_RX_DRV_COHERENT |
-+ MTK_WED_EXT_INT_STATUS_TKID_WO_PYLD;
- else
-- ext_mask |= MTK_WED_EXT_INT_STATUS_RX_FBUF_LO_TH |
-- MTK_WED_EXT_INT_STATUS_RX_FBUF_HI_TH |
-- MTK_WED_EXT_INT_STATUS_RX_DRV_COHERENT |
-- MTK_WED_EXT_INT_STATUS_TX_DMA_W_RESP_ERR;
-+ ext_mask = MTK_WED_EXT_INT_STATUS_ERROR_MASK;
-
- val = wed_r32(dev, MTK_WED_EXT_INT_STATUS);
- wed_w32(dev, MTK_WED_EXT_INT_STATUS, val);
-@@ -1940,6 +2131,9 @@ void mtk_wed_add_hw(struct device_node *
- case 2:
- hw->soc = &mt7986_data;
- break;
-+ case 3:
-+ hw->soc = &mt7988_data;
-+ break;
- default:
- case 1:
- hw->mirror = syscon_regmap_lookup_by_phandle(eth_np,
---- a/drivers/net/ethernet/mediatek/mtk_wed.h
-+++ b/drivers/net/ethernet/mediatek/mtk_wed.h
-@@ -9,6 +9,8 @@
- #include <linux/regmap.h>
- #include <linux/netdevice.h>
-
-+#include "mtk_wed_regs.h"
-+
- struct mtk_eth;
- struct mtk_wed_wo;
-
-@@ -19,6 +21,7 @@ struct mtk_wed_soc_data {
- u32 reset_idx_tx_mask;
- u32 reset_idx_rx_mask;
- } regmap;
-+ u32 tx_ring_desc_size;
- u32 wdma_desc_size;
- };
-
-@@ -35,6 +38,7 @@ struct mtk_wed_hw {
- struct dentry *debugfs_dir;
- struct mtk_wed_device *wed_dev;
- struct mtk_wed_wo *wed_wo;
-+ u32 pcie_base;
- u32 debugfs_reg;
- u32 num_flows;
- u8 version;
-@@ -61,6 +65,16 @@ static inline bool mtk_wed_is_v2(struct
- return hw->version == 2;
- }
-
-+static inline bool mtk_wed_is_v3(struct mtk_wed_hw *hw)
-+{
-+ return hw->version == 3;
-+}
-+
-+static inline bool mtk_wed_is_v3_or_greater(struct mtk_wed_hw *hw)
-+{
-+ return hw->version > 2;
-+}
-+
- static inline void
- wed_w32(struct mtk_wed_device *dev, u32 reg, u32 val)
- {
-@@ -143,6 +157,21 @@ wpdma_txfree_w32(struct mtk_wed_device *
- writel(val, dev->txfree_ring.wpdma + reg);
- }
-
-+static inline u32 mtk_wed_get_pcie_base(struct mtk_wed_device *dev)
-+{
-+ if (!mtk_wed_is_v3_or_greater(dev->hw))
-+ return MTK_WED_PCIE_BASE;
-+
-+ switch (dev->hw->index) {
-+ case 1:
-+ return MTK_WED_PCIE_BASE1;
-+ case 2:
-+ return MTK_WED_PCIE_BASE2;
-+ default:
-+ return MTK_WED_PCIE_BASE0;
-+ }
-+}
-+
- void mtk_wed_add_hw(struct device_node *np, struct mtk_eth *eth,
- void __iomem *wdma, phys_addr_t wdma_phy,
- int index);
---- a/drivers/net/ethernet/mediatek/mtk_wed_mcu.c
-+++ b/drivers/net/ethernet/mediatek/mtk_wed_mcu.c
-@@ -331,10 +331,22 @@ mtk_wed_mcu_load_firmware(struct mtk_wed
- wo->hw->index + 1);
-
- /* load firmware */
-- if (of_device_is_compatible(wo->hw->node, "mediatek,mt7981-wed"))
-- fw_name = MT7981_FIRMWARE_WO;
-- else
-- fw_name = wo->hw->index ? MT7986_FIRMWARE_WO1 : MT7986_FIRMWARE_WO0;
-+ switch (wo->hw->version) {
-+ case 2:
-+ if (of_device_is_compatible(wo->hw->node,
-+ "mediatek,mt7981-wed"))
-+ fw_name = MT7981_FIRMWARE_WO;
-+ else
-+ fw_name = wo->hw->index ? MT7986_FIRMWARE_WO1
-+ : MT7986_FIRMWARE_WO0;
-+ break;
-+ case 3:
-+ fw_name = wo->hw->index ? MT7988_FIRMWARE_WO1
-+ : MT7988_FIRMWARE_WO0;
-+ break;
-+ default:
-+ return -EINVAL;
-+ }
-
- ret = request_firmware(&fw, fw_name, wo->hw->dev);
- if (ret)
-@@ -355,15 +367,16 @@ mtk_wed_mcu_load_firmware(struct mtk_wed
- }
-
- /* set the start address */
-- boot_cr = wo->hw->index ? MTK_WO_MCU_CFG_LS_WA_BOOT_ADDR_ADDR
-- : MTK_WO_MCU_CFG_LS_WM_BOOT_ADDR_ADDR;
-+ if (!mtk_wed_is_v3_or_greater(wo->hw) && wo->hw->index)
-+ boot_cr = MTK_WO_MCU_CFG_LS_WA_BOOT_ADDR_ADDR;
-+ else
-+ boot_cr = MTK_WO_MCU_CFG_LS_WM_BOOT_ADDR_ADDR;
- wo_w32(wo, boot_cr, mem_region[MTK_WED_WO_REGION_EMI].phy_addr >> 16);
- /* wo firmware reset */
- wo_w32(wo, MTK_WO_MCU_CFG_LS_WF_MCCR_CLR_ADDR, 0xc00);
-
-- val = wo_r32(wo, MTK_WO_MCU_CFG_LS_WF_MCU_CFG_WM_WA_ADDR);
-- val |= wo->hw->index ? MTK_WO_MCU_CFG_LS_WF_WM_WA_WA_CPU_RSTB_MASK
-- : MTK_WO_MCU_CFG_LS_WF_WM_WA_WM_CPU_RSTB_MASK;
-+ val = wo_r32(wo, MTK_WO_MCU_CFG_LS_WF_MCU_CFG_WM_WA_ADDR) |
-+ MTK_WO_MCU_CFG_LS_WF_WM_WA_WM_CPU_RSTB_MASK;
- wo_w32(wo, MTK_WO_MCU_CFG_LS_WF_MCU_CFG_WM_WA_ADDR, val);
- out:
- release_firmware(fw);
-@@ -398,3 +411,5 @@ int mtk_wed_mcu_init(struct mtk_wed_wo *
- MODULE_FIRMWARE(MT7981_FIRMWARE_WO);
- MODULE_FIRMWARE(MT7986_FIRMWARE_WO0);
- MODULE_FIRMWARE(MT7986_FIRMWARE_WO1);
-+MODULE_FIRMWARE(MT7988_FIRMWARE_WO0);
-+MODULE_FIRMWARE(MT7988_FIRMWARE_WO1);
---- a/drivers/net/ethernet/mediatek/mtk_wed_regs.h
-+++ b/drivers/net/ethernet/mediatek/mtk_wed_regs.h
-@@ -13,6 +13,9 @@
- #define MTK_WDMA_DESC_CTRL_LAST_SEG0 BIT(30)
- #define MTK_WDMA_DESC_CTRL_DMA_DONE BIT(31)
-
-+#define MTK_WDMA_TXD0_DESC_INFO_DMA_DONE BIT(29)
-+#define MTK_WDMA_TXD1_DESC_INFO_DMA_DONE BIT(31)
-+
- struct mtk_wdma_desc {
- __le32 buf0;
- __le32 ctrl;
-@@ -37,6 +40,7 @@ struct mtk_wdma_desc {
- #define MTK_WED_RESET_WDMA_INT_AGENT BIT(19)
- #define MTK_WED_RESET_RX_RRO_QM BIT(20)
- #define MTK_WED_RESET_RX_ROUTE_QM BIT(21)
-+#define MTK_WED_RESET_TX_AMSDU BIT(22)
- #define MTK_WED_RESET_WED BIT(31)
-
- #define MTK_WED_CTRL 0x00c
-@@ -44,6 +48,9 @@ struct mtk_wdma_desc {
- #define MTK_WED_CTRL_WPDMA_INT_AGENT_BUSY BIT(1)
- #define MTK_WED_CTRL_WDMA_INT_AGENT_EN BIT(2)
- #define MTK_WED_CTRL_WDMA_INT_AGENT_BUSY BIT(3)
-+#define MTK_WED_CTRL_WED_RX_IND_CMD_EN BIT(5)
-+#define MTK_WED_CTRL_WED_RX_PG_BM_EN BIT(6)
-+#define MTK_WED_CTRL_WED_RX_PG_BM_BUSY BIT(7)
- #define MTK_WED_CTRL_WED_TX_BM_EN BIT(8)
- #define MTK_WED_CTRL_WED_TX_BM_BUSY BIT(9)
- #define MTK_WED_CTRL_WED_TX_FREE_AGENT_EN BIT(10)
-@@ -54,9 +61,14 @@ struct mtk_wdma_desc {
- #define MTK_WED_CTRL_RX_RRO_QM_BUSY BIT(15)
- #define MTK_WED_CTRL_RX_ROUTE_QM_EN BIT(16)
- #define MTK_WED_CTRL_RX_ROUTE_QM_BUSY BIT(17)
-+#define MTK_WED_CTRL_TX_TKID_ALI_EN BIT(20)
-+#define MTK_WED_CTRL_TX_TKID_ALI_BUSY BIT(21)
-+#define MTK_WED_CTRL_TX_AMSDU_EN BIT(22)
-+#define MTK_WED_CTRL_TX_AMSDU_BUSY BIT(23)
- #define MTK_WED_CTRL_FINAL_DIDX_READ BIT(24)
- #define MTK_WED_CTRL_ETH_DMAD_FMT BIT(25)
- #define MTK_WED_CTRL_MIB_READ_CLEAR BIT(28)
-+#define MTK_WED_CTRL_FLD_MIB_RD_CLR BIT(28)
-
- #define MTK_WED_EXT_INT_STATUS 0x020
- #define MTK_WED_EXT_INT_STATUS_TF_LEN_ERR BIT(0)
-@@ -89,6 +101,7 @@ struct mtk_wdma_desc {
- #define MTK_WED_EXT_INT_MASK 0x028
- #define MTK_WED_EXT_INT_MASK1 0x02c
- #define MTK_WED_EXT_INT_MASK2 0x030
-+#define MTK_WED_EXT_INT_MASK3 0x034
-
- #define MTK_WED_STATUS 0x060
- #define MTK_WED_STATUS_TX GENMASK(15, 8)
-@@ -96,9 +109,14 @@ struct mtk_wdma_desc {
- #define MTK_WED_TX_BM_CTRL 0x080
- #define MTK_WED_TX_BM_CTRL_VLD_GRP_NUM GENMASK(6, 0)
- #define MTK_WED_TX_BM_CTRL_RSV_GRP_NUM GENMASK(22, 16)
-+#define MTK_WED_TX_BM_CTRL_LEGACY_EN BIT(26)
-+#define MTK_WED_TX_TKID_CTRL_FREE_FORMAT BIT(27)
- #define MTK_WED_TX_BM_CTRL_PAUSE BIT(28)
-
- #define MTK_WED_TX_BM_BASE 0x084
-+#define MTK_WED_TX_BM_INIT_PTR 0x088
-+#define MTK_WED_TX_BM_SW_TAIL_IDX GENMASK(16, 0)
-+#define MTK_WED_TX_BM_INIT_SW_TAIL_IDX BIT(16)
-
- #define MTK_WED_TX_BM_TKID_START GENMASK(15, 0)
- #define MTK_WED_TX_BM_TKID_END GENMASK(31, 16)
-@@ -122,6 +140,9 @@ struct mtk_wdma_desc {
- #define MTK_WED_TX_TKID_CTRL_RSV_GRP_NUM GENMASK(22, 16)
- #define MTK_WED_TX_TKID_CTRL_PAUSE BIT(28)
-
-+#define MTK_WED_TX_TKID_CTRL_VLD_GRP_NUM_V3 GENMASK(7, 0)
-+#define MTK_WED_TX_TKID_CTRL_RSV_GRP_NUM_V3 GENMASK(23, 16)
-+
- #define MTK_WED_TX_TKID_DYN_THR 0x0e0
- #define MTK_WED_TX_TKID_DYN_THR_LO GENMASK(6, 0)
- #define MTK_WED_TX_TKID_DYN_THR_HI GENMASK(22, 16)
-@@ -199,12 +220,15 @@ struct mtk_wdma_desc {
- #define MTK_WED_WPDMA_GLO_CFG_RX_DRV_R1_PKT_PROC BIT(5)
- #define MTK_WED_WPDMA_GLO_CFG_RX_DRV_R0_CRX_SYNC BIT(6)
- #define MTK_WED_WPDMA_GLO_CFG_RX_DRV_R1_CRX_SYNC BIT(7)
--#define MTK_WED_WPDMA_GLO_CFG_RX_DRV_EVENT_PKT_FMT_VER GENMASK(18, 16)
-+#define MTK_WED_WPDMA_GLO_CFG_RX_DRV_EVENT_PKT_FMT_VER GENMASK(15, 12)
-+#define MTK_WED_WPDMA_GLO_CFG_RX_DRV_UNS_VER_FORCE_4 BIT(18)
- #define MTK_WED_WPDMA_GLO_CFG_RX_DRV_UNSUPPORT_FMT BIT(19)
--#define MTK_WED_WPDMA_GLO_CFG_RX_DRV_UEVENT_PKT_FMT_CHK BIT(20)
-+#define MTK_WED_WPDMA_GLO_CFG_RX_DRV_EVENT_PKT_FMT_CHK BIT(20)
- #define MTK_WED_WPDMA_GLO_CFG_RX_DDONE2_WR BIT(21)
- #define MTK_WED_WPDMA_GLO_CFG_TX_TKID_KEEP BIT(24)
-+#define MTK_WED_WPDMA_GLO_CFG_TX_DDONE_CHK_LAST BIT(25)
- #define MTK_WED_WPDMA_GLO_CFG_TX_DMAD_DW3_PREV BIT(28)
-+#define MTK_WED_WPDMA_GLO_CFG_TX_DDONE_CHK BIT(30)
-
- #define MTK_WED_WPDMA_RESET_IDX 0x50c
- #define MTK_WED_WPDMA_RESET_IDX_TX GENMASK(3, 0)
-@@ -250,9 +274,10 @@ struct mtk_wdma_desc {
- #define MTK_WED_PCIE_INT_TRIGGER_STATUS BIT(16)
-
- #define MTK_WED_PCIE_INT_CTRL 0x57c
--#define MTK_WED_PCIE_INT_CTRL_MSK_EN_POLA BIT(20)
--#define MTK_WED_PCIE_INT_CTRL_SRC_SEL GENMASK(17, 16)
- #define MTK_WED_PCIE_INT_CTRL_POLL_EN GENMASK(13, 12)
-+#define MTK_WED_PCIE_INT_CTRL_SRC_SEL GENMASK(17, 16)
-+#define MTK_WED_PCIE_INT_CTRL_MSK_EN_POLA BIT(20)
-+#define MTK_WED_PCIE_INT_CTRL_MSK_IRQ_FILTER BIT(21)
-
- #define MTK_WED_WPDMA_CFG_BASE 0x580
- #define MTK_WED_WPDMA_CFG_INT_MASK 0x584
-@@ -286,6 +311,20 @@ struct mtk_wdma_desc {
- #define MTK_WED_WPDMA_RX_D_PROCESSED_MIB(_n) (0x784 + (_n) * 4)
- #define MTK_WED_WPDMA_RX_D_COHERENT_MIB 0x78c
-
-+#define MTK_WED_WPDMA_RX_D_PREF_CFG 0x7b4
-+#define MTK_WED_WPDMA_RX_D_PREF_EN BIT(0)
-+#define MTK_WED_WPDMA_RX_D_PREF_BURST_SIZE GENMASK(12, 8)
-+#define MTK_WED_WPDMA_RX_D_PREF_LOW_THRES GENMASK(21, 16)
-+
-+#define MTK_WED_WPDMA_RX_D_PREF_RX0_SIDX 0x7b8
-+#define MTK_WED_WPDMA_RX_D_PREF_SIDX_IDX_CLR BIT(15)
-+
-+#define MTK_WED_WPDMA_RX_D_PREF_RX1_SIDX 0x7bc
-+
-+#define MTK_WED_WPDMA_RX_D_PREF_FIFO_CFG 0x7c0
-+#define MTK_WED_WPDMA_RX_D_PREF_FIFO_CFG_R0_CLR BIT(0)
-+#define MTK_WED_WPDMA_RX_D_PREF_FIFO_CFG_R1_CLR BIT(16)
-+
- #define MTK_WED_WDMA_RING_TX 0x800
-
- #define MTK_WED_WDMA_TX_MIB 0x810
-@@ -293,6 +332,18 @@ struct mtk_wdma_desc {
- #define MTK_WED_WDMA_RING_RX(_n) (0x900 + (_n) * 0x10)
- #define MTK_WED_WDMA_RX_THRES(_n) (0x940 + (_n) * 0x4)
-
-+#define MTK_WED_WDMA_RX_PREF_CFG 0x950
-+#define MTK_WED_WDMA_RX_PREF_EN BIT(0)
-+#define MTK_WED_WDMA_RX_PREF_BURST_SIZE GENMASK(12, 8)
-+#define MTK_WED_WDMA_RX_PREF_LOW_THRES GENMASK(21, 16)
-+#define MTK_WED_WDMA_RX_PREF_RX0_SIDX_CLR BIT(24)
-+#define MTK_WED_WDMA_RX_PREF_RX1_SIDX_CLR BIT(25)
-+#define MTK_WED_WDMA_RX_PREF_DDONE2_EN BIT(26)
-+
-+#define MTK_WED_WDMA_RX_PREF_FIFO_CFG 0x95C
-+#define MTK_WED_WDMA_RX_PREF_FIFO_RX0_CLR BIT(0)
-+#define MTK_WED_WDMA_RX_PREF_FIFO_RX1_CLR BIT(16)
-+
- #define MTK_WED_WDMA_GLO_CFG 0xa04
- #define MTK_WED_WDMA_GLO_CFG_TX_DRV_EN BIT(0)
- #define MTK_WED_WDMA_GLO_CFG_TX_DDONE_CHK BIT(1)
-@@ -325,6 +376,7 @@ struct mtk_wdma_desc {
- #define MTK_WED_WDMA_INT_TRIGGER_RX_DONE GENMASK(17, 16)
-
- #define MTK_WED_WDMA_INT_CTRL 0xa2c
-+#define MTK_WED_WDMA_INT_POLL_PRD GENMASK(7, 0)
- #define MTK_WED_WDMA_INT_CTRL_POLL_SRC_SEL GENMASK(17, 16)
-
- #define MTK_WED_WDMA_CFG_BASE 0xaa0
-@@ -388,6 +440,18 @@ struct mtk_wdma_desc {
- #define MTK_WDMA_INT_GRP1 0x250
- #define MTK_WDMA_INT_GRP2 0x254
-
-+#define MTK_WDMA_PREF_TX_CFG 0x2d0
-+#define MTK_WDMA_PREF_TX_CFG_PREF_EN BIT(0)
-+
-+#define MTK_WDMA_PREF_RX_CFG 0x2dc
-+#define MTK_WDMA_PREF_RX_CFG_PREF_EN BIT(0)
-+
-+#define MTK_WDMA_WRBK_TX_CFG 0x300
-+#define MTK_WDMA_WRBK_TX_CFG_WRBK_EN BIT(30)
-+
-+#define MTK_WDMA_WRBK_RX_CFG 0x344
-+#define MTK_WDMA_WRBK_RX_CFG_WRBK_EN BIT(30)
-+
- #define MTK_PCIE_MIRROR_MAP(n) ((n) ? 0x4 : 0x0)
- #define MTK_PCIE_MIRROR_MAP_EN BIT(0)
- #define MTK_PCIE_MIRROR_MAP_WED_ID BIT(1)
-@@ -401,6 +465,30 @@ struct mtk_wdma_desc {
- #define MTK_WED_RTQM_Q_DBG_BYPASS BIT(5)
- #define MTK_WED_RTQM_TXDMAD_FPORT GENMASK(23, 20)
-
-+#define MTK_WED_RTQM_IGRS0_I2HW_DMAD_CNT 0xb1c
-+#define MTK_WED_RTQM_IGRS0_I2H_DMAD_CNT(_n) (0xb20 + (_n) * 0x4)
-+#define MTK_WED_RTQM_IGRS0_I2HW_PKT_CNT 0xb28
-+#define MTK_WED_RTQM_IGRS0_I2H_PKT_CNT(_n) (0xb2c + (_n) * 0x4)
-+#define MTK_WED_RTQM_IGRS0_FDROP_CNT 0xb34
-+
-+#define MTK_WED_RTQM_IGRS1_I2HW_DMAD_CNT 0xb44
-+#define MTK_WED_RTQM_IGRS1_I2H_DMAD_CNT(_n) (0xb48 + (_n) * 0x4)
-+#define MTK_WED_RTQM_IGRS1_I2HW_PKT_CNT 0xb50
-+#define MTK_WED_RTQM_IGRS1_I2H_PKT_CNT(_n) (0xb54 + (_n) * 0x4)
-+#define MTK_WED_RTQM_IGRS1_FDROP_CNT 0xb5c
-+
-+#define MTK_WED_RTQM_IGRS2_I2HW_DMAD_CNT 0xb6c
-+#define MTK_WED_RTQM_IGRS2_I2H_DMAD_CNT(_n) (0xb70 + (_n) * 0x4)
-+#define MTK_WED_RTQM_IGRS2_I2HW_PKT_CNT 0xb78
-+#define MTK_WED_RTQM_IGRS2_I2H_PKT_CNT(_n) (0xb7c + (_n) * 0x4)
-+#define MTK_WED_RTQM_IGRS2_FDROP_CNT 0xb84
-+
-+#define MTK_WED_RTQM_IGRS3_I2HW_DMAD_CNT 0xb94
-+#define MTK_WED_RTQM_IGRS3_I2H_DMAD_CNT(_n) (0xb98 + (_n) * 0x4)
-+#define MTK_WED_RTQM_IGRS3_I2HW_PKT_CNT 0xba0
-+#define MTK_WED_RTQM_IGRS3_I2H_PKT_CNT(_n) (0xba4 + (_n) * 0x4)
-+#define MTK_WED_RTQM_IGRS3_FDROP_CNT 0xbac
-+
- #define MTK_WED_RTQM_R2H_MIB(_n) (0xb70 + (_n) * 0x4)
- #define MTK_WED_RTQM_R2Q_MIB(_n) (0xb78 + (_n) * 0x4)
- #define MTK_WED_RTQM_Q2N_MIB 0xb80
-@@ -409,6 +497,24 @@ struct mtk_wdma_desc {
- #define MTK_WED_RTQM_Q2B_MIB 0xb8c
- #define MTK_WED_RTQM_PFDBK_MIB 0xb90
-
-+#define MTK_WED_RTQM_ENQ_CFG0 0xbb8
-+#define MTK_WED_RTQM_ENQ_CFG_TXDMAD_FPORT GENMASK(15, 12)
-+
-+#define MTK_WED_RTQM_FDROP_MIB 0xb84
-+#define MTK_WED_RTQM_ENQ_I2Q_DMAD_CNT 0xbbc
-+#define MTK_WED_RTQM_ENQ_I2N_DMAD_CNT 0xbc0
-+#define MTK_WED_RTQM_ENQ_I2Q_PKT_CNT 0xbc4
-+#define MTK_WED_RTQM_ENQ_I2N_PKT_CNT 0xbc8
-+#define MTK_WED_RTQM_ENQ_USED_ENTRY_CNT 0xbcc
-+#define MTK_WED_RTQM_ENQ_ERR_CNT 0xbd0
-+
-+#define MTK_WED_RTQM_DEQ_DMAD_CNT 0xbd8
-+#define MTK_WED_RTQM_DEQ_Q2I_DMAD_CNT 0xbdc
-+#define MTK_WED_RTQM_DEQ_PKT_CNT 0xbe0
-+#define MTK_WED_RTQM_DEQ_Q2I_PKT_CNT 0xbe4
-+#define MTK_WED_RTQM_DEQ_USED_PFDBK_CNT 0xbe8
-+#define MTK_WED_RTQM_DEQ_ERR_CNT 0xbec
-+
- #define MTK_WED_RROQM_GLO_CFG 0xc04
- #define MTK_WED_RROQM_RST_IDX 0xc08
- #define MTK_WED_RROQM_RST_IDX_MIOD BIT(0)
-@@ -458,7 +564,116 @@ struct mtk_wdma_desc {
- #define MTK_WED_RX_BM_INTF 0xd9c
- #define MTK_WED_RX_BM_ERR_STS 0xda8
-
-+#define MTK_RRO_IND_CMD_SIGNATURE 0xe00
-+#define MTK_RRO_IND_CMD_DMA_IDX GENMASK(11, 0)
-+#define MTK_RRO_IND_CMD_MAGIC_CNT GENMASK(30, 28)
-+
-+#define MTK_WED_IND_CMD_RX_CTRL0 0xe04
-+#define MTK_WED_IND_CMD_PROC_IDX GENMASK(11, 0)
-+#define MTK_WED_IND_CMD_PREFETCH_FREE_CNT GENMASK(19, 16)
-+#define MTK_WED_IND_CMD_MAGIC_CNT GENMASK(30, 28)
-+
-+#define MTK_WED_IND_CMD_RX_CTRL1 0xe08
-+#define MTK_WED_IND_CMD_RX_CTRL2 0xe0c
-+#define MTK_WED_IND_CMD_MAX_CNT GENMASK(11, 0)
-+#define MTK_WED_IND_CMD_BASE_M GENMASK(19, 16)
-+
-+#define MTK_WED_RRO_CFG0 0xe10
-+#define MTK_WED_RRO_CFG1 0xe14
-+#define MTK_WED_RRO_CFG1_MAX_WIN_SZ GENMASK(31, 29)
-+#define MTK_WED_RRO_CFG1_ACK_SN_BASE_M GENMASK(19, 16)
-+#define MTK_WED_RRO_CFG1_PARTICL_SE_ID GENMASK(11, 0)
-+
-+#define MTK_WED_ADDR_ELEM_CFG0 0xe18
-+#define MTK_WED_ADDR_ELEM_CFG1 0xe1c
-+#define MTK_WED_ADDR_ELEM_PREFETCH_FREE_CNT GENMASK(19, 16)
-+
-+#define MTK_WED_ADDR_ELEM_TBL_CFG 0xe20
-+#define MTK_WED_ADDR_ELEM_TBL_OFFSET GENMASK(6, 0)
-+#define MTK_WED_ADDR_ELEM_TBL_RD_RDY BIT(28)
-+#define MTK_WED_ADDR_ELEM_TBL_WR_RDY BIT(29)
-+#define MTK_WED_ADDR_ELEM_TBL_RD BIT(30)
-+#define MTK_WED_ADDR_ELEM_TBL_WR BIT(31)
-+
-+#define MTK_WED_RADDR_ELEM_TBL_WDATA 0xe24
-+#define MTK_WED_RADDR_ELEM_TBL_RDATA 0xe28
-+
-+#define MTK_WED_PN_CHECK_CFG 0xe30
-+#define MTK_WED_PN_CHECK_SE_ID GENMASK(11, 0)
-+#define MTK_WED_PN_CHECK_RD_RDY BIT(28)
-+#define MTK_WED_PN_CHECK_WR_RDY BIT(29)
-+#define MTK_WED_PN_CHECK_RD BIT(30)
-+#define MTK_WED_PN_CHECK_WR BIT(31)
-+
-+#define MTK_WED_PN_CHECK_WDATA_M 0xe38
-+#define MTK_WED_PN_CHECK_IS_FIRST BIT(17)
-+
-+#define MTK_WED_RRO_MSDU_PG_RING_CFG(_n) (0xe44 + (_n) * 0x8)
-+
-+#define MTK_WED_RRO_MSDU_PG_RING2_CFG 0xe58
-+#define MTK_WED_RRO_MSDU_PG_DRV_CLR BIT(26)
-+#define MTK_WED_RRO_MSDU_PG_DRV_EN BIT(31)
-+
-+#define MTK_WED_RRO_MSDU_PG_CTRL0(_n) (0xe5c + (_n) * 0xc)
-+#define MTK_WED_RRO_MSDU_PG_CTRL1(_n) (0xe60 + (_n) * 0xc)
-+#define MTK_WED_RRO_MSDU_PG_CTRL2(_n) (0xe64 + (_n) * 0xc)
-+
-+#define MTK_WED_RRO_RX_D_RX(_n) (0xe80 + (_n) * 0x10)
-+
-+#define MTK_WED_RRO_RX_MAGIC_CNT BIT(13)
-+
-+#define MTK_WED_RRO_RX_D_CFG(_n) (0xea0 + (_n) * 0x4)
-+#define MTK_WED_RRO_RX_D_DRV_CLR BIT(26)
-+#define MTK_WED_RRO_RX_D_DRV_EN BIT(31)
-+
-+#define MTK_WED_RRO_PG_BM_RX_DMAM 0xeb0
-+#define MTK_WED_RRO_PG_BM_RX_SDL0 GENMASK(13, 0)
-+
-+#define MTK_WED_RRO_PG_BM_BASE 0xeb4
-+#define MTK_WED_RRO_PG_BM_INIT_PTR 0xeb8
-+#define MTK_WED_RRO_PG_BM_SW_TAIL_IDX GENMASK(15, 0)
-+#define MTK_WED_RRO_PG_BM_INIT_SW_TAIL_IDX BIT(16)
-+
-+#define MTK_WED_WPDMA_INT_CTRL_RRO_RX 0xeec
-+#define MTK_WED_WPDMA_INT_CTRL_RRO_RX0_EN BIT(0)
-+#define MTK_WED_WPDMA_INT_CTRL_RRO_RX0_CLR BIT(1)
-+#define MTK_WED_WPDMA_INT_CTRL_RRO_RX0_DONE_TRIG GENMASK(6, 2)
-+#define MTK_WED_WPDMA_INT_CTRL_RRO_RX1_EN BIT(8)
-+#define MTK_WED_WPDMA_INT_CTRL_RRO_RX1_CLR BIT(9)
-+#define MTK_WED_WPDMA_INT_CTRL_RRO_RX1_DONE_TRIG GENMASK(14, 10)
-+
-+#define MTK_WED_WPDMA_INT_CTRL_RRO_MSDU_PG 0xef4
-+#define MTK_WED_WPDMA_INT_CTRL_RRO_PG0_EN BIT(0)
-+#define MTK_WED_WPDMA_INT_CTRL_RRO_PG0_CLR BIT(1)
-+#define MTK_WED_WPDMA_INT_CTRL_RRO_PG0_DONE_TRIG GENMASK(6, 2)
-+#define MTK_WED_WPDMA_INT_CTRL_RRO_PG1_EN BIT(8)
-+#define MTK_WED_WPDMA_INT_CTRL_RRO_PG1_CLR BIT(9)
-+#define MTK_WED_WPDMA_INT_CTRL_RRO_PG1_DONE_TRIG GENMASK(14, 10)
-+#define MTK_WED_WPDMA_INT_CTRL_RRO_PG2_EN BIT(16)
-+#define MTK_WED_WPDMA_INT_CTRL_RRO_PG2_CLR BIT(17)
-+#define MTK_WED_WPDMA_INT_CTRL_RRO_PG2_DONE_TRIG GENMASK(22, 18)
-+
-+#define MTK_WED_RX_IND_CMD_CNT0 0xf20
-+#define MTK_WED_RX_IND_CMD_DBG_CNT_EN BIT(31)
-+
-+#define MTK_WED_RX_IND_CMD_CNT(_n) (0xf20 + (_n) * 0x4)
-+#define MTK_WED_IND_CMD_MAGIC_CNT_FAIL_CNT GENMASK(15, 0)
-+
-+#define MTK_WED_RX_ADDR_ELEM_CNT(_n) (0xf48 + (_n) * 0x4)
-+#define MTK_WED_ADDR_ELEM_SIG_FAIL_CNT GENMASK(15, 0)
-+#define MTK_WED_ADDR_ELEM_FIRST_SIG_FAIL_CNT GENMASK(31, 16)
-+#define MTK_WED_ADDR_ELEM_ACKSN_CNT GENMASK(27, 0)
-+
-+#define MTK_WED_RX_MSDU_PG_CNT(_n) (0xf5c + (_n) * 0x4)
-+
-+#define MTK_WED_RX_PN_CHK_CNT 0xf70
-+#define MTK_WED_PN_CHK_FAIL_CNT GENMASK(15, 0)
-+
- #define MTK_WED_WOCPU_VIEW_MIOD_BASE 0x8000
- #define MTK_WED_PCIE_INT_MASK 0x0
-
-+#define MTK_WED_PCIE_BASE 0x11280000
-+#define MTK_WED_PCIE_BASE0 0x11300000
-+#define MTK_WED_PCIE_BASE1 0x11310000
-+#define MTK_WED_PCIE_BASE2 0x11290000
- #endif
---- a/drivers/net/ethernet/mediatek/mtk_wed_wo.h
-+++ b/drivers/net/ethernet/mediatek/mtk_wed_wo.h
-@@ -91,6 +91,8 @@ enum mtk_wed_dummy_cr_idx {
- #define MT7981_FIRMWARE_WO "mediatek/mt7981_wo.bin"
- #define MT7986_FIRMWARE_WO0 "mediatek/mt7986_wo_0.bin"
- #define MT7986_FIRMWARE_WO1 "mediatek/mt7986_wo_1.bin"
-+#define MT7988_FIRMWARE_WO0 "mediatek/mt7988_wo_0.bin"
-+#define MT7988_FIRMWARE_WO1 "mediatek/mt7988_wo_1.bin"
-
- #define MTK_WO_MCU_CFG_LS_BASE 0
- #define MTK_WO_MCU_CFG_LS_HW_VER_ADDR (MTK_WO_MCU_CFG_LS_BASE + 0x000)
---- a/include/linux/soc/mediatek/mtk_wed.h
-+++ b/include/linux/soc/mediatek/mtk_wed.h
-@@ -138,6 +138,8 @@ struct mtk_wed_device {
- u32 wpdma_rx;
-
- bool wcid_512;
-+ bool hw_rro;
-+ bool msi;
-
- u16 token_start;
- unsigned int nbuf;
-@@ -211,10 +213,12 @@ mtk_wed_device_attach(struct mtk_wed_dev
- return ret;
- }
-
--static inline bool
--mtk_wed_get_rx_capa(struct mtk_wed_device *dev)
-+static inline bool mtk_wed_get_rx_capa(struct mtk_wed_device *dev)
- {
- #ifdef CONFIG_NET_MEDIATEK_SOC_WED
-+ if (dev->version == 3)
-+ return dev->wlan.hw_rro;
-+
- return dev->version != 1;
- #else
- return false;
+++ /dev/null
-Date: Mon, 18 Sep 2023 12:29:14 +0200
-Subject: [PATCH] net: ethernet: mtk_wed: refactor mtk_wed_check_wfdma_rx_fill
- routine
-
-Refactor mtk_wed_check_wfdma_rx_fill() in order to be reused adding HW
-receive offload support for MT7988 SoC.
-
----
-
---- a/drivers/net/ethernet/mediatek/mtk_wed.c
-+++ b/drivers/net/ethernet/mediatek/mtk_wed.c
-@@ -586,22 +586,15 @@ mtk_wed_set_512_support(struct mtk_wed_d
- }
- }
-
--#define MTK_WFMDA_RX_DMA_EN BIT(2)
--static void
--mtk_wed_check_wfdma_rx_fill(struct mtk_wed_device *dev, int idx)
-+static int
-+mtk_wed_check_wfdma_rx_fill(struct mtk_wed_device *dev,
-+ struct mtk_wed_ring *ring)
- {
-- u32 val;
- int i;
-
-- if (!(dev->rx_ring[idx].flags & MTK_WED_RING_CONFIGURED))
-- return; /* queue is not configured by mt76 */
--
- for (i = 0; i < 3; i++) {
-- u32 cur_idx;
-+ u32 cur_idx = readl(ring->wpdma + MTK_WED_RING_OFS_CPU_IDX);
-
-- cur_idx = wed_r32(dev,
-- MTK_WED_WPDMA_RING_RX_DATA(idx) +
-- MTK_WED_RING_OFS_CPU_IDX);
- if (cur_idx == MTK_WED_RX_RING_SIZE - 1)
- break;
-
-@@ -610,12 +603,10 @@ mtk_wed_check_wfdma_rx_fill(struct mtk_w
-
- if (i == 3) {
- dev_err(dev->hw->dev, "rx dma enable failed\n");
-- return;
-+ return -ETIMEDOUT;
- }
-
-- val = wifi_r32(dev, dev->wlan.wpdma_rx_glo - dev->wlan.phy_base) |
-- MTK_WFMDA_RX_DMA_EN;
-- wifi_w32(dev, dev->wlan.wpdma_rx_glo - dev->wlan.phy_base, val);
-+ return 0;
- }
-
- static void
-@@ -1545,6 +1536,7 @@ mtk_wed_configure_irq(struct mtk_wed_dev
- wed_w32(dev, MTK_WED_INT_MASK, irq_mask);
- }
-
-+#define MTK_WFMDA_RX_DMA_EN BIT(2)
- static void
- mtk_wed_dma_enable(struct mtk_wed_device *dev)
- {
-@@ -1632,8 +1624,26 @@ mtk_wed_dma_enable(struct mtk_wed_device
- wdma_set(dev, MTK_WDMA_WRBK_TX_CFG, MTK_WDMA_WRBK_TX_CFG_WRBK_EN);
- }
-
-- for (i = 0; i < MTK_WED_RX_QUEUES; i++)
-- mtk_wed_check_wfdma_rx_fill(dev, i);
-+ for (i = 0; i < MTK_WED_RX_QUEUES; i++) {
-+ struct mtk_wed_ring *ring = &dev->rx_ring[i];
-+ u32 val;
-+
-+ if (!(ring->flags & MTK_WED_RING_CONFIGURED))
-+ continue; /* queue is not configured by mt76 */
-+
-+ if (mtk_wed_check_wfdma_rx_fill(dev, ring)) {
-+ dev_err(dev->hw->dev,
-+ "rx_ring(%d) dma enable failed\n", i);
-+ continue;
-+ }
-+
-+ val = wifi_r32(dev,
-+ dev->wlan.wpdma_rx_glo -
-+ dev->wlan.phy_base) | MTK_WFMDA_RX_DMA_EN;
-+ wifi_w32(dev,
-+ dev->wlan.wpdma_rx_glo - dev->wlan.phy_base,
-+ val);
-+ }
- }
-
- static void
+++ /dev/null
-Date: Mon, 18 Sep 2023 12:29:15 +0200
-Subject: [PATCH] net: ethernet: mtk_wed: introduce partial AMSDU offload
- support for MT7988
-
-Introduce partial AMSDU offload support for MT7988 SoC in order to merge
-in hw packets belonging to the same AMSDU before passing them to the
-WLAN nic.
-
----
-
---- a/drivers/net/ethernet/mediatek/mtk_ppe.c
-+++ b/drivers/net/ethernet/mediatek/mtk_ppe.c
-@@ -425,7 +425,8 @@ int mtk_foe_entry_set_pppoe(struct mtk_e
- }
-
- int mtk_foe_entry_set_wdma(struct mtk_eth *eth, struct mtk_foe_entry *entry,
-- int wdma_idx, int txq, int bss, int wcid)
-+ int wdma_idx, int txq, int bss, int wcid,
-+ bool amsdu_en)
- {
- struct mtk_foe_mac_info *l2 = mtk_foe_entry_l2(eth, entry);
- u32 *ib2 = mtk_foe_entry_ib2(eth, entry);
-@@ -437,6 +438,7 @@ int mtk_foe_entry_set_wdma(struct mtk_et
- MTK_FOE_IB2_WDMA_WINFO_V2;
- l2->w3info = FIELD_PREP(MTK_FOE_WINFO_WCID_V3, wcid) |
- FIELD_PREP(MTK_FOE_WINFO_BSS_V3, bss);
-+ l2->amsdu = FIELD_PREP(MTK_FOE_WINFO_AMSDU_EN, amsdu_en);
- break;
- case 2:
- *ib2 &= ~MTK_FOE_IB2_PORT_MG_V2;
---- a/drivers/net/ethernet/mediatek/mtk_ppe.h
-+++ b/drivers/net/ethernet/mediatek/mtk_ppe.h
-@@ -88,13 +88,13 @@ enum {
- #define MTK_FOE_WINFO_BSS_V3 GENMASK(23, 16)
- #define MTK_FOE_WINFO_WCID_V3 GENMASK(15, 0)
-
--#define MTK_FOE_WINFO_PAO_USR_INFO GENMASK(15, 0)
--#define MTK_FOE_WINFO_PAO_TID GENMASK(19, 16)
--#define MTK_FOE_WINFO_PAO_IS_FIXEDRATE BIT(20)
--#define MTK_FOE_WINFO_PAO_IS_PRIOR BIT(21)
--#define MTK_FOE_WINFO_PAO_IS_SP BIT(22)
--#define MTK_FOE_WINFO_PAO_HF BIT(23)
--#define MTK_FOE_WINFO_PAO_AMSDU_EN BIT(24)
-+#define MTK_FOE_WINFO_AMSDU_USR_INFO GENMASK(15, 0)
-+#define MTK_FOE_WINFO_AMSDU_TID GENMASK(19, 16)
-+#define MTK_FOE_WINFO_AMSDU_IS_FIXEDRATE BIT(20)
-+#define MTK_FOE_WINFO_AMSDU_IS_PRIOR BIT(21)
-+#define MTK_FOE_WINFO_AMSDU_IS_SP BIT(22)
-+#define MTK_FOE_WINFO_AMSDU_HF BIT(23)
-+#define MTK_FOE_WINFO_AMSDU_EN BIT(24)
-
- enum {
- MTK_FOE_STATE_INVALID,
-@@ -123,7 +123,7 @@ struct mtk_foe_mac_info {
-
- /* netsys_v3 */
- u32 w3info;
-- u32 wpao;
-+ u32 amsdu;
- };
-
- /* software-only entry type */
-@@ -392,7 +392,8 @@ int mtk_foe_entry_set_vlan(struct mtk_et
- int mtk_foe_entry_set_pppoe(struct mtk_eth *eth, struct mtk_foe_entry *entry,
- int sid);
- int mtk_foe_entry_set_wdma(struct mtk_eth *eth, struct mtk_foe_entry *entry,
-- int wdma_idx, int txq, int bss, int wcid);
-+ int wdma_idx, int txq, int bss, int wcid,
-+ bool amsdu_en);
- int mtk_foe_entry_set_queue(struct mtk_eth *eth, struct mtk_foe_entry *entry,
- unsigned int queue);
- int mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_flow_entry *entry);
---- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
-+++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
-@@ -115,6 +115,7 @@ mtk_flow_get_wdma_info(struct net_device
- info->queue = path->mtk_wdma.queue;
- info->bss = path->mtk_wdma.bss;
- info->wcid = path->mtk_wdma.wcid;
-+ info->amsdu = path->mtk_wdma.amsdu;
-
- return 0;
- }
-@@ -196,7 +197,7 @@ mtk_flow_set_output_device(struct mtk_et
-
- if (mtk_flow_get_wdma_info(dev, dest_mac, &info) == 0) {
- mtk_foe_entry_set_wdma(eth, foe, info.wdma_idx, info.queue,
-- info.bss, info.wcid);
-+ info.bss, info.wcid, info.amsdu);
- if (mtk_is_netsys_v2_or_greater(eth)) {
- switch (info.wdma_idx) {
- case 0:
---- a/drivers/net/ethernet/mediatek/mtk_wed.c
-+++ b/drivers/net/ethernet/mediatek/mtk_wed.c
-@@ -30,6 +30,8 @@
- #define MTK_WED_RX_PAGE_BUF_PER_PAGE (PAGE_SIZE / 128)
- #define MTK_WED_RX_RING_SIZE 1536
- #define MTK_WED_RX_PG_BM_CNT 8192
-+#define MTK_WED_AMSDU_BUF_SIZE (PAGE_SIZE << 4)
-+#define MTK_WED_AMSDU_NPAGES 32
-
- #define MTK_WED_TX_RING_SIZE 2048
- #define MTK_WED_WDMA_RING_SIZE 1024
-@@ -173,6 +175,23 @@ mtk_wdma_rx_reset(struct mtk_wed_device
- return ret;
- }
-
-+static u32
-+mtk_wed_check_busy(struct mtk_wed_device *dev, u32 reg, u32 mask)
-+{
-+ return !!(wed_r32(dev, reg) & mask);
-+}
-+
-+static int
-+mtk_wed_poll_busy(struct mtk_wed_device *dev, u32 reg, u32 mask)
-+{
-+ int sleep = 15000;
-+ int timeout = 100 * sleep;
-+ u32 val;
-+
-+ return read_poll_timeout(mtk_wed_check_busy, val, !val, sleep,
-+ timeout, false, dev, reg, mask);
-+}
-+
- static void
- mtk_wdma_tx_reset(struct mtk_wed_device *dev)
- {
-@@ -336,6 +355,118 @@ out:
- }
-
- static int
-+mtk_wed_amsdu_buffer_alloc(struct mtk_wed_device *dev)
-+{
-+ struct mtk_wed_hw *hw = dev->hw;
-+ struct mtk_wed_amsdu *wed_amsdu;
-+ int i;
-+
-+ if (!mtk_wed_is_v3_or_greater(hw))
-+ return 0;
-+
-+ wed_amsdu = devm_kcalloc(hw->dev, MTK_WED_AMSDU_NPAGES,
-+ sizeof(*wed_amsdu), GFP_KERNEL);
-+ if (!wed_amsdu)
-+ return -ENOMEM;
-+
-+ for (i = 0; i < MTK_WED_AMSDU_NPAGES; i++) {
-+ void *ptr;
-+
-+ /* each segment is 64K */
-+ ptr = (void *)__get_free_pages(GFP_KERNEL | __GFP_NOWARN |
-+ __GFP_ZERO | __GFP_COMP |
-+ GFP_DMA32,
-+ get_order(MTK_WED_AMSDU_BUF_SIZE));
-+ if (!ptr)
-+ goto error;
-+
-+ wed_amsdu[i].txd = ptr;
-+ wed_amsdu[i].txd_phy = dma_map_single(hw->dev, ptr,
-+ MTK_WED_AMSDU_BUF_SIZE,
-+ DMA_TO_DEVICE);
-+ if (dma_mapping_error(hw->dev, wed_amsdu[i].txd_phy))
-+ goto error;
-+ }
-+ dev->hw->wed_amsdu = wed_amsdu;
-+
-+ return 0;
-+
-+error:
-+ for (i--; i >= 0; i--)
-+ dma_unmap_single(hw->dev, wed_amsdu[i].txd_phy,
-+ MTK_WED_AMSDU_BUF_SIZE, DMA_TO_DEVICE);
-+ return -ENOMEM;
-+}
-+
-+static void
-+mtk_wed_amsdu_free_buffer(struct mtk_wed_device *dev)
-+{
-+ struct mtk_wed_amsdu *wed_amsdu = dev->hw->wed_amsdu;
-+ int i;
-+
-+ if (!wed_amsdu)
-+ return;
-+
-+ for (i = 0; i < MTK_WED_AMSDU_NPAGES; i++) {
-+ dma_unmap_single(dev->hw->dev, wed_amsdu[i].txd_phy,
-+ MTK_WED_AMSDU_BUF_SIZE, DMA_TO_DEVICE);
-+ free_pages((unsigned long)wed_amsdu[i].txd,
-+ get_order(MTK_WED_AMSDU_BUF_SIZE));
-+ }
-+}
-+
-+static int
-+mtk_wed_amsdu_init(struct mtk_wed_device *dev)
-+{
-+ struct mtk_wed_amsdu *wed_amsdu = dev->hw->wed_amsdu;
-+ int i, ret;
-+
-+ if (!wed_amsdu)
-+ return 0;
-+
-+ for (i = 0; i < MTK_WED_AMSDU_NPAGES; i++)
-+ wed_w32(dev, MTK_WED_AMSDU_HIFTXD_BASE_L(i),
-+ wed_amsdu[i].txd_phy);
-+
-+ /* init all sta parameter */
-+ wed_w32(dev, MTK_WED_AMSDU_STA_INFO_INIT, MTK_WED_AMSDU_STA_RMVL |
-+ MTK_WED_AMSDU_STA_WTBL_HDRT_MODE |
-+ FIELD_PREP(MTK_WED_AMSDU_STA_MAX_AMSDU_LEN,
-+ dev->wlan.amsdu_max_len >> 8) |
-+ FIELD_PREP(MTK_WED_AMSDU_STA_MAX_AMSDU_NUM,
-+ dev->wlan.amsdu_max_subframes));
-+
-+ wed_w32(dev, MTK_WED_AMSDU_STA_INFO, MTK_WED_AMSDU_STA_INFO_DO_INIT);
-+
-+ ret = mtk_wed_poll_busy(dev, MTK_WED_AMSDU_STA_INFO,
-+ MTK_WED_AMSDU_STA_INFO_DO_INIT);
-+ if (ret) {
-+ dev_err(dev->hw->dev, "amsdu initialization failed\n");
-+ return ret;
-+ }
-+
-+ /* init partial amsdu offload txd src */
-+ wed_set(dev, MTK_WED_AMSDU_HIFTXD_CFG,
-+ FIELD_PREP(MTK_WED_AMSDU_HIFTXD_SRC, dev->hw->index));
-+
-+ /* init qmem */
-+ wed_set(dev, MTK_WED_AMSDU_PSE, MTK_WED_AMSDU_PSE_RESET);
-+ ret = mtk_wed_poll_busy(dev, MTK_WED_MON_AMSDU_QMEM_STS1, BIT(29));
-+ if (ret) {
-+ pr_info("%s: amsdu qmem initialization failed\n", __func__);
-+ return ret;
-+ }
-+
-+ /* eagle E1 PCIE1 tx ring 22 flow control issue */
-+ if (dev->wlan.id == 0x7991)
-+ wed_clr(dev, MTK_WED_AMSDU_FIFO, MTK_WED_AMSDU_IS_PRIOR0_RING);
-+
-+ wed_set(dev, MTK_WED_CTRL, MTK_WED_CTRL_TX_AMSDU_EN);
-+
-+ return 0;
-+}
-+
-+static int
- mtk_wed_tx_buffer_alloc(struct mtk_wed_device *dev)
- {
- u32 desc_size = dev->hw->soc->tx_ring_desc_size;
-@@ -708,6 +839,7 @@ __mtk_wed_detach(struct mtk_wed_device *
-
- mtk_wdma_rx_reset(dev);
- mtk_wed_reset(dev, MTK_WED_RESET_WED);
-+ mtk_wed_amsdu_free_buffer(dev);
- mtk_wed_free_tx_buffer(dev);
- mtk_wed_free_tx_rings(dev);
-
-@@ -1128,23 +1260,6 @@ mtk_wed_ring_reset(struct mtk_wed_ring *
- }
- }
-
--static u32
--mtk_wed_check_busy(struct mtk_wed_device *dev, u32 reg, u32 mask)
--{
-- return !!(wed_r32(dev, reg) & mask);
--}
--
--static int
--mtk_wed_poll_busy(struct mtk_wed_device *dev, u32 reg, u32 mask)
--{
-- int sleep = 15000;
-- int timeout = 100 * sleep;
-- u32 val;
--
-- return read_poll_timeout(mtk_wed_check_busy, val, !val, sleep,
-- timeout, false, dev, reg, mask);
--}
--
- static int
- mtk_wed_rx_reset(struct mtk_wed_device *dev)
- {
-@@ -1691,6 +1806,7 @@ mtk_wed_start(struct mtk_wed_device *dev
- }
-
- mtk_wed_set_512_support(dev, dev->wlan.wcid_512);
-+ mtk_wed_amsdu_init(dev);
-
- mtk_wed_dma_enable(dev);
- dev->running = true;
-@@ -1747,6 +1863,10 @@ mtk_wed_attach(struct mtk_wed_device *de
- if (ret)
- goto out;
-
-+ ret = mtk_wed_amsdu_buffer_alloc(dev);
-+ if (ret)
-+ goto out;
-+
- if (mtk_wed_get_rx_capa(dev)) {
- ret = mtk_wed_rro_alloc(dev);
- if (ret)
---- a/drivers/net/ethernet/mediatek/mtk_wed.h
-+++ b/drivers/net/ethernet/mediatek/mtk_wed.h
-@@ -25,6 +25,11 @@ struct mtk_wed_soc_data {
- u32 wdma_desc_size;
- };
-
-+struct mtk_wed_amsdu {
-+ void *txd;
-+ dma_addr_t txd_phy;
-+};
-+
- struct mtk_wed_hw {
- const struct mtk_wed_soc_data *soc;
- struct device_node *node;
-@@ -38,6 +43,7 @@ struct mtk_wed_hw {
- struct dentry *debugfs_dir;
- struct mtk_wed_device *wed_dev;
- struct mtk_wed_wo *wed_wo;
-+ struct mtk_wed_amsdu *wed_amsdu;
- u32 pcie_base;
- u32 debugfs_reg;
- u32 num_flows;
-@@ -52,6 +58,7 @@ struct mtk_wdma_info {
- u8 queue;
- u16 wcid;
- u8 bss;
-+ u8 amsdu;
- };
-
- #ifdef CONFIG_NET_MEDIATEK_SOC_WED
---- a/drivers/net/ethernet/mediatek/mtk_wed_regs.h
-+++ b/drivers/net/ethernet/mediatek/mtk_wed_regs.h
-@@ -672,6 +672,82 @@ struct mtk_wdma_desc {
- #define MTK_WED_WOCPU_VIEW_MIOD_BASE 0x8000
- #define MTK_WED_PCIE_INT_MASK 0x0
-
-+#define MTK_WED_AMSDU_FIFO 0x1800
-+#define MTK_WED_AMSDU_IS_PRIOR0_RING BIT(10)
-+
-+#define MTK_WED_AMSDU_STA_INFO 0x01810
-+#define MTK_WED_AMSDU_STA_INFO_DO_INIT BIT(0)
-+#define MTK_WED_AMSDU_STA_INFO_SET_INIT BIT(1)
-+
-+#define MTK_WED_AMSDU_STA_INFO_INIT 0x01814
-+#define MTK_WED_AMSDU_STA_WTBL_HDRT_MODE BIT(0)
-+#define MTK_WED_AMSDU_STA_RMVL BIT(1)
-+#define MTK_WED_AMSDU_STA_MAX_AMSDU_LEN GENMASK(7, 2)
-+#define MTK_WED_AMSDU_STA_MAX_AMSDU_NUM GENMASK(11, 8)
-+
-+#define MTK_WED_AMSDU_HIFTXD_BASE_L(_n) (0x1980 + (_n) * 0x4)
-+
-+#define MTK_WED_AMSDU_PSE 0x1910
-+#define MTK_WED_AMSDU_PSE_RESET BIT(16)
-+
-+#define MTK_WED_AMSDU_HIFTXD_CFG 0x1968
-+#define MTK_WED_AMSDU_HIFTXD_SRC GENMASK(16, 15)
-+
-+#define MTK_WED_MON_AMSDU_FIFO_DMAD 0x1a34
-+
-+#define MTK_WED_MON_AMSDU_ENG_DMAD(_n) (0x1a80 + (_n) * 0x50)
-+#define MTK_WED_MON_AMSDU_ENG_QFPL(_n) (0x1a84 + (_n) * 0x50)
-+#define MTK_WED_MON_AMSDU_ENG_QENI(_n) (0x1a88 + (_n) * 0x50)
-+#define MTK_WED_MON_AMSDU_ENG_QENO(_n) (0x1a8c + (_n) * 0x50)
-+#define MTK_WED_MON_AMSDU_ENG_MERG(_n) (0x1a90 + (_n) * 0x50)
-+
-+#define MTK_WED_MON_AMSDU_ENG_CNT8(_n) (0x1a94 + (_n) * 0x50)
-+#define MTK_WED_AMSDU_ENG_MAX_QGPP_CNT GENMASK(10, 0)
-+#define MTK_WED_AMSDU_ENG_MAX_PL_CNT GENMASK(27, 16)
-+
-+#define MTK_WED_MON_AMSDU_ENG_CNT9(_n) (0x1a98 + (_n) * 0x50)
-+#define MTK_WED_AMSDU_ENG_CUR_ENTRY GENMASK(10, 0)
-+#define MTK_WED_AMSDU_ENG_MAX_BUF_MERGED GENMASK(20, 16)
-+#define MTK_WED_AMSDU_ENG_MAX_MSDU_MERGED GENMASK(28, 24)
-+
-+#define MTK_WED_MON_AMSDU_QMEM_STS1 0x1e04
-+
-+#define MTK_WED_MON_AMSDU_QMEM_CNT(_n) (0x1e0c + (_n) * 0x4)
-+#define MTK_WED_AMSDU_QMEM_FQ_CNT GENMASK(27, 16)
-+#define MTK_WED_AMSDU_QMEM_SP_QCNT GENMASK(11, 0)
-+#define MTK_WED_AMSDU_QMEM_TID0_QCNT GENMASK(27, 16)
-+#define MTK_WED_AMSDU_QMEM_TID1_QCNT GENMASK(11, 0)
-+#define MTK_WED_AMSDU_QMEM_TID2_QCNT GENMASK(27, 16)
-+#define MTK_WED_AMSDU_QMEM_TID3_QCNT GENMASK(11, 0)
-+#define MTK_WED_AMSDU_QMEM_TID4_QCNT GENMASK(27, 16)
-+#define MTK_WED_AMSDU_QMEM_TID5_QCNT GENMASK(11, 0)
-+#define MTK_WED_AMSDU_QMEM_TID6_QCNT GENMASK(27, 16)
-+#define MTK_WED_AMSDU_QMEM_TID7_QCNT GENMASK(11, 0)
-+
-+#define MTK_WED_MON_AMSDU_QMEM_PTR(_n) (0x1e20 + (_n) * 0x4)
-+#define MTK_WED_AMSDU_QMEM_FQ_HEAD GENMASK(27, 16)
-+#define MTK_WED_AMSDU_QMEM_SP_QHEAD GENMASK(11, 0)
-+#define MTK_WED_AMSDU_QMEM_TID0_QHEAD GENMASK(27, 16)
-+#define MTK_WED_AMSDU_QMEM_TID1_QHEAD GENMASK(11, 0)
-+#define MTK_WED_AMSDU_QMEM_TID2_QHEAD GENMASK(27, 16)
-+#define MTK_WED_AMSDU_QMEM_TID3_QHEAD GENMASK(11, 0)
-+#define MTK_WED_AMSDU_QMEM_TID4_QHEAD GENMASK(27, 16)
-+#define MTK_WED_AMSDU_QMEM_TID5_QHEAD GENMASK(11, 0)
-+#define MTK_WED_AMSDU_QMEM_TID6_QHEAD GENMASK(27, 16)
-+#define MTK_WED_AMSDU_QMEM_TID7_QHEAD GENMASK(11, 0)
-+#define MTK_WED_AMSDU_QMEM_FQ_TAIL GENMASK(27, 16)
-+#define MTK_WED_AMSDU_QMEM_SP_QTAIL GENMASK(11, 0)
-+#define MTK_WED_AMSDU_QMEM_TID0_QTAIL GENMASK(27, 16)
-+#define MTK_WED_AMSDU_QMEM_TID1_QTAIL GENMASK(11, 0)
-+#define MTK_WED_AMSDU_QMEM_TID2_QTAIL GENMASK(27, 16)
-+#define MTK_WED_AMSDU_QMEM_TID3_QTAIL GENMASK(11, 0)
-+#define MTK_WED_AMSDU_QMEM_TID4_QTAIL GENMASK(27, 16)
-+#define MTK_WED_AMSDU_QMEM_TID5_QTAIL GENMASK(11, 0)
-+#define MTK_WED_AMSDU_QMEM_TID6_QTAIL GENMASK(27, 16)
-+#define MTK_WED_AMSDU_QMEM_TID7_QTAIL GENMASK(11, 0)
-+
-+#define MTK_WED_MON_AMSDU_HIFTXD_FETCH_MSDU(_n) (0x1ec4 + (_n) * 0x4)
-+
- #define MTK_WED_PCIE_BASE 0x11280000
- #define MTK_WED_PCIE_BASE0 0x11300000
- #define MTK_WED_PCIE_BASE1 0x11310000
---- a/include/linux/netdevice.h
-+++ b/include/linux/netdevice.h
-@@ -917,6 +917,7 @@ struct net_device_path {
- u8 queue;
- u16 wcid;
- u8 bss;
-+ u8 amsdu;
- } mtk_wdma;
- };
- };
---- a/include/linux/soc/mediatek/mtk_wed.h
-+++ b/include/linux/soc/mediatek/mtk_wed.h
-@@ -128,6 +128,7 @@ struct mtk_wed_device {
- enum mtk_wed_bus_tye bus_type;
- void __iomem *base;
- u32 phy_base;
-+ u32 id;
-
- u32 wpdma_phys;
- u32 wpdma_int;
-@@ -146,10 +147,12 @@ struct mtk_wed_device {
- unsigned int rx_nbuf;
- unsigned int rx_npkt;
- unsigned int rx_size;
-+ unsigned int amsdu_max_len;
-
- u8 tx_tbit[MTK_WED_TX_QUEUES];
- u8 rx_tbit[MTK_WED_RX_QUEUES];
- u8 txfree_tbit;
-+ u8 amsdu_max_subframes;
-
- u32 (*init_buf)(void *ptr, dma_addr_t phys, int token_id);
- int (*offload_enable)(struct mtk_wed_device *wed);
-@@ -223,6 +226,15 @@ static inline bool mtk_wed_get_rx_capa(s
- #else
- return false;
- #endif
-+}
-+
-+static inline bool mtk_wed_is_amsdu_supported(struct mtk_wed_device *dev)
-+{
-+#ifdef CONFIG_NET_MEDIATEK_SOC_WED
-+ return dev->version == 3;
-+#else
-+ return false;
-+#endif
- }
-
- #ifdef CONFIG_NET_MEDIATEK_SOC_WED
+++ /dev/null
-Date: Mon, 18 Sep 2023 12:29:16 +0200
-Subject: [PATCH] net: ethernet: mtk_wed: introduce hw_rro support for MT7988
-
-MT7988 SoC support 802.11 receive reordering offload in hw while
-MT7986 SoC implements it through the firmware running on the mcu.
-
----
-
---- a/drivers/net/ethernet/mediatek/mtk_wed.c
-+++ b/drivers/net/ethernet/mediatek/mtk_wed.c
-@@ -27,7 +27,7 @@
- #define MTK_WED_BUF_SIZE 2048
- #define MTK_WED_PAGE_BUF_SIZE 128
- #define MTK_WED_BUF_PER_PAGE (PAGE_SIZE / 2048)
--#define MTK_WED_RX_PAGE_BUF_PER_PAGE (PAGE_SIZE / 128)
-+#define MTK_WED_RX_BUF_PER_PAGE (PAGE_SIZE / MTK_WED_PAGE_BUF_SIZE)
- #define MTK_WED_RX_RING_SIZE 1536
- #define MTK_WED_RX_PG_BM_CNT 8192
- #define MTK_WED_AMSDU_BUF_SIZE (PAGE_SIZE << 4)
-@@ -597,6 +597,68 @@ free_pagelist:
- }
-
- static int
-+mtk_wed_hwrro_buffer_alloc(struct mtk_wed_device *dev)
-+{
-+ int n_pages = MTK_WED_RX_PG_BM_CNT / MTK_WED_RX_BUF_PER_PAGE;
-+ struct mtk_wed_buf *page_list;
-+ struct mtk_wed_bm_desc *desc;
-+ dma_addr_t desc_phys;
-+ int i, page_idx = 0;
-+
-+ if (!dev->wlan.hw_rro)
-+ return 0;
-+
-+ page_list = kcalloc(n_pages, sizeof(*page_list), GFP_KERNEL);
-+ if (!page_list)
-+ return -ENOMEM;
-+
-+ dev->hw_rro.size = dev->wlan.rx_nbuf & ~(MTK_WED_BUF_PER_PAGE - 1);
-+ dev->hw_rro.pages = page_list;
-+ desc = dma_alloc_coherent(dev->hw->dev,
-+ dev->wlan.rx_nbuf * sizeof(*desc),
-+ &desc_phys, GFP_KERNEL);
-+ if (!desc)
-+ return -ENOMEM;
-+
-+ dev->hw_rro.desc = desc;
-+ dev->hw_rro.desc_phys = desc_phys;
-+
-+ for (i = 0; i < MTK_WED_RX_PG_BM_CNT; i += MTK_WED_RX_BUF_PER_PAGE) {
-+ dma_addr_t page_phys, buf_phys;
-+ struct page *page;
-+ int s;
-+
-+ page = __dev_alloc_page(GFP_KERNEL);
-+ if (!page)
-+ return -ENOMEM;
-+
-+ page_phys = dma_map_page(dev->hw->dev, page, 0, PAGE_SIZE,
-+ DMA_BIDIRECTIONAL);
-+ if (dma_mapping_error(dev->hw->dev, page_phys)) {
-+ __free_page(page);
-+ return -ENOMEM;
-+ }
-+
-+ page_list[page_idx].p = page;
-+ page_list[page_idx++].phy_addr = page_phys;
-+ dma_sync_single_for_cpu(dev->hw->dev, page_phys, PAGE_SIZE,
-+ DMA_BIDIRECTIONAL);
-+
-+ buf_phys = page_phys;
-+ for (s = 0; s < MTK_WED_RX_BUF_PER_PAGE; s++) {
-+ desc->buf0 = cpu_to_le32(buf_phys);
-+ buf_phys += MTK_WED_PAGE_BUF_SIZE;
-+ desc++;
-+ }
-+
-+ dma_sync_single_for_device(dev->hw->dev, page_phys, PAGE_SIZE,
-+ DMA_BIDIRECTIONAL);
-+ }
-+
-+ return 0;
-+}
-+
-+static int
- mtk_wed_rx_buffer_alloc(struct mtk_wed_device *dev)
- {
- struct mtk_wed_bm_desc *desc;
-@@ -613,7 +675,42 @@ mtk_wed_rx_buffer_alloc(struct mtk_wed_d
- dev->rx_buf_ring.desc_phys = desc_phys;
- dev->wlan.init_rx_buf(dev, dev->wlan.rx_npkt);
-
-- return 0;
-+ return mtk_wed_hwrro_buffer_alloc(dev);
-+}
-+
-+static void
-+mtk_wed_hwrro_free_buffer(struct mtk_wed_device *dev)
-+{
-+ struct mtk_wed_buf *page_list = dev->hw_rro.pages;
-+ struct mtk_wed_bm_desc *desc = dev->hw_rro.desc;
-+ int i, page_idx = 0;
-+
-+ if (!dev->wlan.hw_rro)
-+ return;
-+
-+ if (!page_list)
-+ return;
-+
-+ if (!desc)
-+ goto free_pagelist;
-+
-+ for (i = 0; i < MTK_WED_RX_PG_BM_CNT; i += MTK_WED_RX_BUF_PER_PAGE) {
-+ dma_addr_t buf_addr = page_list[page_idx].phy_addr;
-+ void *page = page_list[page_idx++].p;
-+
-+ if (!page)
-+ break;
-+
-+ dma_unmap_page(dev->hw->dev, buf_addr, PAGE_SIZE,
-+ DMA_BIDIRECTIONAL);
-+ __free_page(page);
-+ }
-+
-+ dma_free_coherent(dev->hw->dev, dev->hw_rro.size * sizeof(*desc),
-+ desc, dev->hw_rro.desc_phys);
-+
-+free_pagelist:
-+ kfree(page_list);
- }
-
- static void
-@@ -627,6 +724,28 @@ mtk_wed_free_rx_buffer(struct mtk_wed_de
- dev->wlan.release_rx_buf(dev);
- dma_free_coherent(dev->hw->dev, dev->rx_buf_ring.size * sizeof(*desc),
- desc, dev->rx_buf_ring.desc_phys);
-+
-+ mtk_wed_hwrro_free_buffer(dev);
-+}
-+
-+static void
-+mtk_wed_hwrro_init(struct mtk_wed_device *dev)
-+{
-+ if (!mtk_wed_get_rx_capa(dev) || !dev->wlan.hw_rro)
-+ return;
-+
-+ wed_set(dev, MTK_WED_RRO_PG_BM_RX_DMAM,
-+ FIELD_PREP(MTK_WED_RRO_PG_BM_RX_SDL0, 128));
-+
-+ wed_w32(dev, MTK_WED_RRO_PG_BM_BASE, dev->hw_rro.desc_phys);
-+
-+ wed_w32(dev, MTK_WED_RRO_PG_BM_INIT_PTR,
-+ MTK_WED_RRO_PG_BM_INIT_SW_TAIL_IDX |
-+ FIELD_PREP(MTK_WED_RRO_PG_BM_SW_TAIL_IDX,
-+ MTK_WED_RX_PG_BM_CNT));
-+
-+ /* enable rx_page_bm to fetch dmad */
-+ wed_set(dev, MTK_WED_CTRL, MTK_WED_CTRL_WED_RX_PG_BM_EN);
- }
-
- static void
-@@ -640,6 +759,8 @@ mtk_wed_rx_buffer_hw_init(struct mtk_wed
- wed_w32(dev, MTK_WED_RX_BM_DYN_ALLOC_TH,
- FIELD_PREP(MTK_WED_RX_BM_DYN_ALLOC_TH_H, 0xffff));
- wed_set(dev, MTK_WED_CTRL, MTK_WED_CTRL_WED_RX_BM_EN);
-+
-+ mtk_wed_hwrro_init(dev);
- }
-
- static void
-@@ -934,6 +1055,8 @@ mtk_wed_bus_init(struct mtk_wed_device *
- static void
- mtk_wed_set_wpdma(struct mtk_wed_device *dev)
- {
-+ int i;
-+
- if (mtk_wed_is_v1(dev->hw)) {
- wed_w32(dev, MTK_WED_WPDMA_CFG_BASE, dev->wlan.wpdma_phys);
- return;
-@@ -951,6 +1074,15 @@ mtk_wed_set_wpdma(struct mtk_wed_device
-
- wed_w32(dev, MTK_WED_WPDMA_RX_GLO_CFG, dev->wlan.wpdma_rx_glo);
- wed_w32(dev, dev->hw->soc->regmap.wpdma_rx_ring0, dev->wlan.wpdma_rx);
-+
-+ if (!dev->wlan.hw_rro)
-+ return;
-+
-+ wed_w32(dev, MTK_WED_RRO_RX_D_CFG(0), dev->wlan.wpdma_rx_rro[0]);
-+ wed_w32(dev, MTK_WED_RRO_RX_D_CFG(1), dev->wlan.wpdma_rx_rro[1]);
-+ for (i = 0; i < MTK_WED_RX_PAGE_QUEUES; i++)
-+ wed_w32(dev, MTK_WED_RRO_MSDU_PG_RING_CFG(i),
-+ dev->wlan.wpdma_rx_pg + i * 0x10);
- }
-
- static void
-@@ -1762,6 +1894,165 @@ mtk_wed_dma_enable(struct mtk_wed_device
- }
-
- static void
-+mtk_wed_start_hw_rro(struct mtk_wed_device *dev, u32 irq_mask, bool reset)
-+{
-+ int i;
-+
-+ wed_w32(dev, MTK_WED_WPDMA_INT_MASK, irq_mask);
-+ wed_w32(dev, MTK_WED_INT_MASK, irq_mask);
-+
-+ if (!mtk_wed_get_rx_capa(dev) || !dev->wlan.hw_rro)
-+ return;
-+
-+ wed_set(dev, MTK_WED_RRO_RX_D_CFG(2), MTK_WED_RRO_MSDU_PG_DRV_CLR);
-+ wed_w32(dev, MTK_WED_RRO_MSDU_PG_RING2_CFG,
-+ MTK_WED_RRO_MSDU_PG_DRV_CLR);
-+
-+ wed_w32(dev, MTK_WED_WPDMA_INT_CTRL_RRO_RX,
-+ MTK_WED_WPDMA_INT_CTRL_RRO_RX0_EN |
-+ MTK_WED_WPDMA_INT_CTRL_RRO_RX0_CLR |
-+ MTK_WED_WPDMA_INT_CTRL_RRO_RX1_EN |
-+ MTK_WED_WPDMA_INT_CTRL_RRO_RX1_CLR |
-+ FIELD_PREP(MTK_WED_WPDMA_INT_CTRL_RRO_RX0_DONE_TRIG,
-+ dev->wlan.rro_rx_tbit[0]) |
-+ FIELD_PREP(MTK_WED_WPDMA_INT_CTRL_RRO_RX1_DONE_TRIG,
-+ dev->wlan.rro_rx_tbit[1]));
-+
-+ wed_w32(dev, MTK_WED_WPDMA_INT_CTRL_RRO_MSDU_PG,
-+ MTK_WED_WPDMA_INT_CTRL_RRO_PG0_EN |
-+ MTK_WED_WPDMA_INT_CTRL_RRO_PG0_CLR |
-+ MTK_WED_WPDMA_INT_CTRL_RRO_PG1_EN |
-+ MTK_WED_WPDMA_INT_CTRL_RRO_PG1_CLR |
-+ MTK_WED_WPDMA_INT_CTRL_RRO_PG2_EN |
-+ MTK_WED_WPDMA_INT_CTRL_RRO_PG2_CLR |
-+ FIELD_PREP(MTK_WED_WPDMA_INT_CTRL_RRO_PG0_DONE_TRIG,
-+ dev->wlan.rx_pg_tbit[0]) |
-+ FIELD_PREP(MTK_WED_WPDMA_INT_CTRL_RRO_PG1_DONE_TRIG,
-+ dev->wlan.rx_pg_tbit[1]) |
-+ FIELD_PREP(MTK_WED_WPDMA_INT_CTRL_RRO_PG2_DONE_TRIG,
-+ dev->wlan.rx_pg_tbit[2]));
-+
-+ /* RRO_MSDU_PG_RING2_CFG1_FLD_DRV_EN should be enabled after
-+ * WM FWDL completed, otherwise RRO_MSDU_PG ring may broken
-+ */
-+ wed_set(dev, MTK_WED_RRO_MSDU_PG_RING2_CFG,
-+ MTK_WED_RRO_MSDU_PG_DRV_EN);
-+
-+ for (i = 0; i < MTK_WED_RX_QUEUES; i++) {
-+ struct mtk_wed_ring *ring = &dev->rx_rro_ring[i];
-+
-+ if (!(ring->flags & MTK_WED_RING_CONFIGURED))
-+ continue;
-+
-+ if (mtk_wed_check_wfdma_rx_fill(dev, ring))
-+ dev_err(dev->hw->dev,
-+ "rx_rro_ring(%d) initialization failed\n", i);
-+ }
-+
-+ for (i = 0; i < MTK_WED_RX_PAGE_QUEUES; i++) {
-+ struct mtk_wed_ring *ring = &dev->rx_page_ring[i];
-+
-+ if (!(ring->flags & MTK_WED_RING_CONFIGURED))
-+ continue;
-+
-+ if (mtk_wed_check_wfdma_rx_fill(dev, ring))
-+ dev_err(dev->hw->dev,
-+ "rx_page_ring(%d) initialization failed\n", i);
-+ }
-+}
-+
-+static void
-+mtk_wed_rro_rx_ring_setup(struct mtk_wed_device *dev, int idx,
-+ void __iomem *regs)
-+{
-+ struct mtk_wed_ring *ring = &dev->rx_rro_ring[idx];
-+
-+ ring->wpdma = regs;
-+ wed_w32(dev, MTK_WED_RRO_RX_D_RX(idx) + MTK_WED_RING_OFS_BASE,
-+ readl(regs));
-+ wed_w32(dev, MTK_WED_RRO_RX_D_RX(idx) + MTK_WED_RING_OFS_COUNT,
-+ readl(regs + MTK_WED_RING_OFS_COUNT));
-+ ring->flags |= MTK_WED_RING_CONFIGURED;
-+}
-+
-+static void
-+mtk_wed_msdu_pg_rx_ring_setup(struct mtk_wed_device *dev, int idx, void __iomem *regs)
-+{
-+ struct mtk_wed_ring *ring = &dev->rx_page_ring[idx];
-+
-+ ring->wpdma = regs;
-+ wed_w32(dev, MTK_WED_RRO_MSDU_PG_CTRL0(idx) + MTK_WED_RING_OFS_BASE,
-+ readl(regs));
-+ wed_w32(dev, MTK_WED_RRO_MSDU_PG_CTRL0(idx) + MTK_WED_RING_OFS_COUNT,
-+ readl(regs + MTK_WED_RING_OFS_COUNT));
-+ ring->flags |= MTK_WED_RING_CONFIGURED;
-+}
-+
-+static int
-+mtk_wed_ind_rx_ring_setup(struct mtk_wed_device *dev, void __iomem *regs)
-+{
-+ struct mtk_wed_ring *ring = &dev->ind_cmd_ring;
-+ u32 val = readl(regs + MTK_WED_RING_OFS_COUNT);
-+ int i, count = 0;
-+
-+ ring->wpdma = regs;
-+ wed_w32(dev, MTK_WED_IND_CMD_RX_CTRL1 + MTK_WED_RING_OFS_BASE,
-+ readl(regs) & 0xfffffff0);
-+
-+ wed_w32(dev, MTK_WED_IND_CMD_RX_CTRL1 + MTK_WED_RING_OFS_COUNT,
-+ readl(regs + MTK_WED_RING_OFS_COUNT));
-+
-+ /* ack sn cr */
-+ wed_w32(dev, MTK_WED_RRO_CFG0, dev->wlan.phy_base +
-+ dev->wlan.ind_cmd.ack_sn_addr);
-+ wed_w32(dev, MTK_WED_RRO_CFG1,
-+ FIELD_PREP(MTK_WED_RRO_CFG1_MAX_WIN_SZ,
-+ dev->wlan.ind_cmd.win_size) |
-+ FIELD_PREP(MTK_WED_RRO_CFG1_PARTICL_SE_ID,
-+ dev->wlan.ind_cmd.particular_sid));
-+
-+ /* particular session addr element */
-+ wed_w32(dev, MTK_WED_ADDR_ELEM_CFG0,
-+ dev->wlan.ind_cmd.particular_se_phys);
-+
-+ for (i = 0; i < dev->wlan.ind_cmd.se_group_nums; i++) {
-+ wed_w32(dev, MTK_WED_RADDR_ELEM_TBL_WDATA,
-+ dev->wlan.ind_cmd.addr_elem_phys[i] >> 4);
-+ wed_w32(dev, MTK_WED_ADDR_ELEM_TBL_CFG,
-+ MTK_WED_ADDR_ELEM_TBL_WR | (i & 0x7f));
-+
-+ val = wed_r32(dev, MTK_WED_ADDR_ELEM_TBL_CFG);
-+ while (!(val & MTK_WED_ADDR_ELEM_TBL_WR_RDY) && count++ < 100)
-+ val = wed_r32(dev, MTK_WED_ADDR_ELEM_TBL_CFG);
-+ if (count >= 100)
-+ dev_err(dev->hw->dev,
-+ "write ba session base failed\n");
-+ }
-+
-+ /* pn check init */
-+ for (i = 0; i < dev->wlan.ind_cmd.particular_sid; i++) {
-+ wed_w32(dev, MTK_WED_PN_CHECK_WDATA_M,
-+ MTK_WED_PN_CHECK_IS_FIRST);
-+
-+ wed_w32(dev, MTK_WED_PN_CHECK_CFG, MTK_WED_PN_CHECK_WR |
-+ FIELD_PREP(MTK_WED_PN_CHECK_SE_ID, i));
-+
-+ count = 0;
-+ val = wed_r32(dev, MTK_WED_PN_CHECK_CFG);
-+ while (!(val & MTK_WED_PN_CHECK_WR_RDY) && count++ < 100)
-+ val = wed_r32(dev, MTK_WED_PN_CHECK_CFG);
-+ if (count >= 100)
-+ dev_err(dev->hw->dev,
-+ "session(%d) initialization failed\n", i);
-+ }
-+
-+ wed_w32(dev, MTK_WED_RX_IND_CMD_CNT0, MTK_WED_RX_IND_CMD_DBG_CNT_EN);
-+ wed_set(dev, MTK_WED_CTRL, MTK_WED_CTRL_WED_RX_IND_CMD_EN);
-+
-+ return 0;
-+}
-+
-+static void
- mtk_wed_start(struct mtk_wed_device *dev, u32 irq_mask)
- {
- int i;
-@@ -2214,6 +2505,10 @@ void mtk_wed_add_hw(struct device_node *
- .detach = mtk_wed_detach,
- .ppe_check = mtk_wed_ppe_check,
- .setup_tc = mtk_wed_setup_tc,
-+ .start_hw_rro = mtk_wed_start_hw_rro,
-+ .rro_rx_ring_setup = mtk_wed_rro_rx_ring_setup,
-+ .msdu_pg_rx_ring_setup = mtk_wed_msdu_pg_rx_ring_setup,
-+ .ind_rx_ring_setup = mtk_wed_ind_rx_ring_setup,
- };
- struct device_node *eth_np = eth->dev->of_node;
- struct platform_device *pdev;
---- a/include/linux/soc/mediatek/mtk_wed.h
-+++ b/include/linux/soc/mediatek/mtk_wed.h
-@@ -10,6 +10,7 @@
-
- #define MTK_WED_TX_QUEUES 2
- #define MTK_WED_RX_QUEUES 2
-+#define MTK_WED_RX_PAGE_QUEUES 3
-
- #define WED_WO_STA_REC 0x6
-
-@@ -99,6 +100,9 @@ struct mtk_wed_device {
- struct mtk_wed_ring txfree_ring;
- struct mtk_wed_ring tx_wdma[MTK_WED_TX_QUEUES];
- struct mtk_wed_ring rx_wdma[MTK_WED_RX_QUEUES];
-+ struct mtk_wed_ring rx_rro_ring[MTK_WED_RX_QUEUES];
-+ struct mtk_wed_ring rx_page_ring[MTK_WED_RX_PAGE_QUEUES];
-+ struct mtk_wed_ring ind_cmd_ring;
-
- struct {
- int size;
-@@ -119,6 +123,13 @@ struct mtk_wed_device {
- dma_addr_t fdbk_phys;
- } rro;
-
-+ struct {
-+ int size;
-+ struct mtk_wed_buf *pages;
-+ struct mtk_wed_bm_desc *desc;
-+ dma_addr_t desc_phys;
-+ } hw_rro;
-+
- /* filled by driver: */
- struct {
- union {
-@@ -137,6 +148,8 @@ struct mtk_wed_device {
- u32 wpdma_txfree;
- u32 wpdma_rx_glo;
- u32 wpdma_rx;
-+ u32 wpdma_rx_rro[MTK_WED_RX_QUEUES];
-+ u32 wpdma_rx_pg;
-
- bool wcid_512;
- bool hw_rro;
-@@ -151,9 +164,20 @@ struct mtk_wed_device {
-
- u8 tx_tbit[MTK_WED_TX_QUEUES];
- u8 rx_tbit[MTK_WED_RX_QUEUES];
-+ u8 rro_rx_tbit[MTK_WED_RX_QUEUES];
-+ u8 rx_pg_tbit[MTK_WED_RX_PAGE_QUEUES];
- u8 txfree_tbit;
- u8 amsdu_max_subframes;
-
-+ struct {
-+ u8 se_group_nums;
-+ u16 win_size;
-+ u16 particular_sid;
-+ u32 ack_sn_addr;
-+ dma_addr_t particular_se_phys;
-+ dma_addr_t addr_elem_phys[1024];
-+ } ind_cmd;
-+
- u32 (*init_buf)(void *ptr, dma_addr_t phys, int token_id);
- int (*offload_enable)(struct mtk_wed_device *wed);
- void (*offload_disable)(struct mtk_wed_device *wed);
-@@ -192,6 +216,14 @@ struct mtk_wed_ops {
- void (*irq_set_mask)(struct mtk_wed_device *dev, u32 mask);
- int (*setup_tc)(struct mtk_wed_device *wed, struct net_device *dev,
- enum tc_setup_type type, void *type_data);
-+ void (*start_hw_rro)(struct mtk_wed_device *dev, u32 irq_mask,
-+ bool reset);
-+ void (*rro_rx_ring_setup)(struct mtk_wed_device *dev, int ring,
-+ void __iomem *regs);
-+ void (*msdu_pg_rx_ring_setup)(struct mtk_wed_device *dev, int ring,
-+ void __iomem *regs);
-+ int (*ind_rx_ring_setup)(struct mtk_wed_device *dev,
-+ void __iomem *regs);
- };
-
- extern const struct mtk_wed_ops __rcu *mtk_soc_wed_ops;
-@@ -263,6 +295,15 @@ static inline bool mtk_wed_is_amsdu_supp
- #define mtk_wed_device_dma_reset(_dev) (_dev)->ops->reset_dma(_dev)
- #define mtk_wed_device_setup_tc(_dev, _netdev, _type, _type_data) \
- (_dev)->ops->setup_tc(_dev, _netdev, _type, _type_data)
-+#define mtk_wed_device_start_hw_rro(_dev, _mask, _reset) \
-+ (_dev)->ops->start_hw_rro(_dev, _mask, _reset)
-+#define mtk_wed_device_rro_rx_ring_setup(_dev, _ring, _regs) \
-+ (_dev)->ops->rro_rx_ring_setup(_dev, _ring, _regs)
-+#define mtk_wed_device_msdu_pg_rx_ring_setup(_dev, _ring, _regs) \
-+ (_dev)->ops->msdu_pg_rx_ring_setup(_dev, _ring, _regs)
-+#define mtk_wed_device_ind_rx_ring_setup(_dev, _regs) \
-+ (_dev)->ops->ind_rx_ring_setup(_dev, _regs)
-+
- #else
- static inline bool mtk_wed_device_active(struct mtk_wed_device *dev)
- {
-@@ -282,6 +323,10 @@ static inline bool mtk_wed_device_active
- #define mtk_wed_device_stop(_dev) do {} while (0)
- #define mtk_wed_device_dma_reset(_dev) do {} while (0)
- #define mtk_wed_device_setup_tc(_dev, _netdev, _type, _type_data) -EOPNOTSUPP
-+#define mtk_wed_device_start_hw_rro(_dev, _mask, _reset) do {} while (0)
-+#define mtk_wed_device_rro_rx_ring_setup(_dev, _ring, _regs) -ENODEV
-+#define mtk_wed_device_msdu_pg_rx_ring_setup(_dev, _ring, _regs) -ENODEV
-+#define mtk_wed_device_ind_rx_ring_setup(_dev, _regs) -ENODEV
- #endif
-
- #endif
+++ /dev/null
-Date: Mon, 18 Sep 2023 12:29:17 +0200
-Subject: [PATCH] net: ethernet: mtk_wed: debugfs: move wed_v2 specific regs
- out of regs array
-
-Move specific WED2.0 debugfs entries out of regs array. This is a
-preliminary patch to introduce WED 3.0 debugfs info.
-
----
-
---- a/drivers/net/ethernet/mediatek/mtk_wed_debugfs.c
-+++ b/drivers/net/ethernet/mediatek/mtk_wed_debugfs.c
-@@ -151,7 +151,7 @@ DEFINE_SHOW_ATTRIBUTE(wed_txinfo);
- static int
- wed_rxinfo_show(struct seq_file *s, void *data)
- {
-- static const struct reg_dump regs[] = {
-+ static const struct reg_dump regs_common[] = {
- DUMP_STR("WPDMA RX"),
- DUMP_WPDMA_RX_RING(0),
- DUMP_WPDMA_RX_RING(1),
-@@ -169,7 +169,7 @@ wed_rxinfo_show(struct seq_file *s, void
- DUMP_WED_RING(WED_RING_RX_DATA(0)),
- DUMP_WED_RING(WED_RING_RX_DATA(1)),
-
-- DUMP_STR("WED RRO"),
-+ DUMP_STR("WED WO RRO"),
- DUMP_WED_RRO_RING(WED_RROQM_MIOD_CTRL0),
- DUMP_WED(WED_RROQM_MID_MIB),
- DUMP_WED(WED_RROQM_MOD_MIB),
-@@ -180,17 +180,6 @@ wed_rxinfo_show(struct seq_file *s, void
- DUMP_WED(WED_RROQM_FDBK_ANC_MIB),
- DUMP_WED(WED_RROQM_FDBK_ANC2H_MIB),
-
-- DUMP_STR("WED Route QM"),
-- DUMP_WED(WED_RTQM_R2H_MIB(0)),
-- DUMP_WED(WED_RTQM_R2Q_MIB(0)),
-- DUMP_WED(WED_RTQM_Q2H_MIB(0)),
-- DUMP_WED(WED_RTQM_R2H_MIB(1)),
-- DUMP_WED(WED_RTQM_R2Q_MIB(1)),
-- DUMP_WED(WED_RTQM_Q2H_MIB(1)),
-- DUMP_WED(WED_RTQM_Q2N_MIB),
-- DUMP_WED(WED_RTQM_Q2B_MIB),
-- DUMP_WED(WED_RTQM_PFDBK_MIB),
--
- DUMP_STR("WED WDMA TX"),
- DUMP_WED(WED_WDMA_TX_MIB),
- DUMP_WED_RING(WED_WDMA_RING_TX),
-@@ -211,11 +200,25 @@ wed_rxinfo_show(struct seq_file *s, void
- DUMP_WED(WED_RX_BM_INTF),
- DUMP_WED(WED_RX_BM_ERR_STS),
- };
-+ static const struct reg_dump regs_wed_v2[] = {
-+ DUMP_STR("WED Route QM"),
-+ DUMP_WED(WED_RTQM_R2H_MIB(0)),
-+ DUMP_WED(WED_RTQM_R2Q_MIB(0)),
-+ DUMP_WED(WED_RTQM_Q2H_MIB(0)),
-+ DUMP_WED(WED_RTQM_R2H_MIB(1)),
-+ DUMP_WED(WED_RTQM_R2Q_MIB(1)),
-+ DUMP_WED(WED_RTQM_Q2H_MIB(1)),
-+ DUMP_WED(WED_RTQM_Q2N_MIB),
-+ DUMP_WED(WED_RTQM_Q2B_MIB),
-+ DUMP_WED(WED_RTQM_PFDBK_MIB),
-+ };
- struct mtk_wed_hw *hw = s->private;
- struct mtk_wed_device *dev = hw->wed_dev;
-
-- if (dev)
-- dump_wed_regs(s, dev, regs, ARRAY_SIZE(regs));
-+ if (dev) {
-+ dump_wed_regs(s, dev, regs_common, ARRAY_SIZE(regs_common));
-+ dump_wed_regs(s, dev, regs_wed_v2, ARRAY_SIZE(regs_wed_v2));
-+ }
-
- return 0;
- }
+++ /dev/null
-Date: Mon, 18 Sep 2023 12:29:18 +0200
-Subject: [PATCH] net: ethernet: mtk_wed: debugfs: add WED 3.0 debugfs entries
-
-Introduce WED3.0 debugfs entries useful for debugging.
-
----
-
---- a/drivers/net/ethernet/mediatek/mtk_wed_debugfs.c
-+++ b/drivers/net/ethernet/mediatek/mtk_wed_debugfs.c
-@@ -11,6 +11,7 @@ struct reg_dump {
- u16 offset;
- u8 type;
- u8 base;
-+ u32 mask;
- };
-
- enum {
-@@ -25,6 +26,8 @@ enum {
-
- #define DUMP_STR(_str) { _str, 0, DUMP_TYPE_STRING }
- #define DUMP_REG(_reg, ...) { #_reg, MTK_##_reg, __VA_ARGS__ }
-+#define DUMP_REG_MASK(_reg, _mask) \
-+ { #_mask, MTK_##_reg, DUMP_TYPE_WED, 0, MTK_##_mask }
- #define DUMP_RING(_prefix, _base, ...) \
- { _prefix " BASE", _base, __VA_ARGS__ }, \
- { _prefix " CNT", _base + 0x4, __VA_ARGS__ }, \
-@@ -32,6 +35,7 @@ enum {
- { _prefix " DIDX", _base + 0xc, __VA_ARGS__ }
-
- #define DUMP_WED(_reg) DUMP_REG(_reg, DUMP_TYPE_WED)
-+#define DUMP_WED_MASK(_reg, _mask) DUMP_REG_MASK(_reg, _mask)
- #define DUMP_WED_RING(_base) DUMP_RING(#_base, MTK_##_base, DUMP_TYPE_WED)
-
- #define DUMP_WDMA(_reg) DUMP_REG(_reg, DUMP_TYPE_WDMA)
-@@ -212,12 +216,58 @@ wed_rxinfo_show(struct seq_file *s, void
- DUMP_WED(WED_RTQM_Q2B_MIB),
- DUMP_WED(WED_RTQM_PFDBK_MIB),
- };
-+ static const struct reg_dump regs_wed_v3[] = {
-+ DUMP_STR("WED RX RRO DATA"),
-+ DUMP_WED_RING(WED_RRO_RX_D_RX(0)),
-+ DUMP_WED_RING(WED_RRO_RX_D_RX(1)),
-+
-+ DUMP_STR("WED RX MSDU PAGE"),
-+ DUMP_WED_RING(WED_RRO_MSDU_PG_CTRL0(0)),
-+ DUMP_WED_RING(WED_RRO_MSDU_PG_CTRL0(1)),
-+ DUMP_WED_RING(WED_RRO_MSDU_PG_CTRL0(2)),
-+
-+ DUMP_STR("WED RX IND CMD"),
-+ DUMP_WED(WED_IND_CMD_RX_CTRL1),
-+ DUMP_WED_MASK(WED_IND_CMD_RX_CTRL2, WED_IND_CMD_MAX_CNT),
-+ DUMP_WED_MASK(WED_IND_CMD_RX_CTRL0, WED_IND_CMD_PROC_IDX),
-+ DUMP_WED_MASK(RRO_IND_CMD_SIGNATURE, RRO_IND_CMD_DMA_IDX),
-+ DUMP_WED_MASK(WED_IND_CMD_RX_CTRL0, WED_IND_CMD_MAGIC_CNT),
-+ DUMP_WED_MASK(RRO_IND_CMD_SIGNATURE, RRO_IND_CMD_MAGIC_CNT),
-+ DUMP_WED_MASK(WED_IND_CMD_RX_CTRL0,
-+ WED_IND_CMD_PREFETCH_FREE_CNT),
-+ DUMP_WED_MASK(WED_RRO_CFG1, WED_RRO_CFG1_PARTICL_SE_ID),
-+
-+ DUMP_STR("WED ADDR ELEM"),
-+ DUMP_WED(WED_ADDR_ELEM_CFG0),
-+ DUMP_WED_MASK(WED_ADDR_ELEM_CFG1,
-+ WED_ADDR_ELEM_PREFETCH_FREE_CNT),
-+
-+ DUMP_STR("WED Route QM"),
-+ DUMP_WED(WED_RTQM_ENQ_I2Q_DMAD_CNT),
-+ DUMP_WED(WED_RTQM_ENQ_I2N_DMAD_CNT),
-+ DUMP_WED(WED_RTQM_ENQ_I2Q_PKT_CNT),
-+ DUMP_WED(WED_RTQM_ENQ_I2N_PKT_CNT),
-+ DUMP_WED(WED_RTQM_ENQ_USED_ENTRY_CNT),
-+ DUMP_WED(WED_RTQM_ENQ_ERR_CNT),
-+
-+ DUMP_WED(WED_RTQM_DEQ_DMAD_CNT),
-+ DUMP_WED(WED_RTQM_DEQ_Q2I_DMAD_CNT),
-+ DUMP_WED(WED_RTQM_DEQ_PKT_CNT),
-+ DUMP_WED(WED_RTQM_DEQ_Q2I_PKT_CNT),
-+ DUMP_WED(WED_RTQM_DEQ_USED_PFDBK_CNT),
-+ DUMP_WED(WED_RTQM_DEQ_ERR_CNT),
-+ };
- struct mtk_wed_hw *hw = s->private;
- struct mtk_wed_device *dev = hw->wed_dev;
-
- if (dev) {
- dump_wed_regs(s, dev, regs_common, ARRAY_SIZE(regs_common));
-- dump_wed_regs(s, dev, regs_wed_v2, ARRAY_SIZE(regs_wed_v2));
-+ if (mtk_wed_is_v2(hw))
-+ dump_wed_regs(s, dev,
-+ regs_wed_v2, ARRAY_SIZE(regs_wed_v2));
-+ else
-+ dump_wed_regs(s, dev,
-+ regs_wed_v3, ARRAY_SIZE(regs_wed_v3));
- }
-
- return 0;
-@@ -225,6 +275,314 @@ wed_rxinfo_show(struct seq_file *s, void
- DEFINE_SHOW_ATTRIBUTE(wed_rxinfo);
-
- static int
-+wed_amsdu_show(struct seq_file *s, void *data)
-+{
-+ static const struct reg_dump regs[] = {
-+ DUMP_STR("WED AMDSU INFO"),
-+ DUMP_WED(WED_MON_AMSDU_FIFO_DMAD),
-+
-+ DUMP_STR("WED AMDSU ENG0 INFO"),
-+ DUMP_WED(WED_MON_AMSDU_ENG_DMAD(0)),
-+ DUMP_WED(WED_MON_AMSDU_ENG_QFPL(0)),
-+ DUMP_WED(WED_MON_AMSDU_ENG_QENI(0)),
-+ DUMP_WED(WED_MON_AMSDU_ENG_QENO(0)),
-+ DUMP_WED(WED_MON_AMSDU_ENG_MERG(0)),
-+ DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT8(0),
-+ WED_AMSDU_ENG_MAX_PL_CNT),
-+ DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT8(0),
-+ WED_AMSDU_ENG_MAX_QGPP_CNT),
-+ DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(0),
-+ WED_AMSDU_ENG_CUR_ENTRY),
-+ DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(0),
-+ WED_AMSDU_ENG_MAX_BUF_MERGED),
-+ DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(0),
-+ WED_AMSDU_ENG_MAX_MSDU_MERGED),
-+
-+ DUMP_STR("WED AMDSU ENG1 INFO"),
-+ DUMP_WED(WED_MON_AMSDU_ENG_DMAD(1)),
-+ DUMP_WED(WED_MON_AMSDU_ENG_QFPL(1)),
-+ DUMP_WED(WED_MON_AMSDU_ENG_QENI(1)),
-+ DUMP_WED(WED_MON_AMSDU_ENG_QENO(1)),
-+ DUMP_WED(WED_MON_AMSDU_ENG_MERG(1)),
-+ DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT8(1),
-+ WED_AMSDU_ENG_MAX_PL_CNT),
-+ DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT8(1),
-+ WED_AMSDU_ENG_MAX_QGPP_CNT),
-+ DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(1),
-+ WED_AMSDU_ENG_CUR_ENTRY),
-+ DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(2),
-+ WED_AMSDU_ENG_MAX_BUF_MERGED),
-+ DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(2),
-+ WED_AMSDU_ENG_MAX_MSDU_MERGED),
-+
-+ DUMP_STR("WED AMDSU ENG2 INFO"),
-+ DUMP_WED(WED_MON_AMSDU_ENG_DMAD(2)),
-+ DUMP_WED(WED_MON_AMSDU_ENG_QFPL(2)),
-+ DUMP_WED(WED_MON_AMSDU_ENG_QENI(2)),
-+ DUMP_WED(WED_MON_AMSDU_ENG_QENO(2)),
-+ DUMP_WED(WED_MON_AMSDU_ENG_MERG(2)),
-+ DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT8(2),
-+ WED_AMSDU_ENG_MAX_PL_CNT),
-+ DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT8(2),
-+ WED_AMSDU_ENG_MAX_QGPP_CNT),
-+ DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(2),
-+ WED_AMSDU_ENG_CUR_ENTRY),
-+ DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(2),
-+ WED_AMSDU_ENG_MAX_BUF_MERGED),
-+ DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(2),
-+ WED_AMSDU_ENG_MAX_MSDU_MERGED),
-+
-+ DUMP_STR("WED AMDSU ENG3 INFO"),
-+ DUMP_WED(WED_MON_AMSDU_ENG_DMAD(3)),
-+ DUMP_WED(WED_MON_AMSDU_ENG_QFPL(3)),
-+ DUMP_WED(WED_MON_AMSDU_ENG_QENI(3)),
-+ DUMP_WED(WED_MON_AMSDU_ENG_QENO(3)),
-+ DUMP_WED(WED_MON_AMSDU_ENG_MERG(3)),
-+ DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT8(3),
-+ WED_AMSDU_ENG_MAX_PL_CNT),
-+ DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT8(3),
-+ WED_AMSDU_ENG_MAX_QGPP_CNT),
-+ DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(3),
-+ WED_AMSDU_ENG_CUR_ENTRY),
-+ DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(3),
-+ WED_AMSDU_ENG_MAX_BUF_MERGED),
-+ DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(3),
-+ WED_AMSDU_ENG_MAX_MSDU_MERGED),
-+
-+ DUMP_STR("WED AMDSU ENG4 INFO"),
-+ DUMP_WED(WED_MON_AMSDU_ENG_DMAD(4)),
-+ DUMP_WED(WED_MON_AMSDU_ENG_QFPL(4)),
-+ DUMP_WED(WED_MON_AMSDU_ENG_QENI(4)),
-+ DUMP_WED(WED_MON_AMSDU_ENG_QENO(4)),
-+ DUMP_WED(WED_MON_AMSDU_ENG_MERG(4)),
-+ DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT8(4),
-+ WED_AMSDU_ENG_MAX_PL_CNT),
-+ DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT8(4),
-+ WED_AMSDU_ENG_MAX_QGPP_CNT),
-+ DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(4),
-+ WED_AMSDU_ENG_CUR_ENTRY),
-+ DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(4),
-+ WED_AMSDU_ENG_MAX_BUF_MERGED),
-+ DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(4),
-+ WED_AMSDU_ENG_MAX_MSDU_MERGED),
-+
-+ DUMP_STR("WED AMDSU ENG5 INFO"),
-+ DUMP_WED(WED_MON_AMSDU_ENG_DMAD(5)),
-+ DUMP_WED(WED_MON_AMSDU_ENG_QFPL(5)),
-+ DUMP_WED(WED_MON_AMSDU_ENG_QENI(5)),
-+ DUMP_WED(WED_MON_AMSDU_ENG_QENO(5)),
-+ DUMP_WED(WED_MON_AMSDU_ENG_MERG(5)),
-+ DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT8(5),
-+ WED_AMSDU_ENG_MAX_PL_CNT),
-+ DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT8(5),
-+ WED_AMSDU_ENG_MAX_QGPP_CNT),
-+ DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(5),
-+ WED_AMSDU_ENG_CUR_ENTRY),
-+ DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(5),
-+ WED_AMSDU_ENG_MAX_BUF_MERGED),
-+ DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(5),
-+ WED_AMSDU_ENG_MAX_MSDU_MERGED),
-+
-+ DUMP_STR("WED AMDSU ENG6 INFO"),
-+ DUMP_WED(WED_MON_AMSDU_ENG_DMAD(6)),
-+ DUMP_WED(WED_MON_AMSDU_ENG_QFPL(6)),
-+ DUMP_WED(WED_MON_AMSDU_ENG_QENI(6)),
-+ DUMP_WED(WED_MON_AMSDU_ENG_QENO(6)),
-+ DUMP_WED(WED_MON_AMSDU_ENG_MERG(6)),
-+ DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT8(6),
-+ WED_AMSDU_ENG_MAX_PL_CNT),
-+ DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT8(6),
-+ WED_AMSDU_ENG_MAX_QGPP_CNT),
-+ DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(6),
-+ WED_AMSDU_ENG_CUR_ENTRY),
-+ DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(6),
-+ WED_AMSDU_ENG_MAX_BUF_MERGED),
-+ DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(6),
-+ WED_AMSDU_ENG_MAX_MSDU_MERGED),
-+
-+ DUMP_STR("WED AMDSU ENG7 INFO"),
-+ DUMP_WED(WED_MON_AMSDU_ENG_DMAD(7)),
-+ DUMP_WED(WED_MON_AMSDU_ENG_QFPL(7)),
-+ DUMP_WED(WED_MON_AMSDU_ENG_QENI(7)),
-+ DUMP_WED(WED_MON_AMSDU_ENG_QENO(7)),
-+ DUMP_WED(WED_MON_AMSDU_ENG_MERG(7)),
-+ DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT8(7),
-+ WED_AMSDU_ENG_MAX_PL_CNT),
-+ DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT8(7),
-+ WED_AMSDU_ENG_MAX_QGPP_CNT),
-+ DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(7),
-+ WED_AMSDU_ENG_CUR_ENTRY),
-+ DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(7),
-+ WED_AMSDU_ENG_MAX_BUF_MERGED),
-+ DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(4),
-+ WED_AMSDU_ENG_MAX_MSDU_MERGED),
-+
-+ DUMP_STR("WED AMDSU ENG8 INFO"),
-+ DUMP_WED(WED_MON_AMSDU_ENG_DMAD(8)),
-+ DUMP_WED(WED_MON_AMSDU_ENG_QFPL(8)),
-+ DUMP_WED(WED_MON_AMSDU_ENG_QENI(8)),
-+ DUMP_WED(WED_MON_AMSDU_ENG_QENO(8)),
-+ DUMP_WED(WED_MON_AMSDU_ENG_MERG(8)),
-+ DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT8(8),
-+ WED_AMSDU_ENG_MAX_PL_CNT),
-+ DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT8(8),
-+ WED_AMSDU_ENG_MAX_QGPP_CNT),
-+ DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(8),
-+ WED_AMSDU_ENG_CUR_ENTRY),
-+ DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(8),
-+ WED_AMSDU_ENG_MAX_BUF_MERGED),
-+ DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(8),
-+ WED_AMSDU_ENG_MAX_MSDU_MERGED),
-+
-+ DUMP_STR("WED QMEM INFO"),
-+ DUMP_WED_MASK(WED_MON_AMSDU_QMEM_CNT(0), WED_AMSDU_QMEM_FQ_CNT),
-+ DUMP_WED_MASK(WED_MON_AMSDU_QMEM_CNT(0), WED_AMSDU_QMEM_SP_QCNT),
-+ DUMP_WED_MASK(WED_MON_AMSDU_QMEM_CNT(1), WED_AMSDU_QMEM_TID0_QCNT),
-+ DUMP_WED_MASK(WED_MON_AMSDU_QMEM_CNT(1), WED_AMSDU_QMEM_TID1_QCNT),
-+ DUMP_WED_MASK(WED_MON_AMSDU_QMEM_CNT(2), WED_AMSDU_QMEM_TID2_QCNT),
-+ DUMP_WED_MASK(WED_MON_AMSDU_QMEM_CNT(2), WED_AMSDU_QMEM_TID3_QCNT),
-+ DUMP_WED_MASK(WED_MON_AMSDU_QMEM_CNT(3), WED_AMSDU_QMEM_TID4_QCNT),
-+ DUMP_WED_MASK(WED_MON_AMSDU_QMEM_CNT(3), WED_AMSDU_QMEM_TID5_QCNT),
-+ DUMP_WED_MASK(WED_MON_AMSDU_QMEM_CNT(4), WED_AMSDU_QMEM_TID6_QCNT),
-+ DUMP_WED_MASK(WED_MON_AMSDU_QMEM_CNT(4), WED_AMSDU_QMEM_TID7_QCNT),
-+
-+ DUMP_STR("WED QMEM HEAD INFO"),
-+ DUMP_WED_MASK(WED_MON_AMSDU_QMEM_PTR(0), WED_AMSDU_QMEM_FQ_HEAD),
-+ DUMP_WED_MASK(WED_MON_AMSDU_QMEM_PTR(0), WED_AMSDU_QMEM_SP_QHEAD),
-+ DUMP_WED_MASK(WED_MON_AMSDU_QMEM_PTR(1), WED_AMSDU_QMEM_TID0_QHEAD),
-+ DUMP_WED_MASK(WED_MON_AMSDU_QMEM_PTR(1), WED_AMSDU_QMEM_TID1_QHEAD),
-+ DUMP_WED_MASK(WED_MON_AMSDU_QMEM_PTR(2), WED_AMSDU_QMEM_TID2_QHEAD),
-+ DUMP_WED_MASK(WED_MON_AMSDU_QMEM_PTR(2), WED_AMSDU_QMEM_TID3_QHEAD),
-+ DUMP_WED_MASK(WED_MON_AMSDU_QMEM_PTR(3), WED_AMSDU_QMEM_TID4_QHEAD),
-+ DUMP_WED_MASK(WED_MON_AMSDU_QMEM_PTR(3), WED_AMSDU_QMEM_TID5_QHEAD),
-+ DUMP_WED_MASK(WED_MON_AMSDU_QMEM_PTR(4), WED_AMSDU_QMEM_TID6_QHEAD),
-+ DUMP_WED_MASK(WED_MON_AMSDU_QMEM_PTR(4), WED_AMSDU_QMEM_TID7_QHEAD),
-+
-+ DUMP_STR("WED QMEM TAIL INFO"),
-+ DUMP_WED_MASK(WED_MON_AMSDU_QMEM_PTR(5), WED_AMSDU_QMEM_FQ_TAIL),
-+ DUMP_WED_MASK(WED_MON_AMSDU_QMEM_PTR(5), WED_AMSDU_QMEM_SP_QTAIL),
-+ DUMP_WED_MASK(WED_MON_AMSDU_QMEM_PTR(6), WED_AMSDU_QMEM_TID0_QTAIL),
-+ DUMP_WED_MASK(WED_MON_AMSDU_QMEM_PTR(6), WED_AMSDU_QMEM_TID1_QTAIL),
-+ DUMP_WED_MASK(WED_MON_AMSDU_QMEM_PTR(7), WED_AMSDU_QMEM_TID2_QTAIL),
-+ DUMP_WED_MASK(WED_MON_AMSDU_QMEM_PTR(7), WED_AMSDU_QMEM_TID3_QTAIL),
-+ DUMP_WED_MASK(WED_MON_AMSDU_QMEM_PTR(8), WED_AMSDU_QMEM_TID4_QTAIL),
-+ DUMP_WED_MASK(WED_MON_AMSDU_QMEM_PTR(8), WED_AMSDU_QMEM_TID5_QTAIL),
-+ DUMP_WED_MASK(WED_MON_AMSDU_QMEM_PTR(9), WED_AMSDU_QMEM_TID6_QTAIL),
-+ DUMP_WED_MASK(WED_MON_AMSDU_QMEM_PTR(9), WED_AMSDU_QMEM_TID7_QTAIL),
-+
-+ DUMP_STR("WED HIFTXD MSDU INFO"),
-+ DUMP_WED(WED_MON_AMSDU_HIFTXD_FETCH_MSDU(1)),
-+ DUMP_WED(WED_MON_AMSDU_HIFTXD_FETCH_MSDU(2)),
-+ DUMP_WED(WED_MON_AMSDU_HIFTXD_FETCH_MSDU(3)),
-+ DUMP_WED(WED_MON_AMSDU_HIFTXD_FETCH_MSDU(4)),
-+ DUMP_WED(WED_MON_AMSDU_HIFTXD_FETCH_MSDU(5)),
-+ DUMP_WED(WED_MON_AMSDU_HIFTXD_FETCH_MSDU(6)),
-+ DUMP_WED(WED_MON_AMSDU_HIFTXD_FETCH_MSDU(7)),
-+ DUMP_WED(WED_MON_AMSDU_HIFTXD_FETCH_MSDU(8)),
-+ DUMP_WED(WED_MON_AMSDU_HIFTXD_FETCH_MSDU(9)),
-+ DUMP_WED(WED_MON_AMSDU_HIFTXD_FETCH_MSDU(10)),
-+ DUMP_WED(WED_MON_AMSDU_HIFTXD_FETCH_MSDU(11)),
-+ DUMP_WED(WED_MON_AMSDU_HIFTXD_FETCH_MSDU(12)),
-+ DUMP_WED(WED_MON_AMSDU_HIFTXD_FETCH_MSDU(13)),
-+ };
-+ struct mtk_wed_hw *hw = s->private;
-+ struct mtk_wed_device *dev = hw->wed_dev;
-+
-+ if (dev)
-+ dump_wed_regs(s, dev, regs, ARRAY_SIZE(regs));
-+
-+ return 0;
-+}
-+DEFINE_SHOW_ATTRIBUTE(wed_amsdu);
-+
-+static int
-+wed_rtqm_show(struct seq_file *s, void *data)
-+{
-+ static const struct reg_dump regs[] = {
-+ DUMP_STR("WED Route QM IGRS0(N2H + Recycle)"),
-+ DUMP_WED(WED_RTQM_IGRS0_I2HW_DMAD_CNT),
-+ DUMP_WED(WED_RTQM_IGRS0_I2H_DMAD_CNT(0)),
-+ DUMP_WED(WED_RTQM_IGRS0_I2H_DMAD_CNT(1)),
-+ DUMP_WED(WED_RTQM_IGRS0_I2HW_PKT_CNT),
-+ DUMP_WED(WED_RTQM_IGRS0_I2H_PKT_CNT(0)),
-+ DUMP_WED(WED_RTQM_IGRS0_I2H_PKT_CNT(0)),
-+ DUMP_WED(WED_RTQM_IGRS0_FDROP_CNT),
-+
-+ DUMP_STR("WED Route QM IGRS1(Legacy)"),
-+ DUMP_WED(WED_RTQM_IGRS1_I2HW_DMAD_CNT),
-+ DUMP_WED(WED_RTQM_IGRS1_I2H_DMAD_CNT(0)),
-+ DUMP_WED(WED_RTQM_IGRS1_I2H_DMAD_CNT(1)),
-+ DUMP_WED(WED_RTQM_IGRS1_I2HW_PKT_CNT),
-+ DUMP_WED(WED_RTQM_IGRS1_I2H_PKT_CNT(0)),
-+ DUMP_WED(WED_RTQM_IGRS1_I2H_PKT_CNT(1)),
-+ DUMP_WED(WED_RTQM_IGRS1_FDROP_CNT),
-+
-+ DUMP_STR("WED Route QM IGRS2(RRO3.0)"),
-+ DUMP_WED(WED_RTQM_IGRS2_I2HW_DMAD_CNT),
-+ DUMP_WED(WED_RTQM_IGRS2_I2H_DMAD_CNT(0)),
-+ DUMP_WED(WED_RTQM_IGRS2_I2H_DMAD_CNT(1)),
-+ DUMP_WED(WED_RTQM_IGRS2_I2HW_PKT_CNT),
-+ DUMP_WED(WED_RTQM_IGRS2_I2H_PKT_CNT(0)),
-+ DUMP_WED(WED_RTQM_IGRS2_I2H_PKT_CNT(1)),
-+ DUMP_WED(WED_RTQM_IGRS2_FDROP_CNT),
-+
-+ DUMP_STR("WED Route QM IGRS3(DEBUG)"),
-+ DUMP_WED(WED_RTQM_IGRS2_I2HW_DMAD_CNT),
-+ DUMP_WED(WED_RTQM_IGRS3_I2H_DMAD_CNT(0)),
-+ DUMP_WED(WED_RTQM_IGRS3_I2H_DMAD_CNT(1)),
-+ DUMP_WED(WED_RTQM_IGRS3_I2HW_PKT_CNT),
-+ DUMP_WED(WED_RTQM_IGRS3_I2H_PKT_CNT(0)),
-+ DUMP_WED(WED_RTQM_IGRS3_I2H_PKT_CNT(1)),
-+ DUMP_WED(WED_RTQM_IGRS3_FDROP_CNT),
-+ };
-+ struct mtk_wed_hw *hw = s->private;
-+ struct mtk_wed_device *dev = hw->wed_dev;
-+
-+ if (dev)
-+ dump_wed_regs(s, dev, regs, ARRAY_SIZE(regs));
-+
-+ return 0;
-+}
-+DEFINE_SHOW_ATTRIBUTE(wed_rtqm);
-+
-+static int
-+wed_rro_show(struct seq_file *s, void *data)
-+{
-+ static const struct reg_dump regs[] = {
-+ DUMP_STR("RRO/IND CMD CNT"),
-+ DUMP_WED(WED_RX_IND_CMD_CNT(1)),
-+ DUMP_WED(WED_RX_IND_CMD_CNT(2)),
-+ DUMP_WED(WED_RX_IND_CMD_CNT(3)),
-+ DUMP_WED(WED_RX_IND_CMD_CNT(4)),
-+ DUMP_WED(WED_RX_IND_CMD_CNT(5)),
-+ DUMP_WED(WED_RX_IND_CMD_CNT(6)),
-+ DUMP_WED(WED_RX_IND_CMD_CNT(7)),
-+ DUMP_WED(WED_RX_IND_CMD_CNT(8)),
-+ DUMP_WED_MASK(WED_RX_IND_CMD_CNT(9),
-+ WED_IND_CMD_MAGIC_CNT_FAIL_CNT),
-+
-+ DUMP_WED(WED_RX_ADDR_ELEM_CNT(0)),
-+ DUMP_WED_MASK(WED_RX_ADDR_ELEM_CNT(1),
-+ WED_ADDR_ELEM_SIG_FAIL_CNT),
-+ DUMP_WED(WED_RX_MSDU_PG_CNT(1)),
-+ DUMP_WED(WED_RX_MSDU_PG_CNT(2)),
-+ DUMP_WED(WED_RX_MSDU_PG_CNT(3)),
-+ DUMP_WED(WED_RX_MSDU_PG_CNT(4)),
-+ DUMP_WED(WED_RX_MSDU_PG_CNT(5)),
-+ DUMP_WED_MASK(WED_RX_PN_CHK_CNT,
-+ WED_PN_CHK_FAIL_CNT),
-+ };
-+ struct mtk_wed_hw *hw = s->private;
-+ struct mtk_wed_device *dev = hw->wed_dev;
-+
-+ if (dev)
-+ dump_wed_regs(s, dev, regs, ARRAY_SIZE(regs));
-+
-+ return 0;
-+}
-+DEFINE_SHOW_ATTRIBUTE(wed_rro);
-+
-+static int
- mtk_wed_reg_set(void *data, u64 val)
- {
- struct mtk_wed_hw *hw = data;
-@@ -264,7 +622,16 @@ void mtk_wed_hw_add_debugfs(struct mtk_w
- debugfs_create_u32("regidx", 0600, dir, &hw->debugfs_reg);
- debugfs_create_file_unsafe("regval", 0600, dir, hw, &fops_regval);
- debugfs_create_file_unsafe("txinfo", 0400, dir, hw, &wed_txinfo_fops);
-- if (!mtk_wed_is_v1(hw))
-+ if (!mtk_wed_is_v1(hw)) {
- debugfs_create_file_unsafe("rxinfo", 0400, dir, hw,
- &wed_rxinfo_fops);
-+ if (mtk_wed_is_v3_or_greater(hw)) {
-+ debugfs_create_file_unsafe("amsdu", 0400, dir, hw,
-+ &wed_amsdu_fops);
-+ debugfs_create_file_unsafe("rtqm", 0400, dir, hw,
-+ &wed_rtqm_fops);
-+ debugfs_create_file_unsafe("rro", 0400, dir, hw,
-+ &wed_rro_fops);
-+ }
-+ }
- }
+++ /dev/null
-Date: Mon, 18 Sep 2023 12:29:19 +0200
-Subject: [PATCH] net: ethernet: mtk_wed: add wed 3.0 reset support
-
-Introduce support for resetting Wireless Ethernet Dispatcher 3.0
-available on MT988 SoC.
-
----
-
---- a/drivers/net/ethernet/mediatek/mtk_wed.c
-+++ b/drivers/net/ethernet/mediatek/mtk_wed.c
-@@ -149,6 +149,90 @@ mtk_wdma_read_reset(struct mtk_wed_devic
- return wdma_r32(dev, MTK_WDMA_GLO_CFG);
- }
-
-+static void
-+mtk_wdma_v3_rx_reset(struct mtk_wed_device *dev)
-+{
-+ u32 status;
-+
-+ if (!mtk_wed_is_v3_or_greater(dev->hw))
-+ return;
-+
-+ wdma_clr(dev, MTK_WDMA_PREF_TX_CFG, MTK_WDMA_PREF_TX_CFG_PREF_EN);
-+ wdma_clr(dev, MTK_WDMA_PREF_RX_CFG, MTK_WDMA_PREF_RX_CFG_PREF_EN);
-+
-+ if (read_poll_timeout(wdma_r32, status,
-+ !(status & MTK_WDMA_PREF_TX_CFG_PREF_BUSY),
-+ 0, 10000, false, dev, MTK_WDMA_PREF_TX_CFG))
-+ dev_err(dev->hw->dev, "rx reset failed\n");
-+
-+ if (read_poll_timeout(wdma_r32, status,
-+ !(status & MTK_WDMA_PREF_RX_CFG_PREF_BUSY),
-+ 0, 10000, false, dev, MTK_WDMA_PREF_RX_CFG))
-+ dev_err(dev->hw->dev, "rx reset failed\n");
-+
-+ wdma_clr(dev, MTK_WDMA_WRBK_TX_CFG, MTK_WDMA_WRBK_TX_CFG_WRBK_EN);
-+ wdma_clr(dev, MTK_WDMA_WRBK_RX_CFG, MTK_WDMA_WRBK_RX_CFG_WRBK_EN);
-+
-+ if (read_poll_timeout(wdma_r32, status,
-+ !(status & MTK_WDMA_WRBK_TX_CFG_WRBK_BUSY),
-+ 0, 10000, false, dev, MTK_WDMA_WRBK_TX_CFG))
-+ dev_err(dev->hw->dev, "rx reset failed\n");
-+
-+ if (read_poll_timeout(wdma_r32, status,
-+ !(status & MTK_WDMA_WRBK_RX_CFG_WRBK_BUSY),
-+ 0, 10000, false, dev, MTK_WDMA_WRBK_RX_CFG))
-+ dev_err(dev->hw->dev, "rx reset failed\n");
-+
-+ /* prefetch FIFO */
-+ wdma_w32(dev, MTK_WDMA_PREF_RX_FIFO_CFG,
-+ MTK_WDMA_PREF_RX_FIFO_CFG_RING0_CLEAR |
-+ MTK_WDMA_PREF_RX_FIFO_CFG_RING1_CLEAR);
-+ wdma_clr(dev, MTK_WDMA_PREF_RX_FIFO_CFG,
-+ MTK_WDMA_PREF_RX_FIFO_CFG_RING0_CLEAR |
-+ MTK_WDMA_PREF_RX_FIFO_CFG_RING1_CLEAR);
-+
-+ /* core FIFO */
-+ wdma_w32(dev, MTK_WDMA_XDMA_RX_FIFO_CFG,
-+ MTK_WDMA_XDMA_RX_FIFO_CFG_RX_PAR_FIFO_CLEAR |
-+ MTK_WDMA_XDMA_RX_FIFO_CFG_RX_CMD_FIFO_CLEAR |
-+ MTK_WDMA_XDMA_RX_FIFO_CFG_RX_DMAD_FIFO_CLEAR |
-+ MTK_WDMA_XDMA_RX_FIFO_CFG_RX_ARR_FIFO_CLEAR |
-+ MTK_WDMA_XDMA_RX_FIFO_CFG_RX_LEN_FIFO_CLEAR |
-+ MTK_WDMA_XDMA_RX_FIFO_CFG_RX_WID_FIFO_CLEAR |
-+ MTK_WDMA_XDMA_RX_FIFO_CFG_RX_BID_FIFO_CLEAR);
-+ wdma_clr(dev, MTK_WDMA_XDMA_RX_FIFO_CFG,
-+ MTK_WDMA_XDMA_RX_FIFO_CFG_RX_PAR_FIFO_CLEAR |
-+ MTK_WDMA_XDMA_RX_FIFO_CFG_RX_CMD_FIFO_CLEAR |
-+ MTK_WDMA_XDMA_RX_FIFO_CFG_RX_DMAD_FIFO_CLEAR |
-+ MTK_WDMA_XDMA_RX_FIFO_CFG_RX_ARR_FIFO_CLEAR |
-+ MTK_WDMA_XDMA_RX_FIFO_CFG_RX_LEN_FIFO_CLEAR |
-+ MTK_WDMA_XDMA_RX_FIFO_CFG_RX_WID_FIFO_CLEAR |
-+ MTK_WDMA_XDMA_RX_FIFO_CFG_RX_BID_FIFO_CLEAR);
-+
-+ /* writeback FIFO */
-+ wdma_w32(dev, MTK_WDMA_WRBK_RX_FIFO_CFG(0),
-+ MTK_WDMA_WRBK_RX_FIFO_CFG_RING_CLEAR);
-+ wdma_w32(dev, MTK_WDMA_WRBK_RX_FIFO_CFG(1),
-+ MTK_WDMA_WRBK_RX_FIFO_CFG_RING_CLEAR);
-+
-+ wdma_clr(dev, MTK_WDMA_WRBK_RX_FIFO_CFG(0),
-+ MTK_WDMA_WRBK_RX_FIFO_CFG_RING_CLEAR);
-+ wdma_clr(dev, MTK_WDMA_WRBK_RX_FIFO_CFG(1),
-+ MTK_WDMA_WRBK_RX_FIFO_CFG_RING_CLEAR);
-+
-+ /* prefetch ring status */
-+ wdma_w32(dev, MTK_WDMA_PREF_SIDX_CFG,
-+ MTK_WDMA_PREF_SIDX_CFG_RX_RING_CLEAR);
-+ wdma_clr(dev, MTK_WDMA_PREF_SIDX_CFG,
-+ MTK_WDMA_PREF_SIDX_CFG_RX_RING_CLEAR);
-+
-+ /* writeback ring status */
-+ wdma_w32(dev, MTK_WDMA_WRBK_SIDX_CFG,
-+ MTK_WDMA_WRBK_SIDX_CFG_RX_RING_CLEAR);
-+ wdma_clr(dev, MTK_WDMA_WRBK_SIDX_CFG,
-+ MTK_WDMA_WRBK_SIDX_CFG_RX_RING_CLEAR);
-+}
-+
- static int
- mtk_wdma_rx_reset(struct mtk_wed_device *dev)
- {
-@@ -161,6 +245,7 @@ mtk_wdma_rx_reset(struct mtk_wed_device
- if (ret)
- dev_err(dev->hw->dev, "rx reset failed\n");
-
-+ mtk_wdma_v3_rx_reset(dev);
- wdma_w32(dev, MTK_WDMA_RESET_IDX, MTK_WDMA_RESET_IDX_RX);
- wdma_w32(dev, MTK_WDMA_RESET_IDX, 0);
-
-@@ -193,6 +278,84 @@ mtk_wed_poll_busy(struct mtk_wed_device
- }
-
- static void
-+mtk_wdma_v3_tx_reset(struct mtk_wed_device *dev)
-+{
-+ u32 status;
-+
-+ if (!mtk_wed_is_v3_or_greater(dev->hw))
-+ return;
-+
-+ wdma_clr(dev, MTK_WDMA_PREF_TX_CFG, MTK_WDMA_PREF_TX_CFG_PREF_EN);
-+ wdma_clr(dev, MTK_WDMA_PREF_RX_CFG, MTK_WDMA_PREF_RX_CFG_PREF_EN);
-+
-+ if (read_poll_timeout(wdma_r32, status,
-+ !(status & MTK_WDMA_PREF_TX_CFG_PREF_BUSY),
-+ 0, 10000, false, dev, MTK_WDMA_PREF_TX_CFG))
-+ dev_err(dev->hw->dev, "tx reset failed\n");
-+
-+ if (read_poll_timeout(wdma_r32, status,
-+ !(status & MTK_WDMA_PREF_RX_CFG_PREF_BUSY),
-+ 0, 10000, false, dev, MTK_WDMA_PREF_RX_CFG))
-+ dev_err(dev->hw->dev, "tx reset failed\n");
-+
-+ wdma_clr(dev, MTK_WDMA_WRBK_TX_CFG, MTK_WDMA_WRBK_TX_CFG_WRBK_EN);
-+ wdma_clr(dev, MTK_WDMA_WRBK_RX_CFG, MTK_WDMA_WRBK_RX_CFG_WRBK_EN);
-+
-+ if (read_poll_timeout(wdma_r32, status,
-+ !(status & MTK_WDMA_WRBK_TX_CFG_WRBK_BUSY),
-+ 0, 10000, false, dev, MTK_WDMA_WRBK_TX_CFG))
-+ dev_err(dev->hw->dev, "tx reset failed\n");
-+
-+ if (read_poll_timeout(wdma_r32, status,
-+ !(status & MTK_WDMA_WRBK_RX_CFG_WRBK_BUSY),
-+ 0, 10000, false, dev, MTK_WDMA_WRBK_RX_CFG))
-+ dev_err(dev->hw->dev, "tx reset failed\n");
-+
-+ /* prefetch FIFO */
-+ wdma_w32(dev, MTK_WDMA_PREF_TX_FIFO_CFG,
-+ MTK_WDMA_PREF_TX_FIFO_CFG_RING0_CLEAR |
-+ MTK_WDMA_PREF_TX_FIFO_CFG_RING1_CLEAR);
-+ wdma_clr(dev, MTK_WDMA_PREF_TX_FIFO_CFG,
-+ MTK_WDMA_PREF_TX_FIFO_CFG_RING0_CLEAR |
-+ MTK_WDMA_PREF_TX_FIFO_CFG_RING1_CLEAR);
-+
-+ /* core FIFO */
-+ wdma_w32(dev, MTK_WDMA_XDMA_TX_FIFO_CFG,
-+ MTK_WDMA_XDMA_TX_FIFO_CFG_TX_PAR_FIFO_CLEAR |
-+ MTK_WDMA_XDMA_TX_FIFO_CFG_TX_CMD_FIFO_CLEAR |
-+ MTK_WDMA_XDMA_TX_FIFO_CFG_TX_DMAD_FIFO_CLEAR |
-+ MTK_WDMA_XDMA_TX_FIFO_CFG_TX_ARR_FIFO_CLEAR);
-+ wdma_clr(dev, MTK_WDMA_XDMA_TX_FIFO_CFG,
-+ MTK_WDMA_XDMA_TX_FIFO_CFG_TX_PAR_FIFO_CLEAR |
-+ MTK_WDMA_XDMA_TX_FIFO_CFG_TX_CMD_FIFO_CLEAR |
-+ MTK_WDMA_XDMA_TX_FIFO_CFG_TX_DMAD_FIFO_CLEAR |
-+ MTK_WDMA_XDMA_TX_FIFO_CFG_TX_ARR_FIFO_CLEAR);
-+
-+ /* writeback FIFO */
-+ wdma_w32(dev, MTK_WDMA_WRBK_TX_FIFO_CFG(0),
-+ MTK_WDMA_WRBK_TX_FIFO_CFG_RING_CLEAR);
-+ wdma_w32(dev, MTK_WDMA_WRBK_TX_FIFO_CFG(1),
-+ MTK_WDMA_WRBK_TX_FIFO_CFG_RING_CLEAR);
-+
-+ wdma_clr(dev, MTK_WDMA_WRBK_TX_FIFO_CFG(0),
-+ MTK_WDMA_WRBK_TX_FIFO_CFG_RING_CLEAR);
-+ wdma_clr(dev, MTK_WDMA_WRBK_TX_FIFO_CFG(1),
-+ MTK_WDMA_WRBK_TX_FIFO_CFG_RING_CLEAR);
-+
-+ /* prefetch ring status */
-+ wdma_w32(dev, MTK_WDMA_PREF_SIDX_CFG,
-+ MTK_WDMA_PREF_SIDX_CFG_TX_RING_CLEAR);
-+ wdma_clr(dev, MTK_WDMA_PREF_SIDX_CFG,
-+ MTK_WDMA_PREF_SIDX_CFG_TX_RING_CLEAR);
-+
-+ /* writeback ring status */
-+ wdma_w32(dev, MTK_WDMA_WRBK_SIDX_CFG,
-+ MTK_WDMA_WRBK_SIDX_CFG_TX_RING_CLEAR);
-+ wdma_clr(dev, MTK_WDMA_WRBK_SIDX_CFG,
-+ MTK_WDMA_WRBK_SIDX_CFG_TX_RING_CLEAR);
-+}
-+
-+static void
- mtk_wdma_tx_reset(struct mtk_wed_device *dev)
- {
- u32 status, mask = MTK_WDMA_GLO_CFG_TX_DMA_BUSY;
-@@ -203,6 +366,7 @@ mtk_wdma_tx_reset(struct mtk_wed_device
- !(status & mask), 0, 10000))
- dev_err(dev->hw->dev, "tx reset failed\n");
-
-+ mtk_wdma_v3_tx_reset(dev);
- wdma_w32(dev, MTK_WDMA_RESET_IDX, MTK_WDMA_RESET_IDX_TX);
- wdma_w32(dev, MTK_WDMA_RESET_IDX, 0);
-
-@@ -1405,13 +1569,33 @@ mtk_wed_rx_reset(struct mtk_wed_device *
- if (ret)
- return ret;
-
-+ if (dev->wlan.hw_rro) {
-+ wed_clr(dev, MTK_WED_CTRL, MTK_WED_CTRL_WED_RX_IND_CMD_EN);
-+ mtk_wed_poll_busy(dev, MTK_WED_RRO_RX_HW_STS,
-+ MTK_WED_RX_IND_CMD_BUSY);
-+ mtk_wed_reset(dev, MTK_WED_RESET_RRO_RX_TO_PG);
-+ }
-+
- wed_clr(dev, MTK_WED_WPDMA_RX_D_GLO_CFG, MTK_WED_WPDMA_RX_D_RX_DRV_EN);
- ret = mtk_wed_poll_busy(dev, MTK_WED_WPDMA_RX_D_GLO_CFG,
- MTK_WED_WPDMA_RX_D_RX_DRV_BUSY);
-+ if (!ret && mtk_wed_is_v3_or_greater(dev->hw))
-+ ret = mtk_wed_poll_busy(dev, MTK_WED_WPDMA_RX_D_PREF_CFG,
-+ MTK_WED_WPDMA_RX_D_PREF_BUSY);
- if (ret) {
- mtk_wed_reset(dev, MTK_WED_RESET_WPDMA_INT_AGENT);
- mtk_wed_reset(dev, MTK_WED_RESET_WPDMA_RX_D_DRV);
- } else {
-+ if (mtk_wed_is_v3_or_greater(dev->hw)) {
-+ /* 1.a. disable prefetch HW */
-+ wed_clr(dev, MTK_WED_WPDMA_RX_D_PREF_CFG,
-+ MTK_WED_WPDMA_RX_D_PREF_EN);
-+ mtk_wed_poll_busy(dev, MTK_WED_WPDMA_RX_D_PREF_CFG,
-+ MTK_WED_WPDMA_RX_D_PREF_BUSY);
-+ wed_w32(dev, MTK_WED_WPDMA_RX_D_RST_IDX,
-+ MTK_WED_WPDMA_RX_D_RST_DRV_IDX_ALL);
-+ }
-+
- wed_w32(dev, MTK_WED_WPDMA_RX_D_RST_IDX,
- MTK_WED_WPDMA_RX_D_RST_CRX_IDX |
- MTK_WED_WPDMA_RX_D_RST_DRV_IDX);
-@@ -1439,23 +1623,52 @@ mtk_wed_rx_reset(struct mtk_wed_device *
- wed_w32(dev, MTK_WED_RROQM_RST_IDX, 0);
- }
-
-+ if (dev->wlan.hw_rro) {
-+ /* disable rro msdu page drv */
-+ wed_clr(dev, MTK_WED_RRO_MSDU_PG_RING2_CFG,
-+ MTK_WED_RRO_MSDU_PG_DRV_EN);
-+
-+ /* disable rro data drv */
-+ wed_clr(dev, MTK_WED_RRO_RX_D_CFG(2), MTK_WED_RRO_RX_D_DRV_EN);
-+
-+ /* rro msdu page drv reset */
-+ wed_w32(dev, MTK_WED_RRO_MSDU_PG_RING2_CFG,
-+ MTK_WED_RRO_MSDU_PG_DRV_CLR);
-+ mtk_wed_poll_busy(dev, MTK_WED_RRO_MSDU_PG_RING2_CFG,
-+ MTK_WED_RRO_MSDU_PG_DRV_CLR);
-+
-+ /* rro data drv reset */
-+ wed_w32(dev, MTK_WED_RRO_RX_D_CFG(2),
-+ MTK_WED_RRO_RX_D_DRV_CLR);
-+ mtk_wed_poll_busy(dev, MTK_WED_RRO_RX_D_CFG(2),
-+ MTK_WED_RRO_RX_D_DRV_CLR);
-+ }
-+
- /* reset route qm */
- wed_clr(dev, MTK_WED_CTRL, MTK_WED_CTRL_RX_ROUTE_QM_EN);
- ret = mtk_wed_poll_busy(dev, MTK_WED_CTRL,
- MTK_WED_CTRL_RX_ROUTE_QM_BUSY);
-- if (ret)
-+ if (ret) {
- mtk_wed_reset(dev, MTK_WED_RESET_RX_ROUTE_QM);
-- else
-- wed_set(dev, MTK_WED_RTQM_GLO_CFG,
-- MTK_WED_RTQM_Q_RST);
-+ } else if (mtk_wed_is_v3_or_greater(dev->hw)) {
-+ wed_set(dev, MTK_WED_RTQM_RST, BIT(0));
-+ wed_clr(dev, MTK_WED_RTQM_RST, BIT(0));
-+ mtk_wed_reset(dev, MTK_WED_RESET_RX_ROUTE_QM);
-+ } else {
-+ wed_set(dev, MTK_WED_RTQM_GLO_CFG, MTK_WED_RTQM_Q_RST);
-+ }
-
- /* reset tx wdma */
- mtk_wdma_tx_reset(dev);
-
- /* reset tx wdma drv */
- wed_clr(dev, MTK_WED_WDMA_GLO_CFG, MTK_WED_WDMA_GLO_CFG_TX_DRV_EN);
-- mtk_wed_poll_busy(dev, MTK_WED_CTRL,
-- MTK_WED_CTRL_WDMA_INT_AGENT_BUSY);
-+ if (mtk_wed_is_v3_or_greater(dev->hw))
-+ mtk_wed_poll_busy(dev, MTK_WED_WPDMA_STATUS,
-+ MTK_WED_WPDMA_STATUS_TX_DRV);
-+ else
-+ mtk_wed_poll_busy(dev, MTK_WED_CTRL,
-+ MTK_WED_CTRL_WDMA_INT_AGENT_BUSY);
- mtk_wed_reset(dev, MTK_WED_RESET_WDMA_TX_DRV);
-
- /* reset wed rx dma */
-@@ -1476,6 +1689,14 @@ mtk_wed_rx_reset(struct mtk_wed_device *
- MTK_WED_CTRL_WED_RX_BM_BUSY);
- mtk_wed_reset(dev, MTK_WED_RESET_RX_BM);
-
-+ if (dev->wlan.hw_rro) {
-+ wed_clr(dev, MTK_WED_CTRL, MTK_WED_CTRL_WED_RX_PG_BM_EN);
-+ mtk_wed_poll_busy(dev, MTK_WED_CTRL,
-+ MTK_WED_CTRL_WED_RX_PG_BM_BUSY);
-+ wed_set(dev, MTK_WED_RESET, MTK_WED_RESET_RX_PG_BM);
-+ wed_clr(dev, MTK_WED_RESET, MTK_WED_RESET_RX_PG_BM);
-+ }
-+
- /* wo change to enable state */
- val = MTK_WED_WO_STATE_ENABLE;
- ret = mtk_wed_mcu_send_msg(wo, MTK_WED_MODULE_ID_WO,
-@@ -1493,6 +1714,7 @@ mtk_wed_rx_reset(struct mtk_wed_device *
- false);
- }
- mtk_wed_free_rx_buffer(dev);
-+ mtk_wed_hwrro_free_buffer(dev);
-
- return 0;
- }
-@@ -1526,15 +1748,41 @@ mtk_wed_reset_dma(struct mtk_wed_device
-
- /* 2. reset WDMA rx DMA */
- busy = !!mtk_wdma_rx_reset(dev);
-- wed_clr(dev, MTK_WED_WDMA_GLO_CFG, MTK_WED_WDMA_GLO_CFG_RX_DRV_EN);
-+ if (mtk_wed_is_v3_or_greater(dev->hw)) {
-+ val = MTK_WED_WDMA_GLO_CFG_RX_DIS_FSM_AUTO_IDLE |
-+ wed_r32(dev, MTK_WED_WDMA_GLO_CFG);
-+ val &= ~MTK_WED_WDMA_GLO_CFG_RX_DRV_EN;
-+ wed_w32(dev, MTK_WED_WDMA_GLO_CFG, val);
-+ } else {
-+ wed_clr(dev, MTK_WED_WDMA_GLO_CFG,
-+ MTK_WED_WDMA_GLO_CFG_RX_DRV_EN);
-+ }
-+
- if (!busy)
- busy = mtk_wed_poll_busy(dev, MTK_WED_WDMA_GLO_CFG,
- MTK_WED_WDMA_GLO_CFG_RX_DRV_BUSY);
-+ if (!busy && mtk_wed_is_v3_or_greater(dev->hw))
-+ busy = mtk_wed_poll_busy(dev, MTK_WED_WDMA_RX_PREF_CFG,
-+ MTK_WED_WDMA_RX_PREF_BUSY);
-
- if (busy) {
- mtk_wed_reset(dev, MTK_WED_RESET_WDMA_INT_AGENT);
- mtk_wed_reset(dev, MTK_WED_RESET_WDMA_RX_DRV);
- } else {
-+ if (mtk_wed_is_v3_or_greater(dev->hw)) {
-+ /* 1.a. disable prefetch HW */
-+ wed_clr(dev, MTK_WED_WDMA_RX_PREF_CFG,
-+ MTK_WED_WDMA_RX_PREF_EN);
-+ mtk_wed_poll_busy(dev, MTK_WED_WDMA_RX_PREF_CFG,
-+ MTK_WED_WDMA_RX_PREF_BUSY);
-+ wed_clr(dev, MTK_WED_WDMA_RX_PREF_CFG,
-+ MTK_WED_WDMA_RX_PREF_DDONE2_EN);
-+
-+ /* 2. Reset dma index */
-+ wed_w32(dev, MTK_WED_WDMA_RESET_IDX,
-+ MTK_WED_WDMA_RESET_IDX_RX_ALL);
-+ }
-+
- wed_w32(dev, MTK_WED_WDMA_RESET_IDX,
- MTK_WED_WDMA_RESET_IDX_RX | MTK_WED_WDMA_RESET_IDX_DRV);
- wed_w32(dev, MTK_WED_WDMA_RESET_IDX, 0);
-@@ -1550,8 +1798,13 @@ mtk_wed_reset_dma(struct mtk_wed_device
- wed_clr(dev, MTK_WED_CTRL, MTK_WED_CTRL_WED_TX_FREE_AGENT_EN);
-
- for (i = 0; i < 100; i++) {
-- val = wed_r32(dev, MTK_WED_TX_BM_INTF);
-- if (FIELD_GET(MTK_WED_TX_BM_INTF_TKFIFO_FDEP, val) == 0x40)
-+ if (mtk_wed_is_v1(dev->hw))
-+ val = FIELD_GET(MTK_WED_TX_BM_INTF_TKFIFO_FDEP,
-+ wed_r32(dev, MTK_WED_TX_BM_INTF));
-+ else
-+ val = FIELD_GET(MTK_WED_TX_TKID_INTF_TKFIFO_FDEP,
-+ wed_r32(dev, MTK_WED_TX_TKID_INTF));
-+ if (val == 0x40)
- break;
- }
-
-@@ -1573,6 +1826,8 @@ mtk_wed_reset_dma(struct mtk_wed_device
- mtk_wed_reset(dev, MTK_WED_RESET_WPDMA_INT_AGENT);
- mtk_wed_reset(dev, MTK_WED_RESET_WPDMA_TX_DRV);
- mtk_wed_reset(dev, MTK_WED_RESET_WPDMA_RX_DRV);
-+ if (mtk_wed_is_v3_or_greater(dev->hw))
-+ wed_w32(dev, MTK_WED_RX1_CTRL2, 0);
- } else {
- wed_w32(dev, MTK_WED_WPDMA_RESET_IDX,
- MTK_WED_WPDMA_RESET_IDX_TX |
-@@ -1589,7 +1844,14 @@ mtk_wed_reset_dma(struct mtk_wed_device
- wed_w32(dev, MTK_WED_RESET_IDX, 0);
- }
-
-- mtk_wed_rx_reset(dev);
-+ if (mtk_wed_is_v3_or_greater(dev->hw)) {
-+ /* reset amsdu engine */
-+ wed_clr(dev, MTK_WED_CTRL, MTK_WED_CTRL_TX_AMSDU_EN);
-+ mtk_wed_reset(dev, MTK_WED_RESET_TX_AMSDU);
-+ }
-+
-+ if (mtk_wed_get_rx_capa(dev))
-+ mtk_wed_rx_reset(dev);
- }
-
- static int
-@@ -1841,6 +2103,7 @@ mtk_wed_dma_enable(struct mtk_wed_device
- MTK_WED_WPDMA_GLO_CFG_RX_DRV_UNS_VER_FORCE_4);
-
- wdma_set(dev, MTK_WDMA_PREF_RX_CFG, MTK_WDMA_PREF_RX_CFG_PREF_EN);
-+ wdma_set(dev, MTK_WDMA_WRBK_RX_CFG, MTK_WDMA_WRBK_RX_CFG_WRBK_EN);
- }
-
- wed_clr(dev, MTK_WED_WPDMA_GLO_CFG,
-@@ -1904,6 +2167,12 @@ mtk_wed_start_hw_rro(struct mtk_wed_devi
- if (!mtk_wed_get_rx_capa(dev) || !dev->wlan.hw_rro)
- return;
-
-+ if (reset) {
-+ wed_set(dev, MTK_WED_RRO_MSDU_PG_RING2_CFG,
-+ MTK_WED_RRO_MSDU_PG_DRV_EN);
-+ return;
-+ }
-+
- wed_set(dev, MTK_WED_RRO_RX_D_CFG(2), MTK_WED_RRO_MSDU_PG_DRV_CLR);
- wed_w32(dev, MTK_WED_RRO_MSDU_PG_RING2_CFG,
- MTK_WED_RRO_MSDU_PG_DRV_CLR);
---- a/drivers/net/ethernet/mediatek/mtk_wed_regs.h
-+++ b/drivers/net/ethernet/mediatek/mtk_wed_regs.h
-@@ -28,6 +28,8 @@ struct mtk_wdma_desc {
- #define MTK_WED_RESET 0x008
- #define MTK_WED_RESET_TX_BM BIT(0)
- #define MTK_WED_RESET_RX_BM BIT(1)
-+#define MTK_WED_RESET_RX_PG_BM BIT(2)
-+#define MTK_WED_RESET_RRO_RX_TO_PG BIT(3)
- #define MTK_WED_RESET_TX_FREE_AGENT BIT(4)
- #define MTK_WED_RESET_WPDMA_TX_DRV BIT(8)
- #define MTK_WED_RESET_WPDMA_RX_DRV BIT(9)
-@@ -106,6 +108,9 @@ struct mtk_wdma_desc {
- #define MTK_WED_STATUS 0x060
- #define MTK_WED_STATUS_TX GENMASK(15, 8)
-
-+#define MTK_WED_WPDMA_STATUS 0x068
-+#define MTK_WED_WPDMA_STATUS_TX_DRV GENMASK(15, 8)
-+
- #define MTK_WED_TX_BM_CTRL 0x080
- #define MTK_WED_TX_BM_CTRL_VLD_GRP_NUM GENMASK(6, 0)
- #define MTK_WED_TX_BM_CTRL_RSV_GRP_NUM GENMASK(22, 16)
-@@ -140,6 +145,9 @@ struct mtk_wdma_desc {
- #define MTK_WED_TX_TKID_CTRL_RSV_GRP_NUM GENMASK(22, 16)
- #define MTK_WED_TX_TKID_CTRL_PAUSE BIT(28)
-
-+#define MTK_WED_TX_TKID_INTF 0x0dc
-+#define MTK_WED_TX_TKID_INTF_TKFIFO_FDEP GENMASK(25, 16)
-+
- #define MTK_WED_TX_TKID_CTRL_VLD_GRP_NUM_V3 GENMASK(7, 0)
- #define MTK_WED_TX_TKID_CTRL_RSV_GRP_NUM_V3 GENMASK(23, 16)
-
-@@ -190,6 +198,7 @@ struct mtk_wdma_desc {
- #define MTK_WED_RING_RX_DATA(_n) (0x420 + (_n) * 0x10)
-
- #define MTK_WED_SCR0 0x3c0
-+#define MTK_WED_RX1_CTRL2 0x418
- #define MTK_WED_WPDMA_INT_TRIGGER 0x504
- #define MTK_WED_WPDMA_INT_TRIGGER_RX_DONE BIT(1)
- #define MTK_WED_WPDMA_INT_TRIGGER_TX_DONE GENMASK(5, 4)
-@@ -303,6 +312,7 @@ struct mtk_wdma_desc {
-
- #define MTK_WED_WPDMA_RX_D_RST_IDX 0x760
- #define MTK_WED_WPDMA_RX_D_RST_CRX_IDX GENMASK(17, 16)
-+#define MTK_WED_WPDMA_RX_D_RST_DRV_IDX_ALL BIT(20)
- #define MTK_WED_WPDMA_RX_D_RST_DRV_IDX GENMASK(25, 24)
-
- #define MTK_WED_WPDMA_RX_GLO_CFG 0x76c
-@@ -313,6 +323,7 @@ struct mtk_wdma_desc {
-
- #define MTK_WED_WPDMA_RX_D_PREF_CFG 0x7b4
- #define MTK_WED_WPDMA_RX_D_PREF_EN BIT(0)
-+#define MTK_WED_WPDMA_RX_D_PREF_BUSY BIT(1)
- #define MTK_WED_WPDMA_RX_D_PREF_BURST_SIZE GENMASK(12, 8)
- #define MTK_WED_WPDMA_RX_D_PREF_LOW_THRES GENMASK(21, 16)
-
-@@ -334,11 +345,13 @@ struct mtk_wdma_desc {
-
- #define MTK_WED_WDMA_RX_PREF_CFG 0x950
- #define MTK_WED_WDMA_RX_PREF_EN BIT(0)
-+#define MTK_WED_WDMA_RX_PREF_BUSY BIT(1)
- #define MTK_WED_WDMA_RX_PREF_BURST_SIZE GENMASK(12, 8)
- #define MTK_WED_WDMA_RX_PREF_LOW_THRES GENMASK(21, 16)
- #define MTK_WED_WDMA_RX_PREF_RX0_SIDX_CLR BIT(24)
- #define MTK_WED_WDMA_RX_PREF_RX1_SIDX_CLR BIT(25)
- #define MTK_WED_WDMA_RX_PREF_DDONE2_EN BIT(26)
-+#define MTK_WED_WDMA_RX_PREF_DDONE2_BUSY BIT(27)
-
- #define MTK_WED_WDMA_RX_PREF_FIFO_CFG 0x95C
- #define MTK_WED_WDMA_RX_PREF_FIFO_RX0_CLR BIT(0)
-@@ -367,6 +380,7 @@ struct mtk_wdma_desc {
-
- #define MTK_WED_WDMA_RESET_IDX 0xa08
- #define MTK_WED_WDMA_RESET_IDX_RX GENMASK(17, 16)
-+#define MTK_WED_WDMA_RESET_IDX_RX_ALL BIT(20)
- #define MTK_WED_WDMA_RESET_IDX_DRV GENMASK(25, 24)
-
- #define MTK_WED_WDMA_INT_CLR 0xa24
-@@ -437,21 +451,62 @@ struct mtk_wdma_desc {
- #define MTK_WDMA_INT_MASK_RX_DELAY BIT(30)
- #define MTK_WDMA_INT_MASK_RX_COHERENT BIT(31)
-
-+#define MTK_WDMA_XDMA_TX_FIFO_CFG 0x238
-+#define MTK_WDMA_XDMA_TX_FIFO_CFG_TX_PAR_FIFO_CLEAR BIT(0)
-+#define MTK_WDMA_XDMA_TX_FIFO_CFG_TX_CMD_FIFO_CLEAR BIT(4)
-+#define MTK_WDMA_XDMA_TX_FIFO_CFG_TX_DMAD_FIFO_CLEAR BIT(8)
-+#define MTK_WDMA_XDMA_TX_FIFO_CFG_TX_ARR_FIFO_CLEAR BIT(12)
-+
-+#define MTK_WDMA_XDMA_RX_FIFO_CFG 0x23c
-+#define MTK_WDMA_XDMA_RX_FIFO_CFG_RX_PAR_FIFO_CLEAR BIT(0)
-+#define MTK_WDMA_XDMA_RX_FIFO_CFG_RX_CMD_FIFO_CLEAR BIT(4)
-+#define MTK_WDMA_XDMA_RX_FIFO_CFG_RX_DMAD_FIFO_CLEAR BIT(8)
-+#define MTK_WDMA_XDMA_RX_FIFO_CFG_RX_ARR_FIFO_CLEAR BIT(12)
-+#define MTK_WDMA_XDMA_RX_FIFO_CFG_RX_LEN_FIFO_CLEAR BIT(15)
-+#define MTK_WDMA_XDMA_RX_FIFO_CFG_RX_WID_FIFO_CLEAR BIT(18)
-+#define MTK_WDMA_XDMA_RX_FIFO_CFG_RX_BID_FIFO_CLEAR BIT(21)
-+
- #define MTK_WDMA_INT_GRP1 0x250
- #define MTK_WDMA_INT_GRP2 0x254
-
- #define MTK_WDMA_PREF_TX_CFG 0x2d0
- #define MTK_WDMA_PREF_TX_CFG_PREF_EN BIT(0)
-+#define MTK_WDMA_PREF_TX_CFG_PREF_BUSY BIT(1)
-
- #define MTK_WDMA_PREF_RX_CFG 0x2dc
- #define MTK_WDMA_PREF_RX_CFG_PREF_EN BIT(0)
-+#define MTK_WDMA_PREF_RX_CFG_PREF_BUSY BIT(1)
-+
-+#define MTK_WDMA_PREF_RX_FIFO_CFG 0x2e0
-+#define MTK_WDMA_PREF_RX_FIFO_CFG_RING0_CLEAR BIT(0)
-+#define MTK_WDMA_PREF_RX_FIFO_CFG_RING1_CLEAR BIT(16)
-+
-+#define MTK_WDMA_PREF_TX_FIFO_CFG 0x2d4
-+#define MTK_WDMA_PREF_TX_FIFO_CFG_RING0_CLEAR BIT(0)
-+#define MTK_WDMA_PREF_TX_FIFO_CFG_RING1_CLEAR BIT(16)
-+
-+#define MTK_WDMA_PREF_SIDX_CFG 0x2e4
-+#define MTK_WDMA_PREF_SIDX_CFG_TX_RING_CLEAR GENMASK(3, 0)
-+#define MTK_WDMA_PREF_SIDX_CFG_RX_RING_CLEAR GENMASK(5, 4)
-
- #define MTK_WDMA_WRBK_TX_CFG 0x300
-+#define MTK_WDMA_WRBK_TX_CFG_WRBK_BUSY BIT(0)
- #define MTK_WDMA_WRBK_TX_CFG_WRBK_EN BIT(30)
-
-+#define MTK_WDMA_WRBK_TX_FIFO_CFG(_n) (0x304 + (_n) * 0x4)
-+#define MTK_WDMA_WRBK_TX_FIFO_CFG_RING_CLEAR BIT(0)
-+
- #define MTK_WDMA_WRBK_RX_CFG 0x344
-+#define MTK_WDMA_WRBK_RX_CFG_WRBK_BUSY BIT(0)
- #define MTK_WDMA_WRBK_RX_CFG_WRBK_EN BIT(30)
-
-+#define MTK_WDMA_WRBK_RX_FIFO_CFG(_n) (0x348 + (_n) * 0x4)
-+#define MTK_WDMA_WRBK_RX_FIFO_CFG_RING_CLEAR BIT(0)
-+
-+#define MTK_WDMA_WRBK_SIDX_CFG 0x388
-+#define MTK_WDMA_WRBK_SIDX_CFG_TX_RING_CLEAR GENMASK(3, 0)
-+#define MTK_WDMA_WRBK_SIDX_CFG_RX_RING_CLEAR GENMASK(5, 4)
-+
- #define MTK_PCIE_MIRROR_MAP(n) ((n) ? 0x4 : 0x0)
- #define MTK_PCIE_MIRROR_MAP_EN BIT(0)
- #define MTK_PCIE_MIRROR_MAP_WED_ID BIT(1)
-@@ -465,6 +520,8 @@ struct mtk_wdma_desc {
- #define MTK_WED_RTQM_Q_DBG_BYPASS BIT(5)
- #define MTK_WED_RTQM_TXDMAD_FPORT GENMASK(23, 20)
-
-+#define MTK_WED_RTQM_RST 0xb04
-+
- #define MTK_WED_RTQM_IGRS0_I2HW_DMAD_CNT 0xb1c
- #define MTK_WED_RTQM_IGRS0_I2H_DMAD_CNT(_n) (0xb20 + (_n) * 0x4)
- #define MTK_WED_RTQM_IGRS0_I2HW_PKT_CNT 0xb28
-@@ -653,6 +710,9 @@ struct mtk_wdma_desc {
- #define MTK_WED_WPDMA_INT_CTRL_RRO_PG2_CLR BIT(17)
- #define MTK_WED_WPDMA_INT_CTRL_RRO_PG2_DONE_TRIG GENMASK(22, 18)
-
-+#define MTK_WED_RRO_RX_HW_STS 0xf00
-+#define MTK_WED_RX_IND_CMD_BUSY GENMASK(31, 0)
-+
- #define MTK_WED_RX_IND_CMD_CNT0 0xf20
- #define MTK_WED_RX_IND_CMD_DBG_CNT_EN BIT(31)
-
+++ /dev/null
-From 52ea72ad0daa0f29535b4cef39257616c5a211d3 Mon Sep 17 00:00:00 2001
-Date: Tue, 24 Oct 2023 00:00:19 +0200
-Subject: [PATCH 1/5] net: ethernet: mtk_wed: fix firmware loading for MT7986
- SoC
-
-The WED mcu firmware does not contain all the memory regions defined in
-the dts reserved_memory node (e.g. MT7986 WED firmware does not contain
-cpu-boot region).
-Reverse the mtk_wed_mcu_run_firmware() logic to check all the fw
-sections are defined in the dts reserved_memory node.
-
-Fixes: c6d961aeaa77 ("net: ethernet: mtk_wed: move mem_region array out of mtk_wed_mcu_load_firmware")
-Link: https://lore.kernel.org/r/d983cbfe8ea562fef9264de8f0c501f7d5705bd5.1698098381.git.lorenzo@kernel.org
----
- drivers/net/ethernet/mediatek/mtk_wed_mcu.c | 48 +++++++++++----------
- 1 file changed, 25 insertions(+), 23 deletions(-)
-
---- a/drivers/net/ethernet/mediatek/mtk_wed_mcu.c
-+++ b/drivers/net/ethernet/mediatek/mtk_wed_mcu.c
-@@ -258,16 +258,12 @@ mtk_wed_get_memory_region(struct mtk_wed
- }
-
- static int
--mtk_wed_mcu_run_firmware(struct mtk_wed_wo *wo, const struct firmware *fw,
-- struct mtk_wed_wo_memory_region *region)
-+mtk_wed_mcu_run_firmware(struct mtk_wed_wo *wo, const struct firmware *fw)
- {
- const u8 *first_region_ptr, *region_ptr, *trailer_ptr, *ptr = fw->data;
- const struct mtk_wed_fw_trailer *trailer;
- const struct mtk_wed_fw_region *fw_region;
-
-- if (!region->phy_addr || !region->size)
-- return 0;
--
- trailer_ptr = fw->data + fw->size - sizeof(*trailer);
- trailer = (const struct mtk_wed_fw_trailer *)trailer_ptr;
- region_ptr = trailer_ptr - trailer->num_region * sizeof(*fw_region);
-@@ -275,33 +271,41 @@ mtk_wed_mcu_run_firmware(struct mtk_wed_
-
- while (region_ptr < trailer_ptr) {
- u32 length;
-+ int i;
-
- fw_region = (const struct mtk_wed_fw_region *)region_ptr;
- length = le32_to_cpu(fw_region->len);
--
-- if (region->phy_addr != le32_to_cpu(fw_region->addr))
-- goto next;
--
-- if (region->size < length)
-- goto next;
--
- if (first_region_ptr < ptr + length)
- goto next;
-
-- if (region->shared && region->consumed)
-- return 0;
-+ for (i = 0; i < ARRAY_SIZE(mem_region); i++) {
-+ struct mtk_wed_wo_memory_region *region;
-
-- if (!region->shared || !region->consumed) {
-- memcpy_toio(region->addr, ptr, length);
-- region->consumed = true;
-- return 0;
-+ region = &mem_region[i];
-+ if (region->phy_addr != le32_to_cpu(fw_region->addr))
-+ continue;
-+
-+ if (region->size < length)
-+ continue;
-+
-+ if (region->shared && region->consumed)
-+ break;
-+
-+ if (!region->shared || !region->consumed) {
-+ memcpy_toio(region->addr, ptr, length);
-+ region->consumed = true;
-+ break;
-+ }
- }
-+
-+ if (i == ARRAY_SIZE(mem_region))
-+ return -EINVAL;
- next:
- region_ptr += sizeof(*fw_region);
- ptr += length;
- }
-
-- return -EINVAL;
-+ return 0;
- }
-
- static int
-@@ -360,11 +364,9 @@ mtk_wed_mcu_load_firmware(struct mtk_wed
- dev_info(wo->hw->dev, "MTK WED WO Chip ID %02x Region %d\n",
- trailer->chip_id, trailer->num_region);
-
-- for (i = 0; i < ARRAY_SIZE(mem_region); i++) {
-- ret = mtk_wed_mcu_run_firmware(wo, fw, &mem_region[i]);
-- if (ret)
-- goto out;
-- }
-+ ret = mtk_wed_mcu_run_firmware(wo, fw);
-+ if (ret)
-+ goto out;
-
- /* set the start address */
- if (!mtk_wed_is_v3_or_greater(wo->hw) && wo->hw->index)
+++ /dev/null
-From 7aa8defd3495208289abcc629946af26a2af3391 Mon Sep 17 00:00:00 2001
-Date: Tue, 24 Oct 2023 00:01:30 +0200
-Subject: [PATCH 2/5] net: ethernet: mtk_wed: remove wo pointer in
- wo_r32/wo_w32 signature
-
-wo pointer is no longer used in wo_r32 and wo_w32 routines so get rid of
-it.
-
-Link: https://lore.kernel.org/r/530537db0872f7523deff21f0a5dfdd9b75fdc9d.1698098459.git.lorenzo@kernel.org
----
- drivers/net/ethernet/mediatek/mtk_wed_mcu.c | 12 ++++++------
- 1 file changed, 6 insertions(+), 6 deletions(-)
-
---- a/drivers/net/ethernet/mediatek/mtk_wed_mcu.c
-+++ b/drivers/net/ethernet/mediatek/mtk_wed_mcu.c
-@@ -32,12 +32,12 @@ static struct mtk_wed_wo_memory_region m
- },
- };
-
--static u32 wo_r32(struct mtk_wed_wo *wo, u32 reg)
-+static u32 wo_r32(u32 reg)
- {
- return readl(mem_region[MTK_WED_WO_REGION_BOOT].addr + reg);
- }
-
--static void wo_w32(struct mtk_wed_wo *wo, u32 reg, u32 val)
-+static void wo_w32(u32 reg, u32 val)
- {
- writel(val, mem_region[MTK_WED_WO_REGION_BOOT].addr + reg);
- }
-@@ -373,13 +373,13 @@ mtk_wed_mcu_load_firmware(struct mtk_wed
- boot_cr = MTK_WO_MCU_CFG_LS_WA_BOOT_ADDR_ADDR;
- else
- boot_cr = MTK_WO_MCU_CFG_LS_WM_BOOT_ADDR_ADDR;
-- wo_w32(wo, boot_cr, mem_region[MTK_WED_WO_REGION_EMI].phy_addr >> 16);
-+ wo_w32(boot_cr, mem_region[MTK_WED_WO_REGION_EMI].phy_addr >> 16);
- /* wo firmware reset */
-- wo_w32(wo, MTK_WO_MCU_CFG_LS_WF_MCCR_CLR_ADDR, 0xc00);
-+ wo_w32(MTK_WO_MCU_CFG_LS_WF_MCCR_CLR_ADDR, 0xc00);
-
-- val = wo_r32(wo, MTK_WO_MCU_CFG_LS_WF_MCU_CFG_WM_WA_ADDR) |
-+ val = wo_r32(MTK_WO_MCU_CFG_LS_WF_MCU_CFG_WM_WA_ADDR) |
- MTK_WO_MCU_CFG_LS_WF_WM_WA_WM_CPU_RSTB_MASK;
-- wo_w32(wo, MTK_WO_MCU_CFG_LS_WF_MCU_CFG_WM_WA_ADDR, val);
-+ wo_w32(MTK_WO_MCU_CFG_LS_WF_MCU_CFG_WM_WA_ADDR, val);
- out:
- release_firmware(fw);
-
+++ /dev/null
-From 65aacd457eaf5d0c958ed8030ec46f99ea808dd9 Mon Sep 17 00:00:00 2001
-Date: Fri, 17 Nov 2023 17:39:22 +0100
-Subject: [PATCH 3/5] net: ethernet: mtk_wed: rely on __dev_alloc_page in
- mtk_wed_tx_buffer_alloc
-
-Simplify the code and use __dev_alloc_page() instead of __dev_alloc_pages()
-with order 0 in mtk_wed_tx_buffer_alloc routine
-
----
- drivers/net/ethernet/mediatek/mtk_wed.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/net/ethernet/mediatek/mtk_wed.c
-+++ b/drivers/net/ethernet/mediatek/mtk_wed.c
-@@ -670,7 +670,7 @@ mtk_wed_tx_buffer_alloc(struct mtk_wed_d
- void *buf;
- int s;
-
-- page = __dev_alloc_pages(GFP_KERNEL, 0);
-+ page = __dev_alloc_page(GFP_KERNEL);
- if (!page)
- return -ENOMEM;
-
+++ /dev/null
-From 5f5997322584b6257543d4d103f81484b8006d84 Mon Sep 17 00:00:00 2001
-Date: Fri, 17 Nov 2023 17:42:59 +0100
-Subject: [PATCH 4/5] net: ethernet: mtk_wed: add support for devices with more
- than 4GB of dram
-
-Introduce WED offloading support for boards with more than 4GB of
-memory.
-
-Link: https://lore.kernel.org/r/1c7efdf5d384ea7af3c0209723e40b2ee0f956bf.1700239272.git.lorenzo@kernel.org
----
- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 5 ++++-
- drivers/net/ethernet/mediatek/mtk_wed.c | 8 +++++---
- drivers/net/ethernet/mediatek/mtk_wed_wo.c | 3 ++-
- 3 files changed, 11 insertions(+), 5 deletions(-)
-
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -1158,15 +1158,18 @@ static int mtk_init_fq_dma(struct mtk_et
- phy_ring_tail = eth->phy_scratch_ring + soc->tx.desc_size * (cnt - 1);
-
- for (i = 0; i < cnt; i++) {
-+ dma_addr_t addr = dma_addr + i * MTK_QDMA_PAGE_SIZE;
- struct mtk_tx_dma_v2 *txd;
-
- txd = eth->scratch_ring + i * soc->tx.desc_size;
-- txd->txd1 = dma_addr + i * MTK_QDMA_PAGE_SIZE;
-+ txd->txd1 = addr;
- if (i < cnt - 1)
- txd->txd2 = eth->phy_scratch_ring +
- (i + 1) * soc->tx.desc_size;
-
- txd->txd3 = TX_DMA_PLEN0(MTK_QDMA_PAGE_SIZE);
-+ if (MTK_HAS_CAPS(soc->caps, MTK_36BIT_DMA))
-+ txd->txd3 |= TX_DMA_PREP_ADDR64(addr);
- txd->txd4 = 0;
- if (mtk_is_netsys_v2_or_greater(eth)) {
- txd->txd5 = 0;
---- a/drivers/net/ethernet/mediatek/mtk_wed.c
-+++ b/drivers/net/ethernet/mediatek/mtk_wed.c
-@@ -691,10 +691,11 @@ mtk_wed_tx_buffer_alloc(struct mtk_wed_d
-
- for (s = 0; s < MTK_WED_BUF_PER_PAGE; s++) {
- struct mtk_wdma_desc *desc = desc_ptr;
-+ u32 ctrl;
-
- desc->buf0 = cpu_to_le32(buf_phys);
- if (!mtk_wed_is_v3_or_greater(dev->hw)) {
-- u32 txd_size, ctrl;
-+ u32 txd_size;
-
- txd_size = dev->wlan.init_buf(buf, buf_phys,
- token++);
-@@ -708,11 +709,11 @@ mtk_wed_tx_buffer_alloc(struct mtk_wed_d
- ctrl |= MTK_WDMA_DESC_CTRL_LAST_SEG0 |
- FIELD_PREP(MTK_WDMA_DESC_CTRL_LEN1_V2,
- MTK_WED_BUF_SIZE - txd_size);
-- desc->ctrl = cpu_to_le32(ctrl);
- desc->info = 0;
- } else {
-- desc->ctrl = cpu_to_le32(token << 16);
-+ ctrl = token << 16 | TX_DMA_PREP_ADDR64(buf_phys);
- }
-+ desc->ctrl = cpu_to_le32(ctrl);
-
- desc_ptr += desc_size;
- buf += MTK_WED_BUF_SIZE;
-@@ -811,6 +812,7 @@ mtk_wed_hwrro_buffer_alloc(struct mtk_we
- buf_phys = page_phys;
- for (s = 0; s < MTK_WED_RX_BUF_PER_PAGE; s++) {
- desc->buf0 = cpu_to_le32(buf_phys);
-+ desc->token = cpu_to_le32(RX_DMA_PREP_ADDR64(buf_phys));
- buf_phys += MTK_WED_PAGE_BUF_SIZE;
- desc++;
- }
---- a/drivers/net/ethernet/mediatek/mtk_wed_wo.c
-+++ b/drivers/net/ethernet/mediatek/mtk_wed_wo.c
-@@ -142,7 +142,8 @@ mtk_wed_wo_queue_refill(struct mtk_wed_w
- dma_addr_t addr;
- void *buf;
-
-- buf = page_frag_alloc(&q->cache, q->buf_size, GFP_ATOMIC);
-+ buf = page_frag_alloc(&q->cache, q->buf_size,
-+ GFP_ATOMIC | GFP_DMA32);
- if (!buf)
- break;
-
+++ /dev/null
-From c57e558194430d10d5e5f4acd8a8655b68dade13 Mon Sep 17 00:00:00 2001
-Date: Mon, 3 Jun 2024 21:25:05 +0200
-Subject: [PATCH] net: ethernet: mtk_eth_soc: handle dma buffer size soc
- specific
-
-The mainline MTK ethernet driver suffers long time from rarly but
-annoying tx queue timeouts. We think that this is caused by fixed
-dma sizes hardcoded for all SoCs.
-
-We suspect this problem arises from a low level of free TX DMADs,
-the TX Ring alomost full.
-
-The transmit timeout is caused by the Tx queue not waking up. The
-Tx queue stops when the free counter is less than ring->thres, and
-it will wake up once the free counter is greater than ring->thres.
-If the CPU is too late to wake up the Tx queues, it may cause a
-transmit timeout.
-Therefore, we increased the TX and RX DMADs to improve this error
-situation.
-
-Use the dma-size implementation from SDK in a per SoC manner. In
-difference to SDK we have no RSS feature yet, so all RX/TX sizes
-should be raised from 512 to 2048 byte except fqdma on mt7988 to
-avoid the tx timeout issue.
-
-Fixes: 656e705243fd ("net-next: mediatek: add support for MT7623 ethernet")
----
- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 104 +++++++++++++-------
- drivers/net/ethernet/mediatek/mtk_eth_soc.h | 9 +-
- 2 files changed, 77 insertions(+), 36 deletions(-)
-
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -1131,9 +1131,9 @@ static int mtk_init_fq_dma(struct mtk_et
- {
- const struct mtk_soc_data *soc = eth->soc;
- dma_addr_t phy_ring_tail;
-- int cnt = MTK_QDMA_RING_SIZE;
-+ int cnt = soc->tx.fq_dma_size;
- dma_addr_t dma_addr;
-- int i;
-+ int i, j, len;
-
- if (MTK_HAS_CAPS(eth->soc->caps, MTK_SRAM))
- eth->scratch_ring = eth->sram_base;
-@@ -1142,40 +1142,46 @@ static int mtk_init_fq_dma(struct mtk_et
- cnt * soc->tx.desc_size,
- ð->phy_scratch_ring,
- GFP_KERNEL);
-+
- if (unlikely(!eth->scratch_ring))
- return -ENOMEM;
-
-- eth->scratch_head = kcalloc(cnt, MTK_QDMA_PAGE_SIZE, GFP_KERNEL);
-- if (unlikely(!eth->scratch_head))
-- return -ENOMEM;
-+ phy_ring_tail = eth->phy_scratch_ring + soc->tx.desc_size * (cnt - 1);
-
-- dma_addr = dma_map_single(eth->dma_dev,
-- eth->scratch_head, cnt * MTK_QDMA_PAGE_SIZE,
-- DMA_FROM_DEVICE);
-- if (unlikely(dma_mapping_error(eth->dma_dev, dma_addr)))
-- return -ENOMEM;
-+ for (j = 0; j < DIV_ROUND_UP(soc->tx.fq_dma_size, MTK_FQ_DMA_LENGTH); j++) {
-+ len = min_t(int, cnt - j * MTK_FQ_DMA_LENGTH, MTK_FQ_DMA_LENGTH);
-+ eth->scratch_head[j] = kcalloc(len, MTK_QDMA_PAGE_SIZE, GFP_KERNEL);
-
-- phy_ring_tail = eth->phy_scratch_ring + soc->tx.desc_size * (cnt - 1);
-+ if (unlikely(!eth->scratch_head[j]))
-+ return -ENOMEM;
-
-- for (i = 0; i < cnt; i++) {
-- dma_addr_t addr = dma_addr + i * MTK_QDMA_PAGE_SIZE;
-- struct mtk_tx_dma_v2 *txd;
--
-- txd = eth->scratch_ring + i * soc->tx.desc_size;
-- txd->txd1 = addr;
-- if (i < cnt - 1)
-- txd->txd2 = eth->phy_scratch_ring +
-- (i + 1) * soc->tx.desc_size;
--
-- txd->txd3 = TX_DMA_PLEN0(MTK_QDMA_PAGE_SIZE);
-- if (MTK_HAS_CAPS(soc->caps, MTK_36BIT_DMA))
-- txd->txd3 |= TX_DMA_PREP_ADDR64(addr);
-- txd->txd4 = 0;
-- if (mtk_is_netsys_v2_or_greater(eth)) {
-- txd->txd5 = 0;
-- txd->txd6 = 0;
-- txd->txd7 = 0;
-- txd->txd8 = 0;
-+ dma_addr = dma_map_single(eth->dma_dev,
-+ eth->scratch_head[j], len * MTK_QDMA_PAGE_SIZE,
-+ DMA_FROM_DEVICE);
-+
-+ if (unlikely(dma_mapping_error(eth->dma_dev, dma_addr)))
-+ return -ENOMEM;
-+
-+ for (i = 0; i < cnt; i++) {
-+ struct mtk_tx_dma_v2 *txd;
-+
-+ txd = eth->scratch_ring + (j * MTK_FQ_DMA_LENGTH + i) * soc->tx.desc_size;
-+ txd->txd1 = dma_addr + i * MTK_QDMA_PAGE_SIZE;
-+ if (j * MTK_FQ_DMA_LENGTH + i < cnt)
-+ txd->txd2 = eth->phy_scratch_ring +
-+ (j * MTK_FQ_DMA_LENGTH + i + 1) * soc->tx.desc_size;
-+
-+ txd->txd3 = TX_DMA_PLEN0(MTK_QDMA_PAGE_SIZE);
-+ if (MTK_HAS_CAPS(soc->caps, MTK_36BIT_DMA))
-+ txd->txd3 |= TX_DMA_PREP_ADDR64(dma_addr + i * MTK_QDMA_PAGE_SIZE);
-+
-+ txd->txd4 = 0;
-+ if (mtk_is_netsys_v2_or_greater(eth)) {
-+ txd->txd5 = 0;
-+ txd->txd6 = 0;
-+ txd->txd7 = 0;
-+ txd->txd8 = 0;
-+ }
- }
- }
-
-@@ -2469,7 +2475,7 @@ static int mtk_tx_alloc(struct mtk_eth *
- if (MTK_HAS_CAPS(soc->caps, MTK_QDMA))
- ring_size = MTK_QDMA_RING_SIZE;
- else
-- ring_size = MTK_DMA_SIZE;
-+ ring_size = soc->tx.dma_size;
-
- ring->buf = kcalloc(ring_size, sizeof(*ring->buf),
- GFP_KERNEL);
-@@ -2477,8 +2483,8 @@ static int mtk_tx_alloc(struct mtk_eth *
- goto no_tx_mem;
-
- if (MTK_HAS_CAPS(soc->caps, MTK_SRAM)) {
-- ring->dma = eth->sram_base + ring_size * sz;
-- ring->phys = eth->phy_scratch_ring + ring_size * (dma_addr_t)sz;
-+ ring->dma = eth->sram_base + soc->tx.fq_dma_size * sz;
-+ ring->phys = eth->phy_scratch_ring + soc->tx.fq_dma_size * (dma_addr_t)sz;
- } else {
- ring->dma = dma_alloc_coherent(eth->dma_dev, ring_size * sz,
- &ring->phys, GFP_KERNEL);
-@@ -2600,6 +2606,7 @@ static void mtk_tx_clean(struct mtk_eth
- static int mtk_rx_alloc(struct mtk_eth *eth, int ring_no, int rx_flag)
- {
- const struct mtk_reg_map *reg_map = eth->soc->reg_map;
-+ const struct mtk_soc_data *soc = eth->soc;
- struct mtk_rx_ring *ring;
- int rx_data_len, rx_dma_size, tx_ring_size;
- int i;
-@@ -2607,7 +2614,7 @@ static int mtk_rx_alloc(struct mtk_eth *
- if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA))
- tx_ring_size = MTK_QDMA_RING_SIZE;
- else
-- tx_ring_size = MTK_DMA_SIZE;
-+ tx_ring_size = soc->tx.dma_size;
-
- if (rx_flag == MTK_RX_FLAGS_QDMA) {
- if (ring_no)
-@@ -2622,7 +2629,7 @@ static int mtk_rx_alloc(struct mtk_eth *
- rx_dma_size = MTK_HW_LRO_DMA_SIZE;
- } else {
- rx_data_len = ETH_DATA_LEN;
-- rx_dma_size = MTK_DMA_SIZE;
-+ rx_dma_size = soc->rx.dma_size;
- }
-
- ring->frag_size = mtk_max_frag_size(rx_data_len);
-@@ -3159,7 +3166,10 @@ static void mtk_dma_free(struct mtk_eth
- mtk_rx_clean(eth, ð->rx_ring[i], false);
- }
-
-- kfree(eth->scratch_head);
-+ for (i = 0; i < DIV_ROUND_UP(soc->tx.fq_dma_size, MTK_FQ_DMA_LENGTH); i++) {
-+ kfree(eth->scratch_head[i]);
-+ eth->scratch_head[i] = NULL;
-+ }
- }
-
- static bool mtk_hw_reset_check(struct mtk_eth *eth)
-@@ -5081,11 +5091,14 @@ static const struct mtk_soc_data mt2701_
- .desc_size = sizeof(struct mtk_tx_dma),
- .dma_max_len = MTK_TX_DMA_BUF_LEN,
- .dma_len_offset = 16,
-+ .dma_size = MTK_DMA_SIZE(2K),
-+ .fq_dma_size = MTK_DMA_SIZE(2K),
- },
- .rx = {
- .desc_size = sizeof(struct mtk_rx_dma),
- .irq_done_mask = MTK_RX_DONE_INT,
- .dma_l4_valid = RX_DMA_L4_VALID,
-+ .dma_size = MTK_DMA_SIZE(2K),
- .dma_max_len = MTK_TX_DMA_BUF_LEN,
- .dma_len_offset = 16,
- },
-@@ -5105,11 +5118,14 @@ static const struct mtk_soc_data mt7621_
- .desc_size = sizeof(struct mtk_tx_dma),
- .dma_max_len = MTK_TX_DMA_BUF_LEN,
- .dma_len_offset = 16,
-+ .dma_size = MTK_DMA_SIZE(2K),
-+ .fq_dma_size = MTK_DMA_SIZE(2K),
- },
- .rx = {
- .desc_size = sizeof(struct mtk_rx_dma),
- .irq_done_mask = MTK_RX_DONE_INT,
- .dma_l4_valid = RX_DMA_L4_VALID,
-+ .dma_size = MTK_DMA_SIZE(2K),
- .dma_max_len = MTK_TX_DMA_BUF_LEN,
- .dma_len_offset = 16,
- },
-@@ -5131,11 +5147,14 @@ static const struct mtk_soc_data mt7622_
- .desc_size = sizeof(struct mtk_tx_dma),
- .dma_max_len = MTK_TX_DMA_BUF_LEN,
- .dma_len_offset = 16,
-+ .dma_size = MTK_DMA_SIZE(2K),
-+ .fq_dma_size = MTK_DMA_SIZE(2K),
- },
- .rx = {
- .desc_size = sizeof(struct mtk_rx_dma),
- .irq_done_mask = MTK_RX_DONE_INT,
- .dma_l4_valid = RX_DMA_L4_VALID,
-+ .dma_size = MTK_DMA_SIZE(2K),
- .dma_max_len = MTK_TX_DMA_BUF_LEN,
- .dma_len_offset = 16,
- },
-@@ -5156,11 +5175,14 @@ static const struct mtk_soc_data mt7623_
- .desc_size = sizeof(struct mtk_tx_dma),
- .dma_max_len = MTK_TX_DMA_BUF_LEN,
- .dma_len_offset = 16,
-+ .dma_size = MTK_DMA_SIZE(2K),
-+ .fq_dma_size = MTK_DMA_SIZE(2K),
- },
- .rx = {
- .desc_size = sizeof(struct mtk_rx_dma),
- .irq_done_mask = MTK_RX_DONE_INT,
- .dma_l4_valid = RX_DMA_L4_VALID,
-+ .dma_size = MTK_DMA_SIZE(2K),
- .dma_max_len = MTK_TX_DMA_BUF_LEN,
- .dma_len_offset = 16,
- },
-@@ -5179,11 +5201,14 @@ static const struct mtk_soc_data mt7629_
- .desc_size = sizeof(struct mtk_tx_dma),
- .dma_max_len = MTK_TX_DMA_BUF_LEN,
- .dma_len_offset = 16,
-+ .dma_size = MTK_DMA_SIZE(2K),
-+ .fq_dma_size = MTK_DMA_SIZE(2K),
- },
- .rx = {
- .desc_size = sizeof(struct mtk_rx_dma),
- .irq_done_mask = MTK_RX_DONE_INT,
- .dma_l4_valid = RX_DMA_L4_VALID,
-+ .dma_size = MTK_DMA_SIZE(2K),
- .dma_max_len = MTK_TX_DMA_BUF_LEN,
- .dma_len_offset = 16,
- },
-@@ -5205,6 +5230,8 @@ static const struct mtk_soc_data mt7981_
- .desc_size = sizeof(struct mtk_tx_dma_v2),
- .dma_max_len = MTK_TX_DMA_BUF_LEN_V2,
- .dma_len_offset = 8,
-+ .dma_size = MTK_DMA_SIZE(2K),
-+ .fq_dma_size = MTK_DMA_SIZE(2K),
- },
- .rx = {
- .desc_size = sizeof(struct mtk_rx_dma),
-@@ -5212,6 +5239,7 @@ static const struct mtk_soc_data mt7981_
- .dma_l4_valid = RX_DMA_L4_VALID_V2,
- .dma_max_len = MTK_TX_DMA_BUF_LEN,
- .dma_len_offset = 16,
-+ .dma_size = MTK_DMA_SIZE(2K),
- },
- };
-
-@@ -5231,6 +5259,8 @@ static const struct mtk_soc_data mt7986_
- .desc_size = sizeof(struct mtk_tx_dma_v2),
- .dma_max_len = MTK_TX_DMA_BUF_LEN_V2,
- .dma_len_offset = 8,
-+ .dma_size = MTK_DMA_SIZE(2K),
-+ .fq_dma_size = MTK_DMA_SIZE(2K),
- },
- .rx = {
- .desc_size = sizeof(struct mtk_rx_dma),
-@@ -5238,6 +5268,7 @@ static const struct mtk_soc_data mt7986_
- .dma_l4_valid = RX_DMA_L4_VALID_V2,
- .dma_max_len = MTK_TX_DMA_BUF_LEN,
- .dma_len_offset = 16,
-+ .dma_size = MTK_DMA_SIZE(2K),
- },
- };
-
-@@ -5257,6 +5288,8 @@ static const struct mtk_soc_data mt7988_
- .desc_size = sizeof(struct mtk_tx_dma_v2),
- .dma_max_len = MTK_TX_DMA_BUF_LEN_V2,
- .dma_len_offset = 8,
-+ .dma_size = MTK_DMA_SIZE(2K),
-+ .fq_dma_size = MTK_DMA_SIZE(4K),
- },
- .rx = {
- .desc_size = sizeof(struct mtk_rx_dma_v2),
-@@ -5264,6 +5297,7 @@ static const struct mtk_soc_data mt7988_
- .dma_l4_valid = RX_DMA_L4_VALID_V2,
- .dma_max_len = MTK_TX_DMA_BUF_LEN_V2,
- .dma_len_offset = 8,
-+ .dma_size = MTK_DMA_SIZE(2K),
- },
- };
-
-@@ -5278,6 +5312,7 @@ static const struct mtk_soc_data rt5350_
- .desc_size = sizeof(struct mtk_tx_dma),
- .dma_max_len = MTK_TX_DMA_BUF_LEN,
- .dma_len_offset = 16,
-+ .dma_size = MTK_DMA_SIZE(2K),
- },
- .rx = {
- .desc_size = sizeof(struct mtk_rx_dma),
-@@ -5285,6 +5320,7 @@ static const struct mtk_soc_data rt5350_
- .dma_l4_valid = RX_DMA_L4_VALID_PDMA,
- .dma_max_len = MTK_TX_DMA_BUF_LEN,
- .dma_len_offset = 16,
-+ .dma_size = MTK_DMA_SIZE(2K),
- },
- };
-
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-@@ -32,7 +32,9 @@
- #define MTK_TX_DMA_BUF_LEN 0x3fff
- #define MTK_TX_DMA_BUF_LEN_V2 0xffff
- #define MTK_QDMA_RING_SIZE 2048
--#define MTK_DMA_SIZE 512
-+#define MTK_DMA_SIZE(x) (SZ_##x)
-+#define MTK_FQ_DMA_HEAD 32
-+#define MTK_FQ_DMA_LENGTH 2048
- #define MTK_RX_ETH_HLEN (ETH_HLEN + ETH_FCS_LEN)
- #define MTK_RX_HLEN (NET_SKB_PAD + MTK_RX_ETH_HLEN + NET_IP_ALIGN)
- #define MTK_DMA_DUMMY_DESC 0xffffffff
-@@ -1184,6 +1186,8 @@ struct mtk_soc_data {
- u32 desc_size;
- u32 dma_max_len;
- u32 dma_len_offset;
-+ u32 dma_size;
-+ u32 fq_dma_size;
- } tx;
- struct {
- u32 desc_size;
-@@ -1191,6 +1195,7 @@ struct mtk_soc_data {
- u32 dma_l4_valid;
- u32 dma_max_len;
- u32 dma_len_offset;
-+ u32 dma_size;
- } rx;
- };
-
-@@ -1272,7 +1277,7 @@ struct mtk_eth {
- struct napi_struct rx_napi;
- void *scratch_ring;
- dma_addr_t phy_scratch_ring;
-- void *scratch_head;
-+ void *scratch_head[MTK_FQ_DMA_HEAD];
- struct clk *clks[MTK_CLK_MAX];
-
- struct mii_bus *mii_bus;
+++ /dev/null
-From dee4dd10c79aaca192b73520d8fb64628468ae0f Mon Sep 17 00:00:00 2001
-Date: Fri, 7 Jun 2024 11:21:50 +0300
-Subject: [PATCH] net: ethernet: mtk_eth_soc: ppe: add support for multiple
- PPEs
-
-Add the missing pieces to allow multiple PPEs units, one for each GMAC.
-mtk_gdm_config has been modified to work on targted mac ID,
-the inner loop moved outside of the function to allow unrelated
-operations like setting the MAC's PPE index.
-Introduce a sanity check in flow_offload_replace to account for
-non-MTK ingress devices.
-Additional field 'ppe_idx' was added to struct mtk_mac in order
-to keep track on the assigned PPE unit.
-
----
- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 112 +++++++++++-------
- drivers/net/ethernet/mediatek/mtk_eth_soc.h | 8 +-
- .../net/ethernet/mediatek/mtk_ppe_offload.c | 17 ++-
- 3 files changed, 92 insertions(+), 45 deletions(-)
-
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -80,7 +80,9 @@ static const struct mtk_reg_map mtk_reg_
- .fq_blen = 0x1b2c,
- },
- .gdm1_cnt = 0x2400,
-- .gdma_to_ppe = 0x4444,
-+ .gdma_to_ppe = {
-+ [0] = 0x4444,
-+ },
- .ppe_base = 0x0c00,
- .wdma_base = {
- [0] = 0x2800,
-@@ -144,7 +146,10 @@ static const struct mtk_reg_map mt7986_r
- .tx_sch_rate = 0x4798,
- },
- .gdm1_cnt = 0x1c00,
-- .gdma_to_ppe = 0x3333,
-+ .gdma_to_ppe = {
-+ [0] = 0x3333,
-+ [1] = 0x4444,
-+ },
- .ppe_base = 0x2000,
- .wdma_base = {
- [0] = 0x4800,
-@@ -192,7 +197,11 @@ static const struct mtk_reg_map mt7988_r
- .tx_sch_rate = 0x4798,
- },
- .gdm1_cnt = 0x1c00,
-- .gdma_to_ppe = 0x3333,
-+ .gdma_to_ppe = {
-+ [0] = 0x3333,
-+ [1] = 0x4444,
-+ [2] = 0xcccc,
-+ },
- .ppe_base = 0x2000,
- .wdma_base = {
- [0] = 0x4800,
-@@ -2023,6 +2032,7 @@ static int mtk_poll_rx(struct napi_struc
- struct mtk_rx_dma_v2 *rxd, trxd;
- int done = 0, bytes = 0;
- dma_addr_t dma_addr = DMA_MAPPING_ERROR;
-+ int ppe_idx = 0;
-
- while (done < budget) {
- unsigned int pktlen, *rxdcsum;
-@@ -2066,6 +2076,7 @@ static int mtk_poll_rx(struct napi_struc
- goto release_desc;
-
- netdev = eth->netdev[mac];
-+ ppe_idx = eth->mac[mac]->ppe_idx;
-
- if (unlikely(test_bit(MTK_RESETTING, ð->state)))
- goto release_desc;
-@@ -2189,7 +2200,7 @@ static int mtk_poll_rx(struct napi_struc
- }
-
- if (reason == MTK_PPE_CPU_REASON_HIT_UNBIND_RATE_REACHED)
-- mtk_ppe_check_skb(eth->ppe[0], skb, hash);
-+ mtk_ppe_check_skb(eth->ppe[ppe_idx], skb, hash);
-
- skb_record_rx_queue(skb, 0);
- napi_gro_receive(napi, skb);
-@@ -3296,37 +3307,27 @@ static int mtk_start_dma(struct mtk_eth
- return 0;
- }
-
--static void mtk_gdm_config(struct mtk_eth *eth, u32 config)
-+static void mtk_gdm_config(struct mtk_eth *eth, u32 id, u32 config)
- {
-- int i;
-+ u32 val;
-
- if (MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628))
- return;
-
-- for (i = 0; i < MTK_MAX_DEVS; i++) {
-- u32 val;
--
-- if (!eth->netdev[i])
-- continue;
-+ val = mtk_r32(eth, MTK_GDMA_FWD_CFG(id));
-
-- val = mtk_r32(eth, MTK_GDMA_FWD_CFG(i));
-+ /* default setup the forward port to send frame to PDMA */
-+ val &= ~0xffff;
-
-- /* default setup the forward port to send frame to PDMA */
-- val &= ~0xffff;
-+ /* Enable RX checksum */
-+ val |= MTK_GDMA_ICS_EN | MTK_GDMA_TCS_EN | MTK_GDMA_UCS_EN;
-
-- /* Enable RX checksum */
-- val |= MTK_GDMA_ICS_EN | MTK_GDMA_TCS_EN | MTK_GDMA_UCS_EN;
-+ val |= config;
-
-- val |= config;
-+ if (eth->netdev[id] && netdev_uses_dsa(eth->netdev[id]))
-+ val |= MTK_GDMA_SPECIAL_TAG;
-
-- if (netdev_uses_dsa(eth->netdev[i]))
-- val |= MTK_GDMA_SPECIAL_TAG;
--
-- mtk_w32(eth, val, MTK_GDMA_FWD_CFG(i));
-- }
-- /* Reset and enable PSE */
-- mtk_w32(eth, RST_GL_PSE, MTK_RST_GL);
-- mtk_w32(eth, 0, MTK_RST_GL);
-+ mtk_w32(eth, val, MTK_GDMA_FWD_CFG(id));
- }
-
-
-@@ -3386,7 +3387,10 @@ static int mtk_open(struct net_device *d
- {
- struct mtk_mac *mac = netdev_priv(dev);
- struct mtk_eth *eth = mac->hw;
-- int i, err;
-+ struct mtk_mac *target_mac;
-+ int i, err, ppe_num;
-+
-+ ppe_num = eth->soc->ppe_num;
-
- err = phylink_of_phy_connect(mac->phylink, mac->of_node, 0);
- if (err) {
-@@ -3410,18 +3414,38 @@ static int mtk_open(struct net_device *d
- for (i = 0; i < ARRAY_SIZE(eth->ppe); i++)
- mtk_ppe_start(eth->ppe[i]);
-
-- gdm_config = soc->offload_version ? soc->reg_map->gdma_to_ppe
-- : MTK_GDMA_TO_PDMA;
-- mtk_gdm_config(eth, gdm_config);
-+ for (i = 0; i < MTK_MAX_DEVS; i++) {
-+ if (!eth->netdev[i])
-+ break;
-+
-+ target_mac = netdev_priv(eth->netdev[i]);
-+ if (!soc->offload_version) {
-+ target_mac->ppe_idx = 0;
-+ gdm_config = MTK_GDMA_TO_PDMA;
-+ } else if (ppe_num >= 3 && target_mac->id == 2) {
-+ target_mac->ppe_idx = 2;
-+ gdm_config = soc->reg_map->gdma_to_ppe[2];
-+ } else if (ppe_num >= 2 && target_mac->id == 1) {
-+ target_mac->ppe_idx = 1;
-+ gdm_config = soc->reg_map->gdma_to_ppe[1];
-+ } else {
-+ target_mac->ppe_idx = 0;
-+ gdm_config = soc->reg_map->gdma_to_ppe[0];
-+ }
-+ mtk_gdm_config(eth, target_mac->id, gdm_config);
-+ }
-+ /* Reset and enable PSE */
-+ mtk_w32(eth, RST_GL_PSE, MTK_RST_GL);
-+ mtk_w32(eth, 0, MTK_RST_GL);
-
- napi_enable(ð->tx_napi);
- napi_enable(ð->rx_napi);
- mtk_tx_irq_enable(eth, MTK_TX_DONE_INT);
- mtk_rx_irq_enable(eth, soc->rx.irq_done_mask);
- refcount_set(ð->dma_refcnt, 1);
-- }
-- else
-+ } else {
- refcount_inc(ð->dma_refcnt);
-+ }
-
- phylink_start(mac->phylink);
- netif_tx_start_all_queues(dev);
-@@ -3498,7 +3522,8 @@ static int mtk_stop(struct net_device *d
- if (!refcount_dec_and_test(ð->dma_refcnt))
- return 0;
-
-- mtk_gdm_config(eth, MTK_GDMA_DROP_ALL);
-+ for (i = 0; i < MTK_MAX_DEVS; i++)
-+ mtk_gdm_config(eth, i, MTK_GDMA_DROP_ALL);
-
- mtk_tx_irq_disable(eth, MTK_TX_DONE_INT);
- mtk_rx_irq_disable(eth, eth->soc->rx.irq_done_mask);
-@@ -4993,23 +5018,24 @@ static int mtk_probe(struct platform_dev
- }
-
- if (eth->soc->offload_version) {
-- u32 num_ppe = mtk_is_netsys_v2_or_greater(eth) ? 2 : 1;
-+ u8 ppe_num = eth->soc->ppe_num;
-
-- num_ppe = min_t(u32, ARRAY_SIZE(eth->ppe), num_ppe);
-- for (i = 0; i < num_ppe; i++) {
-- u32 ppe_addr = eth->soc->reg_map->ppe_base + i * 0x400;
-+ ppe_num = min_t(u8, ARRAY_SIZE(eth->ppe), ppe_num);
-+ for (i = 0; i < ppe_num; i++) {
-+ u32 ppe_addr = eth->soc->reg_map->ppe_base;
-
-+ ppe_addr += (i == 2 ? 0xc00 : i * 0x400);
- eth->ppe[i] = mtk_ppe_init(eth, eth->base + ppe_addr, i);
-
- if (!eth->ppe[i]) {
- err = -ENOMEM;
- goto err_deinit_ppe;
- }
-- }
-+ err = mtk_eth_offload_init(eth, i);
-
-- err = mtk_eth_offload_init(eth);
-- if (err)
-- goto err_deinit_ppe;
-+ if (err)
-+ goto err_deinit_ppe;
-+ }
- }
-
- for (i = 0; i < MTK_MAX_DEVS; i++) {
-@@ -5112,6 +5138,7 @@ static const struct mtk_soc_data mt7621_
- .required_pctl = false,
- .version = 1,
- .offload_version = 1,
-+ .ppe_num = 1,
- .hash_offset = 2,
- .foe_entry_size = MTK_FOE_ENTRY_V1_SIZE,
- .tx = {
-@@ -5140,6 +5167,7 @@ static const struct mtk_soc_data mt7622_
- .required_pctl = false,
- .version = 1,
- .offload_version = 2,
-+ .ppe_num = 1,
- .hash_offset = 2,
- .has_accounting = true,
- .foe_entry_size = MTK_FOE_ENTRY_V1_SIZE,
-@@ -5168,6 +5196,7 @@ static const struct mtk_soc_data mt7623_
- .required_pctl = true,
- .version = 1,
- .offload_version = 1,
-+ .ppe_num = 1,
- .hash_offset = 2,
- .foe_entry_size = MTK_FOE_ENTRY_V1_SIZE,
- .disable_pll_modes = true,
-@@ -5223,6 +5252,7 @@ static const struct mtk_soc_data mt7981_
- .required_pctl = false,
- .version = 2,
- .offload_version = 2,
-+ .ppe_num = 2,
- .hash_offset = 4,
- .has_accounting = true,
- .foe_entry_size = MTK_FOE_ENTRY_V2_SIZE,
-@@ -5252,6 +5282,7 @@ static const struct mtk_soc_data mt7986_
- .required_pctl = false,
- .version = 2,
- .offload_version = 2,
-+ .ppe_num = 2,
- .hash_offset = 4,
- .has_accounting = true,
- .foe_entry_size = MTK_FOE_ENTRY_V2_SIZE,
-@@ -5281,6 +5312,7 @@ static const struct mtk_soc_data mt7988_
- .required_pctl = false,
- .version = 3,
- .offload_version = 2,
-+ .ppe_num = 3,
- .hash_offset = 4,
- .has_accounting = true,
- .foe_entry_size = MTK_FOE_ENTRY_V3_SIZE,
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-@@ -1140,7 +1140,7 @@ struct mtk_reg_map {
- u32 tx_sch_rate; /* tx scheduler rate control registers */
- } qdma;
- u32 gdm1_cnt;
-- u32 gdma_to_ppe;
-+ u32 gdma_to_ppe[3];
- u32 ppe_base;
- u32 wdma_base[3];
- u32 pse_iq_sta;
-@@ -1178,6 +1178,7 @@ struct mtk_soc_data {
- u8 offload_version;
- u8 hash_offset;
- u8 version;
-+ u8 ppe_num;
- u16 foe_entry_size;
- netdev_features_t hw_features;
- bool has_accounting;
-@@ -1302,7 +1303,7 @@ struct mtk_eth {
-
- struct metadata_dst *dsa_meta[MTK_MAX_DSA_PORTS];
-
-- struct mtk_ppe *ppe[2];
-+ struct mtk_ppe *ppe[3];
- struct rhashtable flow_table;
-
- struct bpf_prog __rcu *prog;
-@@ -1327,6 +1328,7 @@ struct mtk_eth {
- struct mtk_mac {
- int id;
- phy_interface_t interface;
-+ u8 ppe_idx;
- int speed;
- struct device_node *of_node;
- struct phylink *phylink;
-@@ -1448,7 +1450,7 @@ int mtk_gmac_sgmii_path_setup(struct mtk
- int mtk_gmac_gephy_path_setup(struct mtk_eth *eth, int mac_id);
- int mtk_gmac_rgmii_path_setup(struct mtk_eth *eth, int mac_id);
-
--int mtk_eth_offload_init(struct mtk_eth *eth);
-+int mtk_eth_offload_init(struct mtk_eth *eth, u8 id);
- int mtk_eth_setup_tc(struct net_device *dev, enum tc_setup_type type,
- void *type_data);
- int mtk_flow_offload_cmd(struct mtk_eth *eth, struct flow_cls_offload *cls,
---- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
-+++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
-@@ -249,10 +249,10 @@ mtk_flow_offload_replace(struct mtk_eth
- int ppe_index)
- {
- struct flow_rule *rule = flow_cls_offload_flow_rule(f);
-+ struct net_device *idev = NULL, *odev = NULL;
- struct flow_action_entry *act;
- struct mtk_flow_data data = {};
- struct mtk_foe_entry foe;
-- struct net_device *odev = NULL;
- struct mtk_flow_entry *entry;
- int offload_type = 0;
- int wed_index = -1;
-@@ -268,6 +268,17 @@ mtk_flow_offload_replace(struct mtk_eth
- struct flow_match_meta match;
-
- flow_rule_match_meta(rule, &match);
-+ if (mtk_is_netsys_v2_or_greater(eth)) {
-+ idev = __dev_get_by_index(&init_net, match.key->ingress_ifindex);
-+ if (idev) {
-+ struct mtk_mac *mac = netdev_priv(idev);
-+
-+ if (WARN_ON(mac->ppe_idx >= eth->soc->ppe_num))
-+ return -EINVAL;
-+
-+ ppe_index = mac->ppe_idx;
-+ }
-+ }
- } else {
- return -EOPNOTSUPP;
- }
-@@ -635,7 +646,9 @@ int mtk_eth_setup_tc(struct net_device *
- }
- }
-
--int mtk_eth_offload_init(struct mtk_eth *eth)
-+int mtk_eth_offload_init(struct mtk_eth *eth, u8 id)
- {
-+ if (!eth->ppe[id] || !eth->ppe[id]->foe_table)
-+ return 0;
- return rhashtable_init(ð->flow_table, &mtk_flow_ht_params);
- }
+++ /dev/null
-From 73cfd947dbdb25ef9863ac49c4596a7d53ad4025 Mon Sep 17 00:00:00 2001
-Date: Sun, 23 Jun 2024 20:51:09 +0300
-Subject: [PATCH] net: ethernet: mtk_eth_soc: ppe: prevent ppe update for
- non-mtk devices
-
-Introduce an additional validation to ensure that the PPE index
-is modified exclusively for mtk_eth ingress devices.
-This primarily addresses the issue related
-to WED operation with multiple PPEs.
-
-Fixes: dee4dd10c79a ("net: ethernet: mtk_eth_soc: ppe: add support for multiple PPEs")
----
- drivers/net/ethernet/mediatek/mtk_ppe_offload.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
-+++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
-@@ -270,7 +270,7 @@ mtk_flow_offload_replace(struct mtk_eth
- flow_rule_match_meta(rule, &match);
- if (mtk_is_netsys_v2_or_greater(eth)) {
- idev = __dev_get_by_index(&init_net, match.key->ingress_ifindex);
-- if (idev) {
-+ if (idev && idev->netdev_ops == eth->netdev[0]->netdev_ops) {
- struct mtk_mac *mac = netdev_priv(idev);
-
- if (WARN_ON(mac->ppe_idx >= eth->soc->ppe_num))
+++ /dev/null
-From 3b2aef99221d395ce37efa426d7b50e7dcd621d6 Mon Sep 17 00:00:00 2001
-Date: Mon, 1 Jul 2024 20:28:14 +0100
-Subject: [PATCH] net: ethernet: mediatek: Allow gaps in MAC allocation
-
-Some devices with MediaTek SoCs don't use the first but only the second
-MAC in the chip. Especially with MT7981 which got a built-in 1GE PHY
-connected to the second MAC this is quite common.
-Make sure to reset and enable PSE also in those cases by skipping gaps
-using 'continue' instead of aborting the loop using 'break'.
-
-Fixes: dee4dd10c79a ("net: ethernet: mtk_eth_soc: ppe: add support for multiple PPEs")
-Link: https://patch.msgid.link/379ae584cea112db60f4ada79c7e5ba4f3364a64.1719862038.git.daniel@makrotopia.org
----
- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -3416,7 +3416,7 @@ static int mtk_open(struct net_device *d
-
- for (i = 0; i < MTK_MAX_DEVS; i++) {
- if (!eth->netdev[i])
-- break;
-+ continue;
-
- target_mac = netdev_priv(eth->netdev[i]);
- if (!soc->offload_version) {
+++ /dev/null
-From ca18300e00d584d5693127eb60c108b84883b8ac Mon Sep 17 00:00:00 2001
-Date: Fri, 5 Jul 2024 01:26:26 +0800
-Subject: [PATCH] net: ethernet: mtk_ppe: Change PPE entries number to 16K
-
-MT7981,7986 and 7988 all supports 32768 PPE entries, and MT7621/MT7620
-supports 16384 PPE entries, but only set to 8192 entries in driver. So
-incrase max entries to 16384 instead.
-
-Link: https://patch.msgid.link/TY3P286MB261103F937DE4EEB0F88437D98DE2@TY3P286MB2611.JPNP286.PROD.OUTLOOK.COM
----
- drivers/net/ethernet/mediatek/mtk_ppe.h | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/net/ethernet/mediatek/mtk_ppe.h
-+++ b/drivers/net/ethernet/mediatek/mtk_ppe.h
-@@ -8,7 +8,7 @@
- #include <linux/bitfield.h>
- #include <linux/rhashtable.h>
-
--#define MTK_PPE_ENTRIES_SHIFT 3
-+#define MTK_PPE_ENTRIES_SHIFT 4
- #define MTK_PPE_ENTRIES (1024 << MTK_PPE_ENTRIES_SHIFT)
- #define MTK_PPE_HASH_MASK (MTK_PPE_ENTRIES - 1)
- #define MTK_PPE_WAIT_TIMEOUT_US 1000000
+++ /dev/null
-From 064fbc4e9b5a6dbda7fe7b67dc7e9e95d31f8d75 Mon Sep 17 00:00:00 2001
-Date: Thu, 4 Jul 2024 11:14:55 +0100
-Subject: [PATCH] net: ethernet: mtk_eth_soc: implement .{get,set}_pauseparam
- ethtool ops
-
-Implement operations to get and set flow-control link parameters.
-Both is done by simply calling phylink_ethtool_{get,set}_pauseparam().
-Fix whitespace in mtk_ethtool_ops while at it.
-
-Link: https://patch.msgid.link/e3ece47323444631d6cb479f32af0dfd6d145be0.1720088047.git.daniel@makrotopia.org
----
- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 18 +++++++++++++++++-
- 1 file changed, 17 insertions(+), 1 deletion(-)
-
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -4498,6 +4498,20 @@ static int mtk_set_rxnfc(struct net_devi
- return ret;
- }
-
-+static void mtk_get_pauseparam(struct net_device *dev, struct ethtool_pauseparam *pause)
-+{
-+ struct mtk_mac *mac = netdev_priv(dev);
-+
-+ phylink_ethtool_get_pauseparam(mac->phylink, pause);
-+}
-+
-+static int mtk_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam *pause)
-+{
-+ struct mtk_mac *mac = netdev_priv(dev);
-+
-+ return phylink_ethtool_set_pauseparam(mac->phylink, pause);
-+}
-+
- static u16 mtk_select_queue(struct net_device *dev, struct sk_buff *skb,
- struct net_device *sb_dev)
- {
-@@ -4526,8 +4540,10 @@ static const struct ethtool_ops mtk_etht
- .get_strings = mtk_get_strings,
- .get_sset_count = mtk_get_sset_count,
- .get_ethtool_stats = mtk_get_ethtool_stats,
-+ .get_pauseparam = mtk_get_pauseparam,
-+ .set_pauseparam = mtk_set_pauseparam,
- .get_rxnfc = mtk_get_rxnfc,
-- .set_rxnfc = mtk_set_rxnfc,
-+ .set_rxnfc = mtk_set_rxnfc,
- };
-
- static const struct net_device_ops mtk_netdev_ops = {
+++ /dev/null
-Date: Tue, 12 Aug 2025 06:57:23 +0200
-Subject: [PATCH] net: mediatek: wed: Introduce MT7992 WED support to MT7988
- SoC
-
-Introduce the second WDMA RX ring in WED driver for MT7988 SoC since the
-Mediatek MT7992 WiFi chipset supports two separated WDMA rings.
-Add missing MT7988 configurations to properly support WED for MT7992 in
-MT76 driver.
-
----
-
---- a/drivers/net/ethernet/mediatek/mtk_wed.c
-+++ b/drivers/net/ethernet/mediatek/mtk_wed.c
-@@ -59,7 +59,9 @@ struct mtk_wed_flow_block_priv {
- static const struct mtk_wed_soc_data mt7622_data = {
- .regmap = {
- .tx_bm_tkid = 0x088,
-- .wpdma_rx_ring0 = 0x770,
-+ .wpdma_rx_ring = {
-+ 0x770,
-+ },
- .reset_idx_tx_mask = GENMASK(3, 0),
- .reset_idx_rx_mask = GENMASK(17, 16),
- },
-@@ -70,7 +72,9 @@ static const struct mtk_wed_soc_data mt7
- static const struct mtk_wed_soc_data mt7986_data = {
- .regmap = {
- .tx_bm_tkid = 0x0c8,
-- .wpdma_rx_ring0 = 0x770,
-+ .wpdma_rx_ring = {
-+ 0x770,
-+ },
- .reset_idx_tx_mask = GENMASK(1, 0),
- .reset_idx_rx_mask = GENMASK(7, 6),
- },
-@@ -81,7 +85,10 @@ static const struct mtk_wed_soc_data mt7
- static const struct mtk_wed_soc_data mt7988_data = {
- .regmap = {
- .tx_bm_tkid = 0x0c8,
-- .wpdma_rx_ring0 = 0x7d0,
-+ .wpdma_rx_ring = {
-+ 0x7d0,
-+ 0x7d8,
-+ },
- .reset_idx_tx_mask = GENMASK(1, 0),
- .reset_idx_rx_mask = GENMASK(7, 6),
- },
-@@ -621,8 +628,8 @@ mtk_wed_amsdu_init(struct mtk_wed_device
- return ret;
- }
-
-- /* eagle E1 PCIE1 tx ring 22 flow control issue */
-- if (dev->wlan.id == 0x7991)
-+ /* Kite and Eagle E1 PCIE1 tx ring 22 flow control issue */
-+ if (dev->wlan.id == 0x7991 || dev->wlan.id == 0x7992)
- wed_clr(dev, MTK_WED_AMSDU_FIFO, MTK_WED_AMSDU_IS_PRIOR0_RING);
-
- wed_set(dev, MTK_WED_CTRL, MTK_WED_CTRL_TX_AMSDU_EN);
-@@ -1239,7 +1246,11 @@ mtk_wed_set_wpdma(struct mtk_wed_device
- return;
-
- wed_w32(dev, MTK_WED_WPDMA_RX_GLO_CFG, dev->wlan.wpdma_rx_glo);
-- wed_w32(dev, dev->hw->soc->regmap.wpdma_rx_ring0, dev->wlan.wpdma_rx);
-+ wed_w32(dev, dev->hw->soc->regmap.wpdma_rx_ring[0],
-+ dev->wlan.wpdma_rx[0]);
-+ if (mtk_wed_is_v3_or_greater(dev->hw))
-+ wed_w32(dev, dev->hw->soc->regmap.wpdma_rx_ring[1],
-+ dev->wlan.wpdma_rx[1]);
-
- if (!dev->wlan.hw_rro)
- return;
-@@ -2335,6 +2346,16 @@ mtk_wed_start(struct mtk_wed_device *dev
- if (!dev->rx_wdma[i].desc)
- mtk_wed_wdma_rx_ring_setup(dev, i, 16, false);
-
-+ if (dev->wlan.hw_rro) {
-+ for (i = 0; i < MTK_WED_RX_PAGE_QUEUES; i++) {
-+ u32 addr = MTK_WED_RRO_MSDU_PG_CTRL0(i) +
-+ MTK_WED_RING_OFS_COUNT;
-+
-+ if (!wed_r32(dev, addr))
-+ wed_w32(dev, addr, 1);
-+ }
-+ }
-+
- mtk_wed_hw_init(dev);
- mtk_wed_configure_irq(dev, irq_mask);
-
---- a/drivers/net/ethernet/mediatek/mtk_wed.h
-+++ b/drivers/net/ethernet/mediatek/mtk_wed.h
-@@ -17,7 +17,7 @@ struct mtk_wed_wo;
- struct mtk_wed_soc_data {
- struct {
- u32 tx_bm_tkid;
-- u32 wpdma_rx_ring0;
-+ u32 wpdma_rx_ring[MTK_WED_RX_QUEUES];
- u32 reset_idx_tx_mask;
- u32 reset_idx_rx_mask;
- } regmap;
---- a/include/linux/soc/mediatek/mtk_wed.h
-+++ b/include/linux/soc/mediatek/mtk_wed.h
-@@ -147,7 +147,7 @@ struct mtk_wed_device {
- u32 wpdma_tx;
- u32 wpdma_txfree;
- u32 wpdma_rx_glo;
-- u32 wpdma_rx;
-+ u32 wpdma_rx[MTK_WED_RX_QUEUES];
- u32 wpdma_rx_rro[MTK_WED_RX_QUEUES];
- u32 wpdma_rx_pg;
-
+++ /dev/null
-Date: Wed, 8 Oct 2025 12:41:48 +0200
-Subject: [PATCH] wifi: mt76: wed: use proper wed reference in mt76 wed driver
- callabacks
-
-MT7996 driver can use both wed and wed_hif2 devices to offload traffic
-from/to the wireless NIC. In the current codebase we assume to always
-use the primary wed device in wed callbacks resulting in the following
-crash if the hw runs wed_hif2 (e.g. 6GHz link).
-
-[ 297.455876] Unable to handle kernel read from unreadable memory at virtual address 000000000000080a
-[ 297.464928] Mem abort info:
-[ 297.467722] ESR = 0x0000000096000005
-[ 297.471461] EC = 0x25: DABT (current EL), IL = 32 bits
-[ 297.476766] SET = 0, FnV = 0
-[ 297.479809] EA = 0, S1PTW = 0
-[ 297.482940] FSC = 0x05: level 1 translation fault
-[ 297.487809] Data abort info:
-[ 297.490679] ISV = 0, ISS = 0x00000005, ISS2 = 0x00000000
-[ 297.496156] CM = 0, WnR = 0, TnD = 0, TagAccess = 0
-[ 297.501196] GCS = 0, Overlay = 0, DirtyBit = 0, Xs = 0
-[ 297.506500] user pgtable: 4k pages, 39-bit VAs, pgdp=0000000107480000
-[ 297.512927] [000000000000080a] pgd=08000001097fb003, p4d=08000001097fb003, pud=08000001097fb003, pmd=0000000000000000
-[ 297.523532] Internal error: Oops: 0000000096000005 [#1] SMP
-[ 297.715393] CPU: 2 UID: 0 PID: 45 Comm: kworker/u16:2 Tainted: G O 6.12.50 #0
-[ 297.723908] Tainted: [O]=OOT_MODULE
-[ 297.727384] Hardware name: Banana Pi BPI-R4 (2x SFP+) (DT)
-[ 297.732857] Workqueue: nf_ft_offload_del nf_flow_rule_route_ipv6 [nf_flow_table]
-[ 297.740254] pstate: 60400005 (nZCv daif +PAN -UAO -TCO -DIT -SSBS BTYPE=--)
-[ 297.747205] pc : mt76_wed_offload_disable+0x64/0xa0 [mt76]
-[ 297.752688] lr : mtk_wed_flow_remove+0x58/0x80
-[ 297.757126] sp : ffffffc080fe3ae0
-[ 297.760430] x29: ffffffc080fe3ae0 x28: ffffffc080fe3be0 x27: 00000000deadbef7
-[ 297.767557] x26: ffffff80c5ebca00 x25: 0000000000000001 x24: ffffff80c85f4c00
-[ 297.774683] x23: ffffff80c1875b78 x22: ffffffc080d42cd0 x21: ffffffc080660018
-[ 297.781809] x20: ffffff80c6a076d0 x19: ffffff80c6a043c8 x18: 0000000000000000
-[ 297.788935] x17: 0000000000000000 x16: 0000000000000001 x15: 0000000000000000
-[ 297.796060] x14: 0000000000000019 x13: ffffff80c0ad8ec0 x12: 00000000fa83b2da
-[ 297.803185] x11: ffffff80c02700c0 x10: ffffff80c0ad8ec0 x9 : ffffff81fef96200
-[ 297.810311] x8 : ffffff80c02700c0 x7 : ffffff80c02700d0 x6 : 0000000000000002
-[ 297.817435] x5 : 0000000000000400 x4 : 0000000000000000 x3 : 0000000000000000
-[ 297.824561] x2 : 0000000000000001 x1 : 0000000000000800 x0 : ffffff80c6a063c8
-[ 297.831686] Call trace:
-[ 297.834123] mt76_wed_offload_disable+0x64/0xa0 [mt76]
-[ 297.839254] mtk_wed_flow_remove+0x58/0x80
-[ 297.843342] mtk_flow_offload_cmd+0x434/0x574
-[ 297.847689] mtk_wed_setup_tc_block_cb+0x30/0x40
-[ 297.852295] nf_flow_offload_ipv6_hook+0x7f4/0x964 [nf_flow_table]
-[ 297.858466] nf_flow_rule_route_ipv6+0x438/0x4a4 [nf_flow_table]
-[ 297.864463] process_one_work+0x174/0x300
-[ 297.868465] worker_thread+0x278/0x430
-[ 297.872204] kthread+0xd8/0xdc
-[ 297.875251] ret_from_fork+0x10/0x20
-[ 297.878820] Code: 928b5ae0 8b000273 91400a60 f943fa61 (79401421)
-[ 297.884901] ---[ end trace 0000000000000000 ]---
-
-Fix the issue detecting the proper wed reference to use running wed
-callabacks.
-
--- Partial backport for data structure change only (rest is in the mt76 package)
-
-Fixes: 83eafc9251d6 ("wifi: mt76: mt7996: add wed tx support")
----
-
---- a/include/linux/soc/mediatek/mtk_wed.h
-+++ b/include/linux/soc/mediatek/mtk_wed.h
-@@ -154,6 +154,7 @@ struct mtk_wed_device {
- bool wcid_512;
- bool hw_rro;
- bool msi;
-+ bool hif2;
-
- u16 token_start;
- unsigned int nbuf;
+++ /dev/null
-Date: Thu, 9 Oct 2025 08:29:34 +0200
-Subject: [PATCH] net: mtk: wed: add dma mask limitation and GFP_DMA32 for
- device with more than 4GB DRAM
-
-Limit tx/rx buffer address to 32-bit address space for board with more
-than 4GB DRAM.
-
-Fixes: 804775dfc2885 ("net: ethernet: mtk_eth_soc: add support for Wireless Ethernet Dispatch (WED)")
-Fixes: 6757d345dd7db ("net: ethernet: mtk_wed: introduce hw_rro support for MT7988")
----
-
---- a/drivers/net/ethernet/mediatek/mtk_wed.c
-+++ b/drivers/net/ethernet/mediatek/mtk_wed.c
-@@ -677,7 +677,7 @@ mtk_wed_tx_buffer_alloc(struct mtk_wed_d
- void *buf;
- int s;
-
-- page = __dev_alloc_page(GFP_KERNEL);
-+ page = __dev_alloc_page(GFP_KERNEL | GFP_DMA32);
- if (!page)
- return -ENOMEM;
-
-@@ -800,7 +800,7 @@ mtk_wed_hwrro_buffer_alloc(struct mtk_we
- struct page *page;
- int s;
-
-- page = __dev_alloc_page(GFP_KERNEL);
-+ page = __dev_alloc_page(GFP_KERNEL | GFP_DMA32);
- if (!page)
- return -ENOMEM;
-
-@@ -2438,6 +2438,10 @@ mtk_wed_attach(struct mtk_wed_device *de
- dev->version = hw->version;
- dev->hw->pcie_base = mtk_wed_get_pcie_base(dev);
-
-+ ret = dma_set_mask_and_coherent(hw->dev, DMA_BIT_MASK(32));
-+ if (ret)
-+ goto out;
-+
- if (hw->eth->dma_dev == hw->eth->dev &&
- of_dma_is_coherent(hw->eth->dev->of_node))
- mtk_eth_set_dma_device(hw->eth, hw->dev);
+++ /dev/null
-From 952d7325362ffbefa6ce5619fb4e53c2159ec7a7 Mon Sep 17 00:00:00 2001
-Date: Mon, 17 Feb 2025 17:40:21 +0800
-Subject: [PATCH] net: ethernet: mediatek: add EEE support
-
-Add EEE support to MediaTek SoC Ethernet. The register fields are
-similar to the ones in MT7531, except that the LPI threshold is in
-milliseconds.
-
----
- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 64 +++++++++++++++++++++
- drivers/net/ethernet/mediatek/mtk_eth_soc.h | 11 ++++
- 2 files changed, 75 insertions(+)
-
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -786,6 +786,7 @@ static void mtk_mac_link_up(struct phyli
-
- mcr = mtk_r32(mac->hw, MTK_MAC_MCR(mac->id));
- mcr &= ~(MAC_MCR_SPEED_100 | MAC_MCR_SPEED_1000 |
-+ MAC_MCR_EEE100M | MAC_MCR_EEE1G |
- MAC_MCR_FORCE_DPX | MAC_MCR_FORCE_TX_FC |
- MAC_MCR_FORCE_RX_FC);
-
-@@ -811,6 +812,15 @@ static void mtk_mac_link_up(struct phyli
- if (rx_pause)
- mcr |= MAC_MCR_FORCE_RX_FC;
-
-+ if (mode == MLO_AN_PHY && phy && mac->tx_lpi_enabled && phy_init_eee(phy, false) >= 0) {
-+ mcr |= MAC_MCR_EEE100M | MAC_MCR_EEE1G;
-+ mtk_w32(mac->hw,
-+ FIELD_PREP(MAC_EEE_WAKEUP_TIME_1000, 17) |
-+ FIELD_PREP(MAC_EEE_WAKEUP_TIME_100, 36) |
-+ FIELD_PREP(MAC_EEE_LPI_TXIDLE_THD, mac->txidle_thd_ms),
-+ MTK_MAC_EEECR(mac->id));
-+ }
-+
- mcr |= MAC_MCR_TX_EN | MAC_MCR_RX_EN | MAC_MCR_FORCE_LINK;
- mtk_w32(mac->hw, mcr, MTK_MAC_MCR(mac->id));
- }
-@@ -4512,6 +4522,61 @@ static int mtk_set_pauseparam(struct net
- return phylink_ethtool_set_pauseparam(mac->phylink, pause);
- }
-
-+static int mtk_get_eee(struct net_device *dev, struct ethtool_eee *eee)
-+{
-+ struct mtk_mac *mac = netdev_priv(dev);
-+ u32 reg;
-+ int ret;
-+
-+ ret = phylink_ethtool_get_eee(mac->phylink, eee);
-+ if (ret)
-+ return ret;
-+
-+ reg = mtk_r32(mac->hw, MTK_MAC_EEECR(mac->id));
-+ eee->tx_lpi_enabled = mac->tx_lpi_enabled;
-+ eee->tx_lpi_timer = FIELD_GET(MAC_EEE_LPI_TXIDLE_THD, reg) * 1000;
-+
-+ return 0;
-+}
-+
-+static int mtk_set_eee(struct net_device *dev, struct ethtool_eee *eee)
-+{
-+ struct mtk_mac *mac = netdev_priv(dev);
-+ u32 txidle_thd_ms, reg;
-+ int ret;
-+
-+ /* Tx idle timer in ms */
-+ txidle_thd_ms = DIV_ROUND_UP(eee->tx_lpi_timer, 1000);
-+ if (!FIELD_FIT(MAC_EEE_LPI_TXIDLE_THD, txidle_thd_ms))
-+ return -EINVAL;
-+
-+ reg = FIELD_PREP(MAC_EEE_LPI_TXIDLE_THD, txidle_thd_ms);
-+
-+ /* PHY Wake-up time, this field does not have a reset value, so use the
-+ * reset value from MT7531 (36us for 100BaseT and 17us for 1000BaseT).
-+ */
-+ reg |= FIELD_PREP(MAC_EEE_WAKEUP_TIME_1000, 17) |
-+ FIELD_PREP(MAC_EEE_WAKEUP_TIME_100, 36);
-+
-+ if (!txidle_thd_ms)
-+ /* Force LPI Mode without a delay */
-+ reg |= MAC_EEE_LPI_MODE;
-+
-+ ret = phylink_ethtool_set_eee(mac->phylink, eee);
-+ if (ret)
-+ return ret;
-+
-+ mac->tx_lpi_enabled = eee->tx_lpi_enabled;
-+ mac->txidle_thd_ms = txidle_thd_ms;
-+ mtk_w32(mac->hw, reg, MTK_MAC_EEECR(mac->id));
-+ if (eee->eee_enabled && eee->eee_active && eee->tx_lpi_enabled)
-+ mtk_m32(mac->hw, 0, MAC_MCR_EEE100M | MAC_MCR_EEE1G, MTK_MAC_MCR(mac->id));
-+ else
-+ mtk_m32(mac->hw, MAC_MCR_EEE100M | MAC_MCR_EEE1G, 0, MTK_MAC_MCR(mac->id));
-+
-+ return 0;
-+}
-+
- static u16 mtk_select_queue(struct net_device *dev, struct sk_buff *skb,
- struct net_device *sb_dev)
- {
-@@ -4544,6 +4609,8 @@ static const struct ethtool_ops mtk_etht
- .set_pauseparam = mtk_set_pauseparam,
- .get_rxnfc = mtk_get_rxnfc,
- .set_rxnfc = mtk_set_rxnfc,
-+ .get_eee = mtk_get_eee,
-+ .set_eee = mtk_set_eee,
- };
-
- static const struct net_device_ops mtk_netdev_ops = {
-@@ -4604,6 +4671,8 @@ static int mtk_add_mac(struct mtk_eth *e
- }
- mac = netdev_priv(eth->netdev[id]);
- eth->mac[id] = mac;
-+ mac->tx_lpi_enabled = true;
-+ mac->txidle_thd_ms = 1;
- mac->id = id;
- mac->hw = eth;
- mac->of_node = np;
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-@@ -461,6 +461,8 @@
- #define MAC_MCR_RX_FIFO_CLR_DIS BIT(12)
- #define MAC_MCR_BACKOFF_EN BIT(9)
- #define MAC_MCR_BACKPR_EN BIT(8)
-+#define MAC_MCR_EEE1G BIT(7)
-+#define MAC_MCR_EEE100M BIT(6)
- #define MAC_MCR_FORCE_RX_FC BIT(5)
- #define MAC_MCR_FORCE_TX_FC BIT(4)
- #define MAC_MCR_SPEED_1000 BIT(3)
-@@ -469,6 +471,15 @@
- #define MAC_MCR_FORCE_LINK BIT(0)
- #define MAC_MCR_FORCE_LINK_DOWN (MAC_MCR_FORCE_MODE)
-
-+/* Mac EEE control registers */
-+#define MTK_MAC_EEECR(x) (0x10104 + (x * 0x100))
-+#define MAC_EEE_WAKEUP_TIME_1000 GENMASK(31, 24)
-+#define MAC_EEE_WAKEUP_TIME_100 GENMASK(23, 16)
-+#define MAC_EEE_LPI_TXIDLE_THD GENMASK(15, 8)
-+#define MAC_EEE_CKG_TXIDLE BIT(3)
-+#define MAC_EEE_CKG_RXLPI BIT(2)
-+#define MAC_EEE_LPI_MODE BIT(0)
-+
- /* Mac status registers */
- #define MTK_MAC_MSR(x) (0x10108 + (x * 0x100))
- #define MAC_MSR_EEE1G BIT(7)
-@@ -1329,6 +1340,8 @@ struct mtk_mac {
- int id;
- phy_interface_t interface;
- u8 ppe_idx;
-+ bool tx_lpi_enabled;
-+ u8 txidle_thd_ms;
- int speed;
- struct device_node *of_node;
- struct phylink *phylink;
+++ /dev/null
-From 88806efc034a9830f483963326b99930ad519af1 Mon Sep 17 00:00:00 2001
-Date: Tue, 15 Oct 2024 10:17:55 +0200
-Subject: [PATCH] net: ethernet: mtk_eth_soc: fix memory corruption during fq
- dma init
-
-The loop responsible for allocating up to MTK_FQ_DMA_LENGTH buffers must
-only touch as many descriptors, otherwise it ends up corrupting unrelated
-memory. Fix the loop iteration count accordingly.
-
-Fixes: c57e55819443 ("net: ethernet: mtk_eth_soc: handle dma buffer size soc specific")
----
- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -1181,7 +1181,7 @@ static int mtk_init_fq_dma(struct mtk_et
- if (unlikely(dma_mapping_error(eth->dma_dev, dma_addr)))
- return -ENOMEM;
-
-- for (i = 0; i < cnt; i++) {
-+ for (i = 0; i < len; i++) {
- struct mtk_tx_dma_v2 *txd;
-
- txd = eth->scratch_ring + (j * MTK_FQ_DMA_LENGTH + i) * soc->tx.desc_size;
+++ /dev/null
-From 637f41476384c76d3cd7dcf5947caf2c8b8d7a9b Mon Sep 17 00:00:00 2001
-Date: Sat, 26 Oct 2024 14:52:25 +0100
-Subject: [PATCH] net: ethernet: mtk_wed: fix path of MT7988 WO firmware
-
-linux-firmware commit 808cba84 ("mtk_wed: add firmware for mt7988
-Wireless Ethernet Dispatcher") added mt7988_wo_{0,1}.bin in the
-'mediatek/mt7988' directory while driver current expects the files in
-the 'mediatek' directory.
-
-Change path in the driver header now that the firmware has been added.
-
-Fixes: e2f64db13aa1 ("net: ethernet: mtk_wed: introduce WED support for MT7988")
----
- drivers/net/ethernet/mediatek/mtk_wed_wo.h | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
---- a/drivers/net/ethernet/mediatek/mtk_wed_wo.h
-+++ b/drivers/net/ethernet/mediatek/mtk_wed_wo.h
-@@ -91,8 +91,8 @@ enum mtk_wed_dummy_cr_idx {
- #define MT7981_FIRMWARE_WO "mediatek/mt7981_wo.bin"
- #define MT7986_FIRMWARE_WO0 "mediatek/mt7986_wo_0.bin"
- #define MT7986_FIRMWARE_WO1 "mediatek/mt7986_wo_1.bin"
--#define MT7988_FIRMWARE_WO0 "mediatek/mt7988_wo_0.bin"
--#define MT7988_FIRMWARE_WO1 "mediatek/mt7988_wo_1.bin"
-+#define MT7988_FIRMWARE_WO0 "mediatek/mt7988/mt7988_wo_0.bin"
-+#define MT7988_FIRMWARE_WO1 "mediatek/mt7988/mt7988_wo_1.bin"
-
- #define MTK_WO_MCU_CFG_LS_BASE 0
- #define MTK_WO_MCU_CFG_LS_HW_VER_ADDR (MTK_WO_MCU_CFG_LS_BASE + 0x000)
+++ /dev/null
-From ac4aa9dbc702329c447d968325b055af84ae1b59 Mon Sep 17 00:00:00 2001
-Date: Tue, 9 Apr 2024 03:24:12 +0100
-Subject: [PATCH] phy: add driver for MediaTek XFI T-PHY
-
-Add driver for MediaTek's XFI T-PHY which can be found in the MT7988
-SoC. The XFI T-PHY is a 10 Gigabit/s Ethernet SerDes PHY with muxes on
-the internal side to be used with either USXGMII PCS or LynxI PCS,
-depending on the selected PHY interface mode.
-
-The PHY can operates only in PHY_MODE_ETHERNET, the submode is one of
-PHY_INTERFACE_MODE_* corresponding to the supported modes:
-
- * USXGMII \
- * 10GBase-R }- USXGMII PCS - XGDM \
- * 5GBase-R / \
- }- Ethernet MAC
- * 2500Base-X \ /
- * 1000Base-X }- LynxI PCS - GDM /
- * Cisco SGMII (MAC side) /
-
-I chose the name XFI T-PHY because names of functions dealing with the
-phy in the vendor driver are prefixed "xfi_pextp_".
-
-The register space used by the phy is called "pextp" in the vendor
-sources, which could be read as "_P_CI _ex_press _T_-_P_hy", and that
-is quite misleading as this phy isn't used for anything related to
-PCIe, so I wanted to find a better name.
-
-XFI is still somehow related (as in: you would find the relevant
-places using grep in the vendor driver when looking for that) and the
-term seemed to at least somehow be aligned with the function of that
-phy: Dealing with (up to) 10 Gbit/s Ethernet serialized differential
-signals.
-
-In order to work-around a performance issue present on the first of
-two XFI T-PHYs found in MT7988, special tuning is applied which can
-be selected by adding the 'mediatek,usxgmii-performance-errata'
-property to the device tree node, similar to how the vendor driver is
-doing that too.
-
-There is no documentation for most registers used for the
-analog/tuning part, however, most of the registers have been partially
-reverse-engineered from MediaTek's SDK implementation (see links, an
-opaque sequence of 32-bit register writes) and descriptions for all
-relevant digital registers and bits such as resets and muxes have been
-supplied by MediaTek.
-
-Link: https://git01.mediatek.com/plugins/gitiles/openwrt/feeds/mtk-openwrt-feeds/+/b72d6cba92bf9e29fb035c03052fa1e86664a25b/21.02/files/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_sgmii.c
-Link: https://git01.mediatek.com/plugins/gitiles/openwrt/feeds/mtk-openwrt-feeds/+/dec96a1d9b82cdcda4a56453fd0b453d4cab4b85/21.02/files/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-Link: https://lore.kernel.org/r/8719c82634df7e8e984f1a608be3ba2f2d494fb4.1712625857.git.daniel@makrotopia.org
----
- MAINTAINERS | 1 +
- drivers/phy/mediatek/Kconfig | 11 +
- drivers/phy/mediatek/Makefile | 1 +
- drivers/phy/mediatek/phy-mtk-xfi-tphy.c | 451 ++++++++++++++++++++++++
- 4 files changed, 464 insertions(+)
- create mode 100644 drivers/phy/mediatek/phy-mtk-xfi-tphy.c
-
---- a/MAINTAINERS
-+++ b/MAINTAINERS
- S: Maintained
- F: drivers/net/phy/mediatek-ge-soc.c
- F: drivers/net/phy/mediatek-ge.c
-+F: drivers/phy/mediatek/phy-mtk-xfi-tphy.c
-
- MEDIATEK I2C CONTROLLER DRIVER
---- a/drivers/phy/mediatek/Kconfig
-+++ b/drivers/phy/mediatek/Kconfig
-@@ -13,6 +13,17 @@ config PHY_MTK_PCIE
- callback for PCIe GEN3 port, it supports software efuse
- initialization.
-
-+config PHY_MTK_XFI_TPHY
-+ tristate "MediaTek 10GE SerDes XFI T-PHY driver"
-+ depends on ARCH_MEDIATEK || COMPILE_TEST
-+ depends on OF
-+ select GENERIC_PHY
-+ help
-+ Say 'Y' here to add support for MediaTek XFI T-PHY driver.
-+ The driver provides access to the Ethernet SerDes T-PHY supporting
-+ 1GE and 2.5GE modes via the LynxI PCS, and 5GE and 10GE modes
-+ via the USXGMII PCS found in MediaTek SoCs with 10G Ethernet.
-+
- config PHY_MTK_TPHY
- tristate "MediaTek T-PHY Driver"
- depends on ARCH_MEDIATEK || COMPILE_TEST
---- a/drivers/phy/mediatek/Makefile
-+++ b/drivers/phy/mediatek/Makefile
-@@ -8,6 +8,7 @@ obj-$(CONFIG_PHY_MTK_PCIE) += phy-mtk-p
- obj-$(CONFIG_PHY_MTK_TPHY) += phy-mtk-tphy.o
- obj-$(CONFIG_PHY_MTK_UFS) += phy-mtk-ufs.o
- obj-$(CONFIG_PHY_MTK_XSPHY) += phy-mtk-xsphy.o
-+obj-$(CONFIG_PHY_MTK_XFI_TPHY) += phy-mtk-xfi-tphy.o
-
- phy-mtk-hdmi-drv-y := phy-mtk-hdmi.o
- phy-mtk-hdmi-drv-y += phy-mtk-hdmi-mt2701.o
---- /dev/null
-+++ b/drivers/phy/mediatek/phy-mtk-xfi-tphy.c
-@@ -0,0 +1,451 @@
-+// SPDX-License-Identifier: GPL-2.0-or-later
-+/*
-+ * MediaTek 10GE SerDes XFI T-PHY driver
-+ *
-+ * based on mtk_usxgmii.c and mtk_sgmii.c found in MediaTek's SDK (GPL-2.0)
-+ * Copyright (c) 2022 MediaTek Inc.
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/device.h>
-+#include <linux/platform_device.h>
-+#include <linux/of.h>
-+#include <linux/io.h>
-+#include <linux/clk.h>
-+#include <linux/reset.h>
-+#include <linux/phy.h>
-+#include <linux/phy/phy.h>
-+
-+#include "phy-mtk-io.h"
-+
-+#define MTK_XFI_TPHY_NUM_CLOCKS 2
-+
-+#define REG_DIG_GLB_70 0x0070
-+#define XTP_PCS_RX_EQ_IN_PROGRESS(x) FIELD_PREP(GENMASK(25, 24), (x))
-+#define XTP_PCS_MODE_MASK GENMASK(17, 16)
-+#define XTP_PCS_MODE(x) FIELD_PREP(GENMASK(17, 16), (x))
-+#define XTP_PCS_RST_B BIT(15)
-+#define XTP_FRC_PCS_RST_B BIT(14)
-+#define XTP_PCS_PWD_SYNC_MASK GENMASK(13, 12)
-+#define XTP_PCS_PWD_SYNC(x) FIELD_PREP(XTP_PCS_PWD_SYNC_MASK, (x))
-+#define XTP_PCS_PWD_ASYNC_MASK GENMASK(11, 10)
-+#define XTP_PCS_PWD_ASYNC(x) FIELD_PREP(XTP_PCS_PWD_ASYNC_MASK, (x))
-+#define XTP_FRC_PCS_PWD_ASYNC BIT(8)
-+#define XTP_PCS_UPDT BIT(4)
-+#define XTP_PCS_IN_FR_RG BIT(0)
-+
-+#define REG_DIG_GLB_F4 0x00f4
-+#define XFI_DPHY_PCS_SEL BIT(0)
-+#define XFI_DPHY_PCS_SEL_SGMII FIELD_PREP(XFI_DPHY_PCS_SEL, 1)
-+#define XFI_DPHY_PCS_SEL_USXGMII FIELD_PREP(XFI_DPHY_PCS_SEL, 0)
-+#define XFI_DPHY_AD_SGDT_FRC_EN BIT(5)
-+
-+#define REG_DIG_LN_TRX_40 0x3040
-+#define XTP_LN_FRC_TX_DATA_EN BIT(29)
-+#define XTP_LN_TX_DATA_EN BIT(28)
-+
-+#define REG_DIG_LN_TRX_B0 0x30b0
-+#define XTP_LN_FRC_TX_MACCK_EN BIT(5)
-+#define XTP_LN_TX_MACCK_EN BIT(4)
-+
-+#define REG_ANA_GLB_D0 0x90d0
-+#define XTP_GLB_USXGMII_SEL_MASK GENMASK(3, 1)
-+#define XTP_GLB_USXGMII_SEL(x) FIELD_PREP(GENMASK(3, 1), (x))
-+#define XTP_GLB_USXGMII_EN BIT(0)
-+
-+/**
-+ * struct mtk_xfi_tphy - run-time data of the XFI phy instance
-+ * @base: IO memory area to access phy registers.
-+ * @dev: Kernel device used to output prefixed debug info.
-+ * @reset: Reset control corresponding to the phy instance.
-+ * @clocks: All clocks required for the phy to operate.
-+ * @da_war: Enables work-around for 10GBase-R mode.
-+ */
-+struct mtk_xfi_tphy {
-+ void __iomem *base;
-+ struct device *dev;
-+ struct reset_control *reset;
-+ struct clk_bulk_data clocks[MTK_XFI_TPHY_NUM_CLOCKS];
-+ bool da_war;
-+};
-+
-+/**
-+ * mtk_xfi_tphy_setup() - Setup phy for specified interface mode.
-+ * @xfi_tphy: XFI phy instance.
-+ * @interface: Ethernet interface mode
-+ *
-+ * The setup function is the condensed result of combining the 5 functions which
-+ * setup the phy in MediaTek's GPL licensed public SDK sources. They can be found
-+ * in mtk_sgmii.c[1] as well as mtk_usxgmii.c[2].
-+ *
-+ * Many magic values have been replaced by register and bit definitions, however,
-+ * that has not been possible in all cases. While the vendor driver uses a
-+ * sequence of 32-bit writes, here we try to only modify the actually required
-+ * bits.
-+ *
-+ * [1]: https://git01.mediatek.com/plugins/gitiles/openwrt/feeds/mtk-openwrt-feeds/+/b72d6cba92bf9e29fb035c03052fa1e86664a25b/21.02/files/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_sgmii.c
-+ *
-+ * [2]: https://git01.mediatek.com/plugins/gitiles/openwrt/feeds/mtk-openwrt-feeds/+/dec96a1d9b82cdcda4a56453fd0b453d4cab4b85/21.02/files/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-+ */
-+static void mtk_xfi_tphy_setup(struct mtk_xfi_tphy *xfi_tphy,
-+ phy_interface_t interface)
-+{
-+ bool is_1g, is_2p5g, is_5g, is_10g, da_war, use_lynxi_pcs;
-+
-+ /* shorthands for specific clock speeds depending on interface mode */
-+ is_1g = interface == PHY_INTERFACE_MODE_1000BASEX ||
-+ interface == PHY_INTERFACE_MODE_SGMII;
-+ is_2p5g = interface == PHY_INTERFACE_MODE_2500BASEX;
-+ is_5g = interface == PHY_INTERFACE_MODE_5GBASER;
-+ is_10g = interface == PHY_INTERFACE_MODE_10GBASER ||
-+ interface == PHY_INTERFACE_MODE_USXGMII;
-+
-+ /* Is overriding 10GBase-R tuning value required? */
-+ da_war = xfi_tphy->da_war && (interface == PHY_INTERFACE_MODE_10GBASER);
-+
-+ /* configure input mux to either
-+ * - USXGMII PCS (64b/66b coding) for 5G/10G
-+ * - LynxI PCS (8b/10b coding) for 1G/2.5G
-+ */
-+ use_lynxi_pcs = is_1g || is_2p5g;
-+
-+ dev_dbg(xfi_tphy->dev, "setting up for mode %s\n", phy_modes(interface));
-+
-+ /* Setup PLL setting */
-+ mtk_phy_update_bits(xfi_tphy->base + 0x9024, 0x100000, is_10g ? 0x0 : 0x100000);
-+ mtk_phy_update_bits(xfi_tphy->base + 0x2020, 0x202000, is_5g ? 0x202000 : 0x0);
-+ mtk_phy_update_bits(xfi_tphy->base + 0x2030, 0x500, is_1g ? 0x0 : 0x500);
-+ mtk_phy_update_bits(xfi_tphy->base + 0x2034, 0xa00, is_1g ? 0x0 : 0xa00);
-+ mtk_phy_update_bits(xfi_tphy->base + 0x2040, 0x340000, is_1g ? 0x200000 : 0x140000);
-+
-+ /* Setup RXFE BW setting */
-+ mtk_phy_update_bits(xfi_tphy->base + 0x50f0, 0xc10, is_1g ? 0x410 : is_5g ? 0x800 : 0x400);
-+ mtk_phy_update_bits(xfi_tphy->base + 0x50e0, 0x4000, is_5g ? 0x0 : 0x4000);
-+
-+ /* Setup RX CDR setting */
-+ mtk_phy_update_bits(xfi_tphy->base + 0x506c, 0x30000, is_5g ? 0x0 : 0x30000);
-+ mtk_phy_update_bits(xfi_tphy->base + 0x5070, 0x670000, is_5g ? 0x620000 : 0x50000);
-+ mtk_phy_update_bits(xfi_tphy->base + 0x5074, 0x180000, is_5g ? 0x180000 : 0x0);
-+ mtk_phy_update_bits(xfi_tphy->base + 0x5078, 0xf000400, is_5g ? 0x8000000 :
-+ 0x7000400);
-+ mtk_phy_update_bits(xfi_tphy->base + 0x507c, 0x5000500, is_5g ? 0x4000400 :
-+ 0x1000100);
-+ mtk_phy_update_bits(xfi_tphy->base + 0x5080, 0x1410, is_1g ? 0x400 : is_5g ? 0x1010 : 0x0);
-+ mtk_phy_update_bits(xfi_tphy->base + 0x5084, 0x30300, is_1g ? 0x30300 :
-+ is_5g ? 0x30100 :
-+ 0x100);
-+ mtk_phy_update_bits(xfi_tphy->base + 0x5088, 0x60200, is_1g ? 0x20200 :
-+ is_5g ? 0x40000 :
-+ 0x20000);
-+
-+ /* Setting RXFE adaptation range setting */
-+ mtk_phy_update_bits(xfi_tphy->base + 0x50e4, 0xc0000, is_5g ? 0x0 : 0xc0000);
-+ mtk_phy_update_bits(xfi_tphy->base + 0x50e8, 0x40000, is_5g ? 0x0 : 0x40000);
-+ mtk_phy_update_bits(xfi_tphy->base + 0x50ec, 0xa00, is_1g ? 0x200 : 0x800);
-+ mtk_phy_update_bits(xfi_tphy->base + 0x50a8, 0xee0000, is_5g ? 0x800000 :
-+ 0x6e0000);
-+ mtk_phy_update_bits(xfi_tphy->base + 0x6004, 0x190000, is_5g ? 0x0 : 0x190000);
-+
-+ if (is_10g)
-+ writel(0x01423342, xfi_tphy->base + 0x00f8);
-+ else if (is_5g)
-+ writel(0x00a132a1, xfi_tphy->base + 0x00f8);
-+ else if (is_2p5g)
-+ writel(0x009c329c, xfi_tphy->base + 0x00f8);
-+ else
-+ writel(0x00fa32fa, xfi_tphy->base + 0x00f8);
-+
-+ /* Force SGDT_OUT off and select PCS */
-+ mtk_phy_update_bits(xfi_tphy->base + REG_DIG_GLB_F4,
-+ XFI_DPHY_AD_SGDT_FRC_EN | XFI_DPHY_PCS_SEL,
-+ XFI_DPHY_AD_SGDT_FRC_EN |
-+ (use_lynxi_pcs ? XFI_DPHY_PCS_SEL_SGMII :
-+ XFI_DPHY_PCS_SEL_USXGMII));
-+
-+ /* Force GLB_CKDET_OUT */
-+ mtk_phy_set_bits(xfi_tphy->base + 0x0030, 0xc00);
-+
-+ /* Force AEQ on */
-+ writel(XTP_PCS_RX_EQ_IN_PROGRESS(2) | XTP_PCS_PWD_SYNC(2) | XTP_PCS_PWD_ASYNC(2),
-+ xfi_tphy->base + REG_DIG_GLB_70);
-+
-+ usleep_range(1, 5);
-+ writel(XTP_LN_FRC_TX_DATA_EN, xfi_tphy->base + REG_DIG_LN_TRX_40);
-+
-+ /* Setup TX DA default value */
-+ mtk_phy_update_bits(xfi_tphy->base + 0x30b0, 0x30, 0x20);
-+ writel(0x00008a01, xfi_tphy->base + 0x3028);
-+ writel(0x0000a884, xfi_tphy->base + 0x302c);
-+ writel(0x00083002, xfi_tphy->base + 0x3024);
-+
-+ /* Setup RG default value */
-+ if (use_lynxi_pcs) {
-+ writel(0x00011110, xfi_tphy->base + 0x3010);
-+ writel(0x40704000, xfi_tphy->base + 0x3048);
-+ } else {
-+ writel(0x00022220, xfi_tphy->base + 0x3010);
-+ writel(0x0f020a01, xfi_tphy->base + 0x5064);
-+ writel(0x06100600, xfi_tphy->base + 0x50b4);
-+ if (interface == PHY_INTERFACE_MODE_USXGMII)
-+ writel(0x40704000, xfi_tphy->base + 0x3048);
-+ else
-+ writel(0x47684100, xfi_tphy->base + 0x3048);
-+ }
-+
-+ if (is_1g)
-+ writel(0x0000c000, xfi_tphy->base + 0x3064);
-+
-+ /* Setup RX EQ initial value */
-+ mtk_phy_update_bits(xfi_tphy->base + 0x3050, 0xa8000000,
-+ (interface != PHY_INTERFACE_MODE_10GBASER) ? 0xa8000000 : 0x0);
-+ mtk_phy_update_bits(xfi_tphy->base + 0x3054, 0xaa,
-+ (interface != PHY_INTERFACE_MODE_10GBASER) ? 0xaa : 0x0);
-+
-+ if (!use_lynxi_pcs)
-+ writel(0x00000f00, xfi_tphy->base + 0x306c);
-+ else if (is_2p5g)
-+ writel(0x22000f00, xfi_tphy->base + 0x306c);
-+ else
-+ writel(0x20200f00, xfi_tphy->base + 0x306c);
-+
-+ mtk_phy_update_bits(xfi_tphy->base + 0xa008, 0x10000, da_war ? 0x10000 : 0x0);
-+
-+ mtk_phy_update_bits(xfi_tphy->base + 0xa060, 0x50000, use_lynxi_pcs ? 0x50000 : 0x40000);
-+
-+ /* Setup PHYA speed */
-+ mtk_phy_update_bits(xfi_tphy->base + REG_ANA_GLB_D0,
-+ XTP_GLB_USXGMII_SEL_MASK | XTP_GLB_USXGMII_EN,
-+ is_10g ? XTP_GLB_USXGMII_SEL(0) :
-+ is_5g ? XTP_GLB_USXGMII_SEL(1) :
-+ is_2p5g ? XTP_GLB_USXGMII_SEL(2) :
-+ XTP_GLB_USXGMII_SEL(3));
-+ mtk_phy_set_bits(xfi_tphy->base + REG_ANA_GLB_D0, XTP_GLB_USXGMII_EN);
-+
-+ /* Release reset */
-+ mtk_phy_set_bits(xfi_tphy->base + REG_DIG_GLB_70,
-+ XTP_PCS_RST_B | XTP_FRC_PCS_RST_B);
-+ usleep_range(150, 500);
-+
-+ /* Switch to P0 */
-+ mtk_phy_update_bits(xfi_tphy->base + REG_DIG_GLB_70,
-+ XTP_PCS_IN_FR_RG |
-+ XTP_FRC_PCS_PWD_ASYNC |
-+ XTP_PCS_PWD_ASYNC_MASK |
-+ XTP_PCS_PWD_SYNC_MASK |
-+ XTP_PCS_UPDT,
-+ XTP_PCS_IN_FR_RG |
-+ XTP_FRC_PCS_PWD_ASYNC |
-+ XTP_PCS_UPDT);
-+ usleep_range(1, 5);
-+
-+ mtk_phy_clear_bits(xfi_tphy->base + REG_DIG_GLB_70, XTP_PCS_UPDT);
-+ usleep_range(15, 50);
-+
-+ if (use_lynxi_pcs) {
-+ /* Switch to Gen2 */
-+ mtk_phy_update_bits(xfi_tphy->base + REG_DIG_GLB_70,
-+ XTP_PCS_MODE_MASK | XTP_PCS_UPDT,
-+ XTP_PCS_MODE(1) | XTP_PCS_UPDT);
-+ } else {
-+ /* Switch to Gen3 */
-+ mtk_phy_update_bits(xfi_tphy->base + REG_DIG_GLB_70,
-+ XTP_PCS_MODE_MASK | XTP_PCS_UPDT,
-+ XTP_PCS_MODE(2) | XTP_PCS_UPDT);
-+ }
-+ usleep_range(1, 5);
-+
-+ mtk_phy_clear_bits(xfi_tphy->base + REG_DIG_GLB_70, XTP_PCS_UPDT);
-+
-+ usleep_range(100, 500);
-+
-+ /* Enable MAC CK */
-+ mtk_phy_set_bits(xfi_tphy->base + REG_DIG_LN_TRX_B0, XTP_LN_TX_MACCK_EN);
-+ mtk_phy_clear_bits(xfi_tphy->base + REG_DIG_GLB_F4, XFI_DPHY_AD_SGDT_FRC_EN);
-+
-+ /* Enable TX data */
-+ mtk_phy_set_bits(xfi_tphy->base + REG_DIG_LN_TRX_40,
-+ XTP_LN_FRC_TX_DATA_EN | XTP_LN_TX_DATA_EN);
-+ usleep_range(400, 1000);
-+}
-+
-+/**
-+ * mtk_xfi_tphy_set_mode() - Setup phy for specified interface mode.
-+ *
-+ * @phy: Phy instance.
-+ * @mode: Only PHY_MODE_ETHERNET is supported.
-+ * @submode: An Ethernet interface mode.
-+ *
-+ * Validate selected mode and call function mtk_xfi_tphy_setup().
-+ *
-+ * Return:
-+ * * %0 - OK
-+ * * %-EINVAL - invalid mode
-+ */
-+static int mtk_xfi_tphy_set_mode(struct phy *phy, enum phy_mode mode, int
-+ submode)
-+{
-+ struct mtk_xfi_tphy *xfi_tphy = phy_get_drvdata(phy);
-+
-+ if (mode != PHY_MODE_ETHERNET)
-+ return -EINVAL;
-+
-+ switch (submode) {
-+ case PHY_INTERFACE_MODE_1000BASEX:
-+ case PHY_INTERFACE_MODE_2500BASEX:
-+ case PHY_INTERFACE_MODE_SGMII:
-+ case PHY_INTERFACE_MODE_5GBASER:
-+ case PHY_INTERFACE_MODE_10GBASER:
-+ case PHY_INTERFACE_MODE_USXGMII:
-+ mtk_xfi_tphy_setup(xfi_tphy, submode);
-+ return 0;
-+ default:
-+ return -EINVAL;
-+ }
-+}
-+
-+/**
-+ * mtk_xfi_tphy_reset() - Reset the phy.
-+ *
-+ * @phy: Phy instance.
-+ *
-+ * Reset the phy using the external reset controller.
-+ *
-+ * Return:
-+ * %0 - OK
-+ */
-+static int mtk_xfi_tphy_reset(struct phy *phy)
-+{
-+ struct mtk_xfi_tphy *xfi_tphy = phy_get_drvdata(phy);
-+
-+ reset_control_assert(xfi_tphy->reset);
-+ usleep_range(100, 500);
-+ reset_control_deassert(xfi_tphy->reset);
-+ usleep_range(1, 10);
-+
-+ return 0;
-+}
-+
-+/**
-+ * mtk_xfi_tphy_power_on() - Power-on the phy.
-+ *
-+ * @phy: Phy instance.
-+ *
-+ * Prepare and enable all clocks required for the phy to operate.
-+ *
-+ * Return:
-+ * See clk_bulk_prepare_enable().
-+ */
-+static int mtk_xfi_tphy_power_on(struct phy *phy)
-+{
-+ struct mtk_xfi_tphy *xfi_tphy = phy_get_drvdata(phy);
-+
-+ return clk_bulk_prepare_enable(MTK_XFI_TPHY_NUM_CLOCKS, xfi_tphy->clocks);
-+}
-+
-+/**
-+ * mtk_xfi_tphy_power_off() - Power-off the phy.
-+ *
-+ * @phy: Phy instance.
-+ *
-+ * Disable and unprepare all clocks previously enabled.
-+ *
-+ * Return:
-+ * See clk_bulk_prepare_disable().
-+ */
-+static int mtk_xfi_tphy_power_off(struct phy *phy)
-+{
-+ struct mtk_xfi_tphy *xfi_tphy = phy_get_drvdata(phy);
-+
-+ clk_bulk_disable_unprepare(MTK_XFI_TPHY_NUM_CLOCKS, xfi_tphy->clocks);
-+
-+ return 0;
-+}
-+
-+static const struct phy_ops mtk_xfi_tphy_ops = {
-+ .power_on = mtk_xfi_tphy_power_on,
-+ .power_off = mtk_xfi_tphy_power_off,
-+ .set_mode = mtk_xfi_tphy_set_mode,
-+ .reset = mtk_xfi_tphy_reset,
-+ .owner = THIS_MODULE,
-+};
-+
-+/**
-+ * mtk_xfi_tphy_probe() - Probe phy instance from Device Tree.
-+ * @pdev: Matching platform device.
-+ *
-+ * The probe function gets IO resource, clocks, reset controller and
-+ * whether the DA work-around for 10GBase-R is required from Device Tree and
-+ * allocates memory for holding that information in a struct mtk_xfi_tphy.
-+ *
-+ * Return:
-+ * * %0 - OK
-+ * * %-ENODEV - Missing associated Device Tree node (should never happen).
-+ * * %-ENOMEM - Out of memory.
-+ * * Any error value which devm_platform_ioremap_resource(),
-+ * devm_clk_bulk_get(), devm_reset_control_get_exclusive(),
-+ * devm_phy_create() or devm_of_phy_provider_register() may return.
-+ */
-+static int mtk_xfi_tphy_probe(struct platform_device *pdev)
-+{
-+ struct device_node *np = pdev->dev.of_node;
-+ struct phy_provider *phy_provider;
-+ struct mtk_xfi_tphy *xfi_tphy;
-+ struct phy *phy;
-+ int ret;
-+
-+ if (!np)
-+ return -ENODEV;
-+
-+ xfi_tphy = devm_kzalloc(&pdev->dev, sizeof(*xfi_tphy), GFP_KERNEL);
-+ if (!xfi_tphy)
-+ return -ENOMEM;
-+
-+ xfi_tphy->base = devm_platform_ioremap_resource(pdev, 0);
-+ if (IS_ERR(xfi_tphy->base))
-+ return PTR_ERR(xfi_tphy->base);
-+
-+ xfi_tphy->dev = &pdev->dev;
-+ xfi_tphy->clocks[0].id = "topxtal";
-+ xfi_tphy->clocks[1].id = "xfipll";
-+ ret = devm_clk_bulk_get(&pdev->dev, MTK_XFI_TPHY_NUM_CLOCKS, xfi_tphy->clocks);
-+ if (ret)
-+ return ret;
-+
-+ xfi_tphy->reset = devm_reset_control_get_exclusive(&pdev->dev, NULL);
-+ if (IS_ERR(xfi_tphy->reset))
-+ return PTR_ERR(xfi_tphy->reset);
-+
-+ xfi_tphy->da_war = of_property_read_bool(np, "mediatek,usxgmii-performance-errata");
-+
-+ phy = devm_phy_create(&pdev->dev, NULL, &mtk_xfi_tphy_ops);
-+ if (IS_ERR(phy))
-+ return PTR_ERR(phy);
-+
-+ phy_set_drvdata(phy, xfi_tphy);
-+ phy_provider = devm_of_phy_provider_register(&pdev->dev, of_phy_simple_xlate);
-+
-+ return PTR_ERR_OR_ZERO(phy_provider);
-+}
-+
-+static const struct of_device_id mtk_xfi_tphy_match[] = {
-+ { .compatible = "mediatek,mt7988-xfi-tphy", },
-+ { /* sentinel */ }
-+};
-+MODULE_DEVICE_TABLE(of, mtk_xfi_tphy_match);
-+
-+static struct platform_driver mtk_xfi_tphy_driver = {
-+ .probe = mtk_xfi_tphy_probe,
-+ .driver = {
-+ .name = "mtk-xfi-tphy",
-+ .of_match_table = mtk_xfi_tphy_match,
-+ },
-+};
-+module_platform_driver(mtk_xfi_tphy_driver);
-+
-+MODULE_DESCRIPTION("MediaTek 10GE SerDes XFI T-PHY driver");
-+MODULE_LICENSE("GPL");
+++ /dev/null
-From 038ba1dc4e54d51d953f5618d8eb5dd39bd9de25 Mon Sep 17 00:00:00 2001
-Date: Tue, 13 Feb 2024 14:35:51 +0100
-Subject: [PATCH] net: phy: aquantia: add AQR111 and AQR111B0 PHY ID
-
-Add Aquantia AQR111 and AQR111B0 PHY ID. These PHY advertise 10G speed
-but actually supports up to 5G speed, hence some manual fixup is needed.
-
-The Aquantia AQR111B0 PHY is just a variant of the AQR111 with smaller
-chip size.
-
----
- drivers/net/phy/aquantia/aquantia_main.c | 52 ++++++++++++++++++++++++
- 1 file changed, 52 insertions(+)
-
---- a/drivers/net/phy/aquantia/aquantia_main.c
-+++ b/drivers/net/phy/aquantia/aquantia_main.c
-@@ -22,6 +22,8 @@
- #define PHY_ID_AQR107 0x03a1b4e0
- #define PHY_ID_AQCS109 0x03a1b5c2
- #define PHY_ID_AQR405 0x03a1b4b0
-+#define PHY_ID_AQR111 0x03a1b610
-+#define PHY_ID_AQR111B0 0x03a1b612
- #define PHY_ID_AQR112 0x03a1b662
- #define PHY_ID_AQR412 0x03a1b712
- #define PHY_ID_AQR113C 0x31c31c12
-@@ -672,6 +674,16 @@ static int aqr107_probe(struct phy_devic
- return aqr_hwmon_probe(phydev);
- }
-
-+static int aqr111_config_init(struct phy_device *phydev)
-+{
-+ /* AQR111 reports supporting speed up to 10G,
-+ * however only speeds up to 5G are supported.
-+ */
-+ phy_set_max_speed(phydev, SPEED_5000);
-+
-+ return aqr107_config_init(phydev);
-+}
-+
- static struct phy_driver aqr_driver[] = {
- {
- PHY_ID_MATCH_MODEL(PHY_ID_AQ1202),
-@@ -746,6 +758,44 @@ static struct phy_driver aqr_driver[] =
- .link_change_notify = aqr107_link_change_notify,
- },
- {
-+ PHY_ID_MATCH_MODEL(PHY_ID_AQR111),
-+ .name = "Aquantia AQR111",
-+ .probe = aqr107_probe,
-+ .get_rate_matching = aqr107_get_rate_matching,
-+ .config_init = aqr111_config_init,
-+ .config_aneg = aqr_config_aneg,
-+ .config_intr = aqr_config_intr,
-+ .handle_interrupt = aqr_handle_interrupt,
-+ .read_status = aqr107_read_status,
-+ .get_tunable = aqr107_get_tunable,
-+ .set_tunable = aqr107_set_tunable,
-+ .suspend = aqr107_suspend,
-+ .resume = aqr107_resume,
-+ .get_sset_count = aqr107_get_sset_count,
-+ .get_strings = aqr107_get_strings,
-+ .get_stats = aqr107_get_stats,
-+ .link_change_notify = aqr107_link_change_notify,
-+},
-+{
-+ PHY_ID_MATCH_MODEL(PHY_ID_AQR111B0),
-+ .name = "Aquantia AQR111B0",
-+ .probe = aqr107_probe,
-+ .get_rate_matching = aqr107_get_rate_matching,
-+ .config_init = aqr111_config_init,
-+ .config_aneg = aqr_config_aneg,
-+ .config_intr = aqr_config_intr,
-+ .handle_interrupt = aqr_handle_interrupt,
-+ .read_status = aqr107_read_status,
-+ .get_tunable = aqr107_get_tunable,
-+ .set_tunable = aqr107_set_tunable,
-+ .suspend = aqr107_suspend,
-+ .resume = aqr107_resume,
-+ .get_sset_count = aqr107_get_sset_count,
-+ .get_strings = aqr107_get_strings,
-+ .get_stats = aqr107_get_stats,
-+ .link_change_notify = aqr107_link_change_notify,
-+},
-+{
- PHY_ID_MATCH_MODEL(PHY_ID_AQR405),
- .name = "Aquantia AQR405",
- .config_aneg = aqr_config_aneg,
-@@ -820,6 +870,8 @@ static struct mdio_device_id __maybe_unu
- { PHY_ID_MATCH_MODEL(PHY_ID_AQR107) },
- { PHY_ID_MATCH_MODEL(PHY_ID_AQCS109) },
- { PHY_ID_MATCH_MODEL(PHY_ID_AQR405) },
-+ { PHY_ID_MATCH_MODEL(PHY_ID_AQR111) },
-+ { PHY_ID_MATCH_MODEL(PHY_ID_AQR111B0) },
- { PHY_ID_MATCH_MODEL(PHY_ID_AQR112) },
- { PHY_ID_MATCH_MODEL(PHY_ID_AQR412) },
- { PHY_ID_MATCH_MODEL(PHY_ID_AQR113C) },
+++ /dev/null
-From 71b605d32017e5b8d257db7344bc2f8e8fcc973e Mon Sep 17 00:00:00 2001
-Date: Thu, 15 Feb 2024 16:30:05 +0100
-Subject: [PATCH] net: phy: aquantia: add AQR113 PHY ID
-
-Add Aquantia AQR113 PHY ID. Aquantia AQR113 is just a chip size variant of
-the already supported AQR133C where the only difference is the PHY ID
-and the hw chip size.
-
----
- drivers/net/phy/aquantia/aquantia_main.c | 21 +++++++++++++++++++++
- 1 file changed, 21 insertions(+)
-
---- a/drivers/net/phy/aquantia/aquantia_main.c
-+++ b/drivers/net/phy/aquantia/aquantia_main.c
-@@ -26,6 +26,7 @@
- #define PHY_ID_AQR111B0 0x03a1b612
- #define PHY_ID_AQR112 0x03a1b662
- #define PHY_ID_AQR412 0x03a1b712
-+#define PHY_ID_AQR113 0x31c31c40
- #define PHY_ID_AQR113C 0x31c31c12
-
- #define MDIO_PHYXS_VEND_IF_STATUS 0xe812
-@@ -840,6 +841,25 @@ static struct phy_driver aqr_driver[] =
- .link_change_notify = aqr107_link_change_notify,
- },
- {
-+ PHY_ID_MATCH_MODEL(PHY_ID_AQR113),
-+ .name = "Aquantia AQR113",
-+ .probe = aqr107_probe,
-+ .get_rate_matching = aqr107_get_rate_matching,
-+ .config_init = aqr107_config_init,
-+ .config_aneg = aqr_config_aneg,
-+ .config_intr = aqr_config_intr,
-+ .handle_interrupt = aqr_handle_interrupt,
-+ .read_status = aqr107_read_status,
-+ .get_tunable = aqr107_get_tunable,
-+ .set_tunable = aqr107_set_tunable,
-+ .suspend = aqr107_suspend,
-+ .resume = aqr107_resume,
-+ .get_sset_count = aqr107_get_sset_count,
-+ .get_strings = aqr107_get_strings,
-+ .get_stats = aqr107_get_stats,
-+ .link_change_notify = aqr107_link_change_notify,
-+},
-+{
- PHY_ID_MATCH_MODEL(PHY_ID_AQR113C),
- .name = "Aquantia AQR113C",
- .probe = aqr107_probe,
-@@ -874,6 +894,7 @@ static struct mdio_device_id __maybe_unu
- { PHY_ID_MATCH_MODEL(PHY_ID_AQR111B0) },
- { PHY_ID_MATCH_MODEL(PHY_ID_AQR112) },
- { PHY_ID_MATCH_MODEL(PHY_ID_AQR412) },
-+ { PHY_ID_MATCH_MODEL(PHY_ID_AQR113) },
- { PHY_ID_MATCH_MODEL(PHY_ID_AQR113C) },
- { }
- };
+++ /dev/null
-From 6d47302a3f0ba31445478d518d98bd55918bc8ab Mon Sep 17 00:00:00 2001
-Date: Thu, 15 Feb 2024 22:43:30 +0100
-Subject: [PATCH] net: phy: aquantia: add AQR813 PHY ID
-
-Aquantia AQR813 is the Octal Port variant of the AQR113. Add PHY ID for
-it to provide support for it.
-
----
- drivers/net/phy/aquantia/aquantia_main.c | 21 +++++++++++++++++++++
- 1 file changed, 21 insertions(+)
-
---- a/drivers/net/phy/aquantia/aquantia_main.c
-+++ b/drivers/net/phy/aquantia/aquantia_main.c
-@@ -28,6 +28,7 @@
- #define PHY_ID_AQR412 0x03a1b712
- #define PHY_ID_AQR113 0x31c31c40
- #define PHY_ID_AQR113C 0x31c31c12
-+#define PHY_ID_AQR813 0x31c31cb2
-
- #define MDIO_PHYXS_VEND_IF_STATUS 0xe812
- #define MDIO_PHYXS_VEND_IF_STATUS_TYPE_MASK GENMASK(7, 3)
-@@ -878,6 +879,25 @@ static struct phy_driver aqr_driver[] =
- .get_stats = aqr107_get_stats,
- .link_change_notify = aqr107_link_change_notify,
- },
-+{
-+ PHY_ID_MATCH_MODEL(PHY_ID_AQR813),
-+ .name = "Aquantia AQR813",
-+ .probe = aqr107_probe,
-+ .get_rate_matching = aqr107_get_rate_matching,
-+ .config_init = aqr107_config_init,
-+ .config_aneg = aqr_config_aneg,
-+ .config_intr = aqr_config_intr,
-+ .handle_interrupt = aqr_handle_interrupt,
-+ .read_status = aqr107_read_status,
-+ .get_tunable = aqr107_get_tunable,
-+ .set_tunable = aqr107_set_tunable,
-+ .suspend = aqr107_suspend,
-+ .resume = aqr107_resume,
-+ .get_sset_count = aqr107_get_sset_count,
-+ .get_strings = aqr107_get_strings,
-+ .get_stats = aqr107_get_stats,
-+ .link_change_notify = aqr107_link_change_notify,
-+},
- };
-
- module_phy_driver(aqr_driver);
-@@ -896,6 +916,7 @@ static struct mdio_device_id __maybe_unu
- { PHY_ID_MATCH_MODEL(PHY_ID_AQR412) },
- { PHY_ID_MATCH_MODEL(PHY_ID_AQR113) },
- { PHY_ID_MATCH_MODEL(PHY_ID_AQR113C) },
-+ { PHY_ID_MATCH_MODEL(PHY_ID_AQR813) },
- { }
- };
-
+++ /dev/null
-From f13b2b33c7674fa0988dfaa9adb95d7d912b489f Mon Sep 17 00:00:00 2001
-Date: Wed, 10 Apr 2024 20:42:38 +0100
-Subject: [PATCH 1/2] net: dsa: introduce dsa_phylink_to_port()
-
-We convert from a phylink_config struct to a dsa_port struct in many
-places, let's provide a helper for this.
-
----
- include/net/dsa.h | 6 ++++++
- net/dsa/port.c | 12 ++++++------
- 2 files changed, 12 insertions(+), 6 deletions(-)
-
---- a/include/net/dsa.h
-+++ b/include/net/dsa.h
-@@ -327,6 +327,12 @@ struct dsa_port {
- };
- };
-
-+static inline struct dsa_port *
-+dsa_phylink_to_port(struct phylink_config *config)
-+{
-+ return container_of(config, struct dsa_port, pl_config);
-+}
-+
- /* TODO: ideally DSA ports would have a single dp->link_dp member,
- * and no dst->rtable nor this struct dsa_link would be needed,
- * but this would require some more complex tree walking,
---- a/net/dsa/port.c
-+++ b/net/dsa/port.c
-@@ -1572,7 +1572,7 @@ static struct phylink_pcs *
- dsa_port_phylink_mac_select_pcs(struct phylink_config *config,
- phy_interface_t interface)
- {
-- struct dsa_port *dp = container_of(config, struct dsa_port, pl_config);
-+ struct dsa_port *dp = dsa_phylink_to_port(config);
- struct phylink_pcs *pcs = ERR_PTR(-EOPNOTSUPP);
- struct dsa_switch *ds = dp->ds;
-
-@@ -1586,7 +1586,7 @@ static int dsa_port_phylink_mac_prepare(
- unsigned int mode,
- phy_interface_t interface)
- {
-- struct dsa_port *dp = container_of(config, struct dsa_port, pl_config);
-+ struct dsa_port *dp = dsa_phylink_to_port(config);
- struct dsa_switch *ds = dp->ds;
- int err = 0;
-
-@@ -1601,7 +1601,7 @@ static void dsa_port_phylink_mac_config(
- unsigned int mode,
- const struct phylink_link_state *state)
- {
-- struct dsa_port *dp = container_of(config, struct dsa_port, pl_config);
-+ struct dsa_port *dp = dsa_phylink_to_port(config);
- struct dsa_switch *ds = dp->ds;
-
- if (!ds->ops->phylink_mac_config)
-@@ -1614,7 +1614,7 @@ static int dsa_port_phylink_mac_finish(s
- unsigned int mode,
- phy_interface_t interface)
- {
-- struct dsa_port *dp = container_of(config, struct dsa_port, pl_config);
-+ struct dsa_port *dp = dsa_phylink_to_port(config);
- struct dsa_switch *ds = dp->ds;
- int err = 0;
-
-@@ -1629,7 +1629,7 @@ static void dsa_port_phylink_mac_link_do
- unsigned int mode,
- phy_interface_t interface)
- {
-- struct dsa_port *dp = container_of(config, struct dsa_port, pl_config);
-+ struct dsa_port *dp = dsa_phylink_to_port(config);
- struct phy_device *phydev = NULL;
- struct dsa_switch *ds = dp->ds;
-
-@@ -1652,7 +1652,7 @@ static void dsa_port_phylink_mac_link_up
- int speed, int duplex,
- bool tx_pause, bool rx_pause)
- {
-- struct dsa_port *dp = container_of(config, struct dsa_port, pl_config);
-+ struct dsa_port *dp = dsa_phylink_to_port(config);
- struct dsa_switch *ds = dp->ds;
-
- if (!ds->ops->phylink_mac_link_up) {
+++ /dev/null
-From c22d8240fcd73a1c3ec8dcb055bd583fb970c375 Mon Sep 17 00:00:00 2001
-Date: Wed, 10 Apr 2024 20:42:43 +0100
-Subject: [PATCH 2/2] net: dsa: allow DSA switch drivers to provide their own
- phylink mac ops
-
-Rather than having a shim for each and every phylink MAC operation,
-allow DSA switch drivers to provide their own ops structure. When a
-DSA driver provides the phylink MAC operations, the shimmed ops must
-not be provided, so fail an attempt to register a switch with both
-the phylink_mac_ops in struct dsa_switch and the phylink_mac_*
-operations populated in dsa_switch_ops populated.
-
----
- include/net/dsa.h | 5 +++++
- net/dsa/dsa.c | 11 +++++++++++
- net/dsa/port.c | 26 ++++++++++++++++++++------
- 3 files changed, 36 insertions(+), 6 deletions(-)
-
---- a/include/net/dsa.h
-+++ b/include/net/dsa.h
-@@ -458,6 +458,11 @@ struct dsa_switch {
- const struct dsa_switch_ops *ops;
-
- /*
-+ * Allow a DSA switch driver to override the phylink MAC ops
-+ */
-+ const struct phylink_mac_ops *phylink_mac_ops;
-+
-+ /*
- * Slave mii_bus and devices for the individual ports.
- */
- u32 phys_mii_mask;
---- a/net/dsa/dsa.c
-+++ b/net/dsa/dsa.c
-@@ -1549,6 +1549,17 @@ static int dsa_switch_probe(struct dsa_s
- if (!ds->num_ports)
- return -EINVAL;
-
-+ if (ds->phylink_mac_ops) {
-+ if (ds->ops->phylink_mac_select_pcs ||
-+ ds->ops->phylink_mac_prepare ||
-+ ds->ops->phylink_mac_config ||
-+ ds->ops->phylink_mac_finish ||
-+ ds->ops->phylink_mac_link_down ||
-+ ds->ops->phylink_mac_link_up ||
-+ ds->ops->adjust_link)
-+ return -EINVAL;
-+ }
-+
- if (np) {
- err = dsa_switch_parse_of(ds, np);
- if (err)
---- a/net/dsa/port.c
-+++ b/net/dsa/port.c
-@@ -1677,6 +1677,7 @@ static const struct phylink_mac_ops dsa_
-
- int dsa_port_phylink_create(struct dsa_port *dp)
- {
-+ const struct phylink_mac_ops *mac_ops;
- struct dsa_switch *ds = dp->ds;
- phy_interface_t mode;
- struct phylink *pl;
-@@ -1700,8 +1701,12 @@ int dsa_port_phylink_create(struct dsa_p
- }
- }
-
-- pl = phylink_create(&dp->pl_config, of_fwnode_handle(dp->dn),
-- mode, &dsa_port_phylink_mac_ops);
-+ mac_ops = &dsa_port_phylink_mac_ops;
-+ if (ds->phylink_mac_ops)
-+ mac_ops = ds->phylink_mac_ops;
-+
-+ pl = phylink_create(&dp->pl_config, of_fwnode_handle(dp->dn), mode,
-+ mac_ops);
- if (IS_ERR(pl)) {
- pr_err("error creating PHYLINK: %ld\n", PTR_ERR(pl));
- return PTR_ERR(pl);
-@@ -1967,12 +1972,23 @@ static void dsa_shared_port_validate_of(
- dn, dsa_port_is_cpu(dp) ? "CPU" : "DSA", dp->index);
- }
-
-+static void dsa_shared_port_link_down(struct dsa_port *dp)
-+{
-+ struct dsa_switch *ds = dp->ds;
-+
-+ if (ds->phylink_mac_ops && ds->phylink_mac_ops->mac_link_down)
-+ ds->phylink_mac_ops->mac_link_down(&dp->pl_config, MLO_AN_FIXED,
-+ PHY_INTERFACE_MODE_NA);
-+ else if (ds->ops->phylink_mac_link_down)
-+ ds->ops->phylink_mac_link_down(ds, dp->index, MLO_AN_FIXED,
-+ PHY_INTERFACE_MODE_NA);
-+}
-+
- int dsa_shared_port_link_register_of(struct dsa_port *dp)
- {
- struct dsa_switch *ds = dp->ds;
- bool missing_link_description;
- bool missing_phy_mode;
-- int port = dp->index;
-
- dsa_shared_port_validate_of(dp, &missing_phy_mode,
- &missing_link_description);
-@@ -1988,9 +2004,7 @@ int dsa_shared_port_link_register_of(str
- "Skipping phylink registration for %s port %d\n",
- dsa_port_is_cpu(dp) ? "CPU" : "DSA", dp->index);
- } else {
-- if (ds->ops->phylink_mac_link_down)
-- ds->ops->phylink_mac_link_down(ds, port,
-- MLO_AN_FIXED, PHY_INTERFACE_MODE_NA);
-+ dsa_shared_port_link_down(dp);
-
- return dsa_shared_port_phylink_register(dp);
- }
+++ /dev/null
-From c278ec644377249aba5b1e1ca2b5705fd1c0132c Mon Sep 17 00:00:00 2001
-Date: Mon, 1 Apr 2024 16:51:06 +0200
-Subject: [PATCH net-next v2] net: phy: aquantia: add support for AQR114C PHY ID
-
-Add support for AQR114C PHY ID. This PHY advertise 10G speed:
-SPEED(0x04): 0x6031
- capabilities: -400g +5g +2.5g -200g -25g -10g-xr -100g -40g -10g/1g -10
- +100 +1000 -10-ts -2-tl +10g
-EXTABLE(0x0B): 0x40fc
- capabilities: -10g-cx4 -10g-lrm +10g-t +10g-kx4 +10g-kr +1000-t +1000-kx
- +100-tx -10-t -p2mp -40g/100g -1000/100-t1 -25g -200g/400g
- +2.5g/5g -1000-h
-
-but supports only up to 5G speed (as with AQR111/111B0).
-AQR111 init config is used to set max speed 5G.
-
----
- drivers/net/phy/aquantia/aquantia_main.c | 21 +++++++++++++++++++++
- 1 file changed, 21 insertions(+)
-
---- a/drivers/net/phy/aquantia/aquantia_main.c
-+++ b/drivers/net/phy/aquantia/aquantia_main.c
-@@ -28,6 +28,7 @@
- #define PHY_ID_AQR412 0x03a1b712
- #define PHY_ID_AQR113 0x31c31c40
- #define PHY_ID_AQR113C 0x31c31c12
-+#define PHY_ID_AQR114C 0x31c31c22
- #define PHY_ID_AQR813 0x31c31cb2
-
- #define MDIO_PHYXS_VEND_IF_STATUS 0xe812
-@@ -880,6 +881,25 @@ static struct phy_driver aqr_driver[] =
- .link_change_notify = aqr107_link_change_notify,
- },
- {
-+ PHY_ID_MATCH_MODEL(PHY_ID_AQR114C),
-+ .name = "Aquantia AQR114C",
-+ .probe = aqr107_probe,
-+ .get_rate_matching = aqr107_get_rate_matching,
-+ .config_init = aqr111_config_init,
-+ .config_aneg = aqr_config_aneg,
-+ .config_intr = aqr_config_intr,
-+ .handle_interrupt = aqr_handle_interrupt,
-+ .read_status = aqr107_read_status,
-+ .get_tunable = aqr107_get_tunable,
-+ .set_tunable = aqr107_set_tunable,
-+ .suspend = aqr107_suspend,
-+ .resume = aqr107_resume,
-+ .get_sset_count = aqr107_get_sset_count,
-+ .get_strings = aqr107_get_strings,
-+ .get_stats = aqr107_get_stats,
-+ .link_change_notify = aqr107_link_change_notify,
-+},
-+{
- PHY_ID_MATCH_MODEL(PHY_ID_AQR813),
- .name = "Aquantia AQR813",
- .probe = aqr107_probe,
-@@ -916,6 +936,7 @@ static struct mdio_device_id __maybe_unu
- { PHY_ID_MATCH_MODEL(PHY_ID_AQR412) },
- { PHY_ID_MATCH_MODEL(PHY_ID_AQR113) },
- { PHY_ID_MATCH_MODEL(PHY_ID_AQR113C) },
-+ { PHY_ID_MATCH_MODEL(PHY_ID_AQR114C) },
- { PHY_ID_MATCH_MODEL(PHY_ID_AQR813) },
- { }
- };
+++ /dev/null
-From 7f3eb2174512fe6c9c0f062e96eccb0d3cc6d5cd Mon Sep 17 00:00:00 2001
-Date: Wed, 18 Oct 2023 14:35:47 +0200
-Subject: [PATCH] net: introduce napi_is_scheduled helper
-
-We currently have napi_if_scheduled_mark_missed that can be used to
-check if napi is scheduled but that does more thing than simply checking
-it and return a bool. Some driver already implement custom function to
-check if napi is scheduled.
-
-Drop these custom function and introduce napi_is_scheduled that simply
-check if napi is scheduled atomically.
-
-Update any driver and code that implement a similar check and instead
-use this new helper.
-
----
- drivers/net/ethernet/chelsio/cxgb3/sge.c | 8 --------
- drivers/net/wireless/realtek/rtw89/core.c | 2 +-
- include/linux/netdevice.h | 23 +++++++++++++++++++++++
- net/core/dev.c | 2 +-
- 4 files changed, 25 insertions(+), 10 deletions(-)
-
---- a/drivers/net/ethernet/chelsio/cxgb3/sge.c
-+++ b/drivers/net/ethernet/chelsio/cxgb3/sge.c
-@@ -2501,14 +2501,6 @@ static int napi_rx_handler(struct napi_s
- return work_done;
- }
-
--/*
-- * Returns true if the device is already scheduled for polling.
-- */
--static inline int napi_is_scheduled(struct napi_struct *napi)
--{
-- return test_bit(NAPI_STATE_SCHED, &napi->state);
--}
--
- /**
- * process_pure_responses - process pure responses from a response queue
- * @adap: the adapter
---- a/drivers/net/wireless/realtek/rtw89/core.c
-+++ b/drivers/net/wireless/realtek/rtw89/core.c
-@@ -1749,7 +1749,7 @@ static void rtw89_core_rx_to_mac80211(st
- struct napi_struct *napi = &rtwdev->napi;
-
- /* In low power mode, napi isn't scheduled. Receive it to netif. */
-- if (unlikely(!test_bit(NAPI_STATE_SCHED, &napi->state)))
-+ if (unlikely(!napi_is_scheduled(napi)))
- napi = NULL;
-
- rtw89_core_hw_to_sband_rate(rx_status);
---- a/include/linux/netdevice.h
-+++ b/include/linux/netdevice.h
-@@ -480,6 +480,29 @@ static inline bool napi_prefer_busy_poll
- return test_bit(NAPI_STATE_PREFER_BUSY_POLL, &n->state);
- }
-
-+/**
-+ * napi_is_scheduled - test if NAPI is scheduled
-+ * @n: NAPI context
-+ *
-+ * This check is "best-effort". With no locking implemented,
-+ * a NAPI can be scheduled or terminate right after this check
-+ * and produce not precise results.
-+ *
-+ * NAPI_STATE_SCHED is an internal state, napi_is_scheduled
-+ * should not be used normally and napi_schedule should be
-+ * used instead.
-+ *
-+ * Use only if the driver really needs to check if a NAPI
-+ * is scheduled for example in the context of delayed timer
-+ * that can be skipped if a NAPI is already scheduled.
-+ *
-+ * Return True if NAPI is scheduled, False otherwise.
-+ */
-+static inline bool napi_is_scheduled(struct napi_struct *n)
-+{
-+ return test_bit(NAPI_STATE_SCHED, &n->state);
-+}
-+
- bool napi_schedule_prep(struct napi_struct *n);
-
- /**
---- a/net/core/dev.c
-+++ b/net/core/dev.c
-@@ -6655,7 +6655,7 @@ static int __napi_poll(struct napi_struc
- * accidentally calling ->poll() when NAPI is not scheduled.
- */
- work = 0;
-- if (test_bit(NAPI_STATE_SCHED, &n->state)) {
-+ if (napi_is_scheduled(n)) {
- work = n->poll(n, weight);
- trace_napi_poll(n, work, weight);
- }
+++ /dev/null
-From 2d1a42cf7f77cda54dbbee18d00b1200e7bc22aa Mon Sep 17 00:00:00 2001
-Date: Wed, 18 Oct 2023 14:35:48 +0200
-Subject: [PATCH 1/3] net: stmmac: improve TX timer arm logic
-
-There is currently a problem with the TX timer getting armed multiple
-unnecessary times causing big performance regression on some device that
-suffer from heavy handling of hrtimer rearm.
-
-The use of the TX timer is an old implementation that predates the napi
-implementation and the interrupt enable/disable handling.
-
-Due to stmmac being a very old code, the TX timer was never evaluated
-again with this new implementation and was kept there causing
-performance regression. The performance regression started to appear
-with kernel version 4.19 with 8fce33317023 ("net: stmmac: Rework coalesce
-timer and fix multi-queue races") where the timer was reduced to 1ms
-causing it to be armed 40 times more than before.
-
-Decreasing the timer made the problem more present and caused the
-regression in the other of 600-700mbps on some device (regression where
-this was notice is ipq806x).
-
-The problem is in the fact that handling the hrtimer on some target is
-expensive and recent kernel made the timer armed much more times.
-A solution that was proposed was reverting the hrtimer change and use
-mod_timer but such solution would still hide the real problem in the
-current implementation.
-
-To fix the regression, apply some additional logic and skip arming the
-timer when not needed.
-
-Arm the timer ONLY if a napi is not already scheduled. Running the timer
-is redundant since the same function (stmmac_tx_clean) will run in the
-napi TX poll. Also try to cancel any timer if a napi is scheduled to
-prevent redundant run of TX call.
-
-With the following new logic the original performance are restored while
-keeping using the hrtimer.
-
----
- .../net/ethernet/stmicro/stmmac/stmmac_main.c | 18 +++++++++++++++---
- 1 file changed, 15 insertions(+), 3 deletions(-)
-
---- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
-+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
-@@ -2994,13 +2994,25 @@ static void stmmac_tx_timer_arm(struct s
- {
- struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[queue];
- u32 tx_coal_timer = priv->tx_coal_timer[queue];
-+ struct stmmac_channel *ch;
-+ struct napi_struct *napi;
-
- if (!tx_coal_timer)
- return;
-
-- hrtimer_start(&tx_q->txtimer,
-- STMMAC_COAL_TIMER(tx_coal_timer),
-- HRTIMER_MODE_REL);
-+ ch = &priv->channel[tx_q->queue_index];
-+ napi = tx_q->xsk_pool ? &ch->rxtx_napi : &ch->tx_napi;
-+
-+ /* Arm timer only if napi is not already scheduled.
-+ * Try to cancel any timer if napi is scheduled, timer will be armed
-+ * again in the next scheduled napi.
-+ */
-+ if (unlikely(!napi_is_scheduled(napi)))
-+ hrtimer_start(&tx_q->txtimer,
-+ STMMAC_COAL_TIMER(tx_coal_timer),
-+ HRTIMER_MODE_REL);
-+ else
-+ hrtimer_try_to_cancel(&tx_q->txtimer);
- }
-
- /**
+++ /dev/null
-From a594166387fe08e6f5a32130c400249a35b298f9 Mon Sep 17 00:00:00 2001
-Date: Wed, 18 Oct 2023 14:35:49 +0200
-Subject: [PATCH 2/3] net: stmmac: move TX timer arm after DMA enable
-
-Move TX timer arm call after DMA interrupt is enabled again.
-
-The TX timer arm function changed logic and now is skipped if a napi is
-already scheduled. By moving the TX timer arm call after DMA is enabled,
-we permit to correctly skip if a DMA interrupt has been fired and a napi
-has been scheduled again.
-
----
- .../net/ethernet/stmicro/stmmac/stmmac_main.c | 22 +++++++++++++++----
- 1 file changed, 18 insertions(+), 4 deletions(-)
-
---- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
-+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
-@@ -2542,9 +2542,13 @@ static void stmmac_bump_dma_threshold(st
- * @priv: driver private structure
- * @budget: napi budget limiting this functions packet handling
- * @queue: TX queue index
-+ * @pending_packets: signal to arm the TX coal timer
- * Description: it reclaims the transmit resources after transmission completes.
-+ * If some packets still needs to be handled, due to TX coalesce, set
-+ * pending_packets to true to make NAPI arm the TX coal timer.
- */
--static int stmmac_tx_clean(struct stmmac_priv *priv, int budget, u32 queue)
-+static int stmmac_tx_clean(struct stmmac_priv *priv, int budget, u32 queue,
-+ bool *pending_packets)
- {
- struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[queue];
- struct stmmac_txq_stats *txq_stats = &priv->xstats.txq_stats[queue];
-@@ -2704,7 +2708,7 @@ static int stmmac_tx_clean(struct stmmac
-
- /* We still have pending packets, let's call for a new scheduling */
- if (tx_q->dirty_tx != tx_q->cur_tx)
-- stmmac_tx_timer_arm(priv, queue);
-+ *pending_packets = true;
-
- u64_stats_update_begin(&txq_stats->napi_syncp);
- u64_stats_add(&txq_stats->napi.tx_packets, tx_packets);
-@@ -5609,6 +5613,7 @@ static int stmmac_napi_poll_tx(struct na
- container_of(napi, struct stmmac_channel, tx_napi);
- struct stmmac_priv *priv = ch->priv_data;
- struct stmmac_txq_stats *txq_stats;
-+ bool pending_packets = false;
- u32 chan = ch->index;
- int work_done;
-
-@@ -5617,7 +5622,7 @@ static int stmmac_napi_poll_tx(struct na
- u64_stats_inc(&txq_stats->napi.poll);
- u64_stats_update_end(&txq_stats->napi_syncp);
-
-- work_done = stmmac_tx_clean(priv, budget, chan);
-+ work_done = stmmac_tx_clean(priv, budget, chan, &pending_packets);
- work_done = min(work_done, budget);
-
- if (work_done < budget && napi_complete_done(napi, work_done)) {
-@@ -5628,6 +5633,10 @@ static int stmmac_napi_poll_tx(struct na
- spin_unlock_irqrestore(&ch->lock, flags);
- }
-
-+ /* TX still have packet to handle, check if we need to arm tx timer */
-+ if (pending_packets)
-+ stmmac_tx_timer_arm(priv, chan);
-+
- return work_done;
- }
-
-@@ -5636,6 +5645,7 @@ static int stmmac_napi_poll_rxtx(struct
- struct stmmac_channel *ch =
- container_of(napi, struct stmmac_channel, rxtx_napi);
- struct stmmac_priv *priv = ch->priv_data;
-+ bool tx_pending_packets = false;
- int rx_done, tx_done, rxtx_done;
- struct stmmac_rxq_stats *rxq_stats;
- struct stmmac_txq_stats *txq_stats;
-@@ -5651,7 +5661,7 @@ static int stmmac_napi_poll_rxtx(struct
- u64_stats_inc(&txq_stats->napi.poll);
- u64_stats_update_end(&txq_stats->napi_syncp);
-
-- tx_done = stmmac_tx_clean(priv, budget, chan);
-+ tx_done = stmmac_tx_clean(priv, budget, chan, &tx_pending_packets);
- tx_done = min(tx_done, budget);
-
- rx_done = stmmac_rx_zc(priv, budget, chan);
-@@ -5676,6 +5686,10 @@ static int stmmac_napi_poll_rxtx(struct
- spin_unlock_irqrestore(&ch->lock, flags);
- }
-
-+ /* TX still have packet to handle, check if we need to arm tx timer */
-+ if (tx_pending_packets)
-+ stmmac_tx_timer_arm(priv, chan);
-+
- return min(rxtx_done, budget - 1);
- }
-
+++ /dev/null
-From 039550960a2235cfe2dfaa773df9f98f8da31a0c Mon Sep 17 00:00:00 2001
-Date: Wed, 18 Oct 2023 14:35:50 +0200
-Subject: [PATCH 3/3] net: stmmac: increase TX coalesce timer to 5ms
-
-Commit 8fce33317023 ("net: stmmac: Rework coalesce timer and fix
-multi-queue races") decreased the TX coalesce timer from 40ms to 1ms.
-
-This caused some performance regression on some target (regression was
-reported at least on ipq806x) in the order of 600mbps dropping from
-gigabit handling to only 200mbps.
-
-The problem was identified in the TX timer getting armed too much time.
-While this was fixed and improved in another commit, performance can be
-improved even further by increasing the timer delay a bit moving from
-1ms to 5ms.
-
-The value is a good balance between battery saving by prevending too
-much interrupt to be generated and permitting good performance for
-internet oriented devices.
-
----
- drivers/net/ethernet/stmicro/stmmac/common.h | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/net/ethernet/stmicro/stmmac/common.h
-+++ b/drivers/net/ethernet/stmicro/stmmac/common.h
-@@ -318,7 +318,7 @@ struct stmmac_safety_stats {
- #define MIN_DMA_RIWT 0x10
- #define DEF_DMA_RIWT 0xa0
- /* Tx coalesce parameters */
--#define STMMAC_COAL_TX_TIMER 1000
-+#define STMMAC_COAL_TX_TIMER 5000
- #define STMMAC_MAX_COAL_TX_TICK 100000
- #define STMMAC_TX_MAX_FRAMES 256
- #define STMMAC_TX_FRAMES 25
+++ /dev/null
-From 055dd7511f675d26fa283b35bb3dadfc7f77ed97 Mon Sep 17 00:00:00 2001
-Date: Mon, 13 Nov 2023 20:13:26 +0100
-Subject: [PATCH] r8169: improve RTL8411b phy-down fixup
-
-Mirsad proposed a patch to reduce the number of spinlock lock/unlock
-operations and the function code size. This can be further improved
-because the function sets a consecutive register block.
-
----
- drivers/net/ethernet/realtek/r8169_main.c | 139 +++++-----------------
- 1 file changed, 28 insertions(+), 111 deletions(-)
-
---- a/drivers/net/ethernet/realtek/r8169_main.c
-+++ b/drivers/net/ethernet/realtek/r8169_main.c
-@@ -3156,6 +3156,33 @@ static void rtl_hw_start_8168g_2(struct
- rtl_ephy_init(tp, e_info_8168g_2);
- }
-
-+static void rtl8411b_fix_phy_down(struct rtl8169_private *tp)
-+{
-+ static const u16 fix_data[] = {
-+/* 0xf800 */ 0xe008, 0xe00a, 0xe00c, 0xe00e, 0xe027, 0xe04f, 0xe05e, 0xe065,
-+/* 0xf810 */ 0xc602, 0xbe00, 0x0000, 0xc502, 0xbd00, 0x074c, 0xc302, 0xbb00,
-+/* 0xf820 */ 0x080a, 0x6420, 0x48c2, 0x8c20, 0xc516, 0x64a4, 0x49c0, 0xf009,
-+/* 0xf830 */ 0x74a2, 0x8ca5, 0x74a0, 0xc50e, 0x9ca2, 0x1c11, 0x9ca0, 0xe006,
-+/* 0xf840 */ 0x74f8, 0x48c4, 0x8cf8, 0xc404, 0xbc00, 0xc403, 0xbc00, 0x0bf2,
-+/* 0xf850 */ 0x0c0a, 0xe434, 0xd3c0, 0x49d9, 0xf01f, 0xc526, 0x64a5, 0x1400,
-+/* 0xf860 */ 0xf007, 0x0c01, 0x8ca5, 0x1c15, 0xc51b, 0x9ca0, 0xe013, 0xc519,
-+/* 0xf870 */ 0x74a0, 0x48c4, 0x8ca0, 0xc516, 0x74a4, 0x48c8, 0x48ca, 0x9ca4,
-+/* 0xf880 */ 0xc512, 0x1b00, 0x9ba0, 0x1b1c, 0x483f, 0x9ba2, 0x1b04, 0xc508,
-+/* 0xf890 */ 0x9ba0, 0xc505, 0xbd00, 0xc502, 0xbd00, 0x0300, 0x051e, 0xe434,
-+/* 0xf8a0 */ 0xe018, 0xe092, 0xde20, 0xd3c0, 0xc50f, 0x76a4, 0x49e3, 0xf007,
-+/* 0xf8b0 */ 0x49c0, 0xf103, 0xc607, 0xbe00, 0xc606, 0xbe00, 0xc602, 0xbe00,
-+/* 0xf8c0 */ 0x0c4c, 0x0c28, 0x0c2c, 0xdc00, 0xc707, 0x1d00, 0x8de2, 0x48c1,
-+/* 0xf8d0 */ 0xc502, 0xbd00, 0x00aa, 0xe0c0, 0xc502, 0xbd00, 0x0132
-+ };
-+ unsigned long flags;
-+ int i;
-+
-+ raw_spin_lock_irqsave(&tp->mac_ocp_lock, flags);
-+ for (i = 0; i < ARRAY_SIZE(fix_data); i++)
-+ __r8168_mac_ocp_write(tp, 0xf800 + 2 * i, fix_data[i]);
-+ raw_spin_unlock_irqrestore(&tp->mac_ocp_lock, flags);
-+}
-+
- static void rtl_hw_start_8411_2(struct rtl8169_private *tp)
- {
- static const struct ephy_info e_info_8411_2[] = {
-@@ -3189,117 +3216,7 @@ static void rtl_hw_start_8411_2(struct r
- mdelay(3);
- r8168_mac_ocp_write(tp, 0xFC26, 0x0000);
-
-- r8168_mac_ocp_write(tp, 0xF800, 0xE008);
-- r8168_mac_ocp_write(tp, 0xF802, 0xE00A);
-- r8168_mac_ocp_write(tp, 0xF804, 0xE00C);
-- r8168_mac_ocp_write(tp, 0xF806, 0xE00E);
-- r8168_mac_ocp_write(tp, 0xF808, 0xE027);
-- r8168_mac_ocp_write(tp, 0xF80A, 0xE04F);
-- r8168_mac_ocp_write(tp, 0xF80C, 0xE05E);
-- r8168_mac_ocp_write(tp, 0xF80E, 0xE065);
-- r8168_mac_ocp_write(tp, 0xF810, 0xC602);
-- r8168_mac_ocp_write(tp, 0xF812, 0xBE00);
-- r8168_mac_ocp_write(tp, 0xF814, 0x0000);
-- r8168_mac_ocp_write(tp, 0xF816, 0xC502);
-- r8168_mac_ocp_write(tp, 0xF818, 0xBD00);
-- r8168_mac_ocp_write(tp, 0xF81A, 0x074C);
-- r8168_mac_ocp_write(tp, 0xF81C, 0xC302);
-- r8168_mac_ocp_write(tp, 0xF81E, 0xBB00);
-- r8168_mac_ocp_write(tp, 0xF820, 0x080A);
-- r8168_mac_ocp_write(tp, 0xF822, 0x6420);
-- r8168_mac_ocp_write(tp, 0xF824, 0x48C2);
-- r8168_mac_ocp_write(tp, 0xF826, 0x8C20);
-- r8168_mac_ocp_write(tp, 0xF828, 0xC516);
-- r8168_mac_ocp_write(tp, 0xF82A, 0x64A4);
-- r8168_mac_ocp_write(tp, 0xF82C, 0x49C0);
-- r8168_mac_ocp_write(tp, 0xF82E, 0xF009);
-- r8168_mac_ocp_write(tp, 0xF830, 0x74A2);
-- r8168_mac_ocp_write(tp, 0xF832, 0x8CA5);
-- r8168_mac_ocp_write(tp, 0xF834, 0x74A0);
-- r8168_mac_ocp_write(tp, 0xF836, 0xC50E);
-- r8168_mac_ocp_write(tp, 0xF838, 0x9CA2);
-- r8168_mac_ocp_write(tp, 0xF83A, 0x1C11);
-- r8168_mac_ocp_write(tp, 0xF83C, 0x9CA0);
-- r8168_mac_ocp_write(tp, 0xF83E, 0xE006);
-- r8168_mac_ocp_write(tp, 0xF840, 0x74F8);
-- r8168_mac_ocp_write(tp, 0xF842, 0x48C4);
-- r8168_mac_ocp_write(tp, 0xF844, 0x8CF8);
-- r8168_mac_ocp_write(tp, 0xF846, 0xC404);
-- r8168_mac_ocp_write(tp, 0xF848, 0xBC00);
-- r8168_mac_ocp_write(tp, 0xF84A, 0xC403);
-- r8168_mac_ocp_write(tp, 0xF84C, 0xBC00);
-- r8168_mac_ocp_write(tp, 0xF84E, 0x0BF2);
-- r8168_mac_ocp_write(tp, 0xF850, 0x0C0A);
-- r8168_mac_ocp_write(tp, 0xF852, 0xE434);
-- r8168_mac_ocp_write(tp, 0xF854, 0xD3C0);
-- r8168_mac_ocp_write(tp, 0xF856, 0x49D9);
-- r8168_mac_ocp_write(tp, 0xF858, 0xF01F);
-- r8168_mac_ocp_write(tp, 0xF85A, 0xC526);
-- r8168_mac_ocp_write(tp, 0xF85C, 0x64A5);
-- r8168_mac_ocp_write(tp, 0xF85E, 0x1400);
-- r8168_mac_ocp_write(tp, 0xF860, 0xF007);
-- r8168_mac_ocp_write(tp, 0xF862, 0x0C01);
-- r8168_mac_ocp_write(tp, 0xF864, 0x8CA5);
-- r8168_mac_ocp_write(tp, 0xF866, 0x1C15);
-- r8168_mac_ocp_write(tp, 0xF868, 0xC51B);
-- r8168_mac_ocp_write(tp, 0xF86A, 0x9CA0);
-- r8168_mac_ocp_write(tp, 0xF86C, 0xE013);
-- r8168_mac_ocp_write(tp, 0xF86E, 0xC519);
-- r8168_mac_ocp_write(tp, 0xF870, 0x74A0);
-- r8168_mac_ocp_write(tp, 0xF872, 0x48C4);
-- r8168_mac_ocp_write(tp, 0xF874, 0x8CA0);
-- r8168_mac_ocp_write(tp, 0xF876, 0xC516);
-- r8168_mac_ocp_write(tp, 0xF878, 0x74A4);
-- r8168_mac_ocp_write(tp, 0xF87A, 0x48C8);
-- r8168_mac_ocp_write(tp, 0xF87C, 0x48CA);
-- r8168_mac_ocp_write(tp, 0xF87E, 0x9CA4);
-- r8168_mac_ocp_write(tp, 0xF880, 0xC512);
-- r8168_mac_ocp_write(tp, 0xF882, 0x1B00);
-- r8168_mac_ocp_write(tp, 0xF884, 0x9BA0);
-- r8168_mac_ocp_write(tp, 0xF886, 0x1B1C);
-- r8168_mac_ocp_write(tp, 0xF888, 0x483F);
-- r8168_mac_ocp_write(tp, 0xF88A, 0x9BA2);
-- r8168_mac_ocp_write(tp, 0xF88C, 0x1B04);
-- r8168_mac_ocp_write(tp, 0xF88E, 0xC508);
-- r8168_mac_ocp_write(tp, 0xF890, 0x9BA0);
-- r8168_mac_ocp_write(tp, 0xF892, 0xC505);
-- r8168_mac_ocp_write(tp, 0xF894, 0xBD00);
-- r8168_mac_ocp_write(tp, 0xF896, 0xC502);
-- r8168_mac_ocp_write(tp, 0xF898, 0xBD00);
-- r8168_mac_ocp_write(tp, 0xF89A, 0x0300);
-- r8168_mac_ocp_write(tp, 0xF89C, 0x051E);
-- r8168_mac_ocp_write(tp, 0xF89E, 0xE434);
-- r8168_mac_ocp_write(tp, 0xF8A0, 0xE018);
-- r8168_mac_ocp_write(tp, 0xF8A2, 0xE092);
-- r8168_mac_ocp_write(tp, 0xF8A4, 0xDE20);
-- r8168_mac_ocp_write(tp, 0xF8A6, 0xD3C0);
-- r8168_mac_ocp_write(tp, 0xF8A8, 0xC50F);
-- r8168_mac_ocp_write(tp, 0xF8AA, 0x76A4);
-- r8168_mac_ocp_write(tp, 0xF8AC, 0x49E3);
-- r8168_mac_ocp_write(tp, 0xF8AE, 0xF007);
-- r8168_mac_ocp_write(tp, 0xF8B0, 0x49C0);
-- r8168_mac_ocp_write(tp, 0xF8B2, 0xF103);
-- r8168_mac_ocp_write(tp, 0xF8B4, 0xC607);
-- r8168_mac_ocp_write(tp, 0xF8B6, 0xBE00);
-- r8168_mac_ocp_write(tp, 0xF8B8, 0xC606);
-- r8168_mac_ocp_write(tp, 0xF8BA, 0xBE00);
-- r8168_mac_ocp_write(tp, 0xF8BC, 0xC602);
-- r8168_mac_ocp_write(tp, 0xF8BE, 0xBE00);
-- r8168_mac_ocp_write(tp, 0xF8C0, 0x0C4C);
-- r8168_mac_ocp_write(tp, 0xF8C2, 0x0C28);
-- r8168_mac_ocp_write(tp, 0xF8C4, 0x0C2C);
-- r8168_mac_ocp_write(tp, 0xF8C6, 0xDC00);
-- r8168_mac_ocp_write(tp, 0xF8C8, 0xC707);
-- r8168_mac_ocp_write(tp, 0xF8CA, 0x1D00);
-- r8168_mac_ocp_write(tp, 0xF8CC, 0x8DE2);
-- r8168_mac_ocp_write(tp, 0xF8CE, 0x48C1);
-- r8168_mac_ocp_write(tp, 0xF8D0, 0xC502);
-- r8168_mac_ocp_write(tp, 0xF8D2, 0xBD00);
-- r8168_mac_ocp_write(tp, 0xF8D4, 0x00AA);
-- r8168_mac_ocp_write(tp, 0xF8D6, 0xE0C0);
-- r8168_mac_ocp_write(tp, 0xF8D8, 0xC502);
-- r8168_mac_ocp_write(tp, 0xF8DA, 0xBD00);
-- r8168_mac_ocp_write(tp, 0xF8DC, 0x0132);
-+ rtl8411b_fix_phy_down(tp);
-
- r8168_mac_ocp_write(tp, 0xFC26, 0x8000);
-
+++ /dev/null
-From 3a767b482cacd9bfeac786837fcac419af315995 Mon Sep 17 00:00:00 2001
-Date: Thu, 23 Nov 2023 10:53:26 +0100
-Subject: [PATCH] r8169: remove not needed check in rtl_fw_write_firmware
-
-This check can never be true for a firmware file with a correct format.
-Existing checks in rtl_fw_data_ok() are sufficient, no problems with
-invalid firmware files are known.
-
----
- drivers/net/ethernet/realtek/r8169_firmware.c | 3 ---
- 1 file changed, 3 deletions(-)
-
---- a/drivers/net/ethernet/realtek/r8169_firmware.c
-+++ b/drivers/net/ethernet/realtek/r8169_firmware.c
-@@ -151,9 +151,6 @@ void rtl_fw_write_firmware(struct rtl816
- u32 regno = (action & 0x0fff0000) >> 16;
- enum rtl_fw_opcode opcode = action >> 28;
-
-- if (!action)
-- break;
--
- switch (opcode) {
- case PHY_READ:
- predata = fw_read(tp, regno);
+++ /dev/null
-From cd04b44bf055c4cd6bcee2ebfa6932fb20ef369d Mon Sep 17 00:00:00 2001
-Date: Mon, 27 Nov 2023 21:16:10 +0100
-Subject: [PATCH] r8169: remove multicast filter limit
-
-Once upon a time, when r8169 was new, the multicast filter limit code
-was copied from RTL8139 driver. There the filter limit is even
-user-configurable.
-The filtering is hash-based and we don't have perfect filtering.
-Actually the mc filtering on RTL8125 still seems to be the same
-as used on 8390/NE2000. So it's not clear to me which benefit it
-should bring when switching to all-multi mode once a certain number
-of filter bits is set. More the opposite: Filtering out at least
-some unwanted mc traffic is better than no filtering.
-Also the available chip documentation doesn't mention any restriction.
-Therefore remove the filter limit.
-
----
- drivers/net/ethernet/realtek/r8169_main.c | 7 +------
- 1 file changed, 1 insertion(+), 6 deletions(-)
-
---- a/drivers/net/ethernet/realtek/r8169_main.c
-+++ b/drivers/net/ethernet/realtek/r8169_main.c
-@@ -56,10 +56,6 @@
- #define FIRMWARE_8125A_3 "rtl_nic/rtl8125a-3.fw"
- #define FIRMWARE_8125B_2 "rtl_nic/rtl8125b-2.fw"
-
--/* Maximum number of multicast addresses to filter (vs. Rx-all-multicast).
-- The RTL chips use a 64 element hash table based on the Ethernet CRC. */
--#define MC_FILTER_LIMIT 32
--
- #define TX_DMA_BURST 7 /* Maximum PCI burst, '7' is unlimited */
- #define InterFrameGap 0x03 /* 3 means InterFrameGap = the shortest one */
-
-@@ -2653,8 +2649,7 @@ static void rtl_set_rx_mode(struct net_d
- rx_mode |= AcceptAllPhys;
- } else if (!(dev->flags & IFF_MULTICAST)) {
- rx_mode &= ~AcceptMulticast;
-- } else if (netdev_mc_count(dev) > MC_FILTER_LIMIT ||
-- dev->flags & IFF_ALLMULTI ||
-+ } else if (dev->flags & IFF_ALLMULTI ||
- tp->mac_version == RTL_GIGA_MAC_VER_35) {
- /* accept all multicasts */
- } else if (netdev_mc_empty(dev)) {
+++ /dev/null
-From 127532cd0f060ebc3c4cbca81b6438728ad5896e Mon Sep 17 00:00:00 2001
-Date: Mon, 27 Nov 2023 18:20:11 +0100
-Subject: [PATCH] r8169: improve handling task scheduling
-
-If we know that the task is going to be a no-op, don't even schedule it.
-And remove the check for netif_running() in the worker function, the
-check for flag RTL_FLAG_TASK_ENABLED is sufficient. Note that we can't
-remove the check for flag RTL_FLAG_TASK_ENABLED in the worker function
-because we have no guarantee when it will be executed.
-
----
- drivers/net/ethernet/realtek/r8169_main.c | 6 ++++--
- 1 file changed, 4 insertions(+), 2 deletions(-)
-
---- a/drivers/net/ethernet/realtek/r8169_main.c
-+++ b/drivers/net/ethernet/realtek/r8169_main.c
-@@ -2279,6 +2279,9 @@ u16 rtl8168h_2_get_adc_bias_ioffset(stru
-
- static void rtl_schedule_task(struct rtl8169_private *tp, enum rtl_flag flag)
- {
-+ if (!test_bit(RTL_FLAG_TASK_ENABLED, tp->wk.flags))
-+ return;
-+
- set_bit(flag, tp->wk.flags);
- schedule_work(&tp->wk.work);
- }
-@@ -4526,8 +4529,7 @@ static void rtl_task(struct work_struct
-
- rtnl_lock();
-
-- if (!netif_running(tp->dev) ||
-- !test_bit(RTL_FLAG_TASK_ENABLED, tp->wk.flags))
-+ if (!test_bit(RTL_FLAG_TASK_ENABLED, tp->wk.flags))
- goto out_unlock;
-
- if (test_and_clear_bit(RTL_FLAG_TASK_TX_TIMEOUT, tp->wk.flags)) {
+++ /dev/null
-From 18764b883e157e28126b54e7d4ba9dd487d5bf54 Mon Sep 17 00:00:00 2001
-Date: Sat, 16 Dec 2023 20:58:10 +0100
-Subject: [PATCH] r8169: add support for LED's on RTL8168/RTL8101
-
-This adds support for the LED's on most chip versions. Excluded are
-the old non-PCIe versions and RTL8125. RTL8125 has a different LED
-register layout, support for it will follow later.
-
-LED's can be controlled from userspace using the netdev LED trigger.
-
-Tested on RTL8168h.
-
-Note: The driver can't know which LED's are actually physically
-wired. Therefore not every LED device may represent a physically
-available LED.
-
----
- drivers/net/ethernet/realtek/Makefile | 3 +
- drivers/net/ethernet/realtek/r8169.h | 7 +
- drivers/net/ethernet/realtek/r8169_leds.c | 157 ++++++++++++++++++++++
- drivers/net/ethernet/realtek/r8169_main.c | 65 +++++++++
- 4 files changed, 232 insertions(+)
- create mode 100644 drivers/net/ethernet/realtek/r8169_leds.c
-
---- a/drivers/net/ethernet/realtek/Makefile
-+++ b/drivers/net/ethernet/realtek/Makefile
-@@ -7,4 +7,7 @@ obj-$(CONFIG_8139CP) += 8139cp.o
- obj-$(CONFIG_8139TOO) += 8139too.o
- obj-$(CONFIG_ATP) += atp.o
- r8169-objs += r8169_main.o r8169_firmware.o r8169_phy_config.o
-+ifdef CONFIG_LEDS_TRIGGER_NETDEV
-+r8169-objs += r8169_leds.o
-+endif
- obj-$(CONFIG_R8169) += r8169.o
---- a/drivers/net/ethernet/realtek/r8169.h
-+++ b/drivers/net/ethernet/realtek/r8169.h
-@@ -8,6 +8,7 @@
- * See MAINTAINERS file for support contact information.
- */
-
-+#include <linux/netdevice.h>
- #include <linux/types.h>
- #include <linux/phy.h>
-
-@@ -77,3 +78,9 @@ u16 rtl8168h_2_get_adc_bias_ioffset(stru
- u8 rtl8168d_efuse_read(struct rtl8169_private *tp, int reg_addr);
- void r8169_hw_phy_config(struct rtl8169_private *tp, struct phy_device *phydev,
- enum mac_version ver);
-+
-+void r8169_get_led_name(struct rtl8169_private *tp, int idx,
-+ char *buf, int buf_len);
-+int rtl8168_get_led_mode(struct rtl8169_private *tp);
-+int rtl8168_led_mod_ctrl(struct rtl8169_private *tp, u16 mask, u16 val);
-+void rtl8168_init_leds(struct net_device *ndev);
---- /dev/null
-+++ b/drivers/net/ethernet/realtek/r8169_leds.c
-@@ -0,0 +1,157 @@
-+// SPDX-License-Identifier: GPL-2.0-only
-+/* r8169_leds.c: Realtek 8169/8168/8101/8125 ethernet driver.
-+ *
-+ *
-+ * See MAINTAINERS file for support contact information.
-+ */
-+
-+#include <linux/leds.h>
-+#include <linux/netdevice.h>
-+#include <uapi/linux/uleds.h>
-+
-+#include "r8169.h"
-+
-+#define RTL8168_LED_CTRL_OPTION2 BIT(15)
-+#define RTL8168_LED_CTRL_ACT BIT(3)
-+#define RTL8168_LED_CTRL_LINK_1000 BIT(2)
-+#define RTL8168_LED_CTRL_LINK_100 BIT(1)
-+#define RTL8168_LED_CTRL_LINK_10 BIT(0)
-+
-+#define RTL8168_NUM_LEDS 3
-+
-+#define RTL8168_SUPPORTED_MODES \
-+ (BIT(TRIGGER_NETDEV_LINK_1000) | BIT(TRIGGER_NETDEV_LINK_100) | \
-+ BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_RX) | \
-+ BIT(TRIGGER_NETDEV_TX))
-+
-+struct r8169_led_classdev {
-+ struct led_classdev led;
-+ struct net_device *ndev;
-+ int index;
-+};
-+
-+#define lcdev_to_r8169_ldev(lcdev) container_of(lcdev, struct r8169_led_classdev, led)
-+
-+static int rtl8168_led_hw_control_is_supported(struct led_classdev *led_cdev,
-+ unsigned long flags)
-+{
-+ struct r8169_led_classdev *ldev = lcdev_to_r8169_ldev(led_cdev);
-+ struct rtl8169_private *tp = netdev_priv(ldev->ndev);
-+ int shift = ldev->index * 4;
-+ bool rx, tx;
-+
-+ if (flags & ~RTL8168_SUPPORTED_MODES)
-+ goto nosupp;
-+
-+ rx = flags & BIT(TRIGGER_NETDEV_RX);
-+ tx = flags & BIT(TRIGGER_NETDEV_TX);
-+ if (rx != tx)
-+ goto nosupp;
-+
-+ return 0;
-+
-+nosupp:
-+ /* Switch LED off to indicate that mode isn't supported */
-+ rtl8168_led_mod_ctrl(tp, 0x000f << shift, 0);
-+ return -EOPNOTSUPP;
-+}
-+
-+static int rtl8168_led_hw_control_set(struct led_classdev *led_cdev,
-+ unsigned long flags)
-+{
-+ struct r8169_led_classdev *ldev = lcdev_to_r8169_ldev(led_cdev);
-+ struct rtl8169_private *tp = netdev_priv(ldev->ndev);
-+ int shift = ldev->index * 4;
-+ u16 mode = 0;
-+
-+ if (flags & BIT(TRIGGER_NETDEV_LINK_10))
-+ mode |= RTL8168_LED_CTRL_LINK_10;
-+ if (flags & BIT(TRIGGER_NETDEV_LINK_100))
-+ mode |= RTL8168_LED_CTRL_LINK_100;
-+ if (flags & BIT(TRIGGER_NETDEV_LINK_1000))
-+ mode |= RTL8168_LED_CTRL_LINK_1000;
-+ if (flags & BIT(TRIGGER_NETDEV_TX))
-+ mode |= RTL8168_LED_CTRL_ACT;
-+
-+ return rtl8168_led_mod_ctrl(tp, 0x000f << shift, mode << shift);
-+}
-+
-+static int rtl8168_led_hw_control_get(struct led_classdev *led_cdev,
-+ unsigned long *flags)
-+{
-+ struct r8169_led_classdev *ldev = lcdev_to_r8169_ldev(led_cdev);
-+ struct rtl8169_private *tp = netdev_priv(ldev->ndev);
-+ int shift = ldev->index * 4;
-+ int mode;
-+
-+ mode = rtl8168_get_led_mode(tp);
-+ if (mode < 0)
-+ return mode;
-+
-+ if (mode & RTL8168_LED_CTRL_OPTION2) {
-+ rtl8168_led_mod_ctrl(tp, RTL8168_LED_CTRL_OPTION2, 0);
-+ netdev_notice(ldev->ndev, "Deactivating unsupported Option2 LED mode\n");
-+ }
-+
-+ mode = (mode >> shift) & 0x000f;
-+
-+ if (mode & RTL8168_LED_CTRL_ACT)
-+ *flags |= BIT(TRIGGER_NETDEV_TX) | BIT(TRIGGER_NETDEV_RX);
-+
-+ if (mode & RTL8168_LED_CTRL_LINK_10)
-+ *flags |= BIT(TRIGGER_NETDEV_LINK_10);
-+ if (mode & RTL8168_LED_CTRL_LINK_100)
-+ *flags |= BIT(TRIGGER_NETDEV_LINK_100);
-+ if (mode & RTL8168_LED_CTRL_LINK_1000)
-+ *flags |= BIT(TRIGGER_NETDEV_LINK_1000);
-+
-+ return 0;
-+}
-+
-+static struct device *
-+ r8169_led_hw_control_get_device(struct led_classdev *led_cdev)
-+{
-+ struct r8169_led_classdev *ldev = lcdev_to_r8169_ldev(led_cdev);
-+
-+ return &ldev->ndev->dev;
-+}
-+
-+static void rtl8168_setup_ldev(struct r8169_led_classdev *ldev,
-+ struct net_device *ndev, int index)
-+{
-+ struct rtl8169_private *tp = netdev_priv(ndev);
-+ struct led_classdev *led_cdev = &ldev->led;
-+ char led_name[LED_MAX_NAME_SIZE];
-+
-+ ldev->ndev = ndev;
-+ ldev->index = index;
-+
-+ r8169_get_led_name(tp, index, led_name, LED_MAX_NAME_SIZE);
-+ led_cdev->name = led_name;
-+ led_cdev->default_trigger = "netdev";
-+ led_cdev->hw_control_trigger = "netdev";
-+ led_cdev->flags |= LED_RETAIN_AT_SHUTDOWN;
-+ led_cdev->hw_control_is_supported = rtl8168_led_hw_control_is_supported;
-+ led_cdev->hw_control_set = rtl8168_led_hw_control_set;
-+ led_cdev->hw_control_get = rtl8168_led_hw_control_get;
-+ led_cdev->hw_control_get_device = r8169_led_hw_control_get_device;
-+
-+ /* ignore errors */
-+ devm_led_classdev_register(&ndev->dev, led_cdev);
-+}
-+
-+void rtl8168_init_leds(struct net_device *ndev)
-+{
-+ /* bind resource mgmt to netdev */
-+ struct device *dev = &ndev->dev;
-+ struct r8169_led_classdev *leds;
-+ int i;
-+
-+ leds = devm_kcalloc(dev, RTL8168_NUM_LEDS, sizeof(*leds), GFP_KERNEL);
-+ if (!leds)
-+ return;
-+
-+ for (i = 0; i < RTL8168_NUM_LEDS; i++)
-+ rtl8168_setup_ldev(leds + i, ndev, i);
-+}
---- a/drivers/net/ethernet/realtek/r8169_main.c
-+++ b/drivers/net/ethernet/realtek/r8169_main.c
-@@ -285,6 +285,7 @@ enum rtl8168_8101_registers {
- };
-
- enum rtl8168_registers {
-+ LED_CTRL = 0x18,
- LED_FREQ = 0x1a,
- EEE_LED = 0x1b,
- ERIDR = 0x70,
-@@ -643,6 +644,7 @@ struct rtl8169_private {
-
- raw_spinlock_t config25_lock;
- raw_spinlock_t mac_ocp_lock;
-+ struct mutex led_lock; /* serialize LED ctrl RMW access */
-
- raw_spinlock_t cfg9346_usage_lock;
- int cfg9346_usage_count;
-@@ -815,6 +817,62 @@ static const struct rtl_cond name = {
- \
- static bool name ## _check(struct rtl8169_private *tp)
-
-+int rtl8168_led_mod_ctrl(struct rtl8169_private *tp, u16 mask, u16 val)
-+{
-+ struct device *dev = tp_to_dev(tp);
-+ int ret;
-+
-+ ret = pm_runtime_resume_and_get(dev);
-+ if (ret < 0)
-+ return ret;
-+
-+ mutex_lock(&tp->led_lock);
-+ RTL_W16(tp, LED_CTRL, (RTL_R16(tp, LED_CTRL) & ~mask) | val);
-+ mutex_unlock(&tp->led_lock);
-+
-+ pm_runtime_put_sync(dev);
-+
-+ return 0;
-+}
-+
-+int rtl8168_get_led_mode(struct rtl8169_private *tp)
-+{
-+ struct device *dev = tp_to_dev(tp);
-+ int ret;
-+
-+ ret = pm_runtime_resume_and_get(dev);
-+ if (ret < 0)
-+ return ret;
-+
-+ ret = RTL_R16(tp, LED_CTRL);
-+
-+ pm_runtime_put_sync(dev);
-+
-+ return ret;
-+}
-+
-+void r8169_get_led_name(struct rtl8169_private *tp, int idx,
-+ char *buf, int buf_len)
-+{
-+ struct pci_dev *pdev = tp->pci_dev;
-+ char pdom[8], pfun[8];
-+ int domain;
-+
-+ domain = pci_domain_nr(pdev->bus);
-+ if (domain)
-+ snprintf(pdom, sizeof(pdom), "P%d", domain);
-+ else
-+ pdom[0] = '\0';
-+
-+ if (pdev->multifunction)
-+ snprintf(pfun, sizeof(pfun), "f%d", PCI_FUNC(pdev->devfn));
-+ else
-+ pfun[0] = '\0';
-+
-+ snprintf(buf, buf_len, "en%sp%ds%d%s-%d::lan", pdom, pdev->bus->number,
-+ PCI_SLOT(pdev->devfn), pfun, idx);
-+}
-+
- static void r8168fp_adjust_ocp_cmd(struct rtl8169_private *tp, u32 *cmd, int type)
- {
- /* based on RTL8168FP_OOBMAC_BASE in vendor driver */
-@@ -5205,6 +5263,7 @@ static int rtl_init_one(struct pci_dev *
- raw_spin_lock_init(&tp->cfg9346_usage_lock);
- raw_spin_lock_init(&tp->config25_lock);
- raw_spin_lock_init(&tp->mac_ocp_lock);
-+ mutex_init(&tp->led_lock);
-
- dev->tstats = devm_netdev_alloc_pcpu_stats(&pdev->dev,
- struct pcpu_sw_netstats);
-@@ -5361,6 +5420,12 @@ static int rtl_init_one(struct pci_dev *
- if (rc)
- return rc;
-
-+#if IS_REACHABLE(CONFIG_LEDS_CLASS) && IS_ENABLED(CONFIG_LEDS_TRIGGER_NETDEV)
-+ if (tp->mac_version > RTL_GIGA_MAC_VER_06 &&
-+ tp->mac_version < RTL_GIGA_MAC_VER_61)
-+ rtl8168_init_leds(dev);
-+#endif
-+
- netdev_info(dev, "%s, %pM, XID %03x, IRQ %d\n",
- rtl_chip_infos[chipset].name, dev->dev_addr, xid, tp->irq);
-
+++ /dev/null
-From a2634a5ffcafc31c343c6153ae487eb184c433a6 Mon Sep 17 00:00:00 2001
-Date: Wed, 3 Jan 2024 16:52:04 +0100
-Subject: [PATCH] r8169: fix building with CONFIG_LEDS_CLASS=m
-
-When r8169 is built-in but LED support is a loadable module, the new
-code to drive the LED causes a link failure:
-
-ld: drivers/net/ethernet/realtek/r8169_leds.o: in function `rtl8168_init_leds':
-r8169_leds.c:(.text+0x36c): undefined reference to `devm_led_classdev_register_ext'
-
-LED support is an optional feature, so fix this issue by adding a Kconfig
-symbol R8169_LEDS that is guaranteed to be false if r8169 is built-in
-and LED core support is a module. As a positive side effect of this change
-r8169_leds.o no longer is built under this configuration.
-
-Fixes: 18764b883e15 ("r8169: add support for LED's on RTL8168/RTL8101")
----
- drivers/net/ethernet/realtek/Kconfig | 7 +++++++
- drivers/net/ethernet/realtek/Makefile | 6 ++----
- drivers/net/ethernet/realtek/r8169_main.c | 5 ++---
- 3 files changed, 11 insertions(+), 7 deletions(-)
-
---- a/drivers/net/ethernet/realtek/Kconfig
-+++ b/drivers/net/ethernet/realtek/Kconfig
-@@ -113,4 +113,11 @@ config R8169
- To compile this driver as a module, choose M here: the module
- will be called r8169. This is recommended.
-
-+config R8169_LEDS
-+ def_bool R8169 && LEDS_TRIGGER_NETDEV
-+ depends on !(R8169=y && LEDS_CLASS=m)
-+ help
-+ Optional support for controlling the NIC LED's with the netdev
-+ LED trigger.
-+
- endif # NET_VENDOR_REALTEK
---- a/drivers/net/ethernet/realtek/Makefile
-+++ b/drivers/net/ethernet/realtek/Makefile
-@@ -6,8 +6,6 @@
- obj-$(CONFIG_8139CP) += 8139cp.o
- obj-$(CONFIG_8139TOO) += 8139too.o
- obj-$(CONFIG_ATP) += atp.o
--r8169-objs += r8169_main.o r8169_firmware.o r8169_phy_config.o
--ifdef CONFIG_LEDS_TRIGGER_NETDEV
--r8169-objs += r8169_leds.o
--endif
-+r8169-y += r8169_main.o r8169_firmware.o r8169_phy_config.o
-+r8169-$(CONFIG_R8169_LEDS) += r8169_leds.o
- obj-$(CONFIG_R8169) += r8169.o
---- a/drivers/net/ethernet/realtek/r8169_main.c
-+++ b/drivers/net/ethernet/realtek/r8169_main.c
-@@ -5420,11 +5420,10 @@ static int rtl_init_one(struct pci_dev *
- if (rc)
- return rc;
-
--#if IS_REACHABLE(CONFIG_LEDS_CLASS) && IS_ENABLED(CONFIG_LEDS_TRIGGER_NETDEV)
-- if (tp->mac_version > RTL_GIGA_MAC_VER_06 &&
-+ if (IS_ENABLED(CONFIG_R8169_LEDS) &&
-+ tp->mac_version > RTL_GIGA_MAC_VER_06 &&
- tp->mac_version < RTL_GIGA_MAC_VER_61)
- rtl8168_init_leds(dev);
--#endif
-
- netdev_info(dev, "%s, %pM, XID %03x, IRQ %d\n",
- rtl_chip_infos[chipset].name, dev->dev_addr, xid, tp->irq);
+++ /dev/null
-From f5d59230ec26aa5e8b59e9f4a4d288703a737479 Mon Sep 17 00:00:00 2001
-Date: Wed, 31 Jan 2024 21:31:01 +0100
-Subject: [PATCH] r8169: simplify EEE handling
-
-We don't have to store the EEE modes to be advertised in the driver,
-phylib does this for us and stores it in phydev->advertising_eee.
-phylib also takes care of properly handling the EEE advertisement.
-
----
- drivers/net/ethernet/realtek/r8169_main.c | 32 +++--------------------
- 1 file changed, 4 insertions(+), 28 deletions(-)
-
---- a/drivers/net/ethernet/realtek/r8169_main.c
-+++ b/drivers/net/ethernet/realtek/r8169_main.c
-@@ -656,7 +656,6 @@ struct rtl8169_private {
- struct rtl8169_counters *counters;
- struct rtl8169_tc_offsets tc_offset;
- u32 saved_wolopts;
-- int eee_adv;
-
- const char *fw_name;
- struct rtl_fw *rtl_fw;
-@@ -2037,17 +2036,11 @@ static int rtl8169_get_eee(struct net_de
- static int rtl8169_set_eee(struct net_device *dev, struct ethtool_eee *data)
- {
- struct rtl8169_private *tp = netdev_priv(dev);
-- int ret;
-
- if (!rtl_supports_eee(tp))
- return -EOPNOTSUPP;
-
-- ret = phy_ethtool_set_eee(tp->phydev, data);
--
-- if (!ret)
-- tp->eee_adv = phy_read_mmd(dev->phydev, MDIO_MMD_AN,
-- MDIO_AN_EEE_ADV);
-- return ret;
-+ return phy_ethtool_set_eee(tp->phydev, data);
- }
-
- static void rtl8169_get_ringparam(struct net_device *dev,
-@@ -2112,21 +2105,6 @@ static const struct ethtool_ops rtl8169_
- .set_pauseparam = rtl8169_set_pauseparam,
- };
-
--static void rtl_enable_eee(struct rtl8169_private *tp)
--{
-- struct phy_device *phydev = tp->phydev;
-- int adv;
--
-- /* respect EEE advertisement the user may have set */
-- if (tp->eee_adv >= 0)
-- adv = tp->eee_adv;
-- else
-- adv = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_PCS_EEE_ABLE);
--
-- if (adv >= 0)
-- phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV, adv);
--}
--
- static enum mac_version rtl8169_get_mac_version(u16 xid, bool gmii)
- {
- /*
-@@ -2363,9 +2341,6 @@ static void rtl8169_init_phy(struct rtl8
- /* We may have called phy_speed_down before */
- phy_speed_up(tp->phydev);
-
-- if (rtl_supports_eee(tp))
-- rtl_enable_eee(tp);
--
- genphy_soft_reset(tp->phydev);
- }
-
-@@ -5122,7 +5097,9 @@ static int r8169_mdio_register(struct rt
- }
-
- tp->phydev->mac_managed_pm = true;
--
-+ if (rtl_supports_eee(tp))
-+ linkmode_copy(tp->phydev->advertising_eee,
-+ tp->phydev->supported_eee);
- phy_support_asym_pause(tp->phydev);
-
- /* PHY will be woken up in rtl_open() */
-@@ -5257,7 +5234,6 @@ static int rtl_init_one(struct pci_dev *
- tp->dev = dev;
- tp->pci_dev = pdev;
- tp->supports_gmii = ent->driver_data == RTL_CFG_NO_GBIT ? 0 : 1;
-- tp->eee_adv = -1;
- tp->ocp_base = OCP_STD_PHY_BASE;
-
- raw_spin_lock_init(&tp->cfg9346_usage_lock);
+++ /dev/null
-From 3907f1ffc0ecf466d5c04aadc44c4b9203f3ec9a Mon Sep 17 00:00:00 2001
-Date: Thu, 1 Feb 2024 22:38:01 +0100
-Subject: [PATCH] r8169: add support for RTL8126A
-
-This adds support for the RTL8126A found on Asus z790 Maximus Formula.
-It was successfully tested w/o the firmware at 1000Mbps. Firmware file
-has been provided by Realtek and submitted to linux-firmware.
-2.5G and 5G modes are untested.
-
----
- drivers/net/ethernet/realtek/r8169.h | 1 +
- drivers/net/ethernet/realtek/r8169_main.c | 105 ++++++++++++++----
- .../net/ethernet/realtek/r8169_phy_config.c | 7 ++
- 3 files changed, 89 insertions(+), 24 deletions(-)
-
---- a/drivers/net/ethernet/realtek/r8169.h
-+++ b/drivers/net/ethernet/realtek/r8169.h
-@@ -68,6 +68,7 @@ enum mac_version {
- /* support for RTL_GIGA_MAC_VER_60 has been removed */
- RTL_GIGA_MAC_VER_61,
- RTL_GIGA_MAC_VER_63,
-+ RTL_GIGA_MAC_VER_65,
- RTL_GIGA_MAC_NONE
- };
-
---- a/drivers/net/ethernet/realtek/r8169_main.c
-+++ b/drivers/net/ethernet/realtek/r8169_main.c
-@@ -55,6 +55,7 @@
- #define FIRMWARE_8107E_2 "rtl_nic/rtl8107e-2.fw"
- #define FIRMWARE_8125A_3 "rtl_nic/rtl8125a-3.fw"
- #define FIRMWARE_8125B_2 "rtl_nic/rtl8125b-2.fw"
-+#define FIRMWARE_8126A_2 "rtl_nic/rtl8126a-2.fw"
-
- #define TX_DMA_BURST 7 /* Maximum PCI burst, '7' is unlimited */
- #define InterFrameGap 0x03 /* 3 means InterFrameGap = the shortest one */
-@@ -136,6 +137,7 @@ static const struct {
- [RTL_GIGA_MAC_VER_61] = {"RTL8125A", FIRMWARE_8125A_3},
- /* reserve 62 for CFG_METHOD_4 in the vendor driver */
- [RTL_GIGA_MAC_VER_63] = {"RTL8125B", FIRMWARE_8125B_2},
-+ [RTL_GIGA_MAC_VER_65] = {"RTL8126A", FIRMWARE_8126A_2},
- };
-
- static const struct pci_device_id rtl8169_pci_tbl[] = {
-@@ -158,6 +160,7 @@ static const struct pci_device_id rtl816
- { PCI_VENDOR_ID_LINKSYS, 0x1032, PCI_ANY_ID, 0x0024 },
- { 0x0001, 0x8168, PCI_ANY_ID, 0x2410 },
- { PCI_VDEVICE(REALTEK, 0x8125) },
-+ { PCI_VDEVICE(REALTEK, 0x8126) },
- { PCI_VDEVICE(REALTEK, 0x3000) },
- {}
- };
-@@ -327,8 +330,12 @@ enum rtl8168_registers {
- };
-
- enum rtl8125_registers {
-+ INT_CFG0_8125 = 0x34,
-+#define INT_CFG0_ENABLE_8125 BIT(0)
-+#define INT_CFG0_CLKREQEN BIT(3)
- IntrMask_8125 = 0x38,
- IntrStatus_8125 = 0x3c,
-+ INT_CFG1_8125 = 0x7a,
- TxPoll_8125 = 0x90,
- MAC0_BKP = 0x19e0,
- EEE_TXIDLE_TIMER_8125 = 0x6048,
-@@ -1166,7 +1173,7 @@ static void rtl_writephy(struct rtl8169_
- case RTL_GIGA_MAC_VER_31:
- r8168dp_2_mdio_write(tp, location, val);
- break;
-- case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_63:
-+ case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_65:
- r8168g_mdio_write(tp, location, val);
- break;
- default:
-@@ -1181,7 +1188,7 @@ static int rtl_readphy(struct rtl8169_pr
- case RTL_GIGA_MAC_VER_28:
- case RTL_GIGA_MAC_VER_31:
- return r8168dp_2_mdio_read(tp, location);
-- case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_63:
-+ case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_65:
- return r8168g_mdio_read(tp, location);
- default:
- return r8169_mdio_read(tp, location);
-@@ -1390,7 +1397,7 @@ static void rtl_set_d3_pll_down(struct r
- case RTL_GIGA_MAC_VER_25 ... RTL_GIGA_MAC_VER_26:
- case RTL_GIGA_MAC_VER_29 ... RTL_GIGA_MAC_VER_30:
- case RTL_GIGA_MAC_VER_32 ... RTL_GIGA_MAC_VER_37:
-- case RTL_GIGA_MAC_VER_39 ... RTL_GIGA_MAC_VER_63:
-+ case RTL_GIGA_MAC_VER_39 ... RTL_GIGA_MAC_VER_65:
- if (enable)
- RTL_W8(tp, PMCH, RTL_R8(tp, PMCH) & ~D3_NO_PLL_DOWN);
- else
-@@ -1557,7 +1564,7 @@ static void __rtl8169_set_wol(struct rtl
- break;
- case RTL_GIGA_MAC_VER_34:
- case RTL_GIGA_MAC_VER_37:
-- case RTL_GIGA_MAC_VER_39 ... RTL_GIGA_MAC_VER_63:
-+ case RTL_GIGA_MAC_VER_39 ... RTL_GIGA_MAC_VER_65:
- if (wolopts)
- rtl_mod_config2(tp, 0, PME_SIGNAL);
- else
-@@ -2123,6 +2130,9 @@ static enum mac_version rtl8169_get_mac_
- u16 val;
- enum mac_version ver;
- } mac_info[] = {
-+ /* 8126A family. */
-+ { 0x7cf, 0x649, RTL_GIGA_MAC_VER_65 },
-+
- /* 8125B family. */
- { 0x7cf, 0x641, RTL_GIGA_MAC_VER_63 },
-
-@@ -2393,6 +2403,7 @@ static void rtl_init_rxcfg(struct rtl816
- RTL_W32(tp, RxConfig, RX_FETCH_DFLT_8125 | RX_DMA_BURST);
- break;
- case RTL_GIGA_MAC_VER_63:
-+ case RTL_GIGA_MAC_VER_65:
- RTL_W32(tp, RxConfig, RX_FETCH_DFLT_8125 | RX_DMA_BURST |
- RX_PAUSE_SLOT_ON);
- break;
-@@ -2579,7 +2590,7 @@ static void rtl_wait_txrx_fifo_empty(str
- case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_61:
- rtl_loop_wait_high(tp, &rtl_rxtx_empty_cond, 100, 42);
- break;
-- case RTL_GIGA_MAC_VER_63:
-+ case RTL_GIGA_MAC_VER_63 ... RTL_GIGA_MAC_VER_65:
- RTL_W8(tp, ChipCmd, RTL_R8(tp, ChipCmd) | StopReq);
- rtl_loop_wait_high(tp, &rtl_rxtx_empty_cond, 100, 42);
- rtl_loop_wait_high(tp, &rtl_rxtx_empty_cond_2, 100, 42);
-@@ -2822,7 +2833,7 @@ static void rtl_enable_exit_l1(struct rt
- case RTL_GIGA_MAC_VER_37 ... RTL_GIGA_MAC_VER_38:
- rtl_eri_set_bits(tp, 0xd4, 0x0c00);
- break;
-- case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_63:
-+ case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_65:
- r8168_mac_ocp_modify(tp, 0xc0ac, 0, 0x1f80);
- break;
- default:
-@@ -2836,7 +2847,7 @@ static void rtl_disable_exit_l1(struct r
- case RTL_GIGA_MAC_VER_34 ... RTL_GIGA_MAC_VER_38:
- rtl_eri_clear_bits(tp, 0xd4, 0x1f00);
- break;
-- case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_63:
-+ case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_65:
- r8168_mac_ocp_modify(tp, 0xc0ac, 0x1f80, 0);
- break;
- default:
-@@ -2846,6 +2857,8 @@ static void rtl_disable_exit_l1(struct r
-
- static void rtl_hw_aspm_clkreq_enable(struct rtl8169_private *tp, bool enable)
- {
-+ u8 val8;
-+
- if (tp->mac_version < RTL_GIGA_MAC_VER_32)
- return;
-
-@@ -2859,11 +2872,19 @@ static void rtl_hw_aspm_clkreq_enable(st
- return;
-
- rtl_mod_config5(tp, 0, ASPM_en);
-- rtl_mod_config2(tp, 0, ClkReqEn);
-+ switch (tp->mac_version) {
-+ case RTL_GIGA_MAC_VER_65:
-+ val8 = RTL_R8(tp, INT_CFG0_8125) | INT_CFG0_CLKREQEN;
-+ RTL_W8(tp, INT_CFG0_8125, val8);
-+ break;
-+ default:
-+ rtl_mod_config2(tp, 0, ClkReqEn);
-+ break;
-+ }
-
- switch (tp->mac_version) {
- case RTL_GIGA_MAC_VER_46 ... RTL_GIGA_MAC_VER_48:
-- case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_63:
-+ case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_65:
- /* reset ephy tx/rx disable timer */
- r8168_mac_ocp_modify(tp, 0xe094, 0xff00, 0);
- /* chip can trigger L1.2 */
-@@ -2875,14 +2896,22 @@ static void rtl_hw_aspm_clkreq_enable(st
- } else {
- switch (tp->mac_version) {
- case RTL_GIGA_MAC_VER_46 ... RTL_GIGA_MAC_VER_48:
-- case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_63:
-+ case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_65:
- r8168_mac_ocp_modify(tp, 0xe092, 0x00ff, 0);
- break;
- default:
- break;
- }
-
-- rtl_mod_config2(tp, ClkReqEn, 0);
-+ switch (tp->mac_version) {
-+ case RTL_GIGA_MAC_VER_65:
-+ val8 = RTL_R8(tp, INT_CFG0_8125) & ~INT_CFG0_CLKREQEN;
-+ RTL_W8(tp, INT_CFG0_8125, val8);
-+ break;
-+ default:
-+ rtl_mod_config2(tp, ClkReqEn, 0);
-+ break;
-+ }
- rtl_mod_config5(tp, ASPM_en, 0);
- }
- }
-@@ -3595,10 +3624,15 @@ static void rtl_hw_start_8125_common(str
- /* disable new tx descriptor format */
- r8168_mac_ocp_modify(tp, 0xeb58, 0x0001, 0x0000);
-
-- if (tp->mac_version == RTL_GIGA_MAC_VER_63)
-+ if (tp->mac_version == RTL_GIGA_MAC_VER_65)
-+ RTL_W8(tp, 0xD8, RTL_R8(tp, 0xD8) & ~0x02);
-+
-+ if (tp->mac_version == RTL_GIGA_MAC_VER_65)
-+ r8168_mac_ocp_modify(tp, 0xe614, 0x0700, 0x0400);
-+ else if (tp->mac_version == RTL_GIGA_MAC_VER_63)
- r8168_mac_ocp_modify(tp, 0xe614, 0x0700, 0x0200);
- else
-- r8168_mac_ocp_modify(tp, 0xe614, 0x0700, 0x0400);
-+ r8168_mac_ocp_modify(tp, 0xe614, 0x0700, 0x0300);
-
- if (tp->mac_version == RTL_GIGA_MAC_VER_63)
- r8168_mac_ocp_modify(tp, 0xe63e, 0x0c30, 0x0000);
-@@ -3611,6 +3645,10 @@ static void rtl_hw_start_8125_common(str
- r8168_mac_ocp_modify(tp, 0xe056, 0x00f0, 0x0000);
- r8168_mac_ocp_modify(tp, 0xe040, 0x1000, 0x0000);
- r8168_mac_ocp_modify(tp, 0xea1c, 0x0003, 0x0001);
-+ if (tp->mac_version == RTL_GIGA_MAC_VER_65)
-+ r8168_mac_ocp_modify(tp, 0xea1c, 0x0300, 0x0000);
-+ else
-+ r8168_mac_ocp_modify(tp, 0xea1c, 0x0004, 0x0000);
- r8168_mac_ocp_modify(tp, 0xe0c0, 0x4f0f, 0x4403);
- r8168_mac_ocp_modify(tp, 0xe052, 0x0080, 0x0068);
- r8168_mac_ocp_modify(tp, 0xd430, 0x0fff, 0x047f);
-@@ -3625,10 +3663,10 @@ static void rtl_hw_start_8125_common(str
-
- rtl_loop_wait_low(tp, &rtl_mac_ocp_e00e_cond, 1000, 10);
-
-- if (tp->mac_version == RTL_GIGA_MAC_VER_63)
-- rtl8125b_config_eee_mac(tp);
-- else
-+ if (tp->mac_version == RTL_GIGA_MAC_VER_61)
- rtl8125a_config_eee_mac(tp);
-+ else
-+ rtl8125b_config_eee_mac(tp);
-
- rtl_disable_rxdvgate(tp);
- }
-@@ -3672,6 +3710,12 @@ static void rtl_hw_start_8125b(struct rt
- rtl_hw_start_8125_common(tp);
- }
-
-+static void rtl_hw_start_8126a(struct rtl8169_private *tp)
-+{
-+ rtl_set_def_aspm_entry_latency(tp);
-+ rtl_hw_start_8125_common(tp);
-+}
-+
- static void rtl_hw_config(struct rtl8169_private *tp)
- {
- static const rtl_generic_fct hw_configs[] = {
-@@ -3714,6 +3758,7 @@ static void rtl_hw_config(struct rtl8169
- [RTL_GIGA_MAC_VER_53] = rtl_hw_start_8117,
- [RTL_GIGA_MAC_VER_61] = rtl_hw_start_8125a_2,
- [RTL_GIGA_MAC_VER_63] = rtl_hw_start_8125b,
-+ [RTL_GIGA_MAC_VER_65] = rtl_hw_start_8126a,
- };
-
- if (hw_configs[tp->mac_version])
-@@ -3724,9 +3769,23 @@ static void rtl_hw_start_8125(struct rtl
- {
- int i;
-
-+ RTL_W8(tp, INT_CFG0_8125, 0x00);
-+
- /* disable interrupt coalescing */
-- for (i = 0xa00; i < 0xb00; i += 4)
-- RTL_W32(tp, i, 0);
-+ switch (tp->mac_version) {
-+ case RTL_GIGA_MAC_VER_61:
-+ for (i = 0xa00; i < 0xb00; i += 4)
-+ RTL_W32(tp, i, 0);
-+ break;
-+ case RTL_GIGA_MAC_VER_63:
-+ case RTL_GIGA_MAC_VER_65:
-+ for (i = 0xa00; i < 0xa80; i += 4)
-+ RTL_W32(tp, i, 0);
-+ RTL_W16(tp, INT_CFG1_8125, 0x0000);
-+ break;
-+ default:
-+ break;
-+ }
-
- rtl_hw_config(tp);
- }
-@@ -3804,8 +3863,7 @@ static int rtl8169_change_mtu(struct net
- rtl_jumbo_config(tp);
-
- switch (tp->mac_version) {
-- case RTL_GIGA_MAC_VER_61:
-- case RTL_GIGA_MAC_VER_63:
-+ case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_65:
- rtl8125_set_eee_txidle_timer(tp);
- break;
- default:
-@@ -3954,7 +4012,7 @@ static void rtl8169_cleanup(struct rtl81
- RTL_W8(tp, ChipCmd, RTL_R8(tp, ChipCmd) | StopReq);
- rtl_loop_wait_high(tp, &rtl_txcfg_empty_cond, 100, 666);
- break;
-- case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_63:
-+ case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_65:
- rtl_enable_rxdvgate(tp);
- fsleep(2000);
- break;
-@@ -4111,8 +4169,7 @@ static unsigned int rtl_quirk_packet_pad
-
- switch (tp->mac_version) {
- case RTL_GIGA_MAC_VER_34:
-- case RTL_GIGA_MAC_VER_61:
-- case RTL_GIGA_MAC_VER_63:
-+ case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_65:
- padto = max_t(unsigned int, padto, ETH_ZLEN);
- break;
- default:
-@@ -5149,7 +5206,7 @@ static void rtl_hw_initialize(struct rtl
- case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_48:
- rtl_hw_init_8168g(tp);
- break;
-- case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_63:
-+ case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_65:
- rtl_hw_init_8125(tp);
- break;
- default:
---- a/drivers/net/ethernet/realtek/r8169_phy_config.c
-+++ b/drivers/net/ethernet/realtek/r8169_phy_config.c
-@@ -1104,6 +1104,12 @@ static void rtl8125b_hw_phy_config(struc
- rtl8125b_config_eee_phy(phydev);
- }
-
-+static void rtl8126a_hw_phy_config(struct rtl8169_private *tp,
-+ struct phy_device *phydev)
-+{
-+ r8169_apply_firmware(tp);
-+}
-+
- void r8169_hw_phy_config(struct rtl8169_private *tp, struct phy_device *phydev,
- enum mac_version ver)
- {
-@@ -1154,6 +1160,7 @@ void r8169_hw_phy_config(struct rtl8169_
- [RTL_GIGA_MAC_VER_53] = rtl8117_hw_phy_config,
- [RTL_GIGA_MAC_VER_61] = rtl8125a_2_hw_phy_config,
- [RTL_GIGA_MAC_VER_63] = rtl8125b_hw_phy_config,
-+ [RTL_GIGA_MAC_VER_65] = rtl8126a_hw_phy_config,
- };
-
- if (phy_configs[ver])
+++ /dev/null
-From 4c49b6824a607af4760fac4f5c0b9954ab902cef Mon Sep 17 00:00:00 2001
-Date: Wed, 7 Feb 2024 08:16:40 +0100
-Subject: [PATCH] r8169: improve checking for valid LED modes
-
-After 3a2746320403 ("leds: trigger: netdev: Display only supported link
-speed attribute") the check for valid link modes can be simplified.
-In addition factor it out, so that it can be re-used by the upcoming
-LED support for RTL8125.
-
----
- drivers/net/ethernet/realtek/r8169_leds.c | 38 ++++++++++++-----------
- 1 file changed, 20 insertions(+), 18 deletions(-)
-
---- a/drivers/net/ethernet/realtek/r8169_leds.c
-+++ b/drivers/net/ethernet/realtek/r8169_leds.c
-@@ -20,11 +20,6 @@
-
- #define RTL8168_NUM_LEDS 3
-
--#define RTL8168_SUPPORTED_MODES \
-- (BIT(TRIGGER_NETDEV_LINK_1000) | BIT(TRIGGER_NETDEV_LINK_100) | \
-- BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_RX) | \
-- BIT(TRIGGER_NETDEV_TX))
--
- struct r8169_led_classdev {
- struct led_classdev led;
- struct net_device *ndev;
-@@ -33,28 +28,35 @@ struct r8169_led_classdev {
-
- #define lcdev_to_r8169_ldev(lcdev) container_of(lcdev, struct r8169_led_classdev, led)
-
-+static bool r8169_trigger_mode_is_valid(unsigned long flags)
-+{
-+ bool rx, tx;
-+
-+ if (flags & BIT(TRIGGER_NETDEV_HALF_DUPLEX))
-+ return false;
-+ if (flags & BIT(TRIGGER_NETDEV_FULL_DUPLEX))
-+ return false;
-+
-+ rx = flags & BIT(TRIGGER_NETDEV_RX);
-+ tx = flags & BIT(TRIGGER_NETDEV_TX);
-+
-+ return rx == tx;
-+}
-+
- static int rtl8168_led_hw_control_is_supported(struct led_classdev *led_cdev,
- unsigned long flags)
- {
- struct r8169_led_classdev *ldev = lcdev_to_r8169_ldev(led_cdev);
- struct rtl8169_private *tp = netdev_priv(ldev->ndev);
- int shift = ldev->index * 4;
-- bool rx, tx;
-
-- if (flags & ~RTL8168_SUPPORTED_MODES)
-- goto nosupp;
--
-- rx = flags & BIT(TRIGGER_NETDEV_RX);
-- tx = flags & BIT(TRIGGER_NETDEV_TX);
-- if (rx != tx)
-- goto nosupp;
-+ if (!r8169_trigger_mode_is_valid(flags)) {
-+ /* Switch LED off to indicate that mode isn't supported */
-+ rtl8168_led_mod_ctrl(tp, 0x000f << shift, 0);
-+ return -EOPNOTSUPP;
-+ }
-
- return 0;
--
--nosupp:
-- /* Switch LED off to indicate that mode isn't supported */
-- rtl8168_led_mod_ctrl(tp, 0x000f << shift, 0);
-- return -EOPNOTSUPP;
- }
-
- static int rtl8168_led_hw_control_set(struct led_classdev *led_cdev,
+++ /dev/null
-From 400909df6e6543cb5cce3db9bbcd413d59125327 Mon Sep 17 00:00:00 2001
-Date: Sat, 10 Feb 2024 17:58:29 +0100
-Subject: [PATCH] r8169: simplify code by using core-provided pcpu stats
- allocation
-
-Use core-provided pcpu stats allocation instead of open-coding it in
-the driver.
-
----
- drivers/net/ethernet/realtek/r8169_main.c | 7 ++-----
- 1 file changed, 2 insertions(+), 5 deletions(-)
-
---- a/drivers/net/ethernet/realtek/r8169_main.c
-+++ b/drivers/net/ethernet/realtek/r8169_main.c
-@@ -5298,11 +5298,6 @@ static int rtl_init_one(struct pci_dev *
- raw_spin_lock_init(&tp->mac_ocp_lock);
- mutex_init(&tp->led_lock);
-
-- dev->tstats = devm_netdev_alloc_pcpu_stats(&pdev->dev,
-- struct pcpu_sw_netstats);
-- if (!dev->tstats)
-- return -ENOMEM;
--
- /* Get the *optional* external "ether_clk" used on some boards */
- tp->clk = devm_clk_get_optional_enabled(&pdev->dev, "ether_clk");
- if (IS_ERR(tp->clk))
-@@ -5417,6 +5412,8 @@ static int rtl_init_one(struct pci_dev *
- dev->hw_features |= NETIF_F_RXALL;
- dev->hw_features |= NETIF_F_RXFCS;
-
-+ dev->pcpu_stat_type = NETDEV_PCPU_STAT_TSTATS;
-+
- netdev_sw_irq_coalesce_default_on(dev);
-
- /* configure chip for default features */
+++ /dev/null
-From be51ed104ba9929c741afb718ef7198dbcecef94 Mon Sep 17 00:00:00 2001
-Date: Mon, 12 Feb 2024 19:44:11 +0100
-Subject: [PATCH] r8169: add LED support for RTL8125/RTL8126
-
-This adds LED support for RTL8125/RTL8126.
-
-Note: Due to missing datasheets changing the 5Gbps link mode isn't
-supported for RTL8126.
-
----
- drivers/net/ethernet/realtek/r8169.h | 3 +
- drivers/net/ethernet/realtek/r8169_leds.c | 106 ++++++++++++++++++++++
- drivers/net/ethernet/realtek/r8169_main.c | 61 ++++++++++++-
- 3 files changed, 166 insertions(+), 4 deletions(-)
-
---- a/drivers/net/ethernet/realtek/r8169.h
-+++ b/drivers/net/ethernet/realtek/r8169.h
-@@ -85,3 +85,6 @@ void r8169_get_led_name(struct rtl8169_p
- int rtl8168_get_led_mode(struct rtl8169_private *tp);
- int rtl8168_led_mod_ctrl(struct rtl8169_private *tp, u16 mask, u16 val);
- void rtl8168_init_leds(struct net_device *ndev);
-+int rtl8125_get_led_mode(struct rtl8169_private *tp, int index);
-+int rtl8125_set_led_mode(struct rtl8169_private *tp, int index, u16 mode);
-+void rtl8125_init_leds(struct net_device *ndev);
---- a/drivers/net/ethernet/realtek/r8169_leds.c
-+++ b/drivers/net/ethernet/realtek/r8169_leds.c
-@@ -18,7 +18,14 @@
- #define RTL8168_LED_CTRL_LINK_100 BIT(1)
- #define RTL8168_LED_CTRL_LINK_10 BIT(0)
-
-+#define RTL8125_LED_CTRL_ACT BIT(9)
-+#define RTL8125_LED_CTRL_LINK_2500 BIT(5)
-+#define RTL8125_LED_CTRL_LINK_1000 BIT(3)
-+#define RTL8125_LED_CTRL_LINK_100 BIT(1)
-+#define RTL8125_LED_CTRL_LINK_10 BIT(0)
-+
- #define RTL8168_NUM_LEDS 3
-+#define RTL8125_NUM_LEDS 4
-
- struct r8169_led_classdev {
- struct led_classdev led;
-@@ -157,3 +164,102 @@ void rtl8168_init_leds(struct net_device
- for (i = 0; i < RTL8168_NUM_LEDS; i++)
- rtl8168_setup_ldev(leds + i, ndev, i);
- }
-+
-+static int rtl8125_led_hw_control_is_supported(struct led_classdev *led_cdev,
-+ unsigned long flags)
-+{
-+ struct r8169_led_classdev *ldev = lcdev_to_r8169_ldev(led_cdev);
-+ struct rtl8169_private *tp = netdev_priv(ldev->ndev);
-+
-+ if (!r8169_trigger_mode_is_valid(flags)) {
-+ /* Switch LED off to indicate that mode isn't supported */
-+ rtl8125_set_led_mode(tp, ldev->index, 0);
-+ return -EOPNOTSUPP;
-+ }
-+
-+ return 0;
-+}
-+
-+static int rtl8125_led_hw_control_set(struct led_classdev *led_cdev,
-+ unsigned long flags)
-+{
-+ struct r8169_led_classdev *ldev = lcdev_to_r8169_ldev(led_cdev);
-+ struct rtl8169_private *tp = netdev_priv(ldev->ndev);
-+ u16 mode = 0;
-+
-+ if (flags & BIT(TRIGGER_NETDEV_LINK_10))
-+ mode |= RTL8125_LED_CTRL_LINK_10;
-+ if (flags & BIT(TRIGGER_NETDEV_LINK_100))
-+ mode |= RTL8125_LED_CTRL_LINK_100;
-+ if (flags & BIT(TRIGGER_NETDEV_LINK_1000))
-+ mode |= RTL8125_LED_CTRL_LINK_1000;
-+ if (flags & BIT(TRIGGER_NETDEV_LINK_2500))
-+ mode |= RTL8125_LED_CTRL_LINK_2500;
-+ if (flags & (BIT(TRIGGER_NETDEV_TX) | BIT(TRIGGER_NETDEV_RX)))
-+ mode |= RTL8125_LED_CTRL_ACT;
-+
-+ return rtl8125_set_led_mode(tp, ldev->index, mode);
-+}
-+
-+static int rtl8125_led_hw_control_get(struct led_classdev *led_cdev,
-+ unsigned long *flags)
-+{
-+ struct r8169_led_classdev *ldev = lcdev_to_r8169_ldev(led_cdev);
-+ struct rtl8169_private *tp = netdev_priv(ldev->ndev);
-+ int mode;
-+
-+ mode = rtl8125_get_led_mode(tp, ldev->index);
-+ if (mode < 0)
-+ return mode;
-+
-+ if (mode & RTL8125_LED_CTRL_LINK_10)
-+ *flags |= BIT(TRIGGER_NETDEV_LINK_10);
-+ if (mode & RTL8125_LED_CTRL_LINK_100)
-+ *flags |= BIT(TRIGGER_NETDEV_LINK_100);
-+ if (mode & RTL8125_LED_CTRL_LINK_1000)
-+ *flags |= BIT(TRIGGER_NETDEV_LINK_1000);
-+ if (mode & RTL8125_LED_CTRL_LINK_2500)
-+ *flags |= BIT(TRIGGER_NETDEV_LINK_2500);
-+ if (mode & RTL8125_LED_CTRL_ACT)
-+ *flags |= BIT(TRIGGER_NETDEV_TX) | BIT(TRIGGER_NETDEV_RX);
-+
-+ return 0;
-+}
-+
-+static void rtl8125_setup_led_ldev(struct r8169_led_classdev *ldev,
-+ struct net_device *ndev, int index)
-+{
-+ struct rtl8169_private *tp = netdev_priv(ndev);
-+ struct led_classdev *led_cdev = &ldev->led;
-+ char led_name[LED_MAX_NAME_SIZE];
-+
-+ ldev->ndev = ndev;
-+ ldev->index = index;
-+
-+ r8169_get_led_name(tp, index, led_name, LED_MAX_NAME_SIZE);
-+ led_cdev->name = led_name;
-+ led_cdev->hw_control_trigger = "netdev";
-+ led_cdev->flags |= LED_RETAIN_AT_SHUTDOWN;
-+ led_cdev->hw_control_is_supported = rtl8125_led_hw_control_is_supported;
-+ led_cdev->hw_control_set = rtl8125_led_hw_control_set;
-+ led_cdev->hw_control_get = rtl8125_led_hw_control_get;
-+ led_cdev->hw_control_get_device = r8169_led_hw_control_get_device;
-+
-+ /* ignore errors */
-+ devm_led_classdev_register(&ndev->dev, led_cdev);
-+}
-+
-+void rtl8125_init_leds(struct net_device *ndev)
-+{
-+ /* bind resource mgmt to netdev */
-+ struct device *dev = &ndev->dev;
-+ struct r8169_led_classdev *leds;
-+ int i;
-+
-+ leds = devm_kcalloc(dev, RTL8125_NUM_LEDS, sizeof(*leds), GFP_KERNEL);
-+ if (!leds)
-+ return;
-+
-+ for (i = 0; i < RTL8125_NUM_LEDS; i++)
-+ rtl8125_setup_led_ldev(leds + i, ndev, i);
-+}
---- a/drivers/net/ethernet/realtek/r8169_main.c
-+++ b/drivers/net/ethernet/realtek/r8169_main.c
-@@ -330,17 +330,23 @@ enum rtl8168_registers {
- };
-
- enum rtl8125_registers {
-+ LEDSEL0 = 0x18,
- INT_CFG0_8125 = 0x34,
- #define INT_CFG0_ENABLE_8125 BIT(0)
- #define INT_CFG0_CLKREQEN BIT(3)
- IntrMask_8125 = 0x38,
- IntrStatus_8125 = 0x3c,
- INT_CFG1_8125 = 0x7a,
-+ LEDSEL2 = 0x84,
-+ LEDSEL1 = 0x86,
- TxPoll_8125 = 0x90,
-+ LEDSEL3 = 0x96,
- MAC0_BKP = 0x19e0,
- EEE_TXIDLE_TIMER_8125 = 0x6048,
- };
-
-+#define LEDSEL_MASK_8125 0x23f
-+
- #define RX_VLAN_INNER_8125 BIT(22)
- #define RX_VLAN_OUTER_8125 BIT(23)
- #define RX_VLAN_8125 (RX_VLAN_INNER_8125 | RX_VLAN_OUTER_8125)
-@@ -857,6 +863,51 @@ int rtl8168_get_led_mode(struct rtl8169_
- return ret;
- }
-
-+static int rtl8125_get_led_reg(int index)
-+{
-+ static const int led_regs[] = { LEDSEL0, LEDSEL1, LEDSEL2, LEDSEL3 };
-+
-+ return led_regs[index];
-+}
-+
-+int rtl8125_set_led_mode(struct rtl8169_private *tp, int index, u16 mode)
-+{
-+ int reg = rtl8125_get_led_reg(index);
-+ struct device *dev = tp_to_dev(tp);
-+ int ret;
-+ u16 val;
-+
-+ ret = pm_runtime_resume_and_get(dev);
-+ if (ret < 0)
-+ return ret;
-+
-+ mutex_lock(&tp->led_lock);
-+ val = RTL_R16(tp, reg) & ~LEDSEL_MASK_8125;
-+ RTL_W16(tp, reg, val | mode);
-+ mutex_unlock(&tp->led_lock);
-+
-+ pm_runtime_put_sync(dev);
-+
-+ return 0;
-+}
-+
-+int rtl8125_get_led_mode(struct rtl8169_private *tp, int index)
-+{
-+ int reg = rtl8125_get_led_reg(index);
-+ struct device *dev = tp_to_dev(tp);
-+ int ret;
-+
-+ ret = pm_runtime_resume_and_get(dev);
-+ if (ret < 0)
-+ return ret;
-+
-+ ret = RTL_R16(tp, reg);
-+
-+ pm_runtime_put_sync(dev);
-+
-+ return ret;
-+}
-+
- void r8169_get_led_name(struct rtl8169_private *tp, int idx,
- char *buf, int buf_len)
- {
-@@ -5450,10 +5501,12 @@ static int rtl_init_one(struct pci_dev *
- if (rc)
- return rc;
-
-- if (IS_ENABLED(CONFIG_R8169_LEDS) &&
-- tp->mac_version > RTL_GIGA_MAC_VER_06 &&
-- tp->mac_version < RTL_GIGA_MAC_VER_61)
-- rtl8168_init_leds(dev);
-+ if (IS_ENABLED(CONFIG_R8169_LEDS)) {
-+ if (rtl_is_8125(tp))
-+ rtl8125_init_leds(dev);
-+ else if (tp->mac_version > RTL_GIGA_MAC_VER_06)
-+ rtl8168_init_leds(dev);
-+ }
-
- netdev_info(dev, "%s, %pM, XID %03x, IRQ %d\n",
- rtl_chip_infos[chipset].name, dev->dev_addr, xid, tp->irq);
+++ /dev/null
-From 2ce30993831041b9dcd31eb12896be6611e8b7e2 Mon Sep 17 00:00:00 2001
-Date: Mon, 12 Feb 2024 19:57:46 +0100
-Subject: [PATCH] r8169: add generic rtl_set_eee_txidle_timer function
-
-Add a generic setter for the EEE tx idle timer and use it with all
-RTL8125/RTL8126 chip versions, in line with the vendor driver.
-This prepares for adding EEE tx idle timer support for additional
-chip versions.
-
----
- drivers/net/ethernet/realtek/r8169_main.c | 34 +++++++++++++----------
- 1 file changed, 20 insertions(+), 14 deletions(-)
-
---- a/drivers/net/ethernet/realtek/r8169_main.c
-+++ b/drivers/net/ethernet/realtek/r8169_main.c
-@@ -646,6 +646,7 @@ struct rtl8169_private {
- struct page *Rx_databuff[NUM_RX_DESC]; /* Rx data buffers */
- struct ring_info tx_skb[NUM_TX_DESC]; /* Tx data buffers */
- u16 cp_cmd;
-+ u16 tx_lpi_timer;
- u32 irq_mask;
- int irq;
- struct clk *clk;
-@@ -2081,6 +2082,22 @@ static int rtl_set_coalesce(struct net_d
- return 0;
- }
-
-+static void rtl_set_eee_txidle_timer(struct rtl8169_private *tp)
-+{
-+ unsigned int timer_val = READ_ONCE(tp->dev->mtu) + ETH_HLEN + 0x20;
-+
-+ switch (tp->mac_version) {
-+ case RTL_GIGA_MAC_VER_61:
-+ case RTL_GIGA_MAC_VER_63:
-+ case RTL_GIGA_MAC_VER_65:
-+ tp->tx_lpi_timer = timer_val;
-+ RTL_W16(tp, EEE_TXIDLE_TIMER_8125, timer_val);
-+ break;
-+ default:
-+ break;
-+ }
-+}
-+
- static int rtl8169_get_eee(struct net_device *dev, struct ethtool_eee *data)
- {
- struct rtl8169_private *tp = netdev_priv(dev);
-@@ -2339,14 +2356,8 @@ static void rtl8125a_config_eee_mac(stru
- r8168_mac_ocp_modify(tp, 0xeb62, 0, BIT(2) | BIT(1));
- }
-
--static void rtl8125_set_eee_txidle_timer(struct rtl8169_private *tp)
--{
-- RTL_W16(tp, EEE_TXIDLE_TIMER_8125, tp->dev->mtu + ETH_HLEN + 0x20);
--}
--
- static void rtl8125b_config_eee_mac(struct rtl8169_private *tp)
- {
-- rtl8125_set_eee_txidle_timer(tp);
- r8168_mac_ocp_modify(tp, 0xe040, 0, BIT(1) | BIT(0));
- }
-
-@@ -3879,6 +3890,8 @@ static void rtl_hw_start(struct rtl8169
- rtl_hw_aspm_clkreq_enable(tp, false);
- RTL_W16(tp, CPlusCmd, tp->cp_cmd);
-
-+ rtl_set_eee_txidle_timer(tp);
-+
- if (tp->mac_version <= RTL_GIGA_MAC_VER_06)
- rtl_hw_start_8169(tp);
- else if (rtl_is_8125(tp))
-@@ -3912,14 +3925,7 @@ static int rtl8169_change_mtu(struct net
- dev->mtu = new_mtu;
- netdev_update_features(dev);
- rtl_jumbo_config(tp);
--
-- switch (tp->mac_version) {
-- case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_65:
-- rtl8125_set_eee_txidle_timer(tp);
-- break;
-- default:
-- break;
-- }
-+ rtl_set_eee_txidle_timer(tp);
-
- return 0;
- }
+++ /dev/null
-From 57d2d2c8f132c830565058a5cdd8138350e068ec Mon Sep 17 00:00:00 2001
-Date: Mon, 12 Feb 2024 19:58:47 +0100
-Subject: [PATCH] r8169: support setting the EEE tx idle timer on
- RTL8168h
-
-Support setting the EEE tx idle timer also on RTL8168h.
-
----
- drivers/net/ethernet/realtek/r8169_main.c | 5 +++++
- 1 file changed, 5 insertions(+)
-
---- a/drivers/net/ethernet/realtek/r8169_main.c
-+++ b/drivers/net/ethernet/realtek/r8169_main.c
-@@ -2087,6 +2087,11 @@ static void rtl_set_eee_txidle_timer(str
- unsigned int timer_val = READ_ONCE(tp->dev->mtu) + ETH_HLEN + 0x20;
-
- switch (tp->mac_version) {
-+ case RTL_GIGA_MAC_VER_46:
-+ case RTL_GIGA_MAC_VER_48:
-+ tp->tx_lpi_timer = timer_val;
-+ r8168_mac_ocp_write(tp, 0xe048, timer_val);
-+ break;
- case RTL_GIGA_MAC_VER_61:
- case RTL_GIGA_MAC_VER_63:
- case RTL_GIGA_MAC_VER_65:
+++ /dev/null
-From 9c50139727265c088f936e496777bf588850e9f1 Mon Sep 17 00:00:00 2001
-Date: Mon, 12 Feb 2024 19:59:26 +0100
-Subject: [PATCH] r8169: add support for returning tx_lpi_timer in
- ethtool get_eee
-
-Add support for returning the tx_lpi_timer value to userspace.
-This is supported by few chip versions only: RTL8168h/RTL8125/RTL8126
-
----
- drivers/net/ethernet/realtek/r8169_main.c | 22 +++++++++++++++++++++-
- 1 file changed, 21 insertions(+), 1 deletion(-)
-
---- a/drivers/net/ethernet/realtek/r8169_main.c
-+++ b/drivers/net/ethernet/realtek/r8169_main.c
-@@ -2103,14 +2103,34 @@ static void rtl_set_eee_txidle_timer(str
- }
- }
-
-+static unsigned int r8169_get_tx_lpi_timer_us(struct rtl8169_private *tp)
-+{
-+ unsigned int speed = tp->phydev->speed;
-+ unsigned int timer = tp->tx_lpi_timer;
-+
-+ if (!timer || speed == SPEED_UNKNOWN)
-+ return 0;
-+
-+ /* tx_lpi_timer value is in bytes */
-+ return DIV_ROUND_CLOSEST(timer * BITS_PER_BYTE, speed);
-+}
-+
- static int rtl8169_get_eee(struct net_device *dev, struct ethtool_eee *data)
- {
- struct rtl8169_private *tp = netdev_priv(dev);
-+ int ret;
-
- if (!rtl_supports_eee(tp))
- return -EOPNOTSUPP;
-
-- return phy_ethtool_get_eee(tp->phydev, data);
-+ ret = phy_ethtool_get_eee(tp->phydev, data);
-+ if (ret)
-+ return ret;
-+
-+ data->tx_lpi_timer = r8169_get_tx_lpi_timer_us(tp);
-+ data->tx_lpi_enabled = data->tx_lpi_timer ? data->eee_enabled : false;
-+
-+ return 0;
- }
-
- static int rtl8169_set_eee(struct net_device *dev, struct ethtool_eee *data)
+++ /dev/null
-From f4d3e595c0000ce39dec7e4799ea42ce42ab6867 Mon Sep 17 00:00:00 2001
-Date: Sat, 17 Feb 2024 15:48:23 +0100
-Subject: [PATCH] r8169: add MODULE_FIRMWARE entry for RTL8126A
-
-Add the missing MODULE_FIRMWARE entry for RTL8126A.
-
----
- drivers/net/ethernet/realtek/r8169_main.c | 1 +
- 1 file changed, 1 insertion(+)
-
---- a/drivers/net/ethernet/realtek/r8169_main.c
-+++ b/drivers/net/ethernet/realtek/r8169_main.c
-@@ -703,6 +703,7 @@ MODULE_FIRMWARE(FIRMWARE_8168FP_3);
- MODULE_FIRMWARE(FIRMWARE_8107E_2);
- MODULE_FIRMWARE(FIRMWARE_8125A_3);
- MODULE_FIRMWARE(FIRMWARE_8125B_2);
-+MODULE_FIRMWARE(FIRMWARE_8126A_2);
-
- static inline struct device *tp_to_dev(struct rtl8169_private *tp)
- {
+++ /dev/null
-From 19fa4f2a85d777a8052e869c1b892a2f7556569d Mon Sep 17 00:00:00 2001
-Date: Mon, 8 Apr 2024 20:47:40 +0200
-Subject: [PATCH] r8169: fix LED-related deadlock on module removal
-
-Binding devm_led_classdev_register() to the netdev is problematic
-because on module removal we get a RTNL-related deadlock. Fix this
-by avoiding the device-managed LED functions.
-
-Note: We can safely call led_classdev_unregister() for a LED even
-if registering it failed, because led_classdev_unregister() detects
-this and is a no-op in this case.
-
-Fixes: 18764b883e15 ("r8169: add support for LED's on RTL8168/RTL8101")
----
- drivers/net/ethernet/realtek/r8169.h | 6 ++--
- drivers/net/ethernet/realtek/r8169_leds.c | 35 +++++++++++++++--------
- drivers/net/ethernet/realtek/r8169_main.c | 8 ++++--
- 3 files changed, 33 insertions(+), 16 deletions(-)
-
---- a/drivers/net/ethernet/realtek/r8169.h
-+++ b/drivers/net/ethernet/realtek/r8169.h
-@@ -73,6 +73,7 @@ enum mac_version {
- };
-
- struct rtl8169_private;
-+struct r8169_led_classdev;
-
- void r8169_apply_firmware(struct rtl8169_private *tp);
- u16 rtl8168h_2_get_adc_bias_ioffset(struct rtl8169_private *tp);
-@@ -84,7 +85,8 @@ void r8169_get_led_name(struct rtl8169_p
- char *buf, int buf_len);
- int rtl8168_get_led_mode(struct rtl8169_private *tp);
- int rtl8168_led_mod_ctrl(struct rtl8169_private *tp, u16 mask, u16 val);
--void rtl8168_init_leds(struct net_device *ndev);
-+struct r8169_led_classdev *rtl8168_init_leds(struct net_device *ndev);
- int rtl8125_get_led_mode(struct rtl8169_private *tp, int index);
- int rtl8125_set_led_mode(struct rtl8169_private *tp, int index, u16 mode);
--void rtl8125_init_leds(struct net_device *ndev);
-+struct r8169_led_classdev *rtl8125_init_leds(struct net_device *ndev);
-+void r8169_remove_leds(struct r8169_led_classdev *leds);
---- a/drivers/net/ethernet/realtek/r8169_leds.c
-+++ b/drivers/net/ethernet/realtek/r8169_leds.c
-@@ -147,22 +147,22 @@ static void rtl8168_setup_ldev(struct r8
- led_cdev->hw_control_get_device = r8169_led_hw_control_get_device;
-
- /* ignore errors */
-- devm_led_classdev_register(&ndev->dev, led_cdev);
-+ led_classdev_register(&ndev->dev, led_cdev);
- }
-
--void rtl8168_init_leds(struct net_device *ndev)
-+struct r8169_led_classdev *rtl8168_init_leds(struct net_device *ndev)
- {
-- /* bind resource mgmt to netdev */
-- struct device *dev = &ndev->dev;
- struct r8169_led_classdev *leds;
- int i;
-
-- leds = devm_kcalloc(dev, RTL8168_NUM_LEDS, sizeof(*leds), GFP_KERNEL);
-+ leds = kcalloc(RTL8168_NUM_LEDS + 1, sizeof(*leds), GFP_KERNEL);
- if (!leds)
-- return;
-+ return NULL;
-
- for (i = 0; i < RTL8168_NUM_LEDS; i++)
- rtl8168_setup_ldev(leds + i, ndev, i);
-+
-+ return leds;
- }
-
- static int rtl8125_led_hw_control_is_supported(struct led_classdev *led_cdev,
-@@ -246,20 +246,31 @@ static void rtl8125_setup_led_ldev(struc
- led_cdev->hw_control_get_device = r8169_led_hw_control_get_device;
-
- /* ignore errors */
-- devm_led_classdev_register(&ndev->dev, led_cdev);
-+ led_classdev_register(&ndev->dev, led_cdev);
- }
-
--void rtl8125_init_leds(struct net_device *ndev)
-+struct r8169_led_classdev *rtl8125_init_leds(struct net_device *ndev)
- {
-- /* bind resource mgmt to netdev */
-- struct device *dev = &ndev->dev;
- struct r8169_led_classdev *leds;
- int i;
-
-- leds = devm_kcalloc(dev, RTL8125_NUM_LEDS, sizeof(*leds), GFP_KERNEL);
-+ leds = kcalloc(RTL8125_NUM_LEDS + 1, sizeof(*leds), GFP_KERNEL);
- if (!leds)
-- return;
-+ return NULL;
-
- for (i = 0; i < RTL8125_NUM_LEDS; i++)
- rtl8125_setup_led_ldev(leds + i, ndev, i);
-+
-+ return leds;
-+}
-+
-+void r8169_remove_leds(struct r8169_led_classdev *leds)
-+{
-+ if (!leds)
-+ return;
-+
-+ for (struct r8169_led_classdev *l = leds; l->ndev; l++)
-+ led_classdev_unregister(&l->led);
-+
-+ kfree(leds);
- }
---- a/drivers/net/ethernet/realtek/r8169_main.c
-+++ b/drivers/net/ethernet/realtek/r8169_main.c
-@@ -674,6 +674,8 @@ struct rtl8169_private {
- const char *fw_name;
- struct rtl_fw *rtl_fw;
-
-+ struct r8169_led_classdev *leds;
-+
- u32 ocp_base;
- };
-
-@@ -5076,6 +5078,8 @@ static void rtl_remove_one(struct pci_de
-
- cancel_work_sync(&tp->wk.work);
-
-+ r8169_remove_leds(tp->leds);
-+
- unregister_netdev(tp->dev);
-
- if (tp->dash_type != RTL_DASH_NONE)
-@@ -5535,9 +5539,9 @@ static int rtl_init_one(struct pci_dev *
-
- if (IS_ENABLED(CONFIG_R8169_LEDS)) {
- if (rtl_is_8125(tp))
-- rtl8125_init_leds(dev);
-+ tp->leds = rtl8125_init_leds(dev);
- else if (tp->mac_version > RTL_GIGA_MAC_VER_06)
-- rtl8168_init_leds(dev);
-+ tp->leds = rtl8168_init_leds(dev);
- }
-
- netdev_info(dev, "%s, %pM, XID %03x, IRQ %d\n",
+++ /dev/null
-From 97e176fcbbf3c0f2bd410c9b241177c051f57176 Mon Sep 17 00:00:00 2001
-Date: Wed, 10 Apr 2024 15:11:28 +0200
-Subject: [PATCH] r8169: add missing conditional compiling for call to
- r8169_remove_leds
-
-Add missing dependency on CONFIG_R8169_LEDS. As-is a link error occurs
-if config option CONFIG_R8169_LEDS isn't enabled.
-
-Fixes: 19fa4f2a85d7 ("r8169: fix LED-related deadlock on module removal")
----
- drivers/net/ethernet/realtek/r8169_main.c | 3 ++-
- 1 file changed, 2 insertions(+), 1 deletion(-)
-
---- a/drivers/net/ethernet/realtek/r8169_main.c
-+++ b/drivers/net/ethernet/realtek/r8169_main.c
-@@ -5078,7 +5078,8 @@ static void rtl_remove_one(struct pci_de
-
- cancel_work_sync(&tp->wk.work);
-
-- r8169_remove_leds(tp->leds);
-+ if (IS_ENABLED(CONFIG_R8169_LEDS))
-+ r8169_remove_leds(tp->leds);
-
- unregister_netdev(tp->dev);
-
+++ /dev/null
-From 39f59c72ad3a1eaab9a60f0671bc94d2bc826d21 Mon Sep 17 00:00:00 2001
-Date: Sun, 7 Apr 2024 23:19:25 +0200
-Subject: [PATCH] r8169: add support for RTL8168M
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-A user reported an unknown chip version. According to the r8168 vendor
-driver it's called RTL8168M, but handling is identical to RTL8168H.
-So let's simply treat it as RTL8168H.
-
----
- drivers/net/ethernet/realtek/r8169_main.c | 2 ++
- 1 file changed, 2 insertions(+)
-
---- a/drivers/net/ethernet/realtek/r8169_main.c
-+++ b/drivers/net/ethernet/realtek/r8169_main.c
-@@ -2257,6 +2257,8 @@ static enum mac_version rtl8169_get_mac_
- * the wild. Let's disable detection.
- * { 0x7cf, 0x540, RTL_GIGA_MAC_VER_45 },
- */
-+ /* Realtek calls it RTL8168M, but it's handled like RTL8168H */
-+ { 0x7cf, 0x6c0, RTL_GIGA_MAC_VER_46 },
-
- /* 8168G family. */
- { 0x7cf, 0x5c8, RTL_GIGA_MAC_VER_44 },
+++ /dev/null
-From 1eb2cded45b35816085c1f962933c187d970f9dc Mon Sep 17 00:00:00 2001
-Date: Mon, 6 May 2024 10:28:12 +0000
-Subject: [PATCH] net: annotate writes on dev->mtu from ndo_change_mtu()
-
-Simon reported that ndo_change_mtu() methods were never
-updated to use WRITE_ONCE(dev->mtu, new_mtu) as hinted
-in commit 501a90c94510 ("inet: protect against too small
-mtu values.")
-
-We read dev->mtu without holding RTNL in many places,
-with READ_ONCE() annotations.
-
-It is time to take care of ndo_change_mtu() methods
-to use corresponding WRITE_ONCE()
-
----
- drivers/net/ethernet/realtek/8139cp.c | 4 ++--
- drivers/net/ethernet/realtek/r8169_main.c | 2 +-
- 2 files changed, 3 insertions(+), 3 deletions(-)
-
---- a/drivers/net/ethernet/realtek/8139cp.c
-+++ b/drivers/net/ethernet/realtek/8139cp.c
-@@ -1277,14 +1277,14 @@ static int cp_change_mtu(struct net_devi
-
- /* if network interface not up, no need for complexity */
- if (!netif_running(dev)) {
-- dev->mtu = new_mtu;
-+ WRITE_ONCE(dev->mtu, new_mtu);
- cp_set_rxbufsize(cp); /* set new rx buf size */
- return 0;
- }
-
- /* network IS up, close it, reset MTU, and come up again. */
- cp_close(dev);
-- dev->mtu = new_mtu;
-+ WRITE_ONCE(dev->mtu, new_mtu);
- cp_set_rxbufsize(cp);
- return cp_open(dev);
- }
---- a/drivers/net/ethernet/realtek/r8169_main.c
-+++ b/drivers/net/ethernet/realtek/r8169_main.c
-@@ -3952,7 +3952,7 @@ static int rtl8169_change_mtu(struct net
- {
- struct rtl8169_private *tp = netdev_priv(dev);
-
-- dev->mtu = new_mtu;
-+ WRITE_ONCE(dev->mtu, new_mtu);
- netdev_update_features(dev);
- rtl_jumbo_config(tp);
- rtl_set_eee_txidle_timer(tp);
+++ /dev/null
-From 6994520a332887f1688464f250c9ec8002a89a8e Mon Sep 17 00:00:00 2001
-Date: Mon, 27 May 2024 21:16:56 +0200
-Subject: [PATCH] r8169: disable interrupt source RxOverflow
-
-Vendor driver calls this bit RxDescUnavail. All we do in the interrupt
-handler in this case is scheduling NAPI. If we should be out of
-RX descriptors, then NAPI is scheduled anyway. Therefore remove this
-interrupt source. Tested on RTL8168h.
-
----
- drivers/net/ethernet/realtek/r8169_main.c | 4 +---
- 1 file changed, 1 insertion(+), 3 deletions(-)
-
---- a/drivers/net/ethernet/realtek/r8169_main.c
-+++ b/drivers/net/ethernet/realtek/r8169_main.c
-@@ -5119,12 +5119,10 @@ static void rtl_set_irq_mask(struct rtl8
- tp->irq_mask = RxOK | RxErr | TxOK | TxErr | LinkChg;
-
- if (tp->mac_version <= RTL_GIGA_MAC_VER_06)
-- tp->irq_mask |= SYSErr | RxOverflow | RxFIFOOver;
-+ tp->irq_mask |= SYSErr | RxFIFOOver;
- else if (tp->mac_version == RTL_GIGA_MAC_VER_11)
- /* special workaround needed */
- tp->irq_mask |= RxFIFOOver;
-- else
-- tp->irq_mask |= RxOverflow;
- }
-
- static int rtl_alloc_irq(struct rtl8169_private *tp)
+++ /dev/null
-From 982300c115d229565d7af8e8b38aa1ee7bb1f5bd Mon Sep 17 00:00:00 2001
-Date: Mon, 27 May 2024 21:20:16 +0200
-Subject: [PATCH] r8169: remove detection of chip version 11 (early
- RTL8168b)
-
-This early RTL8168b version was the first PCIe chip version, and it's
-quite quirky. Last sign of life is from more than 15 yrs ago.
-Let's remove detection of this chip version, we'll see whether anybody
-complains. If not, support for this chip version can be removed a few
-kernel versions later.
-
----
- drivers/net/ethernet/realtek/r8169_main.c | 4 +++-
- 1 file changed, 3 insertions(+), 1 deletion(-)
-
---- a/drivers/net/ethernet/realtek/r8169_main.c
-+++ b/drivers/net/ethernet/realtek/r8169_main.c
-@@ -2302,7 +2302,9 @@ static enum mac_version rtl8169_get_mac_
-
- /* 8168B family. */
- { 0x7c8, 0x380, RTL_GIGA_MAC_VER_17 },
-- { 0x7c8, 0x300, RTL_GIGA_MAC_VER_11 },
-+ /* This one is very old and rare, let's see if anybody complains.
-+ * { 0x7c8, 0x300, RTL_GIGA_MAC_VER_11 },
-+ */
-
- /* 8101 family. */
- { 0x7c8, 0x448, RTL_GIGA_MAC_VER_39 },
+++ /dev/null
-From 69cb89981c7a181d857b634c0740e914d5df79ea Mon Sep 17 00:00:00 2001
-Date: Fri, 30 Aug 2024 10:18:10 +0800
-Subject: [PATCH] r8169: add support for RTL8126A rev.b
-
-Add support for RTL8126A rev.b. Its XID is 0x64a. It is basically
-based on the one with XID 0x649, but with different firmware file.
-
----
- drivers/net/ethernet/realtek/r8169.h | 1 +
- drivers/net/ethernet/realtek/r8169_main.c | 42 ++++++++++++-------
- .../net/ethernet/realtek/r8169_phy_config.c | 1 +
- 3 files changed, 29 insertions(+), 15 deletions(-)
-
---- a/drivers/net/ethernet/realtek/r8169.h
-+++ b/drivers/net/ethernet/realtek/r8169.h
-@@ -69,6 +69,7 @@ enum mac_version {
- RTL_GIGA_MAC_VER_61,
- RTL_GIGA_MAC_VER_63,
- RTL_GIGA_MAC_VER_65,
-+ RTL_GIGA_MAC_VER_66,
- RTL_GIGA_MAC_NONE
- };
-
---- a/drivers/net/ethernet/realtek/r8169_main.c
-+++ b/drivers/net/ethernet/realtek/r8169_main.c
-@@ -56,6 +56,7 @@
- #define FIRMWARE_8125A_3 "rtl_nic/rtl8125a-3.fw"
- #define FIRMWARE_8125B_2 "rtl_nic/rtl8125b-2.fw"
- #define FIRMWARE_8126A_2 "rtl_nic/rtl8126a-2.fw"
-+#define FIRMWARE_8126A_3 "rtl_nic/rtl8126a-3.fw"
-
- #define TX_DMA_BURST 7 /* Maximum PCI burst, '7' is unlimited */
- #define InterFrameGap 0x03 /* 3 means InterFrameGap = the shortest one */
-@@ -138,6 +139,7 @@ static const struct {
- /* reserve 62 for CFG_METHOD_4 in the vendor driver */
- [RTL_GIGA_MAC_VER_63] = {"RTL8125B", FIRMWARE_8125B_2},
- [RTL_GIGA_MAC_VER_65] = {"RTL8126A", FIRMWARE_8126A_2},
-+ [RTL_GIGA_MAC_VER_66] = {"RTL8126A", FIRMWARE_8126A_3},
- };
-
- static const struct pci_device_id rtl8169_pci_tbl[] = {
-@@ -1228,7 +1230,7 @@ static void rtl_writephy(struct rtl8169_
- case RTL_GIGA_MAC_VER_31:
- r8168dp_2_mdio_write(tp, location, val);
- break;
-- case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_65:
-+ case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_66:
- r8168g_mdio_write(tp, location, val);
- break;
- default:
-@@ -1243,7 +1245,7 @@ static int rtl_readphy(struct rtl8169_pr
- case RTL_GIGA_MAC_VER_28:
- case RTL_GIGA_MAC_VER_31:
- return r8168dp_2_mdio_read(tp, location);
-- case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_65:
-+ case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_66:
- return r8168g_mdio_read(tp, location);
- default:
- return r8169_mdio_read(tp, location);
-@@ -1452,7 +1454,7 @@ static void rtl_set_d3_pll_down(struct r
- case RTL_GIGA_MAC_VER_25 ... RTL_GIGA_MAC_VER_26:
- case RTL_GIGA_MAC_VER_29 ... RTL_GIGA_MAC_VER_30:
- case RTL_GIGA_MAC_VER_32 ... RTL_GIGA_MAC_VER_37:
-- case RTL_GIGA_MAC_VER_39 ... RTL_GIGA_MAC_VER_65:
-+ case RTL_GIGA_MAC_VER_39 ... RTL_GIGA_MAC_VER_66:
- if (enable)
- RTL_W8(tp, PMCH, RTL_R8(tp, PMCH) & ~D3_NO_PLL_DOWN);
- else
-@@ -1619,7 +1621,7 @@ static void __rtl8169_set_wol(struct rtl
- break;
- case RTL_GIGA_MAC_VER_34:
- case RTL_GIGA_MAC_VER_37:
-- case RTL_GIGA_MAC_VER_39 ... RTL_GIGA_MAC_VER_65:
-+ case RTL_GIGA_MAC_VER_39 ... RTL_GIGA_MAC_VER_66:
- if (wolopts)
- rtl_mod_config2(tp, 0, PME_SIGNAL);
- else
-@@ -2098,6 +2100,7 @@ static void rtl_set_eee_txidle_timer(str
- case RTL_GIGA_MAC_VER_61:
- case RTL_GIGA_MAC_VER_63:
- case RTL_GIGA_MAC_VER_65:
-+ case RTL_GIGA_MAC_VER_66:
- tp->tx_lpi_timer = timer_val;
- RTL_W16(tp, EEE_TXIDLE_TIMER_8125, timer_val);
- break;
-@@ -2227,6 +2230,7 @@ static enum mac_version rtl8169_get_mac_
- enum mac_version ver;
- } mac_info[] = {
- /* 8126A family. */
-+ { 0x7cf, 0x64a, RTL_GIGA_MAC_VER_66 },
- { 0x7cf, 0x649, RTL_GIGA_MAC_VER_65 },
-
- /* 8125B family. */
-@@ -2498,6 +2502,7 @@ static void rtl_init_rxcfg(struct rtl816
- break;
- case RTL_GIGA_MAC_VER_63:
- case RTL_GIGA_MAC_VER_65:
-+ case RTL_GIGA_MAC_VER_66:
- RTL_W32(tp, RxConfig, RX_FETCH_DFLT_8125 | RX_DMA_BURST |
- RX_PAUSE_SLOT_ON);
- break;
-@@ -2684,7 +2689,7 @@ static void rtl_wait_txrx_fifo_empty(str
- case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_61:
- rtl_loop_wait_high(tp, &rtl_rxtx_empty_cond, 100, 42);
- break;
-- case RTL_GIGA_MAC_VER_63 ... RTL_GIGA_MAC_VER_65:
-+ case RTL_GIGA_MAC_VER_63 ... RTL_GIGA_MAC_VER_66:
- RTL_W8(tp, ChipCmd, RTL_R8(tp, ChipCmd) | StopReq);
- rtl_loop_wait_high(tp, &rtl_rxtx_empty_cond, 100, 42);
- rtl_loop_wait_high(tp, &rtl_rxtx_empty_cond_2, 100, 42);
-@@ -2927,7 +2932,7 @@ static void rtl_enable_exit_l1(struct rt
- case RTL_GIGA_MAC_VER_37 ... RTL_GIGA_MAC_VER_38:
- rtl_eri_set_bits(tp, 0xd4, 0x0c00);
- break;
-- case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_65:
-+ case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_66:
- r8168_mac_ocp_modify(tp, 0xc0ac, 0, 0x1f80);
- break;
- default:
-@@ -2941,7 +2946,7 @@ static void rtl_disable_exit_l1(struct r
- case RTL_GIGA_MAC_VER_34 ... RTL_GIGA_MAC_VER_38:
- rtl_eri_clear_bits(tp, 0xd4, 0x1f00);
- break;
-- case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_65:
-+ case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_66:
- r8168_mac_ocp_modify(tp, 0xc0ac, 0x1f80, 0);
- break;
- default:
-@@ -2968,6 +2973,7 @@ static void rtl_hw_aspm_clkreq_enable(st
- rtl_mod_config5(tp, 0, ASPM_en);
- switch (tp->mac_version) {
- case RTL_GIGA_MAC_VER_65:
-+ case RTL_GIGA_MAC_VER_66:
- val8 = RTL_R8(tp, INT_CFG0_8125) | INT_CFG0_CLKREQEN;
- RTL_W8(tp, INT_CFG0_8125, val8);
- break;
-@@ -2978,7 +2984,7 @@ static void rtl_hw_aspm_clkreq_enable(st
-
- switch (tp->mac_version) {
- case RTL_GIGA_MAC_VER_46 ... RTL_GIGA_MAC_VER_48:
-- case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_65:
-+ case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_66:
- /* reset ephy tx/rx disable timer */
- r8168_mac_ocp_modify(tp, 0xe094, 0xff00, 0);
- /* chip can trigger L1.2 */
-@@ -2990,7 +2996,7 @@ static void rtl_hw_aspm_clkreq_enable(st
- } else {
- switch (tp->mac_version) {
- case RTL_GIGA_MAC_VER_46 ... RTL_GIGA_MAC_VER_48:
-- case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_65:
-+ case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_66:
- r8168_mac_ocp_modify(tp, 0xe092, 0x00ff, 0);
- break;
- default:
-@@ -2999,6 +3005,7 @@ static void rtl_hw_aspm_clkreq_enable(st
-
- switch (tp->mac_version) {
- case RTL_GIGA_MAC_VER_65:
-+ case RTL_GIGA_MAC_VER_66:
- val8 = RTL_R8(tp, INT_CFG0_8125) & ~INT_CFG0_CLKREQEN;
- RTL_W8(tp, INT_CFG0_8125, val8);
- break;
-@@ -3718,10 +3725,12 @@ static void rtl_hw_start_8125_common(str
- /* disable new tx descriptor format */
- r8168_mac_ocp_modify(tp, 0xeb58, 0x0001, 0x0000);
-
-- if (tp->mac_version == RTL_GIGA_MAC_VER_65)
-+ if (tp->mac_version == RTL_GIGA_MAC_VER_65 ||
-+ tp->mac_version == RTL_GIGA_MAC_VER_66)
- RTL_W8(tp, 0xD8, RTL_R8(tp, 0xD8) & ~0x02);
-
-- if (tp->mac_version == RTL_GIGA_MAC_VER_65)
-+ if (tp->mac_version == RTL_GIGA_MAC_VER_65 ||
-+ tp->mac_version == RTL_GIGA_MAC_VER_66)
- r8168_mac_ocp_modify(tp, 0xe614, 0x0700, 0x0400);
- else if (tp->mac_version == RTL_GIGA_MAC_VER_63)
- r8168_mac_ocp_modify(tp, 0xe614, 0x0700, 0x0200);
-@@ -3739,7 +3748,8 @@ static void rtl_hw_start_8125_common(str
- r8168_mac_ocp_modify(tp, 0xe056, 0x00f0, 0x0000);
- r8168_mac_ocp_modify(tp, 0xe040, 0x1000, 0x0000);
- r8168_mac_ocp_modify(tp, 0xea1c, 0x0003, 0x0001);
-- if (tp->mac_version == RTL_GIGA_MAC_VER_65)
-+ if (tp->mac_version == RTL_GIGA_MAC_VER_65 ||
-+ tp->mac_version == RTL_GIGA_MAC_VER_66)
- r8168_mac_ocp_modify(tp, 0xea1c, 0x0300, 0x0000);
- else
- r8168_mac_ocp_modify(tp, 0xea1c, 0x0004, 0x0000);
-@@ -3853,6 +3863,7 @@ static void rtl_hw_config(struct rtl8169
- [RTL_GIGA_MAC_VER_61] = rtl_hw_start_8125a_2,
- [RTL_GIGA_MAC_VER_63] = rtl_hw_start_8125b,
- [RTL_GIGA_MAC_VER_65] = rtl_hw_start_8126a,
-+ [RTL_GIGA_MAC_VER_66] = rtl_hw_start_8126a,
- };
-
- if (hw_configs[tp->mac_version])
-@@ -3873,6 +3884,7 @@ static void rtl_hw_start_8125(struct rtl
- break;
- case RTL_GIGA_MAC_VER_63:
- case RTL_GIGA_MAC_VER_65:
-+ case RTL_GIGA_MAC_VER_66:
- for (i = 0xa00; i < 0xa80; i += 4)
- RTL_W32(tp, i, 0);
- RTL_W16(tp, INT_CFG1_8125, 0x0000);
-@@ -4101,7 +4113,7 @@ static void rtl8169_cleanup(struct rtl81
- RTL_W8(tp, ChipCmd, RTL_R8(tp, ChipCmd) | StopReq);
- rtl_loop_wait_high(tp, &rtl_txcfg_empty_cond, 100, 666);
- break;
-- case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_65:
-+ case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_66:
- rtl_enable_rxdvgate(tp);
- fsleep(2000);
- break;
-@@ -4258,7 +4270,7 @@ static unsigned int rtl_quirk_packet_pad
-
- switch (tp->mac_version) {
- case RTL_GIGA_MAC_VER_34:
-- case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_65:
-+ case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_66:
- padto = max_t(unsigned int, padto, ETH_ZLEN);
- break;
- default:
-@@ -5296,7 +5308,7 @@ static void rtl_hw_initialize(struct rtl
- case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_48:
- rtl_hw_init_8168g(tp);
- break;
-- case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_65:
-+ case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_66:
- rtl_hw_init_8125(tp);
- break;
- default:
---- a/drivers/net/ethernet/realtek/r8169_phy_config.c
-+++ b/drivers/net/ethernet/realtek/r8169_phy_config.c
-@@ -1161,6 +1161,7 @@ void r8169_hw_phy_config(struct rtl8169_
- [RTL_GIGA_MAC_VER_61] = rtl8125a_2_hw_phy_config,
- [RTL_GIGA_MAC_VER_63] = rtl8125b_hw_phy_config,
- [RTL_GIGA_MAC_VER_65] = rtl8126a_hw_phy_config,
-+ [RTL_GIGA_MAC_VER_66] = rtl8126a_hw_phy_config,
- };
-
- if (phy_configs[ver])
+++ /dev/null
-From 3b067536daa4842adbf685accf47c899a26367d3 Mon Sep 17 00:00:00 2001
-Date: Wed, 18 Sep 2024 20:45:15 +0200
-Subject: [PATCH] r8169: add missing MODULE_FIRMWARE entry for RTL8126A rev.b
-
-Add a missing MODULE_FIRMWARE entry.
-
-Fixes: 69cb89981c7a ("r8169: add support for RTL8126A rev.b")
----
- drivers/net/ethernet/realtek/r8169_main.c | 1 +
- 1 file changed, 1 insertion(+)
-
---- a/drivers/net/ethernet/realtek/r8169_main.c
-+++ b/drivers/net/ethernet/realtek/r8169_main.c
-@@ -708,6 +708,7 @@ MODULE_FIRMWARE(FIRMWARE_8107E_2);
- MODULE_FIRMWARE(FIRMWARE_8125A_3);
- MODULE_FIRMWARE(FIRMWARE_8125B_2);
- MODULE_FIRMWARE(FIRMWARE_8126A_2);
-+MODULE_FIRMWARE(FIRMWARE_8126A_3);
-
- static inline struct device *tp_to_dev(struct rtl8169_private *tp)
- {
+++ /dev/null
-From 854d71c555dfc3383c1fde7d9989b6046e21093d Mon Sep 17 00:00:00 2001
-Date: Wed, 9 Oct 2024 07:48:05 +0200
-Subject: [PATCH] r8169: remove original workaround for RTL8125 broken rx issue
-
-Now that we have b9c7ac4fe22c ("r8169: disable ALDPS per default for
-RTL8125"), the first attempt to fix the issue shouldn't be needed
-any longer. So let's effectively revert 621735f59064 ("r8169: fix
-rare issue with broken rx after link-down on RTL8125") and see
-whether anybody complains.
-
----
- drivers/net/ethernet/realtek/r8169_main.c | 4 ----
- 1 file changed, 4 deletions(-)
-
---- a/drivers/net/ethernet/realtek/r8169_main.c
-+++ b/drivers/net/ethernet/realtek/r8169_main.c
-@@ -4778,11 +4778,7 @@ static void r8169_phylink_handler(struct
- if (netif_carrier_ok(ndev)) {
- rtl_link_chg_patch(tp);
- pm_request_resume(d);
-- netif_wake_queue(tp->dev);
- } else {
-- /* In few cases rx is broken after link-down otherwise */
-- if (rtl_is_8125(tp))
-- rtl_schedule_task(tp, RTL_FLAG_TASK_RESET_NO_QUEUE_WAKE);
- pm_runtime_idle(d);
- }
-
+++ /dev/null
-From b8bf38440ba94e8ed8e2ae55c5dfb0276d30e843 Mon Sep 17 00:00:00 2001
-Date: Thu, 10 Oct 2024 12:58:02 +0200
-Subject: [PATCH] r8169: enable SG/TSO on selected chip versions per default
-
-Due to problem reports in the past SG and TSO/TSO6 are disabled per
-default. It's not fully clear which chip versions are affected, so we
-may impact also users of unaffected chip versions, unless they know
-how to use ethtool for enabling SG/TSO/TSO6.
-Vendor drivers r8168/r8125 enable SG/TSO/TSO6 for selected chip
-versions per default, I'd interpret this as confirmation that these
-chip versions are unaffected. So let's do the same here.
-
----
- drivers/net/ethernet/realtek/r8169_main.c | 16 +++++++++++-----
- 1 file changed, 11 insertions(+), 5 deletions(-)
-
---- a/drivers/net/ethernet/realtek/r8169_main.c
-+++ b/drivers/net/ethernet/realtek/r8169_main.c
-@@ -5493,11 +5493,6 @@ static int rtl_init_one(struct pci_dev *
-
- dev->features |= dev->hw_features;
-
-- /* There has been a number of reports that using SG/TSO results in
-- * tx timeouts. However for a lot of people SG/TSO works fine.
-- * Therefore disable both features by default, but allow users to
-- * enable them. Use at own risk!
-- */
- if (rtl_chip_supports_csum_v2(tp)) {
- dev->hw_features |= NETIF_F_SG | NETIF_F_TSO | NETIF_F_TSO6;
- netif_set_tso_max_size(dev, RTL_GSO_MAX_SIZE_V2);
-@@ -5508,6 +5503,17 @@ static int rtl_init_one(struct pci_dev *
- netif_set_tso_max_segs(dev, RTL_GSO_MAX_SEGS_V1);
- }
-
-+ /* There has been a number of reports that using SG/TSO results in
-+ * tx timeouts. However for a lot of people SG/TSO works fine.
-+ * It's not fully clear which chip versions are affected. Vendor
-+ * drivers enable SG/TSO for certain chip versions per default,
-+ * let's mimic this here. On other chip versions users can
-+ * use ethtool to enable SG/TSO, use at own risk!
-+ */
-+ if (tp->mac_version >= RTL_GIGA_MAC_VER_46 &&
-+ tp->mac_version != RTL_GIGA_MAC_VER_61)
-+ dev->features |= dev->hw_features;
-+
- dev->hw_features |= NETIF_F_RXALL;
- dev->hw_features |= NETIF_F_RXFCS;
-
+++ /dev/null
-From e3fc5139bd8ffaa1498adc21be4e8ecbc6aed508 Mon Sep 17 00:00:00 2001
-Date: Sun, 13 Oct 2024 11:17:39 +0200
-Subject: [PATCH] r8169: implement additional ethtool stats ops
-
-This adds support for ethtool standard statistics, and makes use of the
-extended hardware statistics being available from RTl8125.
-
----
- drivers/net/ethernet/realtek/r8169_main.c | 82 +++++++++++++++++++++++
- 1 file changed, 82 insertions(+)
-
---- a/drivers/net/ethernet/realtek/r8169_main.c
-+++ b/drivers/net/ethernet/realtek/r8169_main.c
-@@ -2161,6 +2161,19 @@ static void rtl8169_get_ringparam(struct
- data->tx_pending = NUM_TX_DESC;
- }
-
-+static void rtl8169_get_pause_stats(struct net_device *dev,
-+ struct ethtool_pause_stats *pause_stats)
-+{
-+ struct rtl8169_private *tp = netdev_priv(dev);
-+
-+ if (!rtl_is_8125(tp))
-+ return;
-+
-+ rtl8169_update_counters(tp);
-+ pause_stats->tx_pause_frames = le32_to_cpu(tp->counters->tx_pause_on);
-+ pause_stats->rx_pause_frames = le32_to_cpu(tp->counters->rx_pause_on);
-+}
-+
- static void rtl8169_get_pauseparam(struct net_device *dev,
- struct ethtool_pauseparam *data)
- {
-@@ -2187,6 +2200,69 @@ static int rtl8169_set_pauseparam(struct
- return 0;
- }
-
-+static void rtl8169_get_eth_mac_stats(struct net_device *dev,
-+ struct ethtool_eth_mac_stats *mac_stats)
-+{
-+ struct rtl8169_private *tp = netdev_priv(dev);
-+
-+ rtl8169_update_counters(tp);
-+
-+ mac_stats->FramesTransmittedOK =
-+ le64_to_cpu(tp->counters->tx_packets);
-+ mac_stats->SingleCollisionFrames =
-+ le32_to_cpu(tp->counters->tx_one_collision);
-+ mac_stats->MultipleCollisionFrames =
-+ le32_to_cpu(tp->counters->tx_multi_collision);
-+ mac_stats->FramesReceivedOK =
-+ le64_to_cpu(tp->counters->rx_packets);
-+ mac_stats->AlignmentErrors =
-+ le16_to_cpu(tp->counters->align_errors);
-+ mac_stats->FramesLostDueToIntMACXmitError =
-+ le64_to_cpu(tp->counters->tx_errors);
-+ mac_stats->BroadcastFramesReceivedOK =
-+ le64_to_cpu(tp->counters->rx_broadcast);
-+ mac_stats->MulticastFramesReceivedOK =
-+ le32_to_cpu(tp->counters->rx_multicast);
-+
-+ if (!rtl_is_8125(tp))
-+ return;
-+
-+ mac_stats->AlignmentErrors =
-+ le32_to_cpu(tp->counters->align_errors32);
-+ mac_stats->OctetsTransmittedOK =
-+ le64_to_cpu(tp->counters->tx_octets);
-+ mac_stats->LateCollisions =
-+ le32_to_cpu(tp->counters->tx_late_collision);
-+ mac_stats->FramesAbortedDueToXSColls =
-+ le32_to_cpu(tp->counters->tx_aborted32);
-+ mac_stats->OctetsReceivedOK =
-+ le64_to_cpu(tp->counters->rx_octets);
-+ mac_stats->FramesLostDueToIntMACRcvError =
-+ le32_to_cpu(tp->counters->rx_mac_error);
-+ mac_stats->MulticastFramesXmittedOK =
-+ le64_to_cpu(tp->counters->tx_multicast64);
-+ mac_stats->BroadcastFramesXmittedOK =
-+ le64_to_cpu(tp->counters->tx_broadcast64);
-+ mac_stats->MulticastFramesReceivedOK =
-+ le64_to_cpu(tp->counters->rx_multicast64);
-+ mac_stats->FrameTooLongErrors =
-+ le32_to_cpu(tp->counters->rx_frame_too_long);
-+}
-+
-+static void rtl8169_get_eth_ctrl_stats(struct net_device *dev,
-+ struct ethtool_eth_ctrl_stats *ctrl_stats)
-+{
-+ struct rtl8169_private *tp = netdev_priv(dev);
-+
-+ if (!rtl_is_8125(tp))
-+ return;
-+
-+ rtl8169_update_counters(tp);
-+
-+ ctrl_stats->UnsupportedOpcodesReceived =
-+ le32_to_cpu(tp->counters->rx_unknown_opcode);
-+}
-+
- static const struct ethtool_ops rtl8169_ethtool_ops = {
- .supported_coalesce_params = ETHTOOL_COALESCE_USECS |
- ETHTOOL_COALESCE_MAX_FRAMES,
-@@ -2208,8 +2284,11 @@ static const struct ethtool_ops rtl8169_
- .get_link_ksettings = phy_ethtool_get_link_ksettings,
- .set_link_ksettings = phy_ethtool_set_link_ksettings,
- .get_ringparam = rtl8169_get_ringparam,
-+ .get_pause_stats = rtl8169_get_pause_stats,
- .get_pauseparam = rtl8169_get_pauseparam,
- .set_pauseparam = rtl8169_set_pauseparam,
-+ .get_eth_mac_stats = rtl8169_get_eth_mac_stats,
-+ .get_eth_ctrl_stats = rtl8169_get_eth_ctrl_stats,
- };
-
- static enum mac_version rtl8169_get_mac_version(u16 xid, bool gmii)
-@@ -3894,6 +3973,9 @@ static void rtl_hw_start_8125(struct rtl
- break;
- }
-
-+ /* enable extended tally counter */
-+ r8168_mac_ocp_modify(tp, 0xea84, 0, BIT(1) | BIT(0));
-+
- rtl_hw_config(tp);
- }
-
+++ /dev/null
-From ac48430368c1a4f4e6c2fa92243b4b93fd25bee4 Mon Sep 17 00:00:00 2001
-Date: Wed, 16 Oct 2024 22:05:57 +0200
-Subject: [PATCH] r8169: don't take RTNL lock in rtl_task()
-
-There's not really a benefit here in taking the RTNL lock. The task
-handler does exception handling only, so we're in trouble anyway when
-we come here, and there's no need to protect against e.g. a parallel
-ethtool call.
-A benefit of removing the RTNL lock here is that we now can
-synchronously cancel the workqueue from a context holding the RTNL mutex.
-
----
- drivers/net/ethernet/realtek/r8169_main.c | 8 ++------
- 1 file changed, 2 insertions(+), 6 deletions(-)
-
---- a/drivers/net/ethernet/realtek/r8169_main.c
-+++ b/drivers/net/ethernet/realtek/r8169_main.c
-@@ -4801,10 +4801,8 @@ static void rtl_task(struct work_struct
- container_of(work, struct rtl8169_private, wk.work);
- int ret;
-
-- rtnl_lock();
--
- if (!test_bit(RTL_FLAG_TASK_ENABLED, tp->wk.flags))
-- goto out_unlock;
-+ return;
-
- if (test_and_clear_bit(RTL_FLAG_TASK_TX_TIMEOUT, tp->wk.flags)) {
- /* if chip isn't accessible, reset bus to revive it */
-@@ -4813,7 +4811,7 @@ static void rtl_task(struct work_struct
- if (ret < 0) {
- netdev_err(tp->dev, "Can't reset secondary PCI bus, detach NIC\n");
- netif_device_detach(tp->dev);
-- goto out_unlock;
-+ return;
- }
- }
-
-@@ -4832,8 +4830,6 @@ reset:
- } else if (test_and_clear_bit(RTL_FLAG_TASK_RESET_NO_QUEUE_WAKE, tp->wk.flags)) {
- rtl_reset_work(tp);
- }
--out_unlock:
-- rtnl_unlock();
- }
-
- static int rtl8169_poll(struct napi_struct *napi, int budget)
+++ /dev/null
-From 1c105bacb160b5918e917ab811552b7be69fc69c Mon Sep 17 00:00:00 2001
-Date: Wed, 16 Oct 2024 22:29:39 +0200
-Subject: [PATCH] r8169: avoid duplicated messages if loading firmware fails
- and switch to warn level
-
-In case of a problem with firmware loading we inform at the driver level,
-in addition the firmware load code itself issues warnings. Therefore
-switch to firmware_request_nowarn() to avoid duplicated error messages.
-In addition switch to warn level because the firmware is optional and
-typically just fixes compatibility issues.
-
----
- drivers/net/ethernet/realtek/r8169_firmware.c | 6 +++---
- 1 file changed, 3 insertions(+), 3 deletions(-)
-
---- a/drivers/net/ethernet/realtek/r8169_firmware.c
-+++ b/drivers/net/ethernet/realtek/r8169_firmware.c
-@@ -215,7 +215,7 @@ int rtl_fw_request_firmware(struct rtl_f
- {
- int rc;
-
-- rc = request_firmware(&rtl_fw->fw, rtl_fw->fw_name, rtl_fw->dev);
-+ rc = firmware_request_nowarn(&rtl_fw->fw, rtl_fw->fw_name, rtl_fw->dev);
- if (rc < 0)
- goto out;
-
-@@ -227,7 +227,7 @@ int rtl_fw_request_firmware(struct rtl_f
-
- return 0;
- out:
-- dev_err(rtl_fw->dev, "Unable to load firmware %s (%d)\n",
-- rtl_fw->fw_name, rc);
-+ dev_warn(rtl_fw->dev, "Unable to load firmware %s (%d)\n",
-+ rtl_fw->fw_name, rc);
- return rc;
- }
+++ /dev/null
-From d64113c6bb5ea5a70b7c9c3a6bcadef307638187 Mon Sep 17 00:00:00 2001
-Date: Wed, 16 Oct 2024 22:31:10 +0200
-Subject: [PATCH] r8169: remove rtl_dash_loop_wait_high/low
-
-Remove rtl_dash_loop_wait_high/low to simplify the code.
-
----
- drivers/net/ethernet/realtek/r8169_main.c | 35 ++++++-----------------
- 1 file changed, 8 insertions(+), 27 deletions(-)
-
---- a/drivers/net/ethernet/realtek/r8169_main.c
-+++ b/drivers/net/ethernet/realtek/r8169_main.c
-@@ -1346,40 +1346,19 @@ static void rtl8168ep_stop_cmac(struct r
- RTL_W8(tp, IBCR0, RTL_R8(tp, IBCR0) & ~0x01);
- }
-
--static void rtl_dash_loop_wait(struct rtl8169_private *tp,
-- const struct rtl_cond *c,
-- unsigned long usecs, int n, bool high)
--{
-- if (!tp->dash_enabled)
-- return;
-- rtl_loop_wait(tp, c, usecs, n, high);
--}
--
--static void rtl_dash_loop_wait_high(struct rtl8169_private *tp,
-- const struct rtl_cond *c,
-- unsigned long d, int n)
--{
-- rtl_dash_loop_wait(tp, c, d, n, true);
--}
--
--static void rtl_dash_loop_wait_low(struct rtl8169_private *tp,
-- const struct rtl_cond *c,
-- unsigned long d, int n)
--{
-- rtl_dash_loop_wait(tp, c, d, n, false);
--}
--
- static void rtl8168dp_driver_start(struct rtl8169_private *tp)
- {
- r8168dp_oob_notify(tp, OOB_CMD_DRIVER_START);
-- rtl_dash_loop_wait_high(tp, &rtl_dp_ocp_read_cond, 10000, 10);
-+ if (tp->dash_enabled)
-+ rtl_loop_wait_high(tp, &rtl_dp_ocp_read_cond, 10000, 10);
- }
-
- static void rtl8168ep_driver_start(struct rtl8169_private *tp)
- {
- r8168ep_ocp_write(tp, 0x01, 0x180, OOB_CMD_DRIVER_START);
- r8168ep_ocp_write(tp, 0x01, 0x30, r8168ep_ocp_read(tp, 0x30) | 0x01);
-- rtl_dash_loop_wait_high(tp, &rtl_ep_ocp_read_cond, 10000, 30);
-+ if (tp->dash_enabled)
-+ rtl_loop_wait_high(tp, &rtl_ep_ocp_read_cond, 10000, 30);
- }
-
- static void rtl8168_driver_start(struct rtl8169_private *tp)
-@@ -1393,7 +1372,8 @@ static void rtl8168_driver_start(struct
- static void rtl8168dp_driver_stop(struct rtl8169_private *tp)
- {
- r8168dp_oob_notify(tp, OOB_CMD_DRIVER_STOP);
-- rtl_dash_loop_wait_low(tp, &rtl_dp_ocp_read_cond, 10000, 10);
-+ if (tp->dash_enabled)
-+ rtl_loop_wait_low(tp, &rtl_dp_ocp_read_cond, 10000, 10);
- }
-
- static void rtl8168ep_driver_stop(struct rtl8169_private *tp)
-@@ -1401,7 +1381,8 @@ static void rtl8168ep_driver_stop(struct
- rtl8168ep_stop_cmac(tp);
- r8168ep_ocp_write(tp, 0x01, 0x180, OOB_CMD_DRIVER_STOP);
- r8168ep_ocp_write(tp, 0x01, 0x30, r8168ep_ocp_read(tp, 0x30) | 0x01);
-- rtl_dash_loop_wait_low(tp, &rtl_ep_ocp_read_cond, 10000, 10);
-+ if (tp->dash_enabled)
-+ rtl_loop_wait_low(tp, &rtl_ep_ocp_read_cond, 10000, 10);
- }
-
- static void rtl8168_driver_stop(struct rtl8169_private *tp)
+++ /dev/null
-From c4e64095c00cb2de413cd6b90be047c273bcd491 Mon Sep 17 00:00:00 2001
-Date: Thu, 17 Oct 2024 22:27:44 +0200
-Subject: [PATCH] r8169: enable EEE at 2.5G per default on RTL8125B
-
-Register a6d/12 is shadowing register MDIO_AN_EEE_ADV2. So this line
-disables advertisement of EEE at 2.5G. Latest vendor driver r8125
-doesn't do this (any longer?), so this mode seems to be safe.
-EEE saves quite some energy, therefore enable this mode per default.
-
----
- drivers/net/ethernet/realtek/r8169_phy_config.c | 1 -
- 1 file changed, 1 deletion(-)
-
---- a/drivers/net/ethernet/realtek/r8169_phy_config.c
-+++ b/drivers/net/ethernet/realtek/r8169_phy_config.c
-@@ -99,7 +99,6 @@ static void rtl8125a_config_eee_phy(stru
-
- static void rtl8125b_config_eee_phy(struct phy_device *phydev)
- {
-- phy_modify_paged(phydev, 0xa6d, 0x12, 0x0001, 0x0000);
- phy_modify_paged(phydev, 0xa6d, 0x14, 0x0010, 0x0000);
- phy_modify_paged(phydev, 0xa42, 0x14, 0x0080, 0x0000);
- phy_modify_paged(phydev, 0xa4a, 0x11, 0x0200, 0x0000);
+++ /dev/null
-From f75d1fbe7809bc5ed134204b920fd9e2fc5db1df Mon Sep 17 00:00:00 2001
-Date: Thu, 24 Oct 2024 22:42:33 +0200
-Subject: [PATCH] r8169: add support for RTL8125D
-
-This adds support for new chip version RTL8125D, which can be found on
-boards like Gigabyte X870E AORUS ELITE WIFI7. Firmware rtl8125d-1.fw
-for this chip version is available in linux-firmware already.
-
----
- drivers/net/ethernet/realtek/r8169.h | 1 +
- drivers/net/ethernet/realtek/r8169_main.c | 23 +++++++++++++------
- .../net/ethernet/realtek/r8169_phy_config.c | 10 ++++++++
- 3 files changed, 27 insertions(+), 7 deletions(-)
-
---- a/drivers/net/ethernet/realtek/r8169.h
-+++ b/drivers/net/ethernet/realtek/r8169.h
-@@ -68,6 +68,7 @@ enum mac_version {
- /* support for RTL_GIGA_MAC_VER_60 has been removed */
- RTL_GIGA_MAC_VER_61,
- RTL_GIGA_MAC_VER_63,
-+ RTL_GIGA_MAC_VER_64,
- RTL_GIGA_MAC_VER_65,
- RTL_GIGA_MAC_VER_66,
- RTL_GIGA_MAC_NONE
---- a/drivers/net/ethernet/realtek/r8169_main.c
-+++ b/drivers/net/ethernet/realtek/r8169_main.c
-@@ -55,6 +55,7 @@
- #define FIRMWARE_8107E_2 "rtl_nic/rtl8107e-2.fw"
- #define FIRMWARE_8125A_3 "rtl_nic/rtl8125a-3.fw"
- #define FIRMWARE_8125B_2 "rtl_nic/rtl8125b-2.fw"
-+#define FIRMWARE_8125D_1 "rtl_nic/rtl8125d-1.fw"
- #define FIRMWARE_8126A_2 "rtl_nic/rtl8126a-2.fw"
- #define FIRMWARE_8126A_3 "rtl_nic/rtl8126a-3.fw"
-
-@@ -138,6 +139,7 @@ static const struct {
- [RTL_GIGA_MAC_VER_61] = {"RTL8125A", FIRMWARE_8125A_3},
- /* reserve 62 for CFG_METHOD_4 in the vendor driver */
- [RTL_GIGA_MAC_VER_63] = {"RTL8125B", FIRMWARE_8125B_2},
-+ [RTL_GIGA_MAC_VER_64] = {"RTL8125D", FIRMWARE_8125D_1},
- [RTL_GIGA_MAC_VER_65] = {"RTL8126A", FIRMWARE_8126A_2},
- [RTL_GIGA_MAC_VER_66] = {"RTL8126A", FIRMWARE_8126A_3},
- };
-@@ -707,6 +709,7 @@ MODULE_FIRMWARE(FIRMWARE_8168FP_3);
- MODULE_FIRMWARE(FIRMWARE_8107E_2);
- MODULE_FIRMWARE(FIRMWARE_8125A_3);
- MODULE_FIRMWARE(FIRMWARE_8125B_2);
-+MODULE_FIRMWARE(FIRMWARE_8125D_1);
- MODULE_FIRMWARE(FIRMWARE_8126A_2);
- MODULE_FIRMWARE(FIRMWARE_8126A_3);
-
-@@ -2079,10 +2082,7 @@ static void rtl_set_eee_txidle_timer(str
- tp->tx_lpi_timer = timer_val;
- r8168_mac_ocp_write(tp, 0xe048, timer_val);
- break;
-- case RTL_GIGA_MAC_VER_61:
-- case RTL_GIGA_MAC_VER_63:
-- case RTL_GIGA_MAC_VER_65:
-- case RTL_GIGA_MAC_VER_66:
-+ case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_66:
- tp->tx_lpi_timer = timer_val;
- RTL_W16(tp, EEE_TXIDLE_TIMER_8125, timer_val);
- break;
-@@ -2294,6 +2294,9 @@ static enum mac_version rtl8169_get_mac_
- { 0x7cf, 0x64a, RTL_GIGA_MAC_VER_66 },
- { 0x7cf, 0x649, RTL_GIGA_MAC_VER_65 },
-
-+ /* 8125D family. */
-+ { 0x7cf, 0x688, RTL_GIGA_MAC_VER_64 },
-+
- /* 8125B family. */
- { 0x7cf, 0x641, RTL_GIGA_MAC_VER_63 },
-
-@@ -2561,9 +2564,7 @@ static void rtl_init_rxcfg(struct rtl816
- case RTL_GIGA_MAC_VER_61:
- RTL_W32(tp, RxConfig, RX_FETCH_DFLT_8125 | RX_DMA_BURST);
- break;
-- case RTL_GIGA_MAC_VER_63:
-- case RTL_GIGA_MAC_VER_65:
-- case RTL_GIGA_MAC_VER_66:
-+ case RTL_GIGA_MAC_VER_63 ... RTL_GIGA_MAC_VER_66:
- RTL_W32(tp, RxConfig, RX_FETCH_DFLT_8125 | RX_DMA_BURST |
- RX_PAUSE_SLOT_ON);
- break;
-@@ -3875,6 +3876,12 @@ static void rtl_hw_start_8125b(struct rt
- rtl_hw_start_8125_common(tp);
- }
-
-+static void rtl_hw_start_8125d(struct rtl8169_private *tp)
-+{
-+ rtl_set_def_aspm_entry_latency(tp);
-+ rtl_hw_start_8125_common(tp);
-+}
-+
- static void rtl_hw_start_8126a(struct rtl8169_private *tp)
- {
- rtl_set_def_aspm_entry_latency(tp);
-@@ -3923,6 +3930,7 @@ static void rtl_hw_config(struct rtl8169
- [RTL_GIGA_MAC_VER_53] = rtl_hw_start_8117,
- [RTL_GIGA_MAC_VER_61] = rtl_hw_start_8125a_2,
- [RTL_GIGA_MAC_VER_63] = rtl_hw_start_8125b,
-+ [RTL_GIGA_MAC_VER_64] = rtl_hw_start_8125d,
- [RTL_GIGA_MAC_VER_65] = rtl_hw_start_8126a,
- [RTL_GIGA_MAC_VER_66] = rtl_hw_start_8126a,
- };
-@@ -3940,6 +3948,7 @@ static void rtl_hw_start_8125(struct rtl
- /* disable interrupt coalescing */
- switch (tp->mac_version) {
- case RTL_GIGA_MAC_VER_61:
-+ case RTL_GIGA_MAC_VER_64:
- for (i = 0xa00; i < 0xb00; i += 4)
- RTL_W32(tp, i, 0);
- break;
---- a/drivers/net/ethernet/realtek/r8169_phy_config.c
-+++ b/drivers/net/ethernet/realtek/r8169_phy_config.c
-@@ -1103,6 +1103,15 @@ static void rtl8125b_hw_phy_config(struc
- rtl8125b_config_eee_phy(phydev);
- }
-
-+static void rtl8125d_hw_phy_config(struct rtl8169_private *tp,
-+ struct phy_device *phydev)
-+{
-+ r8169_apply_firmware(tp);
-+ rtl8125_legacy_force_mode(phydev);
-+ rtl8168g_disable_aldps(phydev);
-+ rtl8125b_config_eee_phy(phydev);
-+}
-+
- static void rtl8126a_hw_phy_config(struct rtl8169_private *tp,
- struct phy_device *phydev)
- {
-@@ -1159,6 +1168,7 @@ void r8169_hw_phy_config(struct rtl8169_
- [RTL_GIGA_MAC_VER_53] = rtl8117_hw_phy_config,
- [RTL_GIGA_MAC_VER_61] = rtl8125a_2_hw_phy_config,
- [RTL_GIGA_MAC_VER_63] = rtl8125b_hw_phy_config,
-+ [RTL_GIGA_MAC_VER_64] = rtl8125d_hw_phy_config,
- [RTL_GIGA_MAC_VER_65] = rtl8126a_hw_phy_config,
- [RTL_GIGA_MAC_VER_66] = rtl8126a_hw_phy_config,
- };
+++ /dev/null
-From b8bd8c44a266c9a7dcb907eab10fbb119e3f6494 Mon Sep 17 00:00:00 2001
-Date: Thu, 24 Oct 2024 22:48:59 +0200
-Subject: [PATCH] r8169: fix inconsistent indenting in
- rtl8169_get_eth_mac_stats
-
-This fixes an inconsistent indenting introduced with e3fc5139bd8f
-("r8169: implement additional ethtool stats ops").
-
----
- drivers/net/ethernet/realtek/r8169_main.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/net/ethernet/realtek/r8169_main.c
-+++ b/drivers/net/ethernet/realtek/r8169_main.c
-@@ -2226,7 +2226,7 @@ static void rtl8169_get_eth_mac_stats(st
- le64_to_cpu(tp->counters->tx_broadcast64);
- mac_stats->MulticastFramesReceivedOK =
- le64_to_cpu(tp->counters->rx_multicast64);
-- mac_stats->FrameTooLongErrors =
-+ mac_stats->FrameTooLongErrors =
- le32_to_cpu(tp->counters->rx_frame_too_long);
- }
-
+++ /dev/null
-From eb90f876b7961d702d7fc549e14614860f531e60 Mon Sep 17 00:00:00 2001
-Date: Thu, 31 Oct 2024 22:42:52 +0100
-Subject: [PATCH] r8169: align RTL8125 EEE config with vendor driver
-
-Align the EEE config for RTL8125A/RTL8125B with vendor driver r8125.
-This should help to avoid compatibility issues.
-
----
- .../net/ethernet/realtek/r8169_phy_config.c | 18 ++++++++++++------
- 1 file changed, 12 insertions(+), 6 deletions(-)
-
---- a/drivers/net/ethernet/realtek/r8169_phy_config.c
-+++ b/drivers/net/ethernet/realtek/r8169_phy_config.c
-@@ -89,19 +89,25 @@ static void rtl8168h_config_eee_phy(stru
- phy_modify_paged(phydev, 0xa42, 0x14, 0x0000, 0x0080);
- }
-
--static void rtl8125a_config_eee_phy(struct phy_device *phydev)
-+static void rtl8125_common_config_eee_phy(struct phy_device *phydev)
- {
-- rtl8168h_config_eee_phy(phydev);
-+ phy_modify_paged(phydev, 0xa6d, 0x14, 0x0010, 0x0000);
-+ phy_modify_paged(phydev, 0xa42, 0x14, 0x0080, 0x0000);
-+ phy_modify_paged(phydev, 0xa4a, 0x11, 0x0200, 0x0000);
-+}
-
-+static void rtl8125a_config_eee_phy(struct phy_device *phydev)
-+{
-+ rtl8168g_config_eee_phy(phydev);
-+ /* disable EEE at 2.5Gbps */
- phy_modify_paged(phydev, 0xa6d, 0x12, 0x0001, 0x0000);
-- phy_modify_paged(phydev, 0xa6d, 0x14, 0x0010, 0x0000);
-+ rtl8125_common_config_eee_phy(phydev);
- }
-
- static void rtl8125b_config_eee_phy(struct phy_device *phydev)
- {
-- phy_modify_paged(phydev, 0xa6d, 0x14, 0x0010, 0x0000);
-- phy_modify_paged(phydev, 0xa42, 0x14, 0x0080, 0x0000);
-- phy_modify_paged(phydev, 0xa4a, 0x11, 0x0200, 0x0000);
-+ rtl8168g_config_eee_phy(phydev);
-+ rtl8125_common_config_eee_phy(phydev);
- }
-
- static void rtl8169s_hw_phy_config(struct rtl8169_private *tp,
+++ /dev/null
-From 4af2f60bf7378bd5c92b15a528d8c6c7d02bed6c Mon Sep 17 00:00:00 2001
-Date: Thu, 31 Oct 2024 22:43:45 +0100
-Subject: [PATCH] r8169: align RTL8125/RTL8126 PHY config with vendor driver
-
-This aligns some parameters with vendor driver r8125/r8126 to avoid
-compatibility issues. Note that for RTL8125B there's no functional
-change, just the open-coded version of the function is replaced.
-
----
- drivers/net/ethernet/realtek/r8169_phy_config.c | 6 +++++-
- 1 file changed, 5 insertions(+), 1 deletion(-)
-
---- a/drivers/net/ethernet/realtek/r8169_phy_config.c
-+++ b/drivers/net/ethernet/realtek/r8169_phy_config.c
-@@ -1073,8 +1073,8 @@ static void rtl8125b_hw_phy_config(struc
- struct phy_device *phydev)
- {
- r8169_apply_firmware(tp);
-+ rtl8168g_enable_gphy_10m(phydev);
-
-- phy_modify_paged(phydev, 0xa44, 0x11, 0x0000, 0x0800);
- phy_modify_paged(phydev, 0xac4, 0x13, 0x00f0, 0x0090);
- phy_modify_paged(phydev, 0xad3, 0x10, 0x0003, 0x0001);
-
-@@ -1113,6 +1113,7 @@ static void rtl8125d_hw_phy_config(struc
- struct phy_device *phydev)
- {
- r8169_apply_firmware(tp);
-+ rtl8168g_enable_gphy_10m(phydev);
- rtl8125_legacy_force_mode(phydev);
- rtl8168g_disable_aldps(phydev);
- rtl8125b_config_eee_phy(phydev);
-@@ -1122,6 +1123,9 @@ static void rtl8126a_hw_phy_config(struc
- struct phy_device *phydev)
- {
- r8169_apply_firmware(tp);
-+ rtl8168g_enable_gphy_10m(phydev);
-+ rtl8125_legacy_force_mode(phydev);
-+ rtl8168g_disable_aldps(phydev);
- }
-
- void r8169_hw_phy_config(struct rtl8169_private *tp, struct phy_device *phydev,
+++ /dev/null
-From a3d8520e6a19ab018da6c7fc22512c913697a829 Mon Sep 17 00:00:00 2001
-Date: Thu, 31 Oct 2024 22:44:36 +0100
-Subject: [PATCH] r8169: align RTL8126 EEE config with vendor driver
-
-Align the EEE config for RTL8126A with vendor driver r8126 to avoid
-compatibility issues.
-
----
- drivers/net/ethernet/realtek/r8169_phy_config.c | 1 +
- 1 file changed, 1 insertion(+)
-
---- a/drivers/net/ethernet/realtek/r8169_phy_config.c
-+++ b/drivers/net/ethernet/realtek/r8169_phy_config.c
-@@ -1126,6 +1126,7 @@ static void rtl8126a_hw_phy_config(struc
- rtl8168g_enable_gphy_10m(phydev);
- rtl8125_legacy_force_mode(phydev);
- rtl8168g_disable_aldps(phydev);
-+ rtl8125_common_config_eee_phy(phydev);
- }
-
- void r8169_hw_phy_config(struct rtl8169_private *tp, struct phy_device *phydev,
+++ /dev/null
-From 2cd02f2fdd8a92e5b6b85ff64eab0fc549b30c07 Mon Sep 17 00:00:00 2001
-Date: Sat, 2 Nov 2024 14:49:01 +0100
-Subject: [PATCH] r8169: improve initialization of RSS registers on
- RTL8125/RTL8126
-
-Replace the register addresses with the names used in r8125/r8126
-vendor driver, and consider that RSS_CTRL_8125 is a 32 bit register.
-
----
- drivers/net/ethernet/realtek/r8169_main.c | 6 ++++--
- 1 file changed, 4 insertions(+), 2 deletions(-)
-
---- a/drivers/net/ethernet/realtek/r8169_main.c
-+++ b/drivers/net/ethernet/realtek/r8169_main.c
-@@ -346,6 +346,8 @@ enum rtl8125_registers {
- TxPoll_8125 = 0x90,
- LEDSEL3 = 0x96,
- MAC0_BKP = 0x19e0,
-+ RSS_CTRL_8125 = 0x4500,
-+ Q_NUM_CTRL_8125 = 0x4800,
- EEE_TXIDLE_TIMER_8125 = 0x6048,
- };
-
-@@ -3769,8 +3771,8 @@ static void rtl_hw_start_8125_common(str
- rtl_pcie_state_l2l3_disable(tp);
-
- RTL_W16(tp, 0x382, 0x221b);
-- RTL_W8(tp, 0x4500, 0);
-- RTL_W16(tp, 0x4800, 0);
-+ RTL_W32(tp, RSS_CTRL_8125, 0);
-+ RTL_W16(tp, Q_NUM_CTRL_8125, 0);
-
- /* disable UPS */
- r8168_mac_ocp_modify(tp, 0xd40a, 0x0010, 0x0000);
+++ /dev/null
-From 83cb4b470c66b37b19a347a35cea01e0cbdd258d Mon Sep 17 00:00:00 2001
-Date: Mon, 4 Nov 2024 23:16:20 +0100
-Subject: [PATCH] r8169: remove leftover locks after reverted change
-
-After e31a9fedc7d8 ("Revert "r8169: disable ASPM during NAPI poll"")
-these locks aren't needed any longer.
-
----
- drivers/net/ethernet/realtek/r8169_main.c | 29 ++---------------------
- 1 file changed, 2 insertions(+), 27 deletions(-)
-
---- a/drivers/net/ethernet/realtek/r8169_main.c
-+++ b/drivers/net/ethernet/realtek/r8169_main.c
-@@ -662,13 +662,9 @@ struct rtl8169_private {
- struct work_struct work;
- } wk;
-
-- raw_spinlock_t config25_lock;
- raw_spinlock_t mac_ocp_lock;
- struct mutex led_lock; /* serialize LED ctrl RMW access */
-
-- raw_spinlock_t cfg9346_usage_lock;
-- int cfg9346_usage_count;
--
- unsigned supports_gmii:1;
- unsigned aspm_manageable:1;
- unsigned dash_enabled:1;
-@@ -722,22 +718,12 @@ static inline struct device *tp_to_dev(s
-
- static void rtl_lock_config_regs(struct rtl8169_private *tp)
- {
-- unsigned long flags;
--
-- raw_spin_lock_irqsave(&tp->cfg9346_usage_lock, flags);
-- if (!--tp->cfg9346_usage_count)
-- RTL_W8(tp, Cfg9346, Cfg9346_Lock);
-- raw_spin_unlock_irqrestore(&tp->cfg9346_usage_lock, flags);
-+ RTL_W8(tp, Cfg9346, Cfg9346_Lock);
- }
-
- static void rtl_unlock_config_regs(struct rtl8169_private *tp)
- {
-- unsigned long flags;
--
-- raw_spin_lock_irqsave(&tp->cfg9346_usage_lock, flags);
-- if (!tp->cfg9346_usage_count++)
-- RTL_W8(tp, Cfg9346, Cfg9346_Unlock);
-- raw_spin_unlock_irqrestore(&tp->cfg9346_usage_lock, flags);
-+ RTL_W8(tp, Cfg9346, Cfg9346_Unlock);
- }
-
- static void rtl_pci_commit(struct rtl8169_private *tp)
-@@ -748,24 +734,18 @@ static void rtl_pci_commit(struct rtl816
-
- static void rtl_mod_config2(struct rtl8169_private *tp, u8 clear, u8 set)
- {
-- unsigned long flags;
- u8 val;
-
-- raw_spin_lock_irqsave(&tp->config25_lock, flags);
- val = RTL_R8(tp, Config2);
- RTL_W8(tp, Config2, (val & ~clear) | set);
-- raw_spin_unlock_irqrestore(&tp->config25_lock, flags);
- }
-
- static void rtl_mod_config5(struct rtl8169_private *tp, u8 clear, u8 set)
- {
-- unsigned long flags;
- u8 val;
-
-- raw_spin_lock_irqsave(&tp->config25_lock, flags);
- val = RTL_R8(tp, Config5);
- RTL_W8(tp, Config5, (val & ~clear) | set);
-- raw_spin_unlock_irqrestore(&tp->config25_lock, flags);
- }
-
- static bool rtl_is_8125(struct rtl8169_private *tp)
-@@ -1571,7 +1551,6 @@ static void __rtl8169_set_wol(struct rtl
- { WAKE_MAGIC, Config3, MagicPacket }
- };
- unsigned int i, tmp = ARRAY_SIZE(cfg);
-- unsigned long flags;
- u8 options;
-
- rtl_unlock_config_regs(tp);
-@@ -1590,14 +1569,12 @@ static void __rtl8169_set_wol(struct rtl
- r8168_mac_ocp_modify(tp, 0xc0b6, BIT(0), 0);
- }
-
-- raw_spin_lock_irqsave(&tp->config25_lock, flags);
- for (i = 0; i < tmp; i++) {
- options = RTL_R8(tp, cfg[i].reg) & ~cfg[i].mask;
- if (wolopts & cfg[i].opt)
- options |= cfg[i].mask;
- RTL_W8(tp, cfg[i].reg, options);
- }
-- raw_spin_unlock_irqrestore(&tp->config25_lock, flags);
-
- switch (tp->mac_version) {
- case RTL_GIGA_MAC_VER_02 ... RTL_GIGA_MAC_VER_06:
-@@ -5462,8 +5439,6 @@ static int rtl_init_one(struct pci_dev *
- tp->supports_gmii = ent->driver_data == RTL_CFG_NO_GBIT ? 0 : 1;
- tp->ocp_base = OCP_STD_PHY_BASE;
-
-- raw_spin_lock_init(&tp->cfg9346_usage_lock);
-- raw_spin_lock_init(&tp->config25_lock);
- raw_spin_lock_init(&tp->mac_ocp_lock);
- mutex_init(&tp->led_lock);
-
+++ /dev/null
-From c507e96b5763b36b63ad50ad804341f72ea000e4 Mon Sep 17 00:00:00 2001
-Date: Wed, 6 Nov 2024 17:55:45 +0100
-Subject: [PATCH] r8169: improve __rtl8169_set_wol
-
-Add helper r8169_mod_reg8_cond() what allows to significantly simplify
-__rtl8169_set_wol().
-
----
- drivers/net/ethernet/realtek/r8169_main.c | 55 ++++++++++-------------
- 1 file changed, 24 insertions(+), 31 deletions(-)
-
---- a/drivers/net/ethernet/realtek/r8169_main.c
-+++ b/drivers/net/ethernet/realtek/r8169_main.c
-@@ -748,6 +748,20 @@ static void rtl_mod_config5(struct rtl81
- RTL_W8(tp, Config5, (val & ~clear) | set);
- }
-
-+static void r8169_mod_reg8_cond(struct rtl8169_private *tp, int reg,
-+ u8 bits, bool cond)
-+{
-+ u8 val, old_val;
-+
-+ old_val = RTL_R8(tp, reg);
-+ if (cond)
-+ val = old_val | bits;
-+ else
-+ val = old_val & ~bits;
-+ if (val != old_val)
-+ RTL_W8(tp, reg, val);
-+}
-+
- static bool rtl_is_8125(struct rtl8169_private *tp)
- {
- return tp->mac_version >= RTL_GIGA_MAC_VER_61;
-@@ -1538,58 +1552,37 @@ static void rtl8169_get_wol(struct net_d
-
- static void __rtl8169_set_wol(struct rtl8169_private *tp, u32 wolopts)
- {
-- static const struct {
-- u32 opt;
-- u16 reg;
-- u8 mask;
-- } cfg[] = {
-- { WAKE_PHY, Config3, LinkUp },
-- { WAKE_UCAST, Config5, UWF },
-- { WAKE_BCAST, Config5, BWF },
-- { WAKE_MCAST, Config5, MWF },
-- { WAKE_ANY, Config5, LanWake },
-- { WAKE_MAGIC, Config3, MagicPacket }
-- };
-- unsigned int i, tmp = ARRAY_SIZE(cfg);
-- u8 options;
--
- rtl_unlock_config_regs(tp);
-
- if (rtl_is_8168evl_up(tp)) {
-- tmp--;
- if (wolopts & WAKE_MAGIC)
- rtl_eri_set_bits(tp, 0x0dc, MagicPacket_v2);
- else
- rtl_eri_clear_bits(tp, 0x0dc, MagicPacket_v2);
- } else if (rtl_is_8125(tp)) {
-- tmp--;
- if (wolopts & WAKE_MAGIC)
- r8168_mac_ocp_modify(tp, 0xc0b6, 0, BIT(0));
- else
- r8168_mac_ocp_modify(tp, 0xc0b6, BIT(0), 0);
-+ } else {
-+ r8169_mod_reg8_cond(tp, Config3, MagicPacket,
-+ wolopts & WAKE_MAGIC);
- }
-
-- for (i = 0; i < tmp; i++) {
-- options = RTL_R8(tp, cfg[i].reg) & ~cfg[i].mask;
-- if (wolopts & cfg[i].opt)
-- options |= cfg[i].mask;
-- RTL_W8(tp, cfg[i].reg, options);
-- }
-+ r8169_mod_reg8_cond(tp, Config3, LinkUp, wolopts & WAKE_PHY);
-+ r8169_mod_reg8_cond(tp, Config5, UWF, wolopts & WAKE_UCAST);
-+ r8169_mod_reg8_cond(tp, Config5, BWF, wolopts & WAKE_BCAST);
-+ r8169_mod_reg8_cond(tp, Config5, MWF, wolopts & WAKE_MCAST);
-+ r8169_mod_reg8_cond(tp, Config5, LanWake, wolopts);
-
- switch (tp->mac_version) {
- case RTL_GIGA_MAC_VER_02 ... RTL_GIGA_MAC_VER_06:
-- options = RTL_R8(tp, Config1) & ~PMEnable;
-- if (wolopts)
-- options |= PMEnable;
-- RTL_W8(tp, Config1, options);
-+ r8169_mod_reg8_cond(tp, Config1, PMEnable, wolopts);
- break;
- case RTL_GIGA_MAC_VER_34:
- case RTL_GIGA_MAC_VER_37:
- case RTL_GIGA_MAC_VER_39 ... RTL_GIGA_MAC_VER_66:
-- if (wolopts)
-- rtl_mod_config2(tp, 0, PME_SIGNAL);
-- else
-- rtl_mod_config2(tp, PME_SIGNAL, 0);
-+ r8169_mod_reg8_cond(tp, Config2, PME_SIGNAL, wolopts);
- break;
- default:
- break;
+++ /dev/null
-From 330dc2297c82953dff402e0b4176a5383a618538 Mon Sep 17 00:00:00 2001
-Date: Wed, 6 Nov 2024 17:56:28 +0100
-Subject: [PATCH] r8169: improve rtl_set_d3_pll_down
-
-Make use of new helper r8169_mod_reg8_cond() and move from a switch()
-to an if() clause. Benefit is that we don't have to touch this piece of
-code each time support for a new chip version is added.
-
----
- drivers/net/ethernet/realtek/r8169_main.c | 18 +++++-------------
- 1 file changed, 5 insertions(+), 13 deletions(-)
-
---- a/drivers/net/ethernet/realtek/r8169_main.c
-+++ b/drivers/net/ethernet/realtek/r8169_main.c
-@@ -1431,19 +1431,11 @@ static enum rtl_dash_type rtl_get_dash_t
-
- static void rtl_set_d3_pll_down(struct rtl8169_private *tp, bool enable)
- {
-- switch (tp->mac_version) {
-- case RTL_GIGA_MAC_VER_25 ... RTL_GIGA_MAC_VER_26:
-- case RTL_GIGA_MAC_VER_29 ... RTL_GIGA_MAC_VER_30:
-- case RTL_GIGA_MAC_VER_32 ... RTL_GIGA_MAC_VER_37:
-- case RTL_GIGA_MAC_VER_39 ... RTL_GIGA_MAC_VER_66:
-- if (enable)
-- RTL_W8(tp, PMCH, RTL_R8(tp, PMCH) & ~D3_NO_PLL_DOWN);
-- else
-- RTL_W8(tp, PMCH, RTL_R8(tp, PMCH) | D3_NO_PLL_DOWN);
-- break;
-- default:
-- break;
-- }
-+ if (tp->mac_version >= RTL_GIGA_MAC_VER_25 &&
-+ tp->mac_version != RTL_GIGA_MAC_VER_28 &&
-+ tp->mac_version != RTL_GIGA_MAC_VER_31 &&
-+ tp->mac_version != RTL_GIGA_MAC_VER_38)
-+ r8169_mod_reg8_cond(tp, PMCH, D3_NO_PLL_DOWN, !enable);
- }
-
- static void rtl_reset_packet_filter(struct rtl8169_private *tp)
+++ /dev/null
-From e3e9e9039fa6ae885c7d5c954d7b9f105fa23e8f Mon Sep 17 00:00:00 2001
-Date: Wed, 6 Nov 2024 17:57:08 +0100
-Subject: [PATCH] r8169: align WAKE_PHY handling with r8125/r8126 vendor
- drivers
-
-Vendor drivers r8125/r8126 apply this additional magic setting when
-enabling WAKE_PHY, so do the same here.
-
----
- drivers/net/ethernet/realtek/r8169_main.c | 3 +++
- 1 file changed, 3 insertions(+)
-
---- a/drivers/net/ethernet/realtek/r8169_main.c
-+++ b/drivers/net/ethernet/realtek/r8169_main.c
-@@ -1562,6 +1562,9 @@ static void __rtl8169_set_wol(struct rtl
- }
-
- r8169_mod_reg8_cond(tp, Config3, LinkUp, wolopts & WAKE_PHY);
-+ if (rtl_is_8125(tp))
-+ r8168_mac_ocp_modify(tp, 0xe0c6, 0x3f,
-+ wolopts & WAKE_PHY ? 0x13 : 0);
- r8169_mod_reg8_cond(tp, Config5, UWF, wolopts & WAKE_UCAST);
- r8169_mod_reg8_cond(tp, Config5, BWF, wolopts & WAKE_BCAST);
- r8169_mod_reg8_cond(tp, Config5, MWF, wolopts & WAKE_MCAST);
+++ /dev/null
-From 7a3bcd39ae1f0e3ab896d9df62339ab4297a0bfd Mon Sep 17 00:00:00 2001
-Date: Sat, 9 Nov 2024 23:12:12 +0100
-Subject: [PATCH] r8169: use helper r8169_mod_reg8_cond to simplify
- rtl_jumbo_config
-
-Use recently added helper r8169_mod_reg8_cond() to simplify jumbo
-mode configuration.
-
----
- drivers/net/ethernet/realtek/r8169_main.c | 77 ++++-------------------
- 1 file changed, 11 insertions(+), 66 deletions(-)
-
---- a/drivers/net/ethernet/realtek/r8169_main.c
-+++ b/drivers/net/ethernet/realtek/r8169_main.c
-@@ -2546,86 +2546,31 @@ static void rtl8169_init_ring_indexes(st
- tp->dirty_tx = tp->cur_tx = tp->cur_rx = 0;
- }
-
--static void r8168c_hw_jumbo_enable(struct rtl8169_private *tp)
--{
-- RTL_W8(tp, Config3, RTL_R8(tp, Config3) | Jumbo_En0);
-- RTL_W8(tp, Config4, RTL_R8(tp, Config4) | Jumbo_En1);
--}
--
--static void r8168c_hw_jumbo_disable(struct rtl8169_private *tp)
--{
-- RTL_W8(tp, Config3, RTL_R8(tp, Config3) & ~Jumbo_En0);
-- RTL_W8(tp, Config4, RTL_R8(tp, Config4) & ~Jumbo_En1);
--}
--
--static void r8168dp_hw_jumbo_enable(struct rtl8169_private *tp)
--{
-- RTL_W8(tp, Config3, RTL_R8(tp, Config3) | Jumbo_En0);
--}
--
--static void r8168dp_hw_jumbo_disable(struct rtl8169_private *tp)
--{
-- RTL_W8(tp, Config3, RTL_R8(tp, Config3) & ~Jumbo_En0);
--}
--
--static void r8168e_hw_jumbo_enable(struct rtl8169_private *tp)
--{
-- RTL_W8(tp, MaxTxPacketSize, 0x24);
-- RTL_W8(tp, Config3, RTL_R8(tp, Config3) | Jumbo_En0);
-- RTL_W8(tp, Config4, RTL_R8(tp, Config4) | 0x01);
--}
--
--static void r8168e_hw_jumbo_disable(struct rtl8169_private *tp)
--{
-- RTL_W8(tp, MaxTxPacketSize, 0x3f);
-- RTL_W8(tp, Config3, RTL_R8(tp, Config3) & ~Jumbo_En0);
-- RTL_W8(tp, Config4, RTL_R8(tp, Config4) & ~0x01);
--}
--
--static void r8168b_1_hw_jumbo_enable(struct rtl8169_private *tp)
--{
-- RTL_W8(tp, Config4, RTL_R8(tp, Config4) | (1 << 0));
--}
--
--static void r8168b_1_hw_jumbo_disable(struct rtl8169_private *tp)
--{
-- RTL_W8(tp, Config4, RTL_R8(tp, Config4) & ~(1 << 0));
--}
--
- static void rtl_jumbo_config(struct rtl8169_private *tp)
- {
- bool jumbo = tp->dev->mtu > ETH_DATA_LEN;
- int readrq = 4096;
-
-+ if (jumbo && tp->mac_version >= RTL_GIGA_MAC_VER_17 &&
-+ tp->mac_version <= RTL_GIGA_MAC_VER_26)
-+ readrq = 512;
-+
- rtl_unlock_config_regs(tp);
- switch (tp->mac_version) {
- case RTL_GIGA_MAC_VER_17:
-- if (jumbo) {
-- readrq = 512;
-- r8168b_1_hw_jumbo_enable(tp);
-- } else {
-- r8168b_1_hw_jumbo_disable(tp);
-- }
-+ r8169_mod_reg8_cond(tp, Config4, BIT(0), jumbo);
- break;
- case RTL_GIGA_MAC_VER_18 ... RTL_GIGA_MAC_VER_26:
-- if (jumbo) {
-- readrq = 512;
-- r8168c_hw_jumbo_enable(tp);
-- } else {
-- r8168c_hw_jumbo_disable(tp);
-- }
-+ r8169_mod_reg8_cond(tp, Config3, Jumbo_En0, jumbo);
-+ r8169_mod_reg8_cond(tp, Config4, Jumbo_En1, jumbo);
- break;
- case RTL_GIGA_MAC_VER_28:
-- if (jumbo)
-- r8168dp_hw_jumbo_enable(tp);
-- else
-- r8168dp_hw_jumbo_disable(tp);
-+ r8169_mod_reg8_cond(tp, Config3, Jumbo_En0, jumbo);
- break;
- case RTL_GIGA_MAC_VER_31 ... RTL_GIGA_MAC_VER_33:
-- if (jumbo)
-- r8168e_hw_jumbo_enable(tp);
-- else
-- r8168e_hw_jumbo_disable(tp);
-+ RTL_W8(tp, MaxTxPacketSize, jumbo ? 0x24 : 0x3f);
-+ r8169_mod_reg8_cond(tp, Config3, Jumbo_En0, jumbo);
-+ r8169_mod_reg8_cond(tp, Config4, BIT(0), jumbo);
- break;
- default:
- break;
+++ /dev/null
-From e340bff27e63ed61a1e9895bed546107859e48a7 Mon Sep 17 00:00:00 2001
-Date: Fri, 8 Nov 2024 08:08:24 +0100
-Subject: [PATCH] r8169: copy vendor driver 2.5G/5G EEE advertisement
- constraints
-
-Vendor driver r8125 doesn't advertise 2.5G EEE on RTL8125A, and r8126
-doesn't advertise 5G EEE. Likely there are compatibility issues,
-therefore do the same in r8169.
-With this change we don't have to disable 2.5G EEE advertisement in
-rtl8125a_config_eee_phy() any longer.
-We use new phylib accessor phy_set_eee_broken() to mark the respective
-EEE modes as broken.
-
----
- drivers/net/ethernet/realtek/r8169_main.c | 6 ++++++
- drivers/net/ethernet/realtek/r8169_phy_config.c | 16 ++++------------
- 2 files changed, 10 insertions(+), 12 deletions(-)
-
---- a/drivers/net/ethernet/realtek/r8169_main.c
-+++ b/drivers/net/ethernet/realtek/r8169_main.c
-@@ -5238,6 +5238,11 @@ static int r8169_mdio_register(struct rt
- tp->phydev->supported_eee);
- phy_support_asym_pause(tp->phydev);
-
-+ /* mimic behavior of r8125/r8126 vendor drivers */
-+ if (tp->mac_version == RTL_GIGA_MAC_VER_61)
-+ tp->phydev->eee_broken_modes |= MDIO_EEE_2_5GT;
-+ tp->phydev->eee_broken_modes |= MDIO_EEE_5GT;
-+
- /* PHY will be woken up in rtl_open() */
- phy_suspend(tp->phydev);
-
---- a/drivers/net/ethernet/realtek/r8169_phy_config.c
-+++ b/drivers/net/ethernet/realtek/r8169_phy_config.c
-@@ -96,15 +96,7 @@ static void rtl8125_common_config_eee_ph
- phy_modify_paged(phydev, 0xa4a, 0x11, 0x0200, 0x0000);
- }
-
--static void rtl8125a_config_eee_phy(struct phy_device *phydev)
--{
-- rtl8168g_config_eee_phy(phydev);
-- /* disable EEE at 2.5Gbps */
-- phy_modify_paged(phydev, 0xa6d, 0x12, 0x0001, 0x0000);
-- rtl8125_common_config_eee_phy(phydev);
--}
--
--static void rtl8125b_config_eee_phy(struct phy_device *phydev)
-+static void rtl8125_config_eee_phy(struct phy_device *phydev)
- {
- rtl8168g_config_eee_phy(phydev);
- rtl8125_common_config_eee_phy(phydev);
-@@ -1066,7 +1058,7 @@ static void rtl8125a_2_hw_phy_config(str
- rtl8168g_enable_gphy_10m(phydev);
-
- rtl8168g_disable_aldps(phydev);
-- rtl8125a_config_eee_phy(phydev);
-+ rtl8125_config_eee_phy(phydev);
- }
-
- static void rtl8125b_hw_phy_config(struct rtl8169_private *tp,
-@@ -1106,7 +1098,7 @@ static void rtl8125b_hw_phy_config(struc
-
- rtl8125_legacy_force_mode(phydev);
- rtl8168g_disable_aldps(phydev);
-- rtl8125b_config_eee_phy(phydev);
-+ rtl8125_config_eee_phy(phydev);
- }
-
- static void rtl8125d_hw_phy_config(struct rtl8169_private *tp,
-@@ -1116,7 +1108,7 @@ static void rtl8125d_hw_phy_config(struc
- rtl8168g_enable_gphy_10m(phydev);
- rtl8125_legacy_force_mode(phydev);
- rtl8168g_disable_aldps(phydev);
-- rtl8125b_config_eee_phy(phydev);
-+ rtl8125_config_eee_phy(phydev);
- }
-
- static void rtl8126a_hw_phy_config(struct rtl8169_private *tp,
+++ /dev/null
-From 2e20bf8cc05766dcd0357cdfcada49e1bc45512b Mon Sep 17 00:00:00 2001
-Date: Mon, 2 Dec 2024 21:14:35 +0100
-Subject: [PATCH] r8169: remove unused flag RTL_FLAG_TASK_RESET_NO_QUEUE_WAKE
-
-After 854d71c555dfc3 ("r8169: remove original workaround for RTL8125
-broken rx issue") this flag isn't used any longer. So remove it.
-
----
- drivers/net/ethernet/realtek/r8169_main.c | 3 ---
- 1 file changed, 3 deletions(-)
-
---- a/drivers/net/ethernet/realtek/r8169_main.c
-+++ b/drivers/net/ethernet/realtek/r8169_main.c
-@@ -623,7 +623,6 @@ struct rtl8169_tc_offsets {
- enum rtl_flag {
- RTL_FLAG_TASK_ENABLED = 0,
- RTL_FLAG_TASK_RESET_PENDING,
-- RTL_FLAG_TASK_RESET_NO_QUEUE_WAKE,
- RTL_FLAG_TASK_TX_TIMEOUT,
- RTL_FLAG_MAX
- };
-@@ -4729,8 +4728,6 @@ static void rtl_task(struct work_struct
- reset:
- rtl_reset_work(tp);
- netif_wake_queue(tp->dev);
-- } else if (test_and_clear_bit(RTL_FLAG_TASK_RESET_NO_QUEUE_WAKE, tp->wk.flags)) {
-- rtl_reset_work(tp);
- }
- }
-
+++ /dev/null
-From bb18265c3aba92b91a1355609769f3e967b65dee Mon Sep 17 00:00:00 2001
-Date: Mon, 2 Dec 2024 21:20:02 +0100
-Subject: [PATCH] r8169: remove support for chip version 11
-
-This is a follow-up to 982300c115d2 ("r8169: remove detection of chip
-version 11 (early RTL8168b)"). Nobody complained yet, so remove
-support for this chip version.
-
----
- drivers/net/ethernet/realtek/r8169.h | 2 +-
- drivers/net/ethernet/realtek/r8169_main.c | 14 +-------------
- drivers/net/ethernet/realtek/r8169_phy_config.c | 10 ----------
- 3 files changed, 2 insertions(+), 24 deletions(-)
-
---- a/drivers/net/ethernet/realtek/r8169.h
-+++ b/drivers/net/ethernet/realtek/r8169.h
-@@ -23,7 +23,7 @@ enum mac_version {
- RTL_GIGA_MAC_VER_08,
- RTL_GIGA_MAC_VER_09,
- RTL_GIGA_MAC_VER_10,
-- RTL_GIGA_MAC_VER_11,
-+ /* support for RTL_GIGA_MAC_VER_11 has been removed */
- /* RTL_GIGA_MAC_VER_12 was handled the same as VER_17 */
- /* RTL_GIGA_MAC_VER_13 was merged with VER_10 */
- RTL_GIGA_MAC_VER_14,
---- a/drivers/net/ethernet/realtek/r8169_main.c
-+++ b/drivers/net/ethernet/realtek/r8169_main.c
-@@ -103,7 +103,6 @@ static const struct {
- [RTL_GIGA_MAC_VER_08] = {"RTL8102e" },
- [RTL_GIGA_MAC_VER_09] = {"RTL8102e/RTL8103e" },
- [RTL_GIGA_MAC_VER_10] = {"RTL8101e/RTL8100e" },
-- [RTL_GIGA_MAC_VER_11] = {"RTL8168b/8111b" },
- [RTL_GIGA_MAC_VER_14] = {"RTL8401" },
- [RTL_GIGA_MAC_VER_17] = {"RTL8168b/8111b" },
- [RTL_GIGA_MAC_VER_18] = {"RTL8168cp/8111cp" },
-@@ -2336,7 +2335,7 @@ static enum mac_version rtl8169_get_mac_
-
- /* 8168B family. */
- { 0x7c8, 0x380, RTL_GIGA_MAC_VER_17 },
-- /* This one is very old and rare, let's see if anybody complains.
-+ /* This one is very old and rare, support has been removed.
- * { 0x7c8, 0x300, RTL_GIGA_MAC_VER_11 },
- */
-
-@@ -3806,7 +3805,6 @@ static void rtl_hw_config(struct rtl8169
- [RTL_GIGA_MAC_VER_08] = rtl_hw_start_8102e_3,
- [RTL_GIGA_MAC_VER_09] = rtl_hw_start_8102e_2,
- [RTL_GIGA_MAC_VER_10] = NULL,
-- [RTL_GIGA_MAC_VER_11] = rtl_hw_start_8168b,
- [RTL_GIGA_MAC_VER_14] = rtl_hw_start_8401,
- [RTL_GIGA_MAC_VER_17] = rtl_hw_start_8168b,
- [RTL_GIGA_MAC_VER_18] = rtl_hw_start_8168cp_1,
-@@ -4682,12 +4680,6 @@ static irqreturn_t rtl8169_interrupt(int
- if (status & LinkChg)
- phy_mac_interrupt(tp->phydev);
-
-- if (unlikely(status & RxFIFOOver &&
-- tp->mac_version == RTL_GIGA_MAC_VER_11)) {
-- netif_stop_queue(tp->dev);
-- rtl_schedule_task(tp, RTL_FLAG_TASK_RESET_PENDING);
-- }
--
- rtl_irq_disable(tp);
- napi_schedule(&tp->napi);
- out:
-@@ -5108,9 +5100,6 @@ static void rtl_set_irq_mask(struct rtl8
-
- if (tp->mac_version <= RTL_GIGA_MAC_VER_06)
- tp->irq_mask |= SYSErr | RxFIFOOver;
-- else if (tp->mac_version == RTL_GIGA_MAC_VER_11)
-- /* special workaround needed */
-- tp->irq_mask |= RxFIFOOver;
- }
-
- static int rtl_alloc_irq(struct rtl8169_private *tp)
-@@ -5306,7 +5295,6 @@ static int rtl_jumbo_max(struct rtl8169_
- case RTL_GIGA_MAC_VER_02 ... RTL_GIGA_MAC_VER_06:
- return JUMBO_7K;
- /* RTL8168b */
-- case RTL_GIGA_MAC_VER_11:
- case RTL_GIGA_MAC_VER_17:
- return JUMBO_4K;
- /* RTL8168c */
---- a/drivers/net/ethernet/realtek/r8169_phy_config.c
-+++ b/drivers/net/ethernet/realtek/r8169_phy_config.c
-@@ -276,15 +276,6 @@ static void rtl8169sce_hw_phy_config(str
- rtl_writephy_batch(phydev, phy_reg_init);
- }
-
--static void rtl8168bb_hw_phy_config(struct rtl8169_private *tp,
-- struct phy_device *phydev)
--{
-- phy_write(phydev, 0x1f, 0x0001);
-- phy_set_bits(phydev, 0x16, BIT(0));
-- phy_write(phydev, 0x10, 0xf41b);
-- phy_write(phydev, 0x1f, 0x0000);
--}
--
- static void rtl8168bef_hw_phy_config(struct rtl8169_private *tp,
- struct phy_device *phydev)
- {
-@@ -1136,7 +1127,6 @@ void r8169_hw_phy_config(struct rtl8169_
- [RTL_GIGA_MAC_VER_08] = rtl8102e_hw_phy_config,
- [RTL_GIGA_MAC_VER_09] = rtl8102e_hw_phy_config,
- [RTL_GIGA_MAC_VER_10] = NULL,
-- [RTL_GIGA_MAC_VER_11] = rtl8168bb_hw_phy_config,
- [RTL_GIGA_MAC_VER_14] = rtl8401_hw_phy_config,
- [RTL_GIGA_MAC_VER_17] = rtl8168bef_hw_phy_config,
- [RTL_GIGA_MAC_VER_18] = rtl8168cp_1_hw_phy_config,
+++ /dev/null
-From b299ea0069284186b0d3d54aebe87f0d195d457a Mon Sep 17 00:00:00 2001
-Date: Fri, 13 Dec 2024 20:01:41 +0100
-Subject: [PATCH] r8169: adjust version numbering for RTL8126
-
-Adjust version numbering for RTL8126, so that it doesn't overlap with
-new RTL8125 versions.
-
----
- drivers/net/ethernet/realtek/r8169.h | 4 +-
- drivers/net/ethernet/realtek/r8169_main.c | 62 +++++++++----------
- .../net/ethernet/realtek/r8169_phy_config.c | 4 +-
- 3 files changed, 35 insertions(+), 35 deletions(-)
-
---- a/drivers/net/ethernet/realtek/r8169.h
-+++ b/drivers/net/ethernet/realtek/r8169.h
-@@ -69,8 +69,8 @@ enum mac_version {
- RTL_GIGA_MAC_VER_61,
- RTL_GIGA_MAC_VER_63,
- RTL_GIGA_MAC_VER_64,
-- RTL_GIGA_MAC_VER_65,
-- RTL_GIGA_MAC_VER_66,
-+ RTL_GIGA_MAC_VER_70,
-+ RTL_GIGA_MAC_VER_71,
- RTL_GIGA_MAC_NONE
- };
-
---- a/drivers/net/ethernet/realtek/r8169_main.c
-+++ b/drivers/net/ethernet/realtek/r8169_main.c
-@@ -139,8 +139,8 @@ static const struct {
- /* reserve 62 for CFG_METHOD_4 in the vendor driver */
- [RTL_GIGA_MAC_VER_63] = {"RTL8125B", FIRMWARE_8125B_2},
- [RTL_GIGA_MAC_VER_64] = {"RTL8125D", FIRMWARE_8125D_1},
-- [RTL_GIGA_MAC_VER_65] = {"RTL8126A", FIRMWARE_8126A_2},
-- [RTL_GIGA_MAC_VER_66] = {"RTL8126A", FIRMWARE_8126A_3},
-+ [RTL_GIGA_MAC_VER_70] = {"RTL8126A", FIRMWARE_8126A_2},
-+ [RTL_GIGA_MAC_VER_71] = {"RTL8126A", FIRMWARE_8126A_3},
- };
-
- static const struct pci_device_id rtl8169_pci_tbl[] = {
-@@ -1228,7 +1228,7 @@ static void rtl_writephy(struct rtl8169_
- case RTL_GIGA_MAC_VER_31:
- r8168dp_2_mdio_write(tp, location, val);
- break;
-- case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_66:
-+ case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_71:
- r8168g_mdio_write(tp, location, val);
- break;
- default:
-@@ -1243,7 +1243,7 @@ static int rtl_readphy(struct rtl8169_pr
- case RTL_GIGA_MAC_VER_28:
- case RTL_GIGA_MAC_VER_31:
- return r8168dp_2_mdio_read(tp, location);
-- case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_66:
-+ case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_71:
- return r8168g_mdio_read(tp, location);
- default:
- return r8169_mdio_read(tp, location);
-@@ -1574,7 +1574,7 @@ static void __rtl8169_set_wol(struct rtl
- break;
- case RTL_GIGA_MAC_VER_34:
- case RTL_GIGA_MAC_VER_37:
-- case RTL_GIGA_MAC_VER_39 ... RTL_GIGA_MAC_VER_66:
-+ case RTL_GIGA_MAC_VER_39 ... RTL_GIGA_MAC_VER_71:
- r8169_mod_reg8_cond(tp, Config2, PME_SIGNAL, wolopts);
- break;
- default:
-@@ -2047,7 +2047,7 @@ static void rtl_set_eee_txidle_timer(str
- tp->tx_lpi_timer = timer_val;
- r8168_mac_ocp_write(tp, 0xe048, timer_val);
- break;
-- case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_66:
-+ case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_71:
- tp->tx_lpi_timer = timer_val;
- RTL_W16(tp, EEE_TXIDLE_TIMER_8125, timer_val);
- break;
-@@ -2256,8 +2256,8 @@ static enum mac_version rtl8169_get_mac_
- enum mac_version ver;
- } mac_info[] = {
- /* 8126A family. */
-- { 0x7cf, 0x64a, RTL_GIGA_MAC_VER_66 },
-- { 0x7cf, 0x649, RTL_GIGA_MAC_VER_65 },
-+ { 0x7cf, 0x64a, RTL_GIGA_MAC_VER_71 },
-+ { 0x7cf, 0x649, RTL_GIGA_MAC_VER_70 },
-
- /* 8125D family. */
- { 0x7cf, 0x688, RTL_GIGA_MAC_VER_64 },
-@@ -2529,7 +2529,7 @@ static void rtl_init_rxcfg(struct rtl816
- case RTL_GIGA_MAC_VER_61:
- RTL_W32(tp, RxConfig, RX_FETCH_DFLT_8125 | RX_DMA_BURST);
- break;
-- case RTL_GIGA_MAC_VER_63 ... RTL_GIGA_MAC_VER_66:
-+ case RTL_GIGA_MAC_VER_63 ... RTL_GIGA_MAC_VER_71:
- RTL_W32(tp, RxConfig, RX_FETCH_DFLT_8125 | RX_DMA_BURST |
- RX_PAUSE_SLOT_ON);
- break;
-@@ -2661,7 +2661,7 @@ static void rtl_wait_txrx_fifo_empty(str
- case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_61:
- rtl_loop_wait_high(tp, &rtl_rxtx_empty_cond, 100, 42);
- break;
-- case RTL_GIGA_MAC_VER_63 ... RTL_GIGA_MAC_VER_66:
-+ case RTL_GIGA_MAC_VER_63 ... RTL_GIGA_MAC_VER_71:
- RTL_W8(tp, ChipCmd, RTL_R8(tp, ChipCmd) | StopReq);
- rtl_loop_wait_high(tp, &rtl_rxtx_empty_cond, 100, 42);
- rtl_loop_wait_high(tp, &rtl_rxtx_empty_cond_2, 100, 42);
-@@ -2904,7 +2904,7 @@ static void rtl_enable_exit_l1(struct rt
- case RTL_GIGA_MAC_VER_37 ... RTL_GIGA_MAC_VER_38:
- rtl_eri_set_bits(tp, 0xd4, 0x0c00);
- break;
-- case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_66:
-+ case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_71:
- r8168_mac_ocp_modify(tp, 0xc0ac, 0, 0x1f80);
- break;
- default:
-@@ -2918,7 +2918,7 @@ static void rtl_disable_exit_l1(struct r
- case RTL_GIGA_MAC_VER_34 ... RTL_GIGA_MAC_VER_38:
- rtl_eri_clear_bits(tp, 0xd4, 0x1f00);
- break;
-- case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_66:
-+ case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_71:
- r8168_mac_ocp_modify(tp, 0xc0ac, 0x1f80, 0);
- break;
- default:
-@@ -2944,8 +2944,8 @@ static void rtl_hw_aspm_clkreq_enable(st
-
- rtl_mod_config5(tp, 0, ASPM_en);
- switch (tp->mac_version) {
-- case RTL_GIGA_MAC_VER_65:
-- case RTL_GIGA_MAC_VER_66:
-+ case RTL_GIGA_MAC_VER_70:
-+ case RTL_GIGA_MAC_VER_71:
- val8 = RTL_R8(tp, INT_CFG0_8125) | INT_CFG0_CLKREQEN;
- RTL_W8(tp, INT_CFG0_8125, val8);
- break;
-@@ -2956,7 +2956,7 @@ static void rtl_hw_aspm_clkreq_enable(st
-
- switch (tp->mac_version) {
- case RTL_GIGA_MAC_VER_46 ... RTL_GIGA_MAC_VER_48:
-- case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_66:
-+ case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_71:
- /* reset ephy tx/rx disable timer */
- r8168_mac_ocp_modify(tp, 0xe094, 0xff00, 0);
- /* chip can trigger L1.2 */
-@@ -2968,7 +2968,7 @@ static void rtl_hw_aspm_clkreq_enable(st
- } else {
- switch (tp->mac_version) {
- case RTL_GIGA_MAC_VER_46 ... RTL_GIGA_MAC_VER_48:
-- case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_66:
-+ case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_71:
- r8168_mac_ocp_modify(tp, 0xe092, 0x00ff, 0);
- break;
- default:
-@@ -2976,8 +2976,8 @@ static void rtl_hw_aspm_clkreq_enable(st
- }
-
- switch (tp->mac_version) {
-- case RTL_GIGA_MAC_VER_65:
-- case RTL_GIGA_MAC_VER_66:
-+ case RTL_GIGA_MAC_VER_70:
-+ case RTL_GIGA_MAC_VER_71:
- val8 = RTL_R8(tp, INT_CFG0_8125) & ~INT_CFG0_CLKREQEN;
- RTL_W8(tp, INT_CFG0_8125, val8);
- break;
-@@ -3697,12 +3697,12 @@ static void rtl_hw_start_8125_common(str
- /* disable new tx descriptor format */
- r8168_mac_ocp_modify(tp, 0xeb58, 0x0001, 0x0000);
-
-- if (tp->mac_version == RTL_GIGA_MAC_VER_65 ||
-- tp->mac_version == RTL_GIGA_MAC_VER_66)
-+ if (tp->mac_version == RTL_GIGA_MAC_VER_70 ||
-+ tp->mac_version == RTL_GIGA_MAC_VER_71)
- RTL_W8(tp, 0xD8, RTL_R8(tp, 0xD8) & ~0x02);
-
-- if (tp->mac_version == RTL_GIGA_MAC_VER_65 ||
-- tp->mac_version == RTL_GIGA_MAC_VER_66)
-+ if (tp->mac_version == RTL_GIGA_MAC_VER_70 ||
-+ tp->mac_version == RTL_GIGA_MAC_VER_71)
- r8168_mac_ocp_modify(tp, 0xe614, 0x0700, 0x0400);
- else if (tp->mac_version == RTL_GIGA_MAC_VER_63)
- r8168_mac_ocp_modify(tp, 0xe614, 0x0700, 0x0200);
-@@ -3720,8 +3720,8 @@ static void rtl_hw_start_8125_common(str
- r8168_mac_ocp_modify(tp, 0xe056, 0x00f0, 0x0000);
- r8168_mac_ocp_modify(tp, 0xe040, 0x1000, 0x0000);
- r8168_mac_ocp_modify(tp, 0xea1c, 0x0003, 0x0001);
-- if (tp->mac_version == RTL_GIGA_MAC_VER_65 ||
-- tp->mac_version == RTL_GIGA_MAC_VER_66)
-+ if (tp->mac_version == RTL_GIGA_MAC_VER_70 ||
-+ tp->mac_version == RTL_GIGA_MAC_VER_71)
- r8168_mac_ocp_modify(tp, 0xea1c, 0x0300, 0x0000);
- else
- r8168_mac_ocp_modify(tp, 0xea1c, 0x0004, 0x0000);
-@@ -3840,8 +3840,8 @@ static void rtl_hw_config(struct rtl8169
- [RTL_GIGA_MAC_VER_61] = rtl_hw_start_8125a_2,
- [RTL_GIGA_MAC_VER_63] = rtl_hw_start_8125b,
- [RTL_GIGA_MAC_VER_64] = rtl_hw_start_8125d,
-- [RTL_GIGA_MAC_VER_65] = rtl_hw_start_8126a,
-- [RTL_GIGA_MAC_VER_66] = rtl_hw_start_8126a,
-+ [RTL_GIGA_MAC_VER_70] = rtl_hw_start_8126a,
-+ [RTL_GIGA_MAC_VER_71] = rtl_hw_start_8126a,
- };
-
- if (hw_configs[tp->mac_version])
-@@ -3862,8 +3862,8 @@ static void rtl_hw_start_8125(struct rtl
- RTL_W32(tp, i, 0);
- break;
- case RTL_GIGA_MAC_VER_63:
-- case RTL_GIGA_MAC_VER_65:
-- case RTL_GIGA_MAC_VER_66:
-+ case RTL_GIGA_MAC_VER_70:
-+ case RTL_GIGA_MAC_VER_71:
- for (i = 0xa00; i < 0xa80; i += 4)
- RTL_W32(tp, i, 0);
- RTL_W16(tp, INT_CFG1_8125, 0x0000);
-@@ -4095,7 +4095,7 @@ static void rtl8169_cleanup(struct rtl81
- RTL_W8(tp, ChipCmd, RTL_R8(tp, ChipCmd) | StopReq);
- rtl_loop_wait_high(tp, &rtl_txcfg_empty_cond, 100, 666);
- break;
-- case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_66:
-+ case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_71:
- rtl_enable_rxdvgate(tp);
- fsleep(2000);
- break;
-@@ -4252,7 +4252,7 @@ static unsigned int rtl_quirk_packet_pad
-
- switch (tp->mac_version) {
- case RTL_GIGA_MAC_VER_34:
-- case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_66:
-+ case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_71:
- padto = max_t(unsigned int, padto, ETH_ZLEN);
- break;
- default:
-@@ -5276,7 +5276,7 @@ static void rtl_hw_initialize(struct rtl
- case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_48:
- rtl_hw_init_8168g(tp);
- break;
-- case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_66:
-+ case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_71:
- rtl_hw_init_8125(tp);
- break;
- default:
---- a/drivers/net/ethernet/realtek/r8169_phy_config.c
-+++ b/drivers/net/ethernet/realtek/r8169_phy_config.c
-@@ -1162,8 +1162,8 @@ void r8169_hw_phy_config(struct rtl8169_
- [RTL_GIGA_MAC_VER_61] = rtl8125a_2_hw_phy_config,
- [RTL_GIGA_MAC_VER_63] = rtl8125b_hw_phy_config,
- [RTL_GIGA_MAC_VER_64] = rtl8125d_hw_phy_config,
-- [RTL_GIGA_MAC_VER_65] = rtl8126a_hw_phy_config,
-- [RTL_GIGA_MAC_VER_66] = rtl8126a_hw_phy_config,
-+ [RTL_GIGA_MAC_VER_70] = rtl8126a_hw_phy_config,
-+ [RTL_GIGA_MAC_VER_71] = rtl8126a_hw_phy_config,
- };
-
- if (phy_configs[ver])
+++ /dev/null
-From b3593df26ab19f114d613693fa8a92ab202803d0 Mon Sep 17 00:00:00 2001
-Date: Fri, 13 Dec 2024 20:02:58 +0100
-Subject: [PATCH] r8169: add support for RTL8125D rev.b
-
-Add support for RTL8125D rev.b. Its XID is 0x689. It is basically
-based on the one with XID 0x688, but with different firmware file.
-
----
- drivers/net/ethernet/realtek/r8169.h | 1 +
- drivers/net/ethernet/realtek/r8169_main.c | 6 ++++++
- drivers/net/ethernet/realtek/r8169_phy_config.c | 1 +
- 3 files changed, 8 insertions(+)
-
---- a/drivers/net/ethernet/realtek/r8169.h
-+++ b/drivers/net/ethernet/realtek/r8169.h
-@@ -69,6 +69,7 @@ enum mac_version {
- RTL_GIGA_MAC_VER_61,
- RTL_GIGA_MAC_VER_63,
- RTL_GIGA_MAC_VER_64,
-+ RTL_GIGA_MAC_VER_65,
- RTL_GIGA_MAC_VER_70,
- RTL_GIGA_MAC_VER_71,
- RTL_GIGA_MAC_NONE
---- a/drivers/net/ethernet/realtek/r8169_main.c
-+++ b/drivers/net/ethernet/realtek/r8169_main.c
-@@ -56,6 +56,7 @@
- #define FIRMWARE_8125A_3 "rtl_nic/rtl8125a-3.fw"
- #define FIRMWARE_8125B_2 "rtl_nic/rtl8125b-2.fw"
- #define FIRMWARE_8125D_1 "rtl_nic/rtl8125d-1.fw"
-+#define FIRMWARE_8125D_2 "rtl_nic/rtl8125d-2.fw"
- #define FIRMWARE_8126A_2 "rtl_nic/rtl8126a-2.fw"
- #define FIRMWARE_8126A_3 "rtl_nic/rtl8126a-3.fw"
-
-@@ -139,6 +140,7 @@ static const struct {
- /* reserve 62 for CFG_METHOD_4 in the vendor driver */
- [RTL_GIGA_MAC_VER_63] = {"RTL8125B", FIRMWARE_8125B_2},
- [RTL_GIGA_MAC_VER_64] = {"RTL8125D", FIRMWARE_8125D_1},
-+ [RTL_GIGA_MAC_VER_65] = {"RTL8125D", FIRMWARE_8125D_2},
- [RTL_GIGA_MAC_VER_70] = {"RTL8126A", FIRMWARE_8126A_2},
- [RTL_GIGA_MAC_VER_71] = {"RTL8126A", FIRMWARE_8126A_3},
- };
-@@ -706,6 +708,7 @@ MODULE_FIRMWARE(FIRMWARE_8107E_2);
- MODULE_FIRMWARE(FIRMWARE_8125A_3);
- MODULE_FIRMWARE(FIRMWARE_8125B_2);
- MODULE_FIRMWARE(FIRMWARE_8125D_1);
-+MODULE_FIRMWARE(FIRMWARE_8125D_2);
- MODULE_FIRMWARE(FIRMWARE_8126A_2);
- MODULE_FIRMWARE(FIRMWARE_8126A_3);
-
-@@ -2260,6 +2263,7 @@ static enum mac_version rtl8169_get_mac_
- { 0x7cf, 0x649, RTL_GIGA_MAC_VER_70 },
-
- /* 8125D family. */
-+ { 0x7cf, 0x689, RTL_GIGA_MAC_VER_65 },
- { 0x7cf, 0x688, RTL_GIGA_MAC_VER_64 },
-
- /* 8125B family. */
-@@ -3840,6 +3844,7 @@ static void rtl_hw_config(struct rtl8169
- [RTL_GIGA_MAC_VER_61] = rtl_hw_start_8125a_2,
- [RTL_GIGA_MAC_VER_63] = rtl_hw_start_8125b,
- [RTL_GIGA_MAC_VER_64] = rtl_hw_start_8125d,
-+ [RTL_GIGA_MAC_VER_65] = rtl_hw_start_8125d,
- [RTL_GIGA_MAC_VER_70] = rtl_hw_start_8126a,
- [RTL_GIGA_MAC_VER_71] = rtl_hw_start_8126a,
- };
-@@ -3858,6 +3863,7 @@ static void rtl_hw_start_8125(struct rtl
- switch (tp->mac_version) {
- case RTL_GIGA_MAC_VER_61:
- case RTL_GIGA_MAC_VER_64:
-+ case RTL_GIGA_MAC_VER_65:
- for (i = 0xa00; i < 0xb00; i += 4)
- RTL_W32(tp, i, 0);
- break;
---- a/drivers/net/ethernet/realtek/r8169_phy_config.c
-+++ b/drivers/net/ethernet/realtek/r8169_phy_config.c
-@@ -1162,6 +1162,7 @@ void r8169_hw_phy_config(struct rtl8169_
- [RTL_GIGA_MAC_VER_61] = rtl8125a_2_hw_phy_config,
- [RTL_GIGA_MAC_VER_63] = rtl8125b_hw_phy_config,
- [RTL_GIGA_MAC_VER_64] = rtl8125d_hw_phy_config,
-+ [RTL_GIGA_MAC_VER_65] = rtl8125d_hw_phy_config,
- [RTL_GIGA_MAC_VER_70] = rtl8126a_hw_phy_config,
- [RTL_GIGA_MAC_VER_71] = rtl8126a_hw_phy_config,
- };
+++ /dev/null
-From b11bff90f2ad52c5c55c822ecd20326619a73898 Mon Sep 17 00:00:00 2001
-Date: Tue, 7 Jan 2025 14:43:55 +0800
-Subject: [PATCH] r8169: add support for RTL8125BP rev.b
-
-Add support for RTL8125BP rev.b. Its XID is 0x689. This chip supports
-DASH and its dash type is "RTL_DASH_25_BP".
-
----
- drivers/net/ethernet/realtek/r8169.h | 1 +
- drivers/net/ethernet/realtek/r8169_main.c | 30 +++++++++++++++++++
- .../net/ethernet/realtek/r8169_phy_config.c | 23 ++++++++++++++
- 3 files changed, 54 insertions(+)
-
---- a/drivers/net/ethernet/realtek/r8169.h
-+++ b/drivers/net/ethernet/realtek/r8169.h
-@@ -70,6 +70,7 @@ enum mac_version {
- RTL_GIGA_MAC_VER_63,
- RTL_GIGA_MAC_VER_64,
- RTL_GIGA_MAC_VER_65,
-+ RTL_GIGA_MAC_VER_66,
- RTL_GIGA_MAC_VER_70,
- RTL_GIGA_MAC_VER_71,
- RTL_GIGA_MAC_NONE
---- a/drivers/net/ethernet/realtek/r8169_main.c
-+++ b/drivers/net/ethernet/realtek/r8169_main.c
-@@ -57,6 +57,7 @@
- #define FIRMWARE_8125B_2 "rtl_nic/rtl8125b-2.fw"
- #define FIRMWARE_8125D_1 "rtl_nic/rtl8125d-1.fw"
- #define FIRMWARE_8125D_2 "rtl_nic/rtl8125d-2.fw"
-+#define FIRMWARE_8125BP_2 "rtl_nic/rtl8125bp-2.fw"
- #define FIRMWARE_8126A_2 "rtl_nic/rtl8126a-2.fw"
- #define FIRMWARE_8126A_3 "rtl_nic/rtl8126a-3.fw"
-
-@@ -141,6 +142,7 @@ static const struct {
- [RTL_GIGA_MAC_VER_63] = {"RTL8125B", FIRMWARE_8125B_2},
- [RTL_GIGA_MAC_VER_64] = {"RTL8125D", FIRMWARE_8125D_1},
- [RTL_GIGA_MAC_VER_65] = {"RTL8125D", FIRMWARE_8125D_2},
-+ [RTL_GIGA_MAC_VER_66] = {"RTL8125BP", FIRMWARE_8125BP_2},
- [RTL_GIGA_MAC_VER_70] = {"RTL8126A", FIRMWARE_8126A_2},
- [RTL_GIGA_MAC_VER_71] = {"RTL8126A", FIRMWARE_8126A_3},
- };
-@@ -632,6 +634,7 @@ enum rtl_dash_type {
- RTL_DASH_NONE,
- RTL_DASH_DP,
- RTL_DASH_EP,
-+ RTL_DASH_25_BP,
- };
-
- struct rtl8169_private {
-@@ -709,6 +712,7 @@ MODULE_FIRMWARE(FIRMWARE_8125A_3);
- MODULE_FIRMWARE(FIRMWARE_8125B_2);
- MODULE_FIRMWARE(FIRMWARE_8125D_1);
- MODULE_FIRMWARE(FIRMWARE_8125D_2);
-+MODULE_FIRMWARE(FIRMWARE_8125BP_2);
- MODULE_FIRMWARE(FIRMWARE_8126A_2);
- MODULE_FIRMWARE(FIRMWARE_8126A_3);
-
-@@ -1361,10 +1365,19 @@ static void rtl8168ep_driver_start(struc
- rtl_loop_wait_high(tp, &rtl_ep_ocp_read_cond, 10000, 30);
- }
-
-+static void rtl8125bp_driver_start(struct rtl8169_private *tp)
-+{
-+ r8168ep_ocp_write(tp, 0x01, 0x14, OOB_CMD_DRIVER_START);
-+ r8168ep_ocp_write(tp, 0x01, 0x18, 0x00);
-+ r8168ep_ocp_write(tp, 0x01, 0x10, 0x01);
-+}
-+
- static void rtl8168_driver_start(struct rtl8169_private *tp)
- {
- if (tp->dash_type == RTL_DASH_DP)
- rtl8168dp_driver_start(tp);
-+ else if (tp->dash_type == RTL_DASH_25_BP)
-+ rtl8125bp_driver_start(tp);
- else
- rtl8168ep_driver_start(tp);
- }
-@@ -1385,10 +1398,19 @@ static void rtl8168ep_driver_stop(struct
- rtl_loop_wait_low(tp, &rtl_ep_ocp_read_cond, 10000, 10);
- }
-
-+static void rtl8125bp_driver_stop(struct rtl8169_private *tp)
-+{
-+ r8168ep_ocp_write(tp, 0x01, 0x14, OOB_CMD_DRIVER_STOP);
-+ r8168ep_ocp_write(tp, 0x01, 0x18, 0x00);
-+ r8168ep_ocp_write(tp, 0x01, 0x10, 0x01);
-+}
-+
- static void rtl8168_driver_stop(struct rtl8169_private *tp)
- {
- if (tp->dash_type == RTL_DASH_DP)
- rtl8168dp_driver_stop(tp);
-+ else if (tp->dash_type == RTL_DASH_25_BP)
-+ rtl8125bp_driver_stop(tp);
- else
- rtl8168ep_driver_stop(tp);
- }
-@@ -1411,6 +1433,7 @@ static bool rtl_dash_is_enabled(struct r
- case RTL_DASH_DP:
- return r8168dp_check_dash(tp);
- case RTL_DASH_EP:
-+ case RTL_DASH_25_BP:
- return r8168ep_check_dash(tp);
- default:
- return false;
-@@ -1425,6 +1448,8 @@ static enum rtl_dash_type rtl_get_dash_t
- return RTL_DASH_DP;
- case RTL_GIGA_MAC_VER_51 ... RTL_GIGA_MAC_VER_53:
- return RTL_DASH_EP;
-+ case RTL_GIGA_MAC_VER_66:
-+ return RTL_DASH_25_BP;
- default:
- return RTL_DASH_NONE;
- }
-@@ -2262,6 +2287,9 @@ static enum mac_version rtl8169_get_mac_
- { 0x7cf, 0x64a, RTL_GIGA_MAC_VER_71 },
- { 0x7cf, 0x649, RTL_GIGA_MAC_VER_70 },
-
-+ /* 8125BP family. */
-+ { 0x7cf, 0x681, RTL_GIGA_MAC_VER_66 },
-+
- /* 8125D family. */
- { 0x7cf, 0x689, RTL_GIGA_MAC_VER_65 },
- { 0x7cf, 0x688, RTL_GIGA_MAC_VER_64 },
-@@ -3845,6 +3873,7 @@ static void rtl_hw_config(struct rtl8169
- [RTL_GIGA_MAC_VER_63] = rtl_hw_start_8125b,
- [RTL_GIGA_MAC_VER_64] = rtl_hw_start_8125d,
- [RTL_GIGA_MAC_VER_65] = rtl_hw_start_8125d,
-+ [RTL_GIGA_MAC_VER_66] = rtl_hw_start_8125d,
- [RTL_GIGA_MAC_VER_70] = rtl_hw_start_8126a,
- [RTL_GIGA_MAC_VER_71] = rtl_hw_start_8126a,
- };
-@@ -3864,6 +3893,7 @@ static void rtl_hw_start_8125(struct rtl
- case RTL_GIGA_MAC_VER_61:
- case RTL_GIGA_MAC_VER_64:
- case RTL_GIGA_MAC_VER_65:
-+ case RTL_GIGA_MAC_VER_66:
- for (i = 0xa00; i < 0xb00; i += 4)
- RTL_W32(tp, i, 0);
- break;
---- a/drivers/net/ethernet/realtek/r8169_phy_config.c
-+++ b/drivers/net/ethernet/realtek/r8169_phy_config.c
-@@ -1102,6 +1102,28 @@ static void rtl8125d_hw_phy_config(struc
- rtl8125_config_eee_phy(phydev);
- }
-
-+static void rtl8125bp_hw_phy_config(struct rtl8169_private *tp,
-+ struct phy_device *phydev)
-+{
-+ r8169_apply_firmware(tp);
-+ rtl8168g_enable_gphy_10m(phydev);
-+
-+ r8168g_phy_param(phydev, 0x8010, 0x0800, 0x0000);
-+
-+ phy_write(phydev, 0x1f, 0x0b87);
-+ phy_write(phydev, 0x16, 0x8088);
-+ phy_modify(phydev, 0x17, 0xff00, 0x9000);
-+ phy_write(phydev, 0x16, 0x808f);
-+ phy_modify(phydev, 0x17, 0xff00, 0x9000);
-+ phy_write(phydev, 0x1f, 0x0000);
-+
-+ r8168g_phy_param(phydev, 0x8174, 0x2000, 0x1800);
-+
-+ rtl8125_legacy_force_mode(phydev);
-+ rtl8168g_disable_aldps(phydev);
-+ rtl8125_config_eee_phy(phydev);
-+}
-+
- static void rtl8126a_hw_phy_config(struct rtl8169_private *tp,
- struct phy_device *phydev)
- {
-@@ -1163,6 +1185,7 @@ void r8169_hw_phy_config(struct rtl8169_
- [RTL_GIGA_MAC_VER_63] = rtl8125b_hw_phy_config,
- [RTL_GIGA_MAC_VER_64] = rtl8125d_hw_phy_config,
- [RTL_GIGA_MAC_VER_65] = rtl8125d_hw_phy_config,
-+ [RTL_GIGA_MAC_VER_66] = rtl8125bp_hw_phy_config,
- [RTL_GIGA_MAC_VER_70] = rtl8126a_hw_phy_config,
- [RTL_GIGA_MAC_VER_71] = rtl8126a_hw_phy_config,
- };
+++ /dev/null
-From 135c3c86a7cef4ba3d368da15b16c275b74582d3 Mon Sep 17 00:00:00 2001
-Date: Mon, 3 Feb 2025 21:35:24 +0100
-Subject: [PATCH] r8169: make Kconfig option for LED support user-visible
-
-Make config option R8169_LEDS user-visible, so that users can remove
-support if not needed.
-
----
- drivers/net/ethernet/realtek/Kconfig | 3 ++-
- 1 file changed, 2 insertions(+), 1 deletion(-)
-
---- a/drivers/net/ethernet/realtek/Kconfig
-+++ b/drivers/net/ethernet/realtek/Kconfig
-@@ -114,7 +114,8 @@ config R8169
- will be called r8169. This is recommended.
-
- config R8169_LEDS
-- def_bool R8169 && LEDS_TRIGGER_NETDEV
-+ bool "Support for controlling the NIC LEDs"
-+ depends on R8169 && LEDS_TRIGGER_NETDEV
- depends on !(R8169=y && LEDS_CLASS=m)
- help
- Optional support for controlling the NIC LED's with the netdev
+++ /dev/null
-From d30460f42675fef5cd4b44ffbc49b545524555e3 Mon Sep 17 00:00:00 2001
-Date: Wed, 12 Feb 2025 08:03:56 +0100
-Subject: [PATCH] r8169: add support for Intel Killer E5000
-
-This adds support for the Intel Killer E5000 which seems to be a
-rebranded RTL8126. Copied from r8126 vendor driver.
-
----
- drivers/net/ethernet/realtek/r8169_main.c | 1 +
- 1 file changed, 1 insertion(+)
-
---- a/drivers/net/ethernet/realtek/r8169_main.c
-+++ b/drivers/net/ethernet/realtek/r8169_main.c
-@@ -169,6 +169,7 @@ static const struct pci_device_id rtl816
- { PCI_VDEVICE(REALTEK, 0x8125) },
- { PCI_VDEVICE(REALTEK, 0x8126) },
- { PCI_VDEVICE(REALTEK, 0x3000) },
-+ { PCI_VDEVICE(REALTEK, 0x5000) },
- {}
- };
-
+++ /dev/null
-From 853e80369cfceb2331bf34f251ba11c6602cc67f Mon Sep 17 00:00:00 2001
-Date: Thu, 13 Feb 2025 20:15:42 +0100
-Subject: [PATCH] r8169: add PHY c45 ops for MDIO_MMD_VENDOR2 registers
-
-The integrated PHYs on chip versions from RTL8168g allow to address
-MDIO_MMD_VEND2 registers. All c22 standard registers are mapped to
-MDIO_MMD_VEND2 registers. So far the paging mechanism is used to
-address PHY registers. Add support for c45 ops to address MDIO_MMD_VEND2
-registers directly, w/o the paging.
-
----
- drivers/net/ethernet/realtek/r8169_main.c | 32 +++++++++++++++++++++++
- 1 file changed, 32 insertions(+)
-
---- a/drivers/net/ethernet/realtek/r8169_main.c
-+++ b/drivers/net/ethernet/realtek/r8169_main.c
-@@ -5209,6 +5209,33 @@ static int r8169_mdio_write_reg(struct m
- return 0;
- }
-
-+static int r8169_mdio_read_reg_c45(struct mii_bus *mii_bus, int addr,
-+ int devnum, int regnum)
-+{
-+ struct rtl8169_private *tp = mii_bus->priv;
-+
-+ if (addr > 0)
-+ return -ENODEV;
-+
-+ if (devnum == MDIO_MMD_VEND2 && regnum > MDIO_STAT2)
-+ return r8168_phy_ocp_read(tp, regnum);
-+
-+ return 0;
-+}
-+
-+static int r8169_mdio_write_reg_c45(struct mii_bus *mii_bus, int addr,
-+ int devnum, int regnum, u16 val)
-+{
-+ struct rtl8169_private *tp = mii_bus->priv;
-+
-+ if (addr > 0 || devnum != MDIO_MMD_VEND2 || regnum <= MDIO_STAT2)
-+ return -ENODEV;
-+
-+ r8168_phy_ocp_write(tp, regnum, val);
-+
-+ return 0;
-+}
-+
- static int r8169_mdio_register(struct rtl8169_private *tp)
- {
- struct pci_dev *pdev = tp->pci_dev;
-@@ -5239,6 +5266,11 @@ static int r8169_mdio_register(struct rt
- new_bus->read = r8169_mdio_read_reg;
- new_bus->write = r8169_mdio_write_reg;
-
-+ if (tp->mac_version >= RTL_GIGA_MAC_VER_40) {
-+ new_bus->read_c45 = r8169_mdio_read_reg_c45;
-+ new_bus->write_c45 = r8169_mdio_write_reg_c45;
-+ }
-+
- ret = devm_mdiobus_register(&pdev->dev, new_bus);
- if (ret)
- return ret;
+++ /dev/null
-From 473367a5ffe1607a61be481e2feda684eb5faea9 Mon Sep 17 00:00:00 2001
-Date: Fri, 7 Mar 2025 08:29:47 +0100
-Subject: [PATCH] r8169: increase max jumbo packet size on RTL8125/RTL8126
-
-Realtek confirmed that all RTL8125/RTL8126 chip versions support up to
-16K jumbo packets. Reflect this in the driver.
-
-Tested by Rui on RTL8125B with 12K jumbo packets.
-
----
- drivers/net/ethernet/realtek/r8169_main.c | 4 ++++
- 1 file changed, 4 insertions(+)
-
---- a/drivers/net/ethernet/realtek/r8169_main.c
-+++ b/drivers/net/ethernet/realtek/r8169_main.c
-@@ -89,6 +89,7 @@
- #define JUMBO_6K (6 * SZ_1K - VLAN_ETH_HLEN - ETH_FCS_LEN)
- #define JUMBO_7K (7 * SZ_1K - VLAN_ETH_HLEN - ETH_FCS_LEN)
- #define JUMBO_9K (9 * SZ_1K - VLAN_ETH_HLEN - ETH_FCS_LEN)
-+#define JUMBO_16K (SZ_16K - VLAN_ETH_HLEN - ETH_FCS_LEN)
-
- static const struct {
- const char *name;
-@@ -5369,6 +5370,9 @@ static int rtl_jumbo_max(struct rtl8169_
- /* RTL8168c */
- case RTL_GIGA_MAC_VER_18 ... RTL_GIGA_MAC_VER_24:
- return JUMBO_6K;
-+ /* RTL8125/8126 */
-+ case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_71:
-+ return JUMBO_16K;
- default:
- return JUMBO_9K;
- }
+++ /dev/null
-From 3d9b8ac5341269d31e59fd5d58d47266ac78bc32 Mon Sep 17 00:00:00 2001
-Date: Tue, 18 Mar 2025 16:37:20 +0800
-Subject: [PATCH] r8169: enable RTL8168H/RTL8168EP/RTL8168FP ASPM support
-
-This patch will enable RTL8168H/RTL8168EP/RTL8168FP ASPM support on
-the platforms that have tested with ASPM enabled.
-
----
- drivers/net/ethernet/realtek/r8169_main.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/net/ethernet/realtek/r8169_main.c
-+++ b/drivers/net/ethernet/realtek/r8169_main.c
-@@ -5407,7 +5407,7 @@ done:
- /* register is set if system vendor successfully tested ASPM 1.2 */
- static bool rtl_aspm_is_safe(struct rtl8169_private *tp)
- {
-- if (tp->mac_version >= RTL_GIGA_MAC_VER_61 &&
-+ if (tp->mac_version >= RTL_GIGA_MAC_VER_46 &&
- r8168_mac_ocp_read(tp, 0xc0b2) & 0xf)
- return true;
-
+++ /dev/null
-From b48688ea3c9ac8d5d910c6e91fb7f80d846581f0 Mon Sep 17 00:00:00 2001
-Date: Tue, 18 Mar 2025 16:37:21 +0800
-Subject: [PATCH] r8169: disable RTL8126 ZRX-DC timeout
-
-Disable it due to it dose not meet ZRX-DC specification. If it is enabled,
-device will exit L1 substate every 100ms. Disable it for saving more power
-in L1 substate.
-
----
- drivers/net/ethernet/realtek/r8169_main.c | 27 +++++++++++++++++++++++
- 1 file changed, 27 insertions(+)
-
---- a/drivers/net/ethernet/realtek/r8169_main.c
-+++ b/drivers/net/ethernet/realtek/r8169_main.c
-@@ -2856,6 +2856,32 @@ static u32 rtl_csi_read(struct rtl8169_p
- RTL_R32(tp, CSIDR) : ~0;
- }
-
-+static void rtl_disable_zrxdc_timeout(struct rtl8169_private *tp)
-+{
-+ struct pci_dev *pdev = tp->pci_dev;
-+ u32 csi;
-+ int rc;
-+ u8 val;
-+
-+#define RTL_GEN3_RELATED_OFF 0x0890
-+#define RTL_GEN3_ZRXDC_NONCOMPL 0x1
-+ if (pdev->cfg_size > RTL_GEN3_RELATED_OFF) {
-+ rc = pci_read_config_byte(pdev, RTL_GEN3_RELATED_OFF, &val);
-+ if (rc == PCIBIOS_SUCCESSFUL) {
-+ val &= ~RTL_GEN3_ZRXDC_NONCOMPL;
-+ rc = pci_write_config_byte(pdev, RTL_GEN3_RELATED_OFF,
-+ val);
-+ if (rc == PCIBIOS_SUCCESSFUL)
-+ return;
-+ }
-+ }
-+
-+ netdev_notice_once(tp->dev,
-+ "No native access to PCI extended config space, falling back to CSI\n");
-+ csi = rtl_csi_read(tp, RTL_GEN3_RELATED_OFF);
-+ rtl_csi_write(tp, RTL_GEN3_RELATED_OFF, csi & ~RTL_GEN3_ZRXDC_NONCOMPL);
-+}
-+
- static void rtl_set_aspm_entry_latency(struct rtl8169_private *tp, u8 val)
- {
- struct pci_dev *pdev = tp->pci_dev;
-@@ -3828,6 +3854,7 @@ static void rtl_hw_start_8125d(struct rt
-
- static void rtl_hw_start_8126a(struct rtl8169_private *tp)
- {
-+ rtl_disable_zrxdc_timeout(tp);
- rtl_set_def_aspm_entry_latency(tp);
- rtl_hw_start_8125_common(tp);
- }
+++ /dev/null
-From 8c40d99e5f43e0545a3f4fea9156313847e2eb79 Mon Sep 17 00:00:00 2001
-Date: Wed, 9 Apr 2025 21:05:37 +0200
-Subject: [PATCH] r8169: add helper rtl_csi_mod for accessing extended config
- space
-
-Add a helper for the Realtek-specific mechanism for accessing extended
-config space if native access isn't possible.
-This avoids code duplication.
-
----
- drivers/net/ethernet/realtek/r8169_main.c | 26 ++++++++++++++---------
- 1 file changed, 16 insertions(+), 10 deletions(-)
-
---- a/drivers/net/ethernet/realtek/r8169_main.c
-+++ b/drivers/net/ethernet/realtek/r8169_main.c
-@@ -2856,10 +2856,23 @@ static u32 rtl_csi_read(struct rtl8169_p
- RTL_R32(tp, CSIDR) : ~0;
- }
-
-+static void rtl_csi_mod(struct rtl8169_private *tp, int addr,
-+ u32 mask, u32 set)
-+{
-+ u32 val;
-+
-+ WARN(addr % 4, "Invalid CSI address %#x\n", addr);
-+
-+ netdev_notice_once(tp->dev,
-+ "No native access to PCI extended config space, falling back to CSI\n");
-+
-+ val = rtl_csi_read(tp, addr);
-+ rtl_csi_write(tp, addr, (val & ~mask) | set);
-+}
-+
- static void rtl_disable_zrxdc_timeout(struct rtl8169_private *tp)
- {
- struct pci_dev *pdev = tp->pci_dev;
-- u32 csi;
- int rc;
- u8 val;
-
-@@ -2876,16 +2889,12 @@ static void rtl_disable_zrxdc_timeout(st
- }
- }
-
-- netdev_notice_once(tp->dev,
-- "No native access to PCI extended config space, falling back to CSI\n");
-- csi = rtl_csi_read(tp, RTL_GEN3_RELATED_OFF);
-- rtl_csi_write(tp, RTL_GEN3_RELATED_OFF, csi & ~RTL_GEN3_ZRXDC_NONCOMPL);
-+ rtl_csi_mod(tp, RTL_GEN3_RELATED_OFF, RTL_GEN3_ZRXDC_NONCOMPL, 0);
- }
-
- static void rtl_set_aspm_entry_latency(struct rtl8169_private *tp, u8 val)
- {
- struct pci_dev *pdev = tp->pci_dev;
-- u32 csi;
-
- /* According to Realtek the value at config space address 0x070f
- * controls the L0s/L1 entrance latency. We try standard ECAM access
-@@ -2897,10 +2906,7 @@ static void rtl_set_aspm_entry_latency(s
- pci_write_config_byte(pdev, 0x070f, val) == PCIBIOS_SUCCESSFUL)
- return;
-
-- netdev_notice_once(tp->dev,
-- "No native access to PCI extended config space, falling back to CSI\n");
-- csi = rtl_csi_read(tp, 0x070c) & 0x00ffffff;
-- rtl_csi_write(tp, 0x070c, csi | val << 24);
-+ rtl_csi_mod(tp, 0x070c, 0xff000000, val << 24);
- }
-
- static void rtl_set_def_aspm_entry_latency(struct rtl8169_private *tp)
+++ /dev/null
-From 0c49baf099ba2147a6ff3bbdc3197c6ddbee5469 Mon Sep 17 00:00:00 2001
-Date: Wed, 9 Apr 2025 21:14:47 +0200
-Subject: [PATCH] r8169: add helper rtl8125_phy_param
-
-The integrated PHY's of RTL8125/8126 have an own mechanism to access
-PHY parameters, similar to what r8168g_phy_param does on earlier PHY
-versions. Add helper rtl8125_phy_param to simplify the code.
-
----
- .../net/ethernet/realtek/r8169_phy_config.c | 36 +++++++++----------
- 1 file changed, 16 insertions(+), 20 deletions(-)
-
---- a/drivers/net/ethernet/realtek/r8169_phy_config.c
-+++ b/drivers/net/ethernet/realtek/r8169_phy_config.c
-@@ -50,6 +50,15 @@ static void r8168g_phy_param(struct phy_
- phy_restore_page(phydev, oldpage, 0);
- }
-
-+static void rtl8125_phy_param(struct phy_device *phydev, u16 parm,
-+ u16 mask, u16 val)
-+{
-+ phy_lock_mdio_bus(phydev);
-+ __phy_write_mmd(phydev, MDIO_MMD_VEND2, 0xb87c, parm);
-+ __phy_modify_mmd(phydev, MDIO_MMD_VEND2, 0xb87e, mask, val);
-+ phy_unlock_mdio_bus(phydev);
-+}
-+
- struct phy_reg {
- u16 reg;
- u16 val;
-@@ -1004,12 +1013,8 @@ static void rtl8125a_2_hw_phy_config(str
- phy_write_paged(phydev, 0xac5, 0x16, 0x01ff);
- phy_modify_paged(phydev, 0xac8, 0x15, 0x00f0, 0x0030);
-
-- phy_write(phydev, 0x1f, 0x0b87);
-- phy_write(phydev, 0x16, 0x80a2);
-- phy_write(phydev, 0x17, 0x0153);
-- phy_write(phydev, 0x16, 0x809c);
-- phy_write(phydev, 0x17, 0x0153);
-- phy_write(phydev, 0x1f, 0x0000);
-+ rtl8125_phy_param(phydev, 0x80a2, 0xffff, 0x0153);
-+ rtl8125_phy_param(phydev, 0x809c, 0xffff, 0x0153);
-
- phy_write(phydev, 0x1f, 0x0a43);
- phy_write(phydev, 0x13, 0x81B3);
-@@ -1061,14 +1066,9 @@ static void rtl8125b_hw_phy_config(struc
- phy_modify_paged(phydev, 0xac4, 0x13, 0x00f0, 0x0090);
- phy_modify_paged(phydev, 0xad3, 0x10, 0x0003, 0x0001);
-
-- phy_write(phydev, 0x1f, 0x0b87);
-- phy_write(phydev, 0x16, 0x80f5);
-- phy_write(phydev, 0x17, 0x760e);
-- phy_write(phydev, 0x16, 0x8107);
-- phy_write(phydev, 0x17, 0x360e);
-- phy_write(phydev, 0x16, 0x8551);
-- phy_modify(phydev, 0x17, 0xff00, 0x0800);
-- phy_write(phydev, 0x1f, 0x0000);
-+ rtl8125_phy_param(phydev, 0x80f5, 0xffff, 0x760e);
-+ rtl8125_phy_param(phydev, 0x8107, 0xffff, 0x360e);
-+ rtl8125_phy_param(phydev, 0x8551, 0xff00, 0x0800);
-
- phy_modify_paged(phydev, 0xbf0, 0x10, 0xe000, 0xa000);
- phy_modify_paged(phydev, 0xbf4, 0x13, 0x0f00, 0x0300);
-@@ -1110,12 +1110,8 @@ static void rtl8125bp_hw_phy_config(stru
-
- r8168g_phy_param(phydev, 0x8010, 0x0800, 0x0000);
-
-- phy_write(phydev, 0x1f, 0x0b87);
-- phy_write(phydev, 0x16, 0x8088);
-- phy_modify(phydev, 0x17, 0xff00, 0x9000);
-- phy_write(phydev, 0x16, 0x808f);
-- phy_modify(phydev, 0x17, 0xff00, 0x9000);
-- phy_write(phydev, 0x1f, 0x0000);
-+ rtl8125_phy_param(phydev, 0x8088, 0xff00, 0x9000);
-+ rtl8125_phy_param(phydev, 0x808f, 0xff00, 0x9000);
-
- r8168g_phy_param(phydev, 0x8174, 0x2000, 0x1800);
-
+++ /dev/null
-From 2b065c098c37a3ed28df7c3be59dca61b9da8402 Mon Sep 17 00:00:00 2001
-Date: Tue, 15 Apr 2025 21:29:34 +0200
-Subject: [PATCH] r8169: refactor chip version detection
-
-Refactor chip version detection and merge both configuration tables.
-Apart from reducing the code by a third, this paves the way for
-merging chip version handling if only difference is the firmware.
-
----
- drivers/net/ethernet/realtek/r8169_main.c | 325 +++++++++-------------
- 1 file changed, 128 insertions(+), 197 deletions(-)
-
---- a/drivers/net/ethernet/realtek/r8169_main.c
-+++ b/drivers/net/ethernet/realtek/r8169_main.c
-@@ -91,61 +91,114 @@
- #define JUMBO_9K (9 * SZ_1K - VLAN_ETH_HLEN - ETH_FCS_LEN)
- #define JUMBO_16K (SZ_16K - VLAN_ETH_HLEN - ETH_FCS_LEN)
-
--static const struct {
-+static const struct rtl_chip_info {
-+ u16 mask;
-+ u16 val;
-+ enum mac_version mac_version;
- const char *name;
- const char *fw_name;
- } rtl_chip_infos[] = {
-- /* PCI devices. */
-- [RTL_GIGA_MAC_VER_02] = {"RTL8169s" },
-- [RTL_GIGA_MAC_VER_03] = {"RTL8110s" },
-- [RTL_GIGA_MAC_VER_04] = {"RTL8169sb/8110sb" },
-- [RTL_GIGA_MAC_VER_05] = {"RTL8169sc/8110sc" },
-- [RTL_GIGA_MAC_VER_06] = {"RTL8169sc/8110sc" },
-- /* PCI-E devices. */
-- [RTL_GIGA_MAC_VER_07] = {"RTL8102e" },
-- [RTL_GIGA_MAC_VER_08] = {"RTL8102e" },
-- [RTL_GIGA_MAC_VER_09] = {"RTL8102e/RTL8103e" },
-- [RTL_GIGA_MAC_VER_10] = {"RTL8101e/RTL8100e" },
-- [RTL_GIGA_MAC_VER_14] = {"RTL8401" },
-- [RTL_GIGA_MAC_VER_17] = {"RTL8168b/8111b" },
-- [RTL_GIGA_MAC_VER_18] = {"RTL8168cp/8111cp" },
-- [RTL_GIGA_MAC_VER_19] = {"RTL8168c/8111c" },
-- [RTL_GIGA_MAC_VER_20] = {"RTL8168c/8111c" },
-- [RTL_GIGA_MAC_VER_21] = {"RTL8168c/8111c" },
-- [RTL_GIGA_MAC_VER_22] = {"RTL8168c/8111c" },
-- [RTL_GIGA_MAC_VER_23] = {"RTL8168cp/8111cp" },
-- [RTL_GIGA_MAC_VER_24] = {"RTL8168cp/8111cp" },
-- [RTL_GIGA_MAC_VER_25] = {"RTL8168d/8111d", FIRMWARE_8168D_1},
-- [RTL_GIGA_MAC_VER_26] = {"RTL8168d/8111d", FIRMWARE_8168D_2},
-- [RTL_GIGA_MAC_VER_28] = {"RTL8168dp/8111dp" },
-- [RTL_GIGA_MAC_VER_29] = {"RTL8105e", FIRMWARE_8105E_1},
-- [RTL_GIGA_MAC_VER_30] = {"RTL8105e", FIRMWARE_8105E_1},
-- [RTL_GIGA_MAC_VER_31] = {"RTL8168dp/8111dp" },
-- [RTL_GIGA_MAC_VER_32] = {"RTL8168e/8111e", FIRMWARE_8168E_1},
-- [RTL_GIGA_MAC_VER_33] = {"RTL8168e/8111e", FIRMWARE_8168E_2},
-- [RTL_GIGA_MAC_VER_34] = {"RTL8168evl/8111evl", FIRMWARE_8168E_3},
-- [RTL_GIGA_MAC_VER_35] = {"RTL8168f/8111f", FIRMWARE_8168F_1},
-- [RTL_GIGA_MAC_VER_36] = {"RTL8168f/8111f", FIRMWARE_8168F_2},
-- [RTL_GIGA_MAC_VER_37] = {"RTL8402", FIRMWARE_8402_1 },
-- [RTL_GIGA_MAC_VER_38] = {"RTL8411", FIRMWARE_8411_1 },
-- [RTL_GIGA_MAC_VER_39] = {"RTL8106e", FIRMWARE_8106E_1},
-- [RTL_GIGA_MAC_VER_40] = {"RTL8168g/8111g", FIRMWARE_8168G_2},
-- [RTL_GIGA_MAC_VER_42] = {"RTL8168gu/8111gu", FIRMWARE_8168G_3},
-- [RTL_GIGA_MAC_VER_43] = {"RTL8106eus", FIRMWARE_8106E_2},
-- [RTL_GIGA_MAC_VER_44] = {"RTL8411b", FIRMWARE_8411_2 },
-- [RTL_GIGA_MAC_VER_46] = {"RTL8168h/8111h", FIRMWARE_8168H_2},
-- [RTL_GIGA_MAC_VER_48] = {"RTL8107e", FIRMWARE_8107E_2},
-- [RTL_GIGA_MAC_VER_51] = {"RTL8168ep/8111ep" },
-- [RTL_GIGA_MAC_VER_52] = {"RTL8168fp/RTL8117", FIRMWARE_8168FP_3},
-- [RTL_GIGA_MAC_VER_53] = {"RTL8168fp/RTL8117", },
-- [RTL_GIGA_MAC_VER_61] = {"RTL8125A", FIRMWARE_8125A_3},
-- /* reserve 62 for CFG_METHOD_4 in the vendor driver */
-- [RTL_GIGA_MAC_VER_63] = {"RTL8125B", FIRMWARE_8125B_2},
-- [RTL_GIGA_MAC_VER_64] = {"RTL8125D", FIRMWARE_8125D_1},
-- [RTL_GIGA_MAC_VER_65] = {"RTL8125D", FIRMWARE_8125D_2},
-- [RTL_GIGA_MAC_VER_66] = {"RTL8125BP", FIRMWARE_8125BP_2},
-- [RTL_GIGA_MAC_VER_70] = {"RTL8126A", FIRMWARE_8126A_2},
-- [RTL_GIGA_MAC_VER_71] = {"RTL8126A", FIRMWARE_8126A_3},
-+ /* 8126A family. */
-+ { 0x7cf, 0x64a, RTL_GIGA_MAC_VER_71, "RTL8126A", FIRMWARE_8126A_3 },
-+ { 0x7cf, 0x649, RTL_GIGA_MAC_VER_70, "RTL8126A", FIRMWARE_8126A_2 },
-+
-+ /* 8125BP family. */
-+ { 0x7cf, 0x681, RTL_GIGA_MAC_VER_66, "RTL8125BP", FIRMWARE_8125BP_2 },
-+
-+ /* 8125D family. */
-+ { 0x7cf, 0x689, RTL_GIGA_MAC_VER_65, "RTL8125D", FIRMWARE_8125D_2 },
-+ { 0x7cf, 0x688, RTL_GIGA_MAC_VER_64, "RTL8125D", FIRMWARE_8125D_1 },
-+
-+ /* 8125B family. */
-+ { 0x7cf, 0x641, RTL_GIGA_MAC_VER_63, "RTL8125B", FIRMWARE_8125B_2 },
-+
-+ /* 8125A family. */
-+ { 0x7cf, 0x609, RTL_GIGA_MAC_VER_61, "RTL8125A", FIRMWARE_8125A_3 },
-+
-+ /* RTL8117 */
-+ { 0x7cf, 0x54b, RTL_GIGA_MAC_VER_53, "RTL8168fp/RTL8117" },
-+ { 0x7cf, 0x54a, RTL_GIGA_MAC_VER_52, "RTL8168fp/RTL8117",
-+ FIRMWARE_8168FP_3 },
-+
-+ /* 8168EP family. */
-+ { 0x7cf, 0x502, RTL_GIGA_MAC_VER_51, "RTL8168ep/8111ep" },
-+
-+ /* 8168H family. */
-+ { 0x7cf, 0x541, RTL_GIGA_MAC_VER_46, "RTL8168h/8111h",
-+ FIRMWARE_8168H_2 },
-+ /* Realtek calls it RTL8168M, but it's handled like RTL8168H */
-+ { 0x7cf, 0x6c0, RTL_GIGA_MAC_VER_46, "RTL8168M", FIRMWARE_8168H_2 },
-+
-+ /* 8168G family. */
-+ { 0x7cf, 0x5c8, RTL_GIGA_MAC_VER_44, "RTL8411b", FIRMWARE_8411_2 },
-+ { 0x7cf, 0x509, RTL_GIGA_MAC_VER_42, "RTL8168gu/8111gu",
-+ FIRMWARE_8168G_3 },
-+ { 0x7cf, 0x4c0, RTL_GIGA_MAC_VER_40, "RTL8168g/8111g",
-+ FIRMWARE_8168G_2 },
-+
-+ /* 8168F family. */
-+ { 0x7c8, 0x488, RTL_GIGA_MAC_VER_38, "RTL8411", FIRMWARE_8411_1 },
-+ { 0x7cf, 0x481, RTL_GIGA_MAC_VER_36, "RTL8168f/8111f",
-+ FIRMWARE_8168F_2 },
-+ { 0x7cf, 0x480, RTL_GIGA_MAC_VER_35, "RTL8168f/8111f",
-+ FIRMWARE_8168F_1 },
-+
-+ /* 8168E family. */
-+ { 0x7c8, 0x2c8, RTL_GIGA_MAC_VER_34, "RTL8168evl/8111evl",
-+ FIRMWARE_8168E_3 },
-+ { 0x7cf, 0x2c1, RTL_GIGA_MAC_VER_32, "RTL8168e/8111e",
-+ FIRMWARE_8168E_1 },
-+ { 0x7c8, 0x2c0, RTL_GIGA_MAC_VER_33, "RTL8168e/8111e",
-+ FIRMWARE_8168E_2 },
-+
-+ /* 8168D family. */
-+ { 0x7cf, 0x281, RTL_GIGA_MAC_VER_25, "RTL8168d/8111d",
-+ FIRMWARE_8168D_1 },
-+ { 0x7c8, 0x280, RTL_GIGA_MAC_VER_26, "RTL8168d/8111d",
-+ FIRMWARE_8168D_2 },
-+
-+ /* 8168DP family. */
-+ { 0x7cf, 0x28a, RTL_GIGA_MAC_VER_28, "RTL8168dp/8111dp" },
-+ { 0x7cf, 0x28b, RTL_GIGA_MAC_VER_31, "RTL8168dp/8111dp" },
-+
-+ /* 8168C family. */
-+ { 0x7cf, 0x3c9, RTL_GIGA_MAC_VER_23, "RTL8168cp/8111cp" },
-+ { 0x7cf, 0x3c8, RTL_GIGA_MAC_VER_18, "RTL8168cp/8111cp" },
-+ { 0x7c8, 0x3c8, RTL_GIGA_MAC_VER_24, "RTL8168cp/8111cp" },
-+ { 0x7cf, 0x3c0, RTL_GIGA_MAC_VER_19, "RTL8168c/8111c" },
-+ { 0x7cf, 0x3c2, RTL_GIGA_MAC_VER_20, "RTL8168c/8111c" },
-+ { 0x7cf, 0x3c3, RTL_GIGA_MAC_VER_21, "RTL8168c/8111c" },
-+ { 0x7c8, 0x3c0, RTL_GIGA_MAC_VER_22, "RTL8168c/8111c" },
-+
-+ /* 8168B family. */
-+ { 0x7c8, 0x380, RTL_GIGA_MAC_VER_17, "RTL8168b/8111b" },
-+ /* This one is very old and rare, support has been removed.
-+ * { 0x7c8, 0x300, RTL_GIGA_MAC_VER_11, "RTL8168b/8111b" },
-+ */
-+
-+ /* 8101 family. */
-+ { 0x7c8, 0x448, RTL_GIGA_MAC_VER_39, "RTL8106e", FIRMWARE_8106E_1 },
-+ { 0x7c8, 0x440, RTL_GIGA_MAC_VER_37, "RTL8402", FIRMWARE_8402_1 },
-+ { 0x7cf, 0x409, RTL_GIGA_MAC_VER_29, "RTL8105e", FIRMWARE_8105E_1 },
-+ { 0x7c8, 0x408, RTL_GIGA_MAC_VER_30, "RTL8105e", FIRMWARE_8105E_1 },
-+ { 0x7cf, 0x349, RTL_GIGA_MAC_VER_08, "RTL8102e" },
-+ { 0x7cf, 0x249, RTL_GIGA_MAC_VER_08, "RTL8102e" },
-+ { 0x7cf, 0x348, RTL_GIGA_MAC_VER_07, "RTL8102e" },
-+ { 0x7cf, 0x248, RTL_GIGA_MAC_VER_07, "RTL8102e" },
-+ { 0x7cf, 0x240, RTL_GIGA_MAC_VER_14, "RTL8401" },
-+ { 0x7c8, 0x348, RTL_GIGA_MAC_VER_09, "RTL8102e/RTL8103e" },
-+ { 0x7c8, 0x248, RTL_GIGA_MAC_VER_09, "RTL8102e/RTL8103e" },
-+ { 0x7c8, 0x340, RTL_GIGA_MAC_VER_10, "RTL8101e/RTL8100e" },
-+
-+ /* 8110 family. */
-+ { 0xfc8, 0x980, RTL_GIGA_MAC_VER_06, "RTL8169sc/8110sc" },
-+ { 0xfc8, 0x180, RTL_GIGA_MAC_VER_05, "RTL8169sc/8110sc" },
-+ { 0xfc8, 0x100, RTL_GIGA_MAC_VER_04, "RTL8169sb/8110sb" },
-+ { 0xfc8, 0x040, RTL_GIGA_MAC_VER_03, "RTL8110s" },
-+ { 0xfc8, 0x008, RTL_GIGA_MAC_VER_02, "RTL8169s" },
-+
-+ /* Catch-all */
-+ { 0x000, 0x000, RTL_GIGA_MAC_NONE }
- };
-
- static const struct pci_device_id rtl8169_pci_tbl[] = {
-@@ -2267,151 +2320,30 @@ static const struct ethtool_ops rtl8169_
- .get_eth_ctrl_stats = rtl8169_get_eth_ctrl_stats,
- };
-
--static enum mac_version rtl8169_get_mac_version(u16 xid, bool gmii)
-+static const struct rtl_chip_info *rtl8169_get_chip_version(u16 xid, bool gmii)
- {
-- /*
-- * The driver currently handles the 8168Bf and the 8168Be identically
-- * but they can be identified more specifically through the test below
-- * if needed:
-- *
-- * (RTL_R32(tp, TxConfig) & 0x700000) == 0x500000 ? 8168Bf : 8168Be
-- *
-- * Same thing for the 8101Eb and the 8101Ec:
-- *
-- * (RTL_R32(tp, TxConfig) & 0x700000) == 0x200000 ? 8101Eb : 8101Ec
-- */
-- static const struct rtl_mac_info {
-- u16 mask;
-- u16 val;
-- enum mac_version ver;
-- } mac_info[] = {
-- /* 8126A family. */
-- { 0x7cf, 0x64a, RTL_GIGA_MAC_VER_71 },
-- { 0x7cf, 0x649, RTL_GIGA_MAC_VER_70 },
--
-- /* 8125BP family. */
-- { 0x7cf, 0x681, RTL_GIGA_MAC_VER_66 },
--
-- /* 8125D family. */
-- { 0x7cf, 0x689, RTL_GIGA_MAC_VER_65 },
-- { 0x7cf, 0x688, RTL_GIGA_MAC_VER_64 },
--
-- /* 8125B family. */
-- { 0x7cf, 0x641, RTL_GIGA_MAC_VER_63 },
--
-- /* 8125A family. */
-- { 0x7cf, 0x609, RTL_GIGA_MAC_VER_61 },
-- /* It seems only XID 609 made it to the mass market.
-- * { 0x7cf, 0x608, RTL_GIGA_MAC_VER_60 },
-- * { 0x7c8, 0x608, RTL_GIGA_MAC_VER_61 },
-- */
--
-- /* RTL8117 */
-- { 0x7cf, 0x54b, RTL_GIGA_MAC_VER_53 },
-- { 0x7cf, 0x54a, RTL_GIGA_MAC_VER_52 },
--
-- /* 8168EP family. */
-- { 0x7cf, 0x502, RTL_GIGA_MAC_VER_51 },
-- /* It seems this chip version never made it to
-- * the wild. Let's disable detection.
-- * { 0x7cf, 0x501, RTL_GIGA_MAC_VER_50 },
-- * { 0x7cf, 0x500, RTL_GIGA_MAC_VER_49 },
-- */
--
-- /* 8168H family. */
-- { 0x7cf, 0x541, RTL_GIGA_MAC_VER_46 },
-- /* It seems this chip version never made it to
-- * the wild. Let's disable detection.
-- * { 0x7cf, 0x540, RTL_GIGA_MAC_VER_45 },
-- */
-- /* Realtek calls it RTL8168M, but it's handled like RTL8168H */
-- { 0x7cf, 0x6c0, RTL_GIGA_MAC_VER_46 },
--
-- /* 8168G family. */
-- { 0x7cf, 0x5c8, RTL_GIGA_MAC_VER_44 },
-- { 0x7cf, 0x509, RTL_GIGA_MAC_VER_42 },
-- /* It seems this chip version never made it to
-- * the wild. Let's disable detection.
-- * { 0x7cf, 0x4c1, RTL_GIGA_MAC_VER_41 },
-- */
-- { 0x7cf, 0x4c0, RTL_GIGA_MAC_VER_40 },
--
-- /* 8168F family. */
-- { 0x7c8, 0x488, RTL_GIGA_MAC_VER_38 },
-- { 0x7cf, 0x481, RTL_GIGA_MAC_VER_36 },
-- { 0x7cf, 0x480, RTL_GIGA_MAC_VER_35 },
--
-- /* 8168E family. */
-- { 0x7c8, 0x2c8, RTL_GIGA_MAC_VER_34 },
-- { 0x7cf, 0x2c1, RTL_GIGA_MAC_VER_32 },
-- { 0x7c8, 0x2c0, RTL_GIGA_MAC_VER_33 },
--
-- /* 8168D family. */
-- { 0x7cf, 0x281, RTL_GIGA_MAC_VER_25 },
-- { 0x7c8, 0x280, RTL_GIGA_MAC_VER_26 },
--
-- /* 8168DP family. */
-- /* It seems this early RTL8168dp version never made it to
-- * the wild. Support has been removed.
-- * { 0x7cf, 0x288, RTL_GIGA_MAC_VER_27 },
-- */
-- { 0x7cf, 0x28a, RTL_GIGA_MAC_VER_28 },
-- { 0x7cf, 0x28b, RTL_GIGA_MAC_VER_31 },
--
-- /* 8168C family. */
-- { 0x7cf, 0x3c9, RTL_GIGA_MAC_VER_23 },
-- { 0x7cf, 0x3c8, RTL_GIGA_MAC_VER_18 },
-- { 0x7c8, 0x3c8, RTL_GIGA_MAC_VER_24 },
-- { 0x7cf, 0x3c0, RTL_GIGA_MAC_VER_19 },
-- { 0x7cf, 0x3c2, RTL_GIGA_MAC_VER_20 },
-- { 0x7cf, 0x3c3, RTL_GIGA_MAC_VER_21 },
-- { 0x7c8, 0x3c0, RTL_GIGA_MAC_VER_22 },
--
-- /* 8168B family. */
-- { 0x7c8, 0x380, RTL_GIGA_MAC_VER_17 },
-- /* This one is very old and rare, support has been removed.
-- * { 0x7c8, 0x300, RTL_GIGA_MAC_VER_11 },
-- */
--
-- /* 8101 family. */
-- { 0x7c8, 0x448, RTL_GIGA_MAC_VER_39 },
-- { 0x7c8, 0x440, RTL_GIGA_MAC_VER_37 },
-- { 0x7cf, 0x409, RTL_GIGA_MAC_VER_29 },
-- { 0x7c8, 0x408, RTL_GIGA_MAC_VER_30 },
-- { 0x7cf, 0x349, RTL_GIGA_MAC_VER_08 },
-- { 0x7cf, 0x249, RTL_GIGA_MAC_VER_08 },
-- { 0x7cf, 0x348, RTL_GIGA_MAC_VER_07 },
-- { 0x7cf, 0x248, RTL_GIGA_MAC_VER_07 },
-- { 0x7cf, 0x240, RTL_GIGA_MAC_VER_14 },
-- { 0x7c8, 0x348, RTL_GIGA_MAC_VER_09 },
-- { 0x7c8, 0x248, RTL_GIGA_MAC_VER_09 },
-- { 0x7c8, 0x340, RTL_GIGA_MAC_VER_10 },
--
-- /* 8110 family. */
-- { 0xfc8, 0x980, RTL_GIGA_MAC_VER_06 },
-- { 0xfc8, 0x180, RTL_GIGA_MAC_VER_05 },
-- { 0xfc8, 0x100, RTL_GIGA_MAC_VER_04 },
-- { 0xfc8, 0x040, RTL_GIGA_MAC_VER_03 },
-- { 0xfc8, 0x008, RTL_GIGA_MAC_VER_02 },
--
-- /* Catch-all */
-- { 0x000, 0x000, RTL_GIGA_MAC_NONE }
-+ /* Chips combining a 1Gbps MAC with a 100Mbps PHY */
-+ static const struct rtl_chip_info rtl8106eus_info = {
-+ .mac_version = RTL_GIGA_MAC_VER_43,
-+ .name = "RTL8106eus",
-+ .fw_name = FIRMWARE_8106E_2,
- };
-- const struct rtl_mac_info *p = mac_info;
-- enum mac_version ver;
-+ static const struct rtl_chip_info rtl8107e_info = {
-+ .mac_version = RTL_GIGA_MAC_VER_48,
-+ .name = "RTL8107e",
-+ .fw_name = FIRMWARE_8107E_2,
-+ };
-+ const struct rtl_chip_info *p = rtl_chip_infos;
-
- while ((xid & p->mask) != p->val)
- p++;
-- ver = p->ver;
-
-- if (ver != RTL_GIGA_MAC_NONE && !gmii) {
-- if (ver == RTL_GIGA_MAC_VER_42)
-- ver = RTL_GIGA_MAC_VER_43;
-- else if (ver == RTL_GIGA_MAC_VER_46)
-- ver = RTL_GIGA_MAC_VER_48;
-- }
-+ if (p->mac_version == RTL_GIGA_MAC_VER_42 && !gmii)
-+ return &rtl8106eus_info;
-+ if (p->mac_version == RTL_GIGA_MAC_VER_46 && !gmii)
-+ return &rtl8107e_info;
-
-- return ver;
-+ return p;
- }
-
- static void rtl_release_firmware(struct rtl8169_private *tp)
-@@ -5449,9 +5381,9 @@ static bool rtl_aspm_is_safe(struct rtl8
-
- static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
- {
-+ const struct rtl_chip_info *chip;
- struct rtl8169_private *tp;
- int jumbo_max, region, rc;
-- enum mac_version chipset;
- struct net_device *dev;
- u32 txconfig;
- u16 xid;
-@@ -5502,12 +5434,13 @@ static int rtl_init_one(struct pci_dev *
- xid = (txconfig >> 20) & 0xfcf;
-
- /* Identify chip attached to board */
-- chipset = rtl8169_get_mac_version(xid, tp->supports_gmii);
-- if (chipset == RTL_GIGA_MAC_NONE)
-+ chip = rtl8169_get_chip_version(xid, tp->supports_gmii);
-+ if (chip->mac_version == RTL_GIGA_MAC_NONE)
- return dev_err_probe(&pdev->dev, -ENODEV,
- "unknown chip XID %03x, contact r8169 maintainers (see MAINTAINERS file)\n",
- xid);
-- tp->mac_version = chipset;
-+ tp->mac_version = chip->mac_version;
-+ tp->fw_name = chip->fw_name;
-
- /* Disable ASPM L1 as that cause random device stop working
- * problems as well as full system hangs for some PCIe devices users.
-@@ -5611,8 +5544,6 @@ static int rtl_init_one(struct pci_dev *
-
- rtl_set_irq_mask(tp);
-
-- tp->fw_name = rtl_chip_infos[chipset].fw_name;
--
- tp->counters = dmam_alloc_coherent (&pdev->dev, sizeof(*tp->counters),
- &tp->counters_phys_addr,
- GFP_KERNEL);
-@@ -5637,7 +5568,7 @@ static int rtl_init_one(struct pci_dev *
- }
-
- netdev_info(dev, "%s, %pM, XID %03x, IRQ %d\n",
-- rtl_chip_infos[chipset].name, dev->dev_addr, xid, tp->irq);
-+ chip->name, dev->dev_addr, xid, tp->irq);
-
- if (jumbo_max)
- netdev_info(dev, "jumbo features [frames: %d bytes, tx checksumming: %s]\n",
+++ /dev/null
-From fe733618b27a8c033f0d246c2efff56fca322656 Mon Sep 17 00:00:00 2001
-Date: Tue, 15 Apr 2025 21:39:23 +0200
-Subject: [PATCH] r8169: add RTL_GIGA_MAC_VER_LAST to facilitate adding support
- for new chip versions
-
-Add a new mac_version enum value RTL_GIGA_MAC_VER_LAST. Benefit is that
-when adding support for a new chip version we have to touch less code,
-except something changes fundamentally.
-
----
- drivers/net/ethernet/realtek/r8169.h | 3 ++-
- drivers/net/ethernet/realtek/r8169_main.c | 28 +++++++++++------------
- 2 files changed, 16 insertions(+), 15 deletions(-)
-
---- a/drivers/net/ethernet/realtek/r8169.h
-+++ b/drivers/net/ethernet/realtek/r8169.h
-@@ -73,7 +73,8 @@ enum mac_version {
- RTL_GIGA_MAC_VER_66,
- RTL_GIGA_MAC_VER_70,
- RTL_GIGA_MAC_VER_71,
-- RTL_GIGA_MAC_NONE
-+ RTL_GIGA_MAC_NONE,
-+ RTL_GIGA_MAC_VER_LAST = RTL_GIGA_MAC_NONE - 1
- };
-
- struct rtl8169_private;
---- a/drivers/net/ethernet/realtek/r8169_main.c
-+++ b/drivers/net/ethernet/realtek/r8169_main.c
-@@ -1290,7 +1290,7 @@ static void rtl_writephy(struct rtl8169_
- case RTL_GIGA_MAC_VER_31:
- r8168dp_2_mdio_write(tp, location, val);
- break;
-- case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_71:
-+ case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_LAST:
- r8168g_mdio_write(tp, location, val);
- break;
- default:
-@@ -1305,7 +1305,7 @@ static int rtl_readphy(struct rtl8169_pr
- case RTL_GIGA_MAC_VER_28:
- case RTL_GIGA_MAC_VER_31:
- return r8168dp_2_mdio_read(tp, location);
-- case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_71:
-+ case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_LAST:
- return r8168g_mdio_read(tp, location);
- default:
- return r8169_mdio_read(tp, location);
-@@ -1657,7 +1657,7 @@ static void __rtl8169_set_wol(struct rtl
- break;
- case RTL_GIGA_MAC_VER_34:
- case RTL_GIGA_MAC_VER_37:
-- case RTL_GIGA_MAC_VER_39 ... RTL_GIGA_MAC_VER_71:
-+ case RTL_GIGA_MAC_VER_39 ... RTL_GIGA_MAC_VER_LAST:
- r8169_mod_reg8_cond(tp, Config2, PME_SIGNAL, wolopts);
- break;
- default:
-@@ -2130,7 +2130,7 @@ static void rtl_set_eee_txidle_timer(str
- tp->tx_lpi_timer = timer_val;
- r8168_mac_ocp_write(tp, 0xe048, timer_val);
- break;
-- case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_71:
-+ case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_LAST:
- tp->tx_lpi_timer = timer_val;
- RTL_W16(tp, EEE_TXIDLE_TIMER_8125, timer_val);
- break;
-@@ -2495,7 +2495,7 @@ static void rtl_init_rxcfg(struct rtl816
- case RTL_GIGA_MAC_VER_61:
- RTL_W32(tp, RxConfig, RX_FETCH_DFLT_8125 | RX_DMA_BURST);
- break;
-- case RTL_GIGA_MAC_VER_63 ... RTL_GIGA_MAC_VER_71:
-+ case RTL_GIGA_MAC_VER_63 ... RTL_GIGA_MAC_VER_LAST:
- RTL_W32(tp, RxConfig, RX_FETCH_DFLT_8125 | RX_DMA_BURST |
- RX_PAUSE_SLOT_ON);
- break;
-@@ -2627,7 +2627,7 @@ static void rtl_wait_txrx_fifo_empty(str
- case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_61:
- rtl_loop_wait_high(tp, &rtl_rxtx_empty_cond, 100, 42);
- break;
-- case RTL_GIGA_MAC_VER_63 ... RTL_GIGA_MAC_VER_71:
-+ case RTL_GIGA_MAC_VER_63 ... RTL_GIGA_MAC_VER_LAST:
- RTL_W8(tp, ChipCmd, RTL_R8(tp, ChipCmd) | StopReq);
- rtl_loop_wait_high(tp, &rtl_rxtx_empty_cond, 100, 42);
- rtl_loop_wait_high(tp, &rtl_rxtx_empty_cond_2, 100, 42);
-@@ -2902,7 +2902,7 @@ static void rtl_enable_exit_l1(struct rt
- case RTL_GIGA_MAC_VER_37 ... RTL_GIGA_MAC_VER_38:
- rtl_eri_set_bits(tp, 0xd4, 0x0c00);
- break;
-- case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_71:
-+ case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_LAST:
- r8168_mac_ocp_modify(tp, 0xc0ac, 0, 0x1f80);
- break;
- default:
-@@ -2916,7 +2916,7 @@ static void rtl_disable_exit_l1(struct r
- case RTL_GIGA_MAC_VER_34 ... RTL_GIGA_MAC_VER_38:
- rtl_eri_clear_bits(tp, 0xd4, 0x1f00);
- break;
-- case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_71:
-+ case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_LAST:
- r8168_mac_ocp_modify(tp, 0xc0ac, 0x1f80, 0);
- break;
- default:
-@@ -2954,7 +2954,7 @@ static void rtl_hw_aspm_clkreq_enable(st
-
- switch (tp->mac_version) {
- case RTL_GIGA_MAC_VER_46 ... RTL_GIGA_MAC_VER_48:
-- case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_71:
-+ case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_LAST:
- /* reset ephy tx/rx disable timer */
- r8168_mac_ocp_modify(tp, 0xe094, 0xff00, 0);
- /* chip can trigger L1.2 */
-@@ -2966,7 +2966,7 @@ static void rtl_hw_aspm_clkreq_enable(st
- } else {
- switch (tp->mac_version) {
- case RTL_GIGA_MAC_VER_46 ... RTL_GIGA_MAC_VER_48:
-- case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_71:
-+ case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_LAST:
- r8168_mac_ocp_modify(tp, 0xe092, 0x00ff, 0);
- break;
- default:
-@@ -4098,7 +4098,7 @@ static void rtl8169_cleanup(struct rtl81
- RTL_W8(tp, ChipCmd, RTL_R8(tp, ChipCmd) | StopReq);
- rtl_loop_wait_high(tp, &rtl_txcfg_empty_cond, 100, 666);
- break;
-- case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_71:
-+ case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_LAST:
- rtl_enable_rxdvgate(tp);
- fsleep(2000);
- break;
-@@ -4255,7 +4255,7 @@ static unsigned int rtl_quirk_packet_pad
-
- switch (tp->mac_version) {
- case RTL_GIGA_MAC_VER_34:
-- case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_71:
-+ case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_LAST:
- padto = max_t(unsigned int, padto, ETH_ZLEN);
- break;
- default:
-@@ -5311,7 +5311,7 @@ static void rtl_hw_initialize(struct rtl
- case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_48:
- rtl_hw_init_8168g(tp);
- break;
-- case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_71:
-+ case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_LAST:
- rtl_hw_init_8125(tp);
- break;
- default:
-@@ -5336,7 +5336,7 @@ static int rtl_jumbo_max(struct rtl8169_
- case RTL_GIGA_MAC_VER_18 ... RTL_GIGA_MAC_VER_24:
- return JUMBO_6K;
- /* RTL8125/8126 */
-- case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_71:
-+ case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_LAST:
- return JUMBO_16K;
- default:
- return JUMBO_9K;
+++ /dev/null
-From b7ed5d5a78fccee96cf8919ac2c7a064c2f4c45b Mon Sep 17 00:00:00 2001
-Date: Mon, 21 Apr 2025 11:25:18 +0200
-Subject: [PATCH] r8169: use pci_prepare_to_sleep in rtl_shutdown
-
-Use pci_prepare_to_sleep() like PCI core does in pci_pm_suspend_noirq.
-This aligns setting a low-power mode during shutdown with the handling
-of the transition to system suspend. Also the transition to runtime
-suspend uses pci_target_state() instead of setting D3hot unconditionally.
-
-Note: pci_prepare_to_sleep() uses device_may_wakeup() to check whether
- device may generate wakeup events. So we don't lose anything by
- not passing tp->saved_wolopts any longer.
-
----
- drivers/net/ethernet/realtek/r8169_main.c | 6 ++----
- 1 file changed, 2 insertions(+), 4 deletions(-)
-
---- a/drivers/net/ethernet/realtek/r8169_main.c
-+++ b/drivers/net/ethernet/realtek/r8169_main.c
-@@ -5048,10 +5048,8 @@ static void rtl_shutdown(struct pci_dev
- /* Restore original MAC address */
- rtl_rar_set(tp, tp->dev->perm_addr);
-
-- if (system_state == SYSTEM_POWER_OFF && !tp->dash_enabled) {
-- pci_wake_from_d3(pdev, tp->saved_wolopts);
-- pci_set_power_state(pdev, PCI_D3hot);
-- }
-+ if (system_state == SYSTEM_POWER_OFF && !tp->dash_enabled)
-+ pci_prepare_to_sleep(pdev);
- }
-
- static void rtl_remove_one(struct pci_dev *pdev)
+++ /dev/null
-From 4dec0702b8627c364a0e1f2c5b249e06709a1c24 Mon Sep 17 00:00:00 2001
-Date: Fri, 18 Apr 2025 11:23:45 +0200
-Subject: [PATCH] r8169: merge chip versions 70 and 71 (RTL8126A)
-
-Handling of both chip versions is the same, only difference is
-the firmware. So we can merge handling of both chip versions.
-
----
- drivers/net/ethernet/realtek/r8169.h | 1 -
- drivers/net/ethernet/realtek/r8169_main.c | 15 ++++-----------
- drivers/net/ethernet/realtek/r8169_phy_config.c | 1 -
- 3 files changed, 4 insertions(+), 13 deletions(-)
-
---- a/drivers/net/ethernet/realtek/r8169.h
-+++ b/drivers/net/ethernet/realtek/r8169.h
-@@ -72,7 +72,6 @@ enum mac_version {
- RTL_GIGA_MAC_VER_65,
- RTL_GIGA_MAC_VER_66,
- RTL_GIGA_MAC_VER_70,
-- RTL_GIGA_MAC_VER_71,
- RTL_GIGA_MAC_NONE,
- RTL_GIGA_MAC_VER_LAST = RTL_GIGA_MAC_NONE - 1
- };
---- a/drivers/net/ethernet/realtek/r8169_main.c
-+++ b/drivers/net/ethernet/realtek/r8169_main.c
-@@ -99,7 +99,7 @@ static const struct rtl_chip_info {
- const char *fw_name;
- } rtl_chip_infos[] = {
- /* 8126A family. */
-- { 0x7cf, 0x64a, RTL_GIGA_MAC_VER_71, "RTL8126A", FIRMWARE_8126A_3 },
-+ { 0x7cf, 0x64a, RTL_GIGA_MAC_VER_70, "RTL8126A", FIRMWARE_8126A_3 },
- { 0x7cf, 0x649, RTL_GIGA_MAC_VER_70, "RTL8126A", FIRMWARE_8126A_2 },
-
- /* 8125BP family. */
-@@ -2943,7 +2943,6 @@ static void rtl_hw_aspm_clkreq_enable(st
- rtl_mod_config5(tp, 0, ASPM_en);
- switch (tp->mac_version) {
- case RTL_GIGA_MAC_VER_70:
-- case RTL_GIGA_MAC_VER_71:
- val8 = RTL_R8(tp, INT_CFG0_8125) | INT_CFG0_CLKREQEN;
- RTL_W8(tp, INT_CFG0_8125, val8);
- break;
-@@ -2975,7 +2974,6 @@ static void rtl_hw_aspm_clkreq_enable(st
-
- switch (tp->mac_version) {
- case RTL_GIGA_MAC_VER_70:
-- case RTL_GIGA_MAC_VER_71:
- val8 = RTL_R8(tp, INT_CFG0_8125) & ~INT_CFG0_CLKREQEN;
- RTL_W8(tp, INT_CFG0_8125, val8);
- break;
-@@ -3695,12 +3693,10 @@ static void rtl_hw_start_8125_common(str
- /* disable new tx descriptor format */
- r8168_mac_ocp_modify(tp, 0xeb58, 0x0001, 0x0000);
-
-- if (tp->mac_version == RTL_GIGA_MAC_VER_70 ||
-- tp->mac_version == RTL_GIGA_MAC_VER_71)
-+ if (tp->mac_version == RTL_GIGA_MAC_VER_70)
- RTL_W8(tp, 0xD8, RTL_R8(tp, 0xD8) & ~0x02);
-
-- if (tp->mac_version == RTL_GIGA_MAC_VER_70 ||
-- tp->mac_version == RTL_GIGA_MAC_VER_71)
-+ if (tp->mac_version == RTL_GIGA_MAC_VER_70)
- r8168_mac_ocp_modify(tp, 0xe614, 0x0700, 0x0400);
- else if (tp->mac_version == RTL_GIGA_MAC_VER_63)
- r8168_mac_ocp_modify(tp, 0xe614, 0x0700, 0x0200);
-@@ -3718,8 +3714,7 @@ static void rtl_hw_start_8125_common(str
- r8168_mac_ocp_modify(tp, 0xe056, 0x00f0, 0x0000);
- r8168_mac_ocp_modify(tp, 0xe040, 0x1000, 0x0000);
- r8168_mac_ocp_modify(tp, 0xea1c, 0x0003, 0x0001);
-- if (tp->mac_version == RTL_GIGA_MAC_VER_70 ||
-- tp->mac_version == RTL_GIGA_MAC_VER_71)
-+ if (tp->mac_version == RTL_GIGA_MAC_VER_70)
- r8168_mac_ocp_modify(tp, 0xea1c, 0x0300, 0x0000);
- else
- r8168_mac_ocp_modify(tp, 0xea1c, 0x0004, 0x0000);
-@@ -3842,7 +3837,6 @@ static void rtl_hw_config(struct rtl8169
- [RTL_GIGA_MAC_VER_65] = rtl_hw_start_8125d,
- [RTL_GIGA_MAC_VER_66] = rtl_hw_start_8125d,
- [RTL_GIGA_MAC_VER_70] = rtl_hw_start_8126a,
-- [RTL_GIGA_MAC_VER_71] = rtl_hw_start_8126a,
- };
-
- if (hw_configs[tp->mac_version])
-@@ -3866,7 +3860,6 @@ static void rtl_hw_start_8125(struct rtl
- break;
- case RTL_GIGA_MAC_VER_63:
- case RTL_GIGA_MAC_VER_70:
-- case RTL_GIGA_MAC_VER_71:
- for (i = 0xa00; i < 0xa80; i += 4)
- RTL_W32(tp, i, 0);
- RTL_W16(tp, INT_CFG1_8125, 0x0000);
---- a/drivers/net/ethernet/realtek/r8169_phy_config.c
-+++ b/drivers/net/ethernet/realtek/r8169_phy_config.c
-@@ -1183,7 +1183,6 @@ void r8169_hw_phy_config(struct rtl8169_
- [RTL_GIGA_MAC_VER_65] = rtl8125d_hw_phy_config,
- [RTL_GIGA_MAC_VER_66] = rtl8125bp_hw_phy_config,
- [RTL_GIGA_MAC_VER_70] = rtl8126a_hw_phy_config,
-- [RTL_GIGA_MAC_VER_71] = rtl8126a_hw_phy_config,
- };
-
- if (phy_configs[ver])
+++ /dev/null
-From f372ef6ed5a6b0401c884561d4bba1843e54d46a Mon Sep 17 00:00:00 2001
-Date: Fri, 18 Apr 2025 11:24:30 +0200
-Subject: [PATCH] r8169: merge chip versions 64 and 65 (RTL8125D)
-
-Handling of both chip versions is the same, only difference is
-the firmware. So we can merge handling of both chip versions.
-
----
- drivers/net/ethernet/realtek/r8169.h | 1 -
- drivers/net/ethernet/realtek/r8169_main.c | 4 +---
- drivers/net/ethernet/realtek/r8169_phy_config.c | 1 -
- 3 files changed, 1 insertion(+), 5 deletions(-)
-
---- a/drivers/net/ethernet/realtek/r8169.h
-+++ b/drivers/net/ethernet/realtek/r8169.h
-@@ -69,7 +69,6 @@ enum mac_version {
- RTL_GIGA_MAC_VER_61,
- RTL_GIGA_MAC_VER_63,
- RTL_GIGA_MAC_VER_64,
-- RTL_GIGA_MAC_VER_65,
- RTL_GIGA_MAC_VER_66,
- RTL_GIGA_MAC_VER_70,
- RTL_GIGA_MAC_NONE,
---- a/drivers/net/ethernet/realtek/r8169_main.c
-+++ b/drivers/net/ethernet/realtek/r8169_main.c
-@@ -106,7 +106,7 @@ static const struct rtl_chip_info {
- { 0x7cf, 0x681, RTL_GIGA_MAC_VER_66, "RTL8125BP", FIRMWARE_8125BP_2 },
-
- /* 8125D family. */
-- { 0x7cf, 0x689, RTL_GIGA_MAC_VER_65, "RTL8125D", FIRMWARE_8125D_2 },
-+ { 0x7cf, 0x689, RTL_GIGA_MAC_VER_64, "RTL8125D", FIRMWARE_8125D_2 },
- { 0x7cf, 0x688, RTL_GIGA_MAC_VER_64, "RTL8125D", FIRMWARE_8125D_1 },
-
- /* 8125B family. */
-@@ -3834,7 +3834,6 @@ static void rtl_hw_config(struct rtl8169
- [RTL_GIGA_MAC_VER_61] = rtl_hw_start_8125a_2,
- [RTL_GIGA_MAC_VER_63] = rtl_hw_start_8125b,
- [RTL_GIGA_MAC_VER_64] = rtl_hw_start_8125d,
-- [RTL_GIGA_MAC_VER_65] = rtl_hw_start_8125d,
- [RTL_GIGA_MAC_VER_66] = rtl_hw_start_8125d,
- [RTL_GIGA_MAC_VER_70] = rtl_hw_start_8126a,
- };
-@@ -3853,7 +3852,6 @@ static void rtl_hw_start_8125(struct rtl
- switch (tp->mac_version) {
- case RTL_GIGA_MAC_VER_61:
- case RTL_GIGA_MAC_VER_64:
-- case RTL_GIGA_MAC_VER_65:
- case RTL_GIGA_MAC_VER_66:
- for (i = 0xa00; i < 0xb00; i += 4)
- RTL_W32(tp, i, 0);
---- a/drivers/net/ethernet/realtek/r8169_phy_config.c
-+++ b/drivers/net/ethernet/realtek/r8169_phy_config.c
-@@ -1180,7 +1180,6 @@ void r8169_hw_phy_config(struct rtl8169_
- [RTL_GIGA_MAC_VER_61] = rtl8125a_2_hw_phy_config,
- [RTL_GIGA_MAC_VER_63] = rtl8125b_hw_phy_config,
- [RTL_GIGA_MAC_VER_64] = rtl8125d_hw_phy_config,
-- [RTL_GIGA_MAC_VER_65] = rtl8125d_hw_phy_config,
- [RTL_GIGA_MAC_VER_66] = rtl8125bp_hw_phy_config,
- [RTL_GIGA_MAC_VER_70] = rtl8126a_hw_phy_config,
- };
+++ /dev/null
-From 4f51e7d370a04122fa78470b031d6487c52298b1 Mon Sep 17 00:00:00 2001
-Date: Fri, 18 Apr 2025 11:25:17 +0200
-Subject: [PATCH] r8169: merge chip versions 52 and 53 (RTL8117)
-
-Handling of both chip versions is the same, only difference is
-the firmware. So we can merge handling of both chip versions.
-
----
- drivers/net/ethernet/realtek/r8169.h | 1 -
- drivers/net/ethernet/realtek/r8169_main.c | 17 +++++++----------
- drivers/net/ethernet/realtek/r8169_phy_config.c | 1 -
- 3 files changed, 7 insertions(+), 12 deletions(-)
-
---- a/drivers/net/ethernet/realtek/r8169.h
-+++ b/drivers/net/ethernet/realtek/r8169.h
-@@ -64,7 +64,6 @@ enum mac_version {
- /* support for RTL_GIGA_MAC_VER_50 has been removed */
- RTL_GIGA_MAC_VER_51,
- RTL_GIGA_MAC_VER_52,
-- RTL_GIGA_MAC_VER_53,
- /* support for RTL_GIGA_MAC_VER_60 has been removed */
- RTL_GIGA_MAC_VER_61,
- RTL_GIGA_MAC_VER_63,
---- a/drivers/net/ethernet/realtek/r8169_main.c
-+++ b/drivers/net/ethernet/realtek/r8169_main.c
-@@ -116,7 +116,7 @@ static const struct rtl_chip_info {
- { 0x7cf, 0x609, RTL_GIGA_MAC_VER_61, "RTL8125A", FIRMWARE_8125A_3 },
-
- /* RTL8117 */
-- { 0x7cf, 0x54b, RTL_GIGA_MAC_VER_53, "RTL8168fp/RTL8117" },
-+ { 0x7cf, 0x54b, RTL_GIGA_MAC_VER_52, "RTL8168fp/RTL8117" },
- { 0x7cf, 0x54a, RTL_GIGA_MAC_VER_52, "RTL8168fp/RTL8117",
- FIRMWARE_8168FP_3 },
-
-@@ -831,7 +831,7 @@ static bool rtl_is_8168evl_up(struct rtl
- {
- return tp->mac_version >= RTL_GIGA_MAC_VER_34 &&
- tp->mac_version != RTL_GIGA_MAC_VER_39 &&
-- tp->mac_version <= RTL_GIGA_MAC_VER_53;
-+ tp->mac_version <= RTL_GIGA_MAC_VER_52;
- }
-
- static bool rtl_supports_eee(struct rtl8169_private *tp)
-@@ -999,9 +999,7 @@ void r8169_get_led_name(struct rtl8169_p
- static void r8168fp_adjust_ocp_cmd(struct rtl8169_private *tp, u32 *cmd, int type)
- {
- /* based on RTL8168FP_OOBMAC_BASE in vendor driver */
-- if (type == ERIAR_OOB &&
-- (tp->mac_version == RTL_GIGA_MAC_VER_52 ||
-- tp->mac_version == RTL_GIGA_MAC_VER_53))
-+ if (type == ERIAR_OOB && tp->mac_version == RTL_GIGA_MAC_VER_52)
- *cmd |= 0xf70 << 18;
- }
-
-@@ -1501,7 +1499,7 @@ static enum rtl_dash_type rtl_get_dash_t
- case RTL_GIGA_MAC_VER_28:
- case RTL_GIGA_MAC_VER_31:
- return RTL_DASH_DP;
-- case RTL_GIGA_MAC_VER_51 ... RTL_GIGA_MAC_VER_53:
-+ case RTL_GIGA_MAC_VER_51 ... RTL_GIGA_MAC_VER_52:
- return RTL_DASH_EP;
- case RTL_GIGA_MAC_VER_66:
- return RTL_DASH_25_BP;
-@@ -2489,7 +2487,7 @@ static void rtl_init_rxcfg(struct rtl816
- case RTL_GIGA_MAC_VER_38:
- RTL_W32(tp, RxConfig, RX128_INT_EN | RX_MULTI_EN | RX_DMA_BURST);
- break;
-- case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_53:
-+ case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_52:
- RTL_W32(tp, RxConfig, RX128_INT_EN | RX_MULTI_EN | RX_DMA_BURST | RX_EARLY_OFF);
- break;
- case RTL_GIGA_MAC_VER_61:
-@@ -2620,7 +2618,7 @@ DECLARE_RTL_COND(rtl_rxtx_empty_cond_2)
- static void rtl_wait_txrx_fifo_empty(struct rtl8169_private *tp)
- {
- switch (tp->mac_version) {
-- case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_53:
-+ case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_52:
- rtl_loop_wait_high(tp, &rtl_txcfg_empty_cond, 100, 42);
- rtl_loop_wait_high(tp, &rtl_rxtx_empty_cond, 100, 42);
- break;
-@@ -3830,7 +3828,6 @@ static void rtl_hw_config(struct rtl8169
- [RTL_GIGA_MAC_VER_48] = rtl_hw_start_8168h_1,
- [RTL_GIGA_MAC_VER_51] = rtl_hw_start_8168ep_3,
- [RTL_GIGA_MAC_VER_52] = rtl_hw_start_8117,
-- [RTL_GIGA_MAC_VER_53] = rtl_hw_start_8117,
- [RTL_GIGA_MAC_VER_61] = rtl_hw_start_8125a_2,
- [RTL_GIGA_MAC_VER_63] = rtl_hw_start_8125b,
- [RTL_GIGA_MAC_VER_64] = rtl_hw_start_8125d,
-@@ -5294,7 +5291,7 @@ static void rtl_hw_init_8125(struct rtl8
- static void rtl_hw_initialize(struct rtl8169_private *tp)
- {
- switch (tp->mac_version) {
-- case RTL_GIGA_MAC_VER_51 ... RTL_GIGA_MAC_VER_53:
-+ case RTL_GIGA_MAC_VER_51 ... RTL_GIGA_MAC_VER_52:
- rtl8168ep_stop_cmac(tp);
- fallthrough;
- case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_48:
---- a/drivers/net/ethernet/realtek/r8169_phy_config.c
-+++ b/drivers/net/ethernet/realtek/r8169_phy_config.c
-@@ -1176,7 +1176,6 @@ void r8169_hw_phy_config(struct rtl8169_
- [RTL_GIGA_MAC_VER_48] = rtl8168h_2_hw_phy_config,
- [RTL_GIGA_MAC_VER_51] = rtl8168ep_2_hw_phy_config,
- [RTL_GIGA_MAC_VER_52] = rtl8117_hw_phy_config,
-- [RTL_GIGA_MAC_VER_53] = rtl8117_hw_phy_config,
- [RTL_GIGA_MAC_VER_61] = rtl8125a_2_hw_phy_config,
- [RTL_GIGA_MAC_VER_63] = rtl8125b_hw_phy_config,
- [RTL_GIGA_MAC_VER_64] = rtl8125d_hw_phy_config,
+++ /dev/null
-From f24f7b2f3af9e008ded20f804d7829ee2efd43f2 Mon Sep 17 00:00:00 2001
-Date: Thu, 15 May 2025 17:53:03 +0800
-Subject: [PATCH] r8169: add support for RTL8127A
-
-This adds support for 10Gbs chip RTL8127A.
-
----
- drivers/net/ethernet/realtek/r8169.h | 1 +
- drivers/net/ethernet/realtek/r8169_main.c | 29 ++-
- .../net/ethernet/realtek/r8169_phy_config.c | 166 ++++++++++++++++++
- 3 files changed, 193 insertions(+), 3 deletions(-)
-
---- a/drivers/net/ethernet/realtek/r8169.h
-+++ b/drivers/net/ethernet/realtek/r8169.h
-@@ -70,6 +70,7 @@ enum mac_version {
- RTL_GIGA_MAC_VER_64,
- RTL_GIGA_MAC_VER_66,
- RTL_GIGA_MAC_VER_70,
-+ RTL_GIGA_MAC_VER_80,
- RTL_GIGA_MAC_NONE,
- RTL_GIGA_MAC_VER_LAST = RTL_GIGA_MAC_NONE - 1
- };
---- a/drivers/net/ethernet/realtek/r8169_main.c
-+++ b/drivers/net/ethernet/realtek/r8169_main.c
-@@ -60,6 +60,7 @@
- #define FIRMWARE_8125BP_2 "rtl_nic/rtl8125bp-2.fw"
- #define FIRMWARE_8126A_2 "rtl_nic/rtl8126a-2.fw"
- #define FIRMWARE_8126A_3 "rtl_nic/rtl8126a-3.fw"
-+#define FIRMWARE_8127A_1 "rtl_nic/rtl8127a-1.fw"
-
- #define TX_DMA_BURST 7 /* Maximum PCI burst, '7' is unlimited */
- #define InterFrameGap 0x03 /* 3 means InterFrameGap = the shortest one */
-@@ -98,6 +99,9 @@ static const struct rtl_chip_info {
- const char *name;
- const char *fw_name;
- } rtl_chip_infos[] = {
-+ /* 8127A family. */
-+ { 0x7cf, 0x6c9, RTL_GIGA_MAC_VER_80, "RTL8127A", FIRMWARE_8127A_1 },
-+
- /* 8126A family. */
- { 0x7cf, 0x64a, RTL_GIGA_MAC_VER_70, "RTL8126A", FIRMWARE_8126A_3 },
- { 0x7cf, 0x649, RTL_GIGA_MAC_VER_70, "RTL8126A", FIRMWARE_8126A_2 },
-@@ -222,8 +226,10 @@ static const struct pci_device_id rtl816
- { 0x0001, 0x8168, PCI_ANY_ID, 0x2410 },
- { PCI_VDEVICE(REALTEK, 0x8125) },
- { PCI_VDEVICE(REALTEK, 0x8126) },
-+ { PCI_VDEVICE(REALTEK, 0x8127) },
- { PCI_VDEVICE(REALTEK, 0x3000) },
- { PCI_VDEVICE(REALTEK, 0x5000) },
-+ { PCI_VDEVICE(REALTEK, 0x0e10) },
- {}
- };
-
-@@ -770,6 +776,7 @@ MODULE_FIRMWARE(FIRMWARE_8125D_2);
- MODULE_FIRMWARE(FIRMWARE_8125BP_2);
- MODULE_FIRMWARE(FIRMWARE_8126A_2);
- MODULE_FIRMWARE(FIRMWARE_8126A_3);
-+MODULE_FIRMWARE(FIRMWARE_8127A_1);
-
- static inline struct device *tp_to_dev(struct rtl8169_private *tp)
- {
-@@ -2941,6 +2948,7 @@ static void rtl_hw_aspm_clkreq_enable(st
- rtl_mod_config5(tp, 0, ASPM_en);
- switch (tp->mac_version) {
- case RTL_GIGA_MAC_VER_70:
-+ case RTL_GIGA_MAC_VER_80:
- val8 = RTL_R8(tp, INT_CFG0_8125) | INT_CFG0_CLKREQEN;
- RTL_W8(tp, INT_CFG0_8125, val8);
- break;
-@@ -2972,6 +2980,7 @@ static void rtl_hw_aspm_clkreq_enable(st
-
- switch (tp->mac_version) {
- case RTL_GIGA_MAC_VER_70:
-+ case RTL_GIGA_MAC_VER_80:
- val8 = RTL_R8(tp, INT_CFG0_8125) & ~INT_CFG0_CLKREQEN;
- RTL_W8(tp, INT_CFG0_8125, val8);
- break;
-@@ -3691,10 +3700,13 @@ static void rtl_hw_start_8125_common(str
- /* disable new tx descriptor format */
- r8168_mac_ocp_modify(tp, 0xeb58, 0x0001, 0x0000);
-
-- if (tp->mac_version == RTL_GIGA_MAC_VER_70)
-+ if (tp->mac_version == RTL_GIGA_MAC_VER_70 ||
-+ tp->mac_version == RTL_GIGA_MAC_VER_80)
- RTL_W8(tp, 0xD8, RTL_R8(tp, 0xD8) & ~0x02);
-
-- if (tp->mac_version == RTL_GIGA_MAC_VER_70)
-+ if (tp->mac_version == RTL_GIGA_MAC_VER_80)
-+ r8168_mac_ocp_modify(tp, 0xe614, 0x0f00, 0x0f00);
-+ else if (tp->mac_version == RTL_GIGA_MAC_VER_70)
- r8168_mac_ocp_modify(tp, 0xe614, 0x0700, 0x0400);
- else if (tp->mac_version == RTL_GIGA_MAC_VER_63)
- r8168_mac_ocp_modify(tp, 0xe614, 0x0700, 0x0200);
-@@ -3712,7 +3724,8 @@ static void rtl_hw_start_8125_common(str
- r8168_mac_ocp_modify(tp, 0xe056, 0x00f0, 0x0000);
- r8168_mac_ocp_modify(tp, 0xe040, 0x1000, 0x0000);
- r8168_mac_ocp_modify(tp, 0xea1c, 0x0003, 0x0001);
-- if (tp->mac_version == RTL_GIGA_MAC_VER_70)
-+ if (tp->mac_version == RTL_GIGA_MAC_VER_70 ||
-+ tp->mac_version == RTL_GIGA_MAC_VER_80)
- r8168_mac_ocp_modify(tp, 0xea1c, 0x0300, 0x0000);
- else
- r8168_mac_ocp_modify(tp, 0xea1c, 0x0004, 0x0000);
-@@ -3790,6 +3803,12 @@ static void rtl_hw_start_8126a(struct rt
- rtl_hw_start_8125_common(tp);
- }
-
-+static void rtl_hw_start_8127a(struct rtl8169_private *tp)
-+{
-+ rtl_set_def_aspm_entry_latency(tp);
-+ rtl_hw_start_8125_common(tp);
-+}
-+
- static void rtl_hw_config(struct rtl8169_private *tp)
- {
- static const rtl_generic_fct hw_configs[] = {
-@@ -3833,6 +3852,7 @@ static void rtl_hw_config(struct rtl8169
- [RTL_GIGA_MAC_VER_64] = rtl_hw_start_8125d,
- [RTL_GIGA_MAC_VER_66] = rtl_hw_start_8125d,
- [RTL_GIGA_MAC_VER_70] = rtl_hw_start_8126a,
-+ [RTL_GIGA_MAC_VER_80] = rtl_hw_start_8127a,
- };
-
- if (hw_configs[tp->mac_version])
-@@ -3850,8 +3870,11 @@ static void rtl_hw_start_8125(struct rtl
- case RTL_GIGA_MAC_VER_61:
- case RTL_GIGA_MAC_VER_64:
- case RTL_GIGA_MAC_VER_66:
-+ case RTL_GIGA_MAC_VER_80:
- for (i = 0xa00; i < 0xb00; i += 4)
- RTL_W32(tp, i, 0);
-+ if (tp->mac_version == RTL_GIGA_MAC_VER_80)
-+ RTL_W16(tp, INT_CFG1_8125, 0x0000);
- break;
- case RTL_GIGA_MAC_VER_63:
- case RTL_GIGA_MAC_VER_70:
---- a/drivers/net/ethernet/realtek/r8169_phy_config.c
-+++ b/drivers/net/ethernet/realtek/r8169_phy_config.c
-@@ -1130,6 +1130,171 @@ static void rtl8126a_hw_phy_config(struc
- rtl8125_common_config_eee_phy(phydev);
- }
-
-+static void rtl8127a_1_hw_phy_config(struct rtl8169_private *tp,
-+ struct phy_device *phydev)
-+{
-+ r8169_apply_firmware(tp);
-+ rtl8168g_enable_gphy_10m(phydev);
-+
-+ r8168g_phy_param(phydev, 0x8415, 0xff00, 0x9300);
-+ r8168g_phy_param(phydev, 0x81a3, 0xff00, 0x0f00);
-+ r8168g_phy_param(phydev, 0x81ae, 0xff00, 0x0f00);
-+ r8168g_phy_param(phydev, 0x81b9, 0xff00, 0xb900);
-+ rtl8125_phy_param(phydev, 0x83b0, 0x0e00, 0x0000);
-+ rtl8125_phy_param(phydev, 0x83C5, 0x0e00, 0x0000);
-+ rtl8125_phy_param(phydev, 0x83da, 0x0e00, 0x0000);
-+ rtl8125_phy_param(phydev, 0x83ef, 0x0e00, 0x0000);
-+ phy_modify_paged(phydev, 0x0bf3, 0x14, 0x01f0, 0x0160);
-+ phy_modify_paged(phydev, 0x0bf3, 0x15, 0x001f, 0x0014);
-+ phy_modify_paged(phydev, 0x0bf2, 0x14, 0x6000, 0x0000);
-+ phy_modify_paged(phydev, 0x0bf2, 0x16, 0xc000, 0x0000);
-+ phy_modify_paged(phydev, 0x0bf2, 0x14, 0x1fff, 0x0187);
-+ phy_modify_paged(phydev, 0x0bf2, 0x15, 0x003f, 0x0003);
-+
-+ r8168g_phy_param(phydev, 0x8173, 0xffff, 0x8620);
-+ r8168g_phy_param(phydev, 0x8175, 0xffff, 0x8671);
-+ r8168g_phy_param(phydev, 0x817c, 0x0000, 0x2000);
-+ r8168g_phy_param(phydev, 0x8187, 0x0000, 0x2000);
-+ r8168g_phy_param(phydev, 0x8192, 0x0000, 0x2000);
-+ r8168g_phy_param(phydev, 0x819d, 0x0000, 0x2000);
-+ r8168g_phy_param(phydev, 0x81a8, 0x2000, 0x0000);
-+ r8168g_phy_param(phydev, 0x81b3, 0x2000, 0x0000);
-+ r8168g_phy_param(phydev, 0x81be, 0x0000, 0x2000);
-+ r8168g_phy_param(phydev, 0x817d, 0xff00, 0xa600);
-+ r8168g_phy_param(phydev, 0x8188, 0xff00, 0xa600);
-+ r8168g_phy_param(phydev, 0x8193, 0xff00, 0xa600);
-+ r8168g_phy_param(phydev, 0x819e, 0xff00, 0xa600);
-+ r8168g_phy_param(phydev, 0x81a9, 0xff00, 0x1400);
-+ r8168g_phy_param(phydev, 0x81b4, 0xff00, 0x1400);
-+ r8168g_phy_param(phydev, 0x81bf, 0xff00, 0xa600);
-+
-+ phy_modify_paged(phydev, 0x0aea, 0x15, 0x0028, 0x0000);
-+
-+ rtl8125_phy_param(phydev, 0x84f0, 0xffff, 0x201c);
-+ rtl8125_phy_param(phydev, 0x84f2, 0xffff, 0x3117);
-+
-+ phy_write_paged(phydev, 0x0aec, 0x13, 0x0000);
-+ phy_write_paged(phydev, 0x0ae2, 0x10, 0xffff);
-+ phy_write_paged(phydev, 0x0aec, 0x17, 0xffff);
-+ phy_write_paged(phydev, 0x0aed, 0x11, 0xffff);
-+ phy_write_paged(phydev, 0x0aec, 0x14, 0x0000);
-+ phy_modify_paged(phydev, 0x0aed, 0x10, 0x0001, 0x0000);
-+ phy_write_paged(phydev, 0x0adb, 0x14, 0x0150);
-+ rtl8125_phy_param(phydev, 0x8197, 0xff00, 0x5000);
-+ rtl8125_phy_param(phydev, 0x8231, 0xff00, 0x5000);
-+ rtl8125_phy_param(phydev, 0x82cb, 0xff00, 0x5000);
-+ rtl8125_phy_param(phydev, 0x82cd, 0xff00, 0x5700);
-+ rtl8125_phy_param(phydev, 0x8233, 0xff00, 0x5700);
-+ rtl8125_phy_param(phydev, 0x8199, 0xff00, 0x5700);
-+
-+ rtl8125_phy_param(phydev, 0x815a, 0xffff, 0x0150);
-+ rtl8125_phy_param(phydev, 0x81f4, 0xffff, 0x0150);
-+ rtl8125_phy_param(phydev, 0x828e, 0xffff, 0x0150);
-+ rtl8125_phy_param(phydev, 0x81b1, 0xffff, 0x0000);
-+ rtl8125_phy_param(phydev, 0x824b, 0xffff, 0x0000);
-+ rtl8125_phy_param(phydev, 0x82e5, 0xffff, 0x0000);
-+
-+ rtl8125_phy_param(phydev, 0x84f7, 0xff00, 0x2800);
-+ phy_modify_paged(phydev, 0x0aec, 0x11, 0x0000, 0x1000);
-+ rtl8125_phy_param(phydev, 0x81b3, 0xff00, 0xad00);
-+ rtl8125_phy_param(phydev, 0x824d, 0xff00, 0xad00);
-+ rtl8125_phy_param(phydev, 0x82e7, 0xff00, 0xad00);
-+ phy_modify_paged(phydev, 0x0ae4, 0x17, 0x000f, 0x0001);
-+ rtl8125_phy_param(phydev, 0x82ce, 0xf000, 0x4000);
-+
-+ rtl8125_phy_param(phydev, 0x84ac, 0xffff, 0x0000);
-+ rtl8125_phy_param(phydev, 0x84ae, 0xffff, 0x0000);
-+ rtl8125_phy_param(phydev, 0x84b0, 0xffff, 0xf818);
-+ rtl8125_phy_param(phydev, 0x84b2, 0xff00, 0x6000);
-+
-+ rtl8125_phy_param(phydev, 0x8ffc, 0xffff, 0x6008);
-+ rtl8125_phy_param(phydev, 0x8ffe, 0xffff, 0xf450);
-+
-+ rtl8125_phy_param(phydev, 0x8015, 0x0000, 0x0200);
-+ rtl8125_phy_param(phydev, 0x8016, 0x0800, 0x0000);
-+ rtl8125_phy_param(phydev, 0x8fe6, 0xff00, 0x0800);
-+ rtl8125_phy_param(phydev, 0x8fe4, 0xffff, 0x2114);
-+
-+ rtl8125_phy_param(phydev, 0x8647, 0xffff, 0xa7b1);
-+ rtl8125_phy_param(phydev, 0x8649, 0xffff, 0xbbca);
-+ rtl8125_phy_param(phydev, 0x864b, 0xff00, 0xdc00);
-+
-+ rtl8125_phy_param(phydev, 0x8154, 0xc000, 0x4000);
-+ rtl8125_phy_param(phydev, 0x8158, 0xc000, 0x0000);
-+
-+ rtl8125_phy_param(phydev, 0x826c, 0xffff, 0xffff);
-+ rtl8125_phy_param(phydev, 0x826e, 0xffff, 0xffff);
-+
-+ rtl8125_phy_param(phydev, 0x8872, 0xff00, 0x0e00);
-+ r8168g_phy_param(phydev, 0x8012, 0x0000, 0x0800);
-+ r8168g_phy_param(phydev, 0x8012, 0x0000, 0x4000);
-+ phy_modify_paged(phydev, 0x0b57, 0x13, 0x0000, 0x0001);
-+ r8168g_phy_param(phydev, 0x834a, 0xff00, 0x0700);
-+ rtl8125_phy_param(phydev, 0x8217, 0x3f00, 0x2a00);
-+ r8168g_phy_param(phydev, 0x81b1, 0xff00, 0x0b00);
-+ rtl8125_phy_param(phydev, 0x8fed, 0xff00, 0x4e00);
-+
-+ rtl8125_phy_param(phydev, 0x88ac, 0xff00, 0x2300);
-+ phy_modify_paged(phydev, 0x0bf0, 0x16, 0x0000, 0x3800);
-+ rtl8125_phy_param(phydev, 0x88de, 0xff00, 0x0000);
-+ rtl8125_phy_param(phydev, 0x80b4, 0xffff, 0x5195);
-+
-+ r8168g_phy_param(phydev, 0x8370, 0xffff, 0x8671);
-+ r8168g_phy_param(phydev, 0x8372, 0xffff, 0x86c8);
-+
-+ r8168g_phy_param(phydev, 0x8401, 0xffff, 0x86c8);
-+ r8168g_phy_param(phydev, 0x8403, 0xffff, 0x86da);
-+ r8168g_phy_param(phydev, 0x8406, 0x1800, 0x1000);
-+ r8168g_phy_param(phydev, 0x8408, 0x1800, 0x1000);
-+ r8168g_phy_param(phydev, 0x840a, 0x1800, 0x1000);
-+ r8168g_phy_param(phydev, 0x840c, 0x1800, 0x1000);
-+ r8168g_phy_param(phydev, 0x840e, 0x1800, 0x1000);
-+ r8168g_phy_param(phydev, 0x8410, 0x1800, 0x1000);
-+ r8168g_phy_param(phydev, 0x8412, 0x1800, 0x1000);
-+ r8168g_phy_param(phydev, 0x8414, 0x1800, 0x1000);
-+ r8168g_phy_param(phydev, 0x8416, 0x1800, 0x1000);
-+
-+ r8168g_phy_param(phydev, 0x82bd, 0xffff, 0x1f40);
-+
-+ phy_modify_paged(phydev, 0x0bfb, 0x12, 0x07ff, 0x0328);
-+ phy_write_paged(phydev, 0x0bfb, 0x13, 0x3e14);
-+
-+ r8168g_phy_param(phydev, 0x81c4, 0xffff, 0x003b);
-+ r8168g_phy_param(phydev, 0x81c6, 0xffff, 0x0086);
-+ r8168g_phy_param(phydev, 0x81c8, 0xffff, 0x00b7);
-+ r8168g_phy_param(phydev, 0x81ca, 0xffff, 0x00db);
-+ r8168g_phy_param(phydev, 0x81cc, 0xffff, 0x00fe);
-+ r8168g_phy_param(phydev, 0x81ce, 0xffff, 0x00fe);
-+ r8168g_phy_param(phydev, 0x81d0, 0xffff, 0x00fe);
-+ r8168g_phy_param(phydev, 0x81d2, 0xffff, 0x00fe);
-+ r8168g_phy_param(phydev, 0x81d4, 0xffff, 0x00c3);
-+ r8168g_phy_param(phydev, 0x81d6, 0xffff, 0x0078);
-+ r8168g_phy_param(phydev, 0x81d8, 0xffff, 0x0047);
-+ r8168g_phy_param(phydev, 0x81da, 0xffff, 0x0023);
-+
-+ rtl8125_phy_param(phydev, 0x88d7, 0xffff, 0x01a0);
-+ rtl8125_phy_param(phydev, 0x88d9, 0xffff, 0x01a0);
-+ rtl8125_phy_param(phydev, 0x8ffa, 0xffff, 0x002a);
-+
-+ rtl8125_phy_param(phydev, 0x8fee, 0xffff, 0xffdf);
-+ rtl8125_phy_param(phydev, 0x8ff0, 0xffff, 0xffff);
-+ rtl8125_phy_param(phydev, 0x8ff2, 0xffff, 0x0a4a);
-+ rtl8125_phy_param(phydev, 0x8ff4, 0xffff, 0xaa5a);
-+ rtl8125_phy_param(phydev, 0x8ff6, 0xffff, 0x0a4a);
-+
-+ rtl8125_phy_param(phydev, 0x8ff8, 0xffff, 0xaa5a);
-+ rtl8125_phy_param(phydev, 0x88d5, 0xff00, 0x0200);
-+
-+ r8168g_phy_param(phydev, 0x84bb, 0xff00, 0x0a00);
-+ r8168g_phy_param(phydev, 0x84c0, 0xff00, 0x1600);
-+
-+ phy_modify_paged(phydev, 0x0a43, 0x10, 0x0000, 0x0003);
-+
-+ rtl8125_legacy_force_mode(phydev);
-+ rtl8168g_disable_aldps(phydev);
-+ rtl8125_common_config_eee_phy(phydev);
-+}
-+
- void r8169_hw_phy_config(struct rtl8169_private *tp, struct phy_device *phydev,
- enum mac_version ver)
- {
-@@ -1181,6 +1346,7 @@ void r8169_hw_phy_config(struct rtl8169_
- [RTL_GIGA_MAC_VER_64] = rtl8125d_hw_phy_config,
- [RTL_GIGA_MAC_VER_66] = rtl8125bp_hw_phy_config,
- [RTL_GIGA_MAC_VER_70] = rtl8126a_hw_phy_config,
-+ [RTL_GIGA_MAC_VER_80] = rtl8127a_1_hw_phy_config,
- };
-
- if (phy_configs[ver])
+++ /dev/null
-From 5befa3728b855e9f75b29bb0069a1ca7f5bab2f7 Mon Sep 17 00:00:00 2001
-Date: Wed, 31 Jan 2024 21:24:29 +0100
-Subject: [PATCH] net: phy: realtek: add support for RTL8126A-integrated 5Gbps
- PHY
-
-A user reported that first consumer mainboards show up with a RTL8126A
-5Gbps MAC/PHY. This adds support for the integrated PHY, which is also
-available stand-alone. From a PHY driver perspective it's treated the
-same as the 2.5Gbps PHY's, we just have to support the new PHY ID.
-
----
- drivers/net/phy/realtek.c | 10 ++++++++++
- 1 file changed, 10 insertions(+)
-
---- a/drivers/net/phy/realtek.c
-+++ b/drivers/net/phy/realtek.c
-@@ -1050,6 +1050,16 @@ static struct phy_driver realtek_drvs[]
- .read_page = rtl821x_read_page,
- .write_page = rtl821x_write_page,
- }, {
-+ PHY_ID_MATCH_EXACT(0x001cc862),
-+ .name = "RTL8251B 5Gbps PHY",
-+ .get_features = rtl822x_get_features,
-+ .config_aneg = rtl822x_config_aneg,
-+ .read_status = rtl822x_read_status,
-+ .suspend = genphy_suspend,
-+ .resume = rtlgen_resume,
-+ .read_page = rtl821x_read_page,
-+ .write_page = rtl821x_write_page,
-+ }, {
- PHY_ID_MATCH_EXACT(0x001cc961),
- .name = "RTL8366RB Gigabit Ethernet",
- .config_init = &rtl8366rb_config_init,
+++ /dev/null
-From 2b9ec5dfb8255656ca731ab9d9bf59d94566d377 Mon Sep 17 00:00:00 2001
-Date: Sun, 4 Feb 2024 15:17:53 +0100
-Subject: [PATCH] net: phy: realtek: use generic MDIO constants
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Drop the ad-hoc MDIO constants used in the driver and use generic
-constants instead.
-
----
- drivers/net/phy/realtek.c | 30 +++++++++++++-----------------
- 1 file changed, 13 insertions(+), 17 deletions(-)
-
---- a/drivers/net/phy/realtek.c
-+++ b/drivers/net/phy/realtek.c
-@@ -57,14 +57,6 @@
- #define RTL8366RB_POWER_SAVE 0x15
- #define RTL8366RB_POWER_SAVE_ON BIT(12)
-
--#define RTL_SUPPORTS_5000FULL BIT(14)
--#define RTL_SUPPORTS_2500FULL BIT(13)
--#define RTL_SUPPORTS_10000FULL BIT(0)
--#define RTL_ADV_2500FULL BIT(7)
--#define RTL_LPADV_10000FULL BIT(11)
--#define RTL_LPADV_5000FULL BIT(6)
--#define RTL_LPADV_2500FULL BIT(5)
--
- #define RTL9000A_GINMR 0x14
- #define RTL9000A_GINMR_LINK_STATUS BIT(4)
-
-@@ -676,11 +668,11 @@ static int rtl822x_get_features(struct p
- return val;
-
- linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
-- phydev->supported, val & RTL_SUPPORTS_2500FULL);
-+ phydev->supported, val & MDIO_PMA_SPEED_2_5G);
- linkmode_mod_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT,
-- phydev->supported, val & RTL_SUPPORTS_5000FULL);
-+ phydev->supported, val & MDIO_PMA_SPEED_5G);
- linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT,
-- phydev->supported, val & RTL_SUPPORTS_10000FULL);
-+ phydev->supported, val & MDIO_SPEED_10G);
-
- return genphy_read_abilities(phydev);
- }
-@@ -694,10 +686,11 @@ static int rtl822x_config_aneg(struct ph
-
- if (linkmode_test_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
- phydev->advertising))
-- adv2500 = RTL_ADV_2500FULL;
-+ adv2500 = MDIO_AN_10GBT_CTRL_ADV2_5G;
-
- ret = phy_modify_paged_changed(phydev, 0xa5d, 0x12,
-- RTL_ADV_2500FULL, adv2500);
-+ MDIO_AN_10GBT_CTRL_ADV2_5G,
-+ adv2500);
- if (ret < 0)
- return ret;
- }
-@@ -716,11 +709,14 @@ static int rtl822x_read_status(struct ph
- return lpadv;
-
- linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT,
-- phydev->lp_advertising, lpadv & RTL_LPADV_10000FULL);
-+ phydev->lp_advertising,
-+ lpadv & MDIO_AN_10GBT_STAT_LP10G);
- linkmode_mod_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT,
-- phydev->lp_advertising, lpadv & RTL_LPADV_5000FULL);
-+ phydev->lp_advertising,
-+ lpadv & MDIO_AN_10GBT_STAT_LP5G);
- linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
-- phydev->lp_advertising, lpadv & RTL_LPADV_2500FULL);
-+ phydev->lp_advertising,
-+ lpadv & MDIO_AN_10GBT_STAT_LP2_5G);
- }
-
- ret = genphy_read_status(phydev);
-@@ -738,7 +734,7 @@ static bool rtlgen_supports_2_5gbps(stru
- val = phy_read(phydev, 0x13);
- phy_write(phydev, RTL821x_PAGE_SELECT, 0);
-
-- return val >= 0 && val & RTL_SUPPORTS_2500FULL;
-+ return val >= 0 && val & MDIO_PMA_SPEED_2_5G;
- }
-
- static int rtlgen_match_phy_device(struct phy_device *phydev)
+++ /dev/null
-From db1bb7741ff29bf2cefcbc0ca567644e9ed1caa9 Mon Sep 17 00:00:00 2001
-Date: Sun, 4 Feb 2024 15:18:50 +0100
-Subject: [PATCH] net: phy: realtek: add 5Gbps support to rtl822x_config_aneg()
-
-RTL8126 as an evolution of RTL8125 supports 5Gbps. rtl822x_config_aneg()
-is used by the PHY driver for the integrated PHY, therefore add 5Gbps
-support to it.
-
----
- drivers/net/phy/realtek.c | 12 ++++++++----
- 1 file changed, 8 insertions(+), 4 deletions(-)
-
---- a/drivers/net/phy/realtek.c
-+++ b/drivers/net/phy/realtek.c
-@@ -682,15 +682,19 @@ static int rtl822x_config_aneg(struct ph
- int ret = 0;
-
- if (phydev->autoneg == AUTONEG_ENABLE) {
-- u16 adv2500 = 0;
-+ u16 adv = 0;
-
- if (linkmode_test_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
- phydev->advertising))
-- adv2500 = MDIO_AN_10GBT_CTRL_ADV2_5G;
-+ adv |= MDIO_AN_10GBT_CTRL_ADV2_5G;
-+ if (linkmode_test_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT,
-+ phydev->advertising))
-+ adv |= MDIO_AN_10GBT_CTRL_ADV5G;
-
- ret = phy_modify_paged_changed(phydev, 0xa5d, 0x12,
-- MDIO_AN_10GBT_CTRL_ADV2_5G,
-- adv2500);
-+ MDIO_AN_10GBT_CTRL_ADV2_5G |
-+ MDIO_AN_10GBT_CTRL_ADV5G,
-+ adv);
- if (ret < 0)
- return ret;
- }
+++ /dev/null
-From b63cc73341e076961d564a74cc3d29b2fd444079 Mon Sep 17 00:00:00 2001
-Date: Thu, 8 Feb 2024 07:59:18 +0100
-Subject: [PATCH] net: phy: realtek: use generic MDIO helpers to simplify the
- code
-
-Use generic MDIO helpers to simplify the code.
-
----
- drivers/net/phy/realtek.c | 20 +++-----------------
- 1 file changed, 3 insertions(+), 17 deletions(-)
-
---- a/drivers/net/phy/realtek.c
-+++ b/drivers/net/phy/realtek.c
-@@ -682,14 +682,7 @@ static int rtl822x_config_aneg(struct ph
- int ret = 0;
-
- if (phydev->autoneg == AUTONEG_ENABLE) {
-- u16 adv = 0;
--
-- if (linkmode_test_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
-- phydev->advertising))
-- adv |= MDIO_AN_10GBT_CTRL_ADV2_5G;
-- if (linkmode_test_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT,
-- phydev->advertising))
-- adv |= MDIO_AN_10GBT_CTRL_ADV5G;
-+ u16 adv = linkmode_adv_to_mii_10gbt_adv_t(phydev->advertising);
-
- ret = phy_modify_paged_changed(phydev, 0xa5d, 0x12,
- MDIO_AN_10GBT_CTRL_ADV2_5G |
-@@ -712,15 +705,8 @@ static int rtl822x_read_status(struct ph
- if (lpadv < 0)
- return lpadv;
-
-- linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT,
-- phydev->lp_advertising,
-- lpadv & MDIO_AN_10GBT_STAT_LP10G);
-- linkmode_mod_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT,
-- phydev->lp_advertising,
-- lpadv & MDIO_AN_10GBT_STAT_LP5G);
-- linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
-- phydev->lp_advertising,
-- lpadv & MDIO_AN_10GBT_STAT_LP2_5G);
-+ mii_10gbt_stat_mod_linkmode_lpa_t(phydev->lp_advertising,
-+ lpadv);
- }
-
- ret = genphy_read_status(phydev);
+++ /dev/null
-From deb8af5243504e379878ae3f9a091b21422d65b2 Mon Sep 17 00:00:00 2001
-Date: Tue, 9 Apr 2024 09:30:11 +0200
-Subject: [PATCH] net: phy: realtek: configure SerDes mode for rtl822xb PHYs
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-The rtl8221b and rtl8226b series support switching SerDes mode between
-2500base-x and sgmii based on the negotiated copper speed.
-
-Configure this switching mode according to SerDes modes supported by
-host.
-
-There is an additional datasheet for RTL8226B/RTL8221B called
-"SERDES MODE SETTING FLOW APPLICATION NOTE" where a sequence is
-described to setup interface and rate adapter mode.
-
-However, there is no documentation about the meaning of registers
-and bits, it's literally just magic numbers and pseudo-code.
-
-[ refactored, dropped HiSGMII mode and changed commit message ]
-[ changed rtl822x_update_interface() to use vendor register ]
-[ always fill in possible interfaces ]
-[ only apply to rtl8221b and rtl8226b phy's ]
-[ set phydev->rate_matching in .config_init() ]
-
-Reviewed-by: should come before them, without any blank lines. As the
----
- drivers/net/phy/realtek.c | 114 ++++++++++++++++++++++++++++++++++++--
- 1 file changed, 110 insertions(+), 4 deletions(-)
-
---- a/drivers/net/phy/realtek.c
-+++ b/drivers/net/phy/realtek.c
-@@ -54,6 +54,16 @@
- RTL8201F_ISR_LINK)
- #define RTL8201F_IER 0x13
-
-+#define RTL822X_VND1_SERDES_OPTION 0x697a
-+#define RTL822X_VND1_SERDES_OPTION_MODE_MASK GENMASK(5, 0)
-+#define RTL822X_VND1_SERDES_OPTION_MODE_2500BASEX_SGMII 0
-+#define RTL822X_VND1_SERDES_OPTION_MODE_2500BASEX 2
-+
-+#define RTL822X_VND1_SERDES_CTRL3 0x7580
-+#define RTL822X_VND1_SERDES_CTRL3_MODE_MASK GENMASK(5, 0)
-+#define RTL822X_VND1_SERDES_CTRL3_MODE_SGMII 0x02
-+#define RTL822X_VND1_SERDES_CTRL3_MODE_2500BASEX 0x16
-+
- #define RTL8366RB_POWER_SAVE 0x15
- #define RTL8366RB_POWER_SAVE_ON BIT(12)
-
-@@ -659,6 +669,63 @@ static int rtl822x_write_mmd(struct phy_
- return ret;
- }
-
-+static int rtl822xb_config_init(struct phy_device *phydev)
-+{
-+ bool has_2500, has_sgmii;
-+ u16 mode;
-+ int ret;
-+
-+ has_2500 = test_bit(PHY_INTERFACE_MODE_2500BASEX,
-+ phydev->host_interfaces) ||
-+ phydev->interface == PHY_INTERFACE_MODE_2500BASEX;
-+
-+ has_sgmii = test_bit(PHY_INTERFACE_MODE_SGMII,
-+ phydev->host_interfaces) ||
-+ phydev->interface == PHY_INTERFACE_MODE_SGMII;
-+
-+ /* fill in possible interfaces */
-+ __assign_bit(PHY_INTERFACE_MODE_2500BASEX, phydev->possible_interfaces,
-+ has_2500);
-+ __assign_bit(PHY_INTERFACE_MODE_SGMII, phydev->possible_interfaces,
-+ has_sgmii);
-+
-+ if (!has_2500 && !has_sgmii)
-+ return 0;
-+
-+ /* determine SerDes option mode */
-+ if (has_2500 && !has_sgmii) {
-+ mode = RTL822X_VND1_SERDES_OPTION_MODE_2500BASEX;
-+ phydev->rate_matching = RATE_MATCH_PAUSE;
-+ } else {
-+ mode = RTL822X_VND1_SERDES_OPTION_MODE_2500BASEX_SGMII;
-+ phydev->rate_matching = RATE_MATCH_NONE;
-+ }
-+
-+ /* the following sequence with magic numbers sets up the SerDes
-+ * option mode
-+ */
-+ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x75f3, 0);
-+ if (ret < 0)
-+ return ret;
-+
-+ ret = phy_modify_mmd_changed(phydev, MDIO_MMD_VEND1,
-+ RTL822X_VND1_SERDES_OPTION,
-+ RTL822X_VND1_SERDES_OPTION_MODE_MASK,
-+ mode);
-+ if (ret < 0)
-+ return ret;
-+
-+ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x6a04, 0x0503);
-+ if (ret < 0)
-+ return ret;
-+
-+ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x6f10, 0xd455);
-+ if (ret < 0)
-+ return ret;
-+
-+ return phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x6f11, 0x8020);
-+}
-+
- static int rtl822x_get_features(struct phy_device *phydev)
- {
- int val;
-@@ -695,6 +762,28 @@ static int rtl822x_config_aneg(struct ph
- return __genphy_config_aneg(phydev, ret);
- }
-
-+static void rtl822xb_update_interface(struct phy_device *phydev)
-+{
-+ int val;
-+
-+ if (!phydev->link)
-+ return;
-+
-+ /* Change interface according to serdes mode */
-+ val = phy_read_mmd(phydev, MDIO_MMD_VEND1, RTL822X_VND1_SERDES_CTRL3);
-+ if (val < 0)
-+ return;
-+
-+ switch (val & RTL822X_VND1_SERDES_CTRL3_MODE_MASK) {
-+ case RTL822X_VND1_SERDES_CTRL3_MODE_2500BASEX:
-+ phydev->interface = PHY_INTERFACE_MODE_2500BASEX;
-+ break;
-+ case RTL822X_VND1_SERDES_CTRL3_MODE_SGMII:
-+ phydev->interface = PHY_INTERFACE_MODE_SGMII;
-+ break;
-+ }
-+}
-+
- static int rtl822x_read_status(struct phy_device *phydev)
- {
- int ret;
-@@ -716,6 +805,19 @@ static int rtl822x_read_status(struct ph
- return rtlgen_get_speed(phydev);
- }
-
-+static int rtl822xb_read_status(struct phy_device *phydev)
-+{
-+ int ret;
-+
-+ ret = rtl822x_read_status(phydev);
-+ if (ret < 0)
-+ return ret;
-+
-+ rtl822xb_update_interface(phydev);
-+
-+ return 0;
-+}
-+
- static bool rtlgen_supports_2_5gbps(struct phy_device *phydev)
- {
- int val;
-@@ -988,7 +1090,8 @@ static struct phy_driver realtek_drvs[]
- .name = "RTL8226B_RTL8221B 2.5Gbps PHY",
- .get_features = rtl822x_get_features,
- .config_aneg = rtl822x_config_aneg,
-- .read_status = rtl822x_read_status,
-+ .config_init = rtl822xb_config_init,
-+ .read_status = rtl822xb_read_status,
- .suspend = genphy_suspend,
- .resume = rtlgen_resume,
- .read_page = rtl821x_read_page,
-@@ -1010,7 +1113,8 @@ static struct phy_driver realtek_drvs[]
- .name = "RTL8226B-CG_RTL8221B-CG 2.5Gbps PHY",
- .get_features = rtl822x_get_features,
- .config_aneg = rtl822x_config_aneg,
-- .read_status = rtl822x_read_status,
-+ .config_init = rtl822xb_config_init,
-+ .read_status = rtl822xb_read_status,
- .suspend = genphy_suspend,
- .resume = rtlgen_resume,
- .read_page = rtl821x_read_page,
-@@ -1020,7 +1124,8 @@ static struct phy_driver realtek_drvs[]
- .name = "RTL8221B-VB-CG 2.5Gbps PHY",
- .get_features = rtl822x_get_features,
- .config_aneg = rtl822x_config_aneg,
-- .read_status = rtl822x_read_status,
-+ .config_init = rtl822xb_config_init,
-+ .read_status = rtl822xb_read_status,
- .suspend = genphy_suspend,
- .resume = rtlgen_resume,
- .read_page = rtl821x_read_page,
-@@ -1030,7 +1135,8 @@ static struct phy_driver realtek_drvs[]
- .name = "RTL8221B-VM-CG 2.5Gbps PHY",
- .get_features = rtl822x_get_features,
- .config_aneg = rtl822x_config_aneg,
-- .read_status = rtl822x_read_status,
-+ .config_init = rtl822xb_config_init,
-+ .read_status = rtl822xb_read_status,
- .suspend = genphy_suspend,
- .resume = rtlgen_resume,
- .read_page = rtl821x_read_page,
+++ /dev/null
-From c189dbd738243be6775bb6878366bf63e27bfd05 Mon Sep 17 00:00:00 2001
-Date: Tue, 9 Apr 2024 09:30:12 +0200
-Subject: [PATCH] net: phy: realtek: add get_rate_matching() for rtl822xb PHYs
-
-Uses vendor register to determine if SerDes is setup in rate-matching mode.
-
-Rate-matching only supported when SerDes is set to 2500base-x.
-
----
- drivers/net/phy/realtek.c | 25 +++++++++++++++++++++++++
- 1 file changed, 25 insertions(+)
-
---- a/drivers/net/phy/realtek.c
-+++ b/drivers/net/phy/realtek.c
-@@ -726,6 +726,27 @@ static int rtl822xb_config_init(struct p
- return phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x6f11, 0x8020);
- }
-
-+static int rtl822xb_get_rate_matching(struct phy_device *phydev,
-+ phy_interface_t iface)
-+{
-+ int val;
-+
-+ /* Only rate matching at 2500base-x */
-+ if (iface != PHY_INTERFACE_MODE_2500BASEX)
-+ return RATE_MATCH_NONE;
-+
-+ val = phy_read_mmd(phydev, MDIO_MMD_VEND1, RTL822X_VND1_SERDES_OPTION);
-+ if (val < 0)
-+ return val;
-+
-+ if ((val & RTL822X_VND1_SERDES_OPTION_MODE_MASK) ==
-+ RTL822X_VND1_SERDES_OPTION_MODE_2500BASEX)
-+ return RATE_MATCH_PAUSE;
-+
-+ /* RTL822X_VND1_SERDES_OPTION_MODE_2500BASEX_SGMII */
-+ return RATE_MATCH_NONE;
-+}
-+
- static int rtl822x_get_features(struct phy_device *phydev)
- {
- int val;
-@@ -1091,6 +1112,7 @@ static struct phy_driver realtek_drvs[]
- .get_features = rtl822x_get_features,
- .config_aneg = rtl822x_config_aneg,
- .config_init = rtl822xb_config_init,
-+ .get_rate_matching = rtl822xb_get_rate_matching,
- .read_status = rtl822xb_read_status,
- .suspend = genphy_suspend,
- .resume = rtlgen_resume,
-@@ -1114,6 +1136,7 @@ static struct phy_driver realtek_drvs[]
- .get_features = rtl822x_get_features,
- .config_aneg = rtl822x_config_aneg,
- .config_init = rtl822xb_config_init,
-+ .get_rate_matching = rtl822xb_get_rate_matching,
- .read_status = rtl822xb_read_status,
- .suspend = genphy_suspend,
- .resume = rtlgen_resume,
-@@ -1125,6 +1148,7 @@ static struct phy_driver realtek_drvs[]
- .get_features = rtl822x_get_features,
- .config_aneg = rtl822x_config_aneg,
- .config_init = rtl822xb_config_init,
-+ .get_rate_matching = rtl822xb_get_rate_matching,
- .read_status = rtl822xb_read_status,
- .suspend = genphy_suspend,
- .resume = rtlgen_resume,
-@@ -1136,6 +1160,7 @@ static struct phy_driver realtek_drvs[]
- .get_features = rtl822x_get_features,
- .config_aneg = rtl822x_config_aneg,
- .config_init = rtl822xb_config_init,
-+ .get_rate_matching = rtl822xb_get_rate_matching,
- .read_status = rtl822xb_read_status,
- .suspend = genphy_suspend,
- .resume = rtlgen_resume,
+++ /dev/null
-From ad5ce743a6b0329f642d80be50ef7b534e908fba Mon Sep 17 00:00:00 2001
-Date: Tue, 9 Apr 2024 09:30:13 +0200
-Subject: [PATCH] net: phy: realtek: Add driver instances for rtl8221b via
- Clause 45
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Collected from several commits in [PATCH net-next]
-"Realtek RTL822x PHY rework to c45 and SerDes interface switching"
-
-The instances are used by Clause 45 only accessible PHY's on several sfp
-modules, which are using RollBall protocol.
-
-[ Added matching functions to differentiate C45 instances ]
-
----
- drivers/net/phy/realtek.c | 135 ++++++++++++++++++++++++++++++++++++--
- 1 file changed, 131 insertions(+), 4 deletions(-)
-
---- a/drivers/net/phy/realtek.c
-+++ b/drivers/net/phy/realtek.c
-@@ -64,6 +64,13 @@
- #define RTL822X_VND1_SERDES_CTRL3_MODE_SGMII 0x02
- #define RTL822X_VND1_SERDES_CTRL3_MODE_2500BASEX 0x16
-
-+/* RTL822X_VND2_XXXXX registers are only accessible when phydev->is_c45
-+ * is set, they cannot be accessed by C45-over-C22.
-+ */
-+#define RTL822X_VND2_GBCR 0xa412
-+
-+#define RTL822X_VND2_GANLPAR 0xa414
-+
- #define RTL8366RB_POWER_SAVE 0x15
- #define RTL8366RB_POWER_SAVE_ON BIT(12)
-
-@@ -74,6 +81,9 @@
-
- #define RTL_GENERIC_PHYID 0x001cc800
- #define RTL_8211FVD_PHYID 0x001cc878
-+#define RTL_8221B_VB_CG 0x001cc849
-+#define RTL_8221B_VN_CG 0x001cc84a
-+#define RTL_8251B 0x001cc862
-
- MODULE_DESCRIPTION("Realtek PHY driver");
- MODULE_AUTHOR("Johnson Leung");
-@@ -839,6 +849,67 @@ static int rtl822xb_read_status(struct p
- return 0;
- }
-
-+static int rtl822x_c45_config_aneg(struct phy_device *phydev)
-+{
-+ bool changed = false;
-+ int ret, val;
-+
-+ if (phydev->autoneg == AUTONEG_DISABLE)
-+ return genphy_c45_pma_setup_forced(phydev);
-+
-+ ret = genphy_c45_an_config_aneg(phydev);
-+ if (ret < 0)
-+ return ret;
-+ if (ret > 0)
-+ changed = true;
-+
-+ val = linkmode_adv_to_mii_ctrl1000_t(phydev->advertising);
-+
-+ /* Vendor register as C45 has no standardized support for 1000BaseT */
-+ ret = phy_modify_mmd_changed(phydev, MDIO_MMD_VEND2, RTL822X_VND2_GBCR,
-+ ADVERTISE_1000FULL, val);
-+ if (ret < 0)
-+ return ret;
-+ if (ret > 0)
-+ changed = true;
-+
-+ return genphy_c45_check_and_restart_aneg(phydev, changed);
-+}
-+
-+static int rtl822x_c45_read_status(struct phy_device *phydev)
-+{
-+ int ret, val;
-+
-+ ret = genphy_c45_read_status(phydev);
-+ if (ret < 0)
-+ return ret;
-+
-+ /* Vendor register as C45 has no standardized support for 1000BaseT */
-+ if (phydev->autoneg == AUTONEG_ENABLE) {
-+ val = phy_read_mmd(phydev, MDIO_MMD_VEND2,
-+ RTL822X_VND2_GANLPAR);
-+ if (val < 0)
-+ return val;
-+
-+ mii_stat1000_mod_linkmode_lpa_t(phydev->lp_advertising, val);
-+ }
-+
-+ return 0;
-+}
-+
-+static int rtl822xb_c45_read_status(struct phy_device *phydev)
-+{
-+ int ret;
-+
-+ ret = rtl822x_c45_read_status(phydev);
-+ if (ret < 0)
-+ return ret;
-+
-+ rtl822xb_update_interface(phydev);
-+
-+ return 0;
-+}
-+
- static bool rtlgen_supports_2_5gbps(struct phy_device *phydev)
- {
- int val;
-@@ -862,6 +933,35 @@ static int rtl8226_match_phy_device(stru
- rtlgen_supports_2_5gbps(phydev);
- }
-
-+static int rtlgen_is_c45_match(struct phy_device *phydev, unsigned int id,
-+ bool is_c45)
-+{
-+ if (phydev->is_c45)
-+ return is_c45 && (id == phydev->c45_ids.device_ids[1]);
-+ else
-+ return !is_c45 && (id == phydev->phy_id);
-+}
-+
-+static int rtl8221b_vb_cg_c22_match_phy_device(struct phy_device *phydev)
-+{
-+ return rtlgen_is_c45_match(phydev, RTL_8221B_VB_CG, false);
-+}
-+
-+static int rtl8221b_vb_cg_c45_match_phy_device(struct phy_device *phydev)
-+{
-+ return rtlgen_is_c45_match(phydev, RTL_8221B_VB_CG, true);
-+}
-+
-+static int rtl8221b_vn_cg_c22_match_phy_device(struct phy_device *phydev)
-+{
-+ return rtlgen_is_c45_match(phydev, RTL_8221B_VN_CG, false);
-+}
-+
-+static int rtl8221b_vn_cg_c45_match_phy_device(struct phy_device *phydev)
-+{
-+ return rtlgen_is_c45_match(phydev, RTL_8221B_VN_CG, true);
-+}
-+
- static int rtlgen_resume(struct phy_device *phydev)
- {
- int ret = genphy_resume(phydev);
-@@ -872,6 +972,15 @@ static int rtlgen_resume(struct phy_devi
- return ret;
- }
-
-+static int rtlgen_c45_resume(struct phy_device *phydev)
-+{
-+ int ret = genphy_c45_pma_resume(phydev);
-+
-+ msleep(20);
-+
-+ return ret;
-+}
-+
- static int rtl9000a_config_init(struct phy_device *phydev)
- {
- phydev->autoneg = AUTONEG_DISABLE;
-@@ -1143,8 +1252,8 @@ static struct phy_driver realtek_drvs[]
- .read_page = rtl821x_read_page,
- .write_page = rtl821x_write_page,
- }, {
-- PHY_ID_MATCH_EXACT(0x001cc849),
-- .name = "RTL8221B-VB-CG 2.5Gbps PHY",
-+ .match_phy_device = rtl8221b_vb_cg_c22_match_phy_device,
-+ .name = "RTL8221B-VB-CG 2.5Gbps PHY (C22)",
- .get_features = rtl822x_get_features,
- .config_aneg = rtl822x_config_aneg,
- .config_init = rtl822xb_config_init,
-@@ -1155,8 +1264,17 @@ static struct phy_driver realtek_drvs[]
- .read_page = rtl821x_read_page,
- .write_page = rtl821x_write_page,
- }, {
-- PHY_ID_MATCH_EXACT(0x001cc84a),
-- .name = "RTL8221B-VM-CG 2.5Gbps PHY",
-+ .match_phy_device = rtl8221b_vb_cg_c45_match_phy_device,
-+ .name = "RTL8221B-VB-CG 2.5Gbps PHY (C45)",
-+ .config_init = rtl822xb_config_init,
-+ .get_rate_matching = rtl822xb_get_rate_matching,
-+ .config_aneg = rtl822x_c45_config_aneg,
-+ .read_status = rtl822xb_c45_read_status,
-+ .suspend = genphy_c45_pma_suspend,
-+ .resume = rtlgen_c45_resume,
-+ }, {
-+ .match_phy_device = rtl8221b_vn_cg_c22_match_phy_device,
-+ .name = "RTL8221B-VM-CG 2.5Gbps PHY (C22)",
- .get_features = rtl822x_get_features,
- .config_aneg = rtl822x_config_aneg,
- .config_init = rtl822xb_config_init,
-@@ -1167,6 +1285,15 @@ static struct phy_driver realtek_drvs[]
- .read_page = rtl821x_read_page,
- .write_page = rtl821x_write_page,
- }, {
-+ .match_phy_device = rtl8221b_vn_cg_c45_match_phy_device,
-+ .name = "RTL8221B-VN-CG 2.5Gbps PHY (C45)",
-+ .config_init = rtl822xb_config_init,
-+ .get_rate_matching = rtl822xb_get_rate_matching,
-+ .config_aneg = rtl822x_c45_config_aneg,
-+ .read_status = rtl822xb_c45_read_status,
-+ .suspend = genphy_c45_pma_suspend,
-+ .resume = rtlgen_c45_resume,
-+ }, {
- PHY_ID_MATCH_EXACT(0x001cc862),
- .name = "RTL8251B 5Gbps PHY",
- .get_features = rtl822x_get_features,
+++ /dev/null
-From 2e4ea707c7e04eb83e58c43e0e744bbdf6b23ff2 Mon Sep 17 00:00:00 2001
-Date: Tue, 9 Apr 2024 09:30:14 +0200
-Subject: [PATCH] net: phy: realtek: Change rtlgen_get_speed() to
- rtlgen_decode_speed()
-
-The value of the register to determine the speed, is retrieved
-differently when using Clause 45 only. To use the rtlgen_get_speed()
-function in this case, pass the value of the register as argument to
-rtlgen_get_speed(). The function would then always return 0, so change it
-to void. A better name for this function now is rtlgen_decode_speed().
-
-Replace a call to genphy_read_status() followed by rtlgen_get_speed()
-with a call to rtlgen_read_status() in rtl822x_read_status().
-
-Add reading speed to rtl822x_c45_read_status().
-
-
----
- drivers/net/phy/realtek.c | 46 +++++++++++++++++++++------------------
- 1 file changed, 25 insertions(+), 21 deletions(-)
-
---- a/drivers/net/phy/realtek.c
-+++ b/drivers/net/phy/realtek.c
-@@ -71,6 +71,8 @@
-
- #define RTL822X_VND2_GANLPAR 0xa414
-
-+#define RTL822X_VND2_PHYSR 0xa434
-+
- #define RTL8366RB_POWER_SAVE 0x15
- #define RTL8366RB_POWER_SAVE_ON BIT(12)
-
-@@ -551,17 +553,8 @@ static int rtl8366rb_config_init(struct
- }
-
- /* get actual speed to cover the downshift case */
--static int rtlgen_get_speed(struct phy_device *phydev)
-+static void rtlgen_decode_speed(struct phy_device *phydev, int val)
- {
-- int val;
--
-- if (!phydev->link)
-- return 0;
--
-- val = phy_read_paged(phydev, 0xa43, 0x12);
-- if (val < 0)
-- return val;
--
- switch (val & RTLGEN_SPEED_MASK) {
- case 0x0000:
- phydev->speed = SPEED_10;
-@@ -584,19 +577,26 @@ static int rtlgen_get_speed(struct phy_d
- default:
- break;
- }
--
-- return 0;
- }
-
- static int rtlgen_read_status(struct phy_device *phydev)
- {
-- int ret;
-+ int ret, val;
-
- ret = genphy_read_status(phydev);
- if (ret < 0)
- return ret;
-
-- return rtlgen_get_speed(phydev);
-+ if (!phydev->link)
-+ return 0;
-+
-+ val = phy_read_paged(phydev, 0xa43, 0x12);
-+ if (val < 0)
-+ return val;
-+
-+ rtlgen_decode_speed(phydev, val);
-+
-+ return 0;
- }
-
- static int rtlgen_read_mmd(struct phy_device *phydev, int devnum, u16 regnum)
-@@ -817,8 +817,6 @@ static void rtl822xb_update_interface(st
-
- static int rtl822x_read_status(struct phy_device *phydev)
- {
-- int ret;
--
- if (phydev->autoneg == AUTONEG_ENABLE) {
- int lpadv = phy_read_paged(phydev, 0xa5d, 0x13);
-
-@@ -829,11 +827,7 @@ static int rtl822x_read_status(struct ph
- lpadv);
- }
-
-- ret = genphy_read_status(phydev);
-- if (ret < 0)
-- return ret;
--
-- return rtlgen_get_speed(phydev);
-+ return rtlgen_read_status(phydev);
- }
-
- static int rtl822xb_read_status(struct phy_device *phydev)
-@@ -894,6 +888,16 @@ static int rtl822x_c45_read_status(struc
- mii_stat1000_mod_linkmode_lpa_t(phydev->lp_advertising, val);
- }
-
-+ if (!phydev->link)
-+ return 0;
-+
-+ /* Read actual speed from vendor register. */
-+ val = phy_read_mmd(phydev, MDIO_MMD_VEND2, RTL822X_VND2_PHYSR);
-+ if (val < 0)
-+ return val;
-+
-+ rtlgen_decode_speed(phydev, val);
-+
- return 0;
- }
-
+++ /dev/null
-From 2d9ce64862705b33397d54dafecc5f51d8b1bb06 Mon Sep 17 00:00:00 2001
-Date: Tue, 9 Apr 2024 09:30:15 +0200
-Subject: [PATCH] net: phy: realtek: add rtl822x_c45_get_features() to set
- supported port
-
-Sets ETHTOOL_LINK_MODE_TP_BIT in phydev->supported.
-
----
- drivers/net/phy/realtek.c | 10 ++++++++++
- 1 file changed, 10 insertions(+)
-
---- a/drivers/net/phy/realtek.c
-+++ b/drivers/net/phy/realtek.c
-@@ -843,6 +843,14 @@ static int rtl822xb_read_status(struct p
- return 0;
- }
-
-+static int rtl822x_c45_get_features(struct phy_device *phydev)
-+{
-+ linkmode_set_bit(ETHTOOL_LINK_MODE_TP_BIT,
-+ phydev->supported);
-+
-+ return genphy_c45_pma_read_abilities(phydev);
-+}
-+
- static int rtl822x_c45_config_aneg(struct phy_device *phydev)
- {
- bool changed = false;
-@@ -1272,6 +1280,7 @@ static struct phy_driver realtek_drvs[]
- .name = "RTL8221B-VB-CG 2.5Gbps PHY (C45)",
- .config_init = rtl822xb_config_init,
- .get_rate_matching = rtl822xb_get_rate_matching,
-+ .get_features = rtl822x_c45_get_features,
- .config_aneg = rtl822x_c45_config_aneg,
- .read_status = rtl822xb_c45_read_status,
- .suspend = genphy_c45_pma_suspend,
-@@ -1293,6 +1302,7 @@ static struct phy_driver realtek_drvs[]
- .name = "RTL8221B-VN-CG 2.5Gbps PHY (C45)",
- .config_init = rtl822xb_config_init,
- .get_rate_matching = rtl822xb_get_rate_matching,
-+ .get_features = rtl822x_c45_get_features,
- .config_aneg = rtl822x_c45_config_aneg,
- .read_status = rtl822xb_c45_read_status,
- .suspend = genphy_c45_pma_suspend,
+++ /dev/null
-From 9e42a2ea7f6703e2092c39171c2bf1fd7eec0bd3 Mon Sep 17 00:00:00 2001
-Date: Tue, 11 Jun 2024 17:34:14 +1200
-Subject: [PATCH] net: phy: realtek: add support for rtl8224 2.5Gbps PHY
-
-The Realtek RTL8224 PHY is a 2.5Gbps capable PHY. It only uses the
-clause 45 MDIO interface and can leverage the support that has already
-been added for the other 822x PHYs.
-
----
- drivers/net/phy/realtek.c | 8 ++++++++
- 1 file changed, 8 insertions(+)
-
---- a/drivers/net/phy/realtek.c
-+++ b/drivers/net/phy/realtek.c
-@@ -1318,6 +1318,14 @@ static struct phy_driver realtek_drvs[]
- .read_page = rtl821x_read_page,
- .write_page = rtl821x_write_page,
- }, {
-+ PHY_ID_MATCH_EXACT(0x001ccad0),
-+ .name = "RTL8224 2.5Gbps PHY",
-+ .get_features = rtl822x_c45_get_features,
-+ .config_aneg = rtl822x_c45_config_aneg,
-+ .read_status = rtl822x_c45_read_status,
-+ .suspend = genphy_c45_pma_suspend,
-+ .resume = rtlgen_c45_resume,
-+ }, {
- PHY_ID_MATCH_EXACT(0x001cc961),
- .name = "RTL8366RB Gigabit Ethernet",
- .config_init = &rtl8366rb_config_init,
+++ /dev/null
-From 17784801d888238571a0c4101b9ac4401fffeaa0 Mon Sep 17 00:00:00 2001
-Date: Tue, 25 Jun 2024 22:42:17 +0200
-Subject: [PATCH] net: phy: realtek: Add support for PHY LEDs on RTL8211F
-
-Realtek RTL8211F Ethernet PHY supports 3 LED pins which are used to
-indicate link status and activity. Add minimal LED controller driver
-supporting the most common uses with the 'netdev' trigger.
-
----
- drivers/net/phy/realtek.c | 106 ++++++++++++++++++++++++++++++++++++++
- 1 file changed, 106 insertions(+)
-
---- a/drivers/net/phy/realtek.c
-+++ b/drivers/net/phy/realtek.c
-@@ -32,6 +32,15 @@
- #define RTL8211F_PHYCR2 0x19
- #define RTL8211F_INSR 0x1d
-
-+#define RTL8211F_LEDCR 0x10
-+#define RTL8211F_LEDCR_MODE BIT(15)
-+#define RTL8211F_LEDCR_ACT_TXRX BIT(4)
-+#define RTL8211F_LEDCR_LINK_1000 BIT(3)
-+#define RTL8211F_LEDCR_LINK_100 BIT(1)
-+#define RTL8211F_LEDCR_LINK_10 BIT(0)
-+#define RTL8211F_LEDCR_MASK GENMASK(4, 0)
-+#define RTL8211F_LEDCR_SHIFT 5
-+
- #define RTL8211F_TX_DELAY BIT(8)
- #define RTL8211F_RX_DELAY BIT(3)
-
-@@ -87,6 +96,8 @@
- #define RTL_8221B_VN_CG 0x001cc84a
- #define RTL_8251B 0x001cc862
-
-+#define RTL8211F_LED_COUNT 3
-+
- MODULE_DESCRIPTION("Realtek PHY driver");
- MODULE_AUTHOR("Johnson Leung");
- MODULE_LICENSE("GPL");
-@@ -476,6 +487,98 @@ static int rtl821x_resume(struct phy_dev
- return 0;
- }
-
-+static int rtl8211f_led_hw_is_supported(struct phy_device *phydev, u8 index,
-+ unsigned long rules)
-+{
-+ const unsigned long mask = BIT(TRIGGER_NETDEV_LINK_10) |
-+ BIT(TRIGGER_NETDEV_LINK_100) |
-+ BIT(TRIGGER_NETDEV_LINK_1000) |
-+ BIT(TRIGGER_NETDEV_RX) |
-+ BIT(TRIGGER_NETDEV_TX);
-+
-+ /* The RTL8211F PHY supports these LED settings on up to three LEDs:
-+ * - Link: Configurable subset of 10/100/1000 link rates
-+ * - Active: Blink on activity, RX or TX is not differentiated
-+ * The Active option has two modes, A and B:
-+ * - A: Link and Active indication at configurable, but matching,
-+ * subset of 10/100/1000 link rates
-+ * - B: Link indication at configurable subset of 10/100/1000 link
-+ * rates and Active indication always at all three 10+100+1000
-+ * link rates.
-+ * This code currently uses mode B only.
-+ */
-+
-+ if (index >= RTL8211F_LED_COUNT)
-+ return -EINVAL;
-+
-+ /* Filter out any other unsupported triggers. */
-+ if (rules & ~mask)
-+ return -EOPNOTSUPP;
-+
-+ /* RX and TX are not differentiated, either both are set or not set. */
-+ if (!(rules & BIT(TRIGGER_NETDEV_RX)) ^ !(rules & BIT(TRIGGER_NETDEV_TX)))
-+ return -EOPNOTSUPP;
-+
-+ return 0;
-+}
-+
-+static int rtl8211f_led_hw_control_get(struct phy_device *phydev, u8 index,
-+ unsigned long *rules)
-+{
-+ int val;
-+
-+ val = phy_read_paged(phydev, 0xd04, RTL8211F_LEDCR);
-+ if (val < 0)
-+ return val;
-+
-+ val >>= RTL8211F_LEDCR_SHIFT * index;
-+ val &= RTL8211F_LEDCR_MASK;
-+
-+ if (val & RTL8211F_LEDCR_LINK_10)
-+ set_bit(TRIGGER_NETDEV_LINK_10, rules);
-+
-+ if (val & RTL8211F_LEDCR_LINK_100)
-+ set_bit(TRIGGER_NETDEV_LINK_100, rules);
-+
-+ if (val & RTL8211F_LEDCR_LINK_1000)
-+ set_bit(TRIGGER_NETDEV_LINK_1000, rules);
-+
-+ if (val & RTL8211F_LEDCR_ACT_TXRX) {
-+ set_bit(TRIGGER_NETDEV_RX, rules);
-+ set_bit(TRIGGER_NETDEV_TX, rules);
-+ }
-+
-+ return 0;
-+}
-+
-+static int rtl8211f_led_hw_control_set(struct phy_device *phydev, u8 index,
-+ unsigned long rules)
-+{
-+ const u16 mask = RTL8211F_LEDCR_MASK << (RTL8211F_LEDCR_SHIFT * index);
-+ u16 reg = RTL8211F_LEDCR_MODE; /* Mode B */
-+
-+ if (index >= RTL8211F_LED_COUNT)
-+ return -EINVAL;
-+
-+ if (test_bit(TRIGGER_NETDEV_LINK_10, &rules))
-+ reg |= RTL8211F_LEDCR_LINK_10;
-+
-+ if (test_bit(TRIGGER_NETDEV_LINK_100, &rules))
-+ reg |= RTL8211F_LEDCR_LINK_100;
-+
-+ if (test_bit(TRIGGER_NETDEV_LINK_1000, &rules))
-+ reg |= RTL8211F_LEDCR_LINK_1000;
-+
-+ if (test_bit(TRIGGER_NETDEV_RX, &rules) ||
-+ test_bit(TRIGGER_NETDEV_TX, &rules)) {
-+ reg |= RTL8211F_LEDCR_ACT_TXRX;
-+ }
-+
-+ reg <<= RTL8211F_LEDCR_SHIFT * index;
-+
-+ return phy_modify_paged(phydev, 0xd04, RTL8211F_LEDCR, mask, reg);
-+}
-+
- static int rtl8211e_config_init(struct phy_device *phydev)
- {
- int ret = 0, oldpage;
-@@ -1192,6 +1295,9 @@ static struct phy_driver realtek_drvs[]
- .read_page = rtl821x_read_page,
- .write_page = rtl821x_write_page,
- .flags = PHY_ALWAYS_CALL_SUSPEND,
-+ .led_hw_is_supported = rtl8211f_led_hw_is_supported,
-+ .led_hw_control_get = rtl8211f_led_hw_control_get,
-+ .led_hw_control_set = rtl8211f_led_hw_control_set,
- }, {
- PHY_ID_MATCH_EXACT(RTL_8211FVD_PHYID),
- .name = "RTL8211F-VD Gigabit Ethernet",
+++ /dev/null
-From a2f5c505b4378cd6fc7c4a44ff3665ccef2037db Mon Sep 17 00:00:00 2001
-Date: Wed, 21 Aug 2024 04:16:57 +0200
-Subject: [PATCH] net: phy: realtek: Fix setting of PHY LEDs Mode B bit on
- RTL8211F
-
-The current implementation incorrectly sets the mode bit of the PHY chip.
-Bit 15 (RTL8211F_LEDCR_MODE) should not be shifted together with the
-configuration nibble of a LED- it should be set independently of the
-index of the LED being configured.
-As a consequence, the RTL8211F LED control is actually operating in Mode A.
-Fix the error by or-ing final register value to write with a const-value of
-RTL8211F_LEDCR_MODE, thus setting Mode bit explicitly.
-
-Fixes: 17784801d888 ("net: phy: realtek: Add support for PHY LEDs on RTL8211F")
-Link: https://patch.msgid.link/PAWP192MB21287372F30C4E55B6DF6158C38E2@PAWP192MB2128.EURP192.PROD.OUTLOOK.COM
----
- drivers/net/phy/realtek.c | 3 ++-
- 1 file changed, 2 insertions(+), 1 deletion(-)
-
---- a/drivers/net/phy/realtek.c
-+++ b/drivers/net/phy/realtek.c
-@@ -555,7 +555,7 @@ static int rtl8211f_led_hw_control_set(s
- unsigned long rules)
- {
- const u16 mask = RTL8211F_LEDCR_MASK << (RTL8211F_LEDCR_SHIFT * index);
-- u16 reg = RTL8211F_LEDCR_MODE; /* Mode B */
-+ u16 reg = 0;
-
- if (index >= RTL8211F_LED_COUNT)
- return -EINVAL;
-@@ -575,6 +575,7 @@ static int rtl8211f_led_hw_control_set(s
- }
-
- reg <<= RTL8211F_LEDCR_SHIFT * index;
-+ reg |= RTL8211F_LEDCR_MODE; /* Mode B */
-
- return phy_modify_paged(phydev, 0xd04, RTL8211F_LEDCR, mask, reg);
- }
+++ /dev/null
-From c283782fc5d60c4d8169137c6f955aa3553d3b3d Mon Sep 17 00:00:00 2001
-Date: Fri, 27 Sep 2024 19:46:10 +0800
-Subject: [PATCH] net: phy: realtek: Check the index value in
- led_hw_control_get
-
-Just like rtl8211f_led_hw_is_supported() and
-rtl8211f_led_hw_control_set(), the rtl8211f_led_hw_control_get() also
-needs to check the index value, otherwise the caller is likely to get
-an incorrect rules.
-
-Fixes: 17784801d888 ("net: phy: realtek: Add support for PHY LEDs on RTL8211F")
----
- drivers/net/phy/realtek.c | 3 +++
- 1 file changed, 3 insertions(+)
-
---- a/drivers/net/phy/realtek.c
-+++ b/drivers/net/phy/realtek.c
-@@ -527,6 +527,9 @@ static int rtl8211f_led_hw_control_get(s
- {
- int val;
-
-+ if (index >= RTL8211F_LED_COUNT)
-+ return -EINVAL;
-+
- val = phy_read_paged(phydev, 0xd04, RTL8211F_LEDCR);
- if (val < 0)
- return val;
+++ /dev/null
-From a6ad589c1d118f9d5b1bc4c6888d42919f830340 Mon Sep 17 00:00:00 2001
-Date: Mon, 7 Oct 2024 11:57:41 +0200
-Subject: [PATCH] net: phy: realtek: Fix MMD access on RTL8126A-integrated PHY
-
-All MMD reads return 0 for the RTL8126A-integrated PHY. Therefore phylib
-assumes it doesn't support EEE, what results in higher power consumption,
-and a significantly higher chip temperature in my case.
-To fix this split out the PHY driver for the RTL8126A-integrated PHY
-and set the read_mmd/write_mmd callbacks to read from vendor-specific
-registers.
-
-Fixes: 5befa3728b85 ("net: phy: realtek: add support for RTL8126A-integrated 5Gbps PHY")
----
- drivers/net/phy/realtek.c | 24 +++++++++++++++++++++++-
- 1 file changed, 23 insertions(+), 1 deletion(-)
-
---- a/drivers/net/phy/realtek.c
-+++ b/drivers/net/phy/realtek.c
-@@ -1081,6 +1081,16 @@ static int rtl8221b_vn_cg_c45_match_phy_
- return rtlgen_is_c45_match(phydev, RTL_8221B_VN_CG, true);
- }
-
-+static int rtl8251b_c22_match_phy_device(struct phy_device *phydev)
-+{
-+ return rtlgen_is_c45_match(phydev, RTL_8251B, false);
-+}
-+
-+static int rtl8251b_c45_match_phy_device(struct phy_device *phydev)
-+{
-+ return rtlgen_is_c45_match(phydev, RTL_8251B, true);
-+}
-+
- static int rtlgen_resume(struct phy_device *phydev)
- {
- int ret = genphy_resume(phydev);
-@@ -1418,7 +1428,7 @@ static struct phy_driver realtek_drvs[]
- .suspend = genphy_c45_pma_suspend,
- .resume = rtlgen_c45_resume,
- }, {
-- PHY_ID_MATCH_EXACT(0x001cc862),
-+ .match_phy_device = rtl8251b_c45_match_phy_device,
- .name = "RTL8251B 5Gbps PHY",
- .get_features = rtl822x_get_features,
- .config_aneg = rtl822x_config_aneg,
-@@ -1428,6 +1438,18 @@ static struct phy_driver realtek_drvs[]
- .read_page = rtl821x_read_page,
- .write_page = rtl821x_write_page,
- }, {
-+ .match_phy_device = rtl8251b_c22_match_phy_device,
-+ .name = "RTL8126A-internal 5Gbps PHY",
-+ .get_features = rtl822x_get_features,
-+ .config_aneg = rtl822x_config_aneg,
-+ .read_status = rtl822x_read_status,
-+ .suspend = genphy_suspend,
-+ .resume = rtlgen_resume,
-+ .read_page = rtl821x_read_page,
-+ .write_page = rtl821x_write_page,
-+ .read_mmd = rtl822x_read_mmd,
-+ .write_mmd = rtl822x_write_mmd,
-+ }, {
- PHY_ID_MATCH_EXACT(0x001ccad0),
- .name = "RTL8224 2.5Gbps PHY",
- .get_features = rtl822x_c45_get_features,
+++ /dev/null
-From 081c9c0265c91b8333165aa6230c20bcbc6f7cbf Mon Sep 17 00:00:00 2001
-Date: Thu, 10 Oct 2024 14:07:16 +0100
-Subject: [PATCH 3/5] net: phy: realtek: read duplex and gbit master from PHYSR
- register
-
-The PHYSR MMD register is present and defined equally for all RTL82xx
-Ethernet PHYs.
-Read duplex and Gbit master bits from rtlgen_decode_speed() and rename
-it to rtlgen_decode_physr().
-
-Link: https://patch.msgid.link/b9a76341da851a18c985bc4774fa295babec79bb.1728565530.git.daniel@makrotopia.org
----
- drivers/net/phy/realtek.c | 41 +++++++++++++++++++++++++++++++--------
- 1 file changed, 33 insertions(+), 8 deletions(-)
-
---- a/drivers/net/phy/realtek.c
-+++ b/drivers/net/phy/realtek.c
-@@ -80,15 +80,18 @@
-
- #define RTL822X_VND2_GANLPAR 0xa414
-
--#define RTL822X_VND2_PHYSR 0xa434
--
- #define RTL8366RB_POWER_SAVE 0x15
- #define RTL8366RB_POWER_SAVE_ON BIT(12)
-
- #define RTL9000A_GINMR 0x14
- #define RTL9000A_GINMR_LINK_STATUS BIT(4)
-
--#define RTLGEN_SPEED_MASK 0x0630
-+#define RTL_VND2_PHYSR 0xa434
-+#define RTL_VND2_PHYSR_DUPLEX BIT(3)
-+#define RTL_VND2_PHYSR_SPEEDL GENMASK(5, 4)
-+#define RTL_VND2_PHYSR_SPEEDH GENMASK(10, 9)
-+#define RTL_VND2_PHYSR_MASTER BIT(11)
-+#define RTL_VND2_PHYSR_SPEED_MASK (RTL_VND2_PHYSR_SPEEDL | RTL_VND2_PHYSR_SPEEDH)
-
- #define RTL_GENERIC_PHYID 0x001cc800
- #define RTL_8211FVD_PHYID 0x001cc878
-@@ -660,9 +663,18 @@ static int rtl8366rb_config_init(struct
- }
-
- /* get actual speed to cover the downshift case */
--static void rtlgen_decode_speed(struct phy_device *phydev, int val)
-+static void rtlgen_decode_physr(struct phy_device *phydev, int val)
- {
-- switch (val & RTLGEN_SPEED_MASK) {
-+ /* bit 3
-+ * 0: Half Duplex
-+ * 1: Full Duplex
-+ */
-+ if (val & RTL_VND2_PHYSR_DUPLEX)
-+ phydev->duplex = DUPLEX_FULL;
-+ else
-+ phydev->duplex = DUPLEX_HALF;
-+
-+ switch (val & RTL_VND2_PHYSR_SPEED_MASK) {
- case 0x0000:
- phydev->speed = SPEED_10;
- break;
-@@ -684,6 +696,19 @@ static void rtlgen_decode_speed(struct p
- default:
- break;
- }
-+
-+ /* bit 11
-+ * 0: Slave Mode
-+ * 1: Master Mode
-+ */
-+ if (phydev->speed >= 1000) {
-+ if (val & RTL_VND2_PHYSR_MASTER)
-+ phydev->master_slave_state = MASTER_SLAVE_STATE_MASTER;
-+ else
-+ phydev->master_slave_state = MASTER_SLAVE_STATE_SLAVE;
-+ } else {
-+ phydev->master_slave_state = MASTER_SLAVE_STATE_UNSUPPORTED;
-+ }
- }
-
- static int rtlgen_read_status(struct phy_device *phydev)
-@@ -701,7 +726,7 @@ static int rtlgen_read_status(struct phy
- if (val < 0)
- return val;
-
-- rtlgen_decode_speed(phydev, val);
-+ rtlgen_decode_physr(phydev, val);
-
- return 0;
- }
-@@ -1007,11 +1032,11 @@ static int rtl822x_c45_read_status(struc
- return 0;
-
- /* Read actual speed from vendor register. */
-- val = phy_read_mmd(phydev, MDIO_MMD_VEND2, RTL822X_VND2_PHYSR);
-+ val = phy_read_mmd(phydev, MDIO_MMD_VEND2, RTL_VND2_PHYSR);
- if (val < 0)
- return val;
-
-- rtlgen_decode_speed(phydev, val);
-+ rtlgen_decode_physr(phydev, val);
-
- return 0;
- }
+++ /dev/null
-From 68d5cd09e8919679ce13b85950debea4b2e98e04 Mon Sep 17 00:00:00 2001
-Date: Thu, 10 Oct 2024 14:07:26 +0100
-Subject: [PATCH 4/5] net: phy: realtek: change order of calls in C22
- read_status()
-
-Always call rtlgen_read_status() first, so genphy_read_status() which
-is called by it clears bits in case auto-negotiation has not completed.
-Also clear 10GBT link-partner advertisement bits in case auto-negotiation
-is disabled or has not completed.
-
-Link: https://patch.msgid.link/b15929a41621d215c6b2b57393368086589569ec.1728565530.git.daniel@makrotopia.org
----
- drivers/net/phy/realtek.c | 22 +++++++++++++++-------
- 1 file changed, 15 insertions(+), 7 deletions(-)
-
---- a/drivers/net/phy/realtek.c
-+++ b/drivers/net/phy/realtek.c
-@@ -949,17 +949,25 @@ static void rtl822xb_update_interface(st
-
- static int rtl822x_read_status(struct phy_device *phydev)
- {
-- if (phydev->autoneg == AUTONEG_ENABLE) {
-- int lpadv = phy_read_paged(phydev, 0xa5d, 0x13);
-+ int lpadv, ret;
-
-- if (lpadv < 0)
-- return lpadv;
-+ ret = rtlgen_read_status(phydev);
-+ if (ret < 0)
-+ return ret;
-
-- mii_10gbt_stat_mod_linkmode_lpa_t(phydev->lp_advertising,
-- lpadv);
-+ if (phydev->autoneg == AUTONEG_DISABLE ||
-+ !phydev->autoneg_complete) {
-+ mii_10gbt_stat_mod_linkmode_lpa_t(phydev->lp_advertising, 0);
-+ return 0;
- }
-
-- return rtlgen_read_status(phydev);
-+ lpadv = phy_read_paged(phydev, 0xa5d, 0x13);
-+ if (lpadv < 0)
-+ return lpadv;
-+
-+ mii_10gbt_stat_mod_linkmode_lpa_t(phydev->lp_advertising, lpadv);
-+
-+ return 0;
- }
-
- static int rtl822xb_read_status(struct phy_device *phydev)
+++ /dev/null
-From 5cb409b3960e75467cbb0a8e1e5596b4490570e3 Mon Sep 17 00:00:00 2001
-Date: Thu, 10 Oct 2024 14:07:39 +0100
-Subject: [PATCH 5/5] net: phy: realtek: clear 1000Base-T link partner
- advertisement
-
-Clear 1000Base-T link partner advertisement bits in Clause-45
-read_status() function in case auto-negotiation is disabled or has not
-been completed.
-
-Link: https://patch.msgid.link/9dc9b47b2d675708afef3ad366bfd78eb584d958.1728565530.git.daniel@makrotopia.org
----
- drivers/net/phy/realtek.c | 4 ++++
- 1 file changed, 4 insertions(+)
-
---- a/drivers/net/phy/realtek.c
-+++ b/drivers/net/phy/realtek.c
-@@ -1026,6 +1026,10 @@ static int rtl822x_c45_read_status(struc
- if (ret < 0)
- return ret;
-
-+ if (phydev->autoneg == AUTONEG_DISABLE ||
-+ !genphy_c45_aneg_done(phydev))
-+ mii_stat1000_mod_linkmode_lpa_t(phydev->lp_advertising, 0);
-+
- /* Vendor register as C45 has no standardized support for 1000BaseT */
- if (phydev->autoneg == AUTONEG_ENABLE) {
- val = phy_read_mmd(phydev, MDIO_MMD_VEND2,
+++ /dev/null
-From f87a17ed3b51fba4dfdd8f8b643b5423a85fc551 Mon Sep 17 00:00:00 2001
-Date: Tue, 15 Oct 2024 07:47:14 +0200
-Subject: [PATCH] net: phy: realtek: merge the drivers for internal NBase-T
- PHY's
-
-The Realtek RTL8125/RTL8126 NBase-T MAC/PHY chips have internal PHY's
-which are register-compatible, at least for the registers we use here.
-So let's use just one PHY driver to support all of them.
-These internal PHY's exist also as external C45 PHY's, but on the
-internal PHY's no access to MMD registers is possible. This can be
-used to differentiate between the internal and external version.
-
-As a side effect the drivers for two now external-only drivers don't
-require read_mmd/write_mmd hooks any longer.
-
----
- drivers/net/phy/realtek.c | 53 +++++++++++++++++++++++++++++++--------
- 1 file changed, 43 insertions(+), 10 deletions(-)
-
---- a/drivers/net/phy/realtek.c
-+++ b/drivers/net/phy/realtek.c
-@@ -95,6 +95,7 @@
-
- #define RTL_GENERIC_PHYID 0x001cc800
- #define RTL_8211FVD_PHYID 0x001cc878
-+#define RTL_8221B 0x001cc840
- #define RTL_8221B_VB_CG 0x001cc849
- #define RTL_8221B_VN_CG 0x001cc84a
- #define RTL_8251B 0x001cc862
-@@ -1077,6 +1078,23 @@ static bool rtlgen_supports_2_5gbps(stru
- return val >= 0 && val & MDIO_PMA_SPEED_2_5G;
- }
-
-+/* On internal PHY's MMD reads over C22 always return 0.
-+ * Check a MMD register which is known to be non-zero.
-+ */
-+static bool rtlgen_supports_mmd(struct phy_device *phydev)
-+{
-+ int val;
-+
-+ phy_lock_mdio_bus(phydev);
-+ __phy_write(phydev, MII_MMD_CTRL, MDIO_MMD_PCS);
-+ __phy_write(phydev, MII_MMD_DATA, MDIO_PCS_EEE_ABLE);
-+ __phy_write(phydev, MII_MMD_CTRL, MDIO_MMD_PCS | MII_MMD_CTRL_NOINCR);
-+ val = __phy_read(phydev, MII_MMD_DATA);
-+ phy_unlock_mdio_bus(phydev);
-+
-+ return val > 0;
-+}
-+
- static int rtlgen_match_phy_device(struct phy_device *phydev)
- {
- return phydev->phy_id == RTL_GENERIC_PHYID &&
-@@ -1086,7 +1104,8 @@ static int rtlgen_match_phy_device(struc
- static int rtl8226_match_phy_device(struct phy_device *phydev)
- {
- return phydev->phy_id == RTL_GENERIC_PHYID &&
-- rtlgen_supports_2_5gbps(phydev);
-+ rtlgen_supports_2_5gbps(phydev) &&
-+ rtlgen_supports_mmd(phydev);
- }
-
- static int rtlgen_is_c45_match(struct phy_device *phydev, unsigned int id,
-@@ -1098,6 +1117,11 @@ static int rtlgen_is_c45_match(struct ph
- return !is_c45 && (id == phydev->phy_id);
- }
-
-+static int rtl8221b_match_phy_device(struct phy_device *phydev)
-+{
-+ return phydev->phy_id == RTL_8221B && rtlgen_supports_mmd(phydev);
-+}
-+
- static int rtl8221b_vb_cg_c22_match_phy_device(struct phy_device *phydev)
- {
- return rtlgen_is_c45_match(phydev, RTL_8221B_VB_CG, false);
-@@ -1118,9 +1142,21 @@ static int rtl8221b_vn_cg_c45_match_phy_
- return rtlgen_is_c45_match(phydev, RTL_8221B_VN_CG, true);
- }
-
--static int rtl8251b_c22_match_phy_device(struct phy_device *phydev)
-+static int rtl_internal_nbaset_match_phy_device(struct phy_device *phydev)
- {
-- return rtlgen_is_c45_match(phydev, RTL_8251B, false);
-+ if (phydev->is_c45)
-+ return false;
-+
-+ switch (phydev->phy_id) {
-+ case RTL_GENERIC_PHYID:
-+ case RTL_8221B:
-+ case RTL_8251B:
-+ break;
-+ default:
-+ return false;
-+ }
-+
-+ return rtlgen_supports_2_5gbps(phydev) && !rtlgen_supports_mmd(phydev);
- }
-
- static int rtl8251b_c45_match_phy_device(struct phy_device *phydev)
-@@ -1382,10 +1418,8 @@ static struct phy_driver realtek_drvs[]
- .resume = rtlgen_resume,
- .read_page = rtl821x_read_page,
- .write_page = rtl821x_write_page,
-- .read_mmd = rtl822x_read_mmd,
-- .write_mmd = rtl822x_write_mmd,
- }, {
-- PHY_ID_MATCH_EXACT(0x001cc840),
-+ .match_phy_device = rtl8221b_match_phy_device,
- .name = "RTL8226B_RTL8221B 2.5Gbps PHY",
- .get_features = rtl822x_get_features,
- .config_aneg = rtl822x_config_aneg,
-@@ -1396,8 +1430,6 @@ static struct phy_driver realtek_drvs[]
- .resume = rtlgen_resume,
- .read_page = rtl821x_read_page,
- .write_page = rtl821x_write_page,
-- .read_mmd = rtl822x_read_mmd,
-- .write_mmd = rtl822x_write_mmd,
- }, {
- PHY_ID_MATCH_EXACT(0x001cc838),
- .name = "RTL8226-CG 2.5Gbps PHY",
-@@ -1475,8 +1507,9 @@ static struct phy_driver realtek_drvs[]
- .read_page = rtl821x_read_page,
- .write_page = rtl821x_write_page,
- }, {
-- .match_phy_device = rtl8251b_c22_match_phy_device,
-- .name = "RTL8126A-internal 5Gbps PHY",
-+ .match_phy_device = rtl_internal_nbaset_match_phy_device,
-+ .name = "Realtek Internal NBASE-T PHY",
-+ .flags = PHY_IS_INTERNAL,
- .get_features = rtl822x_get_features,
- .config_aneg = rtl822x_config_aneg,
- .read_status = rtl822x_read_status,
+++ /dev/null
-From 8989bad541133c43550bff2b80edbe37b8fb9659 Mon Sep 17 00:00:00 2001
-Date: Thu, 17 Oct 2024 18:01:13 +0200
-Subject: [PATCH] net: phy: realtek: add RTL8125D-internal PHY
-
-The first boards show up with Realtek's RTL8125D. This MAC/PHY chip
-comes with an integrated 2.5Gbps PHY with ID 0x001cc841. It's not
-clear yet whether there's an external version of this PHY and how
-Realtek calls it, therefore use the numeric id for now.
-
----
- drivers/net/phy/realtek.c | 1 +
- 1 file changed, 1 insertion(+)
-
---- a/drivers/net/phy/realtek.c
-+++ b/drivers/net/phy/realtek.c
-@@ -1151,6 +1151,7 @@ static int rtl_internal_nbaset_match_phy
- case RTL_GENERIC_PHYID:
- case RTL_8221B:
- case RTL_8251B:
-+ case 0x001cc841:
- break;
- default:
- return false;
+++ /dev/null
-From 34d5a86ff7bbe225fba3ad91f9b4dc85fb408e18 Mon Sep 17 00:00:00 2001
-Date: Wed, 15 Jan 2025 14:43:35 +0000
-Subject: [PATCH] net: phy: realtek: clear 1000Base-T lpa if link is down
-
-Only read 1000Base-T link partner advertisement if autonegotiation has
-completed and otherwise 1000Base-T link partner advertisement bits.
-
-This fixes bogus 1000Base-T link partner advertisement after link goes
-down (eg. by disconnecting the wire).
-Fixes: 5cb409b3960e ("net: phy: realtek: clear 1000Base-T link partner advertisement")
----
- drivers/net/phy/realtek.c | 19 ++++++++-----------
- 1 file changed, 8 insertions(+), 11 deletions(-)
-
---- a/drivers/net/phy/realtek.c
-+++ b/drivers/net/phy/realtek.c
-@@ -1023,23 +1023,20 @@ static int rtl822x_c45_read_status(struc
- {
- int ret, val;
-
-- ret = genphy_c45_read_status(phydev);
-- if (ret < 0)
-- return ret;
--
-- if (phydev->autoneg == AUTONEG_DISABLE ||
-- !genphy_c45_aneg_done(phydev))
-- mii_stat1000_mod_linkmode_lpa_t(phydev->lp_advertising, 0);
--
- /* Vendor register as C45 has no standardized support for 1000BaseT */
-- if (phydev->autoneg == AUTONEG_ENABLE) {
-+ if (phydev->autoneg == AUTONEG_ENABLE && genphy_c45_aneg_done(phydev)) {
- val = phy_read_mmd(phydev, MDIO_MMD_VEND2,
- RTL822X_VND2_GANLPAR);
- if (val < 0)
- return val;
--
-- mii_stat1000_mod_linkmode_lpa_t(phydev->lp_advertising, val);
-+ } else {
-+ val = 0;
- }
-+ mii_stat1000_mod_linkmode_lpa_t(phydev->lp_advertising, val);
-+
-+ ret = genphy_c45_read_status(phydev);
-+ if (ret < 0)
-+ return ret;
-
- if (!phydev->link)
- return 0;
+++ /dev/null
-From ea8318cb33e593bbfc59d637eae45a69732c5387 Mon Sep 17 00:00:00 2001
-Date: Wed, 15 Jan 2025 14:43:43 +0000
-Subject: [PATCH] net: phy: realtek: clear master_slave_state if link is down
-
-rtlgen_decode_physr() which sets master_slave_state isn't called in case
-the link is down and other than rtlgen_read_status(),
-rtl822x_c45_read_status() doesn't implicitely clear master_slave_state.
-
-Avoid stale master_slave_state by always setting it to
-MASTER_SLAVE_STATE_UNKNOWN in rtl822x_c45_read_status() in case the link
-is down.
-
-Fixes: 081c9c0265c9 ("net: phy: realtek: read duplex and gbit master from PHYSR register")
----
- drivers/net/phy/realtek.c | 4 +++-
- 1 file changed, 3 insertions(+), 1 deletion(-)
-
---- a/drivers/net/phy/realtek.c
-+++ b/drivers/net/phy/realtek.c
-@@ -1038,8 +1038,10 @@ static int rtl822x_c45_read_status(struc
- if (ret < 0)
- return ret;
-
-- if (!phydev->link)
-+ if (!phydev->link) {
-+ phydev->master_slave_state = MASTER_SLAVE_STATE_UNKNOWN;
- return 0;
-+ }
-
- /* Read actual speed from vendor register. */
- val = phy_read_mmd(phydev, MDIO_MMD_VEND2, RTL_VND2_PHYSR);
+++ /dev/null
-From d3eb58549842c60ed46f37da7f4da969e3d6ecd3 Mon Sep 17 00:00:00 2001
-Date: Wed, 15 Jan 2025 14:45:00 +0000
-Subject: [PATCH] net: phy: realtek: always clear NBase-T lpa
-
-Clear NBase-T link partner advertisement before calling
-rtlgen_read_status() to avoid phy_resolve_aneg_linkmode() wrongly
-setting speed and duplex.
-
-This fixes bogus 2.5G/5G/10G link partner advertisement and thus
-speed and duplex being set by phy_resolve_aneg_linkmode() due to stale
-NBase-T lpa.
-
-Fixes: 68d5cd09e891 ("net: phy: realtek: change order of calls in C22 read_status()")
----
- drivers/net/phy/realtek.c | 6 +++---
- 1 file changed, 3 insertions(+), 3 deletions(-)
-
---- a/drivers/net/phy/realtek.c
-+++ b/drivers/net/phy/realtek.c
-@@ -952,15 +952,15 @@ static int rtl822x_read_status(struct ph
- {
- int lpadv, ret;
-
-+ mii_10gbt_stat_mod_linkmode_lpa_t(phydev->lp_advertising, 0);
-+
- ret = rtlgen_read_status(phydev);
- if (ret < 0)
- return ret;
-
- if (phydev->autoneg == AUTONEG_DISABLE ||
-- !phydev->autoneg_complete) {
-- mii_10gbt_stat_mod_linkmode_lpa_t(phydev->lp_advertising, 0);
-+ !phydev->autoneg_complete)
- return 0;
-- }
-
- lpadv = phy_read_paged(phydev, 0xa5d, 0x13);
- if (lpadv < 0)
+++ /dev/null
-From 3d483a10327f38595f714f9f9e9dde43a622cb0f Mon Sep 17 00:00:00 2001
-Date: Sat, 11 Jan 2025 21:49:31 +0100
-Subject: [PATCH] net: phy: realtek: add support for reading MDIO_MMD_VEND2
- regs on RTL8125/RTL8126
-
-RTL8125/RTL8126 don't support MMD access to the internal PHY, but
-provide a mechanism to access at least all MDIO_MMD_VEND2 registers.
-By exposing this mechanism standard MMD access functions can be used
-to access the MDIO_MMD_VEND2 registers.
-
----
- drivers/net/phy/realtek.c | 12 ++++++++++--
- 1 file changed, 10 insertions(+), 2 deletions(-)
-
---- a/drivers/net/phy/realtek.c
-+++ b/drivers/net/phy/realtek.c
-@@ -736,7 +736,11 @@ static int rtlgen_read_mmd(struct phy_de
- {
- int ret;
-
-- if (devnum == MDIO_MMD_PCS && regnum == MDIO_PCS_EEE_ABLE) {
-+ if (devnum == MDIO_MMD_VEND2) {
-+ rtl821x_write_page(phydev, regnum >> 4);
-+ ret = __phy_read(phydev, 0x10 + ((regnum & 0xf) >> 1));
-+ rtl821x_write_page(phydev, 0);
-+ } else if (devnum == MDIO_MMD_PCS && regnum == MDIO_PCS_EEE_ABLE) {
- rtl821x_write_page(phydev, 0xa5c);
- ret = __phy_read(phydev, 0x12);
- rtl821x_write_page(phydev, 0);
-@@ -760,7 +764,11 @@ static int rtlgen_write_mmd(struct phy_d
- {
- int ret;
-
-- if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV) {
-+ if (devnum == MDIO_MMD_VEND2) {
-+ rtl821x_write_page(phydev, regnum >> 4);
-+ ret = __phy_write(phydev, 0x10 + ((regnum & 0xf) >> 1), val);
-+ rtl821x_write_page(phydev, 0);
-+ } else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV) {
- rtl821x_write_page(phydev, 0xa5d);
- ret = __phy_write(phydev, 0x10, val);
- rtl821x_write_page(phydev, 0);
+++ /dev/null
-From 1416a9b2ba710d31954131c06d46f298e340aa2c Mon Sep 17 00:00:00 2001
-Date: Sat, 11 Jan 2025 21:50:19 +0100
-Subject: [PATCH] net: phy: move realtek PHY driver to its own subdirectory
-
-In preparation of adding a source file with hwmon support, move the
-Realtek PHY driver to its own subdirectory and rename realtek.c to
-realtek_main.c.
-
----
- drivers/net/phy/Kconfig | 5 +----
- drivers/net/phy/Makefile | 2 +-
- drivers/net/phy/realtek/Kconfig | 5 +++++
- drivers/net/phy/realtek/Makefile | 3 +++
- drivers/net/phy/{realtek.c => realtek/realtek_main.c} | 0
- 5 files changed, 10 insertions(+), 5 deletions(-)
- create mode 100644 drivers/net/phy/realtek/Kconfig
- create mode 100644 drivers/net/phy/realtek/Makefile
- rename drivers/net/phy/{realtek.c => realtek/realtek_main.c} (100%)
-
---- a/drivers/net/phy/Kconfig
-+++ b/drivers/net/phy/Kconfig
-@@ -310,10 +310,7 @@ config QSEMI_PHY
- help
- Currently supports the qs6612
-
--config REALTEK_PHY
-- tristate "Realtek PHYs"
-- help
-- Supports the Realtek 821x PHY.
-+source "drivers/net/phy/realtek/Kconfig"
-
- config RENESAS_PHY
- tristate "Renesas PHYs"
---- a/drivers/net/phy/Makefile
-+++ b/drivers/net/phy/Makefile
-@@ -82,7 +82,7 @@ obj-$(CONFIG_NXP_CBTX_PHY) += nxp-cbtx.o
- obj-$(CONFIG_NXP_TJA11XX_PHY) += nxp-tja11xx.o
- obj-y += qcom/
- obj-$(CONFIG_QSEMI_PHY) += qsemi.o
--obj-$(CONFIG_REALTEK_PHY) += realtek.o
-+obj-$(CONFIG_REALTEK_PHY) += realtek/
- obj-$(CONFIG_RENESAS_PHY) += uPD60620.o
- obj-$(CONFIG_ROCKCHIP_PHY) += rockchip.o
- obj-$(CONFIG_SMSC_PHY) += smsc.o
---- /dev/null
-+++ b/drivers/net/phy/realtek/Kconfig
-@@ -0,0 +1,5 @@
-+# SPDX-License-Identifier: GPL-2.0-only
-+config REALTEK_PHY
-+ tristate "Realtek PHYs"
-+ help
-+ Currently supports RTL821x/RTL822x and fast ethernet PHYs
---- /dev/null
-+++ b/drivers/net/phy/realtek/Makefile
-@@ -0,0 +1,3 @@
-+# SPDX-License-Identifier: GPL-2.0
-+realtek-y += realtek_main.o
-+obj-$(CONFIG_REALTEK_PHY) += realtek.o
---- a/drivers/net/phy/realtek.c
-+++ /dev/null
-@@ -1,1589 +0,0 @@
--// SPDX-License-Identifier: GPL-2.0+
--/* drivers/net/phy/realtek.c
-- *
-- * Driver for Realtek PHYs
-- *
-- *
-- * Copyright (c) 2004 Freescale Semiconductor, Inc.
-- */
--#include <linux/bitops.h>
--#include <linux/of.h>
--#include <linux/phy.h>
--#include <linux/module.h>
--#include <linux/delay.h>
--#include <linux/clk.h>
--
--#define RTL821x_PHYSR 0x11
--#define RTL821x_PHYSR_DUPLEX BIT(13)
--#define RTL821x_PHYSR_SPEED GENMASK(15, 14)
--
--#define RTL821x_INER 0x12
--#define RTL8211B_INER_INIT 0x6400
--#define RTL8211E_INER_LINK_STATUS BIT(10)
--#define RTL8211F_INER_LINK_STATUS BIT(4)
--
--#define RTL821x_INSR 0x13
--
--#define RTL821x_EXT_PAGE_SELECT 0x1e
--#define RTL821x_PAGE_SELECT 0x1f
--
--#define RTL8211F_PHYCR1 0x18
--#define RTL8211F_PHYCR2 0x19
--#define RTL8211F_INSR 0x1d
--
--#define RTL8211F_LEDCR 0x10
--#define RTL8211F_LEDCR_MODE BIT(15)
--#define RTL8211F_LEDCR_ACT_TXRX BIT(4)
--#define RTL8211F_LEDCR_LINK_1000 BIT(3)
--#define RTL8211F_LEDCR_LINK_100 BIT(1)
--#define RTL8211F_LEDCR_LINK_10 BIT(0)
--#define RTL8211F_LEDCR_MASK GENMASK(4, 0)
--#define RTL8211F_LEDCR_SHIFT 5
--
--#define RTL8211F_TX_DELAY BIT(8)
--#define RTL8211F_RX_DELAY BIT(3)
--
--#define RTL8211F_ALDPS_PLL_OFF BIT(1)
--#define RTL8211F_ALDPS_ENABLE BIT(2)
--#define RTL8211F_ALDPS_XTAL_OFF BIT(12)
--
--#define RTL8211E_CTRL_DELAY BIT(13)
--#define RTL8211E_TX_DELAY BIT(12)
--#define RTL8211E_RX_DELAY BIT(11)
--
--#define RTL8211F_CLKOUT_EN BIT(0)
--
--#define RTL8201F_ISR 0x1e
--#define RTL8201F_ISR_ANERR BIT(15)
--#define RTL8201F_ISR_DUPLEX BIT(13)
--#define RTL8201F_ISR_LINK BIT(11)
--#define RTL8201F_ISR_MASK (RTL8201F_ISR_ANERR | \
-- RTL8201F_ISR_DUPLEX | \
-- RTL8201F_ISR_LINK)
--#define RTL8201F_IER 0x13
--
--#define RTL822X_VND1_SERDES_OPTION 0x697a
--#define RTL822X_VND1_SERDES_OPTION_MODE_MASK GENMASK(5, 0)
--#define RTL822X_VND1_SERDES_OPTION_MODE_2500BASEX_SGMII 0
--#define RTL822X_VND1_SERDES_OPTION_MODE_2500BASEX 2
--
--#define RTL822X_VND1_SERDES_CTRL3 0x7580
--#define RTL822X_VND1_SERDES_CTRL3_MODE_MASK GENMASK(5, 0)
--#define RTL822X_VND1_SERDES_CTRL3_MODE_SGMII 0x02
--#define RTL822X_VND1_SERDES_CTRL3_MODE_2500BASEX 0x16
--
--/* RTL822X_VND2_XXXXX registers are only accessible when phydev->is_c45
-- * is set, they cannot be accessed by C45-over-C22.
-- */
--#define RTL822X_VND2_GBCR 0xa412
--
--#define RTL822X_VND2_GANLPAR 0xa414
--
--#define RTL8366RB_POWER_SAVE 0x15
--#define RTL8366RB_POWER_SAVE_ON BIT(12)
--
--#define RTL9000A_GINMR 0x14
--#define RTL9000A_GINMR_LINK_STATUS BIT(4)
--
--#define RTL_VND2_PHYSR 0xa434
--#define RTL_VND2_PHYSR_DUPLEX BIT(3)
--#define RTL_VND2_PHYSR_SPEEDL GENMASK(5, 4)
--#define RTL_VND2_PHYSR_SPEEDH GENMASK(10, 9)
--#define RTL_VND2_PHYSR_MASTER BIT(11)
--#define RTL_VND2_PHYSR_SPEED_MASK (RTL_VND2_PHYSR_SPEEDL | RTL_VND2_PHYSR_SPEEDH)
--
--#define RTL_GENERIC_PHYID 0x001cc800
--#define RTL_8211FVD_PHYID 0x001cc878
--#define RTL_8221B 0x001cc840
--#define RTL_8221B_VB_CG 0x001cc849
--#define RTL_8221B_VN_CG 0x001cc84a
--#define RTL_8251B 0x001cc862
--
--#define RTL8211F_LED_COUNT 3
--
--MODULE_DESCRIPTION("Realtek PHY driver");
--MODULE_AUTHOR("Johnson Leung");
--MODULE_LICENSE("GPL");
--
--struct rtl821x_priv {
-- u16 phycr1;
-- u16 phycr2;
-- bool has_phycr2;
-- struct clk *clk;
--};
--
--static int rtl821x_read_page(struct phy_device *phydev)
--{
-- return __phy_read(phydev, RTL821x_PAGE_SELECT);
--}
--
--static int rtl821x_write_page(struct phy_device *phydev, int page)
--{
-- return __phy_write(phydev, RTL821x_PAGE_SELECT, page);
--}
--
--static int rtl821x_probe(struct phy_device *phydev)
--{
-- struct device *dev = &phydev->mdio.dev;
-- struct rtl821x_priv *priv;
-- u32 phy_id = phydev->drv->phy_id;
-- int ret;
--
-- priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
-- if (!priv)
-- return -ENOMEM;
--
-- priv->clk = devm_clk_get_optional_enabled(dev, NULL);
-- if (IS_ERR(priv->clk))
-- return dev_err_probe(dev, PTR_ERR(priv->clk),
-- "failed to get phy clock\n");
--
-- ret = phy_read_paged(phydev, 0xa43, RTL8211F_PHYCR1);
-- if (ret < 0)
-- return ret;
--
-- priv->phycr1 = ret & (RTL8211F_ALDPS_PLL_OFF | RTL8211F_ALDPS_ENABLE | RTL8211F_ALDPS_XTAL_OFF);
-- if (of_property_read_bool(dev->of_node, "realtek,aldps-enable"))
-- priv->phycr1 |= RTL8211F_ALDPS_PLL_OFF | RTL8211F_ALDPS_ENABLE | RTL8211F_ALDPS_XTAL_OFF;
--
-- priv->has_phycr2 = !(phy_id == RTL_8211FVD_PHYID);
-- if (priv->has_phycr2) {
-- ret = phy_read_paged(phydev, 0xa43, RTL8211F_PHYCR2);
-- if (ret < 0)
-- return ret;
--
-- priv->phycr2 = ret & RTL8211F_CLKOUT_EN;
-- if (of_property_read_bool(dev->of_node, "realtek,clkout-disable"))
-- priv->phycr2 &= ~RTL8211F_CLKOUT_EN;
-- }
--
-- phydev->priv = priv;
--
-- return 0;
--}
--
--static int rtl8201_ack_interrupt(struct phy_device *phydev)
--{
-- int err;
--
-- err = phy_read(phydev, RTL8201F_ISR);
--
-- return (err < 0) ? err : 0;
--}
--
--static int rtl821x_ack_interrupt(struct phy_device *phydev)
--{
-- int err;
--
-- err = phy_read(phydev, RTL821x_INSR);
--
-- return (err < 0) ? err : 0;
--}
--
--static int rtl8211f_ack_interrupt(struct phy_device *phydev)
--{
-- int err;
--
-- err = phy_read_paged(phydev, 0xa43, RTL8211F_INSR);
--
-- return (err < 0) ? err : 0;
--}
--
--static int rtl8201_config_intr(struct phy_device *phydev)
--{
-- u16 val;
-- int err;
--
-- if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
-- err = rtl8201_ack_interrupt(phydev);
-- if (err)
-- return err;
--
-- val = BIT(13) | BIT(12) | BIT(11);
-- err = phy_write_paged(phydev, 0x7, RTL8201F_IER, val);
-- } else {
-- val = 0;
-- err = phy_write_paged(phydev, 0x7, RTL8201F_IER, val);
-- if (err)
-- return err;
--
-- err = rtl8201_ack_interrupt(phydev);
-- }
--
-- return err;
--}
--
--static int rtl8211b_config_intr(struct phy_device *phydev)
--{
-- int err;
--
-- if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
-- err = rtl821x_ack_interrupt(phydev);
-- if (err)
-- return err;
--
-- err = phy_write(phydev, RTL821x_INER,
-- RTL8211B_INER_INIT);
-- } else {
-- err = phy_write(phydev, RTL821x_INER, 0);
-- if (err)
-- return err;
--
-- err = rtl821x_ack_interrupt(phydev);
-- }
--
-- return err;
--}
--
--static int rtl8211e_config_intr(struct phy_device *phydev)
--{
-- int err;
--
-- if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
-- err = rtl821x_ack_interrupt(phydev);
-- if (err)
-- return err;
--
-- err = phy_write(phydev, RTL821x_INER,
-- RTL8211E_INER_LINK_STATUS);
-- } else {
-- err = phy_write(phydev, RTL821x_INER, 0);
-- if (err)
-- return err;
--
-- err = rtl821x_ack_interrupt(phydev);
-- }
--
-- return err;
--}
--
--static int rtl8211f_config_intr(struct phy_device *phydev)
--{
-- u16 val;
-- int err;
--
-- if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
-- err = rtl8211f_ack_interrupt(phydev);
-- if (err)
-- return err;
--
-- val = RTL8211F_INER_LINK_STATUS;
-- err = phy_write_paged(phydev, 0xa42, RTL821x_INER, val);
-- } else {
-- val = 0;
-- err = phy_write_paged(phydev, 0xa42, RTL821x_INER, val);
-- if (err)
-- return err;
--
-- err = rtl8211f_ack_interrupt(phydev);
-- }
--
-- return err;
--}
--
--static irqreturn_t rtl8201_handle_interrupt(struct phy_device *phydev)
--{
-- int irq_status;
--
-- irq_status = phy_read(phydev, RTL8201F_ISR);
-- if (irq_status < 0) {
-- phy_error(phydev);
-- return IRQ_NONE;
-- }
--
-- if (!(irq_status & RTL8201F_ISR_MASK))
-- return IRQ_NONE;
--
-- phy_trigger_machine(phydev);
--
-- return IRQ_HANDLED;
--}
--
--static irqreturn_t rtl821x_handle_interrupt(struct phy_device *phydev)
--{
-- int irq_status, irq_enabled;
--
-- irq_status = phy_read(phydev, RTL821x_INSR);
-- if (irq_status < 0) {
-- phy_error(phydev);
-- return IRQ_NONE;
-- }
--
-- irq_enabled = phy_read(phydev, RTL821x_INER);
-- if (irq_enabled < 0) {
-- phy_error(phydev);
-- return IRQ_NONE;
-- }
--
-- if (!(irq_status & irq_enabled))
-- return IRQ_NONE;
--
-- phy_trigger_machine(phydev);
--
-- return IRQ_HANDLED;
--}
--
--static irqreturn_t rtl8211f_handle_interrupt(struct phy_device *phydev)
--{
-- int irq_status;
--
-- irq_status = phy_read_paged(phydev, 0xa43, RTL8211F_INSR);
-- if (irq_status < 0) {
-- phy_error(phydev);
-- return IRQ_NONE;
-- }
--
-- if (!(irq_status & RTL8211F_INER_LINK_STATUS))
-- return IRQ_NONE;
--
-- phy_trigger_machine(phydev);
--
-- return IRQ_HANDLED;
--}
--
--static int rtl8211_config_aneg(struct phy_device *phydev)
--{
-- int ret;
--
-- ret = genphy_config_aneg(phydev);
-- if (ret < 0)
-- return ret;
--
-- /* Quirk was copied from vendor driver. Unfortunately it includes no
-- * description of the magic numbers.
-- */
-- if (phydev->speed == SPEED_100 && phydev->autoneg == AUTONEG_DISABLE) {
-- phy_write(phydev, 0x17, 0x2138);
-- phy_write(phydev, 0x0e, 0x0260);
-- } else {
-- phy_write(phydev, 0x17, 0x2108);
-- phy_write(phydev, 0x0e, 0x0000);
-- }
--
-- return 0;
--}
--
--static int rtl8211c_config_init(struct phy_device *phydev)
--{
-- /* RTL8211C has an issue when operating in Gigabit slave mode */
-- return phy_set_bits(phydev, MII_CTRL1000,
-- CTL1000_ENABLE_MASTER | CTL1000_AS_MASTER);
--}
--
--static int rtl8211f_config_init(struct phy_device *phydev)
--{
-- struct rtl821x_priv *priv = phydev->priv;
-- struct device *dev = &phydev->mdio.dev;
-- u16 val_txdly, val_rxdly;
-- int ret;
--
-- ret = phy_modify_paged_changed(phydev, 0xa43, RTL8211F_PHYCR1,
-- RTL8211F_ALDPS_PLL_OFF | RTL8211F_ALDPS_ENABLE | RTL8211F_ALDPS_XTAL_OFF,
-- priv->phycr1);
-- if (ret < 0) {
-- dev_err(dev, "aldps mode configuration failed: %pe\n",
-- ERR_PTR(ret));
-- return ret;
-- }
--
-- switch (phydev->interface) {
-- case PHY_INTERFACE_MODE_RGMII:
-- val_txdly = 0;
-- val_rxdly = 0;
-- break;
--
-- case PHY_INTERFACE_MODE_RGMII_RXID:
-- val_txdly = 0;
-- val_rxdly = RTL8211F_RX_DELAY;
-- break;
--
-- case PHY_INTERFACE_MODE_RGMII_TXID:
-- val_txdly = RTL8211F_TX_DELAY;
-- val_rxdly = 0;
-- break;
--
-- case PHY_INTERFACE_MODE_RGMII_ID:
-- val_txdly = RTL8211F_TX_DELAY;
-- val_rxdly = RTL8211F_RX_DELAY;
-- break;
--
-- default: /* the rest of the modes imply leaving delay as is. */
-- return 0;
-- }
--
-- ret = phy_modify_paged_changed(phydev, 0xd08, 0x11, RTL8211F_TX_DELAY,
-- val_txdly);
-- if (ret < 0) {
-- dev_err(dev, "Failed to update the TX delay register\n");
-- return ret;
-- } else if (ret) {
-- dev_dbg(dev,
-- "%s 2ns TX delay (and changing the value from pin-strapping RXD1 or the bootloader)\n",
-- val_txdly ? "Enabling" : "Disabling");
-- } else {
-- dev_dbg(dev,
-- "2ns TX delay was already %s (by pin-strapping RXD1 or bootloader configuration)\n",
-- val_txdly ? "enabled" : "disabled");
-- }
--
-- ret = phy_modify_paged_changed(phydev, 0xd08, 0x15, RTL8211F_RX_DELAY,
-- val_rxdly);
-- if (ret < 0) {
-- dev_err(dev, "Failed to update the RX delay register\n");
-- return ret;
-- } else if (ret) {
-- dev_dbg(dev,
-- "%s 2ns RX delay (and changing the value from pin-strapping RXD0 or the bootloader)\n",
-- val_rxdly ? "Enabling" : "Disabling");
-- } else {
-- dev_dbg(dev,
-- "2ns RX delay was already %s (by pin-strapping RXD0 or bootloader configuration)\n",
-- val_rxdly ? "enabled" : "disabled");
-- }
--
-- if (priv->has_phycr2) {
-- ret = phy_modify_paged(phydev, 0xa43, RTL8211F_PHYCR2,
-- RTL8211F_CLKOUT_EN, priv->phycr2);
-- if (ret < 0) {
-- dev_err(dev, "clkout configuration failed: %pe\n",
-- ERR_PTR(ret));
-- return ret;
-- }
--
-- return genphy_soft_reset(phydev);
-- }
--
-- return 0;
--}
--
--static int rtl821x_suspend(struct phy_device *phydev)
--{
-- struct rtl821x_priv *priv = phydev->priv;
-- int ret = 0;
--
-- if (!phydev->wol_enabled) {
-- ret = genphy_suspend(phydev);
--
-- if (ret)
-- return ret;
--
-- clk_disable_unprepare(priv->clk);
-- }
--
-- return ret;
--}
--
--static int rtl821x_resume(struct phy_device *phydev)
--{
-- struct rtl821x_priv *priv = phydev->priv;
-- int ret;
--
-- if (!phydev->wol_enabled)
-- clk_prepare_enable(priv->clk);
--
-- ret = genphy_resume(phydev);
-- if (ret < 0)
-- return ret;
--
-- msleep(20);
--
-- return 0;
--}
--
--static int rtl8211f_led_hw_is_supported(struct phy_device *phydev, u8 index,
-- unsigned long rules)
--{
-- const unsigned long mask = BIT(TRIGGER_NETDEV_LINK_10) |
-- BIT(TRIGGER_NETDEV_LINK_100) |
-- BIT(TRIGGER_NETDEV_LINK_1000) |
-- BIT(TRIGGER_NETDEV_RX) |
-- BIT(TRIGGER_NETDEV_TX);
--
-- /* The RTL8211F PHY supports these LED settings on up to three LEDs:
-- * - Link: Configurable subset of 10/100/1000 link rates
-- * - Active: Blink on activity, RX or TX is not differentiated
-- * The Active option has two modes, A and B:
-- * - A: Link and Active indication at configurable, but matching,
-- * subset of 10/100/1000 link rates
-- * - B: Link indication at configurable subset of 10/100/1000 link
-- * rates and Active indication always at all three 10+100+1000
-- * link rates.
-- * This code currently uses mode B only.
-- */
--
-- if (index >= RTL8211F_LED_COUNT)
-- return -EINVAL;
--
-- /* Filter out any other unsupported triggers. */
-- if (rules & ~mask)
-- return -EOPNOTSUPP;
--
-- /* RX and TX are not differentiated, either both are set or not set. */
-- if (!(rules & BIT(TRIGGER_NETDEV_RX)) ^ !(rules & BIT(TRIGGER_NETDEV_TX)))
-- return -EOPNOTSUPP;
--
-- return 0;
--}
--
--static int rtl8211f_led_hw_control_get(struct phy_device *phydev, u8 index,
-- unsigned long *rules)
--{
-- int val;
--
-- if (index >= RTL8211F_LED_COUNT)
-- return -EINVAL;
--
-- val = phy_read_paged(phydev, 0xd04, RTL8211F_LEDCR);
-- if (val < 0)
-- return val;
--
-- val >>= RTL8211F_LEDCR_SHIFT * index;
-- val &= RTL8211F_LEDCR_MASK;
--
-- if (val & RTL8211F_LEDCR_LINK_10)
-- set_bit(TRIGGER_NETDEV_LINK_10, rules);
--
-- if (val & RTL8211F_LEDCR_LINK_100)
-- set_bit(TRIGGER_NETDEV_LINK_100, rules);
--
-- if (val & RTL8211F_LEDCR_LINK_1000)
-- set_bit(TRIGGER_NETDEV_LINK_1000, rules);
--
-- if (val & RTL8211F_LEDCR_ACT_TXRX) {
-- set_bit(TRIGGER_NETDEV_RX, rules);
-- set_bit(TRIGGER_NETDEV_TX, rules);
-- }
--
-- return 0;
--}
--
--static int rtl8211f_led_hw_control_set(struct phy_device *phydev, u8 index,
-- unsigned long rules)
--{
-- const u16 mask = RTL8211F_LEDCR_MASK << (RTL8211F_LEDCR_SHIFT * index);
-- u16 reg = 0;
--
-- if (index >= RTL8211F_LED_COUNT)
-- return -EINVAL;
--
-- if (test_bit(TRIGGER_NETDEV_LINK_10, &rules))
-- reg |= RTL8211F_LEDCR_LINK_10;
--
-- if (test_bit(TRIGGER_NETDEV_LINK_100, &rules))
-- reg |= RTL8211F_LEDCR_LINK_100;
--
-- if (test_bit(TRIGGER_NETDEV_LINK_1000, &rules))
-- reg |= RTL8211F_LEDCR_LINK_1000;
--
-- if (test_bit(TRIGGER_NETDEV_RX, &rules) ||
-- test_bit(TRIGGER_NETDEV_TX, &rules)) {
-- reg |= RTL8211F_LEDCR_ACT_TXRX;
-- }
--
-- reg <<= RTL8211F_LEDCR_SHIFT * index;
-- reg |= RTL8211F_LEDCR_MODE; /* Mode B */
--
-- return phy_modify_paged(phydev, 0xd04, RTL8211F_LEDCR, mask, reg);
--}
--
--static int rtl8211e_config_init(struct phy_device *phydev)
--{
-- int ret = 0, oldpage;
-- u16 val;
--
-- /* enable TX/RX delay for rgmii-* modes, and disable them for rgmii. */
-- switch (phydev->interface) {
-- case PHY_INTERFACE_MODE_RGMII:
-- val = RTL8211E_CTRL_DELAY | 0;
-- break;
-- case PHY_INTERFACE_MODE_RGMII_ID:
-- val = RTL8211E_CTRL_DELAY | RTL8211E_TX_DELAY | RTL8211E_RX_DELAY;
-- break;
-- case PHY_INTERFACE_MODE_RGMII_RXID:
-- val = RTL8211E_CTRL_DELAY | RTL8211E_RX_DELAY;
-- break;
-- case PHY_INTERFACE_MODE_RGMII_TXID:
-- val = RTL8211E_CTRL_DELAY | RTL8211E_TX_DELAY;
-- break;
-- default: /* the rest of the modes imply leaving delays as is. */
-- return 0;
-- }
--
-- /* According to a sample driver there is a 0x1c config register on the
-- * 0xa4 extension page (0x7) layout. It can be used to disable/enable
-- * the RX/TX delays otherwise controlled by RXDLY/TXDLY pins.
-- * The configuration register definition:
-- * 14 = reserved
-- * 13 = Force Tx RX Delay controlled by bit12 bit11,
-- * 12 = RX Delay, 11 = TX Delay
-- * 10:0 = Test && debug settings reserved by realtek
-- */
-- oldpage = phy_select_page(phydev, 0x7);
-- if (oldpage < 0)
-- goto err_restore_page;
--
-- ret = __phy_write(phydev, RTL821x_EXT_PAGE_SELECT, 0xa4);
-- if (ret)
-- goto err_restore_page;
--
-- ret = __phy_modify(phydev, 0x1c, RTL8211E_CTRL_DELAY
-- | RTL8211E_TX_DELAY | RTL8211E_RX_DELAY,
-- val);
--
--err_restore_page:
-- return phy_restore_page(phydev, oldpage, ret);
--}
--
--static int rtl8211b_suspend(struct phy_device *phydev)
--{
-- phy_write(phydev, MII_MMD_DATA, BIT(9));
--
-- return genphy_suspend(phydev);
--}
--
--static int rtl8211b_resume(struct phy_device *phydev)
--{
-- phy_write(phydev, MII_MMD_DATA, 0);
--
-- return genphy_resume(phydev);
--}
--
--static int rtl8366rb_config_init(struct phy_device *phydev)
--{
-- int ret;
--
-- ret = phy_set_bits(phydev, RTL8366RB_POWER_SAVE,
-- RTL8366RB_POWER_SAVE_ON);
-- if (ret) {
-- dev_err(&phydev->mdio.dev,
-- "error enabling power management\n");
-- }
--
-- return ret;
--}
--
--/* get actual speed to cover the downshift case */
--static void rtlgen_decode_physr(struct phy_device *phydev, int val)
--{
-- /* bit 3
-- * 0: Half Duplex
-- * 1: Full Duplex
-- */
-- if (val & RTL_VND2_PHYSR_DUPLEX)
-- phydev->duplex = DUPLEX_FULL;
-- else
-- phydev->duplex = DUPLEX_HALF;
--
-- switch (val & RTL_VND2_PHYSR_SPEED_MASK) {
-- case 0x0000:
-- phydev->speed = SPEED_10;
-- break;
-- case 0x0010:
-- phydev->speed = SPEED_100;
-- break;
-- case 0x0020:
-- phydev->speed = SPEED_1000;
-- break;
-- case 0x0200:
-- phydev->speed = SPEED_10000;
-- break;
-- case 0x0210:
-- phydev->speed = SPEED_2500;
-- break;
-- case 0x0220:
-- phydev->speed = SPEED_5000;
-- break;
-- default:
-- break;
-- }
--
-- /* bit 11
-- * 0: Slave Mode
-- * 1: Master Mode
-- */
-- if (phydev->speed >= 1000) {
-- if (val & RTL_VND2_PHYSR_MASTER)
-- phydev->master_slave_state = MASTER_SLAVE_STATE_MASTER;
-- else
-- phydev->master_slave_state = MASTER_SLAVE_STATE_SLAVE;
-- } else {
-- phydev->master_slave_state = MASTER_SLAVE_STATE_UNSUPPORTED;
-- }
--}
--
--static int rtlgen_read_status(struct phy_device *phydev)
--{
-- int ret, val;
--
-- ret = genphy_read_status(phydev);
-- if (ret < 0)
-- return ret;
--
-- if (!phydev->link)
-- return 0;
--
-- val = phy_read_paged(phydev, 0xa43, 0x12);
-- if (val < 0)
-- return val;
--
-- rtlgen_decode_physr(phydev, val);
--
-- return 0;
--}
--
--static int rtlgen_read_mmd(struct phy_device *phydev, int devnum, u16 regnum)
--{
-- int ret;
--
-- if (devnum == MDIO_MMD_VEND2) {
-- rtl821x_write_page(phydev, regnum >> 4);
-- ret = __phy_read(phydev, 0x10 + ((regnum & 0xf) >> 1));
-- rtl821x_write_page(phydev, 0);
-- } else if (devnum == MDIO_MMD_PCS && regnum == MDIO_PCS_EEE_ABLE) {
-- rtl821x_write_page(phydev, 0xa5c);
-- ret = __phy_read(phydev, 0x12);
-- rtl821x_write_page(phydev, 0);
-- } else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV) {
-- rtl821x_write_page(phydev, 0xa5d);
-- ret = __phy_read(phydev, 0x10);
-- rtl821x_write_page(phydev, 0);
-- } else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_LPABLE) {
-- rtl821x_write_page(phydev, 0xa5d);
-- ret = __phy_read(phydev, 0x11);
-- rtl821x_write_page(phydev, 0);
-- } else {
-- ret = -EOPNOTSUPP;
-- }
--
-- return ret;
--}
--
--static int rtlgen_write_mmd(struct phy_device *phydev, int devnum, u16 regnum,
-- u16 val)
--{
-- int ret;
--
-- if (devnum == MDIO_MMD_VEND2) {
-- rtl821x_write_page(phydev, regnum >> 4);
-- ret = __phy_write(phydev, 0x10 + ((regnum & 0xf) >> 1), val);
-- rtl821x_write_page(phydev, 0);
-- } else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV) {
-- rtl821x_write_page(phydev, 0xa5d);
-- ret = __phy_write(phydev, 0x10, val);
-- rtl821x_write_page(phydev, 0);
-- } else {
-- ret = -EOPNOTSUPP;
-- }
--
-- return ret;
--}
--
--static int rtl822x_read_mmd(struct phy_device *phydev, int devnum, u16 regnum)
--{
-- int ret = rtlgen_read_mmd(phydev, devnum, regnum);
--
-- if (ret != -EOPNOTSUPP)
-- return ret;
--
-- if (devnum == MDIO_MMD_PCS && regnum == MDIO_PCS_EEE_ABLE2) {
-- rtl821x_write_page(phydev, 0xa6e);
-- ret = __phy_read(phydev, 0x16);
-- rtl821x_write_page(phydev, 0);
-- } else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV2) {
-- rtl821x_write_page(phydev, 0xa6d);
-- ret = __phy_read(phydev, 0x12);
-- rtl821x_write_page(phydev, 0);
-- } else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_LPABLE2) {
-- rtl821x_write_page(phydev, 0xa6d);
-- ret = __phy_read(phydev, 0x10);
-- rtl821x_write_page(phydev, 0);
-- }
--
-- return ret;
--}
--
--static int rtl822x_write_mmd(struct phy_device *phydev, int devnum, u16 regnum,
-- u16 val)
--{
-- int ret = rtlgen_write_mmd(phydev, devnum, regnum, val);
--
-- if (ret != -EOPNOTSUPP)
-- return ret;
--
-- if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV2) {
-- rtl821x_write_page(phydev, 0xa6d);
-- ret = __phy_write(phydev, 0x12, val);
-- rtl821x_write_page(phydev, 0);
-- }
--
-- return ret;
--}
--
--static int rtl822xb_config_init(struct phy_device *phydev)
--{
-- bool has_2500, has_sgmii;
-- u16 mode;
-- int ret;
--
-- has_2500 = test_bit(PHY_INTERFACE_MODE_2500BASEX,
-- phydev->host_interfaces) ||
-- phydev->interface == PHY_INTERFACE_MODE_2500BASEX;
--
-- has_sgmii = test_bit(PHY_INTERFACE_MODE_SGMII,
-- phydev->host_interfaces) ||
-- phydev->interface == PHY_INTERFACE_MODE_SGMII;
--
-- /* fill in possible interfaces */
-- __assign_bit(PHY_INTERFACE_MODE_2500BASEX, phydev->possible_interfaces,
-- has_2500);
-- __assign_bit(PHY_INTERFACE_MODE_SGMII, phydev->possible_interfaces,
-- has_sgmii);
--
-- if (!has_2500 && !has_sgmii)
-- return 0;
--
-- /* determine SerDes option mode */
-- if (has_2500 && !has_sgmii) {
-- mode = RTL822X_VND1_SERDES_OPTION_MODE_2500BASEX;
-- phydev->rate_matching = RATE_MATCH_PAUSE;
-- } else {
-- mode = RTL822X_VND1_SERDES_OPTION_MODE_2500BASEX_SGMII;
-- phydev->rate_matching = RATE_MATCH_NONE;
-- }
--
-- /* the following sequence with magic numbers sets up the SerDes
-- * option mode
-- */
-- ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x75f3, 0);
-- if (ret < 0)
-- return ret;
--
-- ret = phy_modify_mmd_changed(phydev, MDIO_MMD_VEND1,
-- RTL822X_VND1_SERDES_OPTION,
-- RTL822X_VND1_SERDES_OPTION_MODE_MASK,
-- mode);
-- if (ret < 0)
-- return ret;
--
-- ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x6a04, 0x0503);
-- if (ret < 0)
-- return ret;
--
-- ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x6f10, 0xd455);
-- if (ret < 0)
-- return ret;
--
-- return phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x6f11, 0x8020);
--}
--
--static int rtl822xb_get_rate_matching(struct phy_device *phydev,
-- phy_interface_t iface)
--{
-- int val;
--
-- /* Only rate matching at 2500base-x */
-- if (iface != PHY_INTERFACE_MODE_2500BASEX)
-- return RATE_MATCH_NONE;
--
-- val = phy_read_mmd(phydev, MDIO_MMD_VEND1, RTL822X_VND1_SERDES_OPTION);
-- if (val < 0)
-- return val;
--
-- if ((val & RTL822X_VND1_SERDES_OPTION_MODE_MASK) ==
-- RTL822X_VND1_SERDES_OPTION_MODE_2500BASEX)
-- return RATE_MATCH_PAUSE;
--
-- /* RTL822X_VND1_SERDES_OPTION_MODE_2500BASEX_SGMII */
-- return RATE_MATCH_NONE;
--}
--
--static int rtl822x_get_features(struct phy_device *phydev)
--{
-- int val;
--
-- val = phy_read_paged(phydev, 0xa61, 0x13);
-- if (val < 0)
-- return val;
--
-- linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
-- phydev->supported, val & MDIO_PMA_SPEED_2_5G);
-- linkmode_mod_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT,
-- phydev->supported, val & MDIO_PMA_SPEED_5G);
-- linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT,
-- phydev->supported, val & MDIO_SPEED_10G);
--
-- return genphy_read_abilities(phydev);
--}
--
--static int rtl822x_config_aneg(struct phy_device *phydev)
--{
-- int ret = 0;
--
-- if (phydev->autoneg == AUTONEG_ENABLE) {
-- u16 adv = linkmode_adv_to_mii_10gbt_adv_t(phydev->advertising);
--
-- ret = phy_modify_paged_changed(phydev, 0xa5d, 0x12,
-- MDIO_AN_10GBT_CTRL_ADV2_5G |
-- MDIO_AN_10GBT_CTRL_ADV5G,
-- adv);
-- if (ret < 0)
-- return ret;
-- }
--
-- return __genphy_config_aneg(phydev, ret);
--}
--
--static void rtl822xb_update_interface(struct phy_device *phydev)
--{
-- int val;
--
-- if (!phydev->link)
-- return;
--
-- /* Change interface according to serdes mode */
-- val = phy_read_mmd(phydev, MDIO_MMD_VEND1, RTL822X_VND1_SERDES_CTRL3);
-- if (val < 0)
-- return;
--
-- switch (val & RTL822X_VND1_SERDES_CTRL3_MODE_MASK) {
-- case RTL822X_VND1_SERDES_CTRL3_MODE_2500BASEX:
-- phydev->interface = PHY_INTERFACE_MODE_2500BASEX;
-- break;
-- case RTL822X_VND1_SERDES_CTRL3_MODE_SGMII:
-- phydev->interface = PHY_INTERFACE_MODE_SGMII;
-- break;
-- }
--}
--
--static int rtl822x_read_status(struct phy_device *phydev)
--{
-- int lpadv, ret;
--
-- mii_10gbt_stat_mod_linkmode_lpa_t(phydev->lp_advertising, 0);
--
-- ret = rtlgen_read_status(phydev);
-- if (ret < 0)
-- return ret;
--
-- if (phydev->autoneg == AUTONEG_DISABLE ||
-- !phydev->autoneg_complete)
-- return 0;
--
-- lpadv = phy_read_paged(phydev, 0xa5d, 0x13);
-- if (lpadv < 0)
-- return lpadv;
--
-- mii_10gbt_stat_mod_linkmode_lpa_t(phydev->lp_advertising, lpadv);
--
-- return 0;
--}
--
--static int rtl822xb_read_status(struct phy_device *phydev)
--{
-- int ret;
--
-- ret = rtl822x_read_status(phydev);
-- if (ret < 0)
-- return ret;
--
-- rtl822xb_update_interface(phydev);
--
-- return 0;
--}
--
--static int rtl822x_c45_get_features(struct phy_device *phydev)
--{
-- linkmode_set_bit(ETHTOOL_LINK_MODE_TP_BIT,
-- phydev->supported);
--
-- return genphy_c45_pma_read_abilities(phydev);
--}
--
--static int rtl822x_c45_config_aneg(struct phy_device *phydev)
--{
-- bool changed = false;
-- int ret, val;
--
-- if (phydev->autoneg == AUTONEG_DISABLE)
-- return genphy_c45_pma_setup_forced(phydev);
--
-- ret = genphy_c45_an_config_aneg(phydev);
-- if (ret < 0)
-- return ret;
-- if (ret > 0)
-- changed = true;
--
-- val = linkmode_adv_to_mii_ctrl1000_t(phydev->advertising);
--
-- /* Vendor register as C45 has no standardized support for 1000BaseT */
-- ret = phy_modify_mmd_changed(phydev, MDIO_MMD_VEND2, RTL822X_VND2_GBCR,
-- ADVERTISE_1000FULL, val);
-- if (ret < 0)
-- return ret;
-- if (ret > 0)
-- changed = true;
--
-- return genphy_c45_check_and_restart_aneg(phydev, changed);
--}
--
--static int rtl822x_c45_read_status(struct phy_device *phydev)
--{
-- int ret, val;
--
-- /* Vendor register as C45 has no standardized support for 1000BaseT */
-- if (phydev->autoneg == AUTONEG_ENABLE && genphy_c45_aneg_done(phydev)) {
-- val = phy_read_mmd(phydev, MDIO_MMD_VEND2,
-- RTL822X_VND2_GANLPAR);
-- if (val < 0)
-- return val;
-- } else {
-- val = 0;
-- }
-- mii_stat1000_mod_linkmode_lpa_t(phydev->lp_advertising, val);
--
-- ret = genphy_c45_read_status(phydev);
-- if (ret < 0)
-- return ret;
--
-- if (!phydev->link) {
-- phydev->master_slave_state = MASTER_SLAVE_STATE_UNKNOWN;
-- return 0;
-- }
--
-- /* Read actual speed from vendor register. */
-- val = phy_read_mmd(phydev, MDIO_MMD_VEND2, RTL_VND2_PHYSR);
-- if (val < 0)
-- return val;
--
-- rtlgen_decode_physr(phydev, val);
--
-- return 0;
--}
--
--static int rtl822xb_c45_read_status(struct phy_device *phydev)
--{
-- int ret;
--
-- ret = rtl822x_c45_read_status(phydev);
-- if (ret < 0)
-- return ret;
--
-- rtl822xb_update_interface(phydev);
--
-- return 0;
--}
--
--static bool rtlgen_supports_2_5gbps(struct phy_device *phydev)
--{
-- int val;
--
-- phy_write(phydev, RTL821x_PAGE_SELECT, 0xa61);
-- val = phy_read(phydev, 0x13);
-- phy_write(phydev, RTL821x_PAGE_SELECT, 0);
--
-- return val >= 0 && val & MDIO_PMA_SPEED_2_5G;
--}
--
--/* On internal PHY's MMD reads over C22 always return 0.
-- * Check a MMD register which is known to be non-zero.
-- */
--static bool rtlgen_supports_mmd(struct phy_device *phydev)
--{
-- int val;
--
-- phy_lock_mdio_bus(phydev);
-- __phy_write(phydev, MII_MMD_CTRL, MDIO_MMD_PCS);
-- __phy_write(phydev, MII_MMD_DATA, MDIO_PCS_EEE_ABLE);
-- __phy_write(phydev, MII_MMD_CTRL, MDIO_MMD_PCS | MII_MMD_CTRL_NOINCR);
-- val = __phy_read(phydev, MII_MMD_DATA);
-- phy_unlock_mdio_bus(phydev);
--
-- return val > 0;
--}
--
--static int rtlgen_match_phy_device(struct phy_device *phydev)
--{
-- return phydev->phy_id == RTL_GENERIC_PHYID &&
-- !rtlgen_supports_2_5gbps(phydev);
--}
--
--static int rtl8226_match_phy_device(struct phy_device *phydev)
--{
-- return phydev->phy_id == RTL_GENERIC_PHYID &&
-- rtlgen_supports_2_5gbps(phydev) &&
-- rtlgen_supports_mmd(phydev);
--}
--
--static int rtlgen_is_c45_match(struct phy_device *phydev, unsigned int id,
-- bool is_c45)
--{
-- if (phydev->is_c45)
-- return is_c45 && (id == phydev->c45_ids.device_ids[1]);
-- else
-- return !is_c45 && (id == phydev->phy_id);
--}
--
--static int rtl8221b_match_phy_device(struct phy_device *phydev)
--{
-- return phydev->phy_id == RTL_8221B && rtlgen_supports_mmd(phydev);
--}
--
--static int rtl8221b_vb_cg_c22_match_phy_device(struct phy_device *phydev)
--{
-- return rtlgen_is_c45_match(phydev, RTL_8221B_VB_CG, false);
--}
--
--static int rtl8221b_vb_cg_c45_match_phy_device(struct phy_device *phydev)
--{
-- return rtlgen_is_c45_match(phydev, RTL_8221B_VB_CG, true);
--}
--
--static int rtl8221b_vn_cg_c22_match_phy_device(struct phy_device *phydev)
--{
-- return rtlgen_is_c45_match(phydev, RTL_8221B_VN_CG, false);
--}
--
--static int rtl8221b_vn_cg_c45_match_phy_device(struct phy_device *phydev)
--{
-- return rtlgen_is_c45_match(phydev, RTL_8221B_VN_CG, true);
--}
--
--static int rtl_internal_nbaset_match_phy_device(struct phy_device *phydev)
--{
-- if (phydev->is_c45)
-- return false;
--
-- switch (phydev->phy_id) {
-- case RTL_GENERIC_PHYID:
-- case RTL_8221B:
-- case RTL_8251B:
-- case 0x001cc841:
-- break;
-- default:
-- return false;
-- }
--
-- return rtlgen_supports_2_5gbps(phydev) && !rtlgen_supports_mmd(phydev);
--}
--
--static int rtl8251b_c45_match_phy_device(struct phy_device *phydev)
--{
-- return rtlgen_is_c45_match(phydev, RTL_8251B, true);
--}
--
--static int rtlgen_resume(struct phy_device *phydev)
--{
-- int ret = genphy_resume(phydev);
--
-- /* Internal PHY's from RTL8168h up may not be instantly ready */
-- msleep(20);
--
-- return ret;
--}
--
--static int rtlgen_c45_resume(struct phy_device *phydev)
--{
-- int ret = genphy_c45_pma_resume(phydev);
--
-- msleep(20);
--
-- return ret;
--}
--
--static int rtl9000a_config_init(struct phy_device *phydev)
--{
-- phydev->autoneg = AUTONEG_DISABLE;
-- phydev->speed = SPEED_100;
-- phydev->duplex = DUPLEX_FULL;
--
-- return 0;
--}
--
--static int rtl9000a_config_aneg(struct phy_device *phydev)
--{
-- int ret;
-- u16 ctl = 0;
--
-- switch (phydev->master_slave_set) {
-- case MASTER_SLAVE_CFG_MASTER_FORCE:
-- ctl |= CTL1000_AS_MASTER;
-- break;
-- case MASTER_SLAVE_CFG_SLAVE_FORCE:
-- break;
-- case MASTER_SLAVE_CFG_UNKNOWN:
-- case MASTER_SLAVE_CFG_UNSUPPORTED:
-- return 0;
-- default:
-- phydev_warn(phydev, "Unsupported Master/Slave mode\n");
-- return -EOPNOTSUPP;
-- }
--
-- ret = phy_modify_changed(phydev, MII_CTRL1000, CTL1000_AS_MASTER, ctl);
-- if (ret == 1)
-- ret = genphy_soft_reset(phydev);
--
-- return ret;
--}
--
--static int rtl9000a_read_status(struct phy_device *phydev)
--{
-- int ret;
--
-- phydev->master_slave_get = MASTER_SLAVE_CFG_UNKNOWN;
-- phydev->master_slave_state = MASTER_SLAVE_STATE_UNKNOWN;
--
-- ret = genphy_update_link(phydev);
-- if (ret)
-- return ret;
--
-- ret = phy_read(phydev, MII_CTRL1000);
-- if (ret < 0)
-- return ret;
-- if (ret & CTL1000_AS_MASTER)
-- phydev->master_slave_get = MASTER_SLAVE_CFG_MASTER_FORCE;
-- else
-- phydev->master_slave_get = MASTER_SLAVE_CFG_SLAVE_FORCE;
--
-- ret = phy_read(phydev, MII_STAT1000);
-- if (ret < 0)
-- return ret;
-- if (ret & LPA_1000MSRES)
-- phydev->master_slave_state = MASTER_SLAVE_STATE_MASTER;
-- else
-- phydev->master_slave_state = MASTER_SLAVE_STATE_SLAVE;
--
-- return 0;
--}
--
--static int rtl9000a_ack_interrupt(struct phy_device *phydev)
--{
-- int err;
--
-- err = phy_read(phydev, RTL8211F_INSR);
--
-- return (err < 0) ? err : 0;
--}
--
--static int rtl9000a_config_intr(struct phy_device *phydev)
--{
-- u16 val;
-- int err;
--
-- if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
-- err = rtl9000a_ack_interrupt(phydev);
-- if (err)
-- return err;
--
-- val = (u16)~RTL9000A_GINMR_LINK_STATUS;
-- err = phy_write_paged(phydev, 0xa42, RTL9000A_GINMR, val);
-- } else {
-- val = ~0;
-- err = phy_write_paged(phydev, 0xa42, RTL9000A_GINMR, val);
-- if (err)
-- return err;
--
-- err = rtl9000a_ack_interrupt(phydev);
-- }
--
-- return phy_write_paged(phydev, 0xa42, RTL9000A_GINMR, val);
--}
--
--static irqreturn_t rtl9000a_handle_interrupt(struct phy_device *phydev)
--{
-- int irq_status;
--
-- irq_status = phy_read(phydev, RTL8211F_INSR);
-- if (irq_status < 0) {
-- phy_error(phydev);
-- return IRQ_NONE;
-- }
--
-- if (!(irq_status & RTL8211F_INER_LINK_STATUS))
-- return IRQ_NONE;
--
-- phy_trigger_machine(phydev);
--
-- return IRQ_HANDLED;
--}
--
--static struct phy_driver realtek_drvs[] = {
-- {
-- PHY_ID_MATCH_EXACT(0x00008201),
-- .name = "RTL8201CP Ethernet",
-- .read_page = rtl821x_read_page,
-- .write_page = rtl821x_write_page,
-- }, {
-- PHY_ID_MATCH_EXACT(0x001cc816),
-- .name = "RTL8201F Fast Ethernet",
-- .config_intr = &rtl8201_config_intr,
-- .handle_interrupt = rtl8201_handle_interrupt,
-- .suspend = genphy_suspend,
-- .resume = genphy_resume,
-- .read_page = rtl821x_read_page,
-- .write_page = rtl821x_write_page,
-- }, {
-- PHY_ID_MATCH_MODEL(0x001cc880),
-- .name = "RTL8208 Fast Ethernet",
-- .read_mmd = genphy_read_mmd_unsupported,
-- .write_mmd = genphy_write_mmd_unsupported,
-- .suspend = genphy_suspend,
-- .resume = genphy_resume,
-- .read_page = rtl821x_read_page,
-- .write_page = rtl821x_write_page,
-- }, {
-- PHY_ID_MATCH_EXACT(0x001cc910),
-- .name = "RTL8211 Gigabit Ethernet",
-- .config_aneg = rtl8211_config_aneg,
-- .read_mmd = &genphy_read_mmd_unsupported,
-- .write_mmd = &genphy_write_mmd_unsupported,
-- .read_page = rtl821x_read_page,
-- .write_page = rtl821x_write_page,
-- }, {
-- PHY_ID_MATCH_EXACT(0x001cc912),
-- .name = "RTL8211B Gigabit Ethernet",
-- .config_intr = &rtl8211b_config_intr,
-- .handle_interrupt = rtl821x_handle_interrupt,
-- .read_mmd = &genphy_read_mmd_unsupported,
-- .write_mmd = &genphy_write_mmd_unsupported,
-- .suspend = rtl8211b_suspend,
-- .resume = rtl8211b_resume,
-- .read_page = rtl821x_read_page,
-- .write_page = rtl821x_write_page,
-- }, {
-- PHY_ID_MATCH_EXACT(0x001cc913),
-- .name = "RTL8211C Gigabit Ethernet",
-- .config_init = rtl8211c_config_init,
-- .read_mmd = &genphy_read_mmd_unsupported,
-- .write_mmd = &genphy_write_mmd_unsupported,
-- .read_page = rtl821x_read_page,
-- .write_page = rtl821x_write_page,
-- }, {
-- PHY_ID_MATCH_EXACT(0x001cc914),
-- .name = "RTL8211DN Gigabit Ethernet",
-- .config_intr = rtl8211e_config_intr,
-- .handle_interrupt = rtl821x_handle_interrupt,
-- .suspend = genphy_suspend,
-- .resume = genphy_resume,
-- .read_page = rtl821x_read_page,
-- .write_page = rtl821x_write_page,
-- }, {
-- PHY_ID_MATCH_EXACT(0x001cc915),
-- .name = "RTL8211E Gigabit Ethernet",
-- .config_init = &rtl8211e_config_init,
-- .config_intr = &rtl8211e_config_intr,
-- .handle_interrupt = rtl821x_handle_interrupt,
-- .suspend = genphy_suspend,
-- .resume = genphy_resume,
-- .read_page = rtl821x_read_page,
-- .write_page = rtl821x_write_page,
-- }, {
-- PHY_ID_MATCH_EXACT(0x001cc916),
-- .name = "RTL8211F Gigabit Ethernet",
-- .probe = rtl821x_probe,
-- .config_init = &rtl8211f_config_init,
-- .read_status = rtlgen_read_status,
-- .config_intr = &rtl8211f_config_intr,
-- .handle_interrupt = rtl8211f_handle_interrupt,
-- .suspend = rtl821x_suspend,
-- .resume = rtl821x_resume,
-- .read_page = rtl821x_read_page,
-- .write_page = rtl821x_write_page,
-- .flags = PHY_ALWAYS_CALL_SUSPEND,
-- .led_hw_is_supported = rtl8211f_led_hw_is_supported,
-- .led_hw_control_get = rtl8211f_led_hw_control_get,
-- .led_hw_control_set = rtl8211f_led_hw_control_set,
-- }, {
-- PHY_ID_MATCH_EXACT(RTL_8211FVD_PHYID),
-- .name = "RTL8211F-VD Gigabit Ethernet",
-- .probe = rtl821x_probe,
-- .config_init = &rtl8211f_config_init,
-- .read_status = rtlgen_read_status,
-- .config_intr = &rtl8211f_config_intr,
-- .handle_interrupt = rtl8211f_handle_interrupt,
-- .suspend = rtl821x_suspend,
-- .resume = rtl821x_resume,
-- .read_page = rtl821x_read_page,
-- .write_page = rtl821x_write_page,
-- .flags = PHY_ALWAYS_CALL_SUSPEND,
-- }, {
-- .name = "Generic FE-GE Realtek PHY",
-- .match_phy_device = rtlgen_match_phy_device,
-- .read_status = rtlgen_read_status,
-- .suspend = genphy_suspend,
-- .resume = rtlgen_resume,
-- .read_page = rtl821x_read_page,
-- .write_page = rtl821x_write_page,
-- .read_mmd = rtlgen_read_mmd,
-- .write_mmd = rtlgen_write_mmd,
-- }, {
-- .name = "RTL8226 2.5Gbps PHY",
-- .match_phy_device = rtl8226_match_phy_device,
-- .get_features = rtl822x_get_features,
-- .config_aneg = rtl822x_config_aneg,
-- .read_status = rtl822x_read_status,
-- .suspend = genphy_suspend,
-- .resume = rtlgen_resume,
-- .read_page = rtl821x_read_page,
-- .write_page = rtl821x_write_page,
-- }, {
-- .match_phy_device = rtl8221b_match_phy_device,
-- .name = "RTL8226B_RTL8221B 2.5Gbps PHY",
-- .get_features = rtl822x_get_features,
-- .config_aneg = rtl822x_config_aneg,
-- .config_init = rtl822xb_config_init,
-- .get_rate_matching = rtl822xb_get_rate_matching,
-- .read_status = rtl822xb_read_status,
-- .suspend = genphy_suspend,
-- .resume = rtlgen_resume,
-- .read_page = rtl821x_read_page,
-- .write_page = rtl821x_write_page,
-- }, {
-- PHY_ID_MATCH_EXACT(0x001cc838),
-- .name = "RTL8226-CG 2.5Gbps PHY",
-- .get_features = rtl822x_get_features,
-- .config_aneg = rtl822x_config_aneg,
-- .read_status = rtl822x_read_status,
-- .suspend = genphy_suspend,
-- .resume = rtlgen_resume,
-- .read_page = rtl821x_read_page,
-- .write_page = rtl821x_write_page,
-- }, {
-- PHY_ID_MATCH_EXACT(0x001cc848),
-- .name = "RTL8226B-CG_RTL8221B-CG 2.5Gbps PHY",
-- .get_features = rtl822x_get_features,
-- .config_aneg = rtl822x_config_aneg,
-- .config_init = rtl822xb_config_init,
-- .get_rate_matching = rtl822xb_get_rate_matching,
-- .read_status = rtl822xb_read_status,
-- .suspend = genphy_suspend,
-- .resume = rtlgen_resume,
-- .read_page = rtl821x_read_page,
-- .write_page = rtl821x_write_page,
-- }, {
-- .match_phy_device = rtl8221b_vb_cg_c22_match_phy_device,
-- .name = "RTL8221B-VB-CG 2.5Gbps PHY (C22)",
-- .get_features = rtl822x_get_features,
-- .config_aneg = rtl822x_config_aneg,
-- .config_init = rtl822xb_config_init,
-- .get_rate_matching = rtl822xb_get_rate_matching,
-- .read_status = rtl822xb_read_status,
-- .suspend = genphy_suspend,
-- .resume = rtlgen_resume,
-- .read_page = rtl821x_read_page,
-- .write_page = rtl821x_write_page,
-- }, {
-- .match_phy_device = rtl8221b_vb_cg_c45_match_phy_device,
-- .name = "RTL8221B-VB-CG 2.5Gbps PHY (C45)",
-- .config_init = rtl822xb_config_init,
-- .get_rate_matching = rtl822xb_get_rate_matching,
-- .get_features = rtl822x_c45_get_features,
-- .config_aneg = rtl822x_c45_config_aneg,
-- .read_status = rtl822xb_c45_read_status,
-- .suspend = genphy_c45_pma_suspend,
-- .resume = rtlgen_c45_resume,
-- }, {
-- .match_phy_device = rtl8221b_vn_cg_c22_match_phy_device,
-- .name = "RTL8221B-VM-CG 2.5Gbps PHY (C22)",
-- .get_features = rtl822x_get_features,
-- .config_aneg = rtl822x_config_aneg,
-- .config_init = rtl822xb_config_init,
-- .get_rate_matching = rtl822xb_get_rate_matching,
-- .read_status = rtl822xb_read_status,
-- .suspend = genphy_suspend,
-- .resume = rtlgen_resume,
-- .read_page = rtl821x_read_page,
-- .write_page = rtl821x_write_page,
-- }, {
-- .match_phy_device = rtl8221b_vn_cg_c45_match_phy_device,
-- .name = "RTL8221B-VN-CG 2.5Gbps PHY (C45)",
-- .config_init = rtl822xb_config_init,
-- .get_rate_matching = rtl822xb_get_rate_matching,
-- .get_features = rtl822x_c45_get_features,
-- .config_aneg = rtl822x_c45_config_aneg,
-- .read_status = rtl822xb_c45_read_status,
-- .suspend = genphy_c45_pma_suspend,
-- .resume = rtlgen_c45_resume,
-- }, {
-- .match_phy_device = rtl8251b_c45_match_phy_device,
-- .name = "RTL8251B 5Gbps PHY",
-- .get_features = rtl822x_get_features,
-- .config_aneg = rtl822x_config_aneg,
-- .read_status = rtl822x_read_status,
-- .suspend = genphy_suspend,
-- .resume = rtlgen_resume,
-- .read_page = rtl821x_read_page,
-- .write_page = rtl821x_write_page,
-- }, {
-- .match_phy_device = rtl_internal_nbaset_match_phy_device,
-- .name = "Realtek Internal NBASE-T PHY",
-- .flags = PHY_IS_INTERNAL,
-- .get_features = rtl822x_get_features,
-- .config_aneg = rtl822x_config_aneg,
-- .read_status = rtl822x_read_status,
-- .suspend = genphy_suspend,
-- .resume = rtlgen_resume,
-- .read_page = rtl821x_read_page,
-- .write_page = rtl821x_write_page,
-- .read_mmd = rtl822x_read_mmd,
-- .write_mmd = rtl822x_write_mmd,
-- }, {
-- PHY_ID_MATCH_EXACT(0x001ccad0),
-- .name = "RTL8224 2.5Gbps PHY",
-- .get_features = rtl822x_c45_get_features,
-- .config_aneg = rtl822x_c45_config_aneg,
-- .read_status = rtl822x_c45_read_status,
-- .suspend = genphy_c45_pma_suspend,
-- .resume = rtlgen_c45_resume,
-- }, {
-- PHY_ID_MATCH_EXACT(0x001cc961),
-- .name = "RTL8366RB Gigabit Ethernet",
-- .config_init = &rtl8366rb_config_init,
-- /* These interrupts are handled by the irq controller
-- * embedded inside the RTL8366RB, they get unmasked when the
-- * irq is requested and ACKed by reading the status register,
-- * which is done by the irqchip code.
-- */
-- .config_intr = genphy_no_config_intr,
-- .handle_interrupt = genphy_handle_interrupt_no_ack,
-- .suspend = genphy_suspend,
-- .resume = genphy_resume,
-- }, {
-- PHY_ID_MATCH_EXACT(0x001ccb00),
-- .name = "RTL9000AA_RTL9000AN Ethernet",
-- .features = PHY_BASIC_T1_FEATURES,
-- .config_init = rtl9000a_config_init,
-- .config_aneg = rtl9000a_config_aneg,
-- .read_status = rtl9000a_read_status,
-- .config_intr = rtl9000a_config_intr,
-- .handle_interrupt = rtl9000a_handle_interrupt,
-- .suspend = genphy_suspend,
-- .resume = genphy_resume,
-- .read_page = rtl821x_read_page,
-- .write_page = rtl821x_write_page,
-- }, {
-- PHY_ID_MATCH_EXACT(0x001cc942),
-- .name = "RTL8365MB-VC Gigabit Ethernet",
-- /* Interrupt handling analogous to RTL8366RB */
-- .config_intr = genphy_no_config_intr,
-- .handle_interrupt = genphy_handle_interrupt_no_ack,
-- .suspend = genphy_suspend,
-- .resume = genphy_resume,
-- }, {
-- PHY_ID_MATCH_EXACT(0x001cc960),
-- .name = "RTL8366S Gigabit Ethernet",
-- .suspend = genphy_suspend,
-- .resume = genphy_resume,
-- .read_mmd = genphy_read_mmd_unsupported,
-- .write_mmd = genphy_write_mmd_unsupported,
-- },
--};
--
--module_phy_driver(realtek_drvs);
--
--static const struct mdio_device_id __maybe_unused realtek_tbl[] = {
-- { PHY_ID_MATCH_VENDOR(0x001cc800) },
-- { }
--};
--
--MODULE_DEVICE_TABLE(mdio, realtek_tbl);
---- /dev/null
-+++ b/drivers/net/phy/realtek/realtek_main.c
-@@ -0,0 +1,1589 @@
-+// SPDX-License-Identifier: GPL-2.0+
-+/* drivers/net/phy/realtek.c
-+ *
-+ * Driver for Realtek PHYs
-+ *
-+ *
-+ * Copyright (c) 2004 Freescale Semiconductor, Inc.
-+ */
-+#include <linux/bitops.h>
-+#include <linux/of.h>
-+#include <linux/phy.h>
-+#include <linux/module.h>
-+#include <linux/delay.h>
-+#include <linux/clk.h>
-+
-+#define RTL821x_PHYSR 0x11
-+#define RTL821x_PHYSR_DUPLEX BIT(13)
-+#define RTL821x_PHYSR_SPEED GENMASK(15, 14)
-+
-+#define RTL821x_INER 0x12
-+#define RTL8211B_INER_INIT 0x6400
-+#define RTL8211E_INER_LINK_STATUS BIT(10)
-+#define RTL8211F_INER_LINK_STATUS BIT(4)
-+
-+#define RTL821x_INSR 0x13
-+
-+#define RTL821x_EXT_PAGE_SELECT 0x1e
-+#define RTL821x_PAGE_SELECT 0x1f
-+
-+#define RTL8211F_PHYCR1 0x18
-+#define RTL8211F_PHYCR2 0x19
-+#define RTL8211F_INSR 0x1d
-+
-+#define RTL8211F_LEDCR 0x10
-+#define RTL8211F_LEDCR_MODE BIT(15)
-+#define RTL8211F_LEDCR_ACT_TXRX BIT(4)
-+#define RTL8211F_LEDCR_LINK_1000 BIT(3)
-+#define RTL8211F_LEDCR_LINK_100 BIT(1)
-+#define RTL8211F_LEDCR_LINK_10 BIT(0)
-+#define RTL8211F_LEDCR_MASK GENMASK(4, 0)
-+#define RTL8211F_LEDCR_SHIFT 5
-+
-+#define RTL8211F_TX_DELAY BIT(8)
-+#define RTL8211F_RX_DELAY BIT(3)
-+
-+#define RTL8211F_ALDPS_PLL_OFF BIT(1)
-+#define RTL8211F_ALDPS_ENABLE BIT(2)
-+#define RTL8211F_ALDPS_XTAL_OFF BIT(12)
-+
-+#define RTL8211E_CTRL_DELAY BIT(13)
-+#define RTL8211E_TX_DELAY BIT(12)
-+#define RTL8211E_RX_DELAY BIT(11)
-+
-+#define RTL8211F_CLKOUT_EN BIT(0)
-+
-+#define RTL8201F_ISR 0x1e
-+#define RTL8201F_ISR_ANERR BIT(15)
-+#define RTL8201F_ISR_DUPLEX BIT(13)
-+#define RTL8201F_ISR_LINK BIT(11)
-+#define RTL8201F_ISR_MASK (RTL8201F_ISR_ANERR | \
-+ RTL8201F_ISR_DUPLEX | \
-+ RTL8201F_ISR_LINK)
-+#define RTL8201F_IER 0x13
-+
-+#define RTL822X_VND1_SERDES_OPTION 0x697a
-+#define RTL822X_VND1_SERDES_OPTION_MODE_MASK GENMASK(5, 0)
-+#define RTL822X_VND1_SERDES_OPTION_MODE_2500BASEX_SGMII 0
-+#define RTL822X_VND1_SERDES_OPTION_MODE_2500BASEX 2
-+
-+#define RTL822X_VND1_SERDES_CTRL3 0x7580
-+#define RTL822X_VND1_SERDES_CTRL3_MODE_MASK GENMASK(5, 0)
-+#define RTL822X_VND1_SERDES_CTRL3_MODE_SGMII 0x02
-+#define RTL822X_VND1_SERDES_CTRL3_MODE_2500BASEX 0x16
-+
-+/* RTL822X_VND2_XXXXX registers are only accessible when phydev->is_c45
-+ * is set, they cannot be accessed by C45-over-C22.
-+ */
-+#define RTL822X_VND2_GBCR 0xa412
-+
-+#define RTL822X_VND2_GANLPAR 0xa414
-+
-+#define RTL8366RB_POWER_SAVE 0x15
-+#define RTL8366RB_POWER_SAVE_ON BIT(12)
-+
-+#define RTL9000A_GINMR 0x14
-+#define RTL9000A_GINMR_LINK_STATUS BIT(4)
-+
-+#define RTL_VND2_PHYSR 0xa434
-+#define RTL_VND2_PHYSR_DUPLEX BIT(3)
-+#define RTL_VND2_PHYSR_SPEEDL GENMASK(5, 4)
-+#define RTL_VND2_PHYSR_SPEEDH GENMASK(10, 9)
-+#define RTL_VND2_PHYSR_MASTER BIT(11)
-+#define RTL_VND2_PHYSR_SPEED_MASK (RTL_VND2_PHYSR_SPEEDL | RTL_VND2_PHYSR_SPEEDH)
-+
-+#define RTL_GENERIC_PHYID 0x001cc800
-+#define RTL_8211FVD_PHYID 0x001cc878
-+#define RTL_8221B 0x001cc840
-+#define RTL_8221B_VB_CG 0x001cc849
-+#define RTL_8221B_VN_CG 0x001cc84a
-+#define RTL_8251B 0x001cc862
-+
-+#define RTL8211F_LED_COUNT 3
-+
-+MODULE_DESCRIPTION("Realtek PHY driver");
-+MODULE_AUTHOR("Johnson Leung");
-+MODULE_LICENSE("GPL");
-+
-+struct rtl821x_priv {
-+ u16 phycr1;
-+ u16 phycr2;
-+ bool has_phycr2;
-+ struct clk *clk;
-+};
-+
-+static int rtl821x_read_page(struct phy_device *phydev)
-+{
-+ return __phy_read(phydev, RTL821x_PAGE_SELECT);
-+}
-+
-+static int rtl821x_write_page(struct phy_device *phydev, int page)
-+{
-+ return __phy_write(phydev, RTL821x_PAGE_SELECT, page);
-+}
-+
-+static int rtl821x_probe(struct phy_device *phydev)
-+{
-+ struct device *dev = &phydev->mdio.dev;
-+ struct rtl821x_priv *priv;
-+ u32 phy_id = phydev->drv->phy_id;
-+ int ret;
-+
-+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
-+ if (!priv)
-+ return -ENOMEM;
-+
-+ priv->clk = devm_clk_get_optional_enabled(dev, NULL);
-+ if (IS_ERR(priv->clk))
-+ return dev_err_probe(dev, PTR_ERR(priv->clk),
-+ "failed to get phy clock\n");
-+
-+ ret = phy_read_paged(phydev, 0xa43, RTL8211F_PHYCR1);
-+ if (ret < 0)
-+ return ret;
-+
-+ priv->phycr1 = ret & (RTL8211F_ALDPS_PLL_OFF | RTL8211F_ALDPS_ENABLE | RTL8211F_ALDPS_XTAL_OFF);
-+ if (of_property_read_bool(dev->of_node, "realtek,aldps-enable"))
-+ priv->phycr1 |= RTL8211F_ALDPS_PLL_OFF | RTL8211F_ALDPS_ENABLE | RTL8211F_ALDPS_XTAL_OFF;
-+
-+ priv->has_phycr2 = !(phy_id == RTL_8211FVD_PHYID);
-+ if (priv->has_phycr2) {
-+ ret = phy_read_paged(phydev, 0xa43, RTL8211F_PHYCR2);
-+ if (ret < 0)
-+ return ret;
-+
-+ priv->phycr2 = ret & RTL8211F_CLKOUT_EN;
-+ if (of_property_read_bool(dev->of_node, "realtek,clkout-disable"))
-+ priv->phycr2 &= ~RTL8211F_CLKOUT_EN;
-+ }
-+
-+ phydev->priv = priv;
-+
-+ return 0;
-+}
-+
-+static int rtl8201_ack_interrupt(struct phy_device *phydev)
-+{
-+ int err;
-+
-+ err = phy_read(phydev, RTL8201F_ISR);
-+
-+ return (err < 0) ? err : 0;
-+}
-+
-+static int rtl821x_ack_interrupt(struct phy_device *phydev)
-+{
-+ int err;
-+
-+ err = phy_read(phydev, RTL821x_INSR);
-+
-+ return (err < 0) ? err : 0;
-+}
-+
-+static int rtl8211f_ack_interrupt(struct phy_device *phydev)
-+{
-+ int err;
-+
-+ err = phy_read_paged(phydev, 0xa43, RTL8211F_INSR);
-+
-+ return (err < 0) ? err : 0;
-+}
-+
-+static int rtl8201_config_intr(struct phy_device *phydev)
-+{
-+ u16 val;
-+ int err;
-+
-+ if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
-+ err = rtl8201_ack_interrupt(phydev);
-+ if (err)
-+ return err;
-+
-+ val = BIT(13) | BIT(12) | BIT(11);
-+ err = phy_write_paged(phydev, 0x7, RTL8201F_IER, val);
-+ } else {
-+ val = 0;
-+ err = phy_write_paged(phydev, 0x7, RTL8201F_IER, val);
-+ if (err)
-+ return err;
-+
-+ err = rtl8201_ack_interrupt(phydev);
-+ }
-+
-+ return err;
-+}
-+
-+static int rtl8211b_config_intr(struct phy_device *phydev)
-+{
-+ int err;
-+
-+ if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
-+ err = rtl821x_ack_interrupt(phydev);
-+ if (err)
-+ return err;
-+
-+ err = phy_write(phydev, RTL821x_INER,
-+ RTL8211B_INER_INIT);
-+ } else {
-+ err = phy_write(phydev, RTL821x_INER, 0);
-+ if (err)
-+ return err;
-+
-+ err = rtl821x_ack_interrupt(phydev);
-+ }
-+
-+ return err;
-+}
-+
-+static int rtl8211e_config_intr(struct phy_device *phydev)
-+{
-+ int err;
-+
-+ if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
-+ err = rtl821x_ack_interrupt(phydev);
-+ if (err)
-+ return err;
-+
-+ err = phy_write(phydev, RTL821x_INER,
-+ RTL8211E_INER_LINK_STATUS);
-+ } else {
-+ err = phy_write(phydev, RTL821x_INER, 0);
-+ if (err)
-+ return err;
-+
-+ err = rtl821x_ack_interrupt(phydev);
-+ }
-+
-+ return err;
-+}
-+
-+static int rtl8211f_config_intr(struct phy_device *phydev)
-+{
-+ u16 val;
-+ int err;
-+
-+ if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
-+ err = rtl8211f_ack_interrupt(phydev);
-+ if (err)
-+ return err;
-+
-+ val = RTL8211F_INER_LINK_STATUS;
-+ err = phy_write_paged(phydev, 0xa42, RTL821x_INER, val);
-+ } else {
-+ val = 0;
-+ err = phy_write_paged(phydev, 0xa42, RTL821x_INER, val);
-+ if (err)
-+ return err;
-+
-+ err = rtl8211f_ack_interrupt(phydev);
-+ }
-+
-+ return err;
-+}
-+
-+static irqreturn_t rtl8201_handle_interrupt(struct phy_device *phydev)
-+{
-+ int irq_status;
-+
-+ irq_status = phy_read(phydev, RTL8201F_ISR);
-+ if (irq_status < 0) {
-+ phy_error(phydev);
-+ return IRQ_NONE;
-+ }
-+
-+ if (!(irq_status & RTL8201F_ISR_MASK))
-+ return IRQ_NONE;
-+
-+ phy_trigger_machine(phydev);
-+
-+ return IRQ_HANDLED;
-+}
-+
-+static irqreturn_t rtl821x_handle_interrupt(struct phy_device *phydev)
-+{
-+ int irq_status, irq_enabled;
-+
-+ irq_status = phy_read(phydev, RTL821x_INSR);
-+ if (irq_status < 0) {
-+ phy_error(phydev);
-+ return IRQ_NONE;
-+ }
-+
-+ irq_enabled = phy_read(phydev, RTL821x_INER);
-+ if (irq_enabled < 0) {
-+ phy_error(phydev);
-+ return IRQ_NONE;
-+ }
-+
-+ if (!(irq_status & irq_enabled))
-+ return IRQ_NONE;
-+
-+ phy_trigger_machine(phydev);
-+
-+ return IRQ_HANDLED;
-+}
-+
-+static irqreturn_t rtl8211f_handle_interrupt(struct phy_device *phydev)
-+{
-+ int irq_status;
-+
-+ irq_status = phy_read_paged(phydev, 0xa43, RTL8211F_INSR);
-+ if (irq_status < 0) {
-+ phy_error(phydev);
-+ return IRQ_NONE;
-+ }
-+
-+ if (!(irq_status & RTL8211F_INER_LINK_STATUS))
-+ return IRQ_NONE;
-+
-+ phy_trigger_machine(phydev);
-+
-+ return IRQ_HANDLED;
-+}
-+
-+static int rtl8211_config_aneg(struct phy_device *phydev)
-+{
-+ int ret;
-+
-+ ret = genphy_config_aneg(phydev);
-+ if (ret < 0)
-+ return ret;
-+
-+ /* Quirk was copied from vendor driver. Unfortunately it includes no
-+ * description of the magic numbers.
-+ */
-+ if (phydev->speed == SPEED_100 && phydev->autoneg == AUTONEG_DISABLE) {
-+ phy_write(phydev, 0x17, 0x2138);
-+ phy_write(phydev, 0x0e, 0x0260);
-+ } else {
-+ phy_write(phydev, 0x17, 0x2108);
-+ phy_write(phydev, 0x0e, 0x0000);
-+ }
-+
-+ return 0;
-+}
-+
-+static int rtl8211c_config_init(struct phy_device *phydev)
-+{
-+ /* RTL8211C has an issue when operating in Gigabit slave mode */
-+ return phy_set_bits(phydev, MII_CTRL1000,
-+ CTL1000_ENABLE_MASTER | CTL1000_AS_MASTER);
-+}
-+
-+static int rtl8211f_config_init(struct phy_device *phydev)
-+{
-+ struct rtl821x_priv *priv = phydev->priv;
-+ struct device *dev = &phydev->mdio.dev;
-+ u16 val_txdly, val_rxdly;
-+ int ret;
-+
-+ ret = phy_modify_paged_changed(phydev, 0xa43, RTL8211F_PHYCR1,
-+ RTL8211F_ALDPS_PLL_OFF | RTL8211F_ALDPS_ENABLE | RTL8211F_ALDPS_XTAL_OFF,
-+ priv->phycr1);
-+ if (ret < 0) {
-+ dev_err(dev, "aldps mode configuration failed: %pe\n",
-+ ERR_PTR(ret));
-+ return ret;
-+ }
-+
-+ switch (phydev->interface) {
-+ case PHY_INTERFACE_MODE_RGMII:
-+ val_txdly = 0;
-+ val_rxdly = 0;
-+ break;
-+
-+ case PHY_INTERFACE_MODE_RGMII_RXID:
-+ val_txdly = 0;
-+ val_rxdly = RTL8211F_RX_DELAY;
-+ break;
-+
-+ case PHY_INTERFACE_MODE_RGMII_TXID:
-+ val_txdly = RTL8211F_TX_DELAY;
-+ val_rxdly = 0;
-+ break;
-+
-+ case PHY_INTERFACE_MODE_RGMII_ID:
-+ val_txdly = RTL8211F_TX_DELAY;
-+ val_rxdly = RTL8211F_RX_DELAY;
-+ break;
-+
-+ default: /* the rest of the modes imply leaving delay as is. */
-+ return 0;
-+ }
-+
-+ ret = phy_modify_paged_changed(phydev, 0xd08, 0x11, RTL8211F_TX_DELAY,
-+ val_txdly);
-+ if (ret < 0) {
-+ dev_err(dev, "Failed to update the TX delay register\n");
-+ return ret;
-+ } else if (ret) {
-+ dev_dbg(dev,
-+ "%s 2ns TX delay (and changing the value from pin-strapping RXD1 or the bootloader)\n",
-+ val_txdly ? "Enabling" : "Disabling");
-+ } else {
-+ dev_dbg(dev,
-+ "2ns TX delay was already %s (by pin-strapping RXD1 or bootloader configuration)\n",
-+ val_txdly ? "enabled" : "disabled");
-+ }
-+
-+ ret = phy_modify_paged_changed(phydev, 0xd08, 0x15, RTL8211F_RX_DELAY,
-+ val_rxdly);
-+ if (ret < 0) {
-+ dev_err(dev, "Failed to update the RX delay register\n");
-+ return ret;
-+ } else if (ret) {
-+ dev_dbg(dev,
-+ "%s 2ns RX delay (and changing the value from pin-strapping RXD0 or the bootloader)\n",
-+ val_rxdly ? "Enabling" : "Disabling");
-+ } else {
-+ dev_dbg(dev,
-+ "2ns RX delay was already %s (by pin-strapping RXD0 or bootloader configuration)\n",
-+ val_rxdly ? "enabled" : "disabled");
-+ }
-+
-+ if (priv->has_phycr2) {
-+ ret = phy_modify_paged(phydev, 0xa43, RTL8211F_PHYCR2,
-+ RTL8211F_CLKOUT_EN, priv->phycr2);
-+ if (ret < 0) {
-+ dev_err(dev, "clkout configuration failed: %pe\n",
-+ ERR_PTR(ret));
-+ return ret;
-+ }
-+
-+ return genphy_soft_reset(phydev);
-+ }
-+
-+ return 0;
-+}
-+
-+static int rtl821x_suspend(struct phy_device *phydev)
-+{
-+ struct rtl821x_priv *priv = phydev->priv;
-+ int ret = 0;
-+
-+ if (!phydev->wol_enabled) {
-+ ret = genphy_suspend(phydev);
-+
-+ if (ret)
-+ return ret;
-+
-+ clk_disable_unprepare(priv->clk);
-+ }
-+
-+ return ret;
-+}
-+
-+static int rtl821x_resume(struct phy_device *phydev)
-+{
-+ struct rtl821x_priv *priv = phydev->priv;
-+ int ret;
-+
-+ if (!phydev->wol_enabled)
-+ clk_prepare_enable(priv->clk);
-+
-+ ret = genphy_resume(phydev);
-+ if (ret < 0)
-+ return ret;
-+
-+ msleep(20);
-+
-+ return 0;
-+}
-+
-+static int rtl8211f_led_hw_is_supported(struct phy_device *phydev, u8 index,
-+ unsigned long rules)
-+{
-+ const unsigned long mask = BIT(TRIGGER_NETDEV_LINK_10) |
-+ BIT(TRIGGER_NETDEV_LINK_100) |
-+ BIT(TRIGGER_NETDEV_LINK_1000) |
-+ BIT(TRIGGER_NETDEV_RX) |
-+ BIT(TRIGGER_NETDEV_TX);
-+
-+ /* The RTL8211F PHY supports these LED settings on up to three LEDs:
-+ * - Link: Configurable subset of 10/100/1000 link rates
-+ * - Active: Blink on activity, RX or TX is not differentiated
-+ * The Active option has two modes, A and B:
-+ * - A: Link and Active indication at configurable, but matching,
-+ * subset of 10/100/1000 link rates
-+ * - B: Link indication at configurable subset of 10/100/1000 link
-+ * rates and Active indication always at all three 10+100+1000
-+ * link rates.
-+ * This code currently uses mode B only.
-+ */
-+
-+ if (index >= RTL8211F_LED_COUNT)
-+ return -EINVAL;
-+
-+ /* Filter out any other unsupported triggers. */
-+ if (rules & ~mask)
-+ return -EOPNOTSUPP;
-+
-+ /* RX and TX are not differentiated, either both are set or not set. */
-+ if (!(rules & BIT(TRIGGER_NETDEV_RX)) ^ !(rules & BIT(TRIGGER_NETDEV_TX)))
-+ return -EOPNOTSUPP;
-+
-+ return 0;
-+}
-+
-+static int rtl8211f_led_hw_control_get(struct phy_device *phydev, u8 index,
-+ unsigned long *rules)
-+{
-+ int val;
-+
-+ if (index >= RTL8211F_LED_COUNT)
-+ return -EINVAL;
-+
-+ val = phy_read_paged(phydev, 0xd04, RTL8211F_LEDCR);
-+ if (val < 0)
-+ return val;
-+
-+ val >>= RTL8211F_LEDCR_SHIFT * index;
-+ val &= RTL8211F_LEDCR_MASK;
-+
-+ if (val & RTL8211F_LEDCR_LINK_10)
-+ set_bit(TRIGGER_NETDEV_LINK_10, rules);
-+
-+ if (val & RTL8211F_LEDCR_LINK_100)
-+ set_bit(TRIGGER_NETDEV_LINK_100, rules);
-+
-+ if (val & RTL8211F_LEDCR_LINK_1000)
-+ set_bit(TRIGGER_NETDEV_LINK_1000, rules);
-+
-+ if (val & RTL8211F_LEDCR_ACT_TXRX) {
-+ set_bit(TRIGGER_NETDEV_RX, rules);
-+ set_bit(TRIGGER_NETDEV_TX, rules);
-+ }
-+
-+ return 0;
-+}
-+
-+static int rtl8211f_led_hw_control_set(struct phy_device *phydev, u8 index,
-+ unsigned long rules)
-+{
-+ const u16 mask = RTL8211F_LEDCR_MASK << (RTL8211F_LEDCR_SHIFT * index);
-+ u16 reg = 0;
-+
-+ if (index >= RTL8211F_LED_COUNT)
-+ return -EINVAL;
-+
-+ if (test_bit(TRIGGER_NETDEV_LINK_10, &rules))
-+ reg |= RTL8211F_LEDCR_LINK_10;
-+
-+ if (test_bit(TRIGGER_NETDEV_LINK_100, &rules))
-+ reg |= RTL8211F_LEDCR_LINK_100;
-+
-+ if (test_bit(TRIGGER_NETDEV_LINK_1000, &rules))
-+ reg |= RTL8211F_LEDCR_LINK_1000;
-+
-+ if (test_bit(TRIGGER_NETDEV_RX, &rules) ||
-+ test_bit(TRIGGER_NETDEV_TX, &rules)) {
-+ reg |= RTL8211F_LEDCR_ACT_TXRX;
-+ }
-+
-+ reg <<= RTL8211F_LEDCR_SHIFT * index;
-+ reg |= RTL8211F_LEDCR_MODE; /* Mode B */
-+
-+ return phy_modify_paged(phydev, 0xd04, RTL8211F_LEDCR, mask, reg);
-+}
-+
-+static int rtl8211e_config_init(struct phy_device *phydev)
-+{
-+ int ret = 0, oldpage;
-+ u16 val;
-+
-+ /* enable TX/RX delay for rgmii-* modes, and disable them for rgmii. */
-+ switch (phydev->interface) {
-+ case PHY_INTERFACE_MODE_RGMII:
-+ val = RTL8211E_CTRL_DELAY | 0;
-+ break;
-+ case PHY_INTERFACE_MODE_RGMII_ID:
-+ val = RTL8211E_CTRL_DELAY | RTL8211E_TX_DELAY | RTL8211E_RX_DELAY;
-+ break;
-+ case PHY_INTERFACE_MODE_RGMII_RXID:
-+ val = RTL8211E_CTRL_DELAY | RTL8211E_RX_DELAY;
-+ break;
-+ case PHY_INTERFACE_MODE_RGMII_TXID:
-+ val = RTL8211E_CTRL_DELAY | RTL8211E_TX_DELAY;
-+ break;
-+ default: /* the rest of the modes imply leaving delays as is. */
-+ return 0;
-+ }
-+
-+ /* According to a sample driver there is a 0x1c config register on the
-+ * 0xa4 extension page (0x7) layout. It can be used to disable/enable
-+ * the RX/TX delays otherwise controlled by RXDLY/TXDLY pins.
-+ * The configuration register definition:
-+ * 14 = reserved
-+ * 13 = Force Tx RX Delay controlled by bit12 bit11,
-+ * 12 = RX Delay, 11 = TX Delay
-+ * 10:0 = Test && debug settings reserved by realtek
-+ */
-+ oldpage = phy_select_page(phydev, 0x7);
-+ if (oldpage < 0)
-+ goto err_restore_page;
-+
-+ ret = __phy_write(phydev, RTL821x_EXT_PAGE_SELECT, 0xa4);
-+ if (ret)
-+ goto err_restore_page;
-+
-+ ret = __phy_modify(phydev, 0x1c, RTL8211E_CTRL_DELAY
-+ | RTL8211E_TX_DELAY | RTL8211E_RX_DELAY,
-+ val);
-+
-+err_restore_page:
-+ return phy_restore_page(phydev, oldpage, ret);
-+}
-+
-+static int rtl8211b_suspend(struct phy_device *phydev)
-+{
-+ phy_write(phydev, MII_MMD_DATA, BIT(9));
-+
-+ return genphy_suspend(phydev);
-+}
-+
-+static int rtl8211b_resume(struct phy_device *phydev)
-+{
-+ phy_write(phydev, MII_MMD_DATA, 0);
-+
-+ return genphy_resume(phydev);
-+}
-+
-+static int rtl8366rb_config_init(struct phy_device *phydev)
-+{
-+ int ret;
-+
-+ ret = phy_set_bits(phydev, RTL8366RB_POWER_SAVE,
-+ RTL8366RB_POWER_SAVE_ON);
-+ if (ret) {
-+ dev_err(&phydev->mdio.dev,
-+ "error enabling power management\n");
-+ }
-+
-+ return ret;
-+}
-+
-+/* get actual speed to cover the downshift case */
-+static void rtlgen_decode_physr(struct phy_device *phydev, int val)
-+{
-+ /* bit 3
-+ * 0: Half Duplex
-+ * 1: Full Duplex
-+ */
-+ if (val & RTL_VND2_PHYSR_DUPLEX)
-+ phydev->duplex = DUPLEX_FULL;
-+ else
-+ phydev->duplex = DUPLEX_HALF;
-+
-+ switch (val & RTL_VND2_PHYSR_SPEED_MASK) {
-+ case 0x0000:
-+ phydev->speed = SPEED_10;
-+ break;
-+ case 0x0010:
-+ phydev->speed = SPEED_100;
-+ break;
-+ case 0x0020:
-+ phydev->speed = SPEED_1000;
-+ break;
-+ case 0x0200:
-+ phydev->speed = SPEED_10000;
-+ break;
-+ case 0x0210:
-+ phydev->speed = SPEED_2500;
-+ break;
-+ case 0x0220:
-+ phydev->speed = SPEED_5000;
-+ break;
-+ default:
-+ break;
-+ }
-+
-+ /* bit 11
-+ * 0: Slave Mode
-+ * 1: Master Mode
-+ */
-+ if (phydev->speed >= 1000) {
-+ if (val & RTL_VND2_PHYSR_MASTER)
-+ phydev->master_slave_state = MASTER_SLAVE_STATE_MASTER;
-+ else
-+ phydev->master_slave_state = MASTER_SLAVE_STATE_SLAVE;
-+ } else {
-+ phydev->master_slave_state = MASTER_SLAVE_STATE_UNSUPPORTED;
-+ }
-+}
-+
-+static int rtlgen_read_status(struct phy_device *phydev)
-+{
-+ int ret, val;
-+
-+ ret = genphy_read_status(phydev);
-+ if (ret < 0)
-+ return ret;
-+
-+ if (!phydev->link)
-+ return 0;
-+
-+ val = phy_read_paged(phydev, 0xa43, 0x12);
-+ if (val < 0)
-+ return val;
-+
-+ rtlgen_decode_physr(phydev, val);
-+
-+ return 0;
-+}
-+
-+static int rtlgen_read_mmd(struct phy_device *phydev, int devnum, u16 regnum)
-+{
-+ int ret;
-+
-+ if (devnum == MDIO_MMD_VEND2) {
-+ rtl821x_write_page(phydev, regnum >> 4);
-+ ret = __phy_read(phydev, 0x10 + ((regnum & 0xf) >> 1));
-+ rtl821x_write_page(phydev, 0);
-+ } else if (devnum == MDIO_MMD_PCS && regnum == MDIO_PCS_EEE_ABLE) {
-+ rtl821x_write_page(phydev, 0xa5c);
-+ ret = __phy_read(phydev, 0x12);
-+ rtl821x_write_page(phydev, 0);
-+ } else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV) {
-+ rtl821x_write_page(phydev, 0xa5d);
-+ ret = __phy_read(phydev, 0x10);
-+ rtl821x_write_page(phydev, 0);
-+ } else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_LPABLE) {
-+ rtl821x_write_page(phydev, 0xa5d);
-+ ret = __phy_read(phydev, 0x11);
-+ rtl821x_write_page(phydev, 0);
-+ } else {
-+ ret = -EOPNOTSUPP;
-+ }
-+
-+ return ret;
-+}
-+
-+static int rtlgen_write_mmd(struct phy_device *phydev, int devnum, u16 regnum,
-+ u16 val)
-+{
-+ int ret;
-+
-+ if (devnum == MDIO_MMD_VEND2) {
-+ rtl821x_write_page(phydev, regnum >> 4);
-+ ret = __phy_write(phydev, 0x10 + ((regnum & 0xf) >> 1), val);
-+ rtl821x_write_page(phydev, 0);
-+ } else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV) {
-+ rtl821x_write_page(phydev, 0xa5d);
-+ ret = __phy_write(phydev, 0x10, val);
-+ rtl821x_write_page(phydev, 0);
-+ } else {
-+ ret = -EOPNOTSUPP;
-+ }
-+
-+ return ret;
-+}
-+
-+static int rtl822x_read_mmd(struct phy_device *phydev, int devnum, u16 regnum)
-+{
-+ int ret = rtlgen_read_mmd(phydev, devnum, regnum);
-+
-+ if (ret != -EOPNOTSUPP)
-+ return ret;
-+
-+ if (devnum == MDIO_MMD_PCS && regnum == MDIO_PCS_EEE_ABLE2) {
-+ rtl821x_write_page(phydev, 0xa6e);
-+ ret = __phy_read(phydev, 0x16);
-+ rtl821x_write_page(phydev, 0);
-+ } else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV2) {
-+ rtl821x_write_page(phydev, 0xa6d);
-+ ret = __phy_read(phydev, 0x12);
-+ rtl821x_write_page(phydev, 0);
-+ } else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_LPABLE2) {
-+ rtl821x_write_page(phydev, 0xa6d);
-+ ret = __phy_read(phydev, 0x10);
-+ rtl821x_write_page(phydev, 0);
-+ }
-+
-+ return ret;
-+}
-+
-+static int rtl822x_write_mmd(struct phy_device *phydev, int devnum, u16 regnum,
-+ u16 val)
-+{
-+ int ret = rtlgen_write_mmd(phydev, devnum, regnum, val);
-+
-+ if (ret != -EOPNOTSUPP)
-+ return ret;
-+
-+ if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV2) {
-+ rtl821x_write_page(phydev, 0xa6d);
-+ ret = __phy_write(phydev, 0x12, val);
-+ rtl821x_write_page(phydev, 0);
-+ }
-+
-+ return ret;
-+}
-+
-+static int rtl822xb_config_init(struct phy_device *phydev)
-+{
-+ bool has_2500, has_sgmii;
-+ u16 mode;
-+ int ret;
-+
-+ has_2500 = test_bit(PHY_INTERFACE_MODE_2500BASEX,
-+ phydev->host_interfaces) ||
-+ phydev->interface == PHY_INTERFACE_MODE_2500BASEX;
-+
-+ has_sgmii = test_bit(PHY_INTERFACE_MODE_SGMII,
-+ phydev->host_interfaces) ||
-+ phydev->interface == PHY_INTERFACE_MODE_SGMII;
-+
-+ /* fill in possible interfaces */
-+ __assign_bit(PHY_INTERFACE_MODE_2500BASEX, phydev->possible_interfaces,
-+ has_2500);
-+ __assign_bit(PHY_INTERFACE_MODE_SGMII, phydev->possible_interfaces,
-+ has_sgmii);
-+
-+ if (!has_2500 && !has_sgmii)
-+ return 0;
-+
-+ /* determine SerDes option mode */
-+ if (has_2500 && !has_sgmii) {
-+ mode = RTL822X_VND1_SERDES_OPTION_MODE_2500BASEX;
-+ phydev->rate_matching = RATE_MATCH_PAUSE;
-+ } else {
-+ mode = RTL822X_VND1_SERDES_OPTION_MODE_2500BASEX_SGMII;
-+ phydev->rate_matching = RATE_MATCH_NONE;
-+ }
-+
-+ /* the following sequence with magic numbers sets up the SerDes
-+ * option mode
-+ */
-+ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x75f3, 0);
-+ if (ret < 0)
-+ return ret;
-+
-+ ret = phy_modify_mmd_changed(phydev, MDIO_MMD_VEND1,
-+ RTL822X_VND1_SERDES_OPTION,
-+ RTL822X_VND1_SERDES_OPTION_MODE_MASK,
-+ mode);
-+ if (ret < 0)
-+ return ret;
-+
-+ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x6a04, 0x0503);
-+ if (ret < 0)
-+ return ret;
-+
-+ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x6f10, 0xd455);
-+ if (ret < 0)
-+ return ret;
-+
-+ return phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x6f11, 0x8020);
-+}
-+
-+static int rtl822xb_get_rate_matching(struct phy_device *phydev,
-+ phy_interface_t iface)
-+{
-+ int val;
-+
-+ /* Only rate matching at 2500base-x */
-+ if (iface != PHY_INTERFACE_MODE_2500BASEX)
-+ return RATE_MATCH_NONE;
-+
-+ val = phy_read_mmd(phydev, MDIO_MMD_VEND1, RTL822X_VND1_SERDES_OPTION);
-+ if (val < 0)
-+ return val;
-+
-+ if ((val & RTL822X_VND1_SERDES_OPTION_MODE_MASK) ==
-+ RTL822X_VND1_SERDES_OPTION_MODE_2500BASEX)
-+ return RATE_MATCH_PAUSE;
-+
-+ /* RTL822X_VND1_SERDES_OPTION_MODE_2500BASEX_SGMII */
-+ return RATE_MATCH_NONE;
-+}
-+
-+static int rtl822x_get_features(struct phy_device *phydev)
-+{
-+ int val;
-+
-+ val = phy_read_paged(phydev, 0xa61, 0x13);
-+ if (val < 0)
-+ return val;
-+
-+ linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
-+ phydev->supported, val & MDIO_PMA_SPEED_2_5G);
-+ linkmode_mod_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT,
-+ phydev->supported, val & MDIO_PMA_SPEED_5G);
-+ linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT,
-+ phydev->supported, val & MDIO_SPEED_10G);
-+
-+ return genphy_read_abilities(phydev);
-+}
-+
-+static int rtl822x_config_aneg(struct phy_device *phydev)
-+{
-+ int ret = 0;
-+
-+ if (phydev->autoneg == AUTONEG_ENABLE) {
-+ u16 adv = linkmode_adv_to_mii_10gbt_adv_t(phydev->advertising);
-+
-+ ret = phy_modify_paged_changed(phydev, 0xa5d, 0x12,
-+ MDIO_AN_10GBT_CTRL_ADV2_5G |
-+ MDIO_AN_10GBT_CTRL_ADV5G,
-+ adv);
-+ if (ret < 0)
-+ return ret;
-+ }
-+
-+ return __genphy_config_aneg(phydev, ret);
-+}
-+
-+static void rtl822xb_update_interface(struct phy_device *phydev)
-+{
-+ int val;
-+
-+ if (!phydev->link)
-+ return;
-+
-+ /* Change interface according to serdes mode */
-+ val = phy_read_mmd(phydev, MDIO_MMD_VEND1, RTL822X_VND1_SERDES_CTRL3);
-+ if (val < 0)
-+ return;
-+
-+ switch (val & RTL822X_VND1_SERDES_CTRL3_MODE_MASK) {
-+ case RTL822X_VND1_SERDES_CTRL3_MODE_2500BASEX:
-+ phydev->interface = PHY_INTERFACE_MODE_2500BASEX;
-+ break;
-+ case RTL822X_VND1_SERDES_CTRL3_MODE_SGMII:
-+ phydev->interface = PHY_INTERFACE_MODE_SGMII;
-+ break;
-+ }
-+}
-+
-+static int rtl822x_read_status(struct phy_device *phydev)
-+{
-+ int lpadv, ret;
-+
-+ mii_10gbt_stat_mod_linkmode_lpa_t(phydev->lp_advertising, 0);
-+
-+ ret = rtlgen_read_status(phydev);
-+ if (ret < 0)
-+ return ret;
-+
-+ if (phydev->autoneg == AUTONEG_DISABLE ||
-+ !phydev->autoneg_complete)
-+ return 0;
-+
-+ lpadv = phy_read_paged(phydev, 0xa5d, 0x13);
-+ if (lpadv < 0)
-+ return lpadv;
-+
-+ mii_10gbt_stat_mod_linkmode_lpa_t(phydev->lp_advertising, lpadv);
-+
-+ return 0;
-+}
-+
-+static int rtl822xb_read_status(struct phy_device *phydev)
-+{
-+ int ret;
-+
-+ ret = rtl822x_read_status(phydev);
-+ if (ret < 0)
-+ return ret;
-+
-+ rtl822xb_update_interface(phydev);
-+
-+ return 0;
-+}
-+
-+static int rtl822x_c45_get_features(struct phy_device *phydev)
-+{
-+ linkmode_set_bit(ETHTOOL_LINK_MODE_TP_BIT,
-+ phydev->supported);
-+
-+ return genphy_c45_pma_read_abilities(phydev);
-+}
-+
-+static int rtl822x_c45_config_aneg(struct phy_device *phydev)
-+{
-+ bool changed = false;
-+ int ret, val;
-+
-+ if (phydev->autoneg == AUTONEG_DISABLE)
-+ return genphy_c45_pma_setup_forced(phydev);
-+
-+ ret = genphy_c45_an_config_aneg(phydev);
-+ if (ret < 0)
-+ return ret;
-+ if (ret > 0)
-+ changed = true;
-+
-+ val = linkmode_adv_to_mii_ctrl1000_t(phydev->advertising);
-+
-+ /* Vendor register as C45 has no standardized support for 1000BaseT */
-+ ret = phy_modify_mmd_changed(phydev, MDIO_MMD_VEND2, RTL822X_VND2_GBCR,
-+ ADVERTISE_1000FULL, val);
-+ if (ret < 0)
-+ return ret;
-+ if (ret > 0)
-+ changed = true;
-+
-+ return genphy_c45_check_and_restart_aneg(phydev, changed);
-+}
-+
-+static int rtl822x_c45_read_status(struct phy_device *phydev)
-+{
-+ int ret, val;
-+
-+ /* Vendor register as C45 has no standardized support for 1000BaseT */
-+ if (phydev->autoneg == AUTONEG_ENABLE && genphy_c45_aneg_done(phydev)) {
-+ val = phy_read_mmd(phydev, MDIO_MMD_VEND2,
-+ RTL822X_VND2_GANLPAR);
-+ if (val < 0)
-+ return val;
-+ } else {
-+ val = 0;
-+ }
-+ mii_stat1000_mod_linkmode_lpa_t(phydev->lp_advertising, val);
-+
-+ ret = genphy_c45_read_status(phydev);
-+ if (ret < 0)
-+ return ret;
-+
-+ if (!phydev->link) {
-+ phydev->master_slave_state = MASTER_SLAVE_STATE_UNKNOWN;
-+ return 0;
-+ }
-+
-+ /* Read actual speed from vendor register. */
-+ val = phy_read_mmd(phydev, MDIO_MMD_VEND2, RTL_VND2_PHYSR);
-+ if (val < 0)
-+ return val;
-+
-+ rtlgen_decode_physr(phydev, val);
-+
-+ return 0;
-+}
-+
-+static int rtl822xb_c45_read_status(struct phy_device *phydev)
-+{
-+ int ret;
-+
-+ ret = rtl822x_c45_read_status(phydev);
-+ if (ret < 0)
-+ return ret;
-+
-+ rtl822xb_update_interface(phydev);
-+
-+ return 0;
-+}
-+
-+static bool rtlgen_supports_2_5gbps(struct phy_device *phydev)
-+{
-+ int val;
-+
-+ phy_write(phydev, RTL821x_PAGE_SELECT, 0xa61);
-+ val = phy_read(phydev, 0x13);
-+ phy_write(phydev, RTL821x_PAGE_SELECT, 0);
-+
-+ return val >= 0 && val & MDIO_PMA_SPEED_2_5G;
-+}
-+
-+/* On internal PHY's MMD reads over C22 always return 0.
-+ * Check a MMD register which is known to be non-zero.
-+ */
-+static bool rtlgen_supports_mmd(struct phy_device *phydev)
-+{
-+ int val;
-+
-+ phy_lock_mdio_bus(phydev);
-+ __phy_write(phydev, MII_MMD_CTRL, MDIO_MMD_PCS);
-+ __phy_write(phydev, MII_MMD_DATA, MDIO_PCS_EEE_ABLE);
-+ __phy_write(phydev, MII_MMD_CTRL, MDIO_MMD_PCS | MII_MMD_CTRL_NOINCR);
-+ val = __phy_read(phydev, MII_MMD_DATA);
-+ phy_unlock_mdio_bus(phydev);
-+
-+ return val > 0;
-+}
-+
-+static int rtlgen_match_phy_device(struct phy_device *phydev)
-+{
-+ return phydev->phy_id == RTL_GENERIC_PHYID &&
-+ !rtlgen_supports_2_5gbps(phydev);
-+}
-+
-+static int rtl8226_match_phy_device(struct phy_device *phydev)
-+{
-+ return phydev->phy_id == RTL_GENERIC_PHYID &&
-+ rtlgen_supports_2_5gbps(phydev) &&
-+ rtlgen_supports_mmd(phydev);
-+}
-+
-+static int rtlgen_is_c45_match(struct phy_device *phydev, unsigned int id,
-+ bool is_c45)
-+{
-+ if (phydev->is_c45)
-+ return is_c45 && (id == phydev->c45_ids.device_ids[1]);
-+ else
-+ return !is_c45 && (id == phydev->phy_id);
-+}
-+
-+static int rtl8221b_match_phy_device(struct phy_device *phydev)
-+{
-+ return phydev->phy_id == RTL_8221B && rtlgen_supports_mmd(phydev);
-+}
-+
-+static int rtl8221b_vb_cg_c22_match_phy_device(struct phy_device *phydev)
-+{
-+ return rtlgen_is_c45_match(phydev, RTL_8221B_VB_CG, false);
-+}
-+
-+static int rtl8221b_vb_cg_c45_match_phy_device(struct phy_device *phydev)
-+{
-+ return rtlgen_is_c45_match(phydev, RTL_8221B_VB_CG, true);
-+}
-+
-+static int rtl8221b_vn_cg_c22_match_phy_device(struct phy_device *phydev)
-+{
-+ return rtlgen_is_c45_match(phydev, RTL_8221B_VN_CG, false);
-+}
-+
-+static int rtl8221b_vn_cg_c45_match_phy_device(struct phy_device *phydev)
-+{
-+ return rtlgen_is_c45_match(phydev, RTL_8221B_VN_CG, true);
-+}
-+
-+static int rtl_internal_nbaset_match_phy_device(struct phy_device *phydev)
-+{
-+ if (phydev->is_c45)
-+ return false;
-+
-+ switch (phydev->phy_id) {
-+ case RTL_GENERIC_PHYID:
-+ case RTL_8221B:
-+ case RTL_8251B:
-+ case 0x001cc841:
-+ break;
-+ default:
-+ return false;
-+ }
-+
-+ return rtlgen_supports_2_5gbps(phydev) && !rtlgen_supports_mmd(phydev);
-+}
-+
-+static int rtl8251b_c45_match_phy_device(struct phy_device *phydev)
-+{
-+ return rtlgen_is_c45_match(phydev, RTL_8251B, true);
-+}
-+
-+static int rtlgen_resume(struct phy_device *phydev)
-+{
-+ int ret = genphy_resume(phydev);
-+
-+ /* Internal PHY's from RTL8168h up may not be instantly ready */
-+ msleep(20);
-+
-+ return ret;
-+}
-+
-+static int rtlgen_c45_resume(struct phy_device *phydev)
-+{
-+ int ret = genphy_c45_pma_resume(phydev);
-+
-+ msleep(20);
-+
-+ return ret;
-+}
-+
-+static int rtl9000a_config_init(struct phy_device *phydev)
-+{
-+ phydev->autoneg = AUTONEG_DISABLE;
-+ phydev->speed = SPEED_100;
-+ phydev->duplex = DUPLEX_FULL;
-+
-+ return 0;
-+}
-+
-+static int rtl9000a_config_aneg(struct phy_device *phydev)
-+{
-+ int ret;
-+ u16 ctl = 0;
-+
-+ switch (phydev->master_slave_set) {
-+ case MASTER_SLAVE_CFG_MASTER_FORCE:
-+ ctl |= CTL1000_AS_MASTER;
-+ break;
-+ case MASTER_SLAVE_CFG_SLAVE_FORCE:
-+ break;
-+ case MASTER_SLAVE_CFG_UNKNOWN:
-+ case MASTER_SLAVE_CFG_UNSUPPORTED:
-+ return 0;
-+ default:
-+ phydev_warn(phydev, "Unsupported Master/Slave mode\n");
-+ return -EOPNOTSUPP;
-+ }
-+
-+ ret = phy_modify_changed(phydev, MII_CTRL1000, CTL1000_AS_MASTER, ctl);
-+ if (ret == 1)
-+ ret = genphy_soft_reset(phydev);
-+
-+ return ret;
-+}
-+
-+static int rtl9000a_read_status(struct phy_device *phydev)
-+{
-+ int ret;
-+
-+ phydev->master_slave_get = MASTER_SLAVE_CFG_UNKNOWN;
-+ phydev->master_slave_state = MASTER_SLAVE_STATE_UNKNOWN;
-+
-+ ret = genphy_update_link(phydev);
-+ if (ret)
-+ return ret;
-+
-+ ret = phy_read(phydev, MII_CTRL1000);
-+ if (ret < 0)
-+ return ret;
-+ if (ret & CTL1000_AS_MASTER)
-+ phydev->master_slave_get = MASTER_SLAVE_CFG_MASTER_FORCE;
-+ else
-+ phydev->master_slave_get = MASTER_SLAVE_CFG_SLAVE_FORCE;
-+
-+ ret = phy_read(phydev, MII_STAT1000);
-+ if (ret < 0)
-+ return ret;
-+ if (ret & LPA_1000MSRES)
-+ phydev->master_slave_state = MASTER_SLAVE_STATE_MASTER;
-+ else
-+ phydev->master_slave_state = MASTER_SLAVE_STATE_SLAVE;
-+
-+ return 0;
-+}
-+
-+static int rtl9000a_ack_interrupt(struct phy_device *phydev)
-+{
-+ int err;
-+
-+ err = phy_read(phydev, RTL8211F_INSR);
-+
-+ return (err < 0) ? err : 0;
-+}
-+
-+static int rtl9000a_config_intr(struct phy_device *phydev)
-+{
-+ u16 val;
-+ int err;
-+
-+ if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
-+ err = rtl9000a_ack_interrupt(phydev);
-+ if (err)
-+ return err;
-+
-+ val = (u16)~RTL9000A_GINMR_LINK_STATUS;
-+ err = phy_write_paged(phydev, 0xa42, RTL9000A_GINMR, val);
-+ } else {
-+ val = ~0;
-+ err = phy_write_paged(phydev, 0xa42, RTL9000A_GINMR, val);
-+ if (err)
-+ return err;
-+
-+ err = rtl9000a_ack_interrupt(phydev);
-+ }
-+
-+ return phy_write_paged(phydev, 0xa42, RTL9000A_GINMR, val);
-+}
-+
-+static irqreturn_t rtl9000a_handle_interrupt(struct phy_device *phydev)
-+{
-+ int irq_status;
-+
-+ irq_status = phy_read(phydev, RTL8211F_INSR);
-+ if (irq_status < 0) {
-+ phy_error(phydev);
-+ return IRQ_NONE;
-+ }
-+
-+ if (!(irq_status & RTL8211F_INER_LINK_STATUS))
-+ return IRQ_NONE;
-+
-+ phy_trigger_machine(phydev);
-+
-+ return IRQ_HANDLED;
-+}
-+
-+static struct phy_driver realtek_drvs[] = {
-+ {
-+ PHY_ID_MATCH_EXACT(0x00008201),
-+ .name = "RTL8201CP Ethernet",
-+ .read_page = rtl821x_read_page,
-+ .write_page = rtl821x_write_page,
-+ }, {
-+ PHY_ID_MATCH_EXACT(0x001cc816),
-+ .name = "RTL8201F Fast Ethernet",
-+ .config_intr = &rtl8201_config_intr,
-+ .handle_interrupt = rtl8201_handle_interrupt,
-+ .suspend = genphy_suspend,
-+ .resume = genphy_resume,
-+ .read_page = rtl821x_read_page,
-+ .write_page = rtl821x_write_page,
-+ }, {
-+ PHY_ID_MATCH_MODEL(0x001cc880),
-+ .name = "RTL8208 Fast Ethernet",
-+ .read_mmd = genphy_read_mmd_unsupported,
-+ .write_mmd = genphy_write_mmd_unsupported,
-+ .suspend = genphy_suspend,
-+ .resume = genphy_resume,
-+ .read_page = rtl821x_read_page,
-+ .write_page = rtl821x_write_page,
-+ }, {
-+ PHY_ID_MATCH_EXACT(0x001cc910),
-+ .name = "RTL8211 Gigabit Ethernet",
-+ .config_aneg = rtl8211_config_aneg,
-+ .read_mmd = &genphy_read_mmd_unsupported,
-+ .write_mmd = &genphy_write_mmd_unsupported,
-+ .read_page = rtl821x_read_page,
-+ .write_page = rtl821x_write_page,
-+ }, {
-+ PHY_ID_MATCH_EXACT(0x001cc912),
-+ .name = "RTL8211B Gigabit Ethernet",
-+ .config_intr = &rtl8211b_config_intr,
-+ .handle_interrupt = rtl821x_handle_interrupt,
-+ .read_mmd = &genphy_read_mmd_unsupported,
-+ .write_mmd = &genphy_write_mmd_unsupported,
-+ .suspend = rtl8211b_suspend,
-+ .resume = rtl8211b_resume,
-+ .read_page = rtl821x_read_page,
-+ .write_page = rtl821x_write_page,
-+ }, {
-+ PHY_ID_MATCH_EXACT(0x001cc913),
-+ .name = "RTL8211C Gigabit Ethernet",
-+ .config_init = rtl8211c_config_init,
-+ .read_mmd = &genphy_read_mmd_unsupported,
-+ .write_mmd = &genphy_write_mmd_unsupported,
-+ .read_page = rtl821x_read_page,
-+ .write_page = rtl821x_write_page,
-+ }, {
-+ PHY_ID_MATCH_EXACT(0x001cc914),
-+ .name = "RTL8211DN Gigabit Ethernet",
-+ .config_intr = rtl8211e_config_intr,
-+ .handle_interrupt = rtl821x_handle_interrupt,
-+ .suspend = genphy_suspend,
-+ .resume = genphy_resume,
-+ .read_page = rtl821x_read_page,
-+ .write_page = rtl821x_write_page,
-+ }, {
-+ PHY_ID_MATCH_EXACT(0x001cc915),
-+ .name = "RTL8211E Gigabit Ethernet",
-+ .config_init = &rtl8211e_config_init,
-+ .config_intr = &rtl8211e_config_intr,
-+ .handle_interrupt = rtl821x_handle_interrupt,
-+ .suspend = genphy_suspend,
-+ .resume = genphy_resume,
-+ .read_page = rtl821x_read_page,
-+ .write_page = rtl821x_write_page,
-+ }, {
-+ PHY_ID_MATCH_EXACT(0x001cc916),
-+ .name = "RTL8211F Gigabit Ethernet",
-+ .probe = rtl821x_probe,
-+ .config_init = &rtl8211f_config_init,
-+ .read_status = rtlgen_read_status,
-+ .config_intr = &rtl8211f_config_intr,
-+ .handle_interrupt = rtl8211f_handle_interrupt,
-+ .suspend = rtl821x_suspend,
-+ .resume = rtl821x_resume,
-+ .read_page = rtl821x_read_page,
-+ .write_page = rtl821x_write_page,
-+ .flags = PHY_ALWAYS_CALL_SUSPEND,
-+ .led_hw_is_supported = rtl8211f_led_hw_is_supported,
-+ .led_hw_control_get = rtl8211f_led_hw_control_get,
-+ .led_hw_control_set = rtl8211f_led_hw_control_set,
-+ }, {
-+ PHY_ID_MATCH_EXACT(RTL_8211FVD_PHYID),
-+ .name = "RTL8211F-VD Gigabit Ethernet",
-+ .probe = rtl821x_probe,
-+ .config_init = &rtl8211f_config_init,
-+ .read_status = rtlgen_read_status,
-+ .config_intr = &rtl8211f_config_intr,
-+ .handle_interrupt = rtl8211f_handle_interrupt,
-+ .suspend = rtl821x_suspend,
-+ .resume = rtl821x_resume,
-+ .read_page = rtl821x_read_page,
-+ .write_page = rtl821x_write_page,
-+ .flags = PHY_ALWAYS_CALL_SUSPEND,
-+ }, {
-+ .name = "Generic FE-GE Realtek PHY",
-+ .match_phy_device = rtlgen_match_phy_device,
-+ .read_status = rtlgen_read_status,
-+ .suspend = genphy_suspend,
-+ .resume = rtlgen_resume,
-+ .read_page = rtl821x_read_page,
-+ .write_page = rtl821x_write_page,
-+ .read_mmd = rtlgen_read_mmd,
-+ .write_mmd = rtlgen_write_mmd,
-+ }, {
-+ .name = "RTL8226 2.5Gbps PHY",
-+ .match_phy_device = rtl8226_match_phy_device,
-+ .get_features = rtl822x_get_features,
-+ .config_aneg = rtl822x_config_aneg,
-+ .read_status = rtl822x_read_status,
-+ .suspend = genphy_suspend,
-+ .resume = rtlgen_resume,
-+ .read_page = rtl821x_read_page,
-+ .write_page = rtl821x_write_page,
-+ }, {
-+ .match_phy_device = rtl8221b_match_phy_device,
-+ .name = "RTL8226B_RTL8221B 2.5Gbps PHY",
-+ .get_features = rtl822x_get_features,
-+ .config_aneg = rtl822x_config_aneg,
-+ .config_init = rtl822xb_config_init,
-+ .get_rate_matching = rtl822xb_get_rate_matching,
-+ .read_status = rtl822xb_read_status,
-+ .suspend = genphy_suspend,
-+ .resume = rtlgen_resume,
-+ .read_page = rtl821x_read_page,
-+ .write_page = rtl821x_write_page,
-+ }, {
-+ PHY_ID_MATCH_EXACT(0x001cc838),
-+ .name = "RTL8226-CG 2.5Gbps PHY",
-+ .get_features = rtl822x_get_features,
-+ .config_aneg = rtl822x_config_aneg,
-+ .read_status = rtl822x_read_status,
-+ .suspend = genphy_suspend,
-+ .resume = rtlgen_resume,
-+ .read_page = rtl821x_read_page,
-+ .write_page = rtl821x_write_page,
-+ }, {
-+ PHY_ID_MATCH_EXACT(0x001cc848),
-+ .name = "RTL8226B-CG_RTL8221B-CG 2.5Gbps PHY",
-+ .get_features = rtl822x_get_features,
-+ .config_aneg = rtl822x_config_aneg,
-+ .config_init = rtl822xb_config_init,
-+ .get_rate_matching = rtl822xb_get_rate_matching,
-+ .read_status = rtl822xb_read_status,
-+ .suspend = genphy_suspend,
-+ .resume = rtlgen_resume,
-+ .read_page = rtl821x_read_page,
-+ .write_page = rtl821x_write_page,
-+ }, {
-+ .match_phy_device = rtl8221b_vb_cg_c22_match_phy_device,
-+ .name = "RTL8221B-VB-CG 2.5Gbps PHY (C22)",
-+ .get_features = rtl822x_get_features,
-+ .config_aneg = rtl822x_config_aneg,
-+ .config_init = rtl822xb_config_init,
-+ .get_rate_matching = rtl822xb_get_rate_matching,
-+ .read_status = rtl822xb_read_status,
-+ .suspend = genphy_suspend,
-+ .resume = rtlgen_resume,
-+ .read_page = rtl821x_read_page,
-+ .write_page = rtl821x_write_page,
-+ }, {
-+ .match_phy_device = rtl8221b_vb_cg_c45_match_phy_device,
-+ .name = "RTL8221B-VB-CG 2.5Gbps PHY (C45)",
-+ .config_init = rtl822xb_config_init,
-+ .get_rate_matching = rtl822xb_get_rate_matching,
-+ .get_features = rtl822x_c45_get_features,
-+ .config_aneg = rtl822x_c45_config_aneg,
-+ .read_status = rtl822xb_c45_read_status,
-+ .suspend = genphy_c45_pma_suspend,
-+ .resume = rtlgen_c45_resume,
-+ }, {
-+ .match_phy_device = rtl8221b_vn_cg_c22_match_phy_device,
-+ .name = "RTL8221B-VM-CG 2.5Gbps PHY (C22)",
-+ .get_features = rtl822x_get_features,
-+ .config_aneg = rtl822x_config_aneg,
-+ .config_init = rtl822xb_config_init,
-+ .get_rate_matching = rtl822xb_get_rate_matching,
-+ .read_status = rtl822xb_read_status,
-+ .suspend = genphy_suspend,
-+ .resume = rtlgen_resume,
-+ .read_page = rtl821x_read_page,
-+ .write_page = rtl821x_write_page,
-+ }, {
-+ .match_phy_device = rtl8221b_vn_cg_c45_match_phy_device,
-+ .name = "RTL8221B-VN-CG 2.5Gbps PHY (C45)",
-+ .config_init = rtl822xb_config_init,
-+ .get_rate_matching = rtl822xb_get_rate_matching,
-+ .get_features = rtl822x_c45_get_features,
-+ .config_aneg = rtl822x_c45_config_aneg,
-+ .read_status = rtl822xb_c45_read_status,
-+ .suspend = genphy_c45_pma_suspend,
-+ .resume = rtlgen_c45_resume,
-+ }, {
-+ .match_phy_device = rtl8251b_c45_match_phy_device,
-+ .name = "RTL8251B 5Gbps PHY",
-+ .get_features = rtl822x_get_features,
-+ .config_aneg = rtl822x_config_aneg,
-+ .read_status = rtl822x_read_status,
-+ .suspend = genphy_suspend,
-+ .resume = rtlgen_resume,
-+ .read_page = rtl821x_read_page,
-+ .write_page = rtl821x_write_page,
-+ }, {
-+ .match_phy_device = rtl_internal_nbaset_match_phy_device,
-+ .name = "Realtek Internal NBASE-T PHY",
-+ .flags = PHY_IS_INTERNAL,
-+ .get_features = rtl822x_get_features,
-+ .config_aneg = rtl822x_config_aneg,
-+ .read_status = rtl822x_read_status,
-+ .suspend = genphy_suspend,
-+ .resume = rtlgen_resume,
-+ .read_page = rtl821x_read_page,
-+ .write_page = rtl821x_write_page,
-+ .read_mmd = rtl822x_read_mmd,
-+ .write_mmd = rtl822x_write_mmd,
-+ }, {
-+ PHY_ID_MATCH_EXACT(0x001ccad0),
-+ .name = "RTL8224 2.5Gbps PHY",
-+ .get_features = rtl822x_c45_get_features,
-+ .config_aneg = rtl822x_c45_config_aneg,
-+ .read_status = rtl822x_c45_read_status,
-+ .suspend = genphy_c45_pma_suspend,
-+ .resume = rtlgen_c45_resume,
-+ }, {
-+ PHY_ID_MATCH_EXACT(0x001cc961),
-+ .name = "RTL8366RB Gigabit Ethernet",
-+ .config_init = &rtl8366rb_config_init,
-+ /* These interrupts are handled by the irq controller
-+ * embedded inside the RTL8366RB, they get unmasked when the
-+ * irq is requested and ACKed by reading the status register,
-+ * which is done by the irqchip code.
-+ */
-+ .config_intr = genphy_no_config_intr,
-+ .handle_interrupt = genphy_handle_interrupt_no_ack,
-+ .suspend = genphy_suspend,
-+ .resume = genphy_resume,
-+ }, {
-+ PHY_ID_MATCH_EXACT(0x001ccb00),
-+ .name = "RTL9000AA_RTL9000AN Ethernet",
-+ .features = PHY_BASIC_T1_FEATURES,
-+ .config_init = rtl9000a_config_init,
-+ .config_aneg = rtl9000a_config_aneg,
-+ .read_status = rtl9000a_read_status,
-+ .config_intr = rtl9000a_config_intr,
-+ .handle_interrupt = rtl9000a_handle_interrupt,
-+ .suspend = genphy_suspend,
-+ .resume = genphy_resume,
-+ .read_page = rtl821x_read_page,
-+ .write_page = rtl821x_write_page,
-+ }, {
-+ PHY_ID_MATCH_EXACT(0x001cc942),
-+ .name = "RTL8365MB-VC Gigabit Ethernet",
-+ /* Interrupt handling analogous to RTL8366RB */
-+ .config_intr = genphy_no_config_intr,
-+ .handle_interrupt = genphy_handle_interrupt_no_ack,
-+ .suspend = genphy_suspend,
-+ .resume = genphy_resume,
-+ }, {
-+ PHY_ID_MATCH_EXACT(0x001cc960),
-+ .name = "RTL8366S Gigabit Ethernet",
-+ .suspend = genphy_suspend,
-+ .resume = genphy_resume,
-+ .read_mmd = genphy_read_mmd_unsupported,
-+ .write_mmd = genphy_write_mmd_unsupported,
-+ },
-+};
-+
-+module_phy_driver(realtek_drvs);
-+
-+static const struct mdio_device_id __maybe_unused realtek_tbl[] = {
-+ { PHY_ID_MATCH_VENDOR(0x001cc800) },
-+ { }
-+};
-+
-+MODULE_DEVICE_TABLE(mdio, realtek_tbl);
+++ /dev/null
-From 33700ca45b7d2e1655d4cad95e25671e8a94e2f0 Mon Sep 17 00:00:00 2001
-Date: Sat, 11 Jan 2025 21:51:24 +0100
-Subject: [PATCH] net: phy: realtek: add hwmon support for temp sensor on
- RTL822x
-
-This adds hwmon support for the temperature sensor on RTL822x.
-It's available on the standalone versions of the PHY's, and on
-the integrated PHY's in RTL8125B/RTL8125D/RTL8126.
-
----
- drivers/net/phy/realtek/Kconfig | 6 ++
- drivers/net/phy/realtek/Makefile | 1 +
- drivers/net/phy/realtek/realtek.h | 10 ++++
- drivers/net/phy/realtek/realtek_hwmon.c | 79 +++++++++++++++++++++++++
- drivers/net/phy/realtek/realtek_main.c | 12 ++++
- 5 files changed, 108 insertions(+)
- create mode 100644 drivers/net/phy/realtek/realtek.h
- create mode 100644 drivers/net/phy/realtek/realtek_hwmon.c
-
---- a/drivers/net/phy/realtek/Kconfig
-+++ b/drivers/net/phy/realtek/Kconfig
-@@ -3,3 +3,9 @@ config REALTEK_PHY
- tristate "Realtek PHYs"
- help
- Currently supports RTL821x/RTL822x and fast ethernet PHYs
-+
-+config REALTEK_PHY_HWMON
-+ def_bool REALTEK_PHY && HWMON
-+ depends on !(REALTEK_PHY=y && HWMON=m)
-+ help
-+ Optional hwmon support for the temperature sensor
---- a/drivers/net/phy/realtek/Makefile
-+++ b/drivers/net/phy/realtek/Makefile
-@@ -1,3 +1,4 @@
- # SPDX-License-Identifier: GPL-2.0
- realtek-y += realtek_main.o
-+realtek-$(CONFIG_REALTEK_PHY_HWMON) += realtek_hwmon.o
- obj-$(CONFIG_REALTEK_PHY) += realtek.o
---- /dev/null
-+++ b/drivers/net/phy/realtek/realtek.h
-@@ -0,0 +1,10 @@
-+/* SPDX-License-Identifier: GPL-2.0 */
-+
-+#ifndef REALTEK_H
-+#define REALTEK_H
-+
-+#include <linux/phy.h>
-+
-+int rtl822x_hwmon_init(struct phy_device *phydev);
-+
-+#endif /* REALTEK_H */
---- /dev/null
-+++ b/drivers/net/phy/realtek/realtek_hwmon.c
-@@ -0,0 +1,86 @@
-+// SPDX-License-Identifier: GPL-2.0+
-+/*
-+ * HWMON support for Realtek PHY's
-+ *
-+ */
-+
-+#include <linux/hwmon.h>
-+#include <linux/phy.h>
-+
-+#include "realtek.h"
-+
-+#define RTL822X_VND2_TSALRM 0xa662
-+#define RTL822X_VND2_TSRR 0xbd84
-+#define RTL822X_VND2_TSSR 0xb54c
-+
-+static umode_t rtl822x_hwmon_is_visible(const void *drvdata,
-+ enum hwmon_sensor_types type,
-+ u32 attr, int channel)
-+{
-+ return 0444;
-+}
-+
-+static int rtl822x_hwmon_get_temp(int raw)
-+{
-+ if (raw >= 512)
-+ raw -= 1024;
-+
-+ return 1000 * raw / 2;
-+}
-+
-+static int rtl822x_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
-+ u32 attr, int channel, long *val)
-+{
-+ struct phy_device *phydev = dev_get_drvdata(dev);
-+ int raw;
-+
-+ switch (attr) {
-+ case hwmon_temp_input:
-+ raw = phy_read_mmd(phydev, MDIO_MMD_VEND2, RTL822X_VND2_TSRR) & 0x3ff;
-+ *val = rtl822x_hwmon_get_temp(raw);
-+ break;
-+ case hwmon_temp_max:
-+ /* Chip reduces speed to 1G if threshold is exceeded */
-+ raw = phy_read_mmd(phydev, MDIO_MMD_VEND2, RTL822X_VND2_TSSR) >> 6;
-+ *val = rtl822x_hwmon_get_temp(raw);
-+ break;
-+ default:
-+ return -EINVAL;
-+ }
-+
-+ return 0;
-+}
-+
-+static const struct hwmon_ops rtl822x_hwmon_ops = {
-+ .is_visible = rtl822x_hwmon_is_visible,
-+ .read = rtl822x_hwmon_read,
-+};
-+
-+static const struct hwmon_channel_info * const rtl822x_hwmon_info[] = {
-+ HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | HWMON_T_MAX),
-+ NULL
-+};
-+
-+static const struct hwmon_chip_info rtl822x_hwmon_chip_info = {
-+ .ops = &rtl822x_hwmon_ops,
-+ .info = rtl822x_hwmon_info,
-+};
-+
-+int rtl822x_hwmon_init(struct phy_device *phydev)
-+{
-+ struct device *hwdev, *dev = &phydev->mdio.dev;
-+ const char *name;
-+
-+ /* Ensure over-temp alarm is reset. */
-+ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND2, RTL822X_VND2_TSALRM, 3);
-+
-+ name = devm_hwmon_sanitize_name(dev, dev_name(dev));
-+ if (IS_ERR(name))
-+ return PTR_ERR(name);
-+
-+ hwdev = devm_hwmon_device_register_with_info(dev, name, phydev,
-+ &rtl822x_hwmon_chip_info,
-+ NULL);
-+ return PTR_ERR_OR_ZERO(hwdev);
-+}
---- a/drivers/net/phy/realtek/realtek_main.c
-+++ b/drivers/net/phy/realtek/realtek_main.c
-@@ -14,6 +14,8 @@
- #include <linux/delay.h>
- #include <linux/clk.h>
-
-+#include "realtek.h"
-+
- #define RTL821x_PHYSR 0x11
- #define RTL821x_PHYSR_DUPLEX BIT(13)
- #define RTL821x_PHYSR_SPEED GENMASK(15, 14)
-@@ -820,6 +822,15 @@ static int rtl822x_write_mmd(struct phy_
- return ret;
- }
-
-+static int rtl822x_probe(struct phy_device *phydev)
-+{
-+ if (IS_ENABLED(CONFIG_REALTEK_PHY_HWMON) &&
-+ phydev->phy_id != RTL_GENERIC_PHYID)
-+ return rtl822x_hwmon_init(phydev);
-+
-+ return 0;
-+}
-+
- static int rtl822xb_config_init(struct phy_device *phydev)
- {
- bool has_2500, has_sgmii;
-@@ -1518,6 +1529,7 @@ static struct phy_driver realtek_drvs[]
- .match_phy_device = rtl_internal_nbaset_match_phy_device,
- .name = "Realtek Internal NBASE-T PHY",
- .flags = PHY_IS_INTERNAL,
-+ .probe = rtl822x_probe,
- .get_features = rtl822x_get_features,
- .config_aneg = rtl822x_config_aneg,
- .read_status = rtl822x_read_status,
+++ /dev/null
-From 64ff63aeefb03139ae27454bd4208244579ae88e Mon Sep 17 00:00:00 2001
-Date: Fri, 17 Jan 2025 23:24:21 +0100
-Subject: [PATCH] net: phy: realtek: HWMON support for standalone versions of
- RTL8221B and RTL8251
-
-HWMON support has been added for the RTL8221/8251 PHYs integrated together
-with the MAC inside the RTL8125/8126 chips. This patch extends temperature
-reading support for standalone variants of the mentioned PHYs.
-
-I don't know whether the earlier revisions of the RTL8226 also have a
-built-in temperature sensor, so they have been skipped for now.
-
-Tested on RTL8221B-VB-CG.
-
----
- drivers/net/phy/realtek/realtek_main.c | 5 +++++
- 1 file changed, 5 insertions(+)
-
---- a/drivers/net/phy/realtek/realtek_main.c
-+++ b/drivers/net/phy/realtek/realtek_main.c
-@@ -1474,6 +1474,7 @@ static struct phy_driver realtek_drvs[]
- }, {
- .match_phy_device = rtl8221b_vb_cg_c22_match_phy_device,
- .name = "RTL8221B-VB-CG 2.5Gbps PHY (C22)",
-+ .probe = rtl822x_probe,
- .get_features = rtl822x_get_features,
- .config_aneg = rtl822x_config_aneg,
- .config_init = rtl822xb_config_init,
-@@ -1486,6 +1487,7 @@ static struct phy_driver realtek_drvs[]
- }, {
- .match_phy_device = rtl8221b_vb_cg_c45_match_phy_device,
- .name = "RTL8221B-VB-CG 2.5Gbps PHY (C45)",
-+ .probe = rtl822x_probe,
- .config_init = rtl822xb_config_init,
- .get_rate_matching = rtl822xb_get_rate_matching,
- .get_features = rtl822x_c45_get_features,
-@@ -1496,6 +1498,7 @@ static struct phy_driver realtek_drvs[]
- }, {
- .match_phy_device = rtl8221b_vn_cg_c22_match_phy_device,
- .name = "RTL8221B-VM-CG 2.5Gbps PHY (C22)",
-+ .probe = rtl822x_probe,
- .get_features = rtl822x_get_features,
- .config_aneg = rtl822x_config_aneg,
- .config_init = rtl822xb_config_init,
-@@ -1508,6 +1511,7 @@ static struct phy_driver realtek_drvs[]
- }, {
- .match_phy_device = rtl8221b_vn_cg_c45_match_phy_device,
- .name = "RTL8221B-VN-CG 2.5Gbps PHY (C45)",
-+ .probe = rtl822x_probe,
- .config_init = rtl822xb_config_init,
- .get_rate_matching = rtl822xb_get_rate_matching,
- .get_features = rtl822x_c45_get_features,
-@@ -1518,6 +1522,7 @@ static struct phy_driver realtek_drvs[]
- }, {
- .match_phy_device = rtl8251b_c45_match_phy_device,
- .name = "RTL8251B 5Gbps PHY",
-+ .probe = rtl822x_probe,
- .get_features = rtl822x_get_features,
- .config_aneg = rtl822x_config_aneg,
- .read_status = rtl822x_read_status,
+++ /dev/null
-From 51773846fab24a353bed4ebb660997ced4bc32d7 Mon Sep 17 00:00:00 2001
-Date: Mon, 3 Feb 2025 21:33:39 +0100
-Subject: [PATCH] net: phy: realtek: make HWMON support a user-visible Kconfig
- symbol
-
-Make config symbol REALTEK_PHY_HWMON user-visible, so that users can
-remove support if not needed.
-
----
- drivers/net/phy/realtek/Kconfig | 8 ++++++--
- 1 file changed, 6 insertions(+), 2 deletions(-)
-
---- a/drivers/net/phy/realtek/Kconfig
-+++ b/drivers/net/phy/realtek/Kconfig
-@@ -4,8 +4,12 @@ config REALTEK_PHY
- help
- Currently supports RTL821x/RTL822x and fast ethernet PHYs
-
-+if REALTEK_PHY
-+
- config REALTEK_PHY_HWMON
-- def_bool REALTEK_PHY && HWMON
-- depends on !(REALTEK_PHY=y && HWMON=m)
-+ bool "HWMON support for Realtek PHYs"
-+ depends on HWMON && !(REALTEK_PHY=y && HWMON=m)
- help
- Optional hwmon support for the temperature sensor
-+
-+endif # REALTEK_PHY
+++ /dev/null
-From 0bea93fdbaf8675b7e8124bdcaf51497dcc8bcfa Mon Sep 17 00:00:00 2001
-Date: Mon, 3 Feb 2025 21:41:36 +0100
-Subject: [PATCH] net: phy: realtek: use string choices helpers
-
-Use string choices helpers to simplify the code.
-
----
- drivers/net/phy/realtek/realtek_main.c | 9 +++++----
- 1 file changed, 5 insertions(+), 4 deletions(-)
-
---- a/drivers/net/phy/realtek/realtek_main.c
-+++ b/drivers/net/phy/realtek/realtek_main.c
-@@ -13,6 +13,7 @@
- #include <linux/module.h>
- #include <linux/delay.h>
- #include <linux/clk.h>
-+#include <linux/string_choices.h>
-
- #include "realtek.h"
-
-@@ -422,11 +423,11 @@ static int rtl8211f_config_init(struct p
- } else if (ret) {
- dev_dbg(dev,
- "%s 2ns TX delay (and changing the value from pin-strapping RXD1 or the bootloader)\n",
-- val_txdly ? "Enabling" : "Disabling");
-+ str_enable_disable(val_txdly));
- } else {
- dev_dbg(dev,
- "2ns TX delay was already %s (by pin-strapping RXD1 or bootloader configuration)\n",
-- val_txdly ? "enabled" : "disabled");
-+ str_enabled_disabled(val_txdly));
- }
-
- ret = phy_modify_paged_changed(phydev, 0xd08, 0x15, RTL8211F_RX_DELAY,
-@@ -437,11 +438,11 @@ static int rtl8211f_config_init(struct p
- } else if (ret) {
- dev_dbg(dev,
- "%s 2ns RX delay (and changing the value from pin-strapping RXD0 or the bootloader)\n",
-- val_rxdly ? "Enabling" : "Disabling");
-+ str_enable_disable(val_rxdly));
- } else {
- dev_dbg(dev,
- "2ns RX delay was already %s (by pin-strapping RXD0 or bootloader configuration)\n",
-- val_rxdly ? "enabled" : "disabled");
-+ str_enabled_disabled(val_rxdly));
- }
-
- if (priv->has_phycr2) {
+++ /dev/null
-From da681ed73fb980286fc29de707b35d76bb33e123 Mon Sep 17 00:00:00 2001
-Date: Thu, 13 Feb 2025 20:18:17 +0100
-Subject: [PATCH] net: phy: realtek: improve mmd register access for internal
- PHY's
-
-r8169 provides the MDIO bus for the internal PHY's. It has been extended
-with c45 access functions for addressing MDIO_MMD_VEND2 registers.
-So we can switch from paged access to directly addressing the
-MDIO_MMD_VEND2 registers.
-
----
- drivers/net/phy/realtek/realtek_main.c | 79 +++++++++++---------------
- 1 file changed, 33 insertions(+), 46 deletions(-)
-
---- a/drivers/net/phy/realtek/realtek_main.c
-+++ b/drivers/net/phy/realtek/realtek_main.c
-@@ -735,29 +735,31 @@ static int rtlgen_read_status(struct phy
- return 0;
- }
-
-+static int rtlgen_read_vend2(struct phy_device *phydev, int regnum)
-+{
-+ return __mdiobus_c45_read(phydev->mdio.bus, 0, MDIO_MMD_VEND2, regnum);
-+}
-+
-+static int rtlgen_write_vend2(struct phy_device *phydev, int regnum, u16 val)
-+{
-+ return __mdiobus_c45_write(phydev->mdio.bus, 0, MDIO_MMD_VEND2, regnum,
-+ val);
-+}
-+
- static int rtlgen_read_mmd(struct phy_device *phydev, int devnum, u16 regnum)
- {
- int ret;
-
-- if (devnum == MDIO_MMD_VEND2) {
-- rtl821x_write_page(phydev, regnum >> 4);
-- ret = __phy_read(phydev, 0x10 + ((regnum & 0xf) >> 1));
-- rtl821x_write_page(phydev, 0);
-- } else if (devnum == MDIO_MMD_PCS && regnum == MDIO_PCS_EEE_ABLE) {
-- rtl821x_write_page(phydev, 0xa5c);
-- ret = __phy_read(phydev, 0x12);
-- rtl821x_write_page(phydev, 0);
-- } else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV) {
-- rtl821x_write_page(phydev, 0xa5d);
-- ret = __phy_read(phydev, 0x10);
-- rtl821x_write_page(phydev, 0);
-- } else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_LPABLE) {
-- rtl821x_write_page(phydev, 0xa5d);
-- ret = __phy_read(phydev, 0x11);
-- rtl821x_write_page(phydev, 0);
-- } else {
-+ if (devnum == MDIO_MMD_VEND2)
-+ ret = rtlgen_read_vend2(phydev, regnum);
-+ else if (devnum == MDIO_MMD_PCS && regnum == MDIO_PCS_EEE_ABLE)
-+ ret = rtlgen_read_vend2(phydev, 0xa5c4);
-+ else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV)
-+ ret = rtlgen_read_vend2(phydev, 0xa5d0);
-+ else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_LPABLE)
-+ ret = rtlgen_read_vend2(phydev, 0xa5d2);
-+ else
- ret = -EOPNOTSUPP;
-- }
-
- return ret;
- }
-@@ -767,17 +769,12 @@ static int rtlgen_write_mmd(struct phy_d
- {
- int ret;
-
-- if (devnum == MDIO_MMD_VEND2) {
-- rtl821x_write_page(phydev, regnum >> 4);
-- ret = __phy_write(phydev, 0x10 + ((regnum & 0xf) >> 1), val);
-- rtl821x_write_page(phydev, 0);
-- } else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV) {
-- rtl821x_write_page(phydev, 0xa5d);
-- ret = __phy_write(phydev, 0x10, val);
-- rtl821x_write_page(phydev, 0);
-- } else {
-+ if (devnum == MDIO_MMD_VEND2)
-+ ret = rtlgen_write_vend2(phydev, regnum, val);
-+ else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV)
-+ ret = rtlgen_write_vend2(phydev, regnum, 0xa5d0);
-+ else
- ret = -EOPNOTSUPP;
-- }
-
- return ret;
- }
-@@ -789,19 +786,12 @@ static int rtl822x_read_mmd(struct phy_d
- if (ret != -EOPNOTSUPP)
- return ret;
-
-- if (devnum == MDIO_MMD_PCS && regnum == MDIO_PCS_EEE_ABLE2) {
-- rtl821x_write_page(phydev, 0xa6e);
-- ret = __phy_read(phydev, 0x16);
-- rtl821x_write_page(phydev, 0);
-- } else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV2) {
-- rtl821x_write_page(phydev, 0xa6d);
-- ret = __phy_read(phydev, 0x12);
-- rtl821x_write_page(phydev, 0);
-- } else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_LPABLE2) {
-- rtl821x_write_page(phydev, 0xa6d);
-- ret = __phy_read(phydev, 0x10);
-- rtl821x_write_page(phydev, 0);
-- }
-+ if (devnum == MDIO_MMD_PCS && regnum == MDIO_PCS_EEE_ABLE2)
-+ ret = rtlgen_read_vend2(phydev, 0xa6ec);
-+ else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV2)
-+ ret = rtlgen_read_vend2(phydev, 0xa6d4);
-+ else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_LPABLE2)
-+ ret = rtlgen_read_vend2(phydev, 0xa6d0);
-
- return ret;
- }
-@@ -814,11 +804,8 @@ static int rtl822x_write_mmd(struct phy_
- if (ret != -EOPNOTSUPP)
- return ret;
-
-- if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV2) {
-- rtl821x_write_page(phydev, 0xa6d);
-- ret = __phy_write(phydev, 0x12, val);
-- rtl821x_write_page(phydev, 0);
-- }
-+ if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV2)
-+ ret = rtlgen_write_vend2(phydev, 0xa6d4, val);
-
- return ret;
- }
+++ /dev/null
-From 02d3b306ac2f0b174753d1c5b9e4e5fb8ec5057e Mon Sep 17 00:00:00 2001
-Date: Thu, 13 Feb 2025 20:19:14 +0100
-Subject: [PATCH] net: phy: realtek: switch from paged to MMD ops in rtl822x
- functions
-
-The MDIO bus provided by r8169 for the internal PHY's now supports
-c45 ops for the MDIO_MMD_VEND2 device. So we can switch to standard
-MMD ops here.
-
----
- drivers/net/phy/realtek/realtek_main.c | 11 +++++------
- 1 file changed, 5 insertions(+), 6 deletions(-)
-
---- a/drivers/net/phy/realtek/realtek_main.c
-+++ b/drivers/net/phy/realtek/realtek_main.c
-@@ -901,7 +901,7 @@ static int rtl822x_get_features(struct p
- {
- int val;
-
-- val = phy_read_paged(phydev, 0xa61, 0x13);
-+ val = phy_read_mmd(phydev, MDIO_MMD_VEND2, 0xa616);
- if (val < 0)
- return val;
-
-@@ -922,10 +922,9 @@ static int rtl822x_config_aneg(struct ph
- if (phydev->autoneg == AUTONEG_ENABLE) {
- u16 adv = linkmode_adv_to_mii_10gbt_adv_t(phydev->advertising);
-
-- ret = phy_modify_paged_changed(phydev, 0xa5d, 0x12,
-- MDIO_AN_10GBT_CTRL_ADV2_5G |
-- MDIO_AN_10GBT_CTRL_ADV5G,
-- adv);
-+ ret = phy_modify_mmd_changed(phydev, MDIO_MMD_VEND2, 0xa5d4,
-+ MDIO_AN_10GBT_CTRL_ADV2_5G |
-+ MDIO_AN_10GBT_CTRL_ADV5G, adv);
- if (ret < 0)
- return ret;
- }
-@@ -969,7 +968,7 @@ static int rtl822x_read_status(struct ph
- !phydev->autoneg_complete)
- return 0;
-
-- lpadv = phy_read_paged(phydev, 0xa5d, 0x13);
-+ lpadv = phy_read_mmd(phydev, MDIO_MMD_VEND2, 0xa5d6);
- if (lpadv < 0)
- return lpadv;
-
+++ /dev/null
-From 8af2136e77989a64fae0284bf76fd584e32edd3a Mon Sep 17 00:00:00 2001
-Date: Fri, 14 Feb 2025 21:31:14 +0100
-Subject: [PATCH] net: phy: realtek: add helper RTL822X_VND2_C22_REG
-
-C22 register space is mapped to 0xa400 in MMD VEND2 register space.
-Add a helper to access mapped C22 registers.
-
----
- drivers/net/phy/realtek/realtek_main.c | 9 ++++-----
- 1 file changed, 4 insertions(+), 5 deletions(-)
-
---- a/drivers/net/phy/realtek/realtek_main.c
-+++ b/drivers/net/phy/realtek/realtek_main.c
-@@ -79,9 +79,7 @@
- /* RTL822X_VND2_XXXXX registers are only accessible when phydev->is_c45
- * is set, they cannot be accessed by C45-over-C22.
- */
--#define RTL822X_VND2_GBCR 0xa412
--
--#define RTL822X_VND2_GANLPAR 0xa414
-+#define RTL822X_VND2_C22_REG(reg) (0xa400 + 2 * (reg))
-
- #define RTL8366RB_POWER_SAVE 0x15
- #define RTL8366RB_POWER_SAVE_ON BIT(12)
-@@ -1015,7 +1013,8 @@ static int rtl822x_c45_config_aneg(struc
- val = linkmode_adv_to_mii_ctrl1000_t(phydev->advertising);
-
- /* Vendor register as C45 has no standardized support for 1000BaseT */
-- ret = phy_modify_mmd_changed(phydev, MDIO_MMD_VEND2, RTL822X_VND2_GBCR,
-+ ret = phy_modify_mmd_changed(phydev, MDIO_MMD_VEND2,
-+ RTL822X_VND2_C22_REG(MII_CTRL1000),
- ADVERTISE_1000FULL, val);
- if (ret < 0)
- return ret;
-@@ -1032,7 +1031,7 @@ static int rtl822x_c45_read_status(struc
- /* Vendor register as C45 has no standardized support for 1000BaseT */
- if (phydev->autoneg == AUTONEG_ENABLE && genphy_c45_aneg_done(phydev)) {
- val = phy_read_mmd(phydev, MDIO_MMD_VEND2,
-- RTL822X_VND2_GANLPAR);
-+ RTL822X_VND2_C22_REG(MII_STAT1000));
- if (val < 0)
- return val;
- } else {
+++ /dev/null
-From fabcfd6d10999024a721ae1b965b57eb8a305ace Mon Sep 17 00:00:00 2001
-Date: Sat, 15 Feb 2025 14:29:15 +0100
-Subject: [PATCH] net: phy: realtek: add defines for shadowed c45 standard
- registers
-
-Realtek shadows standard c45 registers in VEND2 device register space.
-Add defines for these VEND2 registers, based on the names of the
-standard c45 registers.
-
----
- drivers/net/phy/realtek/realtek_main.c | 33 +++++++++++++++++---------
- 1 file changed, 22 insertions(+), 11 deletions(-)
-
---- a/drivers/net/phy/realtek/realtek_main.c
-+++ b/drivers/net/phy/realtek/realtek_main.c
-@@ -94,6 +94,16 @@
- #define RTL_VND2_PHYSR_MASTER BIT(11)
- #define RTL_VND2_PHYSR_SPEED_MASK (RTL_VND2_PHYSR_SPEEDL | RTL_VND2_PHYSR_SPEEDH)
-
-+#define RTL_MDIO_PCS_EEE_ABLE 0xa5c4
-+#define RTL_MDIO_AN_EEE_ADV 0xa5d0
-+#define RTL_MDIO_AN_EEE_LPABLE 0xa5d2
-+#define RTL_MDIO_AN_10GBT_CTRL 0xa5d4
-+#define RTL_MDIO_AN_10GBT_STAT 0xa5d6
-+#define RTL_MDIO_PMA_SPEED 0xa616
-+#define RTL_MDIO_AN_EEE_LPABLE2 0xa6d0
-+#define RTL_MDIO_AN_EEE_ADV2 0xa6d4
-+#define RTL_MDIO_PCS_EEE_ABLE2 0xa6ec
-+
- #define RTL_GENERIC_PHYID 0x001cc800
- #define RTL_8211FVD_PHYID 0x001cc878
- #define RTL_8221B 0x001cc840
-@@ -751,11 +761,11 @@ static int rtlgen_read_mmd(struct phy_de
- if (devnum == MDIO_MMD_VEND2)
- ret = rtlgen_read_vend2(phydev, regnum);
- else if (devnum == MDIO_MMD_PCS && regnum == MDIO_PCS_EEE_ABLE)
-- ret = rtlgen_read_vend2(phydev, 0xa5c4);
-+ ret = rtlgen_read_vend2(phydev, RTL_MDIO_PCS_EEE_ABLE);
- else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV)
-- ret = rtlgen_read_vend2(phydev, 0xa5d0);
-+ ret = rtlgen_read_vend2(phydev, RTL_MDIO_AN_EEE_ADV);
- else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_LPABLE)
-- ret = rtlgen_read_vend2(phydev, 0xa5d2);
-+ ret = rtlgen_read_vend2(phydev, RTL_MDIO_AN_EEE_LPABLE);
- else
- ret = -EOPNOTSUPP;
-
-@@ -770,7 +780,7 @@ static int rtlgen_write_mmd(struct phy_d
- if (devnum == MDIO_MMD_VEND2)
- ret = rtlgen_write_vend2(phydev, regnum, val);
- else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV)
-- ret = rtlgen_write_vend2(phydev, regnum, 0xa5d0);
-+ ret = rtlgen_write_vend2(phydev, regnum, RTL_MDIO_AN_EEE_ADV);
- else
- ret = -EOPNOTSUPP;
-
-@@ -785,11 +795,11 @@ static int rtl822x_read_mmd(struct phy_d
- return ret;
-
- if (devnum == MDIO_MMD_PCS && regnum == MDIO_PCS_EEE_ABLE2)
-- ret = rtlgen_read_vend2(phydev, 0xa6ec);
-+ ret = rtlgen_read_vend2(phydev, RTL_MDIO_PCS_EEE_ABLE2);
- else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV2)
-- ret = rtlgen_read_vend2(phydev, 0xa6d4);
-+ ret = rtlgen_read_vend2(phydev, RTL_MDIO_AN_EEE_ADV2);
- else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_LPABLE2)
-- ret = rtlgen_read_vend2(phydev, 0xa6d0);
-+ ret = rtlgen_read_vend2(phydev, RTL_MDIO_AN_EEE_LPABLE2);
-
- return ret;
- }
-@@ -803,7 +813,7 @@ static int rtl822x_write_mmd(struct phy_
- return ret;
-
- if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV2)
-- ret = rtlgen_write_vend2(phydev, 0xa6d4, val);
-+ ret = rtlgen_write_vend2(phydev, RTL_MDIO_AN_EEE_ADV2, val);
-
- return ret;
- }
-@@ -899,7 +909,7 @@ static int rtl822x_get_features(struct p
- {
- int val;
-
-- val = phy_read_mmd(phydev, MDIO_MMD_VEND2, 0xa616);
-+ val = phy_read_mmd(phydev, MDIO_MMD_VEND2, RTL_MDIO_PMA_SPEED);
- if (val < 0)
- return val;
-
-@@ -920,7 +930,8 @@ static int rtl822x_config_aneg(struct ph
- if (phydev->autoneg == AUTONEG_ENABLE) {
- u16 adv = linkmode_adv_to_mii_10gbt_adv_t(phydev->advertising);
-
-- ret = phy_modify_mmd_changed(phydev, MDIO_MMD_VEND2, 0xa5d4,
-+ ret = phy_modify_mmd_changed(phydev, MDIO_MMD_VEND2,
-+ RTL_MDIO_AN_10GBT_CTRL,
- MDIO_AN_10GBT_CTRL_ADV2_5G |
- MDIO_AN_10GBT_CTRL_ADV5G, adv);
- if (ret < 0)
-@@ -966,7 +977,7 @@ static int rtl822x_read_status(struct ph
- !phydev->autoneg_complete)
- return 0;
-
-- lpadv = phy_read_mmd(phydev, MDIO_MMD_VEND2, 0xa5d6);
-+ lpadv = phy_read_mmd(phydev, MDIO_MMD_VEND2, RTL_MDIO_AN_10GBT_STAT);
- if (lpadv < 0)
- return lpadv;
-
+++ /dev/null
-From bfc17c1658353f22843c7c13e27c2d31950f1887 Mon Sep 17 00:00:00 2001
-Date: Sun, 16 Mar 2025 12:39:54 +0000
-Subject: [PATCH] net: phy: realtek: disable PHY-mode EEE
-
-Realtek RTL8211F has a "PHY-mode" EEE support which interferes with an
-IEEE 802.3 compliant implementation. This mode defaults to enabled, and
-results in the MAC receive path not seeing the link transition to LPI
-state.
-
-Fix this by disabling PHY-mode EEE.
-
----
- drivers/net/phy/realtek/realtek_main.c | 11 +++++++++--
- 1 file changed, 9 insertions(+), 2 deletions(-)
-
---- a/drivers/net/phy/realtek/realtek_main.c
-+++ b/drivers/net/phy/realtek/realtek_main.c
-@@ -33,6 +33,9 @@
-
- #define RTL8211F_PHYCR1 0x18
- #define RTL8211F_PHYCR2 0x19
-+#define RTL8211F_CLKOUT_EN BIT(0)
-+#define RTL8211F_PHYCR2_PHY_EEE_ENABLE BIT(5)
-+
- #define RTL8211F_INSR 0x1d
-
- #define RTL8211F_LEDCR 0x10
-@@ -55,8 +58,6 @@
- #define RTL8211E_TX_DELAY BIT(12)
- #define RTL8211E_RX_DELAY BIT(11)
-
--#define RTL8211F_CLKOUT_EN BIT(0)
--
- #define RTL8201F_ISR 0x1e
- #define RTL8201F_ISR_ANERR BIT(15)
- #define RTL8201F_ISR_DUPLEX BIT(13)
-@@ -453,6 +454,12 @@ static int rtl8211f_config_init(struct p
- str_enabled_disabled(val_rxdly));
- }
-
-+ /* Disable PHY-mode EEE so LPI is passed to the MAC */
-+ ret = phy_modify_paged(phydev, 0xa43, RTL8211F_PHYCR2,
-+ RTL8211F_PHYCR2_PHY_EEE_ENABLE, 0);
-+ if (ret)
-+ return ret;
-+
- if (priv->has_phycr2) {
- ret = phy_modify_paged(phydev, 0xa43, RTL8211F_PHYCR2,
- RTL8211F_CLKOUT_EN, priv->phycr2);
+++ /dev/null
-From 7840e4d6f48a75413470935ebdc4bab4fc0c035e Mon Sep 17 00:00:00 2001
-Date: Tue, 29 Apr 2025 13:33:37 +0200
-Subject: [PATCH] net: phy: realtek: Add support for WOL magic packet on
- RTL8211F
-
-The RTL8211F supports multiple WOL modes. This patch adds support for
-magic packets.
-
-The PHY notifies the system via the INTB/PMEB pin when a WOL event
-occurs.
-
----
- drivers/net/phy/realtek/realtek_main.c | 69 ++++++++++++++++++++++++++
- 1 file changed, 69 insertions(+)
-
---- a/drivers/net/phy/realtek/realtek_main.c
-+++ b/drivers/net/phy/realtek/realtek_main.c
-@@ -10,6 +10,7 @@
- #include <linux/bitops.h>
- #include <linux/of.h>
- #include <linux/phy.h>
-+#include <linux/netdevice.h>
- #include <linux/module.h>
- #include <linux/delay.h>
- #include <linux/clk.h>
-@@ -38,6 +39,24 @@
-
- #define RTL8211F_INSR 0x1d
-
-+/* RTL8211F WOL interrupt configuration */
-+#define RTL8211F_INTBCR_PAGE 0xd40
-+#define RTL8211F_INTBCR 0x16
-+#define RTL8211F_INTBCR_INTB_PMEB BIT(5)
-+
-+/* RTL8211F WOL settings */
-+#define RTL8211F_WOL_SETTINGS_PAGE 0xd8a
-+#define RTL8211F_WOL_SETTINGS_EVENTS 16
-+#define RTL8211F_WOL_EVENT_MAGIC BIT(12)
-+#define RTL8211F_WOL_SETTINGS_STATUS 17
-+#define RTL8211F_WOL_STATUS_RESET (BIT(15) | 0x1fff)
-+
-+/* RTL8211F Unique phyiscal and multicast address (WOL) */
-+#define RTL8211F_PHYSICAL_ADDR_PAGE 0xd8c
-+#define RTL8211F_PHYSICAL_ADDR_WORD0 16
-+#define RTL8211F_PHYSICAL_ADDR_WORD1 17
-+#define RTL8211F_PHYSICAL_ADDR_WORD2 18
-+
- #define RTL8211F_LEDCR 0x10
- #define RTL8211F_LEDCR_MODE BIT(15)
- #define RTL8211F_LEDCR_ACT_TXRX BIT(4)
-@@ -123,6 +142,7 @@ struct rtl821x_priv {
- u16 phycr2;
- bool has_phycr2;
- struct clk *clk;
-+ u32 saved_wolopts;
- };
-
- static int rtl821x_read_page(struct phy_device *phydev)
-@@ -354,6 +374,53 @@ static irqreturn_t rtl8211f_handle_inter
- return IRQ_HANDLED;
- }
-
-+static void rtl8211f_get_wol(struct phy_device *dev, struct ethtool_wolinfo *wol)
-+{
-+ wol->supported = WAKE_MAGIC;
-+ if (phy_read_paged(dev, RTL8211F_WOL_SETTINGS_PAGE, RTL8211F_WOL_SETTINGS_EVENTS)
-+ & RTL8211F_WOL_EVENT_MAGIC)
-+ wol->wolopts = WAKE_MAGIC;
-+}
-+
-+static int rtl8211f_set_wol(struct phy_device *dev, struct ethtool_wolinfo *wol)
-+{
-+ const u8 *mac_addr = dev->attached_dev->dev_addr;
-+ int oldpage;
-+
-+ oldpage = phy_save_page(dev);
-+ if (oldpage < 0)
-+ goto err;
-+
-+ if (wol->wolopts & WAKE_MAGIC) {
-+ /* Store the device address for the magic packet */
-+ rtl821x_write_page(dev, RTL8211F_PHYSICAL_ADDR_PAGE);
-+ __phy_write(dev, RTL8211F_PHYSICAL_ADDR_WORD0, mac_addr[1] << 8 | (mac_addr[0]));
-+ __phy_write(dev, RTL8211F_PHYSICAL_ADDR_WORD1, mac_addr[3] << 8 | (mac_addr[2]));
-+ __phy_write(dev, RTL8211F_PHYSICAL_ADDR_WORD2, mac_addr[5] << 8 | (mac_addr[4]));
-+
-+ /* Enable magic packet matching and reset WOL status */
-+ rtl821x_write_page(dev, RTL8211F_WOL_SETTINGS_PAGE);
-+ __phy_write(dev, RTL8211F_WOL_SETTINGS_EVENTS, RTL8211F_WOL_EVENT_MAGIC);
-+ __phy_write(dev, RTL8211F_WOL_SETTINGS_STATUS, RTL8211F_WOL_STATUS_RESET);
-+
-+ /* Enable the WOL interrupt */
-+ rtl821x_write_page(dev, RTL8211F_INTBCR_PAGE);
-+ __phy_set_bits(dev, RTL8211F_INTBCR, RTL8211F_INTBCR_INTB_PMEB);
-+ } else {
-+ /* Disable the WOL interrupt */
-+ rtl821x_write_page(dev, RTL8211F_INTBCR_PAGE);
-+ __phy_clear_bits(dev, RTL8211F_INTBCR, RTL8211F_INTBCR_INTB_PMEB);
-+
-+ /* Disable magic packet matching and reset WOL status */
-+ rtl821x_write_page(dev, RTL8211F_WOL_SETTINGS_PAGE);
-+ __phy_write(dev, RTL8211F_WOL_SETTINGS_EVENTS, 0);
-+ __phy_write(dev, RTL8211F_WOL_SETTINGS_STATUS, RTL8211F_WOL_STATUS_RESET);
-+ }
-+
-+err:
-+ return phy_restore_page(dev, oldpage, 0);
-+}
-+
- static int rtl8211_config_aneg(struct phy_device *phydev)
- {
- int ret;
-@@ -1400,6 +1467,8 @@ static struct phy_driver realtek_drvs[]
- .read_status = rtlgen_read_status,
- .config_intr = &rtl8211f_config_intr,
- .handle_interrupt = rtl8211f_handle_interrupt,
-+ .set_wol = rtl8211f_set_wol,
-+ .get_wol = rtl8211f_get_wol,
- .suspend = rtl821x_suspend,
- .resume = rtl821x_resume,
- .read_page = rtl821x_read_page,
+++ /dev/null
-From f3b265358b911fe9e495619bdfa7797749474f95 Mon Sep 17 00:00:00 2001
-Date: Sun, 4 May 2025 19:29:11 +0200
-Subject: [PATCH] net: phy: realtek: remove unsed RTL821x_PHYSR* macros
-
-These macros have there since the first revision but were never used, so
-let's just remove them.
-
----
- drivers/net/phy/realtek/realtek_main.c | 4 ----
- 1 file changed, 4 deletions(-)
-
---- a/drivers/net/phy/realtek/realtek_main.c
-+++ b/drivers/net/phy/realtek/realtek_main.c
-@@ -18,10 +18,6 @@
-
- #include "realtek.h"
-
--#define RTL821x_PHYSR 0x11
--#define RTL821x_PHYSR_DUPLEX BIT(13)
--#define RTL821x_PHYSR_SPEED GENMASK(15, 14)
--
- #define RTL821x_INER 0x12
- #define RTL8211B_INER_INIT 0x6400
- #define RTL8211E_INER_LINK_STATUS BIT(10)
+++ /dev/null
-From 7c6fa3ffd2650347b1d37f028e232e53d617c1af Mon Sep 17 00:00:00 2001
-Date: Sun, 4 May 2025 19:29:12 +0200
-Subject: [PATCH] net: phy: realtek: Clean up RTL821x ExtPage access
-
-Factor out RTL8211E extension page access code to
-rtl821x_modify_ext_page() and clean up rtl8211e_config_init()
-
----
- drivers/net/phy/realtek/realtek_main.c | 38 ++++++++++++++++----------
- 1 file changed, 23 insertions(+), 15 deletions(-)
-
---- a/drivers/net/phy/realtek/realtek_main.c
-+++ b/drivers/net/phy/realtek/realtek_main.c
-@@ -26,7 +26,9 @@
- #define RTL821x_INSR 0x13
-
- #define RTL821x_EXT_PAGE_SELECT 0x1e
-+
- #define RTL821x_PAGE_SELECT 0x1f
-+#define RTL821x_SET_EXT_PAGE 0x07
-
- #define RTL8211F_PHYCR1 0x18
- #define RTL8211F_PHYCR2 0x19
-@@ -69,9 +71,12 @@
- #define RTL8211F_ALDPS_ENABLE BIT(2)
- #define RTL8211F_ALDPS_XTAL_OFF BIT(12)
-
-+#define RTL8211E_RGMII_EXT_PAGE 0xa4
-+#define RTL8211E_RGMII_DELAY 0x1c
- #define RTL8211E_CTRL_DELAY BIT(13)
- #define RTL8211E_TX_DELAY BIT(12)
- #define RTL8211E_RX_DELAY BIT(11)
-+#define RTL8211E_DELAY_MASK GENMASK(13, 11)
-
- #define RTL8201F_ISR 0x1e
- #define RTL8201F_ISR_ANERR BIT(15)
-@@ -151,6 +156,21 @@ static int rtl821x_write_page(struct phy
- return __phy_write(phydev, RTL821x_PAGE_SELECT, page);
- }
-
-+static int rtl821x_modify_ext_page(struct phy_device *phydev, u16 ext_page,
-+ u32 regnum, u16 mask, u16 set)
-+{
-+ int oldpage, ret = 0;
-+
-+ oldpage = phy_select_page(phydev, RTL821x_SET_EXT_PAGE);
-+ if (oldpage >= 0) {
-+ ret = __phy_write(phydev, RTL821x_EXT_PAGE_SELECT, ext_page);
-+ if (ret == 0)
-+ ret = __phy_modify(phydev, regnum, mask, set);
-+ }
-+
-+ return phy_restore_page(phydev, oldpage, ret);
-+}
-+
- static int rtl821x_probe(struct phy_device *phydev)
- {
- struct device *dev = &phydev->mdio.dev;
-@@ -670,7 +690,6 @@ static int rtl8211f_led_hw_control_set(s
-
- static int rtl8211e_config_init(struct phy_device *phydev)
- {
-- int ret = 0, oldpage;
- u16 val;
-
- /* enable TX/RX delay for rgmii-* modes, and disable them for rgmii. */
-@@ -700,20 +719,9 @@ static int rtl8211e_config_init(struct p
- * 12 = RX Delay, 11 = TX Delay
- * 10:0 = Test && debug settings reserved by realtek
- */
-- oldpage = phy_select_page(phydev, 0x7);
-- if (oldpage < 0)
-- goto err_restore_page;
--
-- ret = __phy_write(phydev, RTL821x_EXT_PAGE_SELECT, 0xa4);
-- if (ret)
-- goto err_restore_page;
--
-- ret = __phy_modify(phydev, 0x1c, RTL8211E_CTRL_DELAY
-- | RTL8211E_TX_DELAY | RTL8211E_RX_DELAY,
-- val);
--
--err_restore_page:
-- return phy_restore_page(phydev, oldpage, ret);
-+ return rtl821x_modify_ext_page(phydev, RTL8211E_RGMII_EXT_PAGE,
-+ RTL8211E_RGMII_DELAY,
-+ RTL8211E_DELAY_MASK, val);
- }
-
- static int rtl8211b_suspend(struct phy_device *phydev)
+++ /dev/null
-From 12d40df259e38851a0d973535e6023b33e2ea4f9 Mon Sep 17 00:00:00 2001
-Date: Sun, 4 May 2025 19:29:13 +0200
-Subject: [PATCH] net: phy: realtek: add RTL8211F register defines
-
-Add some more defines for RTL8211F page and register numbers.
-
----
- drivers/net/phy/realtek/realtek_main.c | 34 ++++++++++++++++++--------
- 1 file changed, 24 insertions(+), 10 deletions(-)
-
---- a/drivers/net/phy/realtek/realtek_main.c
-+++ b/drivers/net/phy/realtek/realtek_main.c
-@@ -30,11 +30,14 @@
- #define RTL821x_PAGE_SELECT 0x1f
- #define RTL821x_SET_EXT_PAGE 0x07
-
-+/* RTL8211F PHY configuration */
-+#define RTL8211F_PHYCR_PAGE 0xa43
- #define RTL8211F_PHYCR1 0x18
- #define RTL8211F_PHYCR2 0x19
- #define RTL8211F_CLKOUT_EN BIT(0)
- #define RTL8211F_PHYCR2_PHY_EEE_ENABLE BIT(5)
-
-+#define RTL8211F_INSR_PAGE 0xa43
- #define RTL8211F_INSR 0x1d
-
- /* RTL8211F WOL interrupt configuration */
-@@ -55,6 +58,8 @@
- #define RTL8211F_PHYSICAL_ADDR_WORD1 17
- #define RTL8211F_PHYSICAL_ADDR_WORD2 18
-
-+/* RTL8211F LED configuration */
-+#define RTL8211F_LEDCR_PAGE 0xd04
- #define RTL8211F_LEDCR 0x10
- #define RTL8211F_LEDCR_MODE BIT(15)
- #define RTL8211F_LEDCR_ACT_TXRX BIT(4)
-@@ -64,7 +69,13 @@
- #define RTL8211F_LEDCR_MASK GENMASK(4, 0)
- #define RTL8211F_LEDCR_SHIFT 5
-
-+/* RTL8211F RGMII configuration */
-+#define RTL8211F_RGMII_PAGE 0xd08
-+
-+#define RTL8211F_TXCR 0x11
- #define RTL8211F_TX_DELAY BIT(8)
-+
-+#define RTL8211F_RXCR 0x15
- #define RTL8211F_RX_DELAY BIT(3)
-
- #define RTL8211F_ALDPS_PLL_OFF BIT(1)
-@@ -187,7 +198,7 @@ static int rtl821x_probe(struct phy_devi
- return dev_err_probe(dev, PTR_ERR(priv->clk),
- "failed to get phy clock\n");
-
-- ret = phy_read_paged(phydev, 0xa43, RTL8211F_PHYCR1);
-+ ret = phy_read_paged(phydev, RTL8211F_PHYCR_PAGE, RTL8211F_PHYCR1);
- if (ret < 0)
- return ret;
-
-@@ -197,7 +208,7 @@ static int rtl821x_probe(struct phy_devi
-
- priv->has_phycr2 = !(phy_id == RTL_8211FVD_PHYID);
- if (priv->has_phycr2) {
-- ret = phy_read_paged(phydev, 0xa43, RTL8211F_PHYCR2);
-+ ret = phy_read_paged(phydev, RTL8211F_PHYCR_PAGE, RTL8211F_PHYCR2);
- if (ret < 0)
- return ret;
-
-@@ -233,7 +244,7 @@ static int rtl8211f_ack_interrupt(struct
- {
- int err;
-
-- err = phy_read_paged(phydev, 0xa43, RTL8211F_INSR);
-+ err = phy_read_paged(phydev, RTL8211F_INSR_PAGE, RTL8211F_INSR);
-
- return (err < 0) ? err : 0;
- }
-@@ -376,7 +387,7 @@ static irqreturn_t rtl8211f_handle_inter
- {
- int irq_status;
-
-- irq_status = phy_read_paged(phydev, 0xa43, RTL8211F_INSR);
-+ irq_status = phy_read_paged(phydev, RTL8211F_INSR_PAGE, RTL8211F_INSR);
- if (irq_status < 0) {
- phy_error(phydev);
- return IRQ_NONE;
-@@ -473,7 +484,7 @@ static int rtl8211f_config_init(struct p
- u16 val_txdly, val_rxdly;
- int ret;
-
-- ret = phy_modify_paged_changed(phydev, 0xa43, RTL8211F_PHYCR1,
-+ ret = phy_modify_paged_changed(phydev, RTL8211F_PHYCR_PAGE, RTL8211F_PHYCR1,
- RTL8211F_ALDPS_PLL_OFF | RTL8211F_ALDPS_ENABLE | RTL8211F_ALDPS_XTAL_OFF,
- priv->phycr1);
- if (ret < 0) {
-@@ -507,7 +518,8 @@ static int rtl8211f_config_init(struct p
- return 0;
- }
-
-- ret = phy_modify_paged_changed(phydev, 0xd08, 0x11, RTL8211F_TX_DELAY,
-+ ret = phy_modify_paged_changed(phydev, RTL8211F_RGMII_PAGE,
-+ RTL8211F_TXCR, RTL8211F_TX_DELAY,
- val_txdly);
- if (ret < 0) {
- dev_err(dev, "Failed to update the TX delay register\n");
-@@ -522,7 +534,8 @@ static int rtl8211f_config_init(struct p
- str_enabled_disabled(val_txdly));
- }
-
-- ret = phy_modify_paged_changed(phydev, 0xd08, 0x15, RTL8211F_RX_DELAY,
-+ ret = phy_modify_paged_changed(phydev, RTL8211F_RGMII_PAGE,
-+ RTL8211F_RXCR, RTL8211F_RX_DELAY,
- val_rxdly);
- if (ret < 0) {
- dev_err(dev, "Failed to update the RX delay register\n");
-@@ -538,14 +551,15 @@ static int rtl8211f_config_init(struct p
- }
-
- /* Disable PHY-mode EEE so LPI is passed to the MAC */
-- ret = phy_modify_paged(phydev, 0xa43, RTL8211F_PHYCR2,
-+ ret = phy_modify_paged(phydev, RTL8211F_PHYCR_PAGE, RTL8211F_PHYCR2,
- RTL8211F_PHYCR2_PHY_EEE_ENABLE, 0);
- if (ret)
- return ret;
-
- if (priv->has_phycr2) {
-- ret = phy_modify_paged(phydev, 0xa43, RTL8211F_PHYCR2,
-- RTL8211F_CLKOUT_EN, priv->phycr2);
-+ ret = phy_modify_paged(phydev, RTL8211F_PHYCR_PAGE,
-+ RTL8211F_PHYCR2, RTL8211F_CLKOUT_EN,
-+ priv->phycr2);
- if (ret < 0) {
- dev_err(dev, "clkout configuration failed: %pe\n",
- ERR_PTR(ret));
+++ /dev/null
-From 8c4d0172657c1f2d86b9c19172150abcd0e35c39 Mon Sep 17 00:00:00 2001
-Date: Sun, 4 May 2025 19:29:14 +0200
-Subject: [PATCH] net: phy: realtek: Group RTL82* macro definitions
-
-Group macro definitions by PHY in lexicographic order. Within each PHY
-block, definitions are order by page number and then register number.
-
----
- drivers/net/phy/realtek/realtek_main.c | 72 +++++++++++++-------------
- 1 file changed, 37 insertions(+), 35 deletions(-)
-
---- a/drivers/net/phy/realtek/realtek_main.c
-+++ b/drivers/net/phy/realtek/realtek_main.c
-@@ -18,6 +18,16 @@
-
- #include "realtek.h"
-
-+#define RTL8201F_IER 0x13
-+
-+#define RTL8201F_ISR 0x1e
-+#define RTL8201F_ISR_ANERR BIT(15)
-+#define RTL8201F_ISR_DUPLEX BIT(13)
-+#define RTL8201F_ISR_LINK BIT(11)
-+#define RTL8201F_ISR_MASK (RTL8201F_ISR_ANERR | \
-+ RTL8201F_ISR_DUPLEX | \
-+ RTL8201F_ISR_LINK)
-+
- #define RTL821x_INER 0x12
- #define RTL8211B_INER_INIT 0x6400
- #define RTL8211E_INER_LINK_STATUS BIT(10)
-@@ -30,9 +40,21 @@
- #define RTL821x_PAGE_SELECT 0x1f
- #define RTL821x_SET_EXT_PAGE 0x07
-
-+/* RTL8211E extension page 164/0xa4 */
-+#define RTL8211E_RGMII_EXT_PAGE 0xa4
-+#define RTL8211E_RGMII_DELAY 0x1c
-+#define RTL8211E_CTRL_DELAY BIT(13)
-+#define RTL8211E_TX_DELAY BIT(12)
-+#define RTL8211E_RX_DELAY BIT(11)
-+#define RTL8211E_DELAY_MASK GENMASK(13, 11)
-+
- /* RTL8211F PHY configuration */
- #define RTL8211F_PHYCR_PAGE 0xa43
- #define RTL8211F_PHYCR1 0x18
-+#define RTL8211F_ALDPS_PLL_OFF BIT(1)
-+#define RTL8211F_ALDPS_ENABLE BIT(2)
-+#define RTL8211F_ALDPS_XTAL_OFF BIT(12)
-+
- #define RTL8211F_PHYCR2 0x19
- #define RTL8211F_CLKOUT_EN BIT(0)
- #define RTL8211F_PHYCR2_PHY_EEE_ENABLE BIT(5)
-@@ -40,24 +62,6 @@
- #define RTL8211F_INSR_PAGE 0xa43
- #define RTL8211F_INSR 0x1d
-
--/* RTL8211F WOL interrupt configuration */
--#define RTL8211F_INTBCR_PAGE 0xd40
--#define RTL8211F_INTBCR 0x16
--#define RTL8211F_INTBCR_INTB_PMEB BIT(5)
--
--/* RTL8211F WOL settings */
--#define RTL8211F_WOL_SETTINGS_PAGE 0xd8a
--#define RTL8211F_WOL_SETTINGS_EVENTS 16
--#define RTL8211F_WOL_EVENT_MAGIC BIT(12)
--#define RTL8211F_WOL_SETTINGS_STATUS 17
--#define RTL8211F_WOL_STATUS_RESET (BIT(15) | 0x1fff)
--
--/* RTL8211F Unique phyiscal and multicast address (WOL) */
--#define RTL8211F_PHYSICAL_ADDR_PAGE 0xd8c
--#define RTL8211F_PHYSICAL_ADDR_WORD0 16
--#define RTL8211F_PHYSICAL_ADDR_WORD1 17
--#define RTL8211F_PHYSICAL_ADDR_WORD2 18
--
- /* RTL8211F LED configuration */
- #define RTL8211F_LEDCR_PAGE 0xd04
- #define RTL8211F_LEDCR 0x10
-@@ -78,25 +82,23 @@
- #define RTL8211F_RXCR 0x15
- #define RTL8211F_RX_DELAY BIT(3)
-
--#define RTL8211F_ALDPS_PLL_OFF BIT(1)
--#define RTL8211F_ALDPS_ENABLE BIT(2)
--#define RTL8211F_ALDPS_XTAL_OFF BIT(12)
-+/* RTL8211F WOL interrupt configuration */
-+#define RTL8211F_INTBCR_PAGE 0xd40
-+#define RTL8211F_INTBCR 0x16
-+#define RTL8211F_INTBCR_INTB_PMEB BIT(5)
-
--#define RTL8211E_RGMII_EXT_PAGE 0xa4
--#define RTL8211E_RGMII_DELAY 0x1c
--#define RTL8211E_CTRL_DELAY BIT(13)
--#define RTL8211E_TX_DELAY BIT(12)
--#define RTL8211E_RX_DELAY BIT(11)
--#define RTL8211E_DELAY_MASK GENMASK(13, 11)
-+/* RTL8211F WOL settings */
-+#define RTL8211F_WOL_SETTINGS_PAGE 0xd8a
-+#define RTL8211F_WOL_SETTINGS_EVENTS 16
-+#define RTL8211F_WOL_EVENT_MAGIC BIT(12)
-+#define RTL8211F_WOL_SETTINGS_STATUS 17
-+#define RTL8211F_WOL_STATUS_RESET (BIT(15) | 0x1fff)
-
--#define RTL8201F_ISR 0x1e
--#define RTL8201F_ISR_ANERR BIT(15)
--#define RTL8201F_ISR_DUPLEX BIT(13)
--#define RTL8201F_ISR_LINK BIT(11)
--#define RTL8201F_ISR_MASK (RTL8201F_ISR_ANERR | \
-- RTL8201F_ISR_DUPLEX | \
-- RTL8201F_ISR_LINK)
--#define RTL8201F_IER 0x13
-+/* RTL8211F Unique phyiscal and multicast address (WOL) */
-+#define RTL8211F_PHYSICAL_ADDR_PAGE 0xd8c
-+#define RTL8211F_PHYSICAL_ADDR_WORD0 16
-+#define RTL8211F_PHYSICAL_ADDR_WORD1 17
-+#define RTL8211F_PHYSICAL_ADDR_WORD2 18
-
- #define RTL822X_VND1_SERDES_OPTION 0x697a
- #define RTL822X_VND1_SERDES_OPTION_MODE_MASK GENMASK(5, 0)
+++ /dev/null
-From be1cc96ddf82bb0c0a159751f73239d6d3e9594a Mon Sep 17 00:00:00 2001
-Date: Sun, 4 May 2025 19:29:15 +0200
-Subject: [PATCH] net: phy: realtek: use __set_bit() in
- rtl8211f_led_hw_control_get()
-
-rtl8211f_led_hw_control_get() does not need atomic bit operations,
-replace set_bit() by __set_bit().
-
----
- drivers/net/phy/realtek/realtek_main.c | 10 +++++-----
- 1 file changed, 5 insertions(+), 5 deletions(-)
-
---- a/drivers/net/phy/realtek/realtek_main.c
-+++ b/drivers/net/phy/realtek/realtek_main.c
-@@ -659,17 +659,17 @@ static int rtl8211f_led_hw_control_get(s
- val &= RTL8211F_LEDCR_MASK;
-
- if (val & RTL8211F_LEDCR_LINK_10)
-- set_bit(TRIGGER_NETDEV_LINK_10, rules);
-+ __set_bit(TRIGGER_NETDEV_LINK_10, rules);
-
- if (val & RTL8211F_LEDCR_LINK_100)
-- set_bit(TRIGGER_NETDEV_LINK_100, rules);
-+ __set_bit(TRIGGER_NETDEV_LINK_100, rules);
-
- if (val & RTL8211F_LEDCR_LINK_1000)
-- set_bit(TRIGGER_NETDEV_LINK_1000, rules);
-+ __set_bit(TRIGGER_NETDEV_LINK_1000, rules);
-
- if (val & RTL8211F_LEDCR_ACT_TXRX) {
-- set_bit(TRIGGER_NETDEV_RX, rules);
-- set_bit(TRIGGER_NETDEV_TX, rules);
-+ __set_bit(TRIGGER_NETDEV_RX, rules);
-+ __set_bit(TRIGGER_NETDEV_TX, rules);
- }
-
- return 0;
+++ /dev/null
-From 708686132ba02659267c0cebcc414348ece389a5 Mon Sep 17 00:00:00 2001
-Date: Sun, 4 May 2025 19:29:16 +0200
-Subject: [PATCH] net: phy: realtek: Add support for PHY LEDs on RTL8211E
-
-Like the RTL8211F, the RTL8211E PHY supports up to three LEDs.
-Add netdev trigger support for them, too.
-
----
- drivers/net/phy/realtek/realtek_main.c | 125 +++++++++++++++++++++++--
- 1 file changed, 119 insertions(+), 6 deletions(-)
-
---- a/drivers/net/phy/realtek/realtek_main.c
-+++ b/drivers/net/phy/realtek/realtek_main.c
-@@ -40,6 +40,20 @@
- #define RTL821x_PAGE_SELECT 0x1f
- #define RTL821x_SET_EXT_PAGE 0x07
-
-+/* RTL8211E extension page 44/0x2c */
-+#define RTL8211E_LEDCR_EXT_PAGE 0x2c
-+#define RTL8211E_LEDCR1 0x1a
-+#define RTL8211E_LEDCR1_ACT_TXRX BIT(4)
-+#define RTL8211E_LEDCR1_MASK BIT(4)
-+#define RTL8211E_LEDCR1_SHIFT 1
-+
-+#define RTL8211E_LEDCR2 0x1c
-+#define RTL8211E_LEDCR2_LINK_1000 BIT(2)
-+#define RTL8211E_LEDCR2_LINK_100 BIT(1)
-+#define RTL8211E_LEDCR2_LINK_10 BIT(0)
-+#define RTL8211E_LEDCR2_MASK GENMASK(2, 0)
-+#define RTL8211E_LEDCR2_SHIFT 4
-+
- /* RTL8211E extension page 164/0xa4 */
- #define RTL8211E_RGMII_EXT_PAGE 0xa4
- #define RTL8211E_RGMII_DELAY 0x1c
-@@ -145,7 +159,8 @@
- #define RTL_8221B_VN_CG 0x001cc84a
- #define RTL_8251B 0x001cc862
-
--#define RTL8211F_LED_COUNT 3
-+/* RTL8211E and RTL8211F support up to three LEDs */
-+#define RTL8211x_LED_COUNT 3
-
- MODULE_DESCRIPTION("Realtek PHY driver");
- MODULE_AUTHOR("Johnson Leung");
-@@ -169,6 +184,21 @@ static int rtl821x_write_page(struct phy
- return __phy_write(phydev, RTL821x_PAGE_SELECT, page);
- }
-
-+static int rtl821x_read_ext_page(struct phy_device *phydev, u16 ext_page,
-+ u32 regnum)
-+{
-+ int oldpage, ret = 0;
-+
-+ oldpage = phy_select_page(phydev, RTL821x_SET_EXT_PAGE);
-+ if (oldpage >= 0) {
-+ ret = __phy_write(phydev, RTL821x_EXT_PAGE_SELECT, ext_page);
-+ if (ret == 0)
-+ ret = __phy_read(phydev, regnum);
-+ }
-+
-+ return phy_restore_page(phydev, oldpage, ret);
-+}
-+
- static int rtl821x_modify_ext_page(struct phy_device *phydev, u16 ext_page,
- u32 regnum, u16 mask, u16 set)
- {
-@@ -608,7 +638,7 @@ static int rtl821x_resume(struct phy_dev
- return 0;
- }
-
--static int rtl8211f_led_hw_is_supported(struct phy_device *phydev, u8 index,
-+static int rtl8211x_led_hw_is_supported(struct phy_device *phydev, u8 index,
- unsigned long rules)
- {
- const unsigned long mask = BIT(TRIGGER_NETDEV_LINK_10) |
-@@ -627,9 +657,11 @@ static int rtl8211f_led_hw_is_supported(
- * rates and Active indication always at all three 10+100+1000
- * link rates.
- * This code currently uses mode B only.
-+ *
-+ * RTL8211E PHY LED has one mode, which works like RTL8211F mode B.
- */
-
-- if (index >= RTL8211F_LED_COUNT)
-+ if (index >= RTL8211x_LED_COUNT)
- return -EINVAL;
-
- /* Filter out any other unsupported triggers. */
-@@ -648,7 +680,7 @@ static int rtl8211f_led_hw_control_get(s
- {
- int val;
-
-- if (index >= RTL8211F_LED_COUNT)
-+ if (index >= RTL8211x_LED_COUNT)
- return -EINVAL;
-
- val = phy_read_paged(phydev, 0xd04, RTL8211F_LEDCR);
-@@ -681,7 +713,7 @@ static int rtl8211f_led_hw_control_set(s
- const u16 mask = RTL8211F_LEDCR_MASK << (RTL8211F_LEDCR_SHIFT * index);
- u16 reg = 0;
-
-- if (index >= RTL8211F_LED_COUNT)
-+ if (index >= RTL8211x_LED_COUNT)
- return -EINVAL;
-
- if (test_bit(TRIGGER_NETDEV_LINK_10, &rules))
-@@ -704,6 +736,84 @@ static int rtl8211f_led_hw_control_set(s
- return phy_modify_paged(phydev, 0xd04, RTL8211F_LEDCR, mask, reg);
- }
-
-+static int rtl8211e_led_hw_control_get(struct phy_device *phydev, u8 index,
-+ unsigned long *rules)
-+{
-+ int ret;
-+ u16 cr1, cr2;
-+
-+ if (index >= RTL8211x_LED_COUNT)
-+ return -EINVAL;
-+
-+ ret = rtl821x_read_ext_page(phydev, RTL8211E_LEDCR_EXT_PAGE,
-+ RTL8211E_LEDCR1);
-+ if (ret < 0)
-+ return ret;
-+
-+ cr1 = ret >> RTL8211E_LEDCR1_SHIFT * index;
-+ if (cr1 & RTL8211E_LEDCR1_ACT_TXRX) {
-+ __set_bit(TRIGGER_NETDEV_RX, rules);
-+ __set_bit(TRIGGER_NETDEV_TX, rules);
-+ }
-+
-+ ret = rtl821x_read_ext_page(phydev, RTL8211E_LEDCR_EXT_PAGE,
-+ RTL8211E_LEDCR2);
-+ if (ret < 0)
-+ return ret;
-+
-+ cr2 = ret >> RTL8211E_LEDCR2_SHIFT * index;
-+ if (cr2 & RTL8211E_LEDCR2_LINK_10)
-+ __set_bit(TRIGGER_NETDEV_LINK_10, rules);
-+
-+ if (cr2 & RTL8211E_LEDCR2_LINK_100)
-+ __set_bit(TRIGGER_NETDEV_LINK_100, rules);
-+
-+ if (cr2 & RTL8211E_LEDCR2_LINK_1000)
-+ __set_bit(TRIGGER_NETDEV_LINK_1000, rules);
-+
-+ return ret;
-+}
-+
-+static int rtl8211e_led_hw_control_set(struct phy_device *phydev, u8 index,
-+ unsigned long rules)
-+{
-+ const u16 cr1mask =
-+ RTL8211E_LEDCR1_MASK << (RTL8211E_LEDCR1_SHIFT * index);
-+ const u16 cr2mask =
-+ RTL8211E_LEDCR2_MASK << (RTL8211E_LEDCR2_SHIFT * index);
-+ u16 cr1 = 0, cr2 = 0;
-+ int ret;
-+
-+ if (index >= RTL8211x_LED_COUNT)
-+ return -EINVAL;
-+
-+ if (test_bit(TRIGGER_NETDEV_RX, &rules) ||
-+ test_bit(TRIGGER_NETDEV_TX, &rules)) {
-+ cr1 |= RTL8211E_LEDCR1_ACT_TXRX;
-+ }
-+
-+ cr1 <<= RTL8211E_LEDCR1_SHIFT * index;
-+ ret = rtl821x_modify_ext_page(phydev, RTL8211E_LEDCR_EXT_PAGE,
-+ RTL8211E_LEDCR1, cr1mask, cr1);
-+ if (ret < 0)
-+ return ret;
-+
-+ if (test_bit(TRIGGER_NETDEV_LINK_10, &rules))
-+ cr2 |= RTL8211E_LEDCR2_LINK_10;
-+
-+ if (test_bit(TRIGGER_NETDEV_LINK_100, &rules))
-+ cr2 |= RTL8211E_LEDCR2_LINK_100;
-+
-+ if (test_bit(TRIGGER_NETDEV_LINK_1000, &rules))
-+ cr2 |= RTL8211E_LEDCR2_LINK_1000;
-+
-+ cr2 <<= RTL8211E_LEDCR2_SHIFT * index;
-+ ret = rtl821x_modify_ext_page(phydev, RTL8211E_LEDCR_EXT_PAGE,
-+ RTL8211E_LEDCR2, cr2mask, cr2);
-+
-+ return ret;
-+}
-+
- static int rtl8211e_config_init(struct phy_device *phydev)
- {
- u16 val;
-@@ -1479,6 +1589,9 @@ static struct phy_driver realtek_drvs[]
- .resume = genphy_resume,
- .read_page = rtl821x_read_page,
- .write_page = rtl821x_write_page,
-+ .led_hw_is_supported = rtl8211x_led_hw_is_supported,
-+ .led_hw_control_get = rtl8211e_led_hw_control_get,
-+ .led_hw_control_set = rtl8211e_led_hw_control_set,
- }, {
- PHY_ID_MATCH_EXACT(0x001cc916),
- .name = "RTL8211F Gigabit Ethernet",
-@@ -1494,7 +1607,7 @@ static struct phy_driver realtek_drvs[]
- .read_page = rtl821x_read_page,
- .write_page = rtl821x_write_page,
- .flags = PHY_ALWAYS_CALL_SUSPEND,
-- .led_hw_is_supported = rtl8211f_led_hw_is_supported,
-+ .led_hw_is_supported = rtl8211x_led_hw_is_supported,
- .led_hw_control_get = rtl8211f_led_hw_control_get,
- .led_hw_control_set = rtl8211f_led_hw_control_set,
- }, {
+++ /dev/null
-From 83d9623161283f5f6883ee3fdb88ef2177b8a5f1 Mon Sep 17 00:00:00 2001
-Date: Fri, 16 May 2025 13:56:22 +0800
-Subject: [PATCH] net: phy: realtek: add RTL8127-internal PHY
-
-RTL8127-internal PHY is RTL8261C which is a integrated 10Gbps PHY with ID
-0x001cc890. It follows the code path of RTL8125/RTL8126 internal NBase-T
-PHY.
-
----
- drivers/net/phy/realtek/realtek_main.c | 2 ++
- 1 file changed, 2 insertions(+)
-
---- a/drivers/net/phy/realtek/realtek_main.c
-+++ b/drivers/net/phy/realtek/realtek_main.c
-@@ -158,6 +158,7 @@
- #define RTL_8221B_VB_CG 0x001cc849
- #define RTL_8221B_VN_CG 0x001cc84a
- #define RTL_8251B 0x001cc862
-+#define RTL_8261C 0x001cc890
-
- /* RTL8211E and RTL8211F support up to three LEDs */
- #define RTL8211x_LED_COUNT 3
-@@ -1370,6 +1371,7 @@ static int rtl_internal_nbaset_match_phy
- case RTL_GENERIC_PHYID:
- case RTL_8221B:
- case RTL_8251B:
-+ case RTL_8261C:
- case 0x001cc841:
- break;
- default:
+++ /dev/null
-From 31afd6bc55cc0093c3e5b0a368319e423d4de8ea Mon Sep 17 00:00:00 2001
-Date: Sat, 17 May 2025 22:13:45 +0200
-Subject: [PATCH 1/5] net: phy: pass PHY driver to .match_phy_device OP
-
-Pass PHY driver pointer to .match_phy_device OP in addition to phydev.
-Having access to the PHY driver struct might be useful to check the
-PHY ID of the driver is being matched for in case the PHY ID scanned in
-the phydev is not consistent.
-
-A scenario for this is a PHY that change PHY ID after a firmware is
-loaded, in such case, the PHY ID stored in PHY device struct is not
-valid anymore and PHY will manually scan the ID in the match_phy_device
-function.
-
-Having the PHY driver info is also useful for those PHY driver that
-implement multiple simple .match_phy_device OP to match specific MMD PHY
-ID. With this extra info if the parsing logic is the same, the matching
-function can be generalized by using the phy_id in the PHY driver
-instead of hardcoding.
-
-Rust wrapper callback is updated to align to the new match_phy_device
-arguments.
-
----
- drivers/net/phy/bcm87xx.c | 6 ++++--
- drivers/net/phy/icplus.c | 6 ++++--
- drivers/net/phy/marvell10g.c | 12 ++++++++----
- drivers/net/phy/micrel.c | 6 ++++--
- drivers/net/phy/nxp-c45-tja11xx.c | 12 ++++++++----
- drivers/net/phy/nxp-tja11xx.c | 6 ++++--
- drivers/net/phy/phy_device.c | 2 +-
- drivers/net/phy/realtek/realtek_main.c | 27 +++++++++++++++++---------
- drivers/net/phy/teranetics.c | 3 ++-
- include/linux/phy.h | 3 ++-
- rust/kernel/net/phy.rs | 1 +
- 11 files changed, 56 insertions(+), 28 deletions(-)
-
---- a/drivers/net/phy/bcm87xx.c
-+++ b/drivers/net/phy/bcm87xx.c
-@@ -185,12 +185,14 @@ static irqreturn_t bcm87xx_handle_interr
- return IRQ_HANDLED;
- }
-
--static int bcm8706_match_phy_device(struct phy_device *phydev)
-+static int bcm8706_match_phy_device(struct phy_device *phydev,
-+ const struct phy_driver *phydrv)
- {
- return phydev->c45_ids.device_ids[4] == PHY_ID_BCM8706;
- }
-
--static int bcm8727_match_phy_device(struct phy_device *phydev)
-+static int bcm8727_match_phy_device(struct phy_device *phydev,
-+ const struct phy_driver *phydrv)
- {
- return phydev->c45_ids.device_ids[4] == PHY_ID_BCM8727;
- }
---- a/drivers/net/phy/icplus.c
-+++ b/drivers/net/phy/icplus.c
-@@ -520,12 +520,14 @@ static int ip101a_g_match_phy_device(str
- return ip101a == !ret;
- }
-
--static int ip101a_match_phy_device(struct phy_device *phydev)
-+static int ip101a_match_phy_device(struct phy_device *phydev,
-+ const struct phy_driver *phydrv)
- {
- return ip101a_g_match_phy_device(phydev, true);
- }
-
--static int ip101g_match_phy_device(struct phy_device *phydev)
-+static int ip101g_match_phy_device(struct phy_device *phydev,
-+ const struct phy_driver *phydrv)
- {
- return ip101a_g_match_phy_device(phydev, false);
- }
---- a/drivers/net/phy/marvell10g.c
-+++ b/drivers/net/phy/marvell10g.c
-@@ -1221,7 +1221,8 @@ static int mv3310_get_number_of_ports(st
- return ret + 1;
- }
-
--static int mv3310_match_phy_device(struct phy_device *phydev)
-+static int mv3310_match_phy_device(struct phy_device *phydev,
-+ const struct phy_driver *phydrv)
- {
- if ((phydev->c45_ids.device_ids[MDIO_MMD_PMAPMD] &
- MARVELL_PHY_ID_MASK) != MARVELL_PHY_ID_88X3310)
-@@ -1230,7 +1231,8 @@ static int mv3310_match_phy_device(struc
- return mv3310_get_number_of_ports(phydev) == 1;
- }
-
--static int mv3340_match_phy_device(struct phy_device *phydev)
-+static int mv3340_match_phy_device(struct phy_device *phydev,
-+ const struct phy_driver *phydrv)
- {
- if ((phydev->c45_ids.device_ids[MDIO_MMD_PMAPMD] &
- MARVELL_PHY_ID_MASK) != MARVELL_PHY_ID_88X3310)
-@@ -1254,12 +1256,14 @@ static int mv211x_match_phy_device(struc
- return !!(val & MDIO_PCS_SPEED_5G) == has_5g;
- }
-
--static int mv2110_match_phy_device(struct phy_device *phydev)
-+static int mv2110_match_phy_device(struct phy_device *phydev,
-+ const struct phy_driver *phydrv)
- {
- return mv211x_match_phy_device(phydev, true);
- }
-
--static int mv2111_match_phy_device(struct phy_device *phydev)
-+static int mv2111_match_phy_device(struct phy_device *phydev,
-+ const struct phy_driver *phydrv)
- {
- return mv211x_match_phy_device(phydev, false);
- }
---- a/drivers/net/phy/micrel.c
-+++ b/drivers/net/phy/micrel.c
-@@ -670,7 +670,8 @@ static int ksz8051_ksz8795_match_phy_dev
- return !ret;
- }
-
--static int ksz8051_match_phy_device(struct phy_device *phydev)
-+static int ksz8051_match_phy_device(struct phy_device *phydev,
-+ const struct phy_driver *phydrv)
- {
- return ksz8051_ksz8795_match_phy_device(phydev, true);
- }
-@@ -790,7 +791,8 @@ static int ksz8061_config_init(struct ph
- return kszphy_config_init(phydev);
- }
-
--static int ksz8795_match_phy_device(struct phy_device *phydev)
-+static int ksz8795_match_phy_device(struct phy_device *phydev,
-+ const struct phy_driver *phydrv)
- {
- return ksz8051_ksz8795_match_phy_device(phydev, false);
- }
---- a/drivers/net/phy/nxp-tja11xx.c
-+++ b/drivers/net/phy/nxp-tja11xx.c
-@@ -648,12 +648,14 @@ static int tja1102_match_phy_device(stru
- return !ret;
- }
-
--static int tja1102_p0_match_phy_device(struct phy_device *phydev)
-+static int tja1102_p0_match_phy_device(struct phy_device *phydev,
-+ const struct phy_driver *phydrv)
- {
- return tja1102_match_phy_device(phydev, true);
- }
-
--static int tja1102_p1_match_phy_device(struct phy_device *phydev)
-+static int tja1102_p1_match_phy_device(struct phy_device *phydev,
-+ const struct phy_driver *phydrv)
- {
- return tja1102_match_phy_device(phydev, false);
- }
---- a/drivers/net/phy/phy_device.c
-+++ b/drivers/net/phy/phy_device.c
-@@ -533,7 +533,7 @@ static int phy_bus_match(struct device *
- return 0;
-
- if (phydrv->match_phy_device)
-- return phydrv->match_phy_device(phydev);
-+ return phydrv->match_phy_device(phydev, phydrv);
-
- if (phydev->is_c45) {
- for (i = 1; i < num_ids; i++) {
---- a/drivers/net/phy/realtek/realtek_main.c
-+++ b/drivers/net/phy/realtek/realtek_main.c
-@@ -1315,13 +1315,15 @@ static bool rtlgen_supports_mmd(struct p
- return val > 0;
- }
-
--static int rtlgen_match_phy_device(struct phy_device *phydev)
-+static int rtlgen_match_phy_device(struct phy_device *phydev,
-+ const struct phy_driver *phydrv)
- {
- return phydev->phy_id == RTL_GENERIC_PHYID &&
- !rtlgen_supports_2_5gbps(phydev);
- }
-
--static int rtl8226_match_phy_device(struct phy_device *phydev)
-+static int rtl8226_match_phy_device(struct phy_device *phydev,
-+ const struct phy_driver *phydrv)
- {
- return phydev->phy_id == RTL_GENERIC_PHYID &&
- rtlgen_supports_2_5gbps(phydev) &&
-@@ -1337,32 +1339,38 @@ static int rtlgen_is_c45_match(struct ph
- return !is_c45 && (id == phydev->phy_id);
- }
-
--static int rtl8221b_match_phy_device(struct phy_device *phydev)
-+static int rtl8221b_match_phy_device(struct phy_device *phydev,
-+ const struct phy_driver *phydrv)
- {
- return phydev->phy_id == RTL_8221B && rtlgen_supports_mmd(phydev);
- }
-
--static int rtl8221b_vb_cg_c22_match_phy_device(struct phy_device *phydev)
-+static int rtl8221b_vb_cg_c22_match_phy_device(struct phy_device *phydev,
-+ const struct phy_driver *phydrv)
- {
- return rtlgen_is_c45_match(phydev, RTL_8221B_VB_CG, false);
- }
-
--static int rtl8221b_vb_cg_c45_match_phy_device(struct phy_device *phydev)
-+static int rtl8221b_vb_cg_c45_match_phy_device(struct phy_device *phydev,
-+ const struct phy_driver *phydrv)
- {
- return rtlgen_is_c45_match(phydev, RTL_8221B_VB_CG, true);
- }
-
--static int rtl8221b_vn_cg_c22_match_phy_device(struct phy_device *phydev)
-+static int rtl8221b_vn_cg_c22_match_phy_device(struct phy_device *phydev,
-+ const struct phy_driver *phydrv)
- {
- return rtlgen_is_c45_match(phydev, RTL_8221B_VN_CG, false);
- }
-
--static int rtl8221b_vn_cg_c45_match_phy_device(struct phy_device *phydev)
-+static int rtl8221b_vn_cg_c45_match_phy_device(struct phy_device *phydev,
-+ const struct phy_driver *phydrv)
- {
- return rtlgen_is_c45_match(phydev, RTL_8221B_VN_CG, true);
- }
-
--static int rtl_internal_nbaset_match_phy_device(struct phy_device *phydev)
-+static int rtl_internal_nbaset_match_phy_device(struct phy_device *phydev,
-+ const struct phy_driver *phydrv)
- {
- if (phydev->is_c45)
- return false;
-@@ -1381,7 +1389,8 @@ static int rtl_internal_nbaset_match_phy
- return rtlgen_supports_2_5gbps(phydev) && !rtlgen_supports_mmd(phydev);
- }
-
--static int rtl8251b_c45_match_phy_device(struct phy_device *phydev)
-+static int rtl8251b_c45_match_phy_device(struct phy_device *phydev,
-+ const struct phy_driver *phydrv)
- {
- return rtlgen_is_c45_match(phydev, RTL_8251B, true);
- }
---- a/drivers/net/phy/teranetics.c
-+++ b/drivers/net/phy/teranetics.c
-@@ -67,7 +67,8 @@ static int teranetics_read_status(struct
- return 0;
- }
-
--static int teranetics_match_phy_device(struct phy_device *phydev)
-+static int teranetics_match_phy_device(struct phy_device *phydev,
-+ const struct phy_driver *phydrv)
- {
- return phydev->c45_ids.device_ids[3] == PHY_ID_TN2020;
- }
---- a/include/linux/phy.h
-+++ b/include/linux/phy.h
-@@ -1003,7 +1003,8 @@ struct phy_driver {
- * driver for the given phydev. If NULL, matching is based on
- * phy_id and phy_id_mask.
- */
-- int (*match_phy_device)(struct phy_device *phydev);
-+ int (*match_phy_device)(struct phy_device *phydev,
-+ const struct phy_driver *phydrv);
-
- /**
- * @set_wol: Some devices (e.g. qnap TS-119P II) require PHY
+++ /dev/null
-From d6c45707ac84c2d9f274ece1cea4dddb97996bde Mon Sep 17 00:00:00 2001
-Date: Sat, 17 May 2025 22:13:48 +0200
-Subject: [PATCH 4/5] net: phy: introduce genphy_match_phy_device()
-
-Introduce new API, genphy_match_phy_device(), to provide a way to check
-to match a PHY driver for a PHY device based on the info stored in the
-PHY device struct.
-
-The function generalize the logic used in phy_bus_match() to check the
-PHY ID whether if C45 or C22 ID should be used for matching.
-
-This is useful for custom .match_phy_device function that wants to use
-the generic logic under some condition. (example a PHY is already setup
-and provide the correct PHY ID)
-
----
- drivers/net/phy/phy_device.c | 52 +++++++++++++++++++++++++-----------
- include/linux/phy.h | 3 +++
- 2 files changed, 40 insertions(+), 15 deletions(-)
-
---- a/drivers/net/phy/phy_device.c
-+++ b/drivers/net/phy/phy_device.c
-@@ -522,20 +522,26 @@ static int phy_scan_fixups(struct phy_de
- return 0;
- }
-
--static int phy_bus_match(struct device *dev, struct device_driver *drv)
-+/**
-+ * genphy_match_phy_device - match a PHY device with a PHY driver
-+ * @phydev: target phy_device struct
-+ * @phydrv: target phy_driver struct
-+ *
-+ * Description: Checks whether the given PHY device matches the specified
-+ * PHY driver. For Clause 45 PHYs, iterates over the available device
-+ * identifiers and compares them against the driver's expected PHY ID,
-+ * applying the provided mask. For Clause 22 PHYs, a direct ID comparison
-+ * is performed.
-+ *
-+ * Return: 1 if the PHY device matches the driver, 0 otherwise.
-+ */
-+int genphy_match_phy_device(struct phy_device *phydev,
-+ struct phy_driver *phydrv)
- {
-- struct phy_device *phydev = to_phy_device(dev);
-- struct phy_driver *phydrv = to_phy_driver(drv);
-- const int num_ids = ARRAY_SIZE(phydev->c45_ids.device_ids);
-- int i;
--
-- if (!(phydrv->mdiodrv.flags & MDIO_DEVICE_IS_PHY))
-- return 0;
--
-- if (phydrv->match_phy_device)
-- return phydrv->match_phy_device(phydev, phydrv);
--
- if (phydev->is_c45) {
-+ const int num_ids = ARRAY_SIZE(phydev->c45_ids.device_ids);
-+ int i;
-+
- for (i = 1; i < num_ids; i++) {
- if (phydev->c45_ids.device_ids[i] == 0xffffffff)
- continue;
-@@ -544,11 +550,27 @@ static int phy_bus_match(struct device *
- phydrv->phy_id, phydrv->phy_id_mask))
- return 1;
- }
-+
- return 0;
-- } else {
-- return phy_id_compare(phydev->phy_id, phydrv->phy_id,
-- phydrv->phy_id_mask);
- }
-+
-+ return phy_id_compare(phydev->phy_id, phydrv->phy_id,
-+ phydrv->phy_id_mask);
-+}
-+EXPORT_SYMBOL_GPL(genphy_match_phy_device);
-+
-+static int phy_bus_match(struct device *dev, struct device_driver *drv)
-+{
-+ struct phy_device *phydev = to_phy_device(dev);
-+ struct phy_driver *phydrv = to_phy_driver(drv);
-+
-+ if (!(phydrv->mdiodrv.flags & MDIO_DEVICE_IS_PHY))
-+ return 0;
-+
-+ if (phydrv->match_phy_device)
-+ return phydrv->match_phy_device(phydev, phydrv);
-+
-+ return genphy_match_phy_device(phydev, phydrv);
- }
-
- static ssize_t
---- a/include/linux/phy.h
-+++ b/include/linux/phy.h
-@@ -1846,6 +1846,9 @@ char *phy_attached_info_irq(struct phy_d
- __malloc;
- void phy_attached_info(struct phy_device *phydev);
-
-+int genphy_match_phy_device(struct phy_device *phydev,
-+ struct phy_driver *phydrv);
-+
- /* Clause 22 PHY */
- int genphy_read_abilities(struct phy_device *phydev);
- int genphy_setup_forced(struct phy_device *phydev);
+++ /dev/null
-From 830877d89edcd834e4b4d0fcc021ff619d89505e Mon Sep 17 00:00:00 2001
-Date: Sat, 17 May 2025 22:13:49 +0200
-Subject: [PATCH 5/5] net: phy: Add support for Aeonsemi AS21xxx PHYs
-
-Add support for Aeonsemi AS21xxx 10G C45 PHYs. These PHYs integrate
-an IPC to setup some configuration and require special handling to
-sync with the parity bit. The parity bit is a way the IPC use to
-follow correct order of command sent.
-
-Supported PHYs AS21011JB1, AS21011PB1, AS21010JB1, AS21010PB1,
-AS21511JB1, AS21511PB1, AS21510JB1, AS21510PB1, AS21210JB1,
-AS21210PB1 that all register with the PHY ID 0x7500 0x7510
-before the firmware is loaded.
-
-They all support up to 5 LEDs with various HW mode supported.
-
-While implementing it was found some strange coincidence with using the
-same logic for implementing C22 in MMD regs in Broadcom PHYs.
-
-For reference here the AS21xxx PHY name logic:
-
-AS21x1xxB1
- ^ ^^
- | |J: Supports SyncE/PTP
- | |P: No SyncE/PTP support
- | 1: Supports 2nd Serdes
- | 2: Not 2nd Serdes support
- 0: 10G, 5G, 2.5G
- 5: 5G, 2.5G
- 2: 2.5G
-
----
- MAINTAINERS | 6 +
- drivers/net/phy/Kconfig | 12 +
- drivers/net/phy/Makefile | 1 +
- drivers/net/phy/as21xxx.c | 1087 +++++++++++++++++++++++++++++++++++++
- 4 files changed, 1106 insertions(+)
- create mode 100644 drivers/net/phy/as21xxx.c
-
---- a/drivers/net/phy/Kconfig
-+++ b/drivers/net/phy/Kconfig
-@@ -68,6 +68,18 @@ config SFP
-
- comment "MII PHY device drivers"
-
-+config AS21XXX_PHY
-+ tristate "Aeonsemi AS21xxx PHYs"
-+ help
-+ Currently supports the Aeonsemi AS21xxx PHY.
-+
-+ These are C45 PHYs 10G that require all a generic firmware.
-+
-+ Supported PHYs AS21011JB1, AS21011PB1, AS21010JB1, AS21010PB1,
-+ AS21511JB1, AS21511PB1, AS21510JB1, AS21510PB1, AS21210JB1,
-+ AS21210PB1 that all register with the PHY ID 0x7500 0x7500
-+ before the firmware is loaded.
-+
- config AMD_PHY
- tristate "AMD PHYs"
- help
---- a/drivers/net/phy/Makefile
-+++ b/drivers/net/phy/Makefile
-@@ -36,6 +36,7 @@ obj-$(CONFIG_ADIN_PHY) += adin.o
- obj-$(CONFIG_ADIN1100_PHY) += adin1100.o
- obj-$(CONFIG_AMD_PHY) += amd.o
- obj-$(CONFIG_AQUANTIA_PHY) += aquantia/
-+obj-$(CONFIG_AS21XXX_PHY) += as21xxx.o
- obj-$(CONFIG_AX88796B_PHY) += ax88796b.o
- obj-$(CONFIG_BCM54140_PHY) += bcm54140.o
- obj-$(CONFIG_BCM63XX_PHY) += bcm63xx.o
---- /dev/null
-+++ b/drivers/net/phy/as21xxx.c
-@@ -0,0 +1,1087 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/*
-+ * Aeonsemi AS21XXxX PHY Driver
-+ *
-+ */
-+
-+#include <linux/bitfield.h>
-+#include <linux/firmware.h>
-+#include <linux/module.h>
-+#include <linux/of.h>
-+#include <linux/phy.h>
-+
-+#define VEND1_GLB_REG_CPU_RESET_ADDR_LO_BASEADDR 0x3
-+#define VEND1_GLB_REG_CPU_RESET_ADDR_HI_BASEADDR 0x4
-+
-+#define VEND1_GLB_REG_CPU_CTRL 0xe
-+#define VEND1_GLB_CPU_CTRL_MASK GENMASK(4, 0)
-+#define VEND1_GLB_CPU_CTRL_LED_POLARITY_MASK GENMASK(12, 8)
-+#define VEND1_GLB_CPU_CTRL_LED_POLARITY(_n) FIELD_PREP(VEND1_GLB_CPU_CTRL_LED_POLARITY_MASK, \
-+ BIT(_n))
-+
-+#define VEND1_FW_START_ADDR 0x100
-+
-+#define VEND1_GLB_REG_MDIO_INDIRECT_ADDRCMD 0x101
-+#define VEND1_GLB_REG_MDIO_INDIRECT_LOAD 0x102
-+
-+#define VEND1_GLB_REG_MDIO_INDIRECT_STATUS 0x103
-+
-+#define VEND1_PTP_CLK 0x142
-+#define VEND1_PTP_CLK_EN BIT(6)
-+
-+/* 5 LED at step of 0x20
-+ * FE: Fast-Ethernet (10/100)
-+ * GE: Gigabit-Ethernet (1000)
-+ * NG: New-Generation (2500/5000/10000)
-+ */
-+#define VEND1_LED_REG(_n) (0x1800 + ((_n) * 0x10))
-+#define VEND1_LED_REG_A_EVENT GENMASK(15, 11)
-+#define VEND1_LED_CONF 0x1881
-+#define VEND1_LED_CONFG_BLINK GENMASK(7, 0)
-+
-+#define VEND1_SPEED_STATUS 0x4002
-+#define VEND1_SPEED_MASK GENMASK(7, 0)
-+#define VEND1_SPEED_10000 FIELD_PREP_CONST(VEND1_SPEED_MASK, 0x3)
-+#define VEND1_SPEED_5000 FIELD_PREP_CONST(VEND1_SPEED_MASK, 0x5)
-+#define VEND1_SPEED_2500 FIELD_PREP_CONST(VEND1_SPEED_MASK, 0x9)
-+#define VEND1_SPEED_1000 FIELD_PREP_CONST(VEND1_SPEED_MASK, 0x10)
-+#define VEND1_SPEED_100 FIELD_PREP_CONST(VEND1_SPEED_MASK, 0x20)
-+#define VEND1_SPEED_10 FIELD_PREP_CONST(VEND1_SPEED_MASK, 0x0)
-+
-+#define VEND1_IPC_CMD 0x5801
-+#define AEON_IPC_CMD_PARITY BIT(15)
-+#define AEON_IPC_CMD_SIZE GENMASK(10, 6)
-+#define AEON_IPC_CMD_OPCODE GENMASK(5, 0)
-+
-+#define IPC_CMD_NOOP 0x0 /* Do nothing */
-+#define IPC_CMD_INFO 0x1 /* Get Firmware Version */
-+#define IPC_CMD_SYS_CPU 0x2 /* SYS_CPU */
-+#define IPC_CMD_BULK_DATA 0xa /* Pass bulk data in ipc registers. */
-+#define IPC_CMD_BULK_WRITE 0xc /* Write bulk data to memory */
-+#define IPC_CMD_CFG_PARAM 0x1a /* Write config parameters to memory */
-+#define IPC_CMD_NG_TESTMODE 0x1b /* Set NG test mode and tone */
-+#define IPC_CMD_TEMP_MON 0x15 /* Temperature monitoring function */
-+#define IPC_CMD_SET_LED 0x23 /* Set led */
-+
-+#define VEND1_IPC_STS 0x5802
-+#define AEON_IPC_STS_PARITY BIT(15)
-+#define AEON_IPC_STS_SIZE GENMASK(14, 10)
-+#define AEON_IPC_STS_OPCODE GENMASK(9, 4)
-+#define AEON_IPC_STS_STATUS GENMASK(3, 0)
-+#define AEON_IPC_STS_STATUS_RCVD FIELD_PREP_CONST(AEON_IPC_STS_STATUS, 0x1)
-+#define AEON_IPC_STS_STATUS_PROCESS FIELD_PREP_CONST(AEON_IPC_STS_STATUS, 0x2)
-+#define AEON_IPC_STS_STATUS_SUCCESS FIELD_PREP_CONST(AEON_IPC_STS_STATUS, 0x4)
-+#define AEON_IPC_STS_STATUS_ERROR FIELD_PREP_CONST(AEON_IPC_STS_STATUS, 0x8)
-+#define AEON_IPC_STS_STATUS_BUSY FIELD_PREP_CONST(AEON_IPC_STS_STATUS, 0xe)
-+#define AEON_IPC_STS_STATUS_READY FIELD_PREP_CONST(AEON_IPC_STS_STATUS, 0xf)
-+
-+#define VEND1_IPC_DATA0 0x5808
-+#define VEND1_IPC_DATA1 0x5809
-+#define VEND1_IPC_DATA2 0x580a
-+#define VEND1_IPC_DATA3 0x580b
-+#define VEND1_IPC_DATA4 0x580c
-+#define VEND1_IPC_DATA5 0x580d
-+#define VEND1_IPC_DATA6 0x580e
-+#define VEND1_IPC_DATA7 0x580f
-+#define VEND1_IPC_DATA(_n) (VEND1_IPC_DATA0 + (_n))
-+
-+/* Sub command of CMD_INFO */
-+#define IPC_INFO_VERSION 0x1
-+
-+/* Sub command of CMD_SYS_CPU */
-+#define IPC_SYS_CPU_REBOOT 0x3
-+#define IPC_SYS_CPU_IMAGE_OFST 0x4
-+#define IPC_SYS_CPU_IMAGE_CHECK 0x5
-+#define IPC_SYS_CPU_PHY_ENABLE 0x6
-+
-+/* Sub command of CMD_CFG_PARAM */
-+#define IPC_CFG_PARAM_DIRECT 0x4
-+
-+/* CFG DIRECT sub command */
-+#define IPC_CFG_PARAM_DIRECT_NG_PHYCTRL 0x1
-+#define IPC_CFG_PARAM_DIRECT_CU_AN 0x2
-+#define IPC_CFG_PARAM_DIRECT_SDS_PCS 0x3
-+#define IPC_CFG_PARAM_DIRECT_AUTO_EEE 0x4
-+#define IPC_CFG_PARAM_DIRECT_SDS_PMA 0x5
-+#define IPC_CFG_PARAM_DIRECT_DPC_RA 0x6
-+#define IPC_CFG_PARAM_DIRECT_DPC_PKT_CHK 0x7
-+#define IPC_CFG_PARAM_DIRECT_DPC_SDS_WAIT_ETH 0x8
-+#define IPC_CFG_PARAM_DIRECT_WDT 0x9
-+#define IPC_CFG_PARAM_DIRECT_SDS_RESTART_AN 0x10
-+#define IPC_CFG_PARAM_DIRECT_TEMP_MON 0x11
-+#define IPC_CFG_PARAM_DIRECT_WOL 0x12
-+
-+/* Sub command of CMD_TEMP_MON */
-+#define IPC_CMD_TEMP_MON_GET 0x4
-+
-+#define AS21XXX_MDIO_AN_C22 0xffe0
-+
-+#define PHY_ID_AS21XXX 0x75009410
-+/* AS21xxx ID Legend
-+ * AS21x1xxB1
-+ * ^ ^^
-+ * | |J: Supports SyncE/PTP
-+ * | |P: No SyncE/PTP support
-+ * | 1: Supports 2nd Serdes
-+ * | 2: Not 2nd Serdes support
-+ * 0: 10G, 5G, 2.5G
-+ * 5: 5G, 2.5G
-+ * 2: 2.5G
-+ */
-+#define PHY_ID_AS21011JB1 0x75009402
-+#define PHY_ID_AS21011PB1 0x75009412
-+#define PHY_ID_AS21010JB1 0x75009422
-+#define PHY_ID_AS21010PB1 0x75009432
-+#define PHY_ID_AS21511JB1 0x75009442
-+#define PHY_ID_AS21511PB1 0x75009452
-+#define PHY_ID_AS21510JB1 0x75009462
-+#define PHY_ID_AS21510PB1 0x75009472
-+#define PHY_ID_AS21210JB1 0x75009482
-+#define PHY_ID_AS21210PB1 0x75009492
-+#define PHY_VENDOR_AEONSEMI 0x75009400
-+
-+#define AEON_MAX_LEDS 5
-+#define AEON_IPC_DELAY 10000
-+#define AEON_IPC_TIMEOUT (AEON_IPC_DELAY * 100)
-+#define AEON_IPC_DATA_NUM_REGISTERS 8
-+#define AEON_IPC_DATA_MAX (AEON_IPC_DATA_NUM_REGISTERS * sizeof(u16))
-+
-+#define AEON_BOOT_ADDR 0x1000
-+#define AEON_CPU_BOOT_ADDR 0x2000
-+#define AEON_CPU_CTRL_FW_LOAD (BIT(4) | BIT(2) | BIT(1) | BIT(0))
-+#define AEON_CPU_CTRL_FW_START BIT(0)
-+
-+enum as21xxx_led_event {
-+ VEND1_LED_REG_A_EVENT_ON_10 = 0x0,
-+ VEND1_LED_REG_A_EVENT_ON_100,
-+ VEND1_LED_REG_A_EVENT_ON_1000,
-+ VEND1_LED_REG_A_EVENT_ON_2500,
-+ VEND1_LED_REG_A_EVENT_ON_5000,
-+ VEND1_LED_REG_A_EVENT_ON_10000,
-+ VEND1_LED_REG_A_EVENT_ON_FE_GE,
-+ VEND1_LED_REG_A_EVENT_ON_NG,
-+ VEND1_LED_REG_A_EVENT_ON_FULL_DUPLEX,
-+ VEND1_LED_REG_A_EVENT_ON_COLLISION,
-+ VEND1_LED_REG_A_EVENT_BLINK_TX,
-+ VEND1_LED_REG_A_EVENT_BLINK_RX,
-+ VEND1_LED_REG_A_EVENT_BLINK_ACT,
-+ VEND1_LED_REG_A_EVENT_ON_LINK,
-+ VEND1_LED_REG_A_EVENT_ON_LINK_BLINK_ACT,
-+ VEND1_LED_REG_A_EVENT_ON_LINK_BLINK_RX,
-+ VEND1_LED_REG_A_EVENT_ON_FE_GE_BLINK_ACT,
-+ VEND1_LED_REG_A_EVENT_ON_NG_BLINK_ACT,
-+ VEND1_LED_REG_A_EVENT_ON_NG_BLINK_FE_GE,
-+ VEND1_LED_REG_A_EVENT_ON_FD_BLINK_COLLISION,
-+ VEND1_LED_REG_A_EVENT_ON,
-+ VEND1_LED_REG_A_EVENT_OFF,
-+};
-+
-+struct as21xxx_led_pattern_info {
-+ unsigned int pattern;
-+ u16 val;
-+};
-+
-+struct as21xxx_priv {
-+ bool parity_status;
-+ /* Protect concurrent IPC access */
-+ struct mutex ipc_lock;
-+};
-+
-+static struct as21xxx_led_pattern_info as21xxx_led_supported_pattern[] = {
-+ {
-+ .pattern = BIT(TRIGGER_NETDEV_LINK_10),
-+ .val = VEND1_LED_REG_A_EVENT_ON_10
-+ },
-+ {
-+ .pattern = BIT(TRIGGER_NETDEV_LINK_100),
-+ .val = VEND1_LED_REG_A_EVENT_ON_100
-+ },
-+ {
-+ .pattern = BIT(TRIGGER_NETDEV_LINK_1000),
-+ .val = VEND1_LED_REG_A_EVENT_ON_1000
-+ },
-+ {
-+ .pattern = BIT(TRIGGER_NETDEV_LINK_2500),
-+ .val = VEND1_LED_REG_A_EVENT_ON_2500
-+ },
-+ {
-+ .pattern = BIT(TRIGGER_NETDEV_LINK_5000),
-+ .val = VEND1_LED_REG_A_EVENT_ON_5000
-+ },
-+ {
-+ .pattern = BIT(TRIGGER_NETDEV_LINK_10000),
-+ .val = VEND1_LED_REG_A_EVENT_ON_10000
-+ },
-+ {
-+ .pattern = BIT(TRIGGER_NETDEV_LINK),
-+ .val = VEND1_LED_REG_A_EVENT_ON_LINK
-+ },
-+ {
-+ .pattern = BIT(TRIGGER_NETDEV_LINK_10) |
-+ BIT(TRIGGER_NETDEV_LINK_100) |
-+ BIT(TRIGGER_NETDEV_LINK_1000),
-+ .val = VEND1_LED_REG_A_EVENT_ON_FE_GE
-+ },
-+ {
-+ .pattern = BIT(TRIGGER_NETDEV_LINK_2500) |
-+ BIT(TRIGGER_NETDEV_LINK_5000) |
-+ BIT(TRIGGER_NETDEV_LINK_10000),
-+ .val = VEND1_LED_REG_A_EVENT_ON_NG
-+ },
-+ {
-+ .pattern = BIT(TRIGGER_NETDEV_FULL_DUPLEX),
-+ .val = VEND1_LED_REG_A_EVENT_ON_FULL_DUPLEX
-+ },
-+ {
-+ .pattern = BIT(TRIGGER_NETDEV_TX),
-+ .val = VEND1_LED_REG_A_EVENT_BLINK_TX
-+ },
-+ {
-+ .pattern = BIT(TRIGGER_NETDEV_RX),
-+ .val = VEND1_LED_REG_A_EVENT_BLINK_RX
-+ },
-+ {
-+ .pattern = BIT(TRIGGER_NETDEV_TX) |
-+ BIT(TRIGGER_NETDEV_RX),
-+ .val = VEND1_LED_REG_A_EVENT_BLINK_ACT
-+ },
-+ {
-+ .pattern = BIT(TRIGGER_NETDEV_LINK_10) |
-+ BIT(TRIGGER_NETDEV_LINK_100) |
-+ BIT(TRIGGER_NETDEV_LINK_1000) |
-+ BIT(TRIGGER_NETDEV_LINK_2500) |
-+ BIT(TRIGGER_NETDEV_LINK_5000) |
-+ BIT(TRIGGER_NETDEV_LINK_10000),
-+ .val = VEND1_LED_REG_A_EVENT_ON_LINK
-+ },
-+ {
-+ .pattern = BIT(TRIGGER_NETDEV_LINK_10) |
-+ BIT(TRIGGER_NETDEV_LINK_100) |
-+ BIT(TRIGGER_NETDEV_LINK_1000) |
-+ BIT(TRIGGER_NETDEV_LINK_2500) |
-+ BIT(TRIGGER_NETDEV_LINK_5000) |
-+ BIT(TRIGGER_NETDEV_LINK_10000) |
-+ BIT(TRIGGER_NETDEV_TX) |
-+ BIT(TRIGGER_NETDEV_RX),
-+ .val = VEND1_LED_REG_A_EVENT_ON_LINK_BLINK_ACT
-+ },
-+ {
-+ .pattern = BIT(TRIGGER_NETDEV_LINK_10) |
-+ BIT(TRIGGER_NETDEV_LINK_100) |
-+ BIT(TRIGGER_NETDEV_LINK_1000) |
-+ BIT(TRIGGER_NETDEV_LINK_2500) |
-+ BIT(TRIGGER_NETDEV_LINK_5000) |
-+ BIT(TRIGGER_NETDEV_LINK_10000) |
-+ BIT(TRIGGER_NETDEV_RX),
-+ .val = VEND1_LED_REG_A_EVENT_ON_LINK_BLINK_RX
-+ },
-+ {
-+ .pattern = BIT(TRIGGER_NETDEV_LINK_10) |
-+ BIT(TRIGGER_NETDEV_LINK_100) |
-+ BIT(TRIGGER_NETDEV_LINK_1000) |
-+ BIT(TRIGGER_NETDEV_TX) |
-+ BIT(TRIGGER_NETDEV_RX),
-+ .val = VEND1_LED_REG_A_EVENT_ON_FE_GE_BLINK_ACT
-+ },
-+ {
-+ .pattern = BIT(TRIGGER_NETDEV_LINK_2500) |
-+ BIT(TRIGGER_NETDEV_LINK_5000) |
-+ BIT(TRIGGER_NETDEV_LINK_10000) |
-+ BIT(TRIGGER_NETDEV_TX) |
-+ BIT(TRIGGER_NETDEV_RX),
-+ .val = VEND1_LED_REG_A_EVENT_ON_NG_BLINK_ACT
-+ }
-+};
-+
-+static int aeon_firmware_boot(struct phy_device *phydev, const u8 *data,
-+ size_t size)
-+{
-+ int i, ret;
-+ u16 val;
-+
-+ ret = phy_modify_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLB_REG_CPU_CTRL,
-+ VEND1_GLB_CPU_CTRL_MASK, AEON_CPU_CTRL_FW_LOAD);
-+ if (ret)
-+ return ret;
-+
-+ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_FW_START_ADDR,
-+ AEON_BOOT_ADDR);
-+ if (ret)
-+ return ret;
-+
-+ ret = phy_modify_mmd(phydev, MDIO_MMD_VEND1,
-+ VEND1_GLB_REG_MDIO_INDIRECT_ADDRCMD,
-+ 0x3ffc, 0xc000);
-+ if (ret)
-+ return ret;
-+
-+ val = phy_read_mmd(phydev, MDIO_MMD_VEND1,
-+ VEND1_GLB_REG_MDIO_INDIRECT_STATUS);
-+ if (val > 1) {
-+ phydev_err(phydev, "wrong origin mdio_indirect_status: %x\n", val);
-+ return -EINVAL;
-+ }
-+
-+ /* Firmware is always aligned to u16 */
-+ for (i = 0; i < size; i += 2) {
-+ val = data[i + 1] << 8 | data[i];
-+
-+ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1,
-+ VEND1_GLB_REG_MDIO_INDIRECT_LOAD, val);
-+ if (ret)
-+ return ret;
-+ }
-+
-+ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1,
-+ VEND1_GLB_REG_CPU_RESET_ADDR_LO_BASEADDR,
-+ lower_16_bits(AEON_CPU_BOOT_ADDR));
-+ if (ret)
-+ return ret;
-+
-+ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1,
-+ VEND1_GLB_REG_CPU_RESET_ADDR_HI_BASEADDR,
-+ upper_16_bits(AEON_CPU_BOOT_ADDR));
-+ if (ret)
-+ return ret;
-+
-+ return phy_modify_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLB_REG_CPU_CTRL,
-+ VEND1_GLB_CPU_CTRL_MASK, AEON_CPU_CTRL_FW_START);
-+}
-+
-+static int aeon_firmware_load(struct phy_device *phydev)
-+{
-+ struct device *dev = &phydev->mdio.dev;
-+ const struct firmware *fw;
-+ const char *fw_name;
-+ int ret;
-+
-+ ret = of_property_read_string(dev->of_node, "firmware-name",
-+ &fw_name);
-+ if (ret)
-+ return ret;
-+
-+ ret = request_firmware(&fw, fw_name, dev);
-+ if (ret) {
-+ phydev_err(phydev, "failed to find FW file %s (%d)\n",
-+ fw_name, ret);
-+ return ret;
-+ }
-+
-+ ret = aeon_firmware_boot(phydev, fw->data, fw->size);
-+
-+ release_firmware(fw);
-+
-+ return ret;
-+}
-+
-+static bool aeon_ipc_ready(u16 val, bool parity_status)
-+{
-+ u16 status;
-+
-+ if (FIELD_GET(AEON_IPC_STS_PARITY, val) != parity_status)
-+ return false;
-+
-+ status = val & AEON_IPC_STS_STATUS;
-+
-+ return status != AEON_IPC_STS_STATUS_RCVD &&
-+ status != AEON_IPC_STS_STATUS_PROCESS &&
-+ status != AEON_IPC_STS_STATUS_BUSY;
-+}
-+
-+static int aeon_ipc_wait_cmd(struct phy_device *phydev, bool parity_status)
-+{
-+ u16 val;
-+
-+ /* Exit condition logic:
-+ * - Wait for parity bit equal
-+ * - Wait for status success, error OR ready
-+ */
-+ return phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND1, VEND1_IPC_STS, val,
-+ aeon_ipc_ready(val, parity_status),
-+ AEON_IPC_DELAY, AEON_IPC_TIMEOUT, false);
-+}
-+
-+static int aeon_ipc_send_cmd(struct phy_device *phydev,
-+ struct as21xxx_priv *priv,
-+ u16 cmd, u16 *ret_sts)
-+{
-+ bool curr_parity;
-+ int ret;
-+
-+ /* The IPC sync by using a single parity bit.
-+ * Each CMD have alternately this bit set or clear
-+ * to understand correct flow and packet order.
-+ */
-+ curr_parity = priv->parity_status;
-+ if (priv->parity_status)
-+ cmd |= AEON_IPC_CMD_PARITY;
-+
-+ /* Always update parity for next packet */
-+ priv->parity_status = !priv->parity_status;
-+
-+ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_IPC_CMD, cmd);
-+ if (ret)
-+ return ret;
-+
-+ /* Wait for packet to be processed */
-+ usleep_range(AEON_IPC_DELAY, AEON_IPC_DELAY + 5000);
-+
-+ /* With no ret_sts, ignore waiting for packet completion
-+ * (ipc parity bit sync)
-+ */
-+ if (!ret_sts)
-+ return 0;
-+
-+ ret = aeon_ipc_wait_cmd(phydev, curr_parity);
-+ if (ret)
-+ return ret;
-+
-+ ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, VEND1_IPC_STS);
-+ if (ret < 0)
-+ return ret;
-+
-+ *ret_sts = ret;
-+ if ((*ret_sts & AEON_IPC_STS_STATUS) != AEON_IPC_STS_STATUS_SUCCESS)
-+ return -EINVAL;
-+
-+ return 0;
-+}
-+
-+/* If data is NULL, return 0 or negative error.
-+ * If data not NULL, return number of Bytes received from IPC or
-+ * a negative error.
-+ */
-+static int aeon_ipc_send_msg(struct phy_device *phydev,
-+ u16 opcode, u16 *data, unsigned int data_len,
-+ u16 *ret_data)
-+{
-+ struct as21xxx_priv *priv = phydev->priv;
-+ unsigned int ret_size;
-+ u16 cmd, ret_sts;
-+ int ret;
-+ int i;
-+
-+ /* IPC have a max of 8 register to transfer data,
-+ * make sure we never exceed this.
-+ */
-+ if (data_len > AEON_IPC_DATA_MAX)
-+ return -EINVAL;
-+
-+ for (i = 0; i < data_len / sizeof(u16); i++)
-+ phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_IPC_DATA(i),
-+ data[i]);
-+
-+ cmd = FIELD_PREP(AEON_IPC_CMD_SIZE, data_len) |
-+ FIELD_PREP(AEON_IPC_CMD_OPCODE, opcode);
-+
-+ mutex_lock(&priv->ipc_lock);
-+
-+ ret = aeon_ipc_send_cmd(phydev, priv, cmd, &ret_sts);
-+ if (ret) {
-+ phydev_err(phydev, "failed to send ipc msg for %x: %d\n",
-+ opcode, ret);
-+ goto out;
-+ }
-+
-+ if (!data)
-+ goto out;
-+
-+ if ((ret_sts & AEON_IPC_STS_STATUS) == AEON_IPC_STS_STATUS_ERROR) {
-+ ret = -EINVAL;
-+ goto out;
-+ }
-+
-+ /* Prevent IPC from stack smashing the kernel.
-+ * We can't trust IPC to return a good value and we always
-+ * preallocate space for 16 Bytes.
-+ */
-+ ret_size = FIELD_GET(AEON_IPC_STS_SIZE, ret_sts);
-+ if (ret_size > AEON_IPC_DATA_MAX) {
-+ ret = -EINVAL;
-+ goto out;
-+ }
-+
-+ /* Read data from IPC data register for ret_size value from IPC */
-+ for (i = 0; i < DIV_ROUND_UP(ret_size, sizeof(u16)); i++) {
-+ ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, VEND1_IPC_DATA(i));
-+ if (ret < 0)
-+ goto out;
-+
-+ ret_data[i] = ret;
-+ }
-+
-+ ret = ret_size;
-+
-+out:
-+ mutex_unlock(&priv->ipc_lock);
-+
-+ return ret;
-+}
-+
-+static int aeon_ipc_noop(struct phy_device *phydev,
-+ struct as21xxx_priv *priv, u16 *ret_sts)
-+{
-+ u16 cmd;
-+
-+ cmd = FIELD_PREP(AEON_IPC_CMD_SIZE, 0) |
-+ FIELD_PREP(AEON_IPC_CMD_OPCODE, IPC_CMD_NOOP);
-+
-+ return aeon_ipc_send_cmd(phydev, priv, cmd, ret_sts);
-+}
-+
-+/* Logic to sync parity bit with IPC.
-+ * We send 2 NOP cmd with same partity and we wait for IPC
-+ * to handle the packet only for the second one. This way
-+ * we make sure we are sync for every next cmd.
-+ */
-+static int aeon_ipc_sync_parity(struct phy_device *phydev,
-+ struct as21xxx_priv *priv)
-+{
-+ u16 ret_sts;
-+ int ret;
-+
-+ mutex_lock(&priv->ipc_lock);
-+
-+ /* Send NOP with no parity */
-+ aeon_ipc_noop(phydev, priv, NULL);
-+
-+ /* Reset packet parity */
-+ priv->parity_status = false;
-+
-+ /* Send second NOP with no parity */
-+ ret = aeon_ipc_noop(phydev, priv, &ret_sts);
-+
-+ mutex_unlock(&priv->ipc_lock);
-+
-+ /* We expect to return -EINVAL */
-+ if (ret != -EINVAL)
-+ return ret;
-+
-+ if ((ret_sts & AEON_IPC_STS_STATUS) != AEON_IPC_STS_STATUS_READY) {
-+ phydev_err(phydev, "Invalid IPC status on sync parity: %x\n",
-+ ret_sts);
-+ return -EINVAL;
-+ }
-+
-+ return 0;
-+}
-+
-+static int aeon_ipc_get_fw_version(struct phy_device *phydev)
-+{
-+ u16 ret_data[AEON_IPC_DATA_NUM_REGISTERS], data[1];
-+ char fw_version[AEON_IPC_DATA_MAX + 1];
-+ int ret;
-+
-+ data[0] = IPC_INFO_VERSION;
-+
-+ ret = aeon_ipc_send_msg(phydev, IPC_CMD_INFO, data,
-+ sizeof(data), ret_data);
-+ if (ret < 0)
-+ return ret;
-+
-+ /* Make sure FW version is NULL terminated */
-+ memcpy(fw_version, ret_data, ret);
-+ fw_version[ret] = '\0';
-+
-+ phydev_info(phydev, "Firmware Version: %s\n", fw_version);
-+
-+ return 0;
-+}
-+
-+static int aeon_dpc_ra_enable(struct phy_device *phydev)
-+{
-+ u16 data[2];
-+
-+ data[0] = IPC_CFG_PARAM_DIRECT;
-+ data[1] = IPC_CFG_PARAM_DIRECT_DPC_RA;
-+
-+ return aeon_ipc_send_msg(phydev, IPC_CMD_CFG_PARAM, data,
-+ sizeof(data), NULL);
-+}
-+
-+static int as21xxx_probe(struct phy_device *phydev)
-+{
-+ struct as21xxx_priv *priv;
-+ int ret;
-+
-+ priv = devm_kzalloc(&phydev->mdio.dev,
-+ sizeof(*priv), GFP_KERNEL);
-+ if (!priv)
-+ return -ENOMEM;
-+ phydev->priv = priv;
-+
-+ ret = devm_mutex_init(&phydev->mdio.dev,
-+ &priv->ipc_lock);
-+ if (ret)
-+ return ret;
-+
-+ ret = aeon_ipc_sync_parity(phydev, priv);
-+ if (ret)
-+ return ret;
-+
-+ ret = aeon_ipc_get_fw_version(phydev);
-+ if (ret)
-+ return ret;
-+
-+ /* Enable PTP clk if not already Enabled */
-+ ret = phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_PTP_CLK,
-+ VEND1_PTP_CLK_EN);
-+ if (ret)
-+ return ret;
-+
-+ return aeon_dpc_ra_enable(phydev);
-+}
-+
-+static int as21xxx_read_link(struct phy_device *phydev, int *bmcr)
-+{
-+ int status;
-+
-+ /* Normal C22 BMCR report inconsistent data, use
-+ * the mapped C22 in C45 to have more consistent link info.
-+ */
-+ *bmcr = phy_read_mmd(phydev, MDIO_MMD_AN,
-+ AS21XXX_MDIO_AN_C22 + MII_BMCR);
-+ if (*bmcr < 0)
-+ return *bmcr;
-+
-+ /* Autoneg is being started, therefore disregard current
-+ * link status and report link as down.
-+ */
-+ if (*bmcr & BMCR_ANRESTART) {
-+ phydev->link = 0;
-+ return 0;
-+ }
-+
-+ status = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_STAT1);
-+ if (status < 0)
-+ return status;
-+
-+ phydev->link = !!(status & MDIO_STAT1_LSTATUS);
-+
-+ return 0;
-+}
-+
-+static int as21xxx_read_c22_lpa(struct phy_device *phydev)
-+{
-+ int lpagb;
-+
-+ /* MII_STAT1000 are only filled in the mapped C22
-+ * in C45, use that to fill lpagb values and check.
-+ */
-+ lpagb = phy_read_mmd(phydev, MDIO_MMD_AN,
-+ AS21XXX_MDIO_AN_C22 + MII_STAT1000);
-+ if (lpagb < 0)
-+ return lpagb;
-+
-+ if (lpagb & LPA_1000MSFAIL) {
-+ int adv = phy_read_mmd(phydev, MDIO_MMD_AN,
-+ AS21XXX_MDIO_AN_C22 + MII_CTRL1000);
-+
-+ if (adv < 0)
-+ return adv;
-+
-+ if (adv & CTL1000_ENABLE_MASTER)
-+ phydev_err(phydev, "Master/Slave resolution failed, maybe conflicting manual settings?\n");
-+ else
-+ phydev_err(phydev, "Master/Slave resolution failed\n");
-+ return -ENOLINK;
-+ }
-+
-+ mii_stat1000_mod_linkmode_lpa_t(phydev->lp_advertising,
-+ lpagb);
-+
-+ return 0;
-+}
-+
-+static int as21xxx_read_status(struct phy_device *phydev)
-+{
-+ int bmcr, old_link = phydev->link;
-+ int ret;
-+
-+ ret = as21xxx_read_link(phydev, &bmcr);
-+ if (ret)
-+ return ret;
-+
-+ /* why bother the PHY if nothing can have changed */
-+ if (phydev->autoneg == AUTONEG_ENABLE && old_link && phydev->link)
-+ return 0;
-+
-+ phydev->speed = SPEED_UNKNOWN;
-+ phydev->duplex = DUPLEX_UNKNOWN;
-+ phydev->pause = 0;
-+ phydev->asym_pause = 0;
-+
-+ if (phydev->autoneg == AUTONEG_ENABLE) {
-+ ret = genphy_c45_read_lpa(phydev);
-+ if (ret)
-+ return ret;
-+
-+ ret = as21xxx_read_c22_lpa(phydev);
-+ if (ret)
-+ return ret;
-+
-+ phy_resolve_aneg_linkmode(phydev);
-+ } else {
-+ int speed;
-+
-+ linkmode_zero(phydev->lp_advertising);
-+
-+ speed = phy_read_mmd(phydev, MDIO_MMD_VEND1,
-+ VEND1_SPEED_STATUS);
-+ if (speed < 0)
-+ return speed;
-+
-+ switch (speed & VEND1_SPEED_STATUS) {
-+ case VEND1_SPEED_10000:
-+ phydev->speed = SPEED_10000;
-+ phydev->duplex = DUPLEX_FULL;
-+ break;
-+ case VEND1_SPEED_5000:
-+ phydev->speed = SPEED_5000;
-+ phydev->duplex = DUPLEX_FULL;
-+ break;
-+ case VEND1_SPEED_2500:
-+ phydev->speed = SPEED_2500;
-+ phydev->duplex = DUPLEX_FULL;
-+ break;
-+ case VEND1_SPEED_1000:
-+ phydev->speed = SPEED_1000;
-+ if (bmcr & BMCR_FULLDPLX)
-+ phydev->duplex = DUPLEX_FULL;
-+ else
-+ phydev->duplex = DUPLEX_HALF;
-+ break;
-+ case VEND1_SPEED_100:
-+ phydev->speed = SPEED_100;
-+ phydev->duplex = DUPLEX_FULL;
-+ break;
-+ case VEND1_SPEED_10:
-+ phydev->speed = SPEED_10;
-+ phydev->duplex = DUPLEX_FULL;
-+ break;
-+ default:
-+ return -EINVAL;
-+ }
-+ }
-+
-+ return 0;
-+}
-+
-+static int as21xxx_led_brightness_set(struct phy_device *phydev,
-+ u8 index, enum led_brightness value)
-+{
-+ u16 val = VEND1_LED_REG_A_EVENT_OFF;
-+
-+ if (index > AEON_MAX_LEDS)
-+ return -EINVAL;
-+
-+ if (value)
-+ val = VEND1_LED_REG_A_EVENT_ON;
-+
-+ return phy_modify_mmd(phydev, MDIO_MMD_VEND1,
-+ VEND1_LED_REG(index),
-+ VEND1_LED_REG_A_EVENT,
-+ FIELD_PREP(VEND1_LED_REG_A_EVENT, val));
-+}
-+
-+static int as21xxx_led_hw_is_supported(struct phy_device *phydev, u8 index,
-+ unsigned long rules)
-+{
-+ int i;
-+
-+ if (index > AEON_MAX_LEDS)
-+ return -EINVAL;
-+
-+ for (i = 0; i < ARRAY_SIZE(as21xxx_led_supported_pattern); i++)
-+ if (rules == as21xxx_led_supported_pattern[i].pattern)
-+ return 0;
-+
-+ return -EOPNOTSUPP;
-+}
-+
-+static int as21xxx_led_hw_control_get(struct phy_device *phydev, u8 index,
-+ unsigned long *rules)
-+{
-+ int i, val;
-+
-+ if (index > AEON_MAX_LEDS)
-+ return -EINVAL;
-+
-+ val = phy_read_mmd(phydev, MDIO_MMD_VEND1, VEND1_LED_REG(index));
-+ if (val < 0)
-+ return val;
-+
-+ val = FIELD_GET(VEND1_LED_REG_A_EVENT, val);
-+ for (i = 0; i < ARRAY_SIZE(as21xxx_led_supported_pattern); i++)
-+ if (val == as21xxx_led_supported_pattern[i].val) {
-+ *rules = as21xxx_led_supported_pattern[i].pattern;
-+ return 0;
-+ }
-+
-+ /* Should be impossible */
-+ return -EINVAL;
-+}
-+
-+static int as21xxx_led_hw_control_set(struct phy_device *phydev, u8 index,
-+ unsigned long rules)
-+{
-+ u16 val = 0;
-+ int i;
-+
-+ if (index > AEON_MAX_LEDS)
-+ return -EINVAL;
-+
-+ for (i = 0; i < ARRAY_SIZE(as21xxx_led_supported_pattern); i++)
-+ if (rules == as21xxx_led_supported_pattern[i].pattern) {
-+ val = as21xxx_led_supported_pattern[i].val;
-+ break;
-+ }
-+
-+ return phy_modify_mmd(phydev, MDIO_MMD_VEND1,
-+ VEND1_LED_REG(index),
-+ VEND1_LED_REG_A_EVENT,
-+ FIELD_PREP(VEND1_LED_REG_A_EVENT, val));
-+}
-+
-+static int as21xxx_led_polarity_set(struct phy_device *phydev, int index,
-+ unsigned long modes)
-+{
-+ bool led_active_low = false;
-+ u16 mask, val = 0;
-+ u32 mode;
-+
-+ if (index > AEON_MAX_LEDS)
-+ return -EINVAL;
-+
-+ for_each_set_bit(mode, &modes, __PHY_LED_MODES_NUM) {
-+ switch (mode) {
-+ case PHY_LED_ACTIVE_LOW:
-+ led_active_low = true;
-+ break;
-+ case PHY_LED_ACTIVE_HIGH: /* default mode */
-+ led_active_low = false;
-+ break;
-+ default:
-+ return -EINVAL;
-+ }
-+ }
-+
-+ mask = VEND1_GLB_CPU_CTRL_LED_POLARITY(index);
-+ if (led_active_low)
-+ val = VEND1_GLB_CPU_CTRL_LED_POLARITY(index);
-+
-+ return phy_modify_mmd(phydev, MDIO_MMD_VEND1,
-+ VEND1_GLB_REG_CPU_CTRL,
-+ mask, val);
-+}
-+
-+static int as21xxx_match_phy_device(struct phy_device *phydev,
-+ const struct phy_driver *phydrv)
-+{
-+ struct as21xxx_priv *priv;
-+ u16 ret_sts;
-+ u32 phy_id;
-+ int ret;
-+
-+ /* Skip PHY that are not AS21xxx or already have firmware loaded */
-+ if (phydev->c45_ids.device_ids[MDIO_MMD_PCS] != PHY_ID_AS21XXX)
-+ return genphy_match_phy_device(phydev, (struct phy_driver *)phydrv);
-+
-+ /* Read PHY ID to handle firmware just loaded */
-+ ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MII_PHYSID1);
-+ if (ret < 0)
-+ return ret;
-+ phy_id = ret << 16;
-+
-+ ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MII_PHYSID2);
-+ if (ret < 0)
-+ return ret;
-+ phy_id |= ret;
-+
-+ /* With PHY ID not the generic AS21xxx one assume
-+ * the firmware just loaded
-+ */
-+ if (phy_id != PHY_ID_AS21XXX)
-+ return phy_id == phydrv->phy_id;
-+
-+ /* Allocate temp priv and load the firmware */
-+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
-+ if (!priv)
-+ return -ENOMEM;
-+
-+ mutex_init(&priv->ipc_lock);
-+
-+ ret = aeon_firmware_load(phydev);
-+ if (ret)
-+ goto out;
-+
-+ /* Sync parity... */
-+ ret = aeon_ipc_sync_parity(phydev, priv);
-+ if (ret)
-+ goto out;
-+
-+ /* ...and send a third NOOP cmd to wait for firmware finish loading */
-+ ret = aeon_ipc_noop(phydev, priv, &ret_sts);
-+ if (ret)
-+ goto out;
-+
-+out:
-+ mutex_destroy(&priv->ipc_lock);
-+ kfree(priv);
-+
-+ /* Return can either be 0 or a negative error code.
-+ * Returning 0 here means THIS is NOT a suitable PHY.
-+ *
-+ * For the specific case of the generic Aeonsemi PHY ID that
-+ * needs the firmware the be loaded first to have a correct PHY ID,
-+ * this is OK as a matching PHY ID will be found right after.
-+ * This relies on the driver probe order where the first PHY driver
-+ * probed is the generic one.
-+ */
-+ return ret;
-+}
-+
-+static struct phy_driver as21xxx_drivers[] = {
-+ {
-+ /* PHY expose in C45 as 0x7500 0x9410
-+ * before firmware is loaded.
-+ * This driver entry must be attempted first to load
-+ * the firmware and thus update the ID registers.
-+ */
-+ PHY_ID_MATCH_EXACT(PHY_ID_AS21XXX),
-+ .name = "Aeonsemi AS21xxx",
-+ .match_phy_device = as21xxx_match_phy_device,
-+ },
-+ {
-+ PHY_ID_MATCH_EXACT(PHY_ID_AS21011JB1),
-+ .name = "Aeonsemi AS21011JB1",
-+ .probe = as21xxx_probe,
-+ .match_phy_device = as21xxx_match_phy_device,
-+ .read_status = as21xxx_read_status,
-+ .led_brightness_set = as21xxx_led_brightness_set,
-+ .led_hw_is_supported = as21xxx_led_hw_is_supported,
-+ .led_hw_control_set = as21xxx_led_hw_control_set,
-+ .led_hw_control_get = as21xxx_led_hw_control_get,
-+ .led_polarity_set = as21xxx_led_polarity_set,
-+ },
-+ {
-+ PHY_ID_MATCH_EXACT(PHY_ID_AS21011PB1),
-+ .name = "Aeonsemi AS21011PB1",
-+ .probe = as21xxx_probe,
-+ .match_phy_device = as21xxx_match_phy_device,
-+ .read_status = as21xxx_read_status,
-+ .led_brightness_set = as21xxx_led_brightness_set,
-+ .led_hw_is_supported = as21xxx_led_hw_is_supported,
-+ .led_hw_control_set = as21xxx_led_hw_control_set,
-+ .led_hw_control_get = as21xxx_led_hw_control_get,
-+ .led_polarity_set = as21xxx_led_polarity_set,
-+ },
-+ {
-+ PHY_ID_MATCH_EXACT(PHY_ID_AS21010PB1),
-+ .name = "Aeonsemi AS21010PB1",
-+ .probe = as21xxx_probe,
-+ .match_phy_device = as21xxx_match_phy_device,
-+ .read_status = as21xxx_read_status,
-+ .led_brightness_set = as21xxx_led_brightness_set,
-+ .led_hw_is_supported = as21xxx_led_hw_is_supported,
-+ .led_hw_control_set = as21xxx_led_hw_control_set,
-+ .led_hw_control_get = as21xxx_led_hw_control_get,
-+ .led_polarity_set = as21xxx_led_polarity_set,
-+ },
-+ {
-+ PHY_ID_MATCH_EXACT(PHY_ID_AS21010JB1),
-+ .name = "Aeonsemi AS21010JB1",
-+ .probe = as21xxx_probe,
-+ .match_phy_device = as21xxx_match_phy_device,
-+ .read_status = as21xxx_read_status,
-+ .led_brightness_set = as21xxx_led_brightness_set,
-+ .led_hw_is_supported = as21xxx_led_hw_is_supported,
-+ .led_hw_control_set = as21xxx_led_hw_control_set,
-+ .led_hw_control_get = as21xxx_led_hw_control_get,
-+ .led_polarity_set = as21xxx_led_polarity_set,
-+ },
-+ {
-+ PHY_ID_MATCH_EXACT(PHY_ID_AS21210PB1),
-+ .name = "Aeonsemi AS21210PB1",
-+ .probe = as21xxx_probe,
-+ .match_phy_device = as21xxx_match_phy_device,
-+ .read_status = as21xxx_read_status,
-+ .led_brightness_set = as21xxx_led_brightness_set,
-+ .led_hw_is_supported = as21xxx_led_hw_is_supported,
-+ .led_hw_control_set = as21xxx_led_hw_control_set,
-+ .led_hw_control_get = as21xxx_led_hw_control_get,
-+ .led_polarity_set = as21xxx_led_polarity_set,
-+ },
-+ {
-+ PHY_ID_MATCH_EXACT(PHY_ID_AS21510JB1),
-+ .name = "Aeonsemi AS21510JB1",
-+ .probe = as21xxx_probe,
-+ .match_phy_device = as21xxx_match_phy_device,
-+ .read_status = as21xxx_read_status,
-+ .led_brightness_set = as21xxx_led_brightness_set,
-+ .led_hw_is_supported = as21xxx_led_hw_is_supported,
-+ .led_hw_control_set = as21xxx_led_hw_control_set,
-+ .led_hw_control_get = as21xxx_led_hw_control_get,
-+ .led_polarity_set = as21xxx_led_polarity_set,
-+ },
-+ {
-+ PHY_ID_MATCH_EXACT(PHY_ID_AS21510PB1),
-+ .name = "Aeonsemi AS21510PB1",
-+ .probe = as21xxx_probe,
-+ .match_phy_device = as21xxx_match_phy_device,
-+ .read_status = as21xxx_read_status,
-+ .led_brightness_set = as21xxx_led_brightness_set,
-+ .led_hw_is_supported = as21xxx_led_hw_is_supported,
-+ .led_hw_control_set = as21xxx_led_hw_control_set,
-+ .led_hw_control_get = as21xxx_led_hw_control_get,
-+ .led_polarity_set = as21xxx_led_polarity_set,
-+ },
-+ {
-+ PHY_ID_MATCH_EXACT(PHY_ID_AS21511JB1),
-+ .name = "Aeonsemi AS21511JB1",
-+ .probe = as21xxx_probe,
-+ .match_phy_device = as21xxx_match_phy_device,
-+ .read_status = as21xxx_read_status,
-+ .led_brightness_set = as21xxx_led_brightness_set,
-+ .led_hw_is_supported = as21xxx_led_hw_is_supported,
-+ .led_hw_control_set = as21xxx_led_hw_control_set,
-+ .led_hw_control_get = as21xxx_led_hw_control_get,
-+ .led_polarity_set = as21xxx_led_polarity_set,
-+ },
-+ {
-+ PHY_ID_MATCH_EXACT(PHY_ID_AS21210JB1),
-+ .name = "Aeonsemi AS21210JB1",
-+ .probe = as21xxx_probe,
-+ .match_phy_device = as21xxx_match_phy_device,
-+ .read_status = as21xxx_read_status,
-+ .led_brightness_set = as21xxx_led_brightness_set,
-+ .led_hw_is_supported = as21xxx_led_hw_is_supported,
-+ .led_hw_control_set = as21xxx_led_hw_control_set,
-+ .led_hw_control_get = as21xxx_led_hw_control_get,
-+ .led_polarity_set = as21xxx_led_polarity_set,
-+ },
-+ {
-+ PHY_ID_MATCH_EXACT(PHY_ID_AS21511PB1),
-+ .name = "Aeonsemi AS21511PB1",
-+ .probe = as21xxx_probe,
-+ .match_phy_device = as21xxx_match_phy_device,
-+ .read_status = as21xxx_read_status,
-+ .led_brightness_set = as21xxx_led_brightness_set,
-+ .led_hw_is_supported = as21xxx_led_hw_is_supported,
-+ .led_hw_control_set = as21xxx_led_hw_control_set,
-+ .led_hw_control_get = as21xxx_led_hw_control_get,
-+ .led_polarity_set = as21xxx_led_polarity_set,
-+ },
-+};
-+module_phy_driver(as21xxx_drivers);
-+
-+static struct mdio_device_id __maybe_unused as21xxx_tbl[] = {
-+ { PHY_ID_MATCH_VENDOR(PHY_VENDOR_AEONSEMI) },
-+ { }
-+};
-+MODULE_DEVICE_TABLE(mdio, as21xxx_tbl);
-+
-+MODULE_DESCRIPTION("Aeonsemi AS21xxx PHY driver");
-+MODULE_LICENSE("GPL");
+++ /dev/null
-From a9b24b3583ae1da7dbda031f141264f2da260219 Mon Sep 17 00:00:00 2001
-Date: Tue, 24 Jun 2025 16:17:33 +0200
-Subject: [PATCH] net: phy: realtek: add error handling to rtl8211f_get_wol
-
-We should check if the WOL settings was successfully read from the PHY.
-
-In case this fails we cannot just use the error code and proceed.
-
----
- drivers/net/phy/realtek/realtek_main.c | 10 ++++++++--
- 1 file changed, 8 insertions(+), 2 deletions(-)
-
---- a/drivers/net/phy/realtek/realtek_main.c
-+++ b/drivers/net/phy/realtek/realtek_main.c
-@@ -436,9 +436,15 @@ static irqreturn_t rtl8211f_handle_inter
-
- static void rtl8211f_get_wol(struct phy_device *dev, struct ethtool_wolinfo *wol)
- {
-+ int wol_events;
-+
- wol->supported = WAKE_MAGIC;
-- if (phy_read_paged(dev, RTL8211F_WOL_SETTINGS_PAGE, RTL8211F_WOL_SETTINGS_EVENTS)
-- & RTL8211F_WOL_EVENT_MAGIC)
-+
-+ wol_events = phy_read_paged(dev, RTL8211F_WOL_SETTINGS_PAGE, RTL8211F_WOL_SETTINGS_EVENTS);
-+ if (wol_events < 0)
-+ return;
-+
-+ if (wol_events & RTL8211F_WOL_EVENT_MAGIC)
- wol->wolopts = WAKE_MAGIC;
- }
-
+++ /dev/null
-From f63f21e82ecafd288b100ea161247820bf1e92c4 Mon Sep 17 00:00:00 2001
-Date: Mon, 25 Aug 2025 23:09:49 +0200
-Subject: [PATCH] net: phy: realtek: support for TRIGGER_NETDEV_LINK on
- RTL8211E and RTL8211F
-
-This patch adds support for the TRIGGER_NETDEV_LINK trigger. It activates
-the LED when a link is established, regardless of the speed.
-
-Tested on Orange Pi PC2 with RTL8211E PHY.
-
----
- drivers/net/phy/realtek/realtek_main.c | 39 +++++++++++++++++++++-----
- 1 file changed, 32 insertions(+), 7 deletions(-)
-
---- a/drivers/net/phy/realtek/realtek_main.c
-+++ b/drivers/net/phy/realtek/realtek_main.c
-@@ -648,7 +648,8 @@ static int rtl821x_resume(struct phy_dev
- static int rtl8211x_led_hw_is_supported(struct phy_device *phydev, u8 index,
- unsigned long rules)
- {
-- const unsigned long mask = BIT(TRIGGER_NETDEV_LINK_10) |
-+ const unsigned long mask = BIT(TRIGGER_NETDEV_LINK) |
-+ BIT(TRIGGER_NETDEV_LINK_10) |
- BIT(TRIGGER_NETDEV_LINK_100) |
- BIT(TRIGGER_NETDEV_LINK_1000) |
- BIT(TRIGGER_NETDEV_RX) |
-@@ -706,6 +707,12 @@ static int rtl8211f_led_hw_control_get(s
- if (val & RTL8211F_LEDCR_LINK_1000)
- __set_bit(TRIGGER_NETDEV_LINK_1000, rules);
-
-+ if ((val & RTL8211F_LEDCR_LINK_10) &&
-+ (val & RTL8211F_LEDCR_LINK_100) &&
-+ (val & RTL8211F_LEDCR_LINK_1000)) {
-+ __set_bit(TRIGGER_NETDEV_LINK, rules);
-+ }
-+
- if (val & RTL8211F_LEDCR_ACT_TXRX) {
- __set_bit(TRIGGER_NETDEV_RX, rules);
- __set_bit(TRIGGER_NETDEV_TX, rules);
-@@ -723,14 +730,20 @@ static int rtl8211f_led_hw_control_set(s
- if (index >= RTL8211x_LED_COUNT)
- return -EINVAL;
-
-- if (test_bit(TRIGGER_NETDEV_LINK_10, &rules))
-+ if (test_bit(TRIGGER_NETDEV_LINK, &rules) ||
-+ test_bit(TRIGGER_NETDEV_LINK_10, &rules)) {
- reg |= RTL8211F_LEDCR_LINK_10;
-+ }
-
-- if (test_bit(TRIGGER_NETDEV_LINK_100, &rules))
-+ if (test_bit(TRIGGER_NETDEV_LINK, &rules) ||
-+ test_bit(TRIGGER_NETDEV_LINK_100, &rules)) {
- reg |= RTL8211F_LEDCR_LINK_100;
-+ }
-
-- if (test_bit(TRIGGER_NETDEV_LINK_1000, &rules))
-+ if (test_bit(TRIGGER_NETDEV_LINK, &rules) ||
-+ test_bit(TRIGGER_NETDEV_LINK_1000, &rules)) {
- reg |= RTL8211F_LEDCR_LINK_1000;
-+ }
-
- if (test_bit(TRIGGER_NETDEV_RX, &rules) ||
- test_bit(TRIGGER_NETDEV_TX, &rules)) {
-@@ -778,6 +791,12 @@ static int rtl8211e_led_hw_control_get(s
- if (cr2 & RTL8211E_LEDCR2_LINK_1000)
- __set_bit(TRIGGER_NETDEV_LINK_1000, rules);
-
-+ if ((cr2 & RTL8211E_LEDCR2_LINK_10) &&
-+ (cr2 & RTL8211E_LEDCR2_LINK_100) &&
-+ (cr2 & RTL8211E_LEDCR2_LINK_1000)) {
-+ __set_bit(TRIGGER_NETDEV_LINK, rules);
-+ }
-+
- return ret;
- }
-
-@@ -805,14 +824,20 @@ static int rtl8211e_led_hw_control_set(s
- if (ret < 0)
- return ret;
-
-- if (test_bit(TRIGGER_NETDEV_LINK_10, &rules))
-+ if (test_bit(TRIGGER_NETDEV_LINK, &rules) ||
-+ test_bit(TRIGGER_NETDEV_LINK_10, &rules)) {
- cr2 |= RTL8211E_LEDCR2_LINK_10;
-+ }
-
-- if (test_bit(TRIGGER_NETDEV_LINK_100, &rules))
-+ if (test_bit(TRIGGER_NETDEV_LINK, &rules) ||
-+ test_bit(TRIGGER_NETDEV_LINK_100, &rules)) {
- cr2 |= RTL8211E_LEDCR2_LINK_100;
-+ }
-
-- if (test_bit(TRIGGER_NETDEV_LINK_1000, &rules))
-+ if (test_bit(TRIGGER_NETDEV_LINK, &rules) ||
-+ test_bit(TRIGGER_NETDEV_LINK_1000, &rules)) {
- cr2 |= RTL8211E_LEDCR2_LINK_1000;
-+ }
-
- cr2 <<= RTL8211E_LEDCR2_SHIFT * index;
- ret = rtl821x_modify_ext_page(phydev, RTL8211E_LEDCR_EXT_PAGE,
+++ /dev/null
-From 2c67301584f2671e320236df6bbe75ae09feb4d0 Mon Sep 17 00:00:00 2001
-Date: Sat, 11 Oct 2025 13:02:49 +0200
-Subject: [PATCH] net: phy: realtek: Avoid PHYCR2 access if PHYCR2 not present
-
-The driver is currently checking for PHYCR2 register presence in
-rtl8211f_config_init(), but it does so after accessing PHYCR2 to
-disable EEE. This was introduced in commit bfc17c165835 ("net:
-phy: realtek: disable PHY-mode EEE"). Move the PHYCR2 presence
-test before the EEE disablement and simplify the code.
-
-Fixes: bfc17c165835 ("net: phy: realtek: disable PHY-mode EEE")
----
- drivers/net/phy/realtek/realtek_main.c | 23 +++++++++++------------
- 1 file changed, 11 insertions(+), 12 deletions(-)
-
---- a/drivers/net/phy/realtek/realtek_main.c
-+++ b/drivers/net/phy/realtek/realtek_main.c
-@@ -589,26 +589,25 @@ static int rtl8211f_config_init(struct p
- str_enabled_disabled(val_rxdly));
- }
-
-+ if (!priv->has_phycr2)
-+ return 0;
-+
- /* Disable PHY-mode EEE so LPI is passed to the MAC */
- ret = phy_modify_paged(phydev, RTL8211F_PHYCR_PAGE, RTL8211F_PHYCR2,
- RTL8211F_PHYCR2_PHY_EEE_ENABLE, 0);
- if (ret)
- return ret;
-
-- if (priv->has_phycr2) {
-- ret = phy_modify_paged(phydev, RTL8211F_PHYCR_PAGE,
-- RTL8211F_PHYCR2, RTL8211F_CLKOUT_EN,
-- priv->phycr2);
-- if (ret < 0) {
-- dev_err(dev, "clkout configuration failed: %pe\n",
-- ERR_PTR(ret));
-- return ret;
-- }
--
-- return genphy_soft_reset(phydev);
-+ ret = phy_modify_paged(phydev, RTL8211F_PHYCR_PAGE,
-+ RTL8211F_PHYCR2, RTL8211F_CLKOUT_EN,
-+ priv->phycr2);
-+ if (ret < 0) {
-+ dev_err(dev, "clkout configuration failed: %pe\n",
-+ ERR_PTR(ret));
-+ return ret;
- }
-
-- return 0;
-+ return genphy_soft_reset(phydev);
- }
-
- static int rtl821x_suspend(struct phy_device *phydev)
+++ /dev/null
-From ffff5c8fc2af2218a3332b3d5b97654599d50cde Mon Sep 17 00:00:00 2001
-Date: Thu, 16 Oct 2025 21:22:52 +0200
-Subject: [PATCH] net: phy: realtek: fix rtl8221b-vm-cg name
-
-When splitting the RTL8221B-VM-CG into C22 and C45 variants, the name was
-accidentally changed to RTL8221B-VN-CG. This patch brings back the previous
-part number.
-
-Fixes: ad5ce743a6b0 ("net: phy: realtek: Add driver instances for rtl8221b via Clause 45")
----
- drivers/net/phy/realtek/realtek_main.c | 16 ++++++++--------
- 1 file changed, 8 insertions(+), 8 deletions(-)
-
---- a/drivers/net/phy/realtek/realtek_main.c
-+++ b/drivers/net/phy/realtek/realtek_main.c
-@@ -156,7 +156,7 @@
- #define RTL_8211FVD_PHYID 0x001cc878
- #define RTL_8221B 0x001cc840
- #define RTL_8221B_VB_CG 0x001cc849
--#define RTL_8221B_VN_CG 0x001cc84a
-+#define RTL_8221B_VM_CG 0x001cc84a
- #define RTL_8251B 0x001cc862
- #define RTL_8261C 0x001cc890
-
-@@ -1387,16 +1387,16 @@ static int rtl8221b_vb_cg_c45_match_phy_
- return rtlgen_is_c45_match(phydev, RTL_8221B_VB_CG, true);
- }
-
--static int rtl8221b_vn_cg_c22_match_phy_device(struct phy_device *phydev,
-+static int rtl8221b_vm_cg_c22_match_phy_device(struct phy_device *phydev,
- const struct phy_driver *phydrv)
- {
-- return rtlgen_is_c45_match(phydev, RTL_8221B_VN_CG, false);
-+ return rtlgen_is_c45_match(phydev, RTL_8221B_VM_CG, false);
- }
-
--static int rtl8221b_vn_cg_c45_match_phy_device(struct phy_device *phydev,
-+static int rtl8221b_vm_cg_c45_match_phy_device(struct phy_device *phydev,
- const struct phy_driver *phydrv)
- {
-- return rtlgen_is_c45_match(phydev, RTL_8221B_VN_CG, true);
-+ return rtlgen_is_c45_match(phydev, RTL_8221B_VM_CG, true);
- }
-
- static int rtl_internal_nbaset_match_phy_device(struct phy_device *phydev,
-@@ -1743,7 +1743,7 @@ static struct phy_driver realtek_drvs[]
- .suspend = genphy_c45_pma_suspend,
- .resume = rtlgen_c45_resume,
- }, {
-- .match_phy_device = rtl8221b_vn_cg_c22_match_phy_device,
-+ .match_phy_device = rtl8221b_vm_cg_c22_match_phy_device,
- .name = "RTL8221B-VM-CG 2.5Gbps PHY (C22)",
- .probe = rtl822x_probe,
- .get_features = rtl822x_get_features,
-@@ -1756,8 +1756,8 @@ static struct phy_driver realtek_drvs[]
- .read_page = rtl821x_read_page,
- .write_page = rtl821x_write_page,
- }, {
-- .match_phy_device = rtl8221b_vn_cg_c45_match_phy_device,
-- .name = "RTL8221B-VN-CG 2.5Gbps PHY (C45)",
-+ .match_phy_device = rtl8221b_vm_cg_c45_match_phy_device,
-+ .name = "RTL8221B-VM-CG 2.5Gbps PHY (C45)",
- .probe = rtl822x_probe,
- .config_init = rtl822xb_config_init,
- .get_rate_matching = rtl822xb_get_rate_matching,
+++ /dev/null
-From 61958b33ef0bab1c1874c933cd3910f495526782 Mon Sep 17 00:00:00 2001
-Date: Fri, 24 Oct 2025 11:49:00 +0200
-Subject: [PATCH] net: phy: realtek: Add RTL8224 cable testing support
-
-The RTL8224 can detect open pairs and short types (in same pair or some
-other pair). The distance to this problem can be estimated. This is done
-for each of the 4 pairs separately.
-
-It is not meant to be run while there is an active link partner because
-this interferes with the active test pulses.
-
-Output with open 50 m cable:
-
- Pair A code Open Circuit, source: TDR
- Pair A, fault length: 51.79m, source: TDR
- Pair B code Open Circuit, source: TDR
- Pair B, fault length: 51.28m, source: TDR
- Pair C code Open Circuit, source: TDR
- Pair C, fault length: 50.46m, source: TDR
- Pair D code Open Circuit, source: TDR
- Pair D, fault length: 51.12m, source: TDR
-
-Terminated cable:
-
- Pair A code OK, source: TDR
- Pair B code OK, source: TDR
- Pair C code OK, source: TDR
- Pair D code OK, source: TDR
-
-Shorted cable (both short types are at roughly the same distance)
-
- Pair A code Short to another pair, source: TDR
- Pair A, fault length: 2.35m, source: TDR
- Pair B code Short to another pair, source: TDR
- Pair B, fault length: 2.15m, source: TDR
- Pair C code OK, source: TDR
- Pair D code Short within Pair, source: TDR
- Pair D, fault length: 1.94m, source: TDR
-
----
- drivers/net/phy/realtek/realtek_main.c | 187 +++++++++++++++++++++++++
- 1 file changed, 187 insertions(+)
-
---- a/drivers/net/phy/realtek/realtek_main.c
-+++ b/drivers/net/phy/realtek/realtek_main.c
-@@ -8,6 +8,7 @@
- * Copyright (c) 2004 Freescale Semiconductor, Inc.
- */
- #include <linux/bitops.h>
-+#include <linux/ethtool_netlink.h>
- #include <linux/of.h>
- #include <linux/phy.h>
- #include <linux/netdevice.h>
-@@ -129,6 +130,27 @@
- */
- #define RTL822X_VND2_C22_REG(reg) (0xa400 + 2 * (reg))
-
-+#define RTL8224_MII_RTCT 0x11
-+#define RTL8224_MII_RTCT_ENABLE BIT(0)
-+#define RTL8224_MII_RTCT_PAIR_A BIT(4)
-+#define RTL8224_MII_RTCT_PAIR_B BIT(5)
-+#define RTL8224_MII_RTCT_PAIR_C BIT(6)
-+#define RTL8224_MII_RTCT_PAIR_D BIT(7)
-+#define RTL8224_MII_RTCT_DONE BIT(15)
-+
-+#define RTL8224_MII_SRAM_ADDR 0x1b
-+#define RTL8224_MII_SRAM_DATA 0x1c
-+
-+#define RTL8224_SRAM_RTCT_FAULT(pair) (0x8026 + (pair) * 4)
-+#define RTL8224_SRAM_RTCT_FAULT_BUSY BIT(0)
-+#define RTL8224_SRAM_RTCT_FAULT_OPEN BIT(3)
-+#define RTL8224_SRAM_RTCT_FAULT_SAME_SHORT BIT(4)
-+#define RTL8224_SRAM_RTCT_FAULT_OK BIT(5)
-+#define RTL8224_SRAM_RTCT_FAULT_DONE BIT(6)
-+#define RTL8224_SRAM_RTCT_FAULT_CROSS_SHORT BIT(7)
-+
-+#define RTL8224_SRAM_RTCT_LEN(pair) (0x8028 + (pair) * 4)
-+
- #define RTL8366RB_POWER_SAVE 0x15
- #define RTL8366RB_POWER_SAVE_ON BIT(12)
-
-@@ -1317,6 +1339,168 @@ static int rtl822xb_c45_read_status(stru
- return 0;
- }
-
-+static int rtl8224_cable_test_start(struct phy_device *phydev)
-+{
-+ u32 val;
-+ int ret;
-+
-+ /* disable auto-negotiation and force 1000/Full */
-+ ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2,
-+ RTL822X_VND2_C22_REG(MII_BMCR),
-+ BMCR_ANENABLE | BMCR_SPEED100 | BMCR_SPEED10,
-+ BMCR_SPEED1000 | BMCR_FULLDPLX);
-+ if (ret)
-+ return ret;
-+
-+ mdelay(500);
-+
-+ /* trigger cable test */
-+ val = RTL8224_MII_RTCT_ENABLE;
-+ val |= RTL8224_MII_RTCT_PAIR_A;
-+ val |= RTL8224_MII_RTCT_PAIR_B;
-+ val |= RTL8224_MII_RTCT_PAIR_C;
-+ val |= RTL8224_MII_RTCT_PAIR_D;
-+
-+ return phy_modify_mmd(phydev, MDIO_MMD_VEND2,
-+ RTL822X_VND2_C22_REG(RTL8224_MII_RTCT),
-+ RTL8224_MII_RTCT_DONE, val);
-+}
-+
-+static int rtl8224_sram_read(struct phy_device *phydev, u32 reg)
-+{
-+ int ret;
-+
-+ ret = phy_write_mmd(phydev, MDIO_MMD_VEND2,
-+ RTL822X_VND2_C22_REG(RTL8224_MII_SRAM_ADDR),
-+ reg);
-+ if (ret)
-+ return ret;
-+
-+ return phy_read_mmd(phydev, MDIO_MMD_VEND2,
-+ RTL822X_VND2_C22_REG(RTL8224_MII_SRAM_DATA));
-+}
-+
-+static int rtl8224_pair_len_get(struct phy_device *phydev, u32 pair)
-+{
-+ int cable_len;
-+ u32 reg_len;
-+ int ret;
-+ u32 cm;
-+
-+ reg_len = RTL8224_SRAM_RTCT_LEN(pair);
-+
-+ ret = rtl8224_sram_read(phydev, reg_len);
-+ if (ret < 0)
-+ return ret;
-+
-+ cable_len = ret & 0xff00;
-+
-+ ret = rtl8224_sram_read(phydev, reg_len + 1);
-+ if (ret < 0)
-+ return ret;
-+
-+ cable_len |= (ret & 0xff00) >> 8;
-+
-+ cable_len -= 620;
-+ cable_len = max(cable_len, 0);
-+
-+ cm = cable_len * 100 / 78;
-+
-+ return cm;
-+}
-+
-+static int rtl8224_cable_test_result_trans(u32 result)
-+{
-+ if (!(result & RTL8224_SRAM_RTCT_FAULT_DONE))
-+ return -EBUSY;
-+
-+ if (result & RTL8224_SRAM_RTCT_FAULT_OK)
-+ return ETHTOOL_A_CABLE_RESULT_CODE_OK;
-+
-+ if (result & RTL8224_SRAM_RTCT_FAULT_OPEN)
-+ return ETHTOOL_A_CABLE_RESULT_CODE_OPEN;
-+
-+ if (result & RTL8224_SRAM_RTCT_FAULT_SAME_SHORT)
-+ return ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT;
-+
-+ if (result & RTL8224_SRAM_RTCT_FAULT_BUSY)
-+ return ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC;
-+
-+ if (result & RTL8224_SRAM_RTCT_FAULT_CROSS_SHORT)
-+ return ETHTOOL_A_CABLE_RESULT_CODE_CROSS_SHORT;
-+
-+ return ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC;
-+}
-+
-+static int rtl8224_cable_test_report_pair(struct phy_device *phydev, unsigned int pair)
-+{
-+ int fault_rslt;
-+ int ret;
-+
-+ ret = rtl8224_sram_read(phydev, RTL8224_SRAM_RTCT_FAULT(pair));
-+ if (ret < 0)
-+ return ret;
-+
-+ fault_rslt = rtl8224_cable_test_result_trans(ret);
-+ if (fault_rslt < 0)
-+ return 0;
-+
-+ ret = ethnl_cable_test_result(phydev, pair, fault_rslt);
-+ if (ret < 0)
-+ return ret;
-+
-+ switch (fault_rslt) {
-+ case ETHTOOL_A_CABLE_RESULT_CODE_OPEN:
-+ case ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT:
-+ case ETHTOOL_A_CABLE_RESULT_CODE_CROSS_SHORT:
-+ ret = rtl8224_pair_len_get(phydev, pair);
-+ if (ret < 0)
-+ return ret;
-+
-+ return ethnl_cable_test_fault_length(phydev, pair, ret);
-+ default:
-+ return 0;
-+ }
-+}
-+
-+static int rtl8224_cable_test_report(struct phy_device *phydev, bool *finished)
-+{
-+ unsigned int pair;
-+ int ret;
-+
-+ for (pair = ETHTOOL_A_CABLE_PAIR_A; pair <= ETHTOOL_A_CABLE_PAIR_D; pair++) {
-+ ret = rtl8224_cable_test_report_pair(phydev, pair);
-+ if (ret == -EBUSY) {
-+ *finished = false;
-+ return 0;
-+ }
-+
-+ if (ret < 0)
-+ return ret;
-+ }
-+
-+ return 0;
-+}
-+
-+static int rtl8224_cable_test_get_status(struct phy_device *phydev, bool *finished)
-+{
-+ int ret;
-+
-+ *finished = false;
-+
-+ ret = phy_read_mmd(phydev, MDIO_MMD_VEND2,
-+ RTL822X_VND2_C22_REG(RTL8224_MII_RTCT));
-+ if (ret < 0)
-+ return ret;
-+
-+ if (!(ret & RTL8224_MII_RTCT_DONE))
-+ return 0;
-+
-+ *finished = true;
-+
-+ return rtl8224_cable_test_report(phydev, finished);
-+}
-+
- static bool rtlgen_supports_2_5gbps(struct phy_device *phydev)
- {
- int val;
-@@ -1794,11 +1978,14 @@ static struct phy_driver realtek_drvs[]
- }, {
- PHY_ID_MATCH_EXACT(0x001ccad0),
- .name = "RTL8224 2.5Gbps PHY",
-+ .flags = PHY_POLL_CABLE_TEST,
- .get_features = rtl822x_c45_get_features,
- .config_aneg = rtl822x_c45_config_aneg,
- .read_status = rtl822x_c45_read_status,
- .suspend = genphy_c45_pma_suspend,
- .resume = rtlgen_c45_resume,
-+ .cable_test_start = rtl8224_cable_test_start,
-+ .cable_test_get_status = rtl8224_cable_test_get_status,
- }, {
- PHY_ID_MATCH_EXACT(0x001cc961),
- .name = "RTL8366RB Gigabit Ethernet",
+++ /dev/null
-From 18aa36238a4d835c1644dcccd63d32c7fdd4b310 Mon Sep 17 00:00:00 2001
-Date: Sun, 2 Nov 2025 16:26:37 +0100
-Subject: [PATCH] net: phy: realtek: add interrupt support for RTL8221B
-
-This commit introduces interrupt support for RTL8221B (C45 mode).
-Interrupts are mapped on the VEND2 page. VEND2 registers are only
-accessible via C45 reads and cannot be accessed by C45 over C22.
-
-[Enable only link state change interrupts]
----
- drivers/net/phy/realtek/realtek_main.c | 56 ++++++++++++++++++++++++++
- 1 file changed, 56 insertions(+)
-
---- a/drivers/net/phy/realtek/realtek_main.c
-+++ b/drivers/net/phy/realtek/realtek_main.c
-@@ -130,6 +130,11 @@
- */
- #define RTL822X_VND2_C22_REG(reg) (0xa400 + 2 * (reg))
-
-+#define RTL8221B_VND2_INER 0xa4d2
-+#define RTL8221B_VND2_INER_LINK_STATUS BIT(4)
-+
-+#define RTL8221B_VND2_INSR 0xa4d4
-+
- #define RTL8224_MII_RTCT 0x11
- #define RTL8224_MII_RTCT_ENABLE BIT(0)
- #define RTL8224_MII_RTCT_PAIR_A BIT(4)
-@@ -1744,6 +1749,53 @@ static irqreturn_t rtl9000a_handle_inter
- return IRQ_HANDLED;
- }
-
-+static int rtl8221b_ack_interrupt(struct phy_device *phydev)
-+{
-+ int err;
-+
-+ err = phy_read_mmd(phydev, MDIO_MMD_VEND2, RTL8221B_VND2_INSR);
-+
-+ return (err < 0) ? err : 0;
-+}
-+
-+static int rtl8221b_config_intr(struct phy_device *phydev)
-+{
-+ int err;
-+
-+ if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
-+ err = rtl8221b_ack_interrupt(phydev);
-+ if (err)
-+ return err;
-+
-+ err = phy_write_mmd(phydev, MDIO_MMD_VEND2, RTL8221B_VND2_INER,
-+ RTL8221B_VND2_INER_LINK_STATUS);
-+ } else {
-+ err = phy_write_mmd(phydev, MDIO_MMD_VEND2,
-+ RTL8221B_VND2_INER, 0);
-+ if (err)
-+ return err;
-+
-+ err = rtl8221b_ack_interrupt(phydev);
-+ }
-+
-+ return err;
-+}
-+
-+static irqreturn_t rtl8221b_handle_interrupt(struct phy_device *phydev)
-+{
-+ int err;
-+
-+ err = rtl8221b_ack_interrupt(phydev);
-+ if (err) {
-+ phy_error(phydev);
-+ return IRQ_NONE;
-+ }
-+
-+ phy_trigger_machine(phydev);
-+
-+ return IRQ_HANDLED;
-+}
-+
- static struct phy_driver realtek_drvs[] = {
- {
- PHY_ID_MATCH_EXACT(0x00008201),
-@@ -1918,6 +1970,8 @@ static struct phy_driver realtek_drvs[]
- }, {
- .match_phy_device = rtl8221b_vb_cg_c45_match_phy_device,
- .name = "RTL8221B-VB-CG 2.5Gbps PHY (C45)",
-+ .config_intr = rtl8221b_config_intr,
-+ .handle_interrupt = rtl8221b_handle_interrupt,
- .probe = rtl822x_probe,
- .config_init = rtl822xb_config_init,
- .get_rate_matching = rtl822xb_get_rate_matching,
-@@ -1942,6 +1996,8 @@ static struct phy_driver realtek_drvs[]
- }, {
- .match_phy_device = rtl8221b_vm_cg_c45_match_phy_device,
- .name = "RTL8221B-VM-CG 2.5Gbps PHY (C45)",
-+ .config_intr = rtl8221b_config_intr,
-+ .handle_interrupt = rtl8221b_handle_interrupt,
- .probe = rtl822x_probe,
- .config_init = rtl822xb_config_init,
- .get_rate_matching = rtl822xb_get_rate_matching,
+++ /dev/null
-From 2f3ce7a56c6e02bc0b258507f3a82b7511f62f9e Mon Sep 17 00:00:00 2001
-Date: Tue, 21 Nov 2023 18:20:24 +0100
-Subject: net: sfp: rework the RollBall PHY waiting code
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-RollBall SFP modules allow the access to PHY registers only after a
-certain time has passed. Until then, the registers read 0xffff.
-
-Currently we have quirks for modules where we need to wait either 25
-seconds or 4 seconds, but recently I got hands on another module where
-the wait is even shorter.
-
-Instead of hardcoding different wait times, lets rework the code:
-- increase the PHY retry count to 25
-- when RollBall module is detected, increase the PHY retry time from
- 50ms to 1s
-
----
- drivers/net/phy/sfp.c | 41 +++++++++++++++++++++--------------------
- 1 file changed, 21 insertions(+), 20 deletions(-)
-
---- a/drivers/net/phy/sfp.c
-+++ b/drivers/net/phy/sfp.c
-@@ -191,7 +191,7 @@ static const enum gpiod_flags gpio_flags
- * R_PHY_RETRY is the number of attempts.
- */
- #define T_PHY_RETRY msecs_to_jiffies(50)
--#define R_PHY_RETRY 12
-+#define R_PHY_RETRY 25
-
- /* SFP module presence detection is poor: the three MOD DEF signals are
- * the same length on the PCB, which means it's possible for MOD DEF 0 to
-@@ -274,7 +274,7 @@ struct sfp {
- struct sfp_eeprom_id id;
- unsigned int module_power_mW;
- unsigned int module_t_start_up;
-- unsigned int module_t_wait;
-+ unsigned int phy_t_retry;
-
- unsigned int rate_kbd;
- unsigned int rs_threshold_kbd;
-@@ -357,18 +357,22 @@ static void sfp_fixup_10gbaset_30m(struc
- sfp->id.base.extended_cc = SFF8024_ECC_10GBASE_T_SR;
- }
-
--static void sfp_fixup_rollball_proto(struct sfp *sfp, unsigned int secs)
-+static void sfp_fixup_rollball(struct sfp *sfp)
- {
- sfp->mdio_protocol = MDIO_I2C_ROLLBALL;
-- sfp->module_t_wait = msecs_to_jiffies(secs * 1000);
-+
-+ /* RollBall modules may disallow access to PHY registers for up to 25
-+ * seconds, and the reads return 0xffff before that. Increase the time
-+ * between PHY probe retries from 50ms to 1s so that we will wait for
-+ * the PHY for a sufficient amount of time.
-+ */
-+ sfp->phy_t_retry = msecs_to_jiffies(1000);
- }
-
- static void sfp_fixup_fs_10gt(struct sfp *sfp)
- {
- sfp_fixup_10gbaset_30m(sfp);
--
-- // These SFPs need 4 seconds before the PHY can be accessed
-- sfp_fixup_rollball_proto(sfp, 4);
-+ sfp_fixup_rollball(sfp);
- }
-
- static void sfp_fixup_halny_gsfp(struct sfp *sfp)
-@@ -380,12 +384,6 @@ static void sfp_fixup_halny_gsfp(struct
- sfp->state_hw_mask &= ~(SFP_F_TX_FAULT | SFP_F_LOS);
- }
-
--static void sfp_fixup_rollball(struct sfp *sfp)
--{
-- // Rollball SFPs need 25 seconds before the PHY can be accessed
-- sfp_fixup_rollball_proto(sfp, 25);
--}
--
- static void sfp_fixup_rollball_cc(struct sfp *sfp)
- {
- sfp_fixup_rollball(sfp);
-@@ -2322,7 +2320,7 @@ static int sfp_sm_mod_probe(struct sfp *
- mask |= SFP_F_RS1;
-
- sfp->module_t_start_up = T_START_UP;
-- sfp->module_t_wait = T_WAIT;
-+ sfp->phy_t_retry = T_PHY_RETRY;
-
- sfp->state_ignore_mask = 0;
-
-@@ -2558,10 +2556,9 @@ static void sfp_sm_main(struct sfp *sfp,
-
- /* We need to check the TX_FAULT state, which is not defined
- * while TX_DISABLE is asserted. The earliest we want to do
-- * anything (such as probe for a PHY) is 50ms (or more on
-- * specific modules).
-+ * anything (such as probe for a PHY) is 50ms.
- */
-- sfp_sm_next(sfp, SFP_S_WAIT, sfp->module_t_wait);
-+ sfp_sm_next(sfp, SFP_S_WAIT, T_WAIT);
- break;
-
- case SFP_S_WAIT:
-@@ -2575,8 +2572,8 @@ static void sfp_sm_main(struct sfp *sfp,
- * deasserting.
- */
- timeout = sfp->module_t_start_up;
-- if (timeout > sfp->module_t_wait)
-- timeout -= sfp->module_t_wait;
-+ if (timeout > T_WAIT)
-+ timeout -= T_WAIT;
- else
- timeout = 1;
-
-@@ -2619,7 +2616,11 @@ static void sfp_sm_main(struct sfp *sfp,
- ret = sfp_sm_probe_for_phy(sfp);
- if (ret == -ENODEV) {
- if (--sfp->sm_phy_retries) {
-- sfp_sm_next(sfp, SFP_S_INIT_PHY, T_PHY_RETRY);
-+ sfp_sm_next(sfp, SFP_S_INIT_PHY,
-+ sfp->phy_t_retry);
-+ dev_dbg(sfp->dev,
-+ "no PHY detected, %u tries left\n",
-+ sfp->sm_phy_retries);
- break;
- } else {
- dev_info(sfp->dev, "no PHY detected\n");
+++ /dev/null
-From e9301af385e7864dea353f5e58cad7339dd6c718 Mon Sep 17 00:00:00 2001
-Date: Tue, 19 Dec 2023 17:24:15 +0100
-Subject: net: sfp: fix PHY discovery for FS SFP-10G-T module
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Commit 2f3ce7a56c6e ("net: sfp: rework the RollBall PHY waiting code")
-changed the long wait before accessing RollBall / FS modules into
-probing for PHY every 1 second, and trying 25 times.
-
-Wei Lei reports that this does not work correctly on FS modules: when
-initializing, they may report values different from 0xffff in PHY ID
-registers for some MMDs, causing get_phy_c45_ids() to find some bogus
-MMD.
-
-Fix this by adding the module_t_wait member back, and setting it to 4
-seconds for FS modules.
-
-Fixes: 2f3ce7a56c6e ("net: sfp: rework the RollBall PHY waiting code")
----
- drivers/net/phy/sfp.c | 17 +++++++++++++----
- 1 file changed, 13 insertions(+), 4 deletions(-)
-
---- a/drivers/net/phy/sfp.c
-+++ b/drivers/net/phy/sfp.c
-@@ -274,6 +274,7 @@ struct sfp {
- struct sfp_eeprom_id id;
- unsigned int module_power_mW;
- unsigned int module_t_start_up;
-+ unsigned int module_t_wait;
- unsigned int phy_t_retry;
-
- unsigned int rate_kbd;
-@@ -373,6 +374,12 @@ static void sfp_fixup_fs_10gt(struct sfp
- {
- sfp_fixup_10gbaset_30m(sfp);
- sfp_fixup_rollball(sfp);
-+
-+ /* The RollBall fixup is not enough for FS modules, the AQR chip inside
-+ * them does not return 0xffff for PHY ID registers in all MMDs for the
-+ * while initializing. They need a 4 second wait before accessing PHY.
-+ */
-+ sfp->module_t_wait = msecs_to_jiffies(4000);
- }
-
- static void sfp_fixup_halny_gsfp(struct sfp *sfp)
-@@ -2320,6 +2327,7 @@ static int sfp_sm_mod_probe(struct sfp *
- mask |= SFP_F_RS1;
-
- sfp->module_t_start_up = T_START_UP;
-+ sfp->module_t_wait = T_WAIT;
- sfp->phy_t_retry = T_PHY_RETRY;
-
- sfp->state_ignore_mask = 0;
-@@ -2556,9 +2564,10 @@ static void sfp_sm_main(struct sfp *sfp,
-
- /* We need to check the TX_FAULT state, which is not defined
- * while TX_DISABLE is asserted. The earliest we want to do
-- * anything (such as probe for a PHY) is 50ms.
-+ * anything (such as probe for a PHY) is 50ms (or more on
-+ * specific modules).
- */
-- sfp_sm_next(sfp, SFP_S_WAIT, T_WAIT);
-+ sfp_sm_next(sfp, SFP_S_WAIT, sfp->module_t_wait);
- break;
-
- case SFP_S_WAIT:
-@@ -2572,8 +2581,8 @@ static void sfp_sm_main(struct sfp *sfp,
- * deasserting.
- */
- timeout = sfp->module_t_start_up;
-- if (timeout > T_WAIT)
-- timeout -= T_WAIT;
-+ if (timeout > sfp->module_t_wait)
-+ timeout -= sfp->module_t_wait;
- else
- timeout = 1;
-
+++ /dev/null
-From 6999e0fc9a552ce98fcc66bee3dca7e55fba0ed3 Mon Sep 17 00:00:00 2001
-Date: Tue, 23 Apr 2024 10:50:38 +0200
-Subject: net: sfp: update comment for FS SFP-10G-T quirk
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Update the comment for the Fibrestore SFP-10G-T module: since commit
-e9301af385e7 ("net: sfp: fix PHY discovery for FS SFP-10G-T module")
-we also do a 4 second wait before probing the PHY.
-
-Fixes: e9301af385e7 ("net: sfp: fix PHY discovery for FS SFP-10G-T module")
----
- drivers/net/phy/sfp.c | 5 +++--
- 1 file changed, 3 insertions(+), 2 deletions(-)
-
---- a/drivers/net/phy/sfp.c
-+++ b/drivers/net/phy/sfp.c
-@@ -454,8 +454,9 @@ static const struct sfp_quirk sfp_quirks
- SFP_QUIRK("ALCATELLUCENT", "3FE46541AA", sfp_quirk_2500basex,
- sfp_fixup_long_startup),
-
-- // Fiberstore SFP-10G-T doesn't identify as copper, and uses the
-- // Rollball protocol to talk to the PHY.
-+ // Fiberstore SFP-10G-T doesn't identify as copper, uses the Rollball
-+ // protocol to talk to the PHY and needs 4 sec wait before probing the
-+ // PHY.
- SFP_QUIRK_F("FS", "SFP-10G-T", sfp_fixup_fs_10gt),
-
- // Fiberstore GPON-ONU-34-20BI can operate at 2500base-X, but report 1.2GBd
+++ /dev/null
-From cd4a32e60061789676f7f018a94fcc9ec56732a0 Mon Sep 17 00:00:00 2001
-Date: Tue, 23 Apr 2024 10:50:39 +0200
-Subject: net: sfp: enhance quirk for Fibrestore 2.5G copper SFP module
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Enhance the quirk for Fibrestore 2.5G copper SFP module. The original
-commit e27aca3760c0 ("net: sfp: add quirk for FS's 2.5G copper SFP")
-introducing the quirk says that the PHY is inaccessible, but that is
-not true.
-
-The module uses Rollball protocol to talk to the PHY, and needs a 4
-second wait before probing it, same as FS 10G module.
-
-The PHY inside the module is Realtek RTL8221B-VB-CG PHY. The realtek
-driver recently gained support to set it up via clause 45 accesses.
-
----
- drivers/net/phy/sfp.c | 18 ++++++++++++------
- 1 file changed, 12 insertions(+), 6 deletions(-)
-
---- a/drivers/net/phy/sfp.c
-+++ b/drivers/net/phy/sfp.c
-@@ -370,18 +370,23 @@ static void sfp_fixup_rollball(struct sf
- sfp->phy_t_retry = msecs_to_jiffies(1000);
- }
-
--static void sfp_fixup_fs_10gt(struct sfp *sfp)
-+static void sfp_fixup_fs_2_5gt(struct sfp *sfp)
- {
-- sfp_fixup_10gbaset_30m(sfp);
- sfp_fixup_rollball(sfp);
-
-- /* The RollBall fixup is not enough for FS modules, the AQR chip inside
-+ /* The RollBall fixup is not enough for FS modules, the PHY chip inside
- * them does not return 0xffff for PHY ID registers in all MMDs for the
- * while initializing. They need a 4 second wait before accessing PHY.
- */
- sfp->module_t_wait = msecs_to_jiffies(4000);
- }
-
-+static void sfp_fixup_fs_10gt(struct sfp *sfp)
-+{
-+ sfp_fixup_10gbaset_30m(sfp);
-+ sfp_fixup_fs_2_5gt(sfp);
-+}
-+
- static void sfp_fixup_halny_gsfp(struct sfp *sfp)
- {
- /* Ignore the TX_FAULT and LOS signals on this module.
-@@ -459,6 +464,10 @@ static const struct sfp_quirk sfp_quirks
- // PHY.
- SFP_QUIRK_F("FS", "SFP-10G-T", sfp_fixup_fs_10gt),
-
-+ // Fiberstore SFP-2.5G-T uses Rollball protocol to talk to the PHY and
-+ // needs 4 sec wait before probing the PHY.
-+ SFP_QUIRK_F("FS", "SFP-2.5G-T", sfp_fixup_fs_2_5gt),
-+
- // Fiberstore GPON-ONU-34-20BI can operate at 2500base-X, but report 1.2GBd
- // NRZ in their EEPROM
- SFP_QUIRK("FS", "GPON-ONU-34-20BI", sfp_quirk_2500basex,
-@@ -475,9 +484,6 @@ static const struct sfp_quirk sfp_quirks
- SFP_QUIRK("HUAWEI", "MA5671A", sfp_quirk_2500basex,
- sfp_fixup_ignore_tx_fault),
-
-- // FS 2.5G Base-T
-- SFP_QUIRK_M("FS", "SFP-2.5G-T", sfp_quirk_oem_2_5g),
--
- // Lantech 8330-262D-E can operate at 2500base-X, but incorrectly report
- // 2500MBd NRZ in their EEPROM
- SFP_QUIRK_M("Lantech", "8330-262D-E", sfp_quirk_2500basex),
+++ /dev/null
-From 05ec5c085eb7ae044d49e04a3cff194a0b2a3251 Mon Sep 17 00:00:00 2001
-Date: Thu, 27 Feb 2025 08:10:58 +0100
-Subject: net: sfp: add quirk for FS SFP-10GM-T copper SFP+ module
-
-Add quirk for a copper SFP that identifies itself as "FS" "SFP-10GM-T".
-It uses RollBall protocol to talk to the PHY and needs 4 sec wait before
-probing the PHY.
-
----
- drivers/net/phy/sfp.c | 11 ++++++-----
- 1 file changed, 6 insertions(+), 5 deletions(-)
-
---- a/drivers/net/phy/sfp.c
-+++ b/drivers/net/phy/sfp.c
-@@ -370,7 +370,7 @@ static void sfp_fixup_rollball(struct sf
- sfp->phy_t_retry = msecs_to_jiffies(1000);
- }
-
--static void sfp_fixup_fs_2_5gt(struct sfp *sfp)
-+static void sfp_fixup_rollball_wait4s(struct sfp *sfp)
- {
- sfp_fixup_rollball(sfp);
-
-@@ -384,7 +384,7 @@ static void sfp_fixup_fs_2_5gt(struct sf
- static void sfp_fixup_fs_10gt(struct sfp *sfp)
- {
- sfp_fixup_10gbaset_30m(sfp);
-- sfp_fixup_fs_2_5gt(sfp);
-+ sfp_fixup_rollball_wait4s(sfp);
- }
-
- static void sfp_fixup_halny_gsfp(struct sfp *sfp)
-@@ -464,9 +464,10 @@ static const struct sfp_quirk sfp_quirks
- // PHY.
- SFP_QUIRK_F("FS", "SFP-10G-T", sfp_fixup_fs_10gt),
-
-- // Fiberstore SFP-2.5G-T uses Rollball protocol to talk to the PHY and
-- // needs 4 sec wait before probing the PHY.
-- SFP_QUIRK_F("FS", "SFP-2.5G-T", sfp_fixup_fs_2_5gt),
-+ // Fiberstore SFP-2.5G-T and SFP-10GM-T uses Rollball protocol to talk
-+ // to the PHY and needs 4 sec wait before probing the PHY.
-+ SFP_QUIRK_F("FS", "SFP-2.5G-T", sfp_fixup_rollball_wait4s),
-+ SFP_QUIRK_F("FS", "SFP-10GM-T", sfp_fixup_rollball_wait4s),
-
- // Fiberstore GPON-ONU-34-20BI can operate at 2500base-X, but report 1.2GBd
- // NRZ in their EEPROM
+++ /dev/null
-From 1c77c721916ae108c2c5865986735bfe92000908 Mon Sep 17 00:00:00 2001
-Date: Tue, 9 Apr 2024 09:30:16 +0200
-Subject: [PATCH] net: sfp: add quirk for another multigig RollBall transceiver
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Add quirk for another RollBall copper transceiver: Turris RTSFP-2.5G,
-containing 2.5g capable RTL8221B PHY.
-
-
----
- drivers/net/phy/sfp.c | 1 +
- 1 file changed, 1 insertion(+)
-
---- a/drivers/net/phy/sfp.c
-+++ b/drivers/net/phy/sfp.c
-@@ -505,6 +505,7 @@ static const struct sfp_quirk sfp_quirks
- SFP_QUIRK_M("OEM", "SFP-2.5G-BX10-U", sfp_quirk_2500basex),
- SFP_QUIRK_F("OEM", "RTSFP-10", sfp_fixup_rollball_cc),
- SFP_QUIRK_F("OEM", "RTSFP-10G", sfp_fixup_rollball_cc),
-+ SFP_QUIRK_F("Turris", "RTSFP-2.5G", sfp_fixup_rollball),
- SFP_QUIRK_F("Turris", "RTSFP-10", sfp_fixup_rollball),
- SFP_QUIRK_F("Turris", "RTSFP-10G", sfp_fixup_rollball),
- };
+++ /dev/null
-From ddbf0e78a8b20ec18d314d31336a0230fdc9b394 Mon Sep 17 00:00:00 2001
-Date: Sun, 31 Aug 2025 12:59:07 +0200
-Subject: net: sfp: add quirk for FLYPRO copper SFP+ module
-
-Add quirk for a copper SFP that identifies itself as "FLYPRO"
-"SFP-10GT-CS-30M". It uses RollBall protocol to talk to the PHY.
-
----
- drivers/net/phy/sfp.c | 3 +++
- 1 file changed, 3 insertions(+)
-
---- a/drivers/net/phy/sfp.c
-+++ b/drivers/net/phy/sfp.c
-@@ -459,6 +459,9 @@ static const struct sfp_quirk sfp_quirks
- SFP_QUIRK("ALCATELLUCENT", "3FE46541AA", sfp_quirk_2500basex,
- sfp_fixup_long_startup),
-
-+ // FLYPRO SFP-10GT-CS-30M uses Rollball protocol to talk to the PHY.
-+ SFP_QUIRK_F("FLYPRO", "SFP-10GT-CS-30M", sfp_fixup_rollball),
-+
- // Fiberstore SFP-10G-T doesn't identify as copper, uses the Rollball
- // protocol to talk to the PHY and needs 4 sec wait before probing the
- // PHY.
+++ /dev/null
-From b91ef50f70e7c092c50c1b92e63ef3fb0041cdd4 Mon Sep 17 00:00:00 2001
-Date: Mon, 18 Sep 2023 21:19:12 +0200
-Subject: [PATCH 01/30] net: dsa: mt7530: Convert to platform remove callback
- returning void
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-The .remove() callback for a platform driver returns an int which makes
-many driver authors wrongly assume it's possible to do error handling by
-returning an error code. However the value returned is ignored (apart
-from emitting a warning) and this typically results in resource leaks.
-To improve here there is a quest to make the remove callback return
-void. In the first step of this quest all drivers are converted to
-.remove_new() which already returns void. Eventually after all drivers
-are converted, .remove_new() is renamed to .remove().
-
-Trivially convert this driver from always returning zero in the remove
-callback to the void returning variant.
-
----
- drivers/net/dsa/mt7530-mmio.c | 7 ++-----
- 1 file changed, 2 insertions(+), 5 deletions(-)
-
---- a/drivers/net/dsa/mt7530-mmio.c
-+++ b/drivers/net/dsa/mt7530-mmio.c
-@@ -63,15 +63,12 @@ mt7988_probe(struct platform_device *pde
- return dsa_register_switch(priv->ds);
- }
-
--static int
--mt7988_remove(struct platform_device *pdev)
-+static void mt7988_remove(struct platform_device *pdev)
- {
- struct mt7530_priv *priv = platform_get_drvdata(pdev);
-
- if (priv)
- mt7530_remove_common(priv);
--
-- return 0;
- }
-
- static void mt7988_shutdown(struct platform_device *pdev)
-@@ -88,7 +85,7 @@ static void mt7988_shutdown(struct platf
-
- static struct platform_driver mt7988_platform_driver = {
- .probe = mt7988_probe,
-- .remove = mt7988_remove,
-+ .remove_new = mt7988_remove,
- .shutdown = mt7988_shutdown,
- .driver = {
- .name = "mt7530-mmio",
+++ /dev/null
-From d22c85764665af931c5c61bbe282b4116a88e792 Mon Sep 17 00:00:00 2001
-Date: Wed, 27 Sep 2023 13:13:56 +0100
-Subject: [PATCH 02/30] net: dsa: mt753x: remove mt753x_phylink_pcs_link_up()
-
-Remove the mt753x_phylink_pcs_link_up() function for two reasons:
-
-1) priv->pcs[i].pcs.neg_mode is set true, meaning it doesn't take a
- MLO_AN_FIXED anymore, but one of PHYLINK_PCS_NEG_*. However, this
- is inconsequential due to...
-2) priv->pcs[port].pcs.ops is always initialised to point at
- mt7530_pcs_ops, which does not have a pcs_link_up() member.
-
-So, let's remove mt753x_phylink_pcs_link_up() entirely.
-
----
- drivers/net/dsa/mt7530.c | 11 -----------
- 1 file changed, 11 deletions(-)
-
---- a/drivers/net/dsa/mt7530.c
-+++ b/drivers/net/dsa/mt7530.c
-@@ -3033,15 +3033,6 @@ static void mt753x_phylink_mac_link_down
- mt7530_clear(priv, MT7530_PMCR_P(port), PMCR_LINK_SETTINGS_MASK);
- }
-
--static void mt753x_phylink_pcs_link_up(struct phylink_pcs *pcs,
-- unsigned int mode,
-- phy_interface_t interface,
-- int speed, int duplex)
--{
-- if (pcs->ops->pcs_link_up)
-- pcs->ops->pcs_link_up(pcs, mode, interface, speed, duplex);
--}
--
- static void mt753x_phylink_mac_link_up(struct dsa_switch *ds, int port,
- unsigned int mode,
- phy_interface_t interface,
-@@ -3129,8 +3120,6 @@ mt7531_cpu_port_config(struct dsa_switch
- return ret;
- mt7530_write(priv, MT7530_PMCR_P(port),
- PMCR_CPU_PORT_SETTING(priv->id));
-- mt753x_phylink_pcs_link_up(&priv->pcs[port].pcs, MLO_AN_FIXED,
-- interface, speed, DUPLEX_FULL);
- mt753x_phylink_mac_link_up(ds, port, MLO_AN_FIXED, interface, NULL,
- speed, DUPLEX_FULL, true, true);
-
+++ /dev/null
-From 9b4f1f5a0801652056670a38503b4049eb413caf Mon Sep 17 00:00:00 2001
-Date: Mon, 9 Oct 2023 18:29:19 +0000
-Subject: [PATCH 03/30] net: dsa: mt7530: replace deprecated strncpy with
- ethtool_sprintf
-
-`strncpy` is deprecated for use on NUL-terminated destination strings
-[1] and as such we should prefer more robust and less ambiguous string
-interfaces.
-
-ethtool_sprintf() is designed specifically for get_strings() usage.
-Let's replace strncpy in favor of this more robust and easier to
-understand interface.
-
-Link: https://www.kernel.org/doc/html/latest/process/deprecated.html#strncpy-on-nul-terminated-strings [1]
-Link: https://manpages.debian.org/testing/linux-manual-4.8/strscpy.9.en.html [2]
-Link: https://github.com/KSPP/linux/issues/90
-Link: https://lore.kernel.org/r/20231009-strncpy-drivers-net-dsa-mt7530-c-v1-1-ec6677a6436a@google.com
----
- drivers/net/dsa/mt7530.c | 3 +--
- 1 file changed, 1 insertion(+), 2 deletions(-)
-
---- a/drivers/net/dsa/mt7530.c
-+++ b/drivers/net/dsa/mt7530.c
-@@ -836,8 +836,7 @@ mt7530_get_strings(struct dsa_switch *ds
- return;
-
- for (i = 0; i < ARRAY_SIZE(mt7530_mib); i++)
-- strncpy(data + i * ETH_GSTRING_LEN, mt7530_mib[i].name,
-- ETH_GSTRING_LEN);
-+ ethtool_sprintf(&data, "%s", mt7530_mib[i].name);
- }
-
- static void
+++ /dev/null
-From af26b0d1bf934bbaa7cafb871a51e95087a088a0 Mon Sep 17 00:00:00 2001
-Date: Mon, 22 Jan 2024 08:34:31 +0300
-Subject: [PATCH 04/30] net: dsa: mt7530: support OF-based registration of
- switch MDIO bus
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Currently the MDIO bus of the switches the MT7530 DSA subdriver controls
-can only be registered as non-OF-based. Bring support for registering the
-bus OF-based.
-
-The subdrivers that control switches [with MDIO bus] probed on OF must
-follow this logic to support all cases properly:
-
-No switch MDIO bus defined: Populate ds->user_mii_bus, register the MDIO
-bus, set the interrupts for PHYs if "interrupt-controller" is defined at
-the switch node. This case should only be covered for the switches which
-their dt-bindings documentation didn't document the MDIO bus from the
-start. This is to keep supporting the device trees that do not describe the
-MDIO bus on the device tree but the MDIO bus is being used nonetheless.
-
-Switch MDIO bus defined: Don't populate ds->user_mii_bus, register the MDIO
-bus, set the interrupts for PHYs if ["interrupt-controller" is defined at
-the switch node and "interrupts" is defined at the PHY nodes under the
-switch MDIO bus node].
-
-Switch MDIO bus defined but explicitly disabled: If the device tree says
-status = "disabled" for the MDIO bus, we shouldn't need an MDIO bus at all.
-Instead, just exit as early as possible and do not call any MDIO API.
-
-The use of ds->user_mii_bus is inappropriate when the MDIO bus of the
-switch is described on the device tree [1], which is why we don't populate
-ds->user_mii_bus in that case.
-
-Link: https://lore.kernel.org/netdev/20231213120656.x46fyad6ls7sqyzv@skbuf/ [1]
----
- drivers/net/dsa/mt7530.c | 34 ++++++++++++++++++++++++++--------
- 1 file changed, 26 insertions(+), 8 deletions(-)
-
---- a/drivers/net/dsa/mt7530.c
-+++ b/drivers/net/dsa/mt7530.c
-@@ -2345,24 +2345,40 @@ mt7530_free_irq_common(struct mt7530_pri
- static void
- mt7530_free_irq(struct mt7530_priv *priv)
- {
-- mt7530_free_mdio_irq(priv);
-+ struct device_node *mnp, *np = priv->dev->of_node;
-+
-+ mnp = of_get_child_by_name(np, "mdio");
-+ if (!mnp)
-+ mt7530_free_mdio_irq(priv);
-+ of_node_put(mnp);
-+
- mt7530_free_irq_common(priv);
- }
-
- static int
- mt7530_setup_mdio(struct mt7530_priv *priv)
- {
-+ struct device_node *mnp, *np = priv->dev->of_node;
- struct dsa_switch *ds = priv->ds;
- struct device *dev = priv->dev;
- struct mii_bus *bus;
- static int idx;
-- int ret;
-+ int ret = 0;
-+
-+ mnp = of_get_child_by_name(np, "mdio");
-+
-+ if (mnp && !of_device_is_available(mnp))
-+ goto out;
-
- bus = devm_mdiobus_alloc(dev);
-- if (!bus)
-- return -ENOMEM;
-+ if (!bus) {
-+ ret = -ENOMEM;
-+ goto out;
-+ }
-+
-+ if (!mnp)
-+ ds->slave_mii_bus = bus;
-
-- ds->slave_mii_bus = bus;
- bus->priv = priv;
- bus->name = KBUILD_MODNAME "-mii";
- snprintf(bus->id, MII_BUS_ID_SIZE, KBUILD_MODNAME "-%d", idx++);
-@@ -2373,16 +2389,18 @@ mt7530_setup_mdio(struct mt7530_priv *pr
- bus->parent = dev;
- bus->phy_mask = ~ds->phys_mii_mask;
-
-- if (priv->irq)
-+ if (priv->irq && !mnp)
- mt7530_setup_mdio_irq(priv);
-
-- ret = devm_mdiobus_register(dev, bus);
-+ ret = devm_of_mdiobus_register(dev, bus, mnp);
- if (ret) {
- dev_err(dev, "failed to register MDIO bus: %d\n", ret);
-- if (priv->irq)
-+ if (priv->irq && !mnp)
- mt7530_free_mdio_irq(priv);
- }
-
-+out:
-+ of_node_put(mnp);
- return ret;
- }
-
+++ /dev/null
-From 617b07e08bcb1f69a72a085a7d847d1ca2999830 Mon Sep 17 00:00:00 2001
-Date: Mon, 22 Jan 2024 08:35:52 +0300
-Subject: [PATCH 05/30] net: dsa: mt7530: always trap frames to active CPU port
- on MT7530
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-On the MT7530 switch, the CPU_PORT field indicates which CPU port to trap
-frames to, regardless of the affinity of the inbound user port.
-
-When multiple CPU ports are in use, if the DSA conduit interface is down,
-trapped frames won't be passed to the conduit interface.
-
-To make trapping frames work including this case, implement
-ds->ops->conduit_state_change() on this subdriver and set the CPU_PORT
-field to the numerically smallest CPU port whose conduit interface is up.
-Introduce the active_cpu_ports field to store the information of the active
-CPU ports. Correct the macros, CPU_PORT is bits 4 through 6 of the
-register.
-
-Add a comment to explain frame trapping for this switch.
-
-Currently, the driver doesn't support the use of multiple CPU ports so this
-is not necessarily a bug fix.
-
-Link: https://lore.kernel.org/r/20240122-for-netnext-mt7530-improvements-1-v3-1-042401f2b279@arinc9.com
----
- drivers/net/dsa/mt7530.c | 35 +++++++++++++++++++++++++++++++----
- drivers/net/dsa/mt7530.h | 6 ++++--
- 2 files changed, 35 insertions(+), 6 deletions(-)
-
---- a/drivers/net/dsa/mt7530.c
-+++ b/drivers/net/dsa/mt7530.c
-@@ -1232,10 +1232,6 @@ mt753x_cpu_port_enable(struct dsa_switch
- mt7530_set(priv, MT7530_MFC, BC_FFP(BIT(port)) | UNM_FFP(BIT(port)) |
- UNU_FFP(BIT(port)));
-
-- /* Set CPU port number */
-- if (priv->id == ID_MT7530 || priv->id == ID_MT7621)
-- mt7530_rmw(priv, MT7530_MFC, CPU_MASK, CPU_EN | CPU_PORT(port));
--
- /* Add the CPU port to the CPU port bitmap for MT7531 and the switch on
- * the MT7988 SoC. Trapped frames will be forwarded to the CPU port that
- * is affine to the inbound user port.
-@@ -3301,6 +3297,36 @@ static int mt753x_set_mac_eee(struct dsa
- return 0;
- }
-
-+static void
-+mt753x_conduit_state_change(struct dsa_switch *ds,
-+ const struct net_device *conduit,
-+ bool operational)
-+{
-+ struct dsa_port *cpu_dp = conduit->dsa_ptr;
-+ struct mt7530_priv *priv = ds->priv;
-+ int val = 0;
-+ u8 mask;
-+
-+ /* Set the CPU port to trap frames to for MT7530. Trapped frames will be
-+ * forwarded to the numerically smallest CPU port whose conduit
-+ * interface is up.
-+ */
-+ if (priv->id != ID_MT7530 && priv->id != ID_MT7621)
-+ return;
-+
-+ mask = BIT(cpu_dp->index);
-+
-+ if (operational)
-+ priv->active_cpu_ports |= mask;
-+ else
-+ priv->active_cpu_ports &= ~mask;
-+
-+ if (priv->active_cpu_ports)
-+ val = CPU_EN | CPU_PORT(__ffs(priv->active_cpu_ports));
-+
-+ mt7530_rmw(priv, MT7530_MFC, CPU_EN | CPU_PORT_MASK, val);
-+}
-+
- static int mt7988_pad_setup(struct dsa_switch *ds, phy_interface_t interface)
- {
- return 0;
-@@ -3356,6 +3382,7 @@ const struct dsa_switch_ops mt7530_switc
- .phylink_mac_link_up = mt753x_phylink_mac_link_up,
- .get_mac_eee = mt753x_get_mac_eee,
- .set_mac_eee = mt753x_set_mac_eee,
-+ .master_state_change = mt753x_conduit_state_change,
- };
- EXPORT_SYMBOL_GPL(mt7530_switch_ops);
-
---- a/drivers/net/dsa/mt7530.h
-+++ b/drivers/net/dsa/mt7530.h
-@@ -45,8 +45,8 @@ enum mt753x_id {
- #define UNU_FFP(x) (((x) & 0xff) << 8)
- #define UNU_FFP_MASK UNU_FFP(~0)
- #define CPU_EN BIT(7)
--#define CPU_PORT(x) ((x) << 4)
--#define CPU_MASK (0xf << 4)
-+#define CPU_PORT_MASK GENMASK(6, 4)
-+#define CPU_PORT(x) FIELD_PREP(CPU_PORT_MASK, x)
- #define MIRROR_EN BIT(3)
- #define MIRROR_PORT(x) ((x) & 0x7)
- #define MIRROR_MASK 0x7
-@@ -790,6 +790,7 @@ struct mt753x_info {
- * @irq_domain: IRQ domain of the switch irq_chip
- * @irq_enable: IRQ enable bits, synced to SYS_INT_EN
- * @create_sgmii: Pointer to function creating SGMII PCS instance(s)
-+ * @active_cpu_ports: Holding the active CPU ports
- */
- struct mt7530_priv {
- struct device *dev;
-@@ -816,6 +817,7 @@ struct mt7530_priv {
- struct irq_domain *irq_domain;
- u32 irq_enable;
- int (*create_sgmii)(struct mt7530_priv *priv, bool dual_sgmii);
-+ u8 active_cpu_ports;
- };
-
- struct mt7530_hw_vlan_entry {
+++ /dev/null
-From 07f411e26f82d75723df1c0c072e5602d06f4e30 Mon Sep 17 00:00:00 2001
-Date: Mon, 22 Jan 2024 08:35:53 +0300
-Subject: [PATCH 06/30] net: dsa: mt7530: use p5_interface_select as data type
- for p5_intf_sel
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Use the p5_interface_select enumeration as the data type for the
-p5_intf_sel field. This ensures p5_intf_sel can only take the values
-defined in the p5_interface_select enumeration.
-
-Remove the explicit assignment of 0 to P5_DISABLED as the first enum item
-is automatically assigned 0.
-
-Link: https://lore.kernel.org/r/20240122-for-netnext-mt7530-improvements-1-v3-2-042401f2b279@arinc9.com
----
- drivers/net/dsa/mt7530.h | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
---- a/drivers/net/dsa/mt7530.h
-+++ b/drivers/net/dsa/mt7530.h
-@@ -713,7 +713,7 @@ struct mt7530_port {
-
- /* Port 5 interface select definitions */
- enum p5_interface_select {
-- P5_DISABLED = 0,
-+ P5_DISABLED,
- P5_INTF_SEL_PHY_P0,
- P5_INTF_SEL_PHY_P4,
- P5_INTF_SEL_GMAC5,
-@@ -806,7 +806,7 @@ struct mt7530_priv {
- bool mcm;
- phy_interface_t p6_interface;
- phy_interface_t p5_interface;
-- unsigned int p5_intf_sel;
-+ enum p5_interface_select p5_intf_sel;
- u8 mirror_rx;
- u8 mirror_tx;
- struct mt7530_port ports[MT7530_NUM_PORTS];
+++ /dev/null
-From 8f7db12efc189eedd196ed8d053236ce27add484 Mon Sep 17 00:00:00 2001
-Date: Mon, 22 Jan 2024 08:35:54 +0300
-Subject: [PATCH 07/30] net: dsa: mt7530: store port 5 SGMII capability of
- MT7531
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Introduce the p5_sgmii field to store the information for whether port 5
-has got SGMII or not. Instead of reading the MT7531_TOP_SIG_SR register
-multiple times, the register will be read once and the value will be
-stored on the p5_sgmii field. This saves unnecessary reads of the
-register.
-
-Move the comment about MT7531AE and MT7531BE to mt7531_setup(), where the
-switch is identified.
-
-Get rid of mt7531_dual_sgmii_supported() now that priv->p5_sgmii stores the
-information. Address the code where mt7531_dual_sgmii_supported() is used.
-
-Get rid of mt7531_is_rgmii_port() which just prints the opposite of
-priv->p5_sgmii.
-
-Instead of calling mt7531_pll_setup() then returning, do not call it if
-port 5 is SGMII.
-
-Remove P5_INTF_SEL_GMAC5_SGMII. The p5_interface_select enum is supposed to
-represent the mode that port 5 is being used in, not the hardware
-information of port 5. Set p5_intf_sel to P5_INTF_SEL_GMAC5 instead, if
-port 5 is not dsa_is_unused_port().
-
-Link: https://lore.kernel.org/r/20240122-for-netnext-mt7530-improvements-1-v3-3-042401f2b279@arinc9.com
----
- drivers/net/dsa/mt7530-mdio.c | 7 ++---
- drivers/net/dsa/mt7530.c | 48 ++++++++++++-----------------------
- drivers/net/dsa/mt7530.h | 6 +++--
- 3 files changed, 22 insertions(+), 39 deletions(-)
-
---- a/drivers/net/dsa/mt7530-mdio.c
-+++ b/drivers/net/dsa/mt7530-mdio.c
-@@ -81,17 +81,14 @@ static const struct regmap_bus mt7530_re
- };
-
- static int
--mt7531_create_sgmii(struct mt7530_priv *priv, bool dual_sgmii)
-+mt7531_create_sgmii(struct mt7530_priv *priv)
- {
- struct regmap_config *mt7531_pcs_config[2] = {};
- struct phylink_pcs *pcs;
- struct regmap *regmap;
- int i, ret = 0;
-
-- /* MT7531AE has two SGMII units for port 5 and port 6
-- * MT7531BE has only one SGMII unit for port 6
-- */
-- for (i = dual_sgmii ? 0 : 1; i < 2; i++) {
-+ for (i = priv->p5_sgmii ? 0 : 1; i < 2; i++) {
- mt7531_pcs_config[i] = devm_kzalloc(priv->dev,
- sizeof(struct regmap_config),
- GFP_KERNEL);
---- a/drivers/net/dsa/mt7530.c
-+++ b/drivers/net/dsa/mt7530.c
-@@ -487,15 +487,6 @@ mt7530_pad_clk_setup(struct dsa_switch *
- return 0;
- }
-
--static bool mt7531_dual_sgmii_supported(struct mt7530_priv *priv)
--{
-- u32 val;
--
-- val = mt7530_read(priv, MT7531_TOP_SIG_SR);
--
-- return (val & PAD_DUAL_SGMII_EN) != 0;
--}
--
- static int
- mt7531_pad_setup(struct dsa_switch *ds, phy_interface_t interface)
- {
-@@ -510,9 +501,6 @@ mt7531_pll_setup(struct mt7530_priv *pri
- u32 xtal;
- u32 val;
-
-- if (mt7531_dual_sgmii_supported(priv))
-- return;
--
- val = mt7530_read(priv, MT7531_CREV);
- top_sig = mt7530_read(priv, MT7531_TOP_SIG_SR);
- hwstrap = mt7530_read(priv, MT7531_HWTRAP);
-@@ -920,8 +908,6 @@ static const char *p5_intf_modes(unsigne
- return "PHY P4";
- case P5_INTF_SEL_GMAC5:
- return "GMAC5";
-- case P5_INTF_SEL_GMAC5_SGMII:
-- return "GMAC5_SGMII";
- default:
- return "unknown";
- }
-@@ -2698,6 +2684,12 @@ mt7531_setup(struct dsa_switch *ds)
- return -ENODEV;
- }
-
-+ /* MT7531AE has got two SGMII units. One for port 5, one for port 6.
-+ * MT7531BE has got only one SGMII unit which is for port 6.
-+ */
-+ val = mt7530_read(priv, MT7531_TOP_SIG_SR);
-+ priv->p5_sgmii = !!(val & PAD_DUAL_SGMII_EN);
-+
- /* all MACs must be forced link-down before sw reset */
- for (i = 0; i < MT7530_NUM_PORTS; i++)
- mt7530_write(priv, MT7530_PMCR_P(i), MT7531_FORCE_LNK);
-@@ -2707,21 +2699,18 @@ mt7531_setup(struct dsa_switch *ds)
- SYS_CTRL_PHY_RST | SYS_CTRL_SW_RST |
- SYS_CTRL_REG_RST);
-
-- mt7531_pll_setup(priv);
--
-- if (mt7531_dual_sgmii_supported(priv)) {
-- priv->p5_intf_sel = P5_INTF_SEL_GMAC5_SGMII;
--
-+ if (!priv->p5_sgmii) {
-+ mt7531_pll_setup(priv);
-+ } else {
- /* Let ds->slave_mii_bus be able to access external phy. */
- mt7530_rmw(priv, MT7531_GPIO_MODE1, MT7531_GPIO11_RG_RXD2_MASK,
- MT7531_EXT_P_MDC_11);
- mt7530_rmw(priv, MT7531_GPIO_MODE1, MT7531_GPIO12_RG_RXD3_MASK,
- MT7531_EXT_P_MDIO_12);
-- } else {
-- priv->p5_intf_sel = P5_INTF_SEL_GMAC5;
- }
-- dev_dbg(ds->dev, "P5 support %s interface\n",
-- p5_intf_modes(priv->p5_intf_sel));
-+
-+ if (!dsa_is_unused_port(ds, 5))
-+ priv->p5_intf_sel = P5_INTF_SEL_GMAC5;
-
- mt7530_rmw(priv, MT7531_GPIO_MODE0, MT7531_GPIO0_MASK,
- MT7531_GPIO0_INTERRUPT);
-@@ -2780,11 +2769,6 @@ static void mt7530_mac_port_get_caps(str
- }
- }
-
--static bool mt7531_is_rgmii_port(struct mt7530_priv *priv, u32 port)
--{
-- return (port == 5) && (priv->p5_intf_sel != P5_INTF_SEL_GMAC5_SGMII);
--}
--
- static void mt7531_mac_port_get_caps(struct dsa_switch *ds, int port,
- struct phylink_config *config)
- {
-@@ -2797,7 +2781,7 @@ static void mt7531_mac_port_get_caps(str
- break;
-
- case 5: /* 2nd cpu port supports either rgmii or sgmii/8023z */
-- if (mt7531_is_rgmii_port(priv, port)) {
-+ if (!priv->p5_sgmii) {
- phy_interface_set_rgmii(config->supported_interfaces);
- break;
- }
-@@ -2864,7 +2848,7 @@ static int mt7531_rgmii_setup(struct mt7
- {
- u32 val;
-
-- if (!mt7531_is_rgmii_port(priv, port)) {
-+ if (priv->p5_sgmii) {
- dev_err(priv->dev, "RGMII mode is not available for port %d\n",
- port);
- return -EINVAL;
-@@ -3107,7 +3091,7 @@ mt7531_cpu_port_config(struct dsa_switch
-
- switch (port) {
- case 5:
-- if (mt7531_is_rgmii_port(priv, port))
-+ if (!priv->p5_sgmii)
- interface = PHY_INTERFACE_MODE_RGMII;
- else
- interface = PHY_INTERFACE_MODE_2500BASEX;
-@@ -3259,7 +3243,7 @@ mt753x_setup(struct dsa_switch *ds)
- mt7530_free_irq_common(priv);
-
- if (priv->create_sgmii) {
-- ret = priv->create_sgmii(priv, mt7531_dual_sgmii_supported(priv));
-+ ret = priv->create_sgmii(priv);
- if (ret && priv->irq)
- mt7530_free_irq(priv);
- }
---- a/drivers/net/dsa/mt7530.h
-+++ b/drivers/net/dsa/mt7530.h
-@@ -717,7 +717,6 @@ enum p5_interface_select {
- P5_INTF_SEL_PHY_P0,
- P5_INTF_SEL_PHY_P4,
- P5_INTF_SEL_GMAC5,
-- P5_INTF_SEL_GMAC5_SGMII,
- };
-
- struct mt7530_priv;
-@@ -786,6 +785,8 @@ struct mt753x_info {
- * registers
- * @p6_interface Holding the current port 6 interface
- * @p5_intf_sel: Holding the current port 5 interface select
-+ * @p5_sgmii: Flag for distinguishing if port 5 of the MT7531 switch
-+ * has got SGMII
- * @irq: IRQ number of the switch
- * @irq_domain: IRQ domain of the switch irq_chip
- * @irq_enable: IRQ enable bits, synced to SYS_INT_EN
-@@ -807,6 +808,7 @@ struct mt7530_priv {
- phy_interface_t p6_interface;
- phy_interface_t p5_interface;
- enum p5_interface_select p5_intf_sel;
-+ bool p5_sgmii;
- u8 mirror_rx;
- u8 mirror_tx;
- struct mt7530_port ports[MT7530_NUM_PORTS];
-@@ -816,7 +818,7 @@ struct mt7530_priv {
- int irq;
- struct irq_domain *irq_domain;
- u32 irq_enable;
-- int (*create_sgmii)(struct mt7530_priv *priv, bool dual_sgmii);
-+ int (*create_sgmii)(struct mt7530_priv *priv);
- u8 active_cpu_ports;
- };
-
+++ /dev/null
-From c91b7fb8fbb2e18ebb497e67f4252cec78e3a29b Mon Sep 17 00:00:00 2001
-Date: Mon, 22 Jan 2024 08:35:55 +0300
-Subject: [PATCH 08/30] net: dsa: mt7530: improve comments regarding switch
- ports
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-There's no logic to numerically order the CPU ports. Just state the port
-number instead.
-
-Remove the irrelevant PHY muxing information from
-mt7530_mac_port_get_caps(). Explain the supported MII modes instead.
-
-Remove the out of place PHY muxing information from
-mt753x_phylink_mac_config(). The function is for MT7530, MT7531, and the
-switch on the MT7988 SoC but there's no PHY muxing on MT7531 or the switch
-on the MT7988 SoC.
-
-These comments were gradually introduced with the commits below.
-commit ca366d6c889b ("net: dsa: mt7530: Convert to PHYLINK API")
-commit 38f790a80560 ("net: dsa: mt7530: Add support for port 5")
-commit 88bdef8be9f6 ("net: dsa: mt7530: Extend device data ready for adding
-a new hardware")
-commit c288575f7810 ("net: dsa: mt7530: Add the support of MT7531 switch")
-
-Link: https://lore.kernel.org/r/20240122-for-netnext-mt7530-improvements-1-v3-4-042401f2b279@arinc9.com
----
- drivers/net/dsa/mt7530.c | 30 ++++++++++++++++++++----------
- 1 file changed, 20 insertions(+), 10 deletions(-)
-
---- a/drivers/net/dsa/mt7530.c
-+++ b/drivers/net/dsa/mt7530.c
-@@ -2747,12 +2747,14 @@ static void mt7530_mac_port_get_caps(str
- struct phylink_config *config)
- {
- switch (port) {
-- case 0 ... 4: /* Internal phy */
-+ /* Ports which are connected to switch PHYs. There is no MII pinout. */
-+ case 0 ... 4:
- __set_bit(PHY_INTERFACE_MODE_GMII,
- config->supported_interfaces);
- break;
-
-- case 5: /* 2nd cpu port with phy of port 0 or 4 / external phy */
-+ /* Port 5 supports rgmii with delays, mii, and gmii. */
-+ case 5:
- phy_interface_set_rgmii(config->supported_interfaces);
- __set_bit(PHY_INTERFACE_MODE_MII,
- config->supported_interfaces);
-@@ -2760,7 +2762,8 @@ static void mt7530_mac_port_get_caps(str
- config->supported_interfaces);
- break;
-
-- case 6: /* 1st cpu port */
-+ /* Port 6 supports rgmii and trgmii. */
-+ case 6:
- __set_bit(PHY_INTERFACE_MODE_RGMII,
- config->supported_interfaces);
- __set_bit(PHY_INTERFACE_MODE_TRGMII,
-@@ -2775,19 +2778,24 @@ static void mt7531_mac_port_get_caps(str
- struct mt7530_priv *priv = ds->priv;
-
- switch (port) {
-- case 0 ... 4: /* Internal phy */
-+ /* Ports which are connected to switch PHYs. There is no MII pinout. */
-+ case 0 ... 4:
- __set_bit(PHY_INTERFACE_MODE_GMII,
- config->supported_interfaces);
- break;
-
-- case 5: /* 2nd cpu port supports either rgmii or sgmii/8023z */
-+ /* Port 5 supports rgmii with delays on MT7531BE, sgmii/802.3z on
-+ * MT7531AE.
-+ */
-+ case 5:
- if (!priv->p5_sgmii) {
- phy_interface_set_rgmii(config->supported_interfaces);
- break;
- }
- fallthrough;
-
-- case 6: /* 1st cpu port supports sgmii/8023z only */
-+ /* Port 6 supports sgmii/802.3z. */
-+ case 6:
- __set_bit(PHY_INTERFACE_MODE_SGMII,
- config->supported_interfaces);
- __set_bit(PHY_INTERFACE_MODE_1000BASEX,
-@@ -2806,11 +2814,13 @@ static void mt7988_mac_port_get_caps(str
- phy_interface_zero(config->supported_interfaces);
-
- switch (port) {
-- case 0 ... 4: /* Internal phy */
-+ /* Ports which are connected to switch PHYs. There is no MII pinout. */
-+ case 0 ... 4:
- __set_bit(PHY_INTERFACE_MODE_INTERNAL,
- config->supported_interfaces);
- break;
-
-+ /* Port 6 is connected to SoC's XGMII MAC. There is no MII pinout. */
- case 6:
- __set_bit(PHY_INTERFACE_MODE_INTERNAL,
- config->supported_interfaces);
-@@ -2974,12 +2984,12 @@ mt753x_phylink_mac_config(struct dsa_swi
- u32 mcr_cur, mcr_new;
-
- switch (port) {
-- case 0 ... 4: /* Internal phy */
-+ case 0 ... 4:
- if (state->interface != PHY_INTERFACE_MODE_GMII &&
- state->interface != PHY_INTERFACE_MODE_INTERNAL)
- goto unsupported;
- break;
-- case 5: /* 2nd cpu port with phy of port 0 or 4 / external phy */
-+ case 5:
- if (priv->p5_interface == state->interface)
- break;
-
-@@ -2989,7 +2999,7 @@ mt753x_phylink_mac_config(struct dsa_swi
- if (priv->p5_intf_sel != P5_DISABLED)
- priv->p5_interface = state->interface;
- break;
-- case 6: /* 1st cpu port */
-+ case 6:
- if (priv->p6_interface == state->interface)
- break;
-
+++ /dev/null
-From c1b2294a9b4b9b6c0cbe58666cb86e0a9cb0abfd Mon Sep 17 00:00:00 2001
-Date: Mon, 22 Jan 2024 08:35:56 +0300
-Subject: [PATCH 09/30] net: dsa: mt7530: improve code path for setting up port
- 5
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-There're two code paths for setting up port 5:
-
-mt7530_setup()
--> mt7530_setup_port5()
-
-mt753x_phylink_mac_config()
--> mt753x_mac_config()
- -> mt7530_mac_config()
- -> mt7530_setup_port5()
-
-Currently mt7530_setup_port5() from mt7530_setup() always runs. If port 5
-is used as a CPU, DSA, or user port, mt7530_setup_port5() from
-mt753x_phylink_mac_config() won't run. That is because priv->p5_interface
-set on mt7530_setup_port5() will match state->interface on
-mt753x_phylink_mac_config() which will stop running mt7530_setup_port5()
-again.
-
-Therefore, mt7530_setup_port5() will never run from
-mt753x_phylink_mac_config().
-
-Address this by not running mt7530_setup_port5() from mt7530_setup() if
-port 5 is used as a CPU, DSA, or user port. This driver isn't in the
-dsa_switches_apply_workarounds[] array so phylink will always be present.
-
-To keep the cases where port 5 isn't controlled by phylink working as
-before, preserve the mt7530_setup_port5() call from mt7530_setup().
-
-Do not set priv->p5_intf_sel to P5_DISABLED. It is already set to that when
-"priv" is allocated.
-
-Move setting the interface to a more specific location. It's supposed to be
-overwritten if PHY muxing is detected.
-
-Improve the comment which explains the process.
-
-Link: https://lore.kernel.org/r/20240122-for-netnext-mt7530-improvements-1-v3-5-042401f2b279@arinc9.com
----
- drivers/net/dsa/mt7530.c | 17 ++++++++---------
- 1 file changed, 8 insertions(+), 9 deletions(-)
-
---- a/drivers/net/dsa/mt7530.c
-+++ b/drivers/net/dsa/mt7530.c
-@@ -2529,16 +2529,15 @@ mt7530_setup(struct dsa_switch *ds)
- return ret;
-
- /* Setup port 5 */
-- priv->p5_intf_sel = P5_DISABLED;
-- interface = PHY_INTERFACE_MODE_NA;
--
- if (!dsa_is_unused_port(ds, 5)) {
- priv->p5_intf_sel = P5_INTF_SEL_GMAC5;
-- ret = of_get_phy_mode(dsa_to_port(ds, 5)->dn, &interface);
-- if (ret && ret != -ENODEV)
-- return ret;
- } else {
-- /* Scan the ethernet nodes. look for GMAC1, lookup used phy */
-+ /* Scan the ethernet nodes. Look for GMAC1, lookup the used PHY.
-+ * Set priv->p5_intf_sel to the appropriate value if PHY muxing
-+ * is detected.
-+ */
-+ interface = PHY_INTERFACE_MODE_NA;
-+
- for_each_child_of_node(dn, mac_np) {
- if (!of_device_is_compatible(mac_np,
- "mediatek,eth-mac"))
-@@ -2569,6 +2568,8 @@ mt7530_setup(struct dsa_switch *ds)
- of_node_put(phy_node);
- break;
- }
-+
-+ mt7530_setup_port5(ds, interface);
- }
-
- #ifdef CONFIG_GPIOLIB
-@@ -2579,8 +2580,6 @@ mt7530_setup(struct dsa_switch *ds)
- }
- #endif /* CONFIG_GPIOLIB */
-
-- mt7530_setup_port5(ds, interface);
--
- /* Flush the FDB table */
- ret = mt7530_fdb_cmd(priv, MT7530_FDB_FLUSH, NULL);
- if (ret < 0)
+++ /dev/null
-From cd1cee68e57eedb460a68d1f42abf9f740b17e94 Mon Sep 17 00:00:00 2001
-Date: Mon, 22 Jan 2024 08:35:57 +0300
-Subject: [PATCH 10/30] net: dsa: mt7530: do not set priv->p5_interface on
- mt7530_setup_port5()
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Running mt7530_setup_port5() from mt7530_setup() used to handle all cases
-of configuring port 5, including phylink.
-
-Setting priv->p5_interface under mt7530_setup_port5() makes sure that
-mt7530_setup_port5() from mt753x_phylink_mac_config() won't run.
-
-The commit ("net: dsa: mt7530: improve code path for setting up port 5")
-makes so that mt7530_setup_port5() from mt7530_setup() runs only on
-non-phylink cases.
-
-Get rid of unnecessarily setting priv->p5_interface under
-mt7530_setup_port5() as port 5 phylink configuration will be done by
-running mt7530_setup_port5() from mt753x_phylink_mac_config() now.
-
-Link: https://lore.kernel.org/r/20240122-for-netnext-mt7530-improvements-1-v3-6-042401f2b279@arinc9.com
----
- drivers/net/dsa/mt7530.c | 2 --
- 1 file changed, 2 deletions(-)
-
---- a/drivers/net/dsa/mt7530.c
-+++ b/drivers/net/dsa/mt7530.c
-@@ -978,8 +978,6 @@ static void mt7530_setup_port5(struct ds
- dev_dbg(ds->dev, "Setup P5, HWTRAP=0x%x, intf_sel=%s, phy-mode=%s\n",
- val, p5_intf_modes(priv->p5_intf_sel), phy_modes(interface));
-
-- priv->p5_interface = interface;
--
- unlock_exit:
- mutex_unlock(&priv->reg_mutex);
- }
+++ /dev/null
-From e55a68aeb0f8b9c74b582b7a5e92b82988832bf8 Mon Sep 17 00:00:00 2001
-Date: Mon, 22 Jan 2024 08:35:58 +0300
-Subject: [PATCH 11/30] net: dsa: mt7530: do not run mt7530_setup_port5() if
- port 5 is disabled
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-There's no need to run all the code on mt7530_setup_port5() if port 5 is
-disabled. The only case for calling mt7530_setup_port5() from
-mt7530_setup() is when PHY muxing is enabled. That is because port 5 is not
-defined as a port on the devicetree, therefore, it cannot be controlled by
-phylink.
-
-Because of this, run mt7530_setup_port5() if priv->p5_intf_sel is
-P5_INTF_SEL_PHY_P0 or P5_INTF_SEL_PHY_P4. Remove the P5_DISABLED case from
-mt7530_setup_port5().
-
-Stop initialising the interface variable as the remaining cases will always
-call mt7530_setup_port5() with it initialised.
-
-Link: https://lore.kernel.org/r/20240122-for-netnext-mt7530-improvements-1-v3-7-042401f2b279@arinc9.com
----
- drivers/net/dsa/mt7530.c | 9 +++------
- 1 file changed, 3 insertions(+), 6 deletions(-)
-
---- a/drivers/net/dsa/mt7530.c
-+++ b/drivers/net/dsa/mt7530.c
-@@ -942,9 +942,6 @@ static void mt7530_setup_port5(struct ds
- /* MT7530_P5_MODE_GMAC: P5 -> External phy or 2nd GMAC */
- val &= ~MHWTRAP_P5_DIS;
- break;
-- case P5_DISABLED:
-- interface = PHY_INTERFACE_MODE_NA;
-- break;
- default:
- dev_err(ds->dev, "Unsupported p5_intf_sel %d\n",
- priv->p5_intf_sel);
-@@ -2534,8 +2531,6 @@ mt7530_setup(struct dsa_switch *ds)
- * Set priv->p5_intf_sel to the appropriate value if PHY muxing
- * is detected.
- */
-- interface = PHY_INTERFACE_MODE_NA;
--
- for_each_child_of_node(dn, mac_np) {
- if (!of_device_is_compatible(mac_np,
- "mediatek,eth-mac"))
-@@ -2567,7 +2562,9 @@ mt7530_setup(struct dsa_switch *ds)
- break;
- }
-
-- mt7530_setup_port5(ds, interface);
-+ if (priv->p5_intf_sel == P5_INTF_SEL_PHY_P0 ||
-+ priv->p5_intf_sel == P5_INTF_SEL_PHY_P4)
-+ mt7530_setup_port5(ds, interface);
- }
-
- #ifdef CONFIG_GPIOLIB
+++ /dev/null
-From 1f538cda24bcb69919da2fcac0211b66281d3d4e Mon Sep 17 00:00:00 2001
-Date: Tue, 6 Feb 2024 01:08:02 +0300
-Subject: [PATCH 12/30] net: dsa: mt7530: empty default case on
- mt7530_setup_port5()
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-There're two code paths for setting up port 5:
-
-mt7530_setup()
--> mt7530_setup_port5()
-
-mt753x_phylink_mac_config()
--> mt753x_mac_config()
- -> mt7530_mac_config()
- -> mt7530_setup_port5()
-
-On the first code path, priv->p5_intf_sel is either set to
-P5_INTF_SEL_PHY_P0 or P5_INTF_SEL_PHY_P4 when mt7530_setup_port5() is run.
-
-On the second code path, priv->p5_intf_sel is set to P5_INTF_SEL_GMAC5 when
-mt7530_setup_port5() is run.
-
-Empty the default case which will never run but is needed nonetheless to
-handle all the remaining enumeration values.
-
-Link: https://lore.kernel.org/r/20240206-for-netnext-mt7530-improvements-2-v5-1-d7d92a185cb1@arinc9.com
----
- drivers/net/dsa/mt7530.c | 5 +----
- 1 file changed, 1 insertion(+), 4 deletions(-)
-
---- a/drivers/net/dsa/mt7530.c
-+++ b/drivers/net/dsa/mt7530.c
-@@ -943,9 +943,7 @@ static void mt7530_setup_port5(struct ds
- val &= ~MHWTRAP_P5_DIS;
- break;
- default:
-- dev_err(ds->dev, "Unsupported p5_intf_sel %d\n",
-- priv->p5_intf_sel);
-- goto unlock_exit;
-+ break;
- }
-
- /* Setup RGMII settings */
-@@ -975,7 +973,6 @@ static void mt7530_setup_port5(struct ds
- dev_dbg(ds->dev, "Setup P5, HWTRAP=0x%x, intf_sel=%s, phy-mode=%s\n",
- val, p5_intf_modes(priv->p5_intf_sel), phy_modes(interface));
-
--unlock_exit:
- mutex_unlock(&priv->reg_mutex);
- }
-
+++ /dev/null
-From 12c511cd31c2dc6bd96e4a89f7709d515aa8a76b Mon Sep 17 00:00:00 2001
-Date: Tue, 6 Feb 2024 01:08:03 +0300
-Subject: [PATCH 13/30] net: dsa: mt7530: move XTAL check to mt7530_setup()
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-The crystal frequency concerns the switch core. The frequency should be
-checked when the switch is being set up so the driver can reject the
-unsupported hardware earlier and without requiring port 6 to be used.
-
-Move it to mt7530_setup(). Drop the unnecessary function printing.
-
-Link: https://lore.kernel.org/r/20240206-for-netnext-mt7530-improvements-2-v5-2-d7d92a185cb1@arinc9.com
----
- drivers/net/dsa/mt7530.c | 13 ++++++-------
- 1 file changed, 6 insertions(+), 7 deletions(-)
-
---- a/drivers/net/dsa/mt7530.c
-+++ b/drivers/net/dsa/mt7530.c
-@@ -422,13 +422,6 @@ mt7530_pad_clk_setup(struct dsa_switch *
-
- xtal = mt7530_read(priv, MT7530_MHWTRAP) & HWTRAP_XTAL_MASK;
-
-- if (xtal == HWTRAP_XTAL_20MHZ) {
-- dev_err(priv->dev,
-- "%s: MT7530 with a 20MHz XTAL is not supported!\n",
-- __func__);
-- return -EINVAL;
-- }
--
- switch (interface) {
- case PHY_INTERFACE_MODE_RGMII:
- trgint = 0;
-@@ -2458,6 +2451,12 @@ mt7530_setup(struct dsa_switch *ds)
- return -ENODEV;
- }
-
-+ if ((val & HWTRAP_XTAL_MASK) == HWTRAP_XTAL_20MHZ) {
-+ dev_err(priv->dev,
-+ "MT7530 with a 20MHz XTAL is not supported!\n");
-+ return -EINVAL;
-+ }
-+
- /* Reset the switch through internal reset */
- mt7530_write(priv, MT7530_SYS_CTRL,
- SYS_CTRL_PHY_RST | SYS_CTRL_SW_RST |
+++ /dev/null
-From c33899a6a8c1a5723afbfc075600aba2e2bdbea7 Mon Sep 17 00:00:00 2001
-Date: Tue, 6 Feb 2024 01:08:04 +0300
-Subject: [PATCH 14/30] net: dsa: mt7530: simplify mt7530_pad_clk_setup()
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-This code is from before this driver was converted to phylink API. Phylink
-deals with the unsupported interface cases before mt7530_pad_clk_setup() is
-run. Therefore, the default case would never run. However, it must be
-defined nonetheless to handle all the remaining enumeration values, the
-phy-modes.
-
-Switch to if statement for RGMII and return which simplifies the code and
-saves an indent.
-
-Set P6_INTF_MODE, which is the three least significant bits of the
-MT7530_P6ECR register, to 0 for RGMII even though it will already be 0
-after reset. This is to keep supporting dynamic reconfiguration of the port
-in the case the interface changes from TRGMII to RGMII.
-
-Disable the TRGMII clocks for all cases. They will be enabled if TRGMII is
-being used.
-
-Read XTAL after checking for RGMII as it's only needed for the TRGMII
-interface mode.
-
-Link: https://lore.kernel.org/r/20240206-for-netnext-mt7530-improvements-2-v5-3-d7d92a185cb1@arinc9.com
----
- drivers/net/dsa/mt7530.c | 91 ++++++++++++++++++----------------------
- 1 file changed, 40 insertions(+), 51 deletions(-)
-
---- a/drivers/net/dsa/mt7530.c
-+++ b/drivers/net/dsa/mt7530.c
-@@ -418,65 +418,54 @@ static int
- mt7530_pad_clk_setup(struct dsa_switch *ds, phy_interface_t interface)
- {
- struct mt7530_priv *priv = ds->priv;
-- u32 ncpo1, ssc_delta, trgint, xtal;
-+ u32 ncpo1, ssc_delta, xtal;
-
-- xtal = mt7530_read(priv, MT7530_MHWTRAP) & HWTRAP_XTAL_MASK;
-+ /* Disable the MT7530 TRGMII clocks */
-+ core_clear(priv, CORE_TRGMII_GSW_CLK_CG, REG_TRGMIICK_EN);
-
-- switch (interface) {
-- case PHY_INTERFACE_MODE_RGMII:
-- trgint = 0;
-- break;
-- case PHY_INTERFACE_MODE_TRGMII:
-- trgint = 1;
-- if (xtal == HWTRAP_XTAL_25MHZ)
-- ssc_delta = 0x57;
-- else
-- ssc_delta = 0x87;
-- if (priv->id == ID_MT7621) {
-- /* PLL frequency: 125MHz: 1.0GBit */
-- if (xtal == HWTRAP_XTAL_40MHZ)
-- ncpo1 = 0x0640;
-- if (xtal == HWTRAP_XTAL_25MHZ)
-- ncpo1 = 0x0a00;
-- } else { /* PLL frequency: 250MHz: 2.0Gbit */
-- if (xtal == HWTRAP_XTAL_40MHZ)
-- ncpo1 = 0x0c80;
-- if (xtal == HWTRAP_XTAL_25MHZ)
-- ncpo1 = 0x1400;
-- }
-- break;
-- default:
-- dev_err(priv->dev, "xMII interface %d not supported\n",
-- interface);
-- return -EINVAL;
-+ if (interface == PHY_INTERFACE_MODE_RGMII) {
-+ mt7530_rmw(priv, MT7530_P6ECR, P6_INTF_MODE_MASK,
-+ P6_INTF_MODE(0));
-+ return 0;
- }
-
-- mt7530_rmw(priv, MT7530_P6ECR, P6_INTF_MODE_MASK,
-- P6_INTF_MODE(trgint));
-+ mt7530_rmw(priv, MT7530_P6ECR, P6_INTF_MODE_MASK, P6_INTF_MODE(1));
-
-- if (trgint) {
-- /* Disable the MT7530 TRGMII clocks */
-- core_clear(priv, CORE_TRGMII_GSW_CLK_CG, REG_TRGMIICK_EN);
--
-- /* Setup the MT7530 TRGMII Tx Clock */
-- core_write(priv, CORE_PLL_GROUP5, RG_LCDDS_PCW_NCPO1(ncpo1));
-- core_write(priv, CORE_PLL_GROUP6, RG_LCDDS_PCW_NCPO0(0));
-- core_write(priv, CORE_PLL_GROUP10, RG_LCDDS_SSC_DELTA(ssc_delta));
-- core_write(priv, CORE_PLL_GROUP11, RG_LCDDS_SSC_DELTA1(ssc_delta));
-- core_write(priv, CORE_PLL_GROUP4,
-- RG_SYSPLL_DDSFBK_EN | RG_SYSPLL_BIAS_EN |
-- RG_SYSPLL_BIAS_LPF_EN);
-- core_write(priv, CORE_PLL_GROUP2,
-- RG_SYSPLL_EN_NORMAL | RG_SYSPLL_VODEN |
-- RG_SYSPLL_POSDIV(1));
-- core_write(priv, CORE_PLL_GROUP7,
-- RG_LCDDS_PCW_NCPO_CHG | RG_LCCDS_C(3) |
-- RG_LCDDS_PWDB | RG_LCDDS_ISO_EN);
-+ xtal = mt7530_read(priv, MT7530_MHWTRAP) & HWTRAP_XTAL_MASK;
-
-- /* Enable the MT7530 TRGMII clocks */
-- core_set(priv, CORE_TRGMII_GSW_CLK_CG, REG_TRGMIICK_EN);
-+ if (xtal == HWTRAP_XTAL_25MHZ)
-+ ssc_delta = 0x57;
-+ else
-+ ssc_delta = 0x87;
-+
-+ if (priv->id == ID_MT7621) {
-+ /* PLL frequency: 125MHz: 1.0GBit */
-+ if (xtal == HWTRAP_XTAL_40MHZ)
-+ ncpo1 = 0x0640;
-+ if (xtal == HWTRAP_XTAL_25MHZ)
-+ ncpo1 = 0x0a00;
-+ } else { /* PLL frequency: 250MHz: 2.0Gbit */
-+ if (xtal == HWTRAP_XTAL_40MHZ)
-+ ncpo1 = 0x0c80;
-+ if (xtal == HWTRAP_XTAL_25MHZ)
-+ ncpo1 = 0x1400;
- }
-
-+ /* Setup the MT7530 TRGMII Tx Clock */
-+ core_write(priv, CORE_PLL_GROUP5, RG_LCDDS_PCW_NCPO1(ncpo1));
-+ core_write(priv, CORE_PLL_GROUP6, RG_LCDDS_PCW_NCPO0(0));
-+ core_write(priv, CORE_PLL_GROUP10, RG_LCDDS_SSC_DELTA(ssc_delta));
-+ core_write(priv, CORE_PLL_GROUP11, RG_LCDDS_SSC_DELTA1(ssc_delta));
-+ core_write(priv, CORE_PLL_GROUP4, RG_SYSPLL_DDSFBK_EN |
-+ RG_SYSPLL_BIAS_EN | RG_SYSPLL_BIAS_LPF_EN);
-+ core_write(priv, CORE_PLL_GROUP2, RG_SYSPLL_EN_NORMAL |
-+ RG_SYSPLL_VODEN | RG_SYSPLL_POSDIV(1));
-+ core_write(priv, CORE_PLL_GROUP7, RG_LCDDS_PCW_NCPO_CHG |
-+ RG_LCCDS_C(3) | RG_LCDDS_PWDB | RG_LCDDS_ISO_EN);
-+
-+ /* Enable the MT7530 TRGMII clocks */
-+ core_set(priv, CORE_TRGMII_GSW_CLK_CG, REG_TRGMIICK_EN);
-+
- return 0;
- }
-
+++ /dev/null
-From e612922de7070a28802216650ee88128a57290de Mon Sep 17 00:00:00 2001
-Date: Tue, 6 Feb 2024 01:08:05 +0300
-Subject: [PATCH 15/30] net: dsa: mt7530: call port 6 setup from
- mt7530_mac_config()
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-mt7530_pad_clk_setup() is called if port 6 is enabled. It used to do more
-things than setting up port 6. That part was moved to more appropriate
-locations, mt7530_setup() and mt7530_pll_setup().
-
-Now that all it does is set up port 6, rename it to mt7530_setup_port6(),
-and move it to a more appropriate location, under mt7530_mac_config().
-
-Change mt7530_setup_port6() to void as there're no error cases.
-
-Leave an empty mt7530_pad_clk_setup() to satisfy the pad_setup function
-pointer.
-
-This is the code path for setting up the ports before:
-
-dsa_switch_ops :: phylink_mac_config() -> mt753x_phylink_mac_config()
--> mt753x_mac_config()
- -> mt753x_info :: mac_port_config() -> mt7530_mac_config()
- -> mt7530_setup_port5()
--> mt753x_pad_setup()
- -> mt753x_info :: pad_setup() -> mt7530_pad_clk_setup()
-
-This is after:
-
-dsa_switch_ops :: phylink_mac_config() -> mt753x_phylink_mac_config()
--> mt753x_mac_config()
- -> mt753x_info :: mac_port_config() -> mt7530_mac_config()
- -> mt7530_setup_port5()
- -> mt7530_setup_port6()
-
-Link: https://lore.kernel.org/r/20240206-for-netnext-mt7530-improvements-2-v5-4-d7d92a185cb1@arinc9.com
----
- drivers/net/dsa/mt7530.c | 19 +++++++++++--------
- 1 file changed, 11 insertions(+), 8 deletions(-)
-
---- a/drivers/net/dsa/mt7530.c
-+++ b/drivers/net/dsa/mt7530.c
-@@ -414,8 +414,8 @@ mt753x_preferred_default_local_cpu_port(
- }
-
- /* Setup port 6 interface mode and TRGMII TX circuit */
--static int
--mt7530_pad_clk_setup(struct dsa_switch *ds, phy_interface_t interface)
-+static void
-+mt7530_setup_port6(struct dsa_switch *ds, phy_interface_t interface)
- {
- struct mt7530_priv *priv = ds->priv;
- u32 ncpo1, ssc_delta, xtal;
-@@ -426,7 +426,7 @@ mt7530_pad_clk_setup(struct dsa_switch *
- if (interface == PHY_INTERFACE_MODE_RGMII) {
- mt7530_rmw(priv, MT7530_P6ECR, P6_INTF_MODE_MASK,
- P6_INTF_MODE(0));
-- return 0;
-+ return;
- }
-
- mt7530_rmw(priv, MT7530_P6ECR, P6_INTF_MODE_MASK, P6_INTF_MODE(1));
-@@ -465,7 +465,11 @@ mt7530_pad_clk_setup(struct dsa_switch *
-
- /* Enable the MT7530 TRGMII clocks */
- core_set(priv, CORE_TRGMII_GSW_CLK_CG, REG_TRGMIICK_EN);
-+}
-
-+static int
-+mt7530_pad_clk_setup(struct dsa_switch *ds, phy_interface_t interface)
-+{
- return 0;
- }
-
-@@ -2822,11 +2826,10 @@ mt7530_mac_config(struct dsa_switch *ds,
- {
- struct mt7530_priv *priv = ds->priv;
-
-- /* Only need to setup port5. */
-- if (port != 5)
-- return 0;
--
-- mt7530_setup_port5(priv->ds, interface);
-+ if (port == 5)
-+ mt7530_setup_port5(priv->ds, interface);
-+ else if (port == 6)
-+ mt7530_setup_port6(priv->ds, interface);
-
- return 0;
- }
+++ /dev/null
-From af83e0c7d766078fcd5580c0c81b9e5b55ff5906 Mon Sep 17 00:00:00 2001
-Date: Tue, 6 Feb 2024 01:08:06 +0300
-Subject: [PATCH 16/30] net: dsa: mt7530: remove pad_setup function pointer
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-The pad_setup function pointer was introduced with 88bdef8be9f6 ("net: dsa:
-mt7530: Extend device data ready for adding a new hardware"). It was being
-used to set up the core clock and port 6 of the MT7530 switch, and pll of
-the MT7531 switch.
-
-All of these were moved to more appropriate locations, and it was never
-used for the switch on the MT7988 SoC. Therefore, this function pointer
-hasn't got a use anymore. Remove it.
-
-Link: https://lore.kernel.org/r/20240206-for-netnext-mt7530-improvements-2-v5-5-d7d92a185cb1@arinc9.com
----
- drivers/net/dsa/mt7530.c | 36 ++----------------------------------
- drivers/net/dsa/mt7530.h | 3 ---
- 2 files changed, 2 insertions(+), 37 deletions(-)
-
---- a/drivers/net/dsa/mt7530.c
-+++ b/drivers/net/dsa/mt7530.c
-@@ -467,18 +467,6 @@ mt7530_setup_port6(struct dsa_switch *ds
- core_set(priv, CORE_TRGMII_GSW_CLK_CG, REG_TRGMIICK_EN);
- }
-
--static int
--mt7530_pad_clk_setup(struct dsa_switch *ds, phy_interface_t interface)
--{
-- return 0;
--}
--
--static int
--mt7531_pad_setup(struct dsa_switch *ds, phy_interface_t interface)
--{
-- return 0;
--}
--
- static void
- mt7531_pll_setup(struct mt7530_priv *priv)
- {
-@@ -2813,14 +2801,6 @@ static void mt7988_mac_port_get_caps(str
- }
-
- static int
--mt753x_pad_setup(struct dsa_switch *ds, const struct phylink_link_state *state)
--{
-- struct mt7530_priv *priv = ds->priv;
--
-- return priv->info->pad_setup(ds, state->interface);
--}
--
--static int
- mt7530_mac_config(struct dsa_switch *ds, int port, unsigned int mode,
- phy_interface_t interface)
- {
-@@ -2985,8 +2965,6 @@ mt753x_phylink_mac_config(struct dsa_swi
- if (priv->p6_interface == state->interface)
- break;
-
-- mt753x_pad_setup(ds, state);
--
- if (mt753x_mac_config(ds, port, mode, state) < 0)
- goto unsupported;
-
-@@ -3303,11 +3281,6 @@ mt753x_conduit_state_change(struct dsa_s
- mt7530_rmw(priv, MT7530_MFC, CPU_EN | CPU_PORT_MASK, val);
- }
-
--static int mt7988_pad_setup(struct dsa_switch *ds, phy_interface_t interface)
--{
-- return 0;
--}
--
- static int mt7988_setup(struct dsa_switch *ds)
- {
- struct mt7530_priv *priv = ds->priv;
-@@ -3371,7 +3344,6 @@ const struct mt753x_info mt753x_table[]
- .phy_write_c22 = mt7530_phy_write_c22,
- .phy_read_c45 = mt7530_phy_read_c45,
- .phy_write_c45 = mt7530_phy_write_c45,
-- .pad_setup = mt7530_pad_clk_setup,
- .mac_port_get_caps = mt7530_mac_port_get_caps,
- .mac_port_config = mt7530_mac_config,
- },
-@@ -3383,7 +3355,6 @@ const struct mt753x_info mt753x_table[]
- .phy_write_c22 = mt7530_phy_write_c22,
- .phy_read_c45 = mt7530_phy_read_c45,
- .phy_write_c45 = mt7530_phy_write_c45,
-- .pad_setup = mt7530_pad_clk_setup,
- .mac_port_get_caps = mt7530_mac_port_get_caps,
- .mac_port_config = mt7530_mac_config,
- },
-@@ -3395,7 +3366,6 @@ const struct mt753x_info mt753x_table[]
- .phy_write_c22 = mt7531_ind_c22_phy_write,
- .phy_read_c45 = mt7531_ind_c45_phy_read,
- .phy_write_c45 = mt7531_ind_c45_phy_write,
-- .pad_setup = mt7531_pad_setup,
- .cpu_port_config = mt7531_cpu_port_config,
- .mac_port_get_caps = mt7531_mac_port_get_caps,
- .mac_port_config = mt7531_mac_config,
-@@ -3408,7 +3378,6 @@ const struct mt753x_info mt753x_table[]
- .phy_write_c22 = mt7531_ind_c22_phy_write,
- .phy_read_c45 = mt7531_ind_c45_phy_read,
- .phy_write_c45 = mt7531_ind_c45_phy_write,
-- .pad_setup = mt7988_pad_setup,
- .cpu_port_config = mt7988_cpu_port_config,
- .mac_port_get_caps = mt7988_mac_port_get_caps,
- .mac_port_config = mt7988_mac_config,
-@@ -3438,9 +3407,8 @@ mt7530_probe_common(struct mt7530_priv *
- /* Sanity check if these required device operations are filled
- * properly.
- */
-- if (!priv->info->sw_setup || !priv->info->pad_setup ||
-- !priv->info->phy_read_c22 || !priv->info->phy_write_c22 ||
-- !priv->info->mac_port_get_caps ||
-+ if (!priv->info->sw_setup || !priv->info->phy_read_c22 ||
-+ !priv->info->phy_write_c22 || !priv->info->mac_port_get_caps ||
- !priv->info->mac_port_config)
- return -EINVAL;
-
---- a/drivers/net/dsa/mt7530.h
-+++ b/drivers/net/dsa/mt7530.h
-@@ -734,8 +734,6 @@ struct mt753x_pcs {
- * @phy_write_c22: Holding the way writing PHY port using C22
- * @phy_read_c45: Holding the way reading PHY port using C45
- * @phy_write_c45: Holding the way writing PHY port using C45
-- * @pad_setup: Holding the way setting up the bus pad for a certain
-- * MAC port
- * @phy_mode_supported: Check if the PHY type is being supported on a certain
- * port
- * @mac_port_validate: Holding the way to set addition validate type for a
-@@ -756,7 +754,6 @@ struct mt753x_info {
- int regnum);
- int (*phy_write_c45)(struct mt7530_priv *priv, int port, int devad,
- int regnum, u16 val);
-- int (*pad_setup)(struct dsa_switch *ds, phy_interface_t interface);
- int (*cpu_port_config)(struct dsa_switch *ds, int port);
- void (*mac_port_get_caps)(struct dsa_switch *ds, int port,
- struct phylink_config *config);
+++ /dev/null
-From 9716e3e2c21547c97a9d79119da8fdce5659c2cc Mon Sep 17 00:00:00 2001
-Date: Tue, 6 Feb 2024 01:08:07 +0300
-Subject: [PATCH 17/30] net: dsa: mt7530: correct port capabilities of MT7988
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-On the switch on the MT7988 SoC, as shown in Block Diagram 8.1.1.3 on page
-125 of "MT7988A Wi-Fi 7 Generation Router Platform: Datasheet (Open
-Version) v0.1", there are only 4 PHYs. That's port 0 to 3. Set the case for
-ports which connect to switch PHYs to '0 ... 3'.
-
-Port 4 and 5 are not used at all in this design.
-
-Link: https://wiki.banana-pi.org/Banana_Pi_BPI-R4#Documents [1]
-Link: https://lore.kernel.org/r/20240206-for-netnext-mt7530-improvements-2-v5-6-d7d92a185cb1@arinc9.com
----
- drivers/net/dsa/mt7530.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/net/dsa/mt7530.c
-+++ b/drivers/net/dsa/mt7530.c
-@@ -2786,7 +2786,7 @@ static void mt7988_mac_port_get_caps(str
-
- switch (port) {
- /* Ports which are connected to switch PHYs. There is no MII pinout. */
-- case 0 ... 4:
-+ case 0 ... 3:
- __set_bit(PHY_INTERFACE_MODE_INTERNAL,
- config->supported_interfaces);
- break;
+++ /dev/null
-From 4d7b17712513710778c0f2f83ea5d9b55ed58c36 Mon Sep 17 00:00:00 2001
-Date: Tue, 6 Feb 2024 01:08:08 +0300
-Subject: [PATCH 18/30] net: dsa: mt7530: do not clear
- config->supported_interfaces
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-There's no need to clear the config->supported_interfaces bitmap before
-reporting the supported interfaces as all bits in the bitmap will already
-be initialized to zero when the phylink_config structure is allocated. The
-"config" pointer points to &dp->phylink_config, and "dp" is allocated by
-dsa_port_touch() with kzalloc(), so all its fields are filled with zeroes.
-
-There's no code that would change the bitmap beforehand. Remove it.
-
-Link: https://lore.kernel.org/r/20240206-for-netnext-mt7530-improvements-2-v5-7-d7d92a185cb1@arinc9.com
----
- drivers/net/dsa/mt7530.c | 2 --
- 1 file changed, 2 deletions(-)
-
---- a/drivers/net/dsa/mt7530.c
-+++ b/drivers/net/dsa/mt7530.c
-@@ -2782,8 +2782,6 @@ static void mt7531_mac_port_get_caps(str
- static void mt7988_mac_port_get_caps(struct dsa_switch *ds, int port,
- struct phylink_config *config)
- {
-- phy_interface_zero(config->supported_interfaces);
--
- switch (port) {
- /* Ports which are connected to switch PHYs. There is no MII pinout. */
- case 0 ... 3:
+++ /dev/null
-From 69e689e28191f9a242de6821a85f2c5ae4dbd5ae Mon Sep 17 00:00:00 2001
-Date: Fri, 1 Mar 2024 12:42:57 +0200
-Subject: [PATCH 19/30] net: dsa: mt7530: remove .mac_port_config for MT7988
- and make it optional
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-For the switch on the MT7988 SoC, the mac_port_config member for ID_MT7988
-in mt753x_table is not needed as the interfaces of all MACs are already
-handled on mt7988_mac_port_get_caps().
-
-Therefore, remove the mac_port_config member from ID_MT7988 in
-mt753x_table. Before calling priv->info->mac_port_config(), if there's no
-mac_port_config member in mt753x_table, exit mt753x_mac_config()
-successfully.
-
-Remove calling priv->info->mac_port_config() from the sanity check as the
-sanity check requires a pointer to a mac_port_config function to be
-non-NULL. This will fail for MT7988 as mac_port_config won't be a member of
-its info table.
-
----
- drivers/net/dsa/mt7530.c | 18 ++++--------------
- 1 file changed, 4 insertions(+), 14 deletions(-)
-
---- a/drivers/net/dsa/mt7530.c
-+++ b/drivers/net/dsa/mt7530.c
-@@ -2865,17 +2865,6 @@ static bool mt753x_is_mac_port(u32 port)
- }
-
- static int
--mt7988_mac_config(struct dsa_switch *ds, int port, unsigned int mode,
-- phy_interface_t interface)
--{
-- if (dsa_is_cpu_port(ds, port) &&
-- interface == PHY_INTERFACE_MODE_INTERNAL)
-- return 0;
--
-- return -EINVAL;
--}
--
--static int
- mt7531_mac_config(struct dsa_switch *ds, int port, unsigned int mode,
- phy_interface_t interface)
- {
-@@ -2915,6 +2904,9 @@ mt753x_mac_config(struct dsa_switch *ds,
- {
- struct mt7530_priv *priv = ds->priv;
-
-+ if (!priv->info->mac_port_config)
-+ return 0;
-+
- return priv->info->mac_port_config(ds, port, mode, state->interface);
- }
-
-@@ -3378,7 +3370,6 @@ const struct mt753x_info mt753x_table[]
- .phy_write_c45 = mt7531_ind_c45_phy_write,
- .cpu_port_config = mt7988_cpu_port_config,
- .mac_port_get_caps = mt7988_mac_port_get_caps,
-- .mac_port_config = mt7988_mac_config,
- },
- };
- EXPORT_SYMBOL_GPL(mt753x_table);
-@@ -3406,8 +3397,7 @@ mt7530_probe_common(struct mt7530_priv *
- * properly.
- */
- if (!priv->info->sw_setup || !priv->info->phy_read_c22 ||
-- !priv->info->phy_write_c22 || !priv->info->mac_port_get_caps ||
-- !priv->info->mac_port_config)
-+ !priv->info->phy_write_c22 || !priv->info->mac_port_get_caps)
- return -EINVAL;
-
- priv->id = priv->info->id;
+++ /dev/null
-From f8faa3a04ca860b31f22d7d526c5e3f3de511a8f Mon Sep 17 00:00:00 2001
-Date: Fri, 1 Mar 2024 12:42:58 +0200
-Subject: [PATCH 20/30] net: dsa: mt7530: set interrupt register only for
- MT7530
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Setting this register related to interrupts is only needed for the MT7530
-switch. Make an exclusive check to ensure this.
-
----
- drivers/net/dsa/mt7530.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/net/dsa/mt7530.c
-+++ b/drivers/net/dsa/mt7530.c
-@@ -2254,7 +2254,7 @@ mt7530_setup_irq(struct mt7530_priv *pri
- }
-
- /* This register must be set for MT7530 to properly fire interrupts */
-- if (priv->id != ID_MT7531)
-+ if (priv->id == ID_MT7530 || priv->id == ID_MT7621)
- mt7530_set(priv, MT7530_TOP_SIG_CTRL, TOP_SIG_CTRL_NORMAL);
-
- ret = request_threaded_irq(priv->irq, NULL, mt7530_irq_thread_fn,
+++ /dev/null
-From 80f4f866d7dad41b12cf37476c38766a89b8b5c4 Mon Sep 17 00:00:00 2001
-Date: Fri, 1 Mar 2024 12:42:59 +0200
-Subject: [PATCH 21/30] net: dsa: mt7530: do not use SW_PHY_RST to reset MT7531
- switch
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-According to the document MT7531 Reference Manual for Development Board
-v1.0, the SW_PHY_RST bit on the SYS_CTRL register doesn't exist for
-MT7531. This is likely why forcing link down on all ports is necessary for
-MT7531.
-
-Therefore, do not set SW_PHY_RST on mt7531_setup().
-
----
- drivers/net/dsa/mt7530.c | 6 ++----
- 1 file changed, 2 insertions(+), 4 deletions(-)
-
---- a/drivers/net/dsa/mt7530.c
-+++ b/drivers/net/dsa/mt7530.c
-@@ -2661,14 +2661,12 @@ mt7531_setup(struct dsa_switch *ds)
- val = mt7530_read(priv, MT7531_TOP_SIG_SR);
- priv->p5_sgmii = !!(val & PAD_DUAL_SGMII_EN);
-
-- /* all MACs must be forced link-down before sw reset */
-+ /* Force link down on all ports before internal reset */
- for (i = 0; i < MT7530_NUM_PORTS; i++)
- mt7530_write(priv, MT7530_PMCR_P(i), MT7531_FORCE_LNK);
-
- /* Reset the switch through internal reset */
-- mt7530_write(priv, MT7530_SYS_CTRL,
-- SYS_CTRL_PHY_RST | SYS_CTRL_SW_RST |
-- SYS_CTRL_REG_RST);
-+ mt7530_write(priv, MT7530_SYS_CTRL, SYS_CTRL_SW_RST | SYS_CTRL_REG_RST);
-
- if (!priv->p5_sgmii) {
- mt7531_pll_setup(priv);
+++ /dev/null
-From 58670652cacb7c5752e01f29979d0ca4cdbfcc0a Mon Sep 17 00:00:00 2001
-Date: Fri, 1 Mar 2024 12:43:00 +0200
-Subject: [PATCH 22/30] net: dsa: mt7530: get rid of useless error returns on
- phylink code path
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Remove error returns on the cases where they are already handled with the
-function the mac_port_get_caps member in mt753x_table points to.
-
-mt7531_mac_config() is also called from mt7531_cpu_port_config() outside of
-phylink but the port and interface modes are already handled there.
-
-Change the functions and the mac_port_config function pointer to void now
-that there're no error returns anymore.
-
-Remove mt753x_is_mac_port() that used to help the said error returns.
-
-On mt7531_mac_config(), switch to if statements to simplify the code.
-
-Remove internal phy cases from mt753x_phylink_mac_config(), there is no
-need to check the interface mode as that's already handled with the
-function the mac_port_get_caps member in mt753x_table points to.
-
----
- drivers/net/dsa/mt7530.c | 81 ++++++++--------------------------------
- drivers/net/dsa/mt7530.h | 6 +--
- 2 files changed, 19 insertions(+), 68 deletions(-)
-
---- a/drivers/net/dsa/mt7530.c
-+++ b/drivers/net/dsa/mt7530.c
-@@ -2796,7 +2796,7 @@ static void mt7988_mac_port_get_caps(str
- }
- }
-
--static int
-+static void
- mt7530_mac_config(struct dsa_switch *ds, int port, unsigned int mode,
- phy_interface_t interface)
- {
-@@ -2806,22 +2806,14 @@ mt7530_mac_config(struct dsa_switch *ds,
- mt7530_setup_port5(priv->ds, interface);
- else if (port == 6)
- mt7530_setup_port6(priv->ds, interface);
--
-- return 0;
- }
-
--static int mt7531_rgmii_setup(struct mt7530_priv *priv, u32 port,
-- phy_interface_t interface,
-- struct phy_device *phydev)
-+static void mt7531_rgmii_setup(struct mt7530_priv *priv, u32 port,
-+ phy_interface_t interface,
-+ struct phy_device *phydev)
- {
- u32 val;
-
-- if (priv->p5_sgmii) {
-- dev_err(priv->dev, "RGMII mode is not available for port %d\n",
-- port);
-- return -EINVAL;
-- }
--
- val = mt7530_read(priv, MT7531_CLKGEN_CTRL);
- val |= GP_CLK_EN;
- val &= ~GP_MODE_MASK;
-@@ -2849,20 +2841,14 @@ static int mt7531_rgmii_setup(struct mt7
- case PHY_INTERFACE_MODE_RGMII_ID:
- break;
- default:
-- return -EINVAL;
-+ break;
- }
- }
-- mt7530_write(priv, MT7531_CLKGEN_CTRL, val);
-
-- return 0;
--}
--
--static bool mt753x_is_mac_port(u32 port)
--{
-- return (port == 5 || port == 6);
-+ mt7530_write(priv, MT7531_CLKGEN_CTRL, val);
- }
-
--static int
-+static void
- mt7531_mac_config(struct dsa_switch *ds, int port, unsigned int mode,
- phy_interface_t interface)
- {
-@@ -2870,42 +2856,21 @@ mt7531_mac_config(struct dsa_switch *ds,
- struct phy_device *phydev;
- struct dsa_port *dp;
-
-- if (!mt753x_is_mac_port(port)) {
-- dev_err(priv->dev, "port %d is not a MAC port\n", port);
-- return -EINVAL;
-- }
--
-- switch (interface) {
-- case PHY_INTERFACE_MODE_RGMII:
-- case PHY_INTERFACE_MODE_RGMII_ID:
-- case PHY_INTERFACE_MODE_RGMII_RXID:
-- case PHY_INTERFACE_MODE_RGMII_TXID:
-+ if (phy_interface_mode_is_rgmii(interface)) {
- dp = dsa_to_port(ds, port);
- phydev = dp->slave->phydev;
-- return mt7531_rgmii_setup(priv, port, interface, phydev);
-- case PHY_INTERFACE_MODE_SGMII:
-- case PHY_INTERFACE_MODE_NA:
-- case PHY_INTERFACE_MODE_1000BASEX:
-- case PHY_INTERFACE_MODE_2500BASEX:
-- /* handled in SGMII PCS driver */
-- return 0;
-- default:
-- return -EINVAL;
-+ mt7531_rgmii_setup(priv, port, interface, phydev);
- }
--
-- return -EINVAL;
- }
-
--static int
-+static void
- mt753x_mac_config(struct dsa_switch *ds, int port, unsigned int mode,
- const struct phylink_link_state *state)
- {
- struct mt7530_priv *priv = ds->priv;
-
-- if (!priv->info->mac_port_config)
-- return 0;
--
-- return priv->info->mac_port_config(ds, port, mode, state->interface);
-+ if (priv->info->mac_port_config)
-+ priv->info->mac_port_config(ds, port, mode, state->interface);
- }
-
- static struct phylink_pcs *
-@@ -2934,17 +2899,11 @@ mt753x_phylink_mac_config(struct dsa_swi
- u32 mcr_cur, mcr_new;
-
- switch (port) {
-- case 0 ... 4:
-- if (state->interface != PHY_INTERFACE_MODE_GMII &&
-- state->interface != PHY_INTERFACE_MODE_INTERNAL)
-- goto unsupported;
-- break;
- case 5:
- if (priv->p5_interface == state->interface)
- break;
-
-- if (mt753x_mac_config(ds, port, mode, state) < 0)
-- goto unsupported;
-+ mt753x_mac_config(ds, port, mode, state);
-
- if (priv->p5_intf_sel != P5_DISABLED)
- priv->p5_interface = state->interface;
-@@ -2953,16 +2912,10 @@ mt753x_phylink_mac_config(struct dsa_swi
- if (priv->p6_interface == state->interface)
- break;
-
-- if (mt753x_mac_config(ds, port, mode, state) < 0)
-- goto unsupported;
-+ mt753x_mac_config(ds, port, mode, state);
-
- priv->p6_interface = state->interface;
- break;
-- default:
--unsupported:
-- dev_err(ds->dev, "%s: unsupported %s port: %i\n",
-- __func__, phy_modes(state->interface), port);
-- return;
- }
-
- mcr_cur = mt7530_read(priv, MT7530_PMCR_P(port));
-@@ -3045,7 +2998,6 @@ mt7531_cpu_port_config(struct dsa_switch
- struct mt7530_priv *priv = ds->priv;
- phy_interface_t interface;
- int speed;
-- int ret;
-
- switch (port) {
- case 5:
-@@ -3070,9 +3022,8 @@ mt7531_cpu_port_config(struct dsa_switch
- else
- speed = SPEED_1000;
-
-- ret = mt7531_mac_config(ds, port, MLO_AN_FIXED, interface);
-- if (ret)
-- return ret;
-+ mt7531_mac_config(ds, port, MLO_AN_FIXED, interface);
-+
- mt7530_write(priv, MT7530_PMCR_P(port),
- PMCR_CPU_PORT_SETTING(priv->id));
- mt753x_phylink_mac_link_up(ds, port, MLO_AN_FIXED, interface, NULL,
---- a/drivers/net/dsa/mt7530.h
-+++ b/drivers/net/dsa/mt7530.h
-@@ -760,9 +760,9 @@ struct mt753x_info {
- void (*mac_port_validate)(struct dsa_switch *ds, int port,
- phy_interface_t interface,
- unsigned long *supported);
-- int (*mac_port_config)(struct dsa_switch *ds, int port,
-- unsigned int mode,
-- phy_interface_t interface);
-+ void (*mac_port_config)(struct dsa_switch *ds, int port,
-+ unsigned int mode,
-+ phy_interface_t interface);
- };
-
- /* struct mt7530_priv - This is the main data structure for holding the state
+++ /dev/null
-From 859df5cf6ff07a9c930be4681284346aa73dd1fb Mon Sep 17 00:00:00 2001
-Date: Fri, 1 Mar 2024 12:43:01 +0200
-Subject: [PATCH 23/30] net: dsa: mt7530: get rid of
- priv->info->cpu_port_config()
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-priv->info->cpu_port_config() is used for MT7531 and the switch on the
-MT7988 SoC. It sets up the ports described as a CPU port earlier than the
-phylink code path would do.
-
-This function is useless as:
-- Configuring the MACs can be done from the phylink_mac_config code path
- instead.
-- All the link configuration it does on the CPU ports are later undone with
- the port_enable, phylink_mac_config, and then phylink_mac_link_up code
- path [1].
-
-priv->p5_interface and priv->p6_interface were being used to prevent
-configuring the MACs from the phylink_mac_config code path. Remove them now
-that they hold no purpose.
-
-Remove priv->info->cpu_port_config(). On mt753x_phylink_mac_config, switch
-to if statements to simplify the code.
-
-Remove the overwriting of the speed and duplex interfaces for certain
-interface modes. Phylink already provides the speed and duplex variables
-with proper values. Phylink already sets the max speed of TRGMII to
-SPEED_1000. Add SPEED_2500 for PHY_INTERFACE_MODE_2500BASEX to where the
-speed and EEE bits are set instead.
-
-On the switch on the MT7988 SoC, PHY_INTERFACE_MODE_INTERNAL is being used
-to describe the interface mode of the 10G MAC, which is of port 6. On
-mt7988_cpu_port_config() PMCR_FORCE_SPEED_1000 was set via the
-PMCR_CPU_PORT_SETTING() mask. Add SPEED_10000 case to where the speed bits
-are set to cover this. No need to add it to where the EEE bits are set as
-the "MT7988A Wi-Fi 7 Generation Router Platform: Datasheet (Open Version)
-v0.1" document shows that these bits don't exist on the MT7530_PMCR_P(6)
-register.
-
-Remove the definition of PMCR_CPU_PORT_SETTING() now that it holds no
-purpose.
-
-Change mt753x_cpu_port_enable() to void now that there're no error cases
-left.
-
----
- drivers/net/dsa/mt7530.c | 114 +++------------------------------------
- drivers/net/dsa/mt7530.h | 11 ----
- 2 files changed, 7 insertions(+), 118 deletions(-)
-
---- a/drivers/net/dsa/mt7530.c
-+++ b/drivers/net/dsa/mt7530.c
-@@ -1163,18 +1163,10 @@ mt753x_trap_frames(struct mt7530_priv *p
- MT753X_BPDU_CPU_ONLY);
- }
-
--static int
-+static void
- mt753x_cpu_port_enable(struct dsa_switch *ds, int port)
- {
- struct mt7530_priv *priv = ds->priv;
-- int ret;
--
-- /* Setup max capability of CPU port at first */
-- if (priv->info->cpu_port_config) {
-- ret = priv->info->cpu_port_config(ds, port);
-- if (ret)
-- return ret;
-- }
-
- /* Enable Mediatek header mode on the cpu port */
- mt7530_write(priv, MT7530_PVC_P(port),
-@@ -1200,8 +1192,6 @@ mt753x_cpu_port_enable(struct dsa_switch
- /* Set to fallback mode for independent VLAN learning */
- mt7530_rmw(priv, MT7530_PCR_P(port), PCR_PORT_VLAN_MASK,
- MT7530_PORT_FALLBACK_MODE);
--
-- return 0;
- }
-
- static int
-@@ -2458,8 +2448,6 @@ mt7530_setup(struct dsa_switch *ds)
- val |= MHWTRAP_MANUAL;
- mt7530_write(priv, MT7530_MHWTRAP, val);
-
-- priv->p6_interface = PHY_INTERFACE_MODE_NA;
--
- if ((val & HWTRAP_XTAL_MASK) == HWTRAP_XTAL_40MHZ)
- mt7530_pll_setup(priv);
-
-@@ -2477,9 +2465,7 @@ mt7530_setup(struct dsa_switch *ds)
- mt7530_set(priv, MT7530_PSC_P(i), SA_DIS);
-
- if (dsa_is_cpu_port(ds, i)) {
-- ret = mt753x_cpu_port_enable(ds, i);
-- if (ret)
-- return ret;
-+ mt753x_cpu_port_enable(ds, i);
- } else {
- mt7530_port_disable(ds, i);
-
-@@ -2589,9 +2575,7 @@ mt7531_setup_common(struct dsa_switch *d
- mt7530_set(priv, MT7531_DBG_CNT(i), MT7531_DIS_CLR);
-
- if (dsa_is_cpu_port(ds, i)) {
-- ret = mt753x_cpu_port_enable(ds, i);
-- if (ret)
-- return ret;
-+ mt753x_cpu_port_enable(ds, i);
- } else {
- mt7530_port_disable(ds, i);
-
-@@ -2684,10 +2668,6 @@ mt7531_setup(struct dsa_switch *ds)
- mt7530_rmw(priv, MT7531_GPIO_MODE0, MT7531_GPIO0_MASK,
- MT7531_GPIO0_INTERRUPT);
-
-- /* Let phylink decide the interface later. */
-- priv->p5_interface = PHY_INTERFACE_MODE_NA;
-- priv->p6_interface = PHY_INTERFACE_MODE_NA;
--
- /* Enable Energy-Efficient Ethernet (EEE) and PHY core PLL, since
- * phy_device has not yet been created provided for
- * phy_[read,write]_mmd_indirect is called, we provide our own
-@@ -2898,26 +2878,9 @@ mt753x_phylink_mac_config(struct dsa_swi
- struct mt7530_priv *priv = ds->priv;
- u32 mcr_cur, mcr_new;
-
-- switch (port) {
-- case 5:
-- if (priv->p5_interface == state->interface)
-- break;
--
-+ if (port == 5 || port == 6)
- mt753x_mac_config(ds, port, mode, state);
-
-- if (priv->p5_intf_sel != P5_DISABLED)
-- priv->p5_interface = state->interface;
-- break;
-- case 6:
-- if (priv->p6_interface == state->interface)
-- break;
--
-- mt753x_mac_config(ds, port, mode, state);
--
-- priv->p6_interface = state->interface;
-- break;
-- }
--
- mcr_cur = mt7530_read(priv, MT7530_PMCR_P(port));
- mcr_new = mcr_cur;
- mcr_new &= ~PMCR_LINK_SETTINGS_MASK;
-@@ -2953,17 +2916,10 @@ static void mt753x_phylink_mac_link_up(s
-
- mcr = PMCR_RX_EN | PMCR_TX_EN | PMCR_FORCE_LNK;
-
-- /* MT753x MAC works in 1G full duplex mode for all up-clocked
-- * variants.
-- */
-- if (interface == PHY_INTERFACE_MODE_TRGMII ||
-- (phy_interface_mode_is_8023z(interface))) {
-- speed = SPEED_1000;
-- duplex = DUPLEX_FULL;
-- }
--
- switch (speed) {
- case SPEED_1000:
-+ case SPEED_2500:
-+ case SPEED_10000:
- mcr |= PMCR_FORCE_SPEED_1000;
- break;
- case SPEED_100:
-@@ -2981,6 +2937,7 @@ static void mt753x_phylink_mac_link_up(s
- if (mode == MLO_AN_PHY && phydev && phy_init_eee(phydev, false) >= 0) {
- switch (speed) {
- case SPEED_1000:
-+ case SPEED_2500:
- mcr |= PMCR_FORCE_EEE1G;
- break;
- case SPEED_100:
-@@ -2992,61 +2949,6 @@ static void mt753x_phylink_mac_link_up(s
- mt7530_set(priv, MT7530_PMCR_P(port), mcr);
- }
-
--static int
--mt7531_cpu_port_config(struct dsa_switch *ds, int port)
--{
-- struct mt7530_priv *priv = ds->priv;
-- phy_interface_t interface;
-- int speed;
--
-- switch (port) {
-- case 5:
-- if (!priv->p5_sgmii)
-- interface = PHY_INTERFACE_MODE_RGMII;
-- else
-- interface = PHY_INTERFACE_MODE_2500BASEX;
--
-- priv->p5_interface = interface;
-- break;
-- case 6:
-- interface = PHY_INTERFACE_MODE_2500BASEX;
--
-- priv->p6_interface = interface;
-- break;
-- default:
-- return -EINVAL;
-- }
--
-- if (interface == PHY_INTERFACE_MODE_2500BASEX)
-- speed = SPEED_2500;
-- else
-- speed = SPEED_1000;
--
-- mt7531_mac_config(ds, port, MLO_AN_FIXED, interface);
--
-- mt7530_write(priv, MT7530_PMCR_P(port),
-- PMCR_CPU_PORT_SETTING(priv->id));
-- mt753x_phylink_mac_link_up(ds, port, MLO_AN_FIXED, interface, NULL,
-- speed, DUPLEX_FULL, true, true);
--
-- return 0;
--}
--
--static int
--mt7988_cpu_port_config(struct dsa_switch *ds, int port)
--{
-- struct mt7530_priv *priv = ds->priv;
--
-- mt7530_write(priv, MT7530_PMCR_P(port),
-- PMCR_CPU_PORT_SETTING(priv->id));
--
-- mt753x_phylink_mac_link_up(ds, port, MLO_AN_FIXED,
-- PHY_INTERFACE_MODE_INTERNAL, NULL,
-- SPEED_10000, DUPLEX_FULL, true, true);
--
-- return 0;
--}
--
- static void mt753x_phylink_get_caps(struct dsa_switch *ds, int port,
- struct phylink_config *config)
- {
-@@ -3305,7 +3207,6 @@ const struct mt753x_info mt753x_table[]
- .phy_write_c22 = mt7531_ind_c22_phy_write,
- .phy_read_c45 = mt7531_ind_c45_phy_read,
- .phy_write_c45 = mt7531_ind_c45_phy_write,
-- .cpu_port_config = mt7531_cpu_port_config,
- .mac_port_get_caps = mt7531_mac_port_get_caps,
- .mac_port_config = mt7531_mac_config,
- },
-@@ -3317,7 +3218,6 @@ const struct mt753x_info mt753x_table[]
- .phy_write_c22 = mt7531_ind_c22_phy_write,
- .phy_read_c45 = mt7531_ind_c45_phy_read,
- .phy_write_c45 = mt7531_ind_c45_phy_write,
-- .cpu_port_config = mt7988_cpu_port_config,
- .mac_port_get_caps = mt7988_mac_port_get_caps,
- },
- };
---- a/drivers/net/dsa/mt7530.h
-+++ b/drivers/net/dsa/mt7530.h
-@@ -340,13 +340,6 @@ enum mt7530_vlan_port_acc_frm {
- PMCR_TX_FC_EN | PMCR_RX_FC_EN | \
- PMCR_FORCE_FDX | PMCR_FORCE_LNK | \
- PMCR_FORCE_EEE1G | PMCR_FORCE_EEE100)
--#define PMCR_CPU_PORT_SETTING(id) (PMCR_FORCE_MODE_ID((id)) | \
-- PMCR_IFG_XMIT(1) | PMCR_MAC_MODE | \
-- PMCR_BACKOFF_EN | PMCR_BACKPR_EN | \
-- PMCR_TX_EN | PMCR_RX_EN | \
-- PMCR_TX_FC_EN | PMCR_RX_FC_EN | \
-- PMCR_FORCE_SPEED_1000 | \
-- PMCR_FORCE_FDX | PMCR_FORCE_LNK)
-
- #define MT7530_PMEEECR_P(x) (0x3004 + (x) * 0x100)
- #define WAKEUP_TIME_1000(x) (((x) & 0xFF) << 24)
-@@ -754,7 +747,6 @@ struct mt753x_info {
- int regnum);
- int (*phy_write_c45)(struct mt7530_priv *priv, int port, int devad,
- int regnum, u16 val);
-- int (*cpu_port_config)(struct dsa_switch *ds, int port);
- void (*mac_port_get_caps)(struct dsa_switch *ds, int port,
- struct phylink_config *config);
- void (*mac_port_validate)(struct dsa_switch *ds, int port,
-@@ -780,7 +772,6 @@ struct mt753x_info {
- * @ports: Holding the state among ports
- * @reg_mutex: The lock for protecting among process accessing
- * registers
-- * @p6_interface Holding the current port 6 interface
- * @p5_intf_sel: Holding the current port 5 interface select
- * @p5_sgmii: Flag for distinguishing if port 5 of the MT7531 switch
- * has got SGMII
-@@ -802,8 +793,6 @@ struct mt7530_priv {
- const struct mt753x_info *info;
- unsigned int id;
- bool mcm;
-- phy_interface_t p6_interface;
-- phy_interface_t p5_interface;
- enum p5_interface_select p5_intf_sel;
- bool p5_sgmii;
- u8 mirror_rx;
+++ /dev/null
-From c74a98baa8d098157975b3f94e496dd3a73e0864 Mon Sep 17 00:00:00 2001
-Date: Fri, 1 Mar 2024 12:43:02 +0200
-Subject: [PATCH 24/30] net: dsa: mt7530: get rid of mt753x_mac_config()
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-There is no need for a separate function to call
-priv->info->mac_port_config(). Call it from mt753x_phylink_mac_config()
-instead and remove mt753x_mac_config().
-
----
- drivers/net/dsa/mt7530.c | 14 ++------------
- 1 file changed, 2 insertions(+), 12 deletions(-)
-
---- a/drivers/net/dsa/mt7530.c
-+++ b/drivers/net/dsa/mt7530.c
-@@ -2843,16 +2843,6 @@ mt7531_mac_config(struct dsa_switch *ds,
- }
- }
-
--static void
--mt753x_mac_config(struct dsa_switch *ds, int port, unsigned int mode,
-- const struct phylink_link_state *state)
--{
-- struct mt7530_priv *priv = ds->priv;
--
-- if (priv->info->mac_port_config)
-- priv->info->mac_port_config(ds, port, mode, state->interface);
--}
--
- static struct phylink_pcs *
- mt753x_phylink_mac_select_pcs(struct dsa_switch *ds, int port,
- phy_interface_t interface)
-@@ -2878,8 +2868,8 @@ mt753x_phylink_mac_config(struct dsa_swi
- struct mt7530_priv *priv = ds->priv;
- u32 mcr_cur, mcr_new;
-
-- if (port == 5 || port == 6)
-- mt753x_mac_config(ds, port, mode, state);
-+ if ((port == 5 || port == 6) && priv->info->mac_port_config)
-+ priv->info->mac_port_config(ds, port, mode, state->interface);
-
- mcr_cur = mt7530_read(priv, MT7530_PMCR_P(port));
- mcr_new = mcr_cur;
+++ /dev/null
-From ab1ddb241bc1cb3d80aa51207810edd5cb0bbdc5 Mon Sep 17 00:00:00 2001
-Date: Fri, 1 Mar 2024 12:43:03 +0200
-Subject: [PATCH 25/30] net: dsa: mt7530: put initialising PCS devices code
- back to original order
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-The commit fae463084032 ("net: dsa: mt753x: fix pcs conversion regression")
-fixes regression caused by cpu_port_config manually calling phylink
-operations. cpu_port_config was deemed useless and was removed. Therefore,
-put initialising PCS devices code back to its original order.
-
----
- drivers/net/dsa/mt7530.c | 20 ++++++++++----------
- 1 file changed, 10 insertions(+), 10 deletions(-)
-
---- a/drivers/net/dsa/mt7530.c
-+++ b/drivers/net/dsa/mt7530.c
-@@ -3021,17 +3021,9 @@ static int
- mt753x_setup(struct dsa_switch *ds)
- {
- struct mt7530_priv *priv = ds->priv;
-- int i, ret;
-+ int ret = priv->info->sw_setup(ds);
-+ int i;
-
-- /* Initialise the PCS devices */
-- for (i = 0; i < priv->ds->num_ports; i++) {
-- priv->pcs[i].pcs.ops = priv->info->pcs_ops;
-- priv->pcs[i].pcs.neg_mode = true;
-- priv->pcs[i].priv = priv;
-- priv->pcs[i].port = i;
-- }
--
-- ret = priv->info->sw_setup(ds);
- if (ret)
- return ret;
-
-@@ -3043,6 +3035,14 @@ mt753x_setup(struct dsa_switch *ds)
- if (ret && priv->irq)
- mt7530_free_irq_common(priv);
-
-+ /* Initialise the PCS devices */
-+ for (i = 0; i < priv->ds->num_ports; i++) {
-+ priv->pcs[i].pcs.ops = priv->info->pcs_ops;
-+ priv->pcs[i].pcs.neg_mode = true;
-+ priv->pcs[i].priv = priv;
-+ priv->pcs[i].port = i;
-+ }
-+
- if (priv->create_sgmii) {
- ret = priv->create_sgmii(priv);
- if (ret && priv->irq)
+++ /dev/null
-From aa474698f75f4790a4de2052dd487736d2361b2e Mon Sep 17 00:00:00 2001
-Date: Fri, 1 Mar 2024 12:43:04 +0200
-Subject: [PATCH 26/30] net: dsa: mt7530: sort link settings ops and force link
- down on all ports
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-port_enable and port_disable clears the link settings. Move that to
-mt7530_setup() and mt7531_setup_common() which set up the switches. This
-way, the link settings are cleared on all ports at setup, and then only
-once with phylink_mac_link_down() when a link goes down.
-
-Enable force mode at setup to apply the force part of the link settings.
-This ensures that disabled ports will have their link down.
-
----
- drivers/net/dsa/mt7530.c | 14 ++++++++++++--
- 1 file changed, 12 insertions(+), 2 deletions(-)
-
---- a/drivers/net/dsa/mt7530.c
-+++ b/drivers/net/dsa/mt7530.c
-@@ -1215,7 +1215,6 @@ mt7530_port_enable(struct dsa_switch *ds
- priv->ports[port].enable = true;
- mt7530_rmw(priv, MT7530_PCR_P(port), PCR_MATRIX_MASK,
- priv->ports[port].pm);
-- mt7530_clear(priv, MT7530_PMCR_P(port), PMCR_LINK_SETTINGS_MASK);
-
- mutex_unlock(&priv->reg_mutex);
-
-@@ -1235,7 +1234,6 @@ mt7530_port_disable(struct dsa_switch *d
- priv->ports[port].enable = false;
- mt7530_rmw(priv, MT7530_PCR_P(port), PCR_MATRIX_MASK,
- PCR_MATRIX_CLR);
-- mt7530_clear(priv, MT7530_PMCR_P(port), PMCR_LINK_SETTINGS_MASK);
-
- mutex_unlock(&priv->reg_mutex);
- }
-@@ -2457,6 +2455,12 @@ mt7530_setup(struct dsa_switch *ds)
- mt7530_mib_reset(ds);
-
- for (i = 0; i < MT7530_NUM_PORTS; i++) {
-+ /* Clear link settings and enable force mode to force link down
-+ * on all ports until they're enabled later.
-+ */
-+ mt7530_rmw(priv, MT7530_PMCR_P(i), PMCR_LINK_SETTINGS_MASK |
-+ PMCR_FORCE_MODE, PMCR_FORCE_MODE);
-+
- /* Disable forwarding by default on all ports */
- mt7530_rmw(priv, MT7530_PCR_P(i), PCR_MATRIX_MASK,
- PCR_MATRIX_CLR);
-@@ -2565,6 +2569,12 @@ mt7531_setup_common(struct dsa_switch *d
- UNU_FFP_MASK);
-
- for (i = 0; i < MT7530_NUM_PORTS; i++) {
-+ /* Clear link settings and enable force mode to force link down
-+ * on all ports until they're enabled later.
-+ */
-+ mt7530_rmw(priv, MT7530_PMCR_P(i), PMCR_LINK_SETTINGS_MASK |
-+ MT7531_FORCE_MODE, MT7531_FORCE_MODE);
-+
- /* Disable forwarding by default on all ports */
- mt7530_rmw(priv, MT7530_PCR_P(i), PCR_MATRIX_MASK,
- PCR_MATRIX_CLR);
+++ /dev/null
-From 1ca89c2e349d7c5e045911d741dacf4c83d029e7 Mon Sep 17 00:00:00 2001
-Date: Fri, 1 Mar 2024 12:43:05 +0200
-Subject: [PATCH 27/30] net: dsa: mt7530: simplify link operations
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-The "MT7621 Giga Switch Programming Guide v0.3", "MT7531 Reference Manual
-for Development Board v1.0", and "MT7988A Wi-Fi 7 Generation Router
-Platform: Datasheet (Open Version) v0.1" documents show that these bits are
-enabled at reset:
-
-PMCR_IFG_XMIT(1) (not part of PMCR_LINK_SETTINGS_MASK)
-PMCR_MAC_MODE (not part of PMCR_LINK_SETTINGS_MASK)
-PMCR_TX_EN
-PMCR_RX_EN
-PMCR_BACKOFF_EN (not part of PMCR_LINK_SETTINGS_MASK)
-PMCR_BACKPR_EN (not part of PMCR_LINK_SETTINGS_MASK)
-PMCR_TX_FC_EN
-PMCR_RX_FC_EN
-
-These bits also don't exist on the MT7530_PMCR_P(6) register of the switch
-on the MT7988 SoC:
-
-PMCR_IFG_XMIT()
-PMCR_MAC_MODE
-PMCR_BACKOFF_EN
-PMCR_BACKPR_EN
-
-Remove the setting of the bits not part of PMCR_LINK_SETTINGS_MASK on
-phylink_mac_config as they're already set.
-
-The bit for setting the port on force mode is already done on
-mt7530_setup() and mt7531_setup_common(). So get rid of
-PMCR_FORCE_MODE_ID() which helped determine which bit to use for the switch
-model.
-
----
- drivers/net/dsa/mt7530.c | 12 +-----------
- drivers/net/dsa/mt7530.h | 2 --
- 2 files changed, 1 insertion(+), 13 deletions(-)
-
---- a/drivers/net/dsa/mt7530.c
-+++ b/drivers/net/dsa/mt7530.c
-@@ -2876,23 +2876,13 @@ mt753x_phylink_mac_config(struct dsa_swi
- const struct phylink_link_state *state)
- {
- struct mt7530_priv *priv = ds->priv;
-- u32 mcr_cur, mcr_new;
-
- if ((port == 5 || port == 6) && priv->info->mac_port_config)
- priv->info->mac_port_config(ds, port, mode, state->interface);
-
-- mcr_cur = mt7530_read(priv, MT7530_PMCR_P(port));
-- mcr_new = mcr_cur;
-- mcr_new &= ~PMCR_LINK_SETTINGS_MASK;
-- mcr_new |= PMCR_IFG_XMIT(1) | PMCR_MAC_MODE | PMCR_BACKOFF_EN |
-- PMCR_BACKPR_EN | PMCR_FORCE_MODE_ID(priv->id);
--
- /* Are we connected to external phy */
- if (port == 5 && dsa_is_user_port(ds, 5))
-- mcr_new |= PMCR_EXT_PHY;
--
-- if (mcr_new != mcr_cur)
-- mt7530_write(priv, MT7530_PMCR_P(port), mcr_new);
-+ mt7530_set(priv, MT7530_PMCR_P(port), PMCR_EXT_PHY);
- }
-
- static void mt753x_phylink_mac_link_down(struct dsa_switch *ds, int port,
---- a/drivers/net/dsa/mt7530.h
-+++ b/drivers/net/dsa/mt7530.h
-@@ -333,8 +333,6 @@ enum mt7530_vlan_port_acc_frm {
- MT7531_FORCE_DPX | \
- MT7531_FORCE_RX_FC | \
- MT7531_FORCE_TX_FC)
--#define PMCR_FORCE_MODE_ID(id) ((((id) == ID_MT7531) || ((id) == ID_MT7988)) ? \
-- MT7531_FORCE_MODE : PMCR_FORCE_MODE)
- #define PMCR_LINK_SETTINGS_MASK (PMCR_TX_EN | PMCR_FORCE_SPEED_1000 | \
- PMCR_RX_EN | PMCR_FORCE_SPEED_100 | \
- PMCR_TX_FC_EN | PMCR_RX_FC_EN | \
+++ /dev/null
-From de16cf680331cd0bd7db97c3f8d376f5eac39cae Mon Sep 17 00:00:00 2001
-Date: Tue, 5 Mar 2024 06:39:51 +0200
-Subject: [PATCH 28/30] net: dsa: mt7530: disable LEDs before reset
-
-Disable LEDs just before resetting the MT7530 to avoid
-situations where the ESW_P4_LED_0 and ESW_P3_LED_0 pin
-states may cause an unintended external crystal frequency
-to be selected.
-
-The HT_XTAL_FSEL (External Crystal Frequency Selection)
-field of HWTRAP (the Hardware Trap register) stores a
-2-bit value that represents the state of the ESW_P4_LED_0
-and ESW_P4_LED_0 pins (seemingly) sampled just after the
-MT7530 has been reset, as:
-
- ESW_P4_LED_0 ESW_P3_LED_0 Frequency
- -----------------------------------------
- 0 1 20MHz
- 1 0 40MHz
- 1 1 25MHz
-
-The value of HT_XTAL_FSEL is bootstrapped by pulling
-ESW_P4_LED_0 and ESW_P3_LED_0 up or down accordingly,
-but:
-
- if a 40MHz crystal has been selected and
- the ESW_P3_LED_0 pin is high during reset,
-
- or a 20MHz crystal has been selected and
- the ESW_P4_LED_0 pin is high during reset,
-
- then the value of HT_XTAL_FSEL will indicate
- that a 25MHz crystal is present.
-
-By default, the state of the LED pins is PHY controlled
-to reflect the link state.
-
-To illustrate, if a board has:
-
- 5 ports with active low LED control,
- and HT_XTAL_FSEL bootstrapped for 40MHz.
-
-When the MT7530 is powered up without any external
-connection, only the LED associated with Port 3 is
-illuminated as ESW_P3_LED_0 is low.
-
-In this state, directly after mt7530_setup()'s reset
-is performed, the HWTRAP register (0x7800) reflects
-the intended HT_XTAL_FSEL (HWTRAP bits 10:9) of 40MHz:
-
- mt7530-mdio mdio-bus:1f: mt7530_read: 00007800 == 00007dcf
-
- >>> bin(0x7dcf >> 9 & 0b11)
- '0b10'
-
-But if a cable is connected to Port 3 and the link
-is active before mt7530_setup()'s reset takes place,
-then HT_XTAL_FSEL seems to be set for 25MHz:
-
- mt7530-mdio mdio-bus:1f: mt7530_read: 00007800 == 00007fcf
-
- >>> bin(0x7fcf >> 9 & 0b11)
- '0b11'
-
-Once HT_XTAL_FSEL reflects 25MHz, none of the ports
-are functional until the MT7621 (or MT7530 itself)
-is reset.
-
-By disabling the LED pins just before reset, the chance
-of an unintended HT_XTAL_FSEL value is reduced.
-
----
- drivers/net/dsa/mt7530.c | 6 ++++++
- 1 file changed, 6 insertions(+)
-
---- a/drivers/net/dsa/mt7530.c
-+++ b/drivers/net/dsa/mt7530.c
-@@ -2391,6 +2391,12 @@ mt7530_setup(struct dsa_switch *ds)
- }
- }
-
-+ /* Disable LEDs before reset to prevent the MT7530 sampling a
-+ * potentially incorrect HT_XTAL_FSEL value.
-+ */
-+ mt7530_write(priv, MT7530_LED_EN, 0);
-+ usleep_range(1000, 1100);
-+
- /* Reset whole chip through gpio pin or memory-mapped registers for
- * different type of hardware
- */
+++ /dev/null
-From b9547109205c5e0a27e5bed568b0fc183fff906b Mon Sep 17 00:00:00 2001
-Date: Thu, 14 Mar 2024 12:28:35 +0300
-Subject: [PATCH 30/30] net: dsa: mt7530: prevent possible incorrect XTAL
- frequency selection
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-On MT7530, the HT_XTAL_FSEL field of the HWTRAP register stores a 2-bit
-value that represents the frequency of the crystal oscillator connected to
-the switch IC. The field is populated by the state of the ESW_P4_LED_0 and
-ESW_P4_LED_0 pins, which is done right after reset is deasserted.
-
- ESW_P4_LED_0 ESW_P3_LED_0 Frequency
- -----------------------------------------
- 0 0 Reserved
- 0 1 20MHz
- 1 0 40MHz
- 1 1 25MHz
-
-On MT7531, the XTAL25 bit of the STRAP register stores this. The LAN0LED0
-pin is used to populate the bit. 25MHz when the pin is high, 40MHz when
-it's low.
-
-These pins are also used with LEDs, therefore, their state can be set to
-something other than the bootstrapping configuration. For example, a link
-may be established on port 3 before the DSA subdriver takes control of the
-switch which would set ESW_P3_LED_0 to high.
-
-Currently on mt7530_setup() and mt7531_setup(), 1000 - 1100 usec delay is
-described between reset assertion and deassertion. Some switch ICs in real
-life conditions cannot always have these pins set back to the bootstrapping
-configuration before reset deassertion in this amount of delay. This causes
-wrong crystal frequency to be selected which puts the switch in a
-nonfunctional state after reset deassertion.
-
-The tests below are conducted on an MT7530 with a 40MHz crystal oscillator
-by Justin Swartz.
-
-With a cable from an active peer connected to port 3 before reset, an
-incorrect crystal frequency (0b11 = 25MHz) is selected:
-
- [1] [3] [5]
- : : :
- _____________________________ __________________
-ESW_P4_LED_0 |_______|
- _____________________________
-ESW_P3_LED_0 |__________________________
-
- : : : :
- : : [4]...:
- : :
- [2]................:
-
-[1] Reset is asserted.
-[2] Period of 1000 - 1100 usec.
-[3] Reset is deasserted.
-[4] Period of 315 usec. HWTRAP register is populated with incorrect
- XTAL frequency.
-[5] Signals reflect the bootstrapped configuration.
-
-Increase the delay between reset_control_assert() and
-reset_control_deassert(), and gpiod_set_value_cansleep(priv->reset, 0) and
-gpiod_set_value_cansleep(priv->reset, 1) to 5000 - 5100 usec. This amount
-ensures a higher possibility that the switch IC will have these pins back
-to the bootstrapping configuration before reset deassertion.
-
-With a cable from an active peer connected to port 3 before reset, the
-correct crystal frequency (0b10 = 40MHz) is selected:
-
- [1] [2-1] [3] [5]
- : : : :
- _____________________________ __________________
-ESW_P4_LED_0 |_______|
- ___________________ _______
-ESW_P3_LED_0 |_________| |__________________
-
- : : : : :
- : [2-2]...: [4]...:
- [2]................:
-
-[1] Reset is asserted.
-[2] Period of 5000 - 5100 usec.
-[2-1] ESW_P3_LED_0 goes low.
-[2-2] Remaining period of 5000 - 5100 usec.
-[3] Reset is deasserted.
-[4] Period of 310 usec. HWTRAP register is populated with bootstrapped
- XTAL frequency.
-[5] Signals reflect the bootstrapped configuration.
-
-ESW_P3_LED_0 low period before reset deassertion:
-
- 5000 usec
- - 5100 usec
- TEST RESET HOLD
- # (usec)
- ---------------------
- 1 5410
- 2 5440
- 3 4375
- 4 5490
- 5 5475
- 6 4335
- 7 4370
- 8 5435
- 9 4205
- 10 4335
- 11 3750
- 12 3170
- 13 4395
- 14 4375
- 15 3515
- 16 4335
- 17 4220
- 18 4175
- 19 4175
- 20 4350
-
- Min 3170
- Max 5490
-
- Median 4342.500
- Avg 4466.500
-
-Revert commit 2920dd92b980 ("net: dsa: mt7530: disable LEDs before reset").
-Changing the state of pins via reset assertion is simpler and more
-efficient than doing so by setting the LED controller off.
-
-Fixes: b8f126a8d543 ("net-next: dsa: add dsa support for Mediatek MT7530 switch")
-Fixes: c288575f7810 ("net: dsa: mt7530: Add the support of MT7531 switch")
----
- drivers/net/dsa/mt7530.c | 6 ------
- 1 file changed, 6 deletions(-)
-
---- a/drivers/net/dsa/mt7530.c
-+++ b/drivers/net/dsa/mt7530.c
-@@ -2391,12 +2391,6 @@ mt7530_setup(struct dsa_switch *ds)
- }
- }
-
-- /* Disable LEDs before reset to prevent the MT7530 sampling a
-- * potentially incorrect HT_XTAL_FSEL value.
-- */
-- mt7530_write(priv, MT7530_LED_EN, 0);
-- usleep_range(1000, 1100);
--
- /* Reset whole chip through gpio pin or memory-mapped registers for
- * different type of hardware
- */
+++ /dev/null
-From 5754b3bdcd872aa229881b8f07f84a8404c7d72a Mon Sep 17 00:00:00 2001
-Date: Fri, 12 Apr 2024 16:15:34 +0100
-Subject: [PATCH 1/5] net: dsa: mt7530: provide own phylink MAC operations
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Convert mt753x to provide its own phylink MAC operations, thus avoiding
-the shim layer in DSA's port.c
-
----
- drivers/net/dsa/mt7530.c | 46 +++++++++++++++++++++++++---------------
- 1 file changed, 29 insertions(+), 17 deletions(-)
-
---- a/drivers/net/dsa/mt7530.c
-+++ b/drivers/net/dsa/mt7530.c
-@@ -2854,28 +2854,34 @@ mt7531_mac_config(struct dsa_switch *ds,
- }
-
- static struct phylink_pcs *
--mt753x_phylink_mac_select_pcs(struct dsa_switch *ds, int port,
-+mt753x_phylink_mac_select_pcs(struct phylink_config *config,
- phy_interface_t interface)
- {
-- struct mt7530_priv *priv = ds->priv;
-+ struct dsa_port *dp = dsa_phylink_to_port(config);
-+ struct mt7530_priv *priv = dp->ds->priv;
-
- switch (interface) {
- case PHY_INTERFACE_MODE_TRGMII:
-- return &priv->pcs[port].pcs;
-+ return &priv->pcs[dp->index].pcs;
- case PHY_INTERFACE_MODE_SGMII:
- case PHY_INTERFACE_MODE_1000BASEX:
- case PHY_INTERFACE_MODE_2500BASEX:
-- return priv->ports[port].sgmii_pcs;
-+ return priv->ports[dp->index].sgmii_pcs;
- default:
- return NULL;
- }
- }
-
- static void
--mt753x_phylink_mac_config(struct dsa_switch *ds, int port, unsigned int mode,
-+mt753x_phylink_mac_config(struct phylink_config *config, unsigned int mode,
- const struct phylink_link_state *state)
- {
-- struct mt7530_priv *priv = ds->priv;
-+ struct dsa_port *dp = dsa_phylink_to_port(config);
-+ struct dsa_switch *ds = dp->ds;
-+ struct mt7530_priv *priv;
-+ int port = dp->index;
-+
-+ priv = ds->priv;
-
- if ((port == 5 || port == 6) && priv->info->mac_port_config)
- priv->info->mac_port_config(ds, port, mode, state->interface);
-@@ -2885,23 +2891,25 @@ mt753x_phylink_mac_config(struct dsa_swi
- mt7530_set(priv, MT7530_PMCR_P(port), PMCR_EXT_PHY);
- }
-
--static void mt753x_phylink_mac_link_down(struct dsa_switch *ds, int port,
-+static void mt753x_phylink_mac_link_down(struct phylink_config *config,
- unsigned int mode,
- phy_interface_t interface)
- {
-- struct mt7530_priv *priv = ds->priv;
-+ struct dsa_port *dp = dsa_phylink_to_port(config);
-+ struct mt7530_priv *priv = dp->ds->priv;
-
-- mt7530_clear(priv, MT7530_PMCR_P(port), PMCR_LINK_SETTINGS_MASK);
-+ mt7530_clear(priv, MT7530_PMCR_P(dp->index), PMCR_LINK_SETTINGS_MASK);
- }
-
--static void mt753x_phylink_mac_link_up(struct dsa_switch *ds, int port,
-+static void mt753x_phylink_mac_link_up(struct phylink_config *config,
-+ struct phy_device *phydev,
- unsigned int mode,
- phy_interface_t interface,
-- struct phy_device *phydev,
- int speed, int duplex,
- bool tx_pause, bool rx_pause)
- {
-- struct mt7530_priv *priv = ds->priv;
-+ struct dsa_port *dp = dsa_phylink_to_port(config);
-+ struct mt7530_priv *priv = dp->ds->priv;
- u32 mcr;
-
- mcr = PMCR_RX_EN | PMCR_TX_EN | PMCR_FORCE_LNK;
-@@ -2936,7 +2944,7 @@ static void mt753x_phylink_mac_link_up(s
- }
- }
-
-- mt7530_set(priv, MT7530_PMCR_P(port), mcr);
-+ mt7530_set(priv, MT7530_PMCR_P(dp->index), mcr);
- }
-
- static void mt753x_phylink_get_caps(struct dsa_switch *ds, int port,
-@@ -3156,16 +3164,19 @@ const struct dsa_switch_ops mt7530_switc
- .port_mirror_add = mt753x_port_mirror_add,
- .port_mirror_del = mt753x_port_mirror_del,
- .phylink_get_caps = mt753x_phylink_get_caps,
-- .phylink_mac_select_pcs = mt753x_phylink_mac_select_pcs,
-- .phylink_mac_config = mt753x_phylink_mac_config,
-- .phylink_mac_link_down = mt753x_phylink_mac_link_down,
-- .phylink_mac_link_up = mt753x_phylink_mac_link_up,
- .get_mac_eee = mt753x_get_mac_eee,
- .set_mac_eee = mt753x_set_mac_eee,
- .master_state_change = mt753x_conduit_state_change,
- };
- EXPORT_SYMBOL_GPL(mt7530_switch_ops);
-
-+static const struct phylink_mac_ops mt753x_phylink_mac_ops = {
-+ .mac_select_pcs = mt753x_phylink_mac_select_pcs,
-+ .mac_config = mt753x_phylink_mac_config,
-+ .mac_link_down = mt753x_phylink_mac_link_down,
-+ .mac_link_up = mt753x_phylink_mac_link_up,
-+};
-+
- const struct mt753x_info mt753x_table[] = {
- [ID_MT7621] = {
- .id = ID_MT7621,
-@@ -3243,6 +3254,7 @@ mt7530_probe_common(struct mt7530_priv *
- priv->dev = dev;
- priv->ds->priv = priv;
- priv->ds->ops = &mt7530_switch_ops;
-+ priv->ds->phylink_mac_ops = &mt753x_phylink_mac_ops;
- mutex_init(&priv->reg_mutex);
- dev_set_drvdata(dev, priv);
-
+++ /dev/null
-From 5053a6cf1d50d785078562470d2a63695a9f3bf2 Mon Sep 17 00:00:00 2001
-Date: Thu, 18 Apr 2024 08:35:30 +0300
-Subject: [PATCH 4/5] net: dsa: mt7530-mdio: read PHY address of switch from
- device tree
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Read the PHY address the switch listens on from the reg property of the
-switch node on the device tree. This change brings support for MT7530
-switches on boards with such bootstrapping configuration where the switch
-listens on a different PHY address than the hardcoded PHY address on the
-driver, 31.
-
-As described on the "MT7621 Programming Guide v0.4" document, the MT7530
-switch and its PHYs can be configured to listen on the range of 7-12,
-15-20, 23-28, and 31 and 0-4 PHY addresses.
-
-There are operations where the switch PHY registers are used. For the PHY
-address of the control PHY, transform the MT753X_CTRL_PHY_ADDR constant
-into a macro and use it. The PHY address for the control PHY is 0 when the
-switch listens on 31. In any other case, it is one greater than the PHY
-address the switch listens on.
-
----
- drivers/net/dsa/mt7530-mdio.c | 28 +++++++++++++-------------
- drivers/net/dsa/mt7530.c | 37 +++++++++++++++++++++++------------
- drivers/net/dsa/mt7530.h | 4 +++-
- 3 files changed, 41 insertions(+), 28 deletions(-)
-
---- a/drivers/net/dsa/mt7530-mdio.c
-+++ b/drivers/net/dsa/mt7530-mdio.c
-@@ -18,7 +18,8 @@
- static int
- mt7530_regmap_write(void *context, unsigned int reg, unsigned int val)
- {
-- struct mii_bus *bus = context;
-+ struct mt7530_priv *priv = context;
-+ struct mii_bus *bus = priv->bus;
- u16 page, r, lo, hi;
- int ret;
-
-@@ -27,36 +28,35 @@ mt7530_regmap_write(void *context, unsig
- lo = val & 0xffff;
- hi = val >> 16;
-
-- /* MT7530 uses 31 as the pseudo port */
-- ret = bus->write(bus, 0x1f, 0x1f, page);
-+ ret = bus->write(bus, priv->mdiodev->addr, 0x1f, page);
- if (ret < 0)
- return ret;
-
-- ret = bus->write(bus, 0x1f, r, lo);
-+ ret = bus->write(bus, priv->mdiodev->addr, r, lo);
- if (ret < 0)
- return ret;
-
-- ret = bus->write(bus, 0x1f, 0x10, hi);
-+ ret = bus->write(bus, priv->mdiodev->addr, 0x10, hi);
- return ret;
- }
-
- static int
- mt7530_regmap_read(void *context, unsigned int reg, unsigned int *val)
- {
-- struct mii_bus *bus = context;
-+ struct mt7530_priv *priv = context;
-+ struct mii_bus *bus = priv->bus;
- u16 page, r, lo, hi;
- int ret;
-
- page = (reg >> 6) & 0x3ff;
- r = (reg >> 2) & 0xf;
-
-- /* MT7530 uses 31 as the pseudo port */
-- ret = bus->write(bus, 0x1f, 0x1f, page);
-+ ret = bus->write(bus, priv->mdiodev->addr, 0x1f, page);
- if (ret < 0)
- return ret;
-
-- lo = bus->read(bus, 0x1f, r);
-- hi = bus->read(bus, 0x1f, 0x10);
-+ lo = bus->read(bus, priv->mdiodev->addr, r);
-+ hi = bus->read(bus, priv->mdiodev->addr, 0x10);
-
- *val = (hi << 16) | (lo & 0xffff);
-
-@@ -107,8 +107,7 @@ mt7531_create_sgmii(struct mt7530_priv *
- mt7531_pcs_config[i]->unlock = mt7530_mdio_regmap_unlock;
- mt7531_pcs_config[i]->lock_arg = &priv->bus->mdio_lock;
-
-- regmap = devm_regmap_init(priv->dev,
-- &mt7530_regmap_bus, priv->bus,
-+ regmap = devm_regmap_init(priv->dev, &mt7530_regmap_bus, priv,
- mt7531_pcs_config[i]);
- if (IS_ERR(regmap)) {
- ret = PTR_ERR(regmap);
-@@ -153,6 +152,7 @@ mt7530_probe(struct mdio_device *mdiodev
-
- priv->bus = mdiodev->bus;
- priv->dev = &mdiodev->dev;
-+ priv->mdiodev = mdiodev;
-
- ret = mt7530_probe_common(priv);
- if (ret)
-@@ -203,8 +203,8 @@ mt7530_probe(struct mdio_device *mdiodev
- regmap_config->reg_stride = 4;
- regmap_config->max_register = MT7530_CREV;
- regmap_config->disable_locking = true;
-- priv->regmap = devm_regmap_init(priv->dev, &mt7530_regmap_bus,
-- priv->bus, regmap_config);
-+ priv->regmap = devm_regmap_init(priv->dev, &mt7530_regmap_bus, priv,
-+ regmap_config);
- if (IS_ERR(priv->regmap))
- return PTR_ERR(priv->regmap);
-
---- a/drivers/net/dsa/mt7530.c
-+++ b/drivers/net/dsa/mt7530.c
-@@ -86,22 +86,26 @@ core_read_mmd_indirect(struct mt7530_pri
- int value, ret;
-
- /* Write the desired MMD Devad */
-- ret = bus->write(bus, 0, MII_MMD_CTRL, devad);
-+ ret = bus->write(bus, MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr),
-+ MII_MMD_CTRL, devad);
- if (ret < 0)
- goto err;
-
- /* Write the desired MMD register address */
-- ret = bus->write(bus, 0, MII_MMD_DATA, prtad);
-+ ret = bus->write(bus, MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr),
-+ MII_MMD_DATA, prtad);
- if (ret < 0)
- goto err;
-
- /* Select the Function : DATA with no post increment */
-- ret = bus->write(bus, 0, MII_MMD_CTRL, (devad | MII_MMD_CTRL_NOINCR));
-+ ret = bus->write(bus, MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr),
-+ MII_MMD_CTRL, devad | MII_MMD_CTRL_NOINCR);
- if (ret < 0)
- goto err;
-
- /* Read the content of the MMD's selected register */
-- value = bus->read(bus, 0, MII_MMD_DATA);
-+ value = bus->read(bus, MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr),
-+ MII_MMD_DATA);
-
- return value;
- err:
-@@ -118,22 +122,26 @@ core_write_mmd_indirect(struct mt7530_pr
- int ret;
-
- /* Write the desired MMD Devad */
-- ret = bus->write(bus, 0, MII_MMD_CTRL, devad);
-+ ret = bus->write(bus, MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr),
-+ MII_MMD_CTRL, devad);
- if (ret < 0)
- goto err;
-
- /* Write the desired MMD register address */
-- ret = bus->write(bus, 0, MII_MMD_DATA, prtad);
-+ ret = bus->write(bus, MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr),
-+ MII_MMD_DATA, prtad);
- if (ret < 0)
- goto err;
-
- /* Select the Function : DATA with no post increment */
-- ret = bus->write(bus, 0, MII_MMD_CTRL, (devad | MII_MMD_CTRL_NOINCR));
-+ ret = bus->write(bus, MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr),
-+ MII_MMD_CTRL, devad | MII_MMD_CTRL_NOINCR);
- if (ret < 0)
- goto err;
-
- /* Write the data into MMD's selected register */
-- ret = bus->write(bus, 0, MII_MMD_DATA, data);
-+ ret = bus->write(bus, MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr),
-+ MII_MMD_DATA, data);
- err:
- if (ret < 0)
- dev_err(&bus->dev,
-@@ -2683,16 +2691,19 @@ mt7531_setup(struct dsa_switch *ds)
- * phy_[read,write]_mmd_indirect is called, we provide our own
- * mt7531_ind_mmd_phy_[read,write] to complete this function.
- */
-- val = mt7531_ind_c45_phy_read(priv, MT753X_CTRL_PHY_ADDR,
-+ val = mt7531_ind_c45_phy_read(priv,
-+ MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr),
- MDIO_MMD_VEND2, CORE_PLL_GROUP4);
- val |= MT7531_RG_SYSPLL_DMY2 | MT7531_PHY_PLL_BYPASS_MODE;
- val &= ~MT7531_PHY_PLL_OFF;
-- mt7531_ind_c45_phy_write(priv, MT753X_CTRL_PHY_ADDR, MDIO_MMD_VEND2,
-- CORE_PLL_GROUP4, val);
-+ mt7531_ind_c45_phy_write(priv,
-+ MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr),
-+ MDIO_MMD_VEND2, CORE_PLL_GROUP4, val);
-
- /* Disable EEE advertisement on the switch PHYs. */
-- for (i = MT753X_CTRL_PHY_ADDR;
-- i < MT753X_CTRL_PHY_ADDR + MT7530_NUM_PHYS; i++) {
-+ for (i = MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr);
-+ i < MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr) + MT7530_NUM_PHYS;
-+ i++) {
- mt7531_ind_c45_phy_write(priv, i, MDIO_MMD_AN, MDIO_AN_EEE_ADV,
- 0);
- }
---- a/drivers/net/dsa/mt7530.h
-+++ b/drivers/net/dsa/mt7530.h
-@@ -629,7 +629,7 @@ enum mt7531_clk_skew {
- #define MT7531_PHY_PLL_OFF BIT(5)
- #define MT7531_PHY_PLL_BYPASS_MODE BIT(4)
-
--#define MT753X_CTRL_PHY_ADDR 0
-+#define MT753X_CTRL_PHY_ADDR(addr) ((addr + 1) & 0x1f)
-
- #define CORE_PLL_GROUP5 0x404
- #define RG_LCDDS_PCW_NCPO1(x) ((x) & 0xffff)
-@@ -778,6 +778,7 @@ struct mt753x_info {
- * @irq_enable: IRQ enable bits, synced to SYS_INT_EN
- * @create_sgmii: Pointer to function creating SGMII PCS instance(s)
- * @active_cpu_ports: Holding the active CPU ports
-+ * @mdiodev: The pointer to the MDIO device structure
- */
- struct mt7530_priv {
- struct device *dev;
-@@ -804,6 +805,7 @@ struct mt7530_priv {
- u32 irq_enable;
- int (*create_sgmii)(struct mt7530_priv *priv);
- u8 active_cpu_ports;
-+ struct mdio_device *mdiodev;
- };
-
- struct mt7530_hw_vlan_entry {
+++ /dev/null
-From 9764a08b3d260f4e7799d34bbfe64463db940d74 Mon Sep 17 00:00:00 2001
-Date: Thu, 18 Apr 2024 08:35:31 +0300
-Subject: [PATCH 5/5] net: dsa: mt7530: simplify core operations
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-The core_rmw() function calls core_read_mmd_indirect() to read the
-requested register, and then calls core_write_mmd_indirect() to write the
-requested value to the register. Because Clause 22 is used to access Clause
-45 registers, some operations on core_write_mmd_indirect() are
-unnecessarily run. Get rid of core_read_mmd_indirect() and
-core_write_mmd_indirect(), and run only the necessary operations on
-core_write() and core_rmw().
-
----
- drivers/net/dsa/mt7530.c | 108 ++++++++++++++++-----------------------
- 1 file changed, 43 insertions(+), 65 deletions(-)
-
---- a/drivers/net/dsa/mt7530.c
-+++ b/drivers/net/dsa/mt7530.c
-@@ -74,116 +74,94 @@ static const struct mt7530_mib_desc mt75
- MIB_DESC(1, 0xb8, "RxArlDrop"),
- };
-
--/* Since phy_device has not yet been created and
-- * phy_{read,write}_mmd_indirect is not available, we provide our own
-- * core_{read,write}_mmd_indirect with core_{clear,write,set} wrappers
-- * to complete this function.
-- */
--static int
--core_read_mmd_indirect(struct mt7530_priv *priv, int prtad, int devad)
-+static void
-+mt7530_mutex_lock(struct mt7530_priv *priv)
-+{
-+ if (priv->bus)
-+ mutex_lock_nested(&priv->bus->mdio_lock, MDIO_MUTEX_NESTED);
-+}
-+
-+static void
-+mt7530_mutex_unlock(struct mt7530_priv *priv)
-+{
-+ if (priv->bus)
-+ mutex_unlock(&priv->bus->mdio_lock);
-+}
-+
-+static void
-+core_write(struct mt7530_priv *priv, u32 reg, u32 val)
- {
- struct mii_bus *bus = priv->bus;
-- int value, ret;
-+ int ret;
-+
-+ mt7530_mutex_lock(priv);
-
- /* Write the desired MMD Devad */
- ret = bus->write(bus, MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr),
-- MII_MMD_CTRL, devad);
-+ MII_MMD_CTRL, MDIO_MMD_VEND2);
- if (ret < 0)
- goto err;
-
- /* Write the desired MMD register address */
- ret = bus->write(bus, MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr),
-- MII_MMD_DATA, prtad);
-+ MII_MMD_DATA, reg);
- if (ret < 0)
- goto err;
-
- /* Select the Function : DATA with no post increment */
- ret = bus->write(bus, MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr),
-- MII_MMD_CTRL, devad | MII_MMD_CTRL_NOINCR);
-+ MII_MMD_CTRL, MDIO_MMD_VEND2 | MII_MMD_CTRL_NOINCR);
- if (ret < 0)
- goto err;
-
-- /* Read the content of the MMD's selected register */
-- value = bus->read(bus, MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr),
-- MII_MMD_DATA);
--
-- return value;
-+ /* Write the data into MMD's selected register */
-+ ret = bus->write(bus, MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr),
-+ MII_MMD_DATA, val);
- err:
-- dev_err(&bus->dev, "failed to read mmd register\n");
-+ if (ret < 0)
-+ dev_err(&bus->dev, "failed to write mmd register\n");
-
-- return ret;
-+ mt7530_mutex_unlock(priv);
- }
-
--static int
--core_write_mmd_indirect(struct mt7530_priv *priv, int prtad,
-- int devad, u32 data)
-+static void
-+core_rmw(struct mt7530_priv *priv, u32 reg, u32 mask, u32 set)
- {
- struct mii_bus *bus = priv->bus;
-+ u32 val;
- int ret;
-
-+ mt7530_mutex_lock(priv);
-+
- /* Write the desired MMD Devad */
- ret = bus->write(bus, MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr),
-- MII_MMD_CTRL, devad);
-+ MII_MMD_CTRL, MDIO_MMD_VEND2);
- if (ret < 0)
- goto err;
-
- /* Write the desired MMD register address */
- ret = bus->write(bus, MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr),
-- MII_MMD_DATA, prtad);
-+ MII_MMD_DATA, reg);
- if (ret < 0)
- goto err;
-
- /* Select the Function : DATA with no post increment */
- ret = bus->write(bus, MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr),
-- MII_MMD_CTRL, devad | MII_MMD_CTRL_NOINCR);
-+ MII_MMD_CTRL, MDIO_MMD_VEND2 | MII_MMD_CTRL_NOINCR);
- if (ret < 0)
- goto err;
-
-+ /* Read the content of the MMD's selected register */
-+ val = bus->read(bus, MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr),
-+ MII_MMD_DATA);
-+ val &= ~mask;
-+ val |= set;
- /* Write the data into MMD's selected register */
- ret = bus->write(bus, MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr),
-- MII_MMD_DATA, data);
-+ MII_MMD_DATA, val);
- err:
- if (ret < 0)
-- dev_err(&bus->dev,
-- "failed to write mmd register\n");
-- return ret;
--}
--
--static void
--mt7530_mutex_lock(struct mt7530_priv *priv)
--{
-- if (priv->bus)
-- mutex_lock_nested(&priv->bus->mdio_lock, MDIO_MUTEX_NESTED);
--}
--
--static void
--mt7530_mutex_unlock(struct mt7530_priv *priv)
--{
-- if (priv->bus)
-- mutex_unlock(&priv->bus->mdio_lock);
--}
--
--static void
--core_write(struct mt7530_priv *priv, u32 reg, u32 val)
--{
-- mt7530_mutex_lock(priv);
--
-- core_write_mmd_indirect(priv, reg, MDIO_MMD_VEND2, val);
--
-- mt7530_mutex_unlock(priv);
--}
--
--static void
--core_rmw(struct mt7530_priv *priv, u32 reg, u32 mask, u32 set)
--{
-- u32 val;
--
-- mt7530_mutex_lock(priv);
--
-- val = core_read_mmd_indirect(priv, reg, MDIO_MMD_VEND2);
-- val &= ~mask;
-- val |= set;
-- core_write_mmd_indirect(priv, reg, MDIO_MMD_VEND2, val);
-+ dev_err(&bus->dev, "failed to write mmd register\n");
-
- mt7530_mutex_unlock(priv);
- }
+++ /dev/null
-From 856e8954a0a88d1a4d2b43e9002b9249131a156f Mon Sep 17 00:00:00 2001
-Date: Mon, 22 Apr 2024 10:15:08 +0300
-Subject: [PATCH 01/15] net: dsa: mt7530: disable EEE abilities on failure on
- MT7531 and MT7988
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-The MT7531_FORCE_EEE1G and MT7531_FORCE_EEE100 bits let the
-PMCR_FORCE_EEE1G and PMCR_FORCE_EEE100 bits determine the 1G/100 EEE
-abilities of the MAC. If MT7531_FORCE_EEE1G and MT7531_FORCE_EEE100 are
-unset, the abilities are left to be determined by PHY auto polling.
-
-The commit 40b5d2f15c09 ("net: dsa: mt7530: Add support for EEE features")
-made it so that the PMCR_FORCE_EEE1G and PMCR_FORCE_EEE100 bits are set on
-mt753x_phylink_mac_link_up(). But it did not set the MT7531_FORCE_EEE1G and
-MT7531_FORCE_EEE100 bits. Because of this, the EEE abilities will be
-determined by PHY auto polling, regardless of the result of phy_init_eee().
-
-Define these bits and add them to the MT7531_FORCE_MODE mask which is set
-in mt7531_setup_common(). With this, there won't be any EEE abilities set
-when phy_init_eee() returns a negative value.
-
-Thanks to Russell for explaining when phy_init_eee() could return a
-negative value below.
-
-Looking at phy_init_eee(), it could return a negative value when:
-
-1. phydev->drv is NULL
-2. if genphy_c45_eee_is_active() returns negative
-3. if genphy_c45_eee_is_active() returns zero, it returns -EPROTONOSUPPORT
-4. if phy_set_bits_mmd() fails (e.g. communication error with the PHY)
-
-If we then look at genphy_c45_eee_is_active(), then:
-
-genphy_c45_read_eee_adv() and genphy_c45_read_eee_lpa() propagate their
-non-zero return values, otherwise this function returns zero or positive
-integer.
-
-If we then look at genphy_c45_read_eee_adv(), then a failure of
-phy_read_mmd() would cause a negative value to be returned.
-
-Looking at genphy_c45_read_eee_lpa(), the same is true.
-
-So, it can be summarised as:
-
-- phydev->drv is NULL
-- there is a communication error accessing the PHY
-- EEE is not active
-
-otherwise, it returns zero on success.
-
-If one wishes to determine whether an error occurred vs EEE not being
-supported through negotiation for the negotiated speed, if it returns
--EPROTONOSUPPORT in the latter case. Other error codes mean either the
-driver has been unloaded or communication error.
-
-In conclusion, determining the EEE abilities by PHY auto polling shouldn't
-result in having any EEE abilities enabled, when one of the last two
-situations in the summary happens. And it seems that if phydev->drv is
-NULL, there would be bigger problems with the device than a broken link. So
-this is not a bugfix.
-
----
- drivers/net/dsa/mt7530.h | 6 +++++-
- 1 file changed, 5 insertions(+), 1 deletion(-)
-
---- a/drivers/net/dsa/mt7530.h
-+++ b/drivers/net/dsa/mt7530.h
-@@ -328,11 +328,15 @@ enum mt7530_vlan_port_acc_frm {
- #define MT7531_FORCE_DPX BIT(29)
- #define MT7531_FORCE_RX_FC BIT(28)
- #define MT7531_FORCE_TX_FC BIT(27)
-+#define MT7531_FORCE_EEE100 BIT(26)
-+#define MT7531_FORCE_EEE1G BIT(25)
- #define MT7531_FORCE_MODE (MT7531_FORCE_LNK | \
- MT7531_FORCE_SPD | \
- MT7531_FORCE_DPX | \
- MT7531_FORCE_RX_FC | \
-- MT7531_FORCE_TX_FC)
-+ MT7531_FORCE_TX_FC | \
-+ MT7531_FORCE_EEE100 | \
-+ MT7531_FORCE_EEE1G)
- #define PMCR_LINK_SETTINGS_MASK (PMCR_TX_EN | PMCR_FORCE_SPEED_1000 | \
- PMCR_RX_EN | PMCR_FORCE_SPEED_100 | \
- PMCR_TX_FC_EN | PMCR_RX_FC_EN | \
+++ /dev/null
-From 712ad00d2f43814c81a7abfcbc339690a05fb6a0 Mon Sep 17 00:00:00 2001
-Date: Mon, 22 Apr 2024 10:15:09 +0300
-Subject: [PATCH 02/15] net: dsa: mt7530: refactor MT7530_PMCR_P()
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-The MT7530_PMCR_P() registers are on MT7530, MT7531, and the switch on the
-MT7988 SoC. Rename the definition for them to MT753X_PMCR_P(). Bit 15 is
-for MT7530 only. Add MT7530 prefix to the definition for bit 15.
-
-Use GENMASK and FIELD_PREP for PMCR_IFG_XMIT().
-
-Rename PMCR_TX_EN and PMCR_RX_EN to PMCR_MAC_TX_EN and PMCR_MAC_TX_EN to
-follow the naming on the "MT7621 Giga Switch Programming Guide v0.3",
-"MT7531 Reference Manual for Development Board v1.0", and "MT7988A Wi-Fi 7
-Generation Router Platform: Datasheet (Open Version) v0.1" documents.
-
-These documents show that PMCR_RX_FC_EN is at bit 5. Correct this along
-with renaming it to PMCR_FORCE_RX_FC_EN, and the same for PMCR_TX_FC_EN.
-
-Remove PMCR_SPEED_MASK which doesn't have a use.
-
-Rename the force mode definitions for MT7531 to FORCE_MODE. Add MASK at the
-end for the mask that includes all force mode definitions.
-
----
- drivers/net/dsa/mt7530.c | 24 ++++++++---------
- drivers/net/dsa/mt7530.h | 58 +++++++++++++++++++++-------------------
- 2 files changed, 42 insertions(+), 40 deletions(-)
-
---- a/drivers/net/dsa/mt7530.c
-+++ b/drivers/net/dsa/mt7530.c
-@@ -896,7 +896,7 @@ static void mt7530_setup_port5(struct ds
- val &= ~MHWTRAP_P5_MAC_SEL & ~MHWTRAP_P5_DIS;
-
- /* Setup the MAC by default for the cpu port */
-- mt7530_write(priv, MT7530_PMCR_P(5), 0x56300);
-+ mt7530_write(priv, MT753X_PMCR_P(5), 0x56300);
- break;
- case P5_INTF_SEL_GMAC5:
- /* MT7530_P5_MODE_GMAC: P5 -> External phy or 2nd GMAC */
-@@ -2444,8 +2444,8 @@ mt7530_setup(struct dsa_switch *ds)
- /* Clear link settings and enable force mode to force link down
- * on all ports until they're enabled later.
- */
-- mt7530_rmw(priv, MT7530_PMCR_P(i), PMCR_LINK_SETTINGS_MASK |
-- PMCR_FORCE_MODE, PMCR_FORCE_MODE);
-+ mt7530_rmw(priv, MT753X_PMCR_P(i), PMCR_LINK_SETTINGS_MASK |
-+ MT7530_FORCE_MODE, MT7530_FORCE_MODE);
-
- /* Disable forwarding by default on all ports */
- mt7530_rmw(priv, MT7530_PCR_P(i), PCR_MATRIX_MASK,
-@@ -2558,8 +2558,8 @@ mt7531_setup_common(struct dsa_switch *d
- /* Clear link settings and enable force mode to force link down
- * on all ports until they're enabled later.
- */
-- mt7530_rmw(priv, MT7530_PMCR_P(i), PMCR_LINK_SETTINGS_MASK |
-- MT7531_FORCE_MODE, MT7531_FORCE_MODE);
-+ mt7530_rmw(priv, MT753X_PMCR_P(i), PMCR_LINK_SETTINGS_MASK |
-+ MT7531_FORCE_MODE_MASK, MT7531_FORCE_MODE_MASK);
-
- /* Disable forwarding by default on all ports */
- mt7530_rmw(priv, MT7530_PCR_P(i), PCR_MATRIX_MASK,
-@@ -2643,7 +2643,7 @@ mt7531_setup(struct dsa_switch *ds)
-
- /* Force link down on all ports before internal reset */
- for (i = 0; i < MT7530_NUM_PORTS; i++)
-- mt7530_write(priv, MT7530_PMCR_P(i), MT7531_FORCE_LNK);
-+ mt7530_write(priv, MT753X_PMCR_P(i), MT7531_FORCE_MODE_LNK);
-
- /* Reset the switch through internal reset */
- mt7530_write(priv, MT7530_SYS_CTRL, SYS_CTRL_SW_RST | SYS_CTRL_REG_RST);
-@@ -2877,7 +2877,7 @@ mt753x_phylink_mac_config(struct phylink
-
- /* Are we connected to external phy */
- if (port == 5 && dsa_is_user_port(ds, 5))
-- mt7530_set(priv, MT7530_PMCR_P(port), PMCR_EXT_PHY);
-+ mt7530_set(priv, MT753X_PMCR_P(port), PMCR_EXT_PHY);
- }
-
- static void mt753x_phylink_mac_link_down(struct phylink_config *config,
-@@ -2887,7 +2887,7 @@ static void mt753x_phylink_mac_link_down
- struct dsa_port *dp = dsa_phylink_to_port(config);
- struct mt7530_priv *priv = dp->ds->priv;
-
-- mt7530_clear(priv, MT7530_PMCR_P(dp->index), PMCR_LINK_SETTINGS_MASK);
-+ mt7530_clear(priv, MT753X_PMCR_P(dp->index), PMCR_LINK_SETTINGS_MASK);
- }
-
- static void mt753x_phylink_mac_link_up(struct phylink_config *config,
-@@ -2901,7 +2901,7 @@ static void mt753x_phylink_mac_link_up(s
- struct mt7530_priv *priv = dp->ds->priv;
- u32 mcr;
-
-- mcr = PMCR_RX_EN | PMCR_TX_EN | PMCR_FORCE_LNK;
-+ mcr = PMCR_MAC_RX_EN | PMCR_MAC_TX_EN | PMCR_FORCE_LNK;
-
- switch (speed) {
- case SPEED_1000:
-@@ -2916,9 +2916,9 @@ static void mt753x_phylink_mac_link_up(s
- if (duplex == DUPLEX_FULL) {
- mcr |= PMCR_FORCE_FDX;
- if (tx_pause)
-- mcr |= PMCR_TX_FC_EN;
-+ mcr |= PMCR_FORCE_TX_FC_EN;
- if (rx_pause)
-- mcr |= PMCR_RX_FC_EN;
-+ mcr |= PMCR_FORCE_RX_FC_EN;
- }
-
- if (mode == MLO_AN_PHY && phydev && phy_init_eee(phydev, false) >= 0) {
-@@ -2933,7 +2933,7 @@ static void mt753x_phylink_mac_link_up(s
- }
- }
-
-- mt7530_set(priv, MT7530_PMCR_P(dp->index), mcr);
-+ mt7530_set(priv, MT753X_PMCR_P(dp->index), mcr);
- }
-
- static void mt753x_phylink_get_caps(struct dsa_switch *ds, int port,
---- a/drivers/net/dsa/mt7530.h
-+++ b/drivers/net/dsa/mt7530.h
-@@ -304,44 +304,46 @@ enum mt7530_vlan_port_acc_frm {
- #define G0_PORT_VID_DEF G0_PORT_VID(0)
-
- /* Register for port MAC control register */
--#define MT7530_PMCR_P(x) (0x3000 + ((x) * 0x100))
--#define PMCR_IFG_XMIT(x) (((x) & 0x3) << 18)
-+#define MT753X_PMCR_P(x) (0x3000 + ((x) * 0x100))
-+#define PMCR_IFG_XMIT_MASK GENMASK(19, 18)
-+#define PMCR_IFG_XMIT(x) FIELD_PREP(PMCR_IFG_XMIT_MASK, x)
- #define PMCR_EXT_PHY BIT(17)
- #define PMCR_MAC_MODE BIT(16)
--#define PMCR_FORCE_MODE BIT(15)
--#define PMCR_TX_EN BIT(14)
--#define PMCR_RX_EN BIT(13)
-+#define MT7530_FORCE_MODE BIT(15)
-+#define PMCR_MAC_TX_EN BIT(14)
-+#define PMCR_MAC_RX_EN BIT(13)
- #define PMCR_BACKOFF_EN BIT(9)
- #define PMCR_BACKPR_EN BIT(8)
- #define PMCR_FORCE_EEE1G BIT(7)
- #define PMCR_FORCE_EEE100 BIT(6)
--#define PMCR_TX_FC_EN BIT(5)
--#define PMCR_RX_FC_EN BIT(4)
-+#define PMCR_FORCE_RX_FC_EN BIT(5)
-+#define PMCR_FORCE_TX_FC_EN BIT(4)
- #define PMCR_FORCE_SPEED_1000 BIT(3)
- #define PMCR_FORCE_SPEED_100 BIT(2)
- #define PMCR_FORCE_FDX BIT(1)
- #define PMCR_FORCE_LNK BIT(0)
--#define PMCR_SPEED_MASK (PMCR_FORCE_SPEED_100 | \
-- PMCR_FORCE_SPEED_1000)
--#define MT7531_FORCE_LNK BIT(31)
--#define MT7531_FORCE_SPD BIT(30)
--#define MT7531_FORCE_DPX BIT(29)
--#define MT7531_FORCE_RX_FC BIT(28)
--#define MT7531_FORCE_TX_FC BIT(27)
--#define MT7531_FORCE_EEE100 BIT(26)
--#define MT7531_FORCE_EEE1G BIT(25)
--#define MT7531_FORCE_MODE (MT7531_FORCE_LNK | \
-- MT7531_FORCE_SPD | \
-- MT7531_FORCE_DPX | \
-- MT7531_FORCE_RX_FC | \
-- MT7531_FORCE_TX_FC | \
-- MT7531_FORCE_EEE100 | \
-- MT7531_FORCE_EEE1G)
--#define PMCR_LINK_SETTINGS_MASK (PMCR_TX_EN | PMCR_FORCE_SPEED_1000 | \
-- PMCR_RX_EN | PMCR_FORCE_SPEED_100 | \
-- PMCR_TX_FC_EN | PMCR_RX_FC_EN | \
-- PMCR_FORCE_FDX | PMCR_FORCE_LNK | \
-- PMCR_FORCE_EEE1G | PMCR_FORCE_EEE100)
-+#define MT7531_FORCE_MODE_LNK BIT(31)
-+#define MT7531_FORCE_MODE_SPD BIT(30)
-+#define MT7531_FORCE_MODE_DPX BIT(29)
-+#define MT7531_FORCE_MODE_RX_FC BIT(28)
-+#define MT7531_FORCE_MODE_TX_FC BIT(27)
-+#define MT7531_FORCE_MODE_EEE100 BIT(26)
-+#define MT7531_FORCE_MODE_EEE1G BIT(25)
-+#define MT7531_FORCE_MODE_MASK (MT7531_FORCE_MODE_LNK | \
-+ MT7531_FORCE_MODE_SPD | \
-+ MT7531_FORCE_MODE_DPX | \
-+ MT7531_FORCE_MODE_RX_FC | \
-+ MT7531_FORCE_MODE_TX_FC | \
-+ MT7531_FORCE_MODE_EEE100 | \
-+ MT7531_FORCE_MODE_EEE1G)
-+#define PMCR_LINK_SETTINGS_MASK (PMCR_MAC_TX_EN | PMCR_MAC_RX_EN | \
-+ PMCR_FORCE_EEE1G | \
-+ PMCR_FORCE_EEE100 | \
-+ PMCR_FORCE_RX_FC_EN | \
-+ PMCR_FORCE_TX_FC_EN | \
-+ PMCR_FORCE_SPEED_1000 | \
-+ PMCR_FORCE_SPEED_100 | \
-+ PMCR_FORCE_FDX | PMCR_FORCE_LNK)
-
- #define MT7530_PMEEECR_P(x) (0x3004 + (x) * 0x100)
- #define WAKEUP_TIME_1000(x) (((x) & 0xFF) << 24)
+++ /dev/null
-From 875ec5b67ab88e969b171e6e9ea803e3ed759614 Mon Sep 17 00:00:00 2001
-Date: Mon, 22 Apr 2024 10:15:10 +0300
-Subject: [PATCH 03/15] net: dsa: mt7530: rename p5_intf_sel and use only for
- MT7530 switch
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-The p5_intf_sel pointer is used to store the information of whether PHY
-muxing is used or not. PHY muxing is a feature specific to port 5 of the
-MT7530 switch. Do not use it for other switch models.
-
-Rename the pointer to p5_mode to store the mode the port is being used in.
-Rename the p5_interface_select enum to mt7530_p5_mode, the string
-representation to mt7530_p5_mode_str, and the enum elements.
-
-If PHY muxing is not detected, the default mode, GMAC5, will be used.
-
----
- drivers/net/dsa/mt7530.c | 62 +++++++++++++++++-----------------------
- drivers/net/dsa/mt7530.h | 15 +++++-----
- 2 files changed, 33 insertions(+), 44 deletions(-)
-
---- a/drivers/net/dsa/mt7530.c
-+++ b/drivers/net/dsa/mt7530.c
-@@ -857,19 +857,15 @@ mt7530_set_ageing_time(struct dsa_switch
- return 0;
- }
-
--static const char *p5_intf_modes(unsigned int p5_interface)
-+static const char *mt7530_p5_mode_str(unsigned int mode)
- {
-- switch (p5_interface) {
-- case P5_DISABLED:
-- return "DISABLED";
-- case P5_INTF_SEL_PHY_P0:
-- return "PHY P0";
-- case P5_INTF_SEL_PHY_P4:
-- return "PHY P4";
-- case P5_INTF_SEL_GMAC5:
-- return "GMAC5";
-+ switch (mode) {
-+ case MUX_PHY_P0:
-+ return "MUX PHY P0";
-+ case MUX_PHY_P4:
-+ return "MUX PHY P4";
- default:
-- return "unknown";
-+ return "GMAC5";
- }
- }
-
-@@ -886,23 +882,23 @@ static void mt7530_setup_port5(struct ds
- val |= MHWTRAP_MANUAL | MHWTRAP_P5_MAC_SEL | MHWTRAP_P5_DIS;
- val &= ~MHWTRAP_P5_RGMII_MODE & ~MHWTRAP_PHY0_SEL;
-
-- switch (priv->p5_intf_sel) {
-- case P5_INTF_SEL_PHY_P0:
-- /* MT7530_P5_MODE_GPHY_P0: 2nd GMAC -> P5 -> P0 */
-+ switch (priv->p5_mode) {
-+ /* MUX_PHY_P0: P0 -> P5 -> SoC MAC */
-+ case MUX_PHY_P0:
- val |= MHWTRAP_PHY0_SEL;
- fallthrough;
-- case P5_INTF_SEL_PHY_P4:
-- /* MT7530_P5_MODE_GPHY_P4: 2nd GMAC -> P5 -> P4 */
-+
-+ /* MUX_PHY_P4: P4 -> P5 -> SoC MAC */
-+ case MUX_PHY_P4:
- val &= ~MHWTRAP_P5_MAC_SEL & ~MHWTRAP_P5_DIS;
-
- /* Setup the MAC by default for the cpu port */
- mt7530_write(priv, MT753X_PMCR_P(5), 0x56300);
- break;
-- case P5_INTF_SEL_GMAC5:
-- /* MT7530_P5_MODE_GMAC: P5 -> External phy or 2nd GMAC */
-- val &= ~MHWTRAP_P5_DIS;
-- break;
-+
-+ /* GMAC5: P5 -> SoC MAC or external PHY */
- default:
-+ val &= ~MHWTRAP_P5_DIS;
- break;
- }
-
-@@ -930,8 +926,8 @@ static void mt7530_setup_port5(struct ds
-
- mt7530_write(priv, MT7530_MHWTRAP, val);
-
-- dev_dbg(ds->dev, "Setup P5, HWTRAP=0x%x, intf_sel=%s, phy-mode=%s\n",
-- val, p5_intf_modes(priv->p5_intf_sel), phy_modes(interface));
-+ dev_dbg(ds->dev, "Setup P5, HWTRAP=0x%x, mode=%s, phy-mode=%s\n", val,
-+ mt7530_p5_mode_str(priv->p5_mode), phy_modes(interface));
-
- mutex_unlock(&priv->reg_mutex);
- }
-@@ -2476,13 +2472,11 @@ mt7530_setup(struct dsa_switch *ds)
- if (ret)
- return ret;
-
-- /* Setup port 5 */
-- if (!dsa_is_unused_port(ds, 5)) {
-- priv->p5_intf_sel = P5_INTF_SEL_GMAC5;
-- } else {
-+ /* Check for PHY muxing on port 5 */
-+ if (dsa_is_unused_port(ds, 5)) {
- /* Scan the ethernet nodes. Look for GMAC1, lookup the used PHY.
-- * Set priv->p5_intf_sel to the appropriate value if PHY muxing
-- * is detected.
-+ * Set priv->p5_mode to the appropriate value if PHY muxing is
-+ * detected.
- */
- for_each_child_of_node(dn, mac_np) {
- if (!of_device_is_compatible(mac_np,
-@@ -2506,17 +2500,16 @@ mt7530_setup(struct dsa_switch *ds)
- }
- id = of_mdio_parse_addr(ds->dev, phy_node);
- if (id == 0)
-- priv->p5_intf_sel = P5_INTF_SEL_PHY_P0;
-+ priv->p5_mode = MUX_PHY_P0;
- if (id == 4)
-- priv->p5_intf_sel = P5_INTF_SEL_PHY_P4;
-+ priv->p5_mode = MUX_PHY_P4;
- }
- of_node_put(mac_np);
- of_node_put(phy_node);
- break;
- }
-
-- if (priv->p5_intf_sel == P5_INTF_SEL_PHY_P0 ||
-- priv->p5_intf_sel == P5_INTF_SEL_PHY_P4)
-+ if (priv->p5_mode == MUX_PHY_P0 || priv->p5_mode == MUX_PHY_P4)
- mt7530_setup_port5(ds, interface);
- }
-
-@@ -2658,9 +2651,6 @@ mt7531_setup(struct dsa_switch *ds)
- MT7531_EXT_P_MDIO_12);
- }
-
-- if (!dsa_is_unused_port(ds, 5))
-- priv->p5_intf_sel = P5_INTF_SEL_GMAC5;
--
- mt7530_rmw(priv, MT7531_GPIO_MODE0, MT7531_GPIO0_MASK,
- MT7531_GPIO0_INTERRUPT);
-
---- a/drivers/net/dsa/mt7530.h
-+++ b/drivers/net/dsa/mt7530.h
-@@ -708,12 +708,11 @@ struct mt7530_port {
- struct phylink_pcs *sgmii_pcs;
- };
-
--/* Port 5 interface select definitions */
--enum p5_interface_select {
-- P5_DISABLED,
-- P5_INTF_SEL_PHY_P0,
-- P5_INTF_SEL_PHY_P4,
-- P5_INTF_SEL_GMAC5,
-+/* Port 5 mode definitions of the MT7530 switch */
-+enum mt7530_p5_mode {
-+ GMAC5,
-+ MUX_PHY_P0,
-+ MUX_PHY_P4,
- };
-
- struct mt7530_priv;
-@@ -776,7 +775,7 @@ struct mt753x_info {
- * @ports: Holding the state among ports
- * @reg_mutex: The lock for protecting among process accessing
- * registers
-- * @p5_intf_sel: Holding the current port 5 interface select
-+ * @p5_mode: Holding the current mode of port 5 of the MT7530 switch
- * @p5_sgmii: Flag for distinguishing if port 5 of the MT7531 switch
- * has got SGMII
- * @irq: IRQ number of the switch
-@@ -798,7 +797,7 @@ struct mt7530_priv {
- const struct mt753x_info *info;
- unsigned int id;
- bool mcm;
-- enum p5_interface_select p5_intf_sel;
-+ enum mt7530_p5_mode p5_mode;
- bool p5_sgmii;
- u8 mirror_rx;
- u8 mirror_tx;
+++ /dev/null
-From 83fe3df057e641cd0e88425e579d7a5a370ca430 Mon Sep 17 00:00:00 2001
-Date: Mon, 22 Apr 2024 10:15:11 +0300
-Subject: [PATCH 04/15] net: dsa: mt7530: rename mt753x_bpdu_port_fw enum to
- mt753x_to_cpu_fw
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-The mt753x_bpdu_port_fw enum is globally used for manipulating the process
-of deciding the forwardable ports, specifically concerning the CPU port(s).
-Therefore, rename it and the values in it to mt753x_to_cpu_fw.
-
-Change FOLLOW_MFC to SYSTEM_DEFAULT to be on par with the switch documents.
-
----
- drivers/net/dsa/mt7530.c | 44 ++++++++++-------------
- drivers/net/dsa/mt7530.h | 76 ++++++++++++++++++++--------------------
- 2 files changed, 56 insertions(+), 64 deletions(-)
-
---- a/drivers/net/dsa/mt7530.c
-+++ b/drivers/net/dsa/mt7530.c
-@@ -1107,42 +1107,34 @@ mt753x_trap_frames(struct mt7530_priv *p
- * VLAN-untagged.
- */
- mt7530_rmw(priv, MT753X_BPC,
-- MT753X_PAE_BPDU_FR | MT753X_PAE_EG_TAG_MASK |
-- MT753X_PAE_PORT_FW_MASK | MT753X_BPDU_EG_TAG_MASK |
-- MT753X_BPDU_PORT_FW_MASK,
-- MT753X_PAE_BPDU_FR |
-- MT753X_PAE_EG_TAG(MT7530_VLAN_EG_UNTAGGED) |
-- MT753X_PAE_PORT_FW(MT753X_BPDU_CPU_ONLY) |
-- MT753X_BPDU_EG_TAG(MT7530_VLAN_EG_UNTAGGED) |
-- MT753X_BPDU_CPU_ONLY);
-+ PAE_BPDU_FR | PAE_EG_TAG_MASK | PAE_PORT_FW_MASK |
-+ BPDU_EG_TAG_MASK | BPDU_PORT_FW_MASK,
-+ PAE_BPDU_FR | PAE_EG_TAG(MT7530_VLAN_EG_UNTAGGED) |
-+ PAE_PORT_FW(TO_CPU_FW_CPU_ONLY) |
-+ BPDU_EG_TAG(MT7530_VLAN_EG_UNTAGGED) |
-+ TO_CPU_FW_CPU_ONLY);
-
- /* Trap frames with :01 and :02 MAC DAs to the CPU port(s) and egress
- * them VLAN-untagged.
- */
- mt7530_rmw(priv, MT753X_RGAC1,
-- MT753X_R02_BPDU_FR | MT753X_R02_EG_TAG_MASK |
-- MT753X_R02_PORT_FW_MASK | MT753X_R01_BPDU_FR |
-- MT753X_R01_EG_TAG_MASK | MT753X_R01_PORT_FW_MASK,
-- MT753X_R02_BPDU_FR |
-- MT753X_R02_EG_TAG(MT7530_VLAN_EG_UNTAGGED) |
-- MT753X_R02_PORT_FW(MT753X_BPDU_CPU_ONLY) |
-- MT753X_R01_BPDU_FR |
-- MT753X_R01_EG_TAG(MT7530_VLAN_EG_UNTAGGED) |
-- MT753X_BPDU_CPU_ONLY);
-+ R02_BPDU_FR | R02_EG_TAG_MASK | R02_PORT_FW_MASK |
-+ R01_BPDU_FR | R01_EG_TAG_MASK | R01_PORT_FW_MASK,
-+ R02_BPDU_FR | R02_EG_TAG(MT7530_VLAN_EG_UNTAGGED) |
-+ R02_PORT_FW(TO_CPU_FW_CPU_ONLY) | R01_BPDU_FR |
-+ R01_EG_TAG(MT7530_VLAN_EG_UNTAGGED) |
-+ TO_CPU_FW_CPU_ONLY);
-
- /* Trap frames with :03 and :0E MAC DAs to the CPU port(s) and egress
- * them VLAN-untagged.
- */
- mt7530_rmw(priv, MT753X_RGAC2,
-- MT753X_R0E_BPDU_FR | MT753X_R0E_EG_TAG_MASK |
-- MT753X_R0E_PORT_FW_MASK | MT753X_R03_BPDU_FR |
-- MT753X_R03_EG_TAG_MASK | MT753X_R03_PORT_FW_MASK,
-- MT753X_R0E_BPDU_FR |
-- MT753X_R0E_EG_TAG(MT7530_VLAN_EG_UNTAGGED) |
-- MT753X_R0E_PORT_FW(MT753X_BPDU_CPU_ONLY) |
-- MT753X_R03_BPDU_FR |
-- MT753X_R03_EG_TAG(MT7530_VLAN_EG_UNTAGGED) |
-- MT753X_BPDU_CPU_ONLY);
-+ R0E_BPDU_FR | R0E_EG_TAG_MASK | R0E_PORT_FW_MASK |
-+ R03_BPDU_FR | R03_EG_TAG_MASK | R03_PORT_FW_MASK,
-+ R0E_BPDU_FR | R0E_EG_TAG(MT7530_VLAN_EG_UNTAGGED) |
-+ R0E_PORT_FW(TO_CPU_FW_CPU_ONLY) | R03_BPDU_FR |
-+ R03_EG_TAG(MT7530_VLAN_EG_UNTAGGED) |
-+ TO_CPU_FW_CPU_ONLY);
- }
-
- static void
---- a/drivers/net/dsa/mt7530.h
-+++ b/drivers/net/dsa/mt7530.h
-@@ -67,47 +67,47 @@ enum mt753x_id {
- #define MT753X_MIRROR_MASK(id) ((((id) == ID_MT7531) || ((id) == ID_MT7988)) ? \
- MT7531_MIRROR_MASK : MIRROR_MASK)
-
--/* Registers for BPDU and PAE frame control*/
-+/* Register for BPDU and PAE frame control */
- #define MT753X_BPC 0x24
--#define MT753X_PAE_BPDU_FR BIT(25)
--#define MT753X_PAE_EG_TAG_MASK GENMASK(24, 22)
--#define MT753X_PAE_EG_TAG(x) FIELD_PREP(MT753X_PAE_EG_TAG_MASK, x)
--#define MT753X_PAE_PORT_FW_MASK GENMASK(18, 16)
--#define MT753X_PAE_PORT_FW(x) FIELD_PREP(MT753X_PAE_PORT_FW_MASK, x)
--#define MT753X_BPDU_EG_TAG_MASK GENMASK(8, 6)
--#define MT753X_BPDU_EG_TAG(x) FIELD_PREP(MT753X_BPDU_EG_TAG_MASK, x)
--#define MT753X_BPDU_PORT_FW_MASK GENMASK(2, 0)
-+#define PAE_BPDU_FR BIT(25)
-+#define PAE_EG_TAG_MASK GENMASK(24, 22)
-+#define PAE_EG_TAG(x) FIELD_PREP(PAE_EG_TAG_MASK, x)
-+#define PAE_PORT_FW_MASK GENMASK(18, 16)
-+#define PAE_PORT_FW(x) FIELD_PREP(PAE_PORT_FW_MASK, x)
-+#define BPDU_EG_TAG_MASK GENMASK(8, 6)
-+#define BPDU_EG_TAG(x) FIELD_PREP(BPDU_EG_TAG_MASK, x)
-+#define BPDU_PORT_FW_MASK GENMASK(2, 0)
-
--/* Register for :01 and :02 MAC DA frame control */
-+/* Register for 01-80-C2-00-00-[01,02] MAC DA frame control */
- #define MT753X_RGAC1 0x28
--#define MT753X_R02_BPDU_FR BIT(25)
--#define MT753X_R02_EG_TAG_MASK GENMASK(24, 22)
--#define MT753X_R02_EG_TAG(x) FIELD_PREP(MT753X_R02_EG_TAG_MASK, x)
--#define MT753X_R02_PORT_FW_MASK GENMASK(18, 16)
--#define MT753X_R02_PORT_FW(x) FIELD_PREP(MT753X_R02_PORT_FW_MASK, x)
--#define MT753X_R01_BPDU_FR BIT(9)
--#define MT753X_R01_EG_TAG_MASK GENMASK(8, 6)
--#define MT753X_R01_EG_TAG(x) FIELD_PREP(MT753X_R01_EG_TAG_MASK, x)
--#define MT753X_R01_PORT_FW_MASK GENMASK(2, 0)
-+#define R02_BPDU_FR BIT(25)
-+#define R02_EG_TAG_MASK GENMASK(24, 22)
-+#define R02_EG_TAG(x) FIELD_PREP(R02_EG_TAG_MASK, x)
-+#define R02_PORT_FW_MASK GENMASK(18, 16)
-+#define R02_PORT_FW(x) FIELD_PREP(R02_PORT_FW_MASK, x)
-+#define R01_BPDU_FR BIT(9)
-+#define R01_EG_TAG_MASK GENMASK(8, 6)
-+#define R01_EG_TAG(x) FIELD_PREP(R01_EG_TAG_MASK, x)
-+#define R01_PORT_FW_MASK GENMASK(2, 0)
-
--/* Register for :03 and :0E MAC DA frame control */
-+/* Register for 01-80-C2-00-00-[03,0E] MAC DA frame control */
- #define MT753X_RGAC2 0x2c
--#define MT753X_R0E_BPDU_FR BIT(25)
--#define MT753X_R0E_EG_TAG_MASK GENMASK(24, 22)
--#define MT753X_R0E_EG_TAG(x) FIELD_PREP(MT753X_R0E_EG_TAG_MASK, x)
--#define MT753X_R0E_PORT_FW_MASK GENMASK(18, 16)
--#define MT753X_R0E_PORT_FW(x) FIELD_PREP(MT753X_R0E_PORT_FW_MASK, x)
--#define MT753X_R03_BPDU_FR BIT(9)
--#define MT753X_R03_EG_TAG_MASK GENMASK(8, 6)
--#define MT753X_R03_EG_TAG(x) FIELD_PREP(MT753X_R03_EG_TAG_MASK, x)
--#define MT753X_R03_PORT_FW_MASK GENMASK(2, 0)
-+#define R0E_BPDU_FR BIT(25)
-+#define R0E_EG_TAG_MASK GENMASK(24, 22)
-+#define R0E_EG_TAG(x) FIELD_PREP(R0E_EG_TAG_MASK, x)
-+#define R0E_PORT_FW_MASK GENMASK(18, 16)
-+#define R0E_PORT_FW(x) FIELD_PREP(R0E_PORT_FW_MASK, x)
-+#define R03_BPDU_FR BIT(9)
-+#define R03_EG_TAG_MASK GENMASK(8, 6)
-+#define R03_EG_TAG(x) FIELD_PREP(R03_EG_TAG_MASK, x)
-+#define R03_PORT_FW_MASK GENMASK(2, 0)
-
--enum mt753x_bpdu_port_fw {
-- MT753X_BPDU_FOLLOW_MFC,
-- MT753X_BPDU_CPU_EXCLUDE = 4,
-- MT753X_BPDU_CPU_INCLUDE = 5,
-- MT753X_BPDU_CPU_ONLY = 6,
-- MT753X_BPDU_DROP = 7,
-+enum mt753x_to_cpu_fw {
-+ TO_CPU_FW_SYSTEM_DEFAULT,
-+ TO_CPU_FW_CPU_EXCLUDE = 4,
-+ TO_CPU_FW_CPU_INCLUDE = 5,
-+ TO_CPU_FW_CPU_ONLY = 6,
-+ TO_CPU_FW_DROP = 7,
- };
-
- /* Registers for address table access */
+++ /dev/null
-From 1dbc1bdc2869e6d2929235c70d64e393aa5a5fa2 Mon Sep 17 00:00:00 2001
-Date: Mon, 22 Apr 2024 10:15:12 +0300
-Subject: [PATCH 05/15] net: dsa: mt7530: refactor MT7530_MFC and MT7531_CFC,
- add MT7531_QRY_FFP
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-The MT7530_MFC register is on MT7530, MT7531, and the switch on the MT7988
-SoC. Rename it to MT753X_MFC. Bit 7 to 0 differs between MT7530 and
-MT7531/MT7988. Add MT7530 prefix to these definitions, and define the
-IGMP/MLD Query Frame Flooding Ports mask for MT7531.
-
-Rename the cases of MIRROR_MASK to MIRROR_PORT_MASK.
-
-Move mt753x_mirror_port_get() and mt753x_port_mirror_set() to mt7530.h as
-macros.
-
----
- drivers/net/dsa/mt7530.c | 38 ++++++++--------------
- drivers/net/dsa/mt7530.h | 69 +++++++++++++++++++++++++---------------
- 2 files changed, 57 insertions(+), 50 deletions(-)
-
---- a/drivers/net/dsa/mt7530.c
-+++ b/drivers/net/dsa/mt7530.c
-@@ -1147,7 +1147,7 @@ mt753x_cpu_port_enable(struct dsa_switch
- PORT_SPEC_TAG);
-
- /* Enable flooding on the CPU port */
-- mt7530_set(priv, MT7530_MFC, BC_FFP(BIT(port)) | UNM_FFP(BIT(port)) |
-+ mt7530_set(priv, MT753X_MFC, BC_FFP(BIT(port)) | UNM_FFP(BIT(port)) |
- UNU_FFP(BIT(port)));
-
- /* Add the CPU port to the CPU port bitmap for MT7531 and the switch on
-@@ -1311,15 +1311,15 @@ mt7530_port_bridge_flags(struct dsa_swit
- flags.val & BR_LEARNING ? 0 : SA_DIS);
-
- if (flags.mask & BR_FLOOD)
-- mt7530_rmw(priv, MT7530_MFC, UNU_FFP(BIT(port)),
-+ mt7530_rmw(priv, MT753X_MFC, UNU_FFP(BIT(port)),
- flags.val & BR_FLOOD ? UNU_FFP(BIT(port)) : 0);
-
- if (flags.mask & BR_MCAST_FLOOD)
-- mt7530_rmw(priv, MT7530_MFC, UNM_FFP(BIT(port)),
-+ mt7530_rmw(priv, MT753X_MFC, UNM_FFP(BIT(port)),
- flags.val & BR_MCAST_FLOOD ? UNM_FFP(BIT(port)) : 0);
-
- if (flags.mask & BR_BCAST_FLOOD)
-- mt7530_rmw(priv, MT7530_MFC, BC_FFP(BIT(port)),
-+ mt7530_rmw(priv, MT753X_MFC, BC_FFP(BIT(port)),
- flags.val & BR_BCAST_FLOOD ? BC_FFP(BIT(port)) : 0);
-
- return 0;
-@@ -1855,20 +1855,6 @@ mt7530_port_vlan_del(struct dsa_switch *
- return 0;
- }
-
--static int mt753x_mirror_port_get(unsigned int id, u32 val)
--{
-- return (id == ID_MT7531 || id == ID_MT7988) ?
-- MT7531_MIRROR_PORT_GET(val) :
-- MIRROR_PORT(val);
--}
--
--static int mt753x_mirror_port_set(unsigned int id, u32 val)
--{
-- return (id == ID_MT7531 || id == ID_MT7988) ?
-- MT7531_MIRROR_PORT_SET(val) :
-- MIRROR_PORT(val);
--}
--
- static int mt753x_port_mirror_add(struct dsa_switch *ds, int port,
- struct dsa_mall_mirror_tc_entry *mirror,
- bool ingress, struct netlink_ext_ack *extack)
-@@ -1884,14 +1870,14 @@ static int mt753x_port_mirror_add(struct
- val = mt7530_read(priv, MT753X_MIRROR_REG(priv->id));
-
- /* MT7530 only supports one monitor port */
-- monitor_port = mt753x_mirror_port_get(priv->id, val);
-+ monitor_port = MT753X_MIRROR_PORT_GET(priv->id, val);
- if (val & MT753X_MIRROR_EN(priv->id) &&
- monitor_port != mirror->to_local_port)
- return -EEXIST;
-
- val |= MT753X_MIRROR_EN(priv->id);
-- val &= ~MT753X_MIRROR_MASK(priv->id);
-- val |= mt753x_mirror_port_set(priv->id, mirror->to_local_port);
-+ val &= ~MT753X_MIRROR_PORT_MASK(priv->id);
-+ val |= MT753X_MIRROR_PORT_SET(priv->id, mirror->to_local_port);
- mt7530_write(priv, MT753X_MIRROR_REG(priv->id), val);
-
- val = mt7530_read(priv, MT7530_PCR_P(port));
-@@ -2536,7 +2522,7 @@ mt7531_setup_common(struct dsa_switch *d
- mt7530_mib_reset(ds);
-
- /* Disable flooding on all ports */
-- mt7530_clear(priv, MT7530_MFC, BC_FFP_MASK | UNM_FFP_MASK |
-+ mt7530_clear(priv, MT753X_MFC, BC_FFP_MASK | UNM_FFP_MASK |
- UNU_FFP_MASK);
-
- for (i = 0; i < MT7530_NUM_PORTS; i++) {
-@@ -3085,10 +3071,12 @@ mt753x_conduit_state_change(struct dsa_s
- else
- priv->active_cpu_ports &= ~mask;
-
-- if (priv->active_cpu_ports)
-- val = CPU_EN | CPU_PORT(__ffs(priv->active_cpu_ports));
-+ if (priv->active_cpu_ports) {
-+ val = MT7530_CPU_EN |
-+ MT7530_CPU_PORT(__ffs(priv->active_cpu_ports));
-+ }
-
-- mt7530_rmw(priv, MT7530_MFC, CPU_EN | CPU_PORT_MASK, val);
-+ mt7530_rmw(priv, MT753X_MFC, MT7530_CPU_EN | MT7530_CPU_PORT_MASK, val);
- }
-
- static int mt7988_setup(struct dsa_switch *ds)
---- a/drivers/net/dsa/mt7530.h
-+++ b/drivers/net/dsa/mt7530.h
-@@ -36,36 +36,55 @@ enum mt753x_id {
- #define MT753X_AGC 0xc
- #define LOCAL_EN BIT(7)
-
--/* Registers to mac forward control for unknown frames */
--#define MT7530_MFC 0x10
--#define BC_FFP(x) (((x) & 0xff) << 24)
--#define BC_FFP_MASK BC_FFP(~0)
--#define UNM_FFP(x) (((x) & 0xff) << 16)
--#define UNM_FFP_MASK UNM_FFP(~0)
--#define UNU_FFP(x) (((x) & 0xff) << 8)
--#define UNU_FFP_MASK UNU_FFP(~0)
--#define CPU_EN BIT(7)
--#define CPU_PORT_MASK GENMASK(6, 4)
--#define CPU_PORT(x) FIELD_PREP(CPU_PORT_MASK, x)
--#define MIRROR_EN BIT(3)
--#define MIRROR_PORT(x) ((x) & 0x7)
--#define MIRROR_MASK 0x7
-+/* Register for MAC forward control */
-+#define MT753X_MFC 0x10
-+#define BC_FFP_MASK GENMASK(31, 24)
-+#define BC_FFP(x) FIELD_PREP(BC_FFP_MASK, x)
-+#define UNM_FFP_MASK GENMASK(23, 16)
-+#define UNM_FFP(x) FIELD_PREP(UNM_FFP_MASK, x)
-+#define UNU_FFP_MASK GENMASK(15, 8)
-+#define UNU_FFP(x) FIELD_PREP(UNU_FFP_MASK, x)
-+#define MT7530_CPU_EN BIT(7)
-+#define MT7530_CPU_PORT_MASK GENMASK(6, 4)
-+#define MT7530_CPU_PORT(x) FIELD_PREP(MT7530_CPU_PORT_MASK, x)
-+#define MT7530_MIRROR_EN BIT(3)
-+#define MT7530_MIRROR_PORT_MASK GENMASK(2, 0)
-+#define MT7530_MIRROR_PORT_GET(x) FIELD_GET(MT7530_MIRROR_PORT_MASK, x)
-+#define MT7530_MIRROR_PORT_SET(x) FIELD_PREP(MT7530_MIRROR_PORT_MASK, x)
-+#define MT7531_QRY_FFP_MASK GENMASK(7, 0)
-+#define MT7531_QRY_FFP(x) FIELD_PREP(MT7531_QRY_FFP_MASK, x)
-
--/* Registers for CPU forward control */
-+/* Register for CPU forward control */
- #define MT7531_CFC 0x4
- #define MT7531_MIRROR_EN BIT(19)
--#define MT7531_MIRROR_MASK (MIRROR_MASK << 16)
--#define MT7531_MIRROR_PORT_GET(x) (((x) >> 16) & MIRROR_MASK)
--#define MT7531_MIRROR_PORT_SET(x) (((x) & MIRROR_MASK) << 16)
-+#define MT7531_MIRROR_PORT_MASK GENMASK(18, 16)
-+#define MT7531_MIRROR_PORT_GET(x) FIELD_GET(MT7531_MIRROR_PORT_MASK, x)
-+#define MT7531_MIRROR_PORT_SET(x) FIELD_PREP(MT7531_MIRROR_PORT_MASK, x)
- #define MT7531_CPU_PMAP_MASK GENMASK(7, 0)
- #define MT7531_CPU_PMAP(x) FIELD_PREP(MT7531_CPU_PMAP_MASK, x)
-
--#define MT753X_MIRROR_REG(id) ((((id) == ID_MT7531) || ((id) == ID_MT7988)) ? \
-- MT7531_CFC : MT7530_MFC)
--#define MT753X_MIRROR_EN(id) ((((id) == ID_MT7531) || ((id) == ID_MT7988)) ? \
-- MT7531_MIRROR_EN : MIRROR_EN)
--#define MT753X_MIRROR_MASK(id) ((((id) == ID_MT7531) || ((id) == ID_MT7988)) ? \
-- MT7531_MIRROR_MASK : MIRROR_MASK)
-+#define MT753X_MIRROR_REG(id) ((id == ID_MT7531 || \
-+ id == ID_MT7988) ? \
-+ MT7531_CFC : MT753X_MFC)
-+
-+#define MT753X_MIRROR_EN(id) ((id == ID_MT7531 || \
-+ id == ID_MT7988) ? \
-+ MT7531_MIRROR_EN : MT7530_MIRROR_EN)
-+
-+#define MT753X_MIRROR_PORT_MASK(id) ((id == ID_MT7531 || \
-+ id == ID_MT7988) ? \
-+ MT7531_MIRROR_PORT_MASK : \
-+ MT7530_MIRROR_PORT_MASK)
-+
-+#define MT753X_MIRROR_PORT_GET(id, val) ((id == ID_MT7531 || \
-+ id == ID_MT7988) ? \
-+ MT7531_MIRROR_PORT_GET(val) : \
-+ MT7530_MIRROR_PORT_GET(val))
-+
-+#define MT753X_MIRROR_PORT_SET(id, val) ((id == ID_MT7531 || \
-+ id == ID_MT7988) ? \
-+ MT7531_MIRROR_PORT_SET(val) : \
-+ MT7530_MIRROR_PORT_SET(val))
-
- /* Register for BPDU and PAE frame control */
- #define MT753X_BPC 0x24
+++ /dev/null
-From 3ccf67597d35c06a7319e407b1c42f78a7966779 Mon Sep 17 00:00:00 2001
-Date: Mon, 22 Apr 2024 10:15:13 +0300
-Subject: [PATCH 06/15] net: dsa: mt7530: refactor MT7530_HWTRAP and
- MT7530_MHWTRAP
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-The MT7530_HWTRAP and MT7530_MHWTRAP registers are on MT7530 and MT7531.
-It's called hardware trap on MT7530, software trap on MT7531. That's
-because some bits of the trap on MT7530 cannot be modified by software
-whilst all bits of the trap on MT7531 can. Rename the definitions for them
-to MT753X_TRAP and MT753X_MTRAP. Add MT7530 and MT7531 prefixes to the
-definitions specific to the switch model.
-
-Remove the extra parentheses from MT7530_XTAL_40MHZ and MT7530_XTAL_20MHZ.
-
-Rename MHWTRAP_PHY0_SEL, MHWTRAP_MANUAL, and MHWTRAP_PHY_ACCESS to be on
-par with the "MT7621 Giga Switch Programming Guide v0.3" document.
-
-Make an enumaration for the XTAL frequency. Set the data type of the xtal
-variable on mt7531_pll_setup() to it.
-
----
- drivers/net/dsa/mt7530.c | 59 ++++++++++++++++++++--------------------
- drivers/net/dsa/mt7530.h | 50 ++++++++++++++++------------------
- 2 files changed, 54 insertions(+), 55 deletions(-)
-
---- a/drivers/net/dsa/mt7530.c
-+++ b/drivers/net/dsa/mt7530.c
-@@ -417,23 +417,23 @@ mt7530_setup_port6(struct dsa_switch *ds
-
- mt7530_rmw(priv, MT7530_P6ECR, P6_INTF_MODE_MASK, P6_INTF_MODE(1));
-
-- xtal = mt7530_read(priv, MT7530_MHWTRAP) & HWTRAP_XTAL_MASK;
-+ xtal = mt7530_read(priv, MT753X_MTRAP) & MT7530_XTAL_MASK;
-
-- if (xtal == HWTRAP_XTAL_25MHZ)
-+ if (xtal == MT7530_XTAL_25MHZ)
- ssc_delta = 0x57;
- else
- ssc_delta = 0x87;
-
- if (priv->id == ID_MT7621) {
- /* PLL frequency: 125MHz: 1.0GBit */
-- if (xtal == HWTRAP_XTAL_40MHZ)
-+ if (xtal == MT7530_XTAL_40MHZ)
- ncpo1 = 0x0640;
-- if (xtal == HWTRAP_XTAL_25MHZ)
-+ if (xtal == MT7530_XTAL_25MHZ)
- ncpo1 = 0x0a00;
- } else { /* PLL frequency: 250MHz: 2.0Gbit */
-- if (xtal == HWTRAP_XTAL_40MHZ)
-+ if (xtal == MT7530_XTAL_40MHZ)
- ncpo1 = 0x0c80;
-- if (xtal == HWTRAP_XTAL_25MHZ)
-+ if (xtal == MT7530_XTAL_25MHZ)
- ncpo1 = 0x1400;
- }
-
-@@ -456,19 +456,20 @@ mt7530_setup_port6(struct dsa_switch *ds
- static void
- mt7531_pll_setup(struct mt7530_priv *priv)
- {
-+ enum mt7531_xtal_fsel xtal;
- u32 top_sig;
- u32 hwstrap;
-- u32 xtal;
- u32 val;
-
- val = mt7530_read(priv, MT7531_CREV);
- top_sig = mt7530_read(priv, MT7531_TOP_SIG_SR);
-- hwstrap = mt7530_read(priv, MT7531_HWTRAP);
-+ hwstrap = mt7530_read(priv, MT753X_TRAP);
- if ((val & CHIP_REV_M) > 0)
-- xtal = (top_sig & PAD_MCM_SMI_EN) ? HWTRAP_XTAL_FSEL_40MHZ :
-- HWTRAP_XTAL_FSEL_25MHZ;
-+ xtal = (top_sig & PAD_MCM_SMI_EN) ? MT7531_XTAL_FSEL_40MHZ :
-+ MT7531_XTAL_FSEL_25MHZ;
- else
-- xtal = hwstrap & HWTRAP_XTAL_FSEL_MASK;
-+ xtal = (hwstrap & MT7531_XTAL25) ? MT7531_XTAL_FSEL_25MHZ :
-+ MT7531_XTAL_FSEL_40MHZ;
-
- /* Step 1 : Disable MT7531 COREPLL */
- val = mt7530_read(priv, MT7531_PLLGP_EN);
-@@ -497,13 +498,13 @@ mt7531_pll_setup(struct mt7530_priv *pri
- usleep_range(25, 35);
-
- switch (xtal) {
-- case HWTRAP_XTAL_FSEL_25MHZ:
-+ case MT7531_XTAL_FSEL_25MHZ:
- val = mt7530_read(priv, MT7531_PLLGP_CR0);
- val &= ~RG_COREPLL_SDM_PCW_M;
- val |= 0x140000 << RG_COREPLL_SDM_PCW_S;
- mt7530_write(priv, MT7531_PLLGP_CR0, val);
- break;
-- case HWTRAP_XTAL_FSEL_40MHZ:
-+ case MT7531_XTAL_FSEL_40MHZ:
- val = mt7530_read(priv, MT7531_PLLGP_CR0);
- val &= ~RG_COREPLL_SDM_PCW_M;
- val |= 0x190000 << RG_COREPLL_SDM_PCW_S;
-@@ -877,20 +878,20 @@ static void mt7530_setup_port5(struct ds
-
- mutex_lock(&priv->reg_mutex);
-
-- val = mt7530_read(priv, MT7530_MHWTRAP);
-+ val = mt7530_read(priv, MT753X_MTRAP);
-
-- val |= MHWTRAP_MANUAL | MHWTRAP_P5_MAC_SEL | MHWTRAP_P5_DIS;
-- val &= ~MHWTRAP_P5_RGMII_MODE & ~MHWTRAP_PHY0_SEL;
-+ val |= MT7530_CHG_TRAP | MT7530_P5_MAC_SEL | MT7530_P5_DIS;
-+ val &= ~MT7530_P5_RGMII_MODE & ~MT7530_P5_PHY0_SEL;
-
- switch (priv->p5_mode) {
- /* MUX_PHY_P0: P0 -> P5 -> SoC MAC */
- case MUX_PHY_P0:
-- val |= MHWTRAP_PHY0_SEL;
-+ val |= MT7530_P5_PHY0_SEL;
- fallthrough;
-
- /* MUX_PHY_P4: P4 -> P5 -> SoC MAC */
- case MUX_PHY_P4:
-- val &= ~MHWTRAP_P5_MAC_SEL & ~MHWTRAP_P5_DIS;
-+ val &= ~MT7530_P5_MAC_SEL & ~MT7530_P5_DIS;
-
- /* Setup the MAC by default for the cpu port */
- mt7530_write(priv, MT753X_PMCR_P(5), 0x56300);
-@@ -898,13 +899,13 @@ static void mt7530_setup_port5(struct ds
-
- /* GMAC5: P5 -> SoC MAC or external PHY */
- default:
-- val &= ~MHWTRAP_P5_DIS;
-+ val &= ~MT7530_P5_DIS;
- break;
- }
-
- /* Setup RGMII settings */
- if (phy_interface_mode_is_rgmii(interface)) {
-- val |= MHWTRAP_P5_RGMII_MODE;
-+ val |= MT7530_P5_RGMII_MODE;
-
- /* P5 RGMII RX Clock Control: delay setting for 1000M */
- mt7530_write(priv, MT7530_P5RGMIIRXCR, CSR_RGMII_EDGE_ALIGN);
-@@ -924,7 +925,7 @@ static void mt7530_setup_port5(struct ds
- P5_IO_CLK_DRV(1) | P5_IO_DATA_DRV(1));
- }
-
-- mt7530_write(priv, MT7530_MHWTRAP, val);
-+ mt7530_write(priv, MT753X_MTRAP, val);
-
- dev_dbg(ds->dev, "Setup P5, HWTRAP=0x%x, mode=%s, phy-mode=%s\n", val,
- mt7530_p5_mode_str(priv->p5_mode), phy_modes(interface));
-@@ -2365,7 +2366,7 @@ mt7530_setup(struct dsa_switch *ds)
- }
-
- /* Waiting for MT7530 got to stable */
-- INIT_MT7530_DUMMY_POLL(&p, priv, MT7530_HWTRAP);
-+ INIT_MT7530_DUMMY_POLL(&p, priv, MT753X_TRAP);
- ret = readx_poll_timeout(_mt7530_read, &p, val, val != 0,
- 20, 1000000);
- if (ret < 0) {
-@@ -2380,7 +2381,7 @@ mt7530_setup(struct dsa_switch *ds)
- return -ENODEV;
- }
-
-- if ((val & HWTRAP_XTAL_MASK) == HWTRAP_XTAL_20MHZ) {
-+ if ((val & MT7530_XTAL_MASK) == MT7530_XTAL_20MHZ) {
- dev_err(priv->dev,
- "MT7530 with a 20MHz XTAL is not supported!\n");
- return -EINVAL;
-@@ -2401,12 +2402,12 @@ mt7530_setup(struct dsa_switch *ds)
- RD_TAP_MASK, RD_TAP(16));
-
- /* Enable port 6 */
-- val = mt7530_read(priv, MT7530_MHWTRAP);
-- val &= ~MHWTRAP_P6_DIS & ~MHWTRAP_PHY_ACCESS;
-- val |= MHWTRAP_MANUAL;
-- mt7530_write(priv, MT7530_MHWTRAP, val);
-+ val = mt7530_read(priv, MT753X_MTRAP);
-+ val &= ~MT7530_P6_DIS & ~MT7530_PHY_INDIRECT_ACCESS;
-+ val |= MT7530_CHG_TRAP;
-+ mt7530_write(priv, MT753X_MTRAP, val);
-
-- if ((val & HWTRAP_XTAL_MASK) == HWTRAP_XTAL_40MHZ)
-+ if ((val & MT7530_XTAL_MASK) == MT7530_XTAL_40MHZ)
- mt7530_pll_setup(priv);
-
- mt753x_trap_frames(priv);
-@@ -2590,7 +2591,7 @@ mt7531_setup(struct dsa_switch *ds)
- }
-
- /* Waiting for MT7530 got to stable */
-- INIT_MT7530_DUMMY_POLL(&p, priv, MT7530_HWTRAP);
-+ INIT_MT7530_DUMMY_POLL(&p, priv, MT753X_TRAP);
- ret = readx_poll_timeout(_mt7530_read, &p, val, val != 0,
- 20, 1000000);
- if (ret < 0) {
---- a/drivers/net/dsa/mt7530.h
-+++ b/drivers/net/dsa/mt7530.h
-@@ -495,32 +495,30 @@ enum mt7531_clk_skew {
- MT7531_CLK_SKEW_REVERSE = 3,
- };
-
--/* Register for hw trap status */
--#define MT7530_HWTRAP 0x7800
--#define HWTRAP_XTAL_MASK (BIT(10) | BIT(9))
--#define HWTRAP_XTAL_25MHZ (BIT(10) | BIT(9))
--#define HWTRAP_XTAL_40MHZ (BIT(10))
--#define HWTRAP_XTAL_20MHZ (BIT(9))
-+/* Register for trap status */
-+#define MT753X_TRAP 0x7800
-+#define MT7530_XTAL_MASK (BIT(10) | BIT(9))
-+#define MT7530_XTAL_25MHZ (BIT(10) | BIT(9))
-+#define MT7530_XTAL_40MHZ BIT(10)
-+#define MT7530_XTAL_20MHZ BIT(9)
-+#define MT7531_XTAL25 BIT(7)
-
--#define MT7531_HWTRAP 0x7800
--#define HWTRAP_XTAL_FSEL_MASK BIT(7)
--#define HWTRAP_XTAL_FSEL_25MHZ BIT(7)
--#define HWTRAP_XTAL_FSEL_40MHZ 0
--/* Unique fields of (M)HWSTRAP for MT7531 */
--#define XTAL_FSEL_S 7
--#define XTAL_FSEL_M BIT(7)
--#define PHY_EN BIT(6)
--#define CHG_STRAP BIT(8)
-+/* Register for trap modification */
-+#define MT753X_MTRAP 0x7804
-+#define MT7530_P5_PHY0_SEL BIT(20)
-+#define MT7530_CHG_TRAP BIT(16)
-+#define MT7530_P5_MAC_SEL BIT(13)
-+#define MT7530_P6_DIS BIT(8)
-+#define MT7530_P5_RGMII_MODE BIT(7)
-+#define MT7530_P5_DIS BIT(6)
-+#define MT7530_PHY_INDIRECT_ACCESS BIT(5)
-+#define MT7531_CHG_STRAP BIT(8)
-+#define MT7531_PHY_EN BIT(6)
-
--/* Register for hw trap modification */
--#define MT7530_MHWTRAP 0x7804
--#define MHWTRAP_PHY0_SEL BIT(20)
--#define MHWTRAP_MANUAL BIT(16)
--#define MHWTRAP_P5_MAC_SEL BIT(13)
--#define MHWTRAP_P6_DIS BIT(8)
--#define MHWTRAP_P5_RGMII_MODE BIT(7)
--#define MHWTRAP_P5_DIS BIT(6)
--#define MHWTRAP_PHY_ACCESS BIT(5)
-+enum mt7531_xtal_fsel {
-+ MT7531_XTAL_FSEL_25MHZ,
-+ MT7531_XTAL_FSEL_40MHZ,
-+};
-
- /* Register for TOP signal control */
- #define MT7530_TOP_SIG_CTRL 0x7808
+++ /dev/null
-From 2982f395c9a513b168f1e685588f70013cba2f5f Mon Sep 17 00:00:00 2001
-Date: Mon, 22 Apr 2024 10:15:14 +0300
-Subject: [PATCH 07/15] net: dsa: mt7530: move MT753X_MTRAP operations for
- MT7530
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-On MT7530, the media-independent interfaces of port 5 and 6 are controlled
-by the MT7530_P5_DIS and MT7530_P6_DIS bits of the hardware trap. Deal with
-these bits only when the relevant port is being enabled or disabled. This
-ensures that these ports will be disabled when they are not in use.
-
-Do not set MT7530_CHG_TRAP on mt7530_setup_port5() as that's already being
-done on mt7530_setup().
-
-Instead of globally setting MT7530_P5_MAC_SEL, clear it, then set it only
-on the appropriate case.
-
-If PHY muxing is detected, clear MT7530_P5_DIS before calling
-mt7530_setup_port5().
-
----
- drivers/net/dsa/mt7530.c | 38 +++++++++++++++++++++++++++-----------
- 1 file changed, 27 insertions(+), 11 deletions(-)
-
---- a/drivers/net/dsa/mt7530.c
-+++ b/drivers/net/dsa/mt7530.c
-@@ -880,8 +880,7 @@ static void mt7530_setup_port5(struct ds
-
- val = mt7530_read(priv, MT753X_MTRAP);
-
-- val |= MT7530_CHG_TRAP | MT7530_P5_MAC_SEL | MT7530_P5_DIS;
-- val &= ~MT7530_P5_RGMII_MODE & ~MT7530_P5_PHY0_SEL;
-+ val &= ~MT7530_P5_PHY0_SEL & ~MT7530_P5_MAC_SEL & ~MT7530_P5_RGMII_MODE;
-
- switch (priv->p5_mode) {
- /* MUX_PHY_P0: P0 -> P5 -> SoC MAC */
-@@ -891,15 +890,13 @@ static void mt7530_setup_port5(struct ds
-
- /* MUX_PHY_P4: P4 -> P5 -> SoC MAC */
- case MUX_PHY_P4:
-- val &= ~MT7530_P5_MAC_SEL & ~MT7530_P5_DIS;
--
- /* Setup the MAC by default for the cpu port */
- mt7530_write(priv, MT753X_PMCR_P(5), 0x56300);
- break;
-
- /* GMAC5: P5 -> SoC MAC or external PHY */
- default:
-- val &= ~MT7530_P5_DIS;
-+ val |= MT7530_P5_MAC_SEL;
- break;
- }
-
-@@ -1193,6 +1190,14 @@ mt7530_port_enable(struct dsa_switch *ds
-
- mutex_unlock(&priv->reg_mutex);
-
-+ if (priv->id != ID_MT7530 && priv->id != ID_MT7621)
-+ return 0;
-+
-+ if (port == 5)
-+ mt7530_clear(priv, MT753X_MTRAP, MT7530_P5_DIS);
-+ else if (port == 6)
-+ mt7530_clear(priv, MT753X_MTRAP, MT7530_P6_DIS);
-+
- return 0;
- }
-
-@@ -1211,6 +1216,14 @@ mt7530_port_disable(struct dsa_switch *d
- PCR_MATRIX_CLR);
-
- mutex_unlock(&priv->reg_mutex);
-+
-+ if (priv->id != ID_MT7530 && priv->id != ID_MT7621)
-+ return;
-+
-+ if (port == 5)
-+ mt7530_set(priv, MT753X_MTRAP, MT7530_P5_DIS);
-+ else if (port == 6)
-+ mt7530_set(priv, MT753X_MTRAP, MT7530_P6_DIS);
- }
-
- static int
-@@ -2401,11 +2414,11 @@ mt7530_setup(struct dsa_switch *ds)
- mt7530_rmw(priv, MT7530_TRGMII_RD(i),
- RD_TAP_MASK, RD_TAP(16));
-
-- /* Enable port 6 */
-- val = mt7530_read(priv, MT753X_MTRAP);
-- val &= ~MT7530_P6_DIS & ~MT7530_PHY_INDIRECT_ACCESS;
-- val |= MT7530_CHG_TRAP;
-- mt7530_write(priv, MT753X_MTRAP, val);
-+ /* Allow modifying the trap and directly access PHY registers via the
-+ * MDIO bus the switch is on.
-+ */
-+ mt7530_rmw(priv, MT753X_MTRAP, MT7530_CHG_TRAP |
-+ MT7530_PHY_INDIRECT_ACCESS, MT7530_CHG_TRAP);
-
- if ((val & MT7530_XTAL_MASK) == MT7530_XTAL_40MHZ)
- mt7530_pll_setup(priv);
-@@ -2488,8 +2501,11 @@ mt7530_setup(struct dsa_switch *ds)
- break;
- }
-
-- if (priv->p5_mode == MUX_PHY_P0 || priv->p5_mode == MUX_PHY_P4)
-+ if (priv->p5_mode == MUX_PHY_P0 ||
-+ priv->p5_mode == MUX_PHY_P4) {
-+ mt7530_clear(priv, MT753X_MTRAP, MT7530_P5_DIS);
- mt7530_setup_port5(ds, interface);
-+ }
- }
-
- #ifdef CONFIG_GPIOLIB
+++ /dev/null
-From 1f5669efca65564c7533704917f79003c6b36c9c Mon Sep 17 00:00:00 2001
-Date: Mon, 22 Apr 2024 10:15:15 +0300
-Subject: [PATCH 08/15] net: dsa: mt7530: return mt7530_setup_mdio &
- mt7531_setup_common on error
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-The mt7530_setup_mdio() and mt7531_setup_common() functions should be
-checked for errors. Return if the functions return a non-zero value.
-
----
- drivers/net/dsa/mt7530.c | 6 +++++-
- 1 file changed, 5 insertions(+), 1 deletion(-)
-
---- a/drivers/net/dsa/mt7530.c
-+++ b/drivers/net/dsa/mt7530.c
-@@ -2671,7 +2671,9 @@ mt7531_setup(struct dsa_switch *ds)
- 0);
- }
-
-- mt7531_setup_common(ds);
-+ ret = mt7531_setup_common(ds);
-+ if (ret)
-+ return ret;
-
- return 0;
- }
-@@ -3016,6 +3018,8 @@ mt753x_setup(struct dsa_switch *ds)
- ret = mt7530_setup_mdio(priv);
- if (ret && priv->irq)
- mt7530_free_irq_common(priv);
-+ if (ret)
-+ return ret;
-
- /* Initialise the PCS devices */
- for (i = 0; i < priv->ds->num_ports; i++) {
+++ /dev/null
-From 6cc2d4ccd77509df74b7b8ef46bbc6ba0a571318 Mon Sep 17 00:00:00 2001
-Date: Mon, 22 Apr 2024 10:15:16 +0300
-Subject: [PATCH 09/15] net: dsa: mt7530: define MAC speed capabilities per
- switch model
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-With the support of the MT7988 SoC switch, the MAC speed capabilities
-defined on mt753x_phylink_get_caps() won't apply to all switch models
-anymore. Move them to more appropriate locations instead of overwriting
-config->mac_capabilities.
-
-Remove the comment on mt753x_phylink_get_caps() as it's become invalid with
-the support of MT7531 and MT7988 SoC switch.
-
-Add break to case 6 of mt7988_mac_port_get_caps() to be explicit.
-
----
- drivers/net/dsa/mt7530.c | 15 ++++++++++-----
- 1 file changed, 10 insertions(+), 5 deletions(-)
-
---- a/drivers/net/dsa/mt7530.c
-+++ b/drivers/net/dsa/mt7530.c
-@@ -2681,6 +2681,8 @@ mt7531_setup(struct dsa_switch *ds)
- static void mt7530_mac_port_get_caps(struct dsa_switch *ds, int port,
- struct phylink_config *config)
- {
-+ config->mac_capabilities |= MAC_10 | MAC_100 | MAC_1000FD;
-+
- switch (port) {
- /* Ports which are connected to switch PHYs. There is no MII pinout. */
- case 0 ... 4:
-@@ -2712,6 +2714,8 @@ static void mt7531_mac_port_get_caps(str
- {
- struct mt7530_priv *priv = ds->priv;
-
-+ config->mac_capabilities |= MAC_10 | MAC_100 | MAC_1000FD;
-+
- switch (port) {
- /* Ports which are connected to switch PHYs. There is no MII pinout. */
- case 0 ... 4:
-@@ -2751,14 +2755,17 @@ static void mt7988_mac_port_get_caps(str
- case 0 ... 3:
- __set_bit(PHY_INTERFACE_MODE_INTERNAL,
- config->supported_interfaces);
-+
-+ config->mac_capabilities |= MAC_10 | MAC_100 | MAC_1000FD;
- break;
-
- /* Port 6 is connected to SoC's XGMII MAC. There is no MII pinout. */
- case 6:
- __set_bit(PHY_INTERFACE_MODE_INTERNAL,
- config->supported_interfaces);
-- config->mac_capabilities = MAC_ASYM_PAUSE | MAC_SYM_PAUSE |
-- MAC_10000FD;
-+
-+ config->mac_capabilities |= MAC_10000FD;
-+ break;
- }
- }
-
-@@ -2928,9 +2935,7 @@ static void mt753x_phylink_get_caps(stru
- {
- struct mt7530_priv *priv = ds->priv;
-
-- /* This switch only supports full-duplex at 1Gbps */
-- config->mac_capabilities = MAC_ASYM_PAUSE | MAC_SYM_PAUSE |
-- MAC_10 | MAC_100 | MAC_1000FD;
-+ config->mac_capabilities = MAC_ASYM_PAUSE | MAC_SYM_PAUSE;
-
- priv->info->mac_port_get_caps(ds, port, config);
- }
+++ /dev/null
-From dd0f15fc877c10567699190bce0f55e96f4ad6b5 Mon Sep 17 00:00:00 2001
-Date: Mon, 22 Apr 2024 10:15:17 +0300
-Subject: [PATCH 10/15] net: dsa: mt7530: get rid of function sanity check
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Get rid of checking whether functions are filled properly. priv->info which
-is an mt753x_info structure is filled and checked for before this check.
-It's unnecessary checking whether it's filled properly.
-
----
- drivers/net/dsa/mt7530.c | 7 -------
- 1 file changed, 7 deletions(-)
-
---- a/drivers/net/dsa/mt7530.c
-+++ b/drivers/net/dsa/mt7530.c
-@@ -3228,13 +3228,6 @@ mt7530_probe_common(struct mt7530_priv *
- if (!priv->info)
- return -EINVAL;
-
-- /* Sanity check if these required device operations are filled
-- * properly.
-- */
-- if (!priv->info->sw_setup || !priv->info->phy_read_c22 ||
-- !priv->info->phy_write_c22 || !priv->info->mac_port_get_caps)
-- return -EINVAL;
--
- priv->id = priv->info->id;
- priv->dev = dev;
- priv->ds->priv = priv;
+++ /dev/null
-From 2dff9759602b069f97ccc939e15a47ca051b2983 Mon Sep 17 00:00:00 2001
-Date: Mon, 22 Apr 2024 10:15:18 +0300
-Subject: [PATCH 11/15] net: dsa: mt7530: refactor MT7530_PMEEECR_P()
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-The MT7530_PMEEECR_P() register is on MT7530, MT7531, and the switch on the
-MT7988 SoC. Rename the definition for them to MT753X_PMEEECR_P(). Use the
-FIELD_PREP and FIELD_GET macros. Rename GET_LPI_THRESH() and
-SET_LPI_THRESH() to LPI_THRESH_GET() and LPI_THRESH_SET().
-
----
- drivers/net/dsa/mt7530.c | 8 ++++----
- drivers/net/dsa/mt7530.h | 13 +++++++------
- 2 files changed, 11 insertions(+), 10 deletions(-)
-
---- a/drivers/net/dsa/mt7530.c
-+++ b/drivers/net/dsa/mt7530.c
-@@ -3047,10 +3047,10 @@ static int mt753x_get_mac_eee(struct dsa
- struct ethtool_eee *e)
- {
- struct mt7530_priv *priv = ds->priv;
-- u32 eeecr = mt7530_read(priv, MT7530_PMEEECR_P(port));
-+ u32 eeecr = mt7530_read(priv, MT753X_PMEEECR_P(port));
-
- e->tx_lpi_enabled = !(eeecr & LPI_MODE_EN);
-- e->tx_lpi_timer = GET_LPI_THRESH(eeecr);
-+ e->tx_lpi_timer = LPI_THRESH_GET(eeecr);
-
- return 0;
- }
-@@ -3064,11 +3064,11 @@ static int mt753x_set_mac_eee(struct dsa
- if (e->tx_lpi_timer > 0xFFF)
- return -EINVAL;
-
-- set = SET_LPI_THRESH(e->tx_lpi_timer);
-+ set = LPI_THRESH_SET(e->tx_lpi_timer);
- if (!e->tx_lpi_enabled)
- /* Force LPI Mode without a delay */
- set |= LPI_MODE_EN;
-- mt7530_rmw(priv, MT7530_PMEEECR_P(port), mask, set);
-+ mt7530_rmw(priv, MT753X_PMEEECR_P(port), mask, set);
-
- return 0;
- }
---- a/drivers/net/dsa/mt7530.h
-+++ b/drivers/net/dsa/mt7530.h
-@@ -364,13 +364,14 @@ enum mt7530_vlan_port_acc_frm {
- PMCR_FORCE_SPEED_100 | \
- PMCR_FORCE_FDX | PMCR_FORCE_LNK)
-
--#define MT7530_PMEEECR_P(x) (0x3004 + (x) * 0x100)
--#define WAKEUP_TIME_1000(x) (((x) & 0xFF) << 24)
--#define WAKEUP_TIME_100(x) (((x) & 0xFF) << 16)
-+#define MT753X_PMEEECR_P(x) (0x3004 + (x) * 0x100)
-+#define WAKEUP_TIME_1000_MASK GENMASK(31, 24)
-+#define WAKEUP_TIME_1000(x) FIELD_PREP(WAKEUP_TIME_1000_MASK, x)
-+#define WAKEUP_TIME_100_MASK GENMASK(23, 16)
-+#define WAKEUP_TIME_100(x) FIELD_PREP(WAKEUP_TIME_100_MASK, x)
- #define LPI_THRESH_MASK GENMASK(15, 4)
--#define LPI_THRESH_SHT 4
--#define SET_LPI_THRESH(x) (((x) << LPI_THRESH_SHT) & LPI_THRESH_MASK)
--#define GET_LPI_THRESH(x) (((x) & LPI_THRESH_MASK) >> LPI_THRESH_SHT)
-+#define LPI_THRESH_GET(x) FIELD_GET(LPI_THRESH_MASK, x)
-+#define LPI_THRESH_SET(x) FIELD_PREP(LPI_THRESH_MASK, x)
- #define LPI_MODE_EN BIT(0)
-
- #define MT7530_PMSR_P(x) (0x3008 + (x) * 0x100)
+++ /dev/null
-From 21d67c2fabfe40baf33202d3287b67b6c16f8382 Mon Sep 17 00:00:00 2001
-Date: Mon, 22 Apr 2024 10:15:19 +0300
-Subject: [PATCH 12/15] net: dsa: mt7530: get rid of mac_port_validate member
- of mt753x_info
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-The mac_port_validate member of the mt753x_info structure is not being
-used, remove it. Improve the member description section in the process.
-
----
- drivers/net/dsa/mt7530.h | 10 +++-------
- 1 file changed, 3 insertions(+), 7 deletions(-)
-
---- a/drivers/net/dsa/mt7530.h
-+++ b/drivers/net/dsa/mt7530.h
-@@ -743,15 +743,14 @@ struct mt753x_pcs {
-
- /* struct mt753x_info - This is the main data structure for holding the specific
- * part for each supported device
-+ * @id: Holding the identifier to a switch model
-+ * @pcs_ops: Holding the pointer to the MAC PCS operations structure
- * @sw_setup: Holding the handler to a device initialization
- * @phy_read_c22: Holding the way reading PHY port using C22
- * @phy_write_c22: Holding the way writing PHY port using C22
- * @phy_read_c45: Holding the way reading PHY port using C45
- * @phy_write_c45: Holding the way writing PHY port using C45
-- * @phy_mode_supported: Check if the PHY type is being supported on a certain
-- * port
-- * @mac_port_validate: Holding the way to set addition validate type for a
-- * certan MAC port
-+ * @mac_port_get_caps: Holding the handler that provides MAC capabilities
- * @mac_port_config: Holding the way setting up the PHY attribute to a
- * certain MAC port
- */
-@@ -770,9 +769,6 @@ struct mt753x_info {
- int regnum, u16 val);
- void (*mac_port_get_caps)(struct dsa_switch *ds, int port,
- struct phylink_config *config);
-- void (*mac_port_validate)(struct dsa_switch *ds, int port,
-- phy_interface_t interface,
-- unsigned long *supported);
- void (*mac_port_config)(struct dsa_switch *ds, int port,
- unsigned int mode,
- phy_interface_t interface);
+++ /dev/null
-From 6efc8ae3eb0363328f479191a0cf0dc12a16e090 Mon Sep 17 00:00:00 2001
-Date: Mon, 22 Apr 2024 10:15:20 +0300
-Subject: [PATCH 13/15] net: dsa: mt7530: use priv->ds->num_ports instead of
- MT7530_NUM_PORTS
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Use priv->ds->num_ports on all for loops which configure the switch
-registers. In the future, the value of MT7530_NUM_PORTS will depend on
-priv->id. Therefore, this change prepares the subdriver for a simpler
-implementation.
-
----
- drivers/net/dsa/mt7530.c | 8 ++++----
- 1 file changed, 4 insertions(+), 4 deletions(-)
-
---- a/drivers/net/dsa/mt7530.c
-+++ b/drivers/net/dsa/mt7530.c
-@@ -1411,7 +1411,7 @@ mt7530_port_set_vlan_unaware(struct dsa_
- mt7530_rmw(priv, MT7530_PPBV1_P(port), G0_PORT_VID_MASK,
- G0_PORT_VID_DEF);
-
-- for (i = 0; i < MT7530_NUM_PORTS; i++) {
-+ for (i = 0; i < priv->ds->num_ports; i++) {
- if (dsa_is_user_port(ds, i) &&
- dsa_port_is_vlan_filtering(dsa_to_port(ds, i))) {
- all_user_ports_removed = false;
-@@ -2428,7 +2428,7 @@ mt7530_setup(struct dsa_switch *ds)
- /* Enable and reset MIB counters */
- mt7530_mib_reset(ds);
-
-- for (i = 0; i < MT7530_NUM_PORTS; i++) {
-+ for (i = 0; i < priv->ds->num_ports; i++) {
- /* Clear link settings and enable force mode to force link down
- * on all ports until they're enabled later.
- */
-@@ -2542,7 +2542,7 @@ mt7531_setup_common(struct dsa_switch *d
- mt7530_clear(priv, MT753X_MFC, BC_FFP_MASK | UNM_FFP_MASK |
- UNU_FFP_MASK);
-
-- for (i = 0; i < MT7530_NUM_PORTS; i++) {
-+ for (i = 0; i < priv->ds->num_ports; i++) {
- /* Clear link settings and enable force mode to force link down
- * on all ports until they're enabled later.
- */
-@@ -2630,7 +2630,7 @@ mt7531_setup(struct dsa_switch *ds)
- priv->p5_sgmii = !!(val & PAD_DUAL_SGMII_EN);
-
- /* Force link down on all ports before internal reset */
-- for (i = 0; i < MT7530_NUM_PORTS; i++)
-+ for (i = 0; i < priv->ds->num_ports; i++)
- mt7530_write(priv, MT753X_PMCR_P(i), MT7531_FORCE_MODE_LNK);
-
- /* Reset the switch through internal reset */
+++ /dev/null
-From c078ebbf5f6f6d8390035a9f92eeab766b78884d Mon Sep 17 00:00:00 2001
-Date: Mon, 22 Apr 2024 10:15:21 +0300
-Subject: [PATCH 14/15] net: dsa: mt7530: do not pass port variable to
- mt7531_rgmii_setup()
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-The mt7531_rgmii_setup() function does not use the port variable, do not
-pass the variable to it.
-
----
- drivers/net/dsa/mt7530.c | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
---- a/drivers/net/dsa/mt7530.c
-+++ b/drivers/net/dsa/mt7530.c
-@@ -2781,7 +2781,7 @@ mt7530_mac_config(struct dsa_switch *ds,
- mt7530_setup_port6(priv->ds, interface);
- }
-
--static void mt7531_rgmii_setup(struct mt7530_priv *priv, u32 port,
-+static void mt7531_rgmii_setup(struct mt7530_priv *priv,
- phy_interface_t interface,
- struct phy_device *phydev)
- {
-@@ -2832,7 +2832,7 @@ mt7531_mac_config(struct dsa_switch *ds,
- if (phy_interface_mode_is_rgmii(interface)) {
- dp = dsa_to_port(ds, port);
- phydev = dp->slave->phydev;
-- mt7531_rgmii_setup(priv, port, interface, phydev);
-+ mt7531_rgmii_setup(priv, interface, phydev);
- }
- }
-
+++ /dev/null
-From e7a9cc3cc00b40e0bc2bae40bd2ece0e48fa51d5 Mon Sep 17 00:00:00 2001
-Date: Mon, 22 Apr 2024 10:15:22 +0300
-Subject: [PATCH 15/15] net: dsa: mt7530: explain exposing MDIO bus of MT7531AE
- better
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Unlike MT7531BE, the GPIO 6-12 pins are not used for RGMII on MT7531AE.
-Therefore, the GPIO 11-12 pins are set to function as MDC and MDIO to
-expose the MDIO bus of the switch. Replace the comment with a better
-explanation.
-
----
- drivers/net/dsa/mt7530.c | 5 ++++-
- 1 file changed, 4 insertions(+), 1 deletion(-)
-
---- a/drivers/net/dsa/mt7530.c
-+++ b/drivers/net/dsa/mt7530.c
-@@ -2639,7 +2639,10 @@ mt7531_setup(struct dsa_switch *ds)
- if (!priv->p5_sgmii) {
- mt7531_pll_setup(priv);
- } else {
-- /* Let ds->slave_mii_bus be able to access external phy. */
-+ /* Unlike MT7531BE, the GPIO 6-12 pins are not used for RGMII on
-+ * MT7531AE. Set the GPIO 11-12 pins to function as MDC and MDIO
-+ * to expose the MDIO bus of the switch.
-+ */
- mt7530_rmw(priv, MT7531_GPIO_MODE1, MT7531_GPIO11_RG_RXD2_MASK,
- MT7531_EXT_P_MDC_11);
- mt7530_rmw(priv, MT7531_GPIO_MODE1, MT7531_GPIO12_RG_RXD3_MASK,
+++ /dev/null
-From 16e6592cd5c5bd74d8890973489f60176c692614 Mon Sep 17 00:00:00 2001
-Date: Sun, 28 Apr 2024 12:19:58 +0300
-Subject: [PATCH] net: dsa: mt7530: do not set MT7530_P5_DIS when PHY muxing is
- being used
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-DSA initalises the ds->num_ports amount of ports in
-dsa_switch_touch_ports(). When the PHY muxing feature is in use, port 5
-won't be defined in the device tree. Because of this, the type member of
-the dsa_port structure for this port will be assigned DSA_PORT_TYPE_UNUSED.
-The dsa_port_setup() function calls ds->ops->port_disable() when the port
-type is DSA_PORT_TYPE_UNUSED.
-
-The MT7530_P5_DIS bit is unset in mt7530_setup() when PHY muxing is being
-used. mt7530_port_disable() which is assigned to ds->ops->port_disable() is
-called afterwards. Currently, mt7530_port_disable() sets MT7530_P5_DIS
-which breaks network connectivity when PHY muxing is being used.
-
-Therefore, do not set MT7530_P5_DIS when PHY muxing is being used.
-
-Fixes: 377174c5760c ("net: dsa: mt7530: move MT753X_MTRAP operations for MT7530")
-Link: https://lore.kernel.org/r/20240428-for-netnext-mt7530-do-not-disable-port5-when-phy-muxing-v2-1-bb7c37d293f8@arinc9.com
----
- drivers/net/dsa/mt7530.c | 3 ++-
- 1 file changed, 2 insertions(+), 1 deletion(-)
-
---- a/drivers/net/dsa/mt7530.c
-+++ b/drivers/net/dsa/mt7530.c
-@@ -1220,7 +1220,8 @@ mt7530_port_disable(struct dsa_switch *d
- if (priv->id != ID_MT7530 && priv->id != ID_MT7621)
- return;
-
-- if (port == 5)
-+ /* Do not set MT7530_P5_DIS when port 5 is being used for PHY muxing. */
-+ if (port == 5 && priv->p5_mode == GMAC5)
- mt7530_set(priv, MT753X_MTRAP, MT7530_P5_DIS);
- else if (port == 6)
- mt7530_set(priv, MT753X_MTRAP, MT7530_P6_DIS);
+++ /dev/null
-From d8dcf5bd6d0eace9f7c1daa14b63b3925b09d033 Mon Sep 17 00:00:00 2001
-Date: Tue, 30 Apr 2024 08:01:33 +0300
-Subject: [PATCH] net: dsa: mt7530: detect PHY muxing when PHY is defined on
- switch MDIO bus
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Currently, the MT7530 DSA subdriver configures the MT7530 switch to provide
-direct access to switch PHYs, meaning, the switch PHYs listen on the MDIO
-bus the switch listens on. The PHY muxing feature makes use of this.
-
-This is problematic as the PHY may be attached before the switch is
-initialised, in which case, the PHY will fail to be attached.
-
-Since commit 91374ba537bd ("net: dsa: mt7530: support OF-based registration
-of switch MDIO bus"), we can describe the switch PHYs on the MDIO bus of
-the switch on the device tree. Extend the check to detect PHY muxing when
-the PHY is defined on the MDIO bus of the switch on the device tree.
-
-When the PHY is described this way, the switch will be initialised first,
-then the switch MDIO bus will be registered. Only after these steps, the
-PHY will be attached.
-
-Link: https://lore.kernel.org/r/20240430-b4-for-netnext-mt7530-use-switch-mdio-bus-for-phy-muxing-v2-1-9104d886d0db@arinc9.com
----
- drivers/net/dsa/mt7530.c | 3 ++-
- 1 file changed, 2 insertions(+), 1 deletion(-)
-
---- a/drivers/net/dsa/mt7530.c
-+++ b/drivers/net/dsa/mt7530.c
-@@ -2484,7 +2484,8 @@ mt7530_setup(struct dsa_switch *ds)
- if (!phy_node)
- continue;
-
-- if (phy_node->parent == priv->dev->of_node->parent) {
-+ if (phy_node->parent == priv->dev->of_node->parent ||
-+ phy_node->parent->parent == priv->dev->of_node) {
- ret = of_get_phy_mode(mac_np, &interface);
- if (ret && ret != -ENODEV) {
- of_node_put(mac_np);
+++ /dev/null
-From c25c961fc7f36682f0a530150f1b7453ebc344cd Mon Sep 17 00:00:00 2001
-Date: Tue, 18 Jun 2024 09:17:12 +0200
-Subject: [PATCH 1/2] net: dsa: mt7530: factor out bridge join/leave logic
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-As preparation for implementing bridge port isolation, move the logic to
-add and remove bits in the port matrix into a new helper
-mt7530_update_port_member(), which is called from
-mt7530_port_bridge_join() and mt7530_port_bridge_leave().
-
-Another part of the preparation is using dsa_port_offloads_bridge_dev()
-instead of dsa_port_offloads_bridge() to check for bridge membership, as
-we don't have a struct dsa_bridge in mt7530_port_bridge_flags().
-
-The port matrix setting is slightly streamlined, now always first setting
-the mt7530_port's pm field and then writing the port matrix from that
-field into the hardware register, instead of duplicating the bit
-manipulation for both the struct field and the register.
-
-mt7530_port_bridge_join() was previously using |= to update the port
-matrix with the port bitmap, which was unnecessary, as pm would only
-have the CPU port set before joining a bridge; a simple assignment can
-be used for both joining and leaving (and will also work when individual
-bits are added/removed in port_bitmap with regard to the previous port
-matrix, which is what happens with port isolation).
-
-No functional change intended.
-
----
- drivers/net/dsa/mt7530.c | 105 ++++++++++++++++++---------------------
- 1 file changed, 48 insertions(+), 57 deletions(-)
-
---- a/drivers/net/dsa/mt7530.c
-+++ b/drivers/net/dsa/mt7530.c
-@@ -1302,6 +1302,52 @@ mt7530_stp_state_set(struct dsa_switch *
- FID_PST(FID_BRIDGED, stp_state));
- }
-
-+static void mt7530_update_port_member(struct mt7530_priv *priv, int port,
-+ const struct net_device *bridge_dev,
-+ bool join) __must_hold(&priv->reg_mutex)
-+{
-+ struct dsa_port *dp = dsa_to_port(priv->ds, port), *other_dp;
-+ struct mt7530_port *p = &priv->ports[port], *other_p;
-+ struct dsa_port *cpu_dp = dp->cpu_dp;
-+ u32 port_bitmap = BIT(cpu_dp->index);
-+ int other_port;
-+
-+ dsa_switch_for_each_user_port(other_dp, priv->ds) {
-+ other_port = other_dp->index;
-+ other_p = &priv->ports[other_port];
-+
-+ if (dp == other_dp)
-+ continue;
-+
-+ /* Add/remove this port to/from the port matrix of the other
-+ * ports in the same bridge. If the port is disabled, port
-+ * matrix is kept and not being setup until the port becomes
-+ * enabled.
-+ */
-+ if (!dsa_port_offloads_bridge_dev(other_dp, bridge_dev))
-+ continue;
-+
-+ if (join) {
-+ other_p->pm |= PCR_MATRIX(BIT(port));
-+ port_bitmap |= BIT(other_port);
-+ } else {
-+ other_p->pm &= ~PCR_MATRIX(BIT(port));
-+ }
-+
-+ if (other_p->enable)
-+ mt7530_rmw(priv, MT7530_PCR_P(other_port),
-+ PCR_MATRIX_MASK, other_p->pm);
-+ }
-+
-+ /* Add/remove the all other ports to this port matrix. For !join
-+ * (leaving the bridge), only the CPU port will remain in the port matrix
-+ * of this port.
-+ */
-+ p->pm = PCR_MATRIX(port_bitmap);
-+ if (priv->ports[port].enable)
-+ mt7530_rmw(priv, MT7530_PCR_P(port), PCR_MATRIX_MASK, p->pm);
-+}
-+
- static int
- mt7530_port_pre_bridge_flags(struct dsa_switch *ds, int port,
- struct switchdev_brport_flags flags,
-@@ -1345,39 +1391,11 @@ mt7530_port_bridge_join(struct dsa_switc
- struct dsa_bridge bridge, bool *tx_fwd_offload,
- struct netlink_ext_ack *extack)
- {
-- struct dsa_port *dp = dsa_to_port(ds, port), *other_dp;
-- struct dsa_port *cpu_dp = dp->cpu_dp;
-- u32 port_bitmap = BIT(cpu_dp->index);
- struct mt7530_priv *priv = ds->priv;
-
- mutex_lock(&priv->reg_mutex);
-
-- dsa_switch_for_each_user_port(other_dp, ds) {
-- int other_port = other_dp->index;
--
-- if (dp == other_dp)
-- continue;
--
-- /* Add this port to the port matrix of the other ports in the
-- * same bridge. If the port is disabled, port matrix is kept
-- * and not being setup until the port becomes enabled.
-- */
-- if (!dsa_port_offloads_bridge(other_dp, &bridge))
-- continue;
--
-- if (priv->ports[other_port].enable)
-- mt7530_set(priv, MT7530_PCR_P(other_port),
-- PCR_MATRIX(BIT(port)));
-- priv->ports[other_port].pm |= PCR_MATRIX(BIT(port));
--
-- port_bitmap |= BIT(other_port);
-- }
--
-- /* Add the all other ports to this port matrix. */
-- if (priv->ports[port].enable)
-- mt7530_rmw(priv, MT7530_PCR_P(port),
-- PCR_MATRIX_MASK, PCR_MATRIX(port_bitmap));
-- priv->ports[port].pm |= PCR_MATRIX(port_bitmap);
-+ mt7530_update_port_member(priv, port, bridge.dev, true);
-
- /* Set to fallback mode for independent VLAN learning */
- mt7530_rmw(priv, MT7530_PCR_P(port), PCR_PORT_VLAN_MASK,
-@@ -1478,38 +1496,11 @@ static void
- mt7530_port_bridge_leave(struct dsa_switch *ds, int port,
- struct dsa_bridge bridge)
- {
-- struct dsa_port *dp = dsa_to_port(ds, port), *other_dp;
-- struct dsa_port *cpu_dp = dp->cpu_dp;
- struct mt7530_priv *priv = ds->priv;
-
- mutex_lock(&priv->reg_mutex);
-
-- dsa_switch_for_each_user_port(other_dp, ds) {
-- int other_port = other_dp->index;
--
-- if (dp == other_dp)
-- continue;
--
-- /* Remove this port from the port matrix of the other ports
-- * in the same bridge. If the port is disabled, port matrix
-- * is kept and not being setup until the port becomes enabled.
-- */
-- if (!dsa_port_offloads_bridge(other_dp, &bridge))
-- continue;
--
-- if (priv->ports[other_port].enable)
-- mt7530_clear(priv, MT7530_PCR_P(other_port),
-- PCR_MATRIX(BIT(port)));
-- priv->ports[other_port].pm &= ~PCR_MATRIX(BIT(port));
-- }
--
-- /* Set the cpu port to be the only one in the port matrix of
-- * this port.
-- */
-- if (priv->ports[port].enable)
-- mt7530_rmw(priv, MT7530_PCR_P(port), PCR_MATRIX_MASK,
-- PCR_MATRIX(BIT(cpu_dp->index)));
-- priv->ports[port].pm = PCR_MATRIX(BIT(cpu_dp->index));
-+ mt7530_update_port_member(priv, port, bridge.dev, false);
-
- /* When a port is removed from the bridge, the port would be set up
- * back to the default as is at initial boot which is a VLAN-unaware
+++ /dev/null
-From 3d49ee2127c26fd2c77944fd2e3168c057f99439 Mon Sep 17 00:00:00 2001
-Date: Tue, 18 Jun 2024 09:17:13 +0200
-Subject: [PATCH 2/2] net: dsa: mt7530: add support for bridge port isolation
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Remove a pair of ports from the port matrix when both ports have the
-isolated flag set.
-
----
- drivers/net/dsa/mt7530.c | 18 ++++++++++++++++--
- drivers/net/dsa/mt7530.h | 1 +
- 2 files changed, 17 insertions(+), 2 deletions(-)
-
---- a/drivers/net/dsa/mt7530.c
-+++ b/drivers/net/dsa/mt7530.c
-@@ -1311,6 +1311,7 @@ static void mt7530_update_port_member(st
- struct dsa_port *cpu_dp = dp->cpu_dp;
- u32 port_bitmap = BIT(cpu_dp->index);
- int other_port;
-+ bool isolated;
-
- dsa_switch_for_each_user_port(other_dp, priv->ds) {
- other_port = other_dp->index;
-@@ -1327,7 +1328,9 @@ static void mt7530_update_port_member(st
- if (!dsa_port_offloads_bridge_dev(other_dp, bridge_dev))
- continue;
-
-- if (join) {
-+ isolated = p->isolated && other_p->isolated;
-+
-+ if (join && !isolated) {
- other_p->pm |= PCR_MATRIX(BIT(port));
- port_bitmap |= BIT(other_port);
- } else {
-@@ -1354,7 +1357,7 @@ mt7530_port_pre_bridge_flags(struct dsa_
- struct netlink_ext_ack *extack)
- {
- if (flags.mask & ~(BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD |
-- BR_BCAST_FLOOD))
-+ BR_BCAST_FLOOD | BR_ISOLATED))
- return -EINVAL;
-
- return 0;
-@@ -1383,6 +1386,17 @@ mt7530_port_bridge_flags(struct dsa_swit
- mt7530_rmw(priv, MT753X_MFC, BC_FFP(BIT(port)),
- flags.val & BR_BCAST_FLOOD ? BC_FFP(BIT(port)) : 0);
-
-+ if (flags.mask & BR_ISOLATED) {
-+ struct dsa_port *dp = dsa_to_port(ds, port);
-+ struct net_device *bridge_dev = dsa_port_bridge_dev_get(dp);
-+
-+ priv->ports[port].isolated = !!(flags.val & BR_ISOLATED);
-+
-+ mutex_lock(&priv->reg_mutex);
-+ mt7530_update_port_member(priv, port, bridge_dev, true);
-+ mutex_unlock(&priv->reg_mutex);
-+ }
-+
- return 0;
- }
-
---- a/drivers/net/dsa/mt7530.h
-+++ b/drivers/net/dsa/mt7530.h
-@@ -721,6 +721,7 @@ struct mt7530_fdb {
- */
- struct mt7530_port {
- bool enable;
-+ bool isolated;
- u32 pm;
- u16 pvid;
- struct phylink_pcs *sgmii_pcs;
+++ /dev/null
-From c11d5dbbe73fa7b450aaa77bb18df86a9714b422 Mon Sep 17 00:00:00 2001
-Date: Sat, 1 Jun 2024 01:35:02 +0200
-Subject: [PATCH 1/2] net: phy: aquantia: move priv and hw stat to header
-
-In preparation for LEDs support, move priv and hw stat to header to
-reference priv struct also in other .c outside aquantia.main
-
----
- drivers/net/phy/aquantia/aquantia.h | 38 ++++++++++++++++++++++++
- drivers/net/phy/aquantia/aquantia_main.c | 37 -----------------------
- 2 files changed, 38 insertions(+), 37 deletions(-)
-
---- a/drivers/net/phy/aquantia/aquantia.h
-+++ b/drivers/net/phy/aquantia/aquantia.h
-@@ -82,6 +82,18 @@
- #define VEND1_GLOBAL_RSVD_STAT9_MODE GENMASK(7, 0)
- #define VEND1_GLOBAL_RSVD_STAT9_1000BT2 0x23
-
-+/* MDIO_MMD_C22EXT */
-+#define MDIO_C22EXT_STAT_SGMII_RX_GOOD_FRAMES 0xd292
-+#define MDIO_C22EXT_STAT_SGMII_RX_BAD_FRAMES 0xd294
-+#define MDIO_C22EXT_STAT_SGMII_RX_FALSE_CARRIER 0xd297
-+#define MDIO_C22EXT_STAT_SGMII_TX_GOOD_FRAMES 0xd313
-+#define MDIO_C22EXT_STAT_SGMII_TX_BAD_FRAMES 0xd315
-+#define MDIO_C22EXT_STAT_SGMII_TX_FALSE_CARRIER 0xd317
-+#define MDIO_C22EXT_STAT_SGMII_TX_COLLISIONS 0xd318
-+#define MDIO_C22EXT_STAT_SGMII_TX_LINE_COLLISIONS 0xd319
-+#define MDIO_C22EXT_STAT_SGMII_TX_FRAME_ALIGN_ERR 0xd31a
-+#define MDIO_C22EXT_STAT_SGMII_TX_RUNT_FRAMES 0xd31b
-+
- #define VEND1_GLOBAL_INT_STD_STATUS 0xfc00
- #define VEND1_GLOBAL_INT_VEND_STATUS 0xfc01
-
-@@ -108,6 +120,32 @@
- #define VEND1_GLOBAL_INT_VEND_MASK_GLOBAL2 BIT(1)
- #define VEND1_GLOBAL_INT_VEND_MASK_GLOBAL3 BIT(0)
-
-+struct aqr107_hw_stat {
-+ const char *name;
-+ int reg;
-+ int size;
-+};
-+
-+#define SGMII_STAT(n, r, s) { n, MDIO_C22EXT_STAT_SGMII_ ## r, s }
-+static const struct aqr107_hw_stat aqr107_hw_stats[] = {
-+ SGMII_STAT("sgmii_rx_good_frames", RX_GOOD_FRAMES, 26),
-+ SGMII_STAT("sgmii_rx_bad_frames", RX_BAD_FRAMES, 26),
-+ SGMII_STAT("sgmii_rx_false_carrier_events", RX_FALSE_CARRIER, 8),
-+ SGMII_STAT("sgmii_tx_good_frames", TX_GOOD_FRAMES, 26),
-+ SGMII_STAT("sgmii_tx_bad_frames", TX_BAD_FRAMES, 26),
-+ SGMII_STAT("sgmii_tx_false_carrier_events", TX_FALSE_CARRIER, 8),
-+ SGMII_STAT("sgmii_tx_collisions", TX_COLLISIONS, 8),
-+ SGMII_STAT("sgmii_tx_line_collisions", TX_LINE_COLLISIONS, 8),
-+ SGMII_STAT("sgmii_tx_frame_alignment_err", TX_FRAME_ALIGN_ERR, 16),
-+ SGMII_STAT("sgmii_tx_runt_frames", TX_RUNT_FRAMES, 22),
-+};
-+
-+#define AQR107_SGMII_STAT_SZ ARRAY_SIZE(aqr107_hw_stats)
-+
-+struct aqr107_priv {
-+ u64 sgmii_stats[AQR107_SGMII_STAT_SZ];
-+};
-+
- #if IS_REACHABLE(CONFIG_HWMON)
- int aqr_hwmon_probe(struct phy_device *phydev);
- #else
---- a/drivers/net/phy/aquantia/aquantia_main.c
-+++ b/drivers/net/phy/aquantia/aquantia_main.c
-@@ -84,49 +84,12 @@
- #define MDIO_AN_RX_VEND_STAT3 0xe832
- #define MDIO_AN_RX_VEND_STAT3_AFR BIT(0)
-
--/* MDIO_MMD_C22EXT */
--#define MDIO_C22EXT_STAT_SGMII_RX_GOOD_FRAMES 0xd292
--#define MDIO_C22EXT_STAT_SGMII_RX_BAD_FRAMES 0xd294
--#define MDIO_C22EXT_STAT_SGMII_RX_FALSE_CARRIER 0xd297
--#define MDIO_C22EXT_STAT_SGMII_TX_GOOD_FRAMES 0xd313
--#define MDIO_C22EXT_STAT_SGMII_TX_BAD_FRAMES 0xd315
--#define MDIO_C22EXT_STAT_SGMII_TX_FALSE_CARRIER 0xd317
--#define MDIO_C22EXT_STAT_SGMII_TX_COLLISIONS 0xd318
--#define MDIO_C22EXT_STAT_SGMII_TX_LINE_COLLISIONS 0xd319
--#define MDIO_C22EXT_STAT_SGMII_TX_FRAME_ALIGN_ERR 0xd31a
--#define MDIO_C22EXT_STAT_SGMII_TX_RUNT_FRAMES 0xd31b
--
- /* Sleep and timeout for checking if the Processor-Intensive
- * MDIO operation is finished
- */
- #define AQR107_OP_IN_PROG_SLEEP 1000
- #define AQR107_OP_IN_PROG_TIMEOUT 100000
-
--struct aqr107_hw_stat {
-- const char *name;
-- int reg;
-- int size;
--};
--
--#define SGMII_STAT(n, r, s) { n, MDIO_C22EXT_STAT_SGMII_ ## r, s }
--static const struct aqr107_hw_stat aqr107_hw_stats[] = {
-- SGMII_STAT("sgmii_rx_good_frames", RX_GOOD_FRAMES, 26),
-- SGMII_STAT("sgmii_rx_bad_frames", RX_BAD_FRAMES, 26),
-- SGMII_STAT("sgmii_rx_false_carrier_events", RX_FALSE_CARRIER, 8),
-- SGMII_STAT("sgmii_tx_good_frames", TX_GOOD_FRAMES, 26),
-- SGMII_STAT("sgmii_tx_bad_frames", TX_BAD_FRAMES, 26),
-- SGMII_STAT("sgmii_tx_false_carrier_events", TX_FALSE_CARRIER, 8),
-- SGMII_STAT("sgmii_tx_collisions", TX_COLLISIONS, 8),
-- SGMII_STAT("sgmii_tx_line_collisions", TX_LINE_COLLISIONS, 8),
-- SGMII_STAT("sgmii_tx_frame_alignment_err", TX_FRAME_ALIGN_ERR, 16),
-- SGMII_STAT("sgmii_tx_runt_frames", TX_RUNT_FRAMES, 22),
--};
--#define AQR107_SGMII_STAT_SZ ARRAY_SIZE(aqr107_hw_stats)
--
--struct aqr107_priv {
-- u64 sgmii_stats[AQR107_SGMII_STAT_SZ];
--};
--
- static int aqr107_get_sset_count(struct phy_device *phydev)
- {
- return AQR107_SGMII_STAT_SZ;
+++ /dev/null
-From 61578f67937881abf54c8bd258eb913312dbe4c1 Mon Sep 17 00:00:00 2001
-Date: Sat, 1 Jun 2024 01:35:03 +0200
-Subject: [PATCH 2/2] net: phy: aquantia: add support for PHY LEDs
-
-Aquantia Ethernet PHYs got 3 LED output pins which are typically used
-to indicate link status and activity.
-Add a minimal LED controller driver supporting the most common uses
-with the 'netdev' trigger as well as software-driven forced control of
-the LEDs.
-
-[ rework indentation, fix checkpatch error and improve some functions ]
----
- drivers/net/phy/aquantia/Makefile | 2 +-
- drivers/net/phy/aquantia/aquantia.h | 40 ++++++
- drivers/net/phy/aquantia/aquantia_leds.c | 150 +++++++++++++++++++++++
- drivers/net/phy/aquantia/aquantia_main.c | 63 +++++++++-
- 4 files changed, 252 insertions(+), 3 deletions(-)
- create mode 100644 drivers/net/phy/aquantia/aquantia_leds.c
-
---- a/drivers/net/phy/aquantia/Makefile
-+++ b/drivers/net/phy/aquantia/Makefile
-@@ -1,5 +1,5 @@
- # SPDX-License-Identifier: GPL-2.0
--aquantia-objs += aquantia_main.o aquantia_firmware.o
-+aquantia-objs += aquantia_main.o aquantia_firmware.o aquantia_leds.o
- ifdef CONFIG_HWMON
- aquantia-objs += aquantia_hwmon.o
- endif
---- a/drivers/net/phy/aquantia/aquantia.h
-+++ b/drivers/net/phy/aquantia/aquantia.h
-@@ -58,6 +58,28 @@
- #define VEND1_GLOBAL_CONTROL2_UP_RUN_STALL_OVD BIT(6)
- #define VEND1_GLOBAL_CONTROL2_UP_RUN_STALL BIT(0)
-
-+#define VEND1_GLOBAL_LED_PROV 0xc430
-+#define AQR_LED_PROV(x) (VEND1_GLOBAL_LED_PROV + (x))
-+#define VEND1_GLOBAL_LED_PROV_LINK2500 BIT(14)
-+#define VEND1_GLOBAL_LED_PROV_LINK5000 BIT(15)
-+#define VEND1_GLOBAL_LED_PROV_FORCE_ON BIT(8)
-+#define VEND1_GLOBAL_LED_PROV_LINK10000 BIT(7)
-+#define VEND1_GLOBAL_LED_PROV_LINK1000 BIT(6)
-+#define VEND1_GLOBAL_LED_PROV_LINK100 BIT(5)
-+#define VEND1_GLOBAL_LED_PROV_RX_ACT BIT(3)
-+#define VEND1_GLOBAL_LED_PROV_TX_ACT BIT(2)
-+#define VEND1_GLOBAL_LED_PROV_ACT_STRETCH GENMASK(0, 1)
-+
-+#define VEND1_GLOBAL_LED_PROV_LINK_MASK (VEND1_GLOBAL_LED_PROV_LINK100 | \
-+ VEND1_GLOBAL_LED_PROV_LINK1000 | \
-+ VEND1_GLOBAL_LED_PROV_LINK10000 | \
-+ VEND1_GLOBAL_LED_PROV_LINK5000 | \
-+ VEND1_GLOBAL_LED_PROV_LINK2500)
-+
-+#define VEND1_GLOBAL_LED_DRIVE 0xc438
-+#define VEND1_GLOBAL_LED_DRIVE_VDD BIT(1)
-+#define AQR_LED_DRIVE(x) (VEND1_GLOBAL_LED_DRIVE + (x))
-+
- #define VEND1_THERMAL_PROV_HIGH_TEMP_FAIL 0xc421
- #define VEND1_THERMAL_PROV_LOW_TEMP_FAIL 0xc422
- #define VEND1_THERMAL_PROV_HIGH_TEMP_WARN 0xc423
-@@ -120,6 +142,8 @@
- #define VEND1_GLOBAL_INT_VEND_MASK_GLOBAL2 BIT(1)
- #define VEND1_GLOBAL_INT_VEND_MASK_GLOBAL3 BIT(0)
-
-+#define AQR_MAX_LEDS 3
-+
- struct aqr107_hw_stat {
- const char *name;
- int reg;
-@@ -144,6 +168,7 @@ static const struct aqr107_hw_stat aqr10
-
- struct aqr107_priv {
- u64 sgmii_stats[AQR107_SGMII_STAT_SZ];
-+ unsigned long leds_active_low;
- };
-
- #if IS_REACHABLE(CONFIG_HWMON)
-@@ -153,3 +178,18 @@ static inline int aqr_hwmon_probe(struct
- #endif
-
- int aqr_firmware_load(struct phy_device *phydev);
-+
-+int aqr_phy_led_blink_set(struct phy_device *phydev, u8 index,
-+ unsigned long *delay_on,
-+ unsigned long *delay_off);
-+int aqr_phy_led_brightness_set(struct phy_device *phydev,
-+ u8 index, enum led_brightness value);
-+int aqr_phy_led_hw_is_supported(struct phy_device *phydev, u8 index,
-+ unsigned long rules);
-+int aqr_phy_led_hw_control_get(struct phy_device *phydev, u8 index,
-+ unsigned long *rules);
-+int aqr_phy_led_hw_control_set(struct phy_device *phydev, u8 index,
-+ unsigned long rules);
-+int aqr_phy_led_active_low_set(struct phy_device *phydev, int index, bool enable);
-+int aqr_phy_led_polarity_set(struct phy_device *phydev, int index,
-+ unsigned long modes);
---- /dev/null
-+++ b/drivers/net/phy/aquantia/aquantia_leds.c
-@@ -0,0 +1,150 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/* LED driver for Aquantia PHY
-+ *
-+ */
-+
-+#include <linux/phy.h>
-+
-+#include "aquantia.h"
-+
-+int aqr_phy_led_brightness_set(struct phy_device *phydev,
-+ u8 index, enum led_brightness value)
-+{
-+ if (index >= AQR_MAX_LEDS)
-+ return -EINVAL;
-+
-+ return phy_modify_mmd(phydev, MDIO_MMD_VEND1, AQR_LED_PROV(index),
-+ VEND1_GLOBAL_LED_PROV_LINK_MASK |
-+ VEND1_GLOBAL_LED_PROV_FORCE_ON |
-+ VEND1_GLOBAL_LED_PROV_RX_ACT |
-+ VEND1_GLOBAL_LED_PROV_TX_ACT,
-+ value ? VEND1_GLOBAL_LED_PROV_FORCE_ON : 0);
-+}
-+
-+static const unsigned long supported_triggers = (BIT(TRIGGER_NETDEV_LINK) |
-+ BIT(TRIGGER_NETDEV_LINK_100) |
-+ BIT(TRIGGER_NETDEV_LINK_1000) |
-+ BIT(TRIGGER_NETDEV_LINK_2500) |
-+ BIT(TRIGGER_NETDEV_LINK_5000) |
-+ BIT(TRIGGER_NETDEV_LINK_10000) |
-+ BIT(TRIGGER_NETDEV_RX) |
-+ BIT(TRIGGER_NETDEV_TX));
-+
-+int aqr_phy_led_hw_is_supported(struct phy_device *phydev, u8 index,
-+ unsigned long rules)
-+{
-+ if (index >= AQR_MAX_LEDS)
-+ return -EINVAL;
-+
-+ /* All combinations of the supported triggers are allowed */
-+ if (rules & ~supported_triggers)
-+ return -EOPNOTSUPP;
-+
-+ return 0;
-+}
-+
-+int aqr_phy_led_hw_control_get(struct phy_device *phydev, u8 index,
-+ unsigned long *rules)
-+{
-+ int val;
-+
-+ if (index >= AQR_MAX_LEDS)
-+ return -EINVAL;
-+
-+ val = phy_read_mmd(phydev, MDIO_MMD_VEND1, AQR_LED_PROV(index));
-+ if (val < 0)
-+ return val;
-+
-+ *rules = 0;
-+ if (val & VEND1_GLOBAL_LED_PROV_LINK100)
-+ *rules |= BIT(TRIGGER_NETDEV_LINK_100);
-+
-+ if (val & VEND1_GLOBAL_LED_PROV_LINK1000)
-+ *rules |= BIT(TRIGGER_NETDEV_LINK_1000);
-+
-+ if (val & VEND1_GLOBAL_LED_PROV_LINK2500)
-+ *rules |= BIT(TRIGGER_NETDEV_LINK_2500);
-+
-+ if (val & VEND1_GLOBAL_LED_PROV_LINK5000)
-+ *rules |= BIT(TRIGGER_NETDEV_LINK_5000);
-+
-+ if (val & VEND1_GLOBAL_LED_PROV_LINK10000)
-+ *rules |= BIT(TRIGGER_NETDEV_LINK_10000);
-+
-+ if (val & VEND1_GLOBAL_LED_PROV_RX_ACT)
-+ *rules |= BIT(TRIGGER_NETDEV_RX);
-+
-+ if (val & VEND1_GLOBAL_LED_PROV_TX_ACT)
-+ *rules |= BIT(TRIGGER_NETDEV_TX);
-+
-+ return 0;
-+}
-+
-+int aqr_phy_led_hw_control_set(struct phy_device *phydev, u8 index,
-+ unsigned long rules)
-+{
-+ u16 val = 0;
-+
-+ if (index >= AQR_MAX_LEDS)
-+ return -EINVAL;
-+
-+ if (rules & (BIT(TRIGGER_NETDEV_LINK_100) | BIT(TRIGGER_NETDEV_LINK)))
-+ val |= VEND1_GLOBAL_LED_PROV_LINK100;
-+
-+ if (rules & (BIT(TRIGGER_NETDEV_LINK_1000) | BIT(TRIGGER_NETDEV_LINK)))
-+ val |= VEND1_GLOBAL_LED_PROV_LINK1000;
-+
-+ if (rules & (BIT(TRIGGER_NETDEV_LINK_2500) | BIT(TRIGGER_NETDEV_LINK)))
-+ val |= VEND1_GLOBAL_LED_PROV_LINK2500;
-+
-+ if (rules & (BIT(TRIGGER_NETDEV_LINK_5000) | BIT(TRIGGER_NETDEV_LINK)))
-+ val |= VEND1_GLOBAL_LED_PROV_LINK5000;
-+
-+ if (rules & (BIT(TRIGGER_NETDEV_LINK_10000) | BIT(TRIGGER_NETDEV_LINK)))
-+ val |= VEND1_GLOBAL_LED_PROV_LINK10000;
-+
-+ if (rules & BIT(TRIGGER_NETDEV_RX))
-+ val |= VEND1_GLOBAL_LED_PROV_RX_ACT;
-+
-+ if (rules & BIT(TRIGGER_NETDEV_TX))
-+ val |= VEND1_GLOBAL_LED_PROV_TX_ACT;
-+
-+ return phy_modify_mmd(phydev, MDIO_MMD_VEND1, AQR_LED_PROV(index),
-+ VEND1_GLOBAL_LED_PROV_LINK_MASK |
-+ VEND1_GLOBAL_LED_PROV_FORCE_ON |
-+ VEND1_GLOBAL_LED_PROV_RX_ACT |
-+ VEND1_GLOBAL_LED_PROV_TX_ACT, val);
-+}
-+
-+int aqr_phy_led_active_low_set(struct phy_device *phydev, int index, bool enable)
-+{
-+ return phy_modify_mmd(phydev, MDIO_MMD_VEND1, AQR_LED_DRIVE(index),
-+ VEND1_GLOBAL_LED_DRIVE_VDD, enable);
-+}
-+
-+int aqr_phy_led_polarity_set(struct phy_device *phydev, int index, unsigned long modes)
-+{
-+ struct aqr107_priv *priv = phydev->priv;
-+ bool active_low = false;
-+ u32 mode;
-+
-+ if (index >= AQR_MAX_LEDS)
-+ return -EINVAL;
-+
-+ for_each_set_bit(mode, &modes, __PHY_LED_MODES_NUM) {
-+ switch (mode) {
-+ case PHY_LED_ACTIVE_LOW:
-+ active_low = true;
-+ break;
-+ default:
-+ return -EINVAL;
-+ }
-+ }
-+
-+ /* Save LED driver vdd state to restore on SW reset */
-+ if (active_low)
-+ priv->leds_active_low |= BIT(index);
-+
-+ return aqr_phy_led_active_low_set(phydev, index, active_low);
-+}
---- a/drivers/net/phy/aquantia/aquantia_main.c
-+++ b/drivers/net/phy/aquantia/aquantia_main.c
-@@ -475,7 +475,9 @@ static void aqr107_chip_info(struct phy_
-
- static int aqr107_config_init(struct phy_device *phydev)
- {
-- int ret;
-+ struct aqr107_priv *priv = phydev->priv;
-+ u32 led_active_low;
-+ int ret, index = 0;
-
- /* Check that the PHY interface type is compatible */
- if (phydev->interface != PHY_INTERFACE_MODE_SGMII &&
-@@ -496,7 +498,19 @@ static int aqr107_config_init(struct phy
- if (!ret)
- aqr107_chip_info(phydev);
-
-- return aqr107_set_downshift(phydev, MDIO_AN_VEND_PROV_DOWNSHIFT_DFLT);
-+ ret = aqr107_set_downshift(phydev, MDIO_AN_VEND_PROV_DOWNSHIFT_DFLT);
-+ if (ret)
-+ return ret;
-+
-+ /* Restore LED polarity state after reset */
-+ for_each_set_bit(led_active_low, &priv->leds_active_low, AQR_MAX_LEDS) {
-+ ret = aqr_phy_led_active_low_set(phydev, index, led_active_low);
-+ if (ret)
-+ return ret;
-+ index++;
-+ }
-+
-+ return 0;
- }
-
- static int aqcs109_config_init(struct phy_device *phydev)
-@@ -703,6 +717,11 @@ static struct phy_driver aqr_driver[] =
- .get_strings = aqr107_get_strings,
- .get_stats = aqr107_get_stats,
- .link_change_notify = aqr107_link_change_notify,
-+ .led_brightness_set = aqr_phy_led_brightness_set,
-+ .led_hw_is_supported = aqr_phy_led_hw_is_supported,
-+ .led_hw_control_set = aqr_phy_led_hw_control_set,
-+ .led_hw_control_get = aqr_phy_led_hw_control_get,
-+ .led_polarity_set = aqr_phy_led_polarity_set,
- },
- {
- PHY_ID_MATCH_MODEL(PHY_ID_AQCS109),
-@@ -722,6 +741,11 @@ static struct phy_driver aqr_driver[] =
- .get_strings = aqr107_get_strings,
- .get_stats = aqr107_get_stats,
- .link_change_notify = aqr107_link_change_notify,
-+ .led_brightness_set = aqr_phy_led_brightness_set,
-+ .led_hw_is_supported = aqr_phy_led_hw_is_supported,
-+ .led_hw_control_set = aqr_phy_led_hw_control_set,
-+ .led_hw_control_get = aqr_phy_led_hw_control_get,
-+ .led_polarity_set = aqr_phy_led_polarity_set,
- },
- {
- PHY_ID_MATCH_MODEL(PHY_ID_AQR111),
-@@ -741,6 +765,11 @@ static struct phy_driver aqr_driver[] =
- .get_strings = aqr107_get_strings,
- .get_stats = aqr107_get_stats,
- .link_change_notify = aqr107_link_change_notify,
-+ .led_brightness_set = aqr_phy_led_brightness_set,
-+ .led_hw_is_supported = aqr_phy_led_hw_is_supported,
-+ .led_hw_control_set = aqr_phy_led_hw_control_set,
-+ .led_hw_control_get = aqr_phy_led_hw_control_get,
-+ .led_polarity_set = aqr_phy_led_polarity_set,
- },
- {
- PHY_ID_MATCH_MODEL(PHY_ID_AQR111B0),
-@@ -760,6 +789,11 @@ static struct phy_driver aqr_driver[] =
- .get_strings = aqr107_get_strings,
- .get_stats = aqr107_get_stats,
- .link_change_notify = aqr107_link_change_notify,
-+ .led_brightness_set = aqr_phy_led_brightness_set,
-+ .led_hw_is_supported = aqr_phy_led_hw_is_supported,
-+ .led_hw_control_set = aqr_phy_led_hw_control_set,
-+ .led_hw_control_get = aqr_phy_led_hw_control_get,
-+ .led_polarity_set = aqr_phy_led_polarity_set,
- },
- {
- PHY_ID_MATCH_MODEL(PHY_ID_AQR405),
-@@ -786,6 +820,11 @@ static struct phy_driver aqr_driver[] =
- .get_strings = aqr107_get_strings,
- .get_stats = aqr107_get_stats,
- .link_change_notify = aqr107_link_change_notify,
-+ .led_brightness_set = aqr_phy_led_brightness_set,
-+ .led_hw_is_supported = aqr_phy_led_hw_is_supported,
-+ .led_hw_control_set = aqr_phy_led_hw_control_set,
-+ .led_hw_control_get = aqr_phy_led_hw_control_get,
-+ .led_polarity_set = aqr_phy_led_polarity_set,
- },
- {
- PHY_ID_MATCH_MODEL(PHY_ID_AQR412),
-@@ -823,6 +862,11 @@ static struct phy_driver aqr_driver[] =
- .get_strings = aqr107_get_strings,
- .get_stats = aqr107_get_stats,
- .link_change_notify = aqr107_link_change_notify,
-+ .led_brightness_set = aqr_phy_led_brightness_set,
-+ .led_hw_is_supported = aqr_phy_led_hw_is_supported,
-+ .led_hw_control_set = aqr_phy_led_hw_control_set,
-+ .led_hw_control_get = aqr_phy_led_hw_control_get,
-+ .led_polarity_set = aqr_phy_led_polarity_set,
- },
- {
- PHY_ID_MATCH_MODEL(PHY_ID_AQR113C),
-@@ -842,6 +886,11 @@ static struct phy_driver aqr_driver[] =
- .get_strings = aqr107_get_strings,
- .get_stats = aqr107_get_stats,
- .link_change_notify = aqr107_link_change_notify,
-+ .led_brightness_set = aqr_phy_led_brightness_set,
-+ .led_hw_is_supported = aqr_phy_led_hw_is_supported,
-+ .led_hw_control_set = aqr_phy_led_hw_control_set,
-+ .led_hw_control_get = aqr_phy_led_hw_control_get,
-+ .led_polarity_set = aqr_phy_led_polarity_set,
- },
- {
- PHY_ID_MATCH_MODEL(PHY_ID_AQR114C),
-@@ -861,6 +910,11 @@ static struct phy_driver aqr_driver[] =
- .get_strings = aqr107_get_strings,
- .get_stats = aqr107_get_stats,
- .link_change_notify = aqr107_link_change_notify,
-+ .led_brightness_set = aqr_phy_led_brightness_set,
-+ .led_hw_is_supported = aqr_phy_led_hw_is_supported,
-+ .led_hw_control_set = aqr_phy_led_hw_control_set,
-+ .led_hw_control_get = aqr_phy_led_hw_control_get,
-+ .led_polarity_set = aqr_phy_led_polarity_set,
- },
- {
- PHY_ID_MATCH_MODEL(PHY_ID_AQR813),
-@@ -880,6 +934,11 @@ static struct phy_driver aqr_driver[] =
- .get_strings = aqr107_get_strings,
- .get_stats = aqr107_get_stats,
- .link_change_notify = aqr107_link_change_notify,
-+ .led_brightness_set = aqr_phy_led_brightness_set,
-+ .led_hw_is_supported = aqr_phy_led_hw_is_supported,
-+ .led_hw_control_set = aqr_phy_led_hw_control_set,
-+ .led_hw_control_get = aqr_phy_led_hw_control_get,
-+ .led_polarity_set = aqr_phy_led_polarity_set,
- },
- };
-
+++ /dev/null
-From 8cae5a0d91fea01d90ce7c1827e26934a22ca2fa Mon Sep 17 00:00:00 2001
-Date: Wed, 5 Mar 2025 11:53:56 +0000
-Subject: [PATCH] igc: enable HW vlan tag insertion/stripping by default
-
-This is enabled by default in other Intel drivers I've checked (e1000, e1000e,
-iavf, igb and ice). Fixes an out-of-the-box performance issue when running
-OpenWrt on typical mini-PCs with igc-supported Ethernet controllers and 802.1Q
-VLAN configurations, as ethtool isn't part of the default packages and sane
-defaults are expected.
-
-In my specific case, with an Intel N100-based machine with four I226-V Ethernet
-controllers, my upload performance increased from under 30 Mb/s to the expected
-~1 Gb/s.
-
----
- drivers/net/ethernet/intel/igc/igc_main.c | 3 +++
- 1 file changed, 3 insertions(+)
-
---- a/drivers/net/ethernet/intel/igc/igc_main.c
-+++ b/drivers/net/ethernet/intel/igc/igc_main.c
-@@ -6854,6 +6854,9 @@ static int igc_probe(struct pci_dev *pde
- netdev->xdp_features = NETDEV_XDP_ACT_BASIC | NETDEV_XDP_ACT_REDIRECT |
- NETDEV_XDP_ACT_XSK_ZEROCOPY;
-
-+ /* enable HW vlan tag insertion/stripping by default */
-+ netdev->features |= NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX;
-+
- /* MTU range: 68 - 9216 */
- netdev->min_mtu = ETH_MIN_MTU;
- netdev->max_mtu = MAX_STD_JUMBO_FRAME_SIZE;
+++ /dev/null
-From e85d3e6fea05c8ae21a40809a3c6b7adc97411c7 Mon Sep 17 00:00:00 2001
-Message-ID: <e85d3e6fea05c8ae21a40809a3c6b7adc97411c7.1728674648.git.mschiffer@universe-factory.net>
-Date: Thu, 20 Jun 2024 19:25:48 +0200
-Subject: [PATCH] net: dsa: qca8k: do not write port mask twice in bridge
- join/leave
-
-qca8k_port_bridge_join() set QCA8K_PORT_LOOKUP_CTRL() for i == port twice,
-once in the loop handling all other port's masks, and finally at the end
-with the accumulated port_mask.
-
-The first time it would incorrectly set the port's own bit in the mask,
-only to correct the mistake a moment later. qca8k_port_bridge_leave() had
-the same issue, but here the regmap_clear_bits() was a no-op rather than
-setting an unintended value.
-
-Remove the duplicate assignment by skipping the whole loop iteration for
-i == port. The unintended bit setting doesn't seem to have any negative
-effects (even when not reverted right away), so the change is submitted
-as a simple cleanup rather than a fix.
-
----
- drivers/net/dsa/qca/qca8k-common.c | 7 +++++--
- 1 file changed, 5 insertions(+), 2 deletions(-)
-
---- a/drivers/net/dsa/qca/qca8k-common.c
-+++ b/drivers/net/dsa/qca/qca8k-common.c
-@@ -654,6 +654,8 @@ int qca8k_port_bridge_join(struct dsa_sw
- port_mask = BIT(cpu_port);
-
- for (i = 0; i < QCA8K_NUM_PORTS; i++) {
-+ if (i == port)
-+ continue;
- if (dsa_is_cpu_port(ds, i))
- continue;
- if (!dsa_port_offloads_bridge(dsa_to_port(ds, i), &bridge))
-@@ -666,8 +668,7 @@ int qca8k_port_bridge_join(struct dsa_sw
- BIT(port));
- if (ret)
- return ret;
-- if (i != port)
-- port_mask |= BIT(i);
-+ port_mask |= BIT(i);
- }
-
- /* Add all other ports to this ports portvlan mask */
-@@ -686,6 +687,8 @@ void qca8k_port_bridge_leave(struct dsa_
- cpu_port = dsa_to_port(ds, port)->cpu_dp->index;
-
- for (i = 0; i < QCA8K_NUM_PORTS; i++) {
-+ if (i == port)
-+ continue;
- if (dsa_is_cpu_port(ds, i))
- continue;
- if (!dsa_port_offloads_bridge(dsa_to_port(ds, i), &bridge))
+++ /dev/null
-From 412e1775f413c944b8c51bdadb675be957d83dc8 Mon Sep 17 00:00:00 2001
-Message-ID: <412e1775f413c944b8c51bdadb675be957d83dc8.1728674648.git.mschiffer@universe-factory.net>
-In-Reply-To: <e85d3e6fea05c8ae21a40809a3c6b7adc97411c7.1728674648.git.mschiffer@universe-factory.net>
-References: <e85d3e6fea05c8ae21a40809a3c6b7adc97411c7.1728674648.git.mschiffer@universe-factory.net>
-Date: Thu, 20 Jun 2024 19:25:49 +0200
-Subject: [PATCH] net: dsa: qca8k: factor out bridge join/leave logic
-
-Most of the logic in qca8k_port_bridge_join() and qca8k_port_bridge_leave()
-is the same. Refactor to reduce duplication and prepare for reusing the
-code for implementing bridge port isolation.
-
-dsa_port_offloads_bridge_dev() is used instead of
-dsa_port_offloads_bridge(), passing the bridge in as a struct netdevice *,
-as we won't have a struct dsa_bridge in qca8k_port_bridge_flags().
-
-The error handling is changed slightly in the bridge leave case,
-returning early and emitting an error message when a regmap access fails.
-This shouldn't matter in practice, as there isn't much we can do if
-communication with the switch breaks down in the middle of reconfiguration.
-
----
- drivers/net/dsa/qca/qca8k-common.c | 101 ++++++++++++++---------------
- 1 file changed, 50 insertions(+), 51 deletions(-)
-
---- a/drivers/net/dsa/qca/qca8k-common.c
-+++ b/drivers/net/dsa/qca/qca8k-common.c
-@@ -615,6 +615,49 @@ void qca8k_port_stp_state_set(struct dsa
- qca8k_port_configure_learning(ds, port, learning);
- }
-
-+static int qca8k_update_port_member(struct qca8k_priv *priv, int port,
-+ const struct net_device *bridge_dev,
-+ bool join)
-+{
-+ struct dsa_port *dp = dsa_to_port(priv->ds, port), *other_dp;
-+ u32 port_mask = BIT(dp->cpu_dp->index);
-+ int i, ret;
-+
-+ for (i = 0; i < QCA8K_NUM_PORTS; i++) {
-+ if (i == port)
-+ continue;
-+ if (dsa_is_cpu_port(priv->ds, i))
-+ continue;
-+
-+ other_dp = dsa_to_port(priv->ds, i);
-+ if (!dsa_port_offloads_bridge_dev(other_dp, bridge_dev))
-+ continue;
-+
-+ /* Add/remove this port to/from the portvlan mask of the other
-+ * ports in the bridge
-+ */
-+ if (join) {
-+ port_mask |= BIT(i);
-+ ret = regmap_set_bits(priv->regmap,
-+ QCA8K_PORT_LOOKUP_CTRL(i),
-+ BIT(port));
-+ } else {
-+ ret = regmap_clear_bits(priv->regmap,
-+ QCA8K_PORT_LOOKUP_CTRL(i),
-+ BIT(port));
-+ }
-+
-+ if (ret)
-+ return ret;
-+ }
-+
-+ /* Add/remove all other ports to/from this port's portvlan mask */
-+ ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port),
-+ QCA8K_PORT_LOOKUP_MEMBER, port_mask);
-+
-+ return ret;
-+}
-+
- int qca8k_port_pre_bridge_flags(struct dsa_switch *ds, int port,
- struct switchdev_brport_flags flags,
- struct netlink_ext_ack *extack)
-@@ -647,65 +690,21 @@ int qca8k_port_bridge_join(struct dsa_sw
- struct netlink_ext_ack *extack)
- {
- struct qca8k_priv *priv = ds->priv;
-- int port_mask, cpu_port;
-- int i, ret;
--
-- cpu_port = dsa_to_port(ds, port)->cpu_dp->index;
-- port_mask = BIT(cpu_port);
-
-- for (i = 0; i < QCA8K_NUM_PORTS; i++) {
-- if (i == port)
-- continue;
-- if (dsa_is_cpu_port(ds, i))
-- continue;
-- if (!dsa_port_offloads_bridge(dsa_to_port(ds, i), &bridge))
-- continue;
-- /* Add this port to the portvlan mask of the other ports
-- * in the bridge
-- */
-- ret = regmap_set_bits(priv->regmap,
-- QCA8K_PORT_LOOKUP_CTRL(i),
-- BIT(port));
-- if (ret)
-- return ret;
-- port_mask |= BIT(i);
-- }
--
-- /* Add all other ports to this ports portvlan mask */
-- ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port),
-- QCA8K_PORT_LOOKUP_MEMBER, port_mask);
--
-- return ret;
-+ return qca8k_update_port_member(priv, port, bridge.dev, true);
- }
-
- void qca8k_port_bridge_leave(struct dsa_switch *ds, int port,
- struct dsa_bridge bridge)
- {
- struct qca8k_priv *priv = ds->priv;
-- int cpu_port, i;
--
-- cpu_port = dsa_to_port(ds, port)->cpu_dp->index;
--
-- for (i = 0; i < QCA8K_NUM_PORTS; i++) {
-- if (i == port)
-- continue;
-- if (dsa_is_cpu_port(ds, i))
-- continue;
-- if (!dsa_port_offloads_bridge(dsa_to_port(ds, i), &bridge))
-- continue;
-- /* Remove this port to the portvlan mask of the other ports
-- * in the bridge
-- */
-- regmap_clear_bits(priv->regmap,
-- QCA8K_PORT_LOOKUP_CTRL(i),
-- BIT(port));
-- }
-+ int err;
-
-- /* Set the cpu port to be the only one in the portvlan mask of
-- * this port
-- */
-- qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port),
-- QCA8K_PORT_LOOKUP_MEMBER, BIT(cpu_port));
-+ err = qca8k_update_port_member(priv, port, bridge.dev, false);
-+ if (err)
-+ dev_err(priv->dev,
-+ "Failed to update switch config for bridge leave: %d\n",
-+ err);
- }
-
- void qca8k_port_fast_age(struct dsa_switch *ds, int port)
+++ /dev/null
-From 422b64025ec10981c48f9367311846bf4bd38042 Mon Sep 17 00:00:00 2001
-Message-ID: <422b64025ec10981c48f9367311846bf4bd38042.1728674648.git.mschiffer@universe-factory.net>
-In-Reply-To: <e85d3e6fea05c8ae21a40809a3c6b7adc97411c7.1728674648.git.mschiffer@universe-factory.net>
-References: <e85d3e6fea05c8ae21a40809a3c6b7adc97411c7.1728674648.git.mschiffer@universe-factory.net>
-Date: Thu, 20 Jun 2024 19:25:50 +0200
-Subject: [PATCH] net: dsa: qca8k: add support for bridge port isolation
-
-Remove a pair of ports from the port matrix when both ports have the
-isolated flag set.
-
----
- drivers/net/dsa/qca/qca8k-common.c | 22 ++++++++++++++++++++--
- drivers/net/dsa/qca/qca8k.h | 1 +
- 2 files changed, 21 insertions(+), 2 deletions(-)
-
---- a/drivers/net/dsa/qca/qca8k-common.c
-+++ b/drivers/net/dsa/qca/qca8k-common.c
-@@ -619,6 +619,7 @@ static int qca8k_update_port_member(stru
- const struct net_device *bridge_dev,
- bool join)
- {
-+ bool isolated = !!(priv->port_isolated_map & BIT(port)), other_isolated;
- struct dsa_port *dp = dsa_to_port(priv->ds, port), *other_dp;
- u32 port_mask = BIT(dp->cpu_dp->index);
- int i, ret;
-@@ -633,10 +634,12 @@ static int qca8k_update_port_member(stru
- if (!dsa_port_offloads_bridge_dev(other_dp, bridge_dev))
- continue;
-
-+ other_isolated = !!(priv->port_isolated_map & BIT(i));
-+
- /* Add/remove this port to/from the portvlan mask of the other
- * ports in the bridge
- */
-- if (join) {
-+ if (join && !(isolated && other_isolated)) {
- port_mask |= BIT(i);
- ret = regmap_set_bits(priv->regmap,
- QCA8K_PORT_LOOKUP_CTRL(i),
-@@ -662,7 +665,7 @@ int qca8k_port_pre_bridge_flags(struct d
- struct switchdev_brport_flags flags,
- struct netlink_ext_ack *extack)
- {
-- if (flags.mask & ~BR_LEARNING)
-+ if (flags.mask & ~(BR_LEARNING | BR_ISOLATED))
- return -EINVAL;
-
- return 0;
-@@ -672,6 +675,7 @@ int qca8k_port_bridge_flags(struct dsa_s
- struct switchdev_brport_flags flags,
- struct netlink_ext_ack *extack)
- {
-+ struct qca8k_priv *priv = ds->priv;
- int ret;
-
- if (flags.mask & BR_LEARNING) {
-@@ -680,6 +684,20 @@ int qca8k_port_bridge_flags(struct dsa_s
- if (ret)
- return ret;
- }
-+
-+ if (flags.mask & BR_ISOLATED) {
-+ struct dsa_port *dp = dsa_to_port(ds, port);
-+ struct net_device *bridge_dev = dsa_port_bridge_dev_get(dp);
-+
-+ if (flags.val & BR_ISOLATED)
-+ priv->port_isolated_map |= BIT(port);
-+ else
-+ priv->port_isolated_map &= ~BIT(port);
-+
-+ ret = qca8k_update_port_member(priv, port, bridge_dev, true);
-+ if (ret)
-+ return ret;
-+ }
-
- return 0;
- }
---- a/drivers/net/dsa/qca/qca8k.h
-+++ b/drivers/net/dsa/qca/qca8k.h
-@@ -451,6 +451,7 @@ struct qca8k_priv {
- * Bit 1: port enabled. Bit 0: port disabled.
- */
- u8 port_enabled_map;
-+ u8 port_isolated_map;
- struct qca8k_ports_config ports_config;
- struct regmap *regmap;
- struct mii_bus *bus;
+++ /dev/null
-From 788d30daa8f97f06166b6a63f0e51f2a4c2f036a Mon Sep 17 00:00:00 2001
-Date: Tue, 26 Sep 2023 19:17:14 +0800
-Subject: [PATCH] r8152: use napi_gro_frags
-
-Use napi_gro_frags() for the skb of fragments when the work_done is less
-than budget.
-
----
- drivers/net/usb/r8152.c | 67 ++++++++++++++++++++++++++++++-----------
- 1 file changed, 50 insertions(+), 17 deletions(-)
-
---- a/drivers/net/usb/r8152.c
-+++ b/drivers/net/usb/r8152.c
-@@ -2585,8 +2585,9 @@ static int rx_bottom(struct r8152 *tp, i
- while (urb->actual_length > len_used) {
- struct net_device *netdev = tp->netdev;
- struct net_device_stats *stats = &netdev->stats;
-- unsigned int pkt_len, rx_frag_head_sz;
-+ unsigned int pkt_len, rx_frag_head_sz, len;
- struct sk_buff *skb;
-+ bool use_frags;
-
- WARN_ON_ONCE(skb_queue_len(&tp->rx_queue) >= 1000);
-
-@@ -2599,45 +2600,77 @@ static int rx_bottom(struct r8152 *tp, i
- break;
-
- pkt_len -= ETH_FCS_LEN;
-+ len = pkt_len;
- rx_data += sizeof(struct rx_desc);
-
-- if (!agg_free || tp->rx_copybreak > pkt_len)
-- rx_frag_head_sz = pkt_len;
-+ if (!agg_free || tp->rx_copybreak > len)
-+ use_frags = false;
- else
-- rx_frag_head_sz = tp->rx_copybreak;
-+ use_frags = true;
-+
-+ if (use_frags) {
-+ /* If the budget is exhausted, the packet
-+ * would be queued in the driver. That is,
-+ * napi_gro_frags() wouldn't be called, so
-+ * we couldn't use napi_get_frags().
-+ */
-+ if (work_done >= budget) {
-+ rx_frag_head_sz = tp->rx_copybreak;
-+ skb = napi_alloc_skb(napi,
-+ rx_frag_head_sz);
-+ } else {
-+ rx_frag_head_sz = 0;
-+ skb = napi_get_frags(napi);
-+ }
-+ } else {
-+ rx_frag_head_sz = 0;
-+ skb = napi_alloc_skb(napi, len);
-+ }
-
-- skb = napi_alloc_skb(napi, rx_frag_head_sz);
- if (!skb) {
- stats->rx_dropped++;
- goto find_next_rx;
- }
-
- skb->ip_summed = r8152_rx_csum(tp, rx_desc);
-- memcpy(skb->data, rx_data, rx_frag_head_sz);
-- skb_put(skb, rx_frag_head_sz);
-- pkt_len -= rx_frag_head_sz;
-- rx_data += rx_frag_head_sz;
-- if (pkt_len) {
-+ rtl_rx_vlan_tag(rx_desc, skb);
-+
-+ if (use_frags) {
-+ if (rx_frag_head_sz) {
-+ memcpy(skb->data, rx_data,
-+ rx_frag_head_sz);
-+ skb_put(skb, rx_frag_head_sz);
-+ len -= rx_frag_head_sz;
-+ rx_data += rx_frag_head_sz;
-+ skb->protocol = eth_type_trans(skb,
-+ netdev);
-+ }
-+
- skb_add_rx_frag(skb, 0, agg->page,
- agg_offset(agg, rx_data),
-- pkt_len,
-- SKB_DATA_ALIGN(pkt_len));
-+ len, SKB_DATA_ALIGN(len));
- get_page(agg->page);
-+ } else {
-+ memcpy(skb->data, rx_data, len);
-+ skb_put(skb, len);
-+ skb->protocol = eth_type_trans(skb, netdev);
- }
-
-- skb->protocol = eth_type_trans(skb, netdev);
-- rtl_rx_vlan_tag(rx_desc, skb);
- if (work_done < budget) {
-+ if (use_frags)
-+ napi_gro_frags(napi);
-+ else
-+ napi_gro_receive(napi, skb);
-+
- work_done++;
- stats->rx_packets++;
-- stats->rx_bytes += skb->len;
-- napi_gro_receive(napi, skb);
-+ stats->rx_bytes += pkt_len;
- } else {
- __skb_queue_tail(&tp->rx_queue, skb);
- }
-
- find_next_rx:
-- rx_data = rx_agg_align(rx_data + pkt_len + ETH_FCS_LEN);
-+ rx_data = rx_agg_align(rx_data + len + ETH_FCS_LEN);
- rx_desc = (struct rx_desc *)rx_data;
- len_used = agg_offset(agg, rx_data);
- len_used += sizeof(struct rx_desc);
+++ /dev/null
-From 71e79430117d56c409c5ea485a263bc0d8083390 Mon Sep 17 00:00:00 2001
-Date: Tue, 26 Mar 2024 17:23:05 +0100
-Subject: [PATCH] net: phy: air_en8811h: Add the Airoha EN8811H PHY driver
-
-Add the driver for the Airoha EN8811H 2.5 Gigabit PHY. The phy supports
-100/1000/2500 Mbps with auto negotiation only.
-
-The driver uses two firmware files, for which updated versions are added to
-linux-firmware already.
-
-Note: At phy-address + 8 there is another device on the mdio bus, that
-belongs to the EN881H. While the original driver writes to it, Airoha
-has confirmed this is not needed. Therefore, communication with this
-device is not included in this driver.
-
----
- drivers/net/phy/Kconfig | 5 +
- drivers/net/phy/Makefile | 1 +
- drivers/net/phy/air_en8811h.c | 1086 +++++++++++++++++++++++++++++++++
- 3 files changed, 1092 insertions(+)
- create mode 100644 drivers/net/phy/air_en8811h.c
-
---- a/drivers/net/phy/Kconfig
-+++ b/drivers/net/phy/Kconfig
-@@ -80,6 +80,11 @@ config AS21XXX_PHY
- AS21210PB1 that all register with the PHY ID 0x7500 0x7500
- before the firmware is loaded.
-
-+config AIR_EN8811H_PHY
-+ tristate "Airoha EN8811H 2.5 Gigabit PHY"
-+ help
-+ Currently supports the Airoha EN8811H PHY.
-+
- config AMD_PHY
- tristate "AMD PHYs"
- help
---- a/drivers/net/phy/Makefile
-+++ b/drivers/net/phy/Makefile
-@@ -34,6 +34,7 @@ obj-y += $(sfp-obj-y) $(sfp-obj-m)
-
- obj-$(CONFIG_ADIN_PHY) += adin.o
- obj-$(CONFIG_ADIN1100_PHY) += adin1100.o
-+obj-$(CONFIG_AIR_EN8811H_PHY) += air_en8811h.o
- obj-$(CONFIG_AMD_PHY) += amd.o
- obj-$(CONFIG_AQUANTIA_PHY) += aquantia/
- obj-$(CONFIG_AS21XXX_PHY) += as21xxx.o
---- /dev/null
-+++ b/drivers/net/phy/air_en8811h.c
-@@ -0,0 +1,1086 @@
-+// SPDX-License-Identifier: GPL-2.0+
-+/*
-+ * Driver for the Airoha EN8811H 2.5 Gigabit PHY.
-+ *
-+ * Limitations of the EN8811H:
-+ * - Only full duplex supported
-+ * - Forced speed (AN off) is not supported by hardware (100Mbps)
-+ *
-+ * Source originated from airoha's en8811h.c and en8811h.h v1.2.1
-+ *
-+ * Copyright (C) 2023 Airoha Technology Corp.
-+ */
-+
-+#include <linux/phy.h>
-+#include <linux/firmware.h>
-+#include <linux/property.h>
-+#include <linux/wordpart.h>
-+#include <asm/unaligned.h>
-+
-+#define EN8811H_PHY_ID 0x03a2a411
-+
-+#define EN8811H_MD32_DM "airoha/EthMD32.dm.bin"
-+#define EN8811H_MD32_DSP "airoha/EthMD32.DSP.bin"
-+
-+#define AIR_FW_ADDR_DM 0x00000000
-+#define AIR_FW_ADDR_DSP 0x00100000
-+
-+/* MII Registers */
-+#define AIR_AUX_CTRL_STATUS 0x1d
-+#define AIR_AUX_CTRL_STATUS_SPEED_MASK GENMASK(4, 2)
-+#define AIR_AUX_CTRL_STATUS_SPEED_100 0x4
-+#define AIR_AUX_CTRL_STATUS_SPEED_1000 0x8
-+#define AIR_AUX_CTRL_STATUS_SPEED_2500 0xc
-+
-+#define AIR_EXT_PAGE_ACCESS 0x1f
-+#define AIR_PHY_PAGE_STANDARD 0x0000
-+#define AIR_PHY_PAGE_EXTENDED_4 0x0004
-+
-+/* MII Registers Page 4*/
-+#define AIR_BPBUS_MODE 0x10
-+#define AIR_BPBUS_MODE_ADDR_FIXED 0x0000
-+#define AIR_BPBUS_MODE_ADDR_INCR BIT(15)
-+#define AIR_BPBUS_WR_ADDR_HIGH 0x11
-+#define AIR_BPBUS_WR_ADDR_LOW 0x12
-+#define AIR_BPBUS_WR_DATA_HIGH 0x13
-+#define AIR_BPBUS_WR_DATA_LOW 0x14
-+#define AIR_BPBUS_RD_ADDR_HIGH 0x15
-+#define AIR_BPBUS_RD_ADDR_LOW 0x16
-+#define AIR_BPBUS_RD_DATA_HIGH 0x17
-+#define AIR_BPBUS_RD_DATA_LOW 0x18
-+
-+/* Registers on MDIO_MMD_VEND1 */
-+#define EN8811H_PHY_FW_STATUS 0x8009
-+#define EN8811H_PHY_READY 0x02
-+
-+#define AIR_PHY_MCU_CMD_1 0x800c
-+#define AIR_PHY_MCU_CMD_1_MODE1 0x0
-+#define AIR_PHY_MCU_CMD_2 0x800d
-+#define AIR_PHY_MCU_CMD_2_MODE1 0x0
-+#define AIR_PHY_MCU_CMD_3 0x800e
-+#define AIR_PHY_MCU_CMD_3_MODE1 0x1101
-+#define AIR_PHY_MCU_CMD_3_DOCMD 0x1100
-+#define AIR_PHY_MCU_CMD_4 0x800f
-+#define AIR_PHY_MCU_CMD_4_MODE1 0x0002
-+#define AIR_PHY_MCU_CMD_4_INTCLR 0x00e4
-+
-+/* Registers on MDIO_MMD_VEND2 */
-+#define AIR_PHY_LED_BCR 0x021
-+#define AIR_PHY_LED_BCR_MODE_MASK GENMASK(1, 0)
-+#define AIR_PHY_LED_BCR_TIME_TEST BIT(2)
-+#define AIR_PHY_LED_BCR_CLK_EN BIT(3)
-+#define AIR_PHY_LED_BCR_EXT_CTRL BIT(15)
-+
-+#define AIR_PHY_LED_DUR_ON 0x022
-+
-+#define AIR_PHY_LED_DUR_BLINK 0x023
-+
-+#define AIR_PHY_LED_ON(i) (0x024 + ((i) * 2))
-+#define AIR_PHY_LED_ON_MASK (GENMASK(6, 0) | BIT(8))
-+#define AIR_PHY_LED_ON_LINK1000 BIT(0)
-+#define AIR_PHY_LED_ON_LINK100 BIT(1)
-+#define AIR_PHY_LED_ON_LINK10 BIT(2)
-+#define AIR_PHY_LED_ON_LINKDOWN BIT(3)
-+#define AIR_PHY_LED_ON_FDX BIT(4) /* Full duplex */
-+#define AIR_PHY_LED_ON_HDX BIT(5) /* Half duplex */
-+#define AIR_PHY_LED_ON_FORCE_ON BIT(6)
-+#define AIR_PHY_LED_ON_LINK2500 BIT(8)
-+#define AIR_PHY_LED_ON_POLARITY BIT(14)
-+#define AIR_PHY_LED_ON_ENABLE BIT(15)
-+
-+#define AIR_PHY_LED_BLINK(i) (0x025 + ((i) * 2))
-+#define AIR_PHY_LED_BLINK_1000TX BIT(0)
-+#define AIR_PHY_LED_BLINK_1000RX BIT(1)
-+#define AIR_PHY_LED_BLINK_100TX BIT(2)
-+#define AIR_PHY_LED_BLINK_100RX BIT(3)
-+#define AIR_PHY_LED_BLINK_10TX BIT(4)
-+#define AIR_PHY_LED_BLINK_10RX BIT(5)
-+#define AIR_PHY_LED_BLINK_COLLISION BIT(6)
-+#define AIR_PHY_LED_BLINK_RX_CRC_ERR BIT(7)
-+#define AIR_PHY_LED_BLINK_RX_IDLE_ERR BIT(8)
-+#define AIR_PHY_LED_BLINK_FORCE_BLINK BIT(9)
-+#define AIR_PHY_LED_BLINK_2500TX BIT(10)
-+#define AIR_PHY_LED_BLINK_2500RX BIT(11)
-+
-+/* Registers on BUCKPBUS */
-+#define EN8811H_2P5G_LPA 0x3b30
-+#define EN8811H_2P5G_LPA_2P5G BIT(0)
-+
-+#define EN8811H_FW_VERSION 0x3b3c
-+
-+#define EN8811H_POLARITY 0xca0f8
-+#define EN8811H_POLARITY_TX_NORMAL BIT(0)
-+#define EN8811H_POLARITY_RX_REVERSE BIT(1)
-+
-+#define EN8811H_GPIO_OUTPUT 0xcf8b8
-+#define EN8811H_GPIO_OUTPUT_345 (BIT(3) | BIT(4) | BIT(5))
-+
-+#define EN8811H_FW_CTRL_1 0x0f0018
-+#define EN8811H_FW_CTRL_1_START 0x0
-+#define EN8811H_FW_CTRL_1_FINISH 0x1
-+#define EN8811H_FW_CTRL_2 0x800000
-+#define EN8811H_FW_CTRL_2_LOADING BIT(11)
-+
-+/* Led definitions */
-+#define EN8811H_LED_COUNT 3
-+
-+/* Default LED setup:
-+ * GPIO5 <-> LED0 On: Link detected, blink Rx/Tx
-+ * GPIO4 <-> LED1 On: Link detected at 2500 or 1000 Mbps
-+ * GPIO3 <-> LED2 On: Link detected at 2500 or 100 Mbps
-+ */
-+#define AIR_DEFAULT_TRIGGER_LED0 (BIT(TRIGGER_NETDEV_LINK) | \
-+ BIT(TRIGGER_NETDEV_RX) | \
-+ BIT(TRIGGER_NETDEV_TX))
-+#define AIR_DEFAULT_TRIGGER_LED1 (BIT(TRIGGER_NETDEV_LINK_2500) | \
-+ BIT(TRIGGER_NETDEV_LINK_1000))
-+#define AIR_DEFAULT_TRIGGER_LED2 (BIT(TRIGGER_NETDEV_LINK_2500) | \
-+ BIT(TRIGGER_NETDEV_LINK_100))
-+
-+struct led {
-+ unsigned long rules;
-+ unsigned long state;
-+};
-+
-+struct en8811h_priv {
-+ u32 firmware_version;
-+ bool mcu_needs_restart;
-+ struct led led[EN8811H_LED_COUNT];
-+};
-+
-+enum {
-+ AIR_PHY_LED_STATE_FORCE_ON,
-+ AIR_PHY_LED_STATE_FORCE_BLINK,
-+};
-+
-+enum {
-+ AIR_PHY_LED_DUR_BLINK_32MS,
-+ AIR_PHY_LED_DUR_BLINK_64MS,
-+ AIR_PHY_LED_DUR_BLINK_128MS,
-+ AIR_PHY_LED_DUR_BLINK_256MS,
-+ AIR_PHY_LED_DUR_BLINK_512MS,
-+ AIR_PHY_LED_DUR_BLINK_1024MS,
-+};
-+
-+enum {
-+ AIR_LED_DISABLE,
-+ AIR_LED_ENABLE,
-+};
-+
-+enum {
-+ AIR_ACTIVE_LOW,
-+ AIR_ACTIVE_HIGH,
-+};
-+
-+enum {
-+ AIR_LED_MODE_DISABLE,
-+ AIR_LED_MODE_USER_DEFINE,
-+};
-+
-+#define AIR_PHY_LED_DUR_UNIT 1024
-+#define AIR_PHY_LED_DUR (AIR_PHY_LED_DUR_UNIT << AIR_PHY_LED_DUR_BLINK_64MS)
-+
-+static const unsigned long en8811h_led_trig = BIT(TRIGGER_NETDEV_FULL_DUPLEX) |
-+ BIT(TRIGGER_NETDEV_LINK) |
-+ BIT(TRIGGER_NETDEV_LINK_10) |
-+ BIT(TRIGGER_NETDEV_LINK_100) |
-+ BIT(TRIGGER_NETDEV_LINK_1000) |
-+ BIT(TRIGGER_NETDEV_LINK_2500) |
-+ BIT(TRIGGER_NETDEV_RX) |
-+ BIT(TRIGGER_NETDEV_TX);
-+
-+static int air_phy_read_page(struct phy_device *phydev)
-+{
-+ return __phy_read(phydev, AIR_EXT_PAGE_ACCESS);
-+}
-+
-+static int air_phy_write_page(struct phy_device *phydev, int page)
-+{
-+ return __phy_write(phydev, AIR_EXT_PAGE_ACCESS, page);
-+}
-+
-+static int __air_buckpbus_reg_write(struct phy_device *phydev,
-+ u32 pbus_address, u32 pbus_data)
-+{
-+ int ret;
-+
-+ ret = __phy_write(phydev, AIR_BPBUS_MODE, AIR_BPBUS_MODE_ADDR_FIXED);
-+ if (ret < 0)
-+ return ret;
-+
-+ ret = __phy_write(phydev, AIR_BPBUS_WR_ADDR_HIGH,
-+ upper_16_bits(pbus_address));
-+ if (ret < 0)
-+ return ret;
-+
-+ ret = __phy_write(phydev, AIR_BPBUS_WR_ADDR_LOW,
-+ lower_16_bits(pbus_address));
-+ if (ret < 0)
-+ return ret;
-+
-+ ret = __phy_write(phydev, AIR_BPBUS_WR_DATA_HIGH,
-+ upper_16_bits(pbus_data));
-+ if (ret < 0)
-+ return ret;
-+
-+ ret = __phy_write(phydev, AIR_BPBUS_WR_DATA_LOW,
-+ lower_16_bits(pbus_data));
-+ if (ret < 0)
-+ return ret;
-+
-+ return 0;
-+}
-+
-+static int air_buckpbus_reg_write(struct phy_device *phydev,
-+ u32 pbus_address, u32 pbus_data)
-+{
-+ int saved_page;
-+ int ret = 0;
-+
-+ saved_page = phy_select_page(phydev, AIR_PHY_PAGE_EXTENDED_4);
-+
-+ if (saved_page >= 0) {
-+ ret = __air_buckpbus_reg_write(phydev, pbus_address,
-+ pbus_data);
-+ if (ret < 0)
-+ phydev_err(phydev, "%s 0x%08x failed: %d\n", __func__,
-+ pbus_address, ret);
-+ }
-+
-+ return phy_restore_page(phydev, saved_page, ret);
-+}
-+
-+static int __air_buckpbus_reg_read(struct phy_device *phydev,
-+ u32 pbus_address, u32 *pbus_data)
-+{
-+ int pbus_data_low, pbus_data_high;
-+ int ret;
-+
-+ ret = __phy_write(phydev, AIR_BPBUS_MODE, AIR_BPBUS_MODE_ADDR_FIXED);
-+ if (ret < 0)
-+ return ret;
-+
-+ ret = __phy_write(phydev, AIR_BPBUS_RD_ADDR_HIGH,
-+ upper_16_bits(pbus_address));
-+ if (ret < 0)
-+ return ret;
-+
-+ ret = __phy_write(phydev, AIR_BPBUS_RD_ADDR_LOW,
-+ lower_16_bits(pbus_address));
-+ if (ret < 0)
-+ return ret;
-+
-+ pbus_data_high = __phy_read(phydev, AIR_BPBUS_RD_DATA_HIGH);
-+ if (pbus_data_high < 0)
-+ return ret;
-+
-+ pbus_data_low = __phy_read(phydev, AIR_BPBUS_RD_DATA_LOW);
-+ if (pbus_data_low < 0)
-+ return ret;
-+
-+ *pbus_data = pbus_data_low | (pbus_data_high << 16);
-+ return 0;
-+}
-+
-+static int air_buckpbus_reg_read(struct phy_device *phydev,
-+ u32 pbus_address, u32 *pbus_data)
-+{
-+ int saved_page;
-+ int ret = 0;
-+
-+ saved_page = phy_select_page(phydev, AIR_PHY_PAGE_EXTENDED_4);
-+
-+ if (saved_page >= 0) {
-+ ret = __air_buckpbus_reg_read(phydev, pbus_address, pbus_data);
-+ if (ret < 0)
-+ phydev_err(phydev, "%s 0x%08x failed: %d\n", __func__,
-+ pbus_address, ret);
-+ }
-+
-+ return phy_restore_page(phydev, saved_page, ret);
-+}
-+
-+static int __air_buckpbus_reg_modify(struct phy_device *phydev,
-+ u32 pbus_address, u32 mask, u32 set)
-+{
-+ int pbus_data_low, pbus_data_high;
-+ u32 pbus_data_old, pbus_data_new;
-+ int ret;
-+
-+ ret = __phy_write(phydev, AIR_BPBUS_MODE, AIR_BPBUS_MODE_ADDR_FIXED);
-+ if (ret < 0)
-+ return ret;
-+
-+ ret = __phy_write(phydev, AIR_BPBUS_RD_ADDR_HIGH,
-+ upper_16_bits(pbus_address));
-+ if (ret < 0)
-+ return ret;
-+
-+ ret = __phy_write(phydev, AIR_BPBUS_RD_ADDR_LOW,
-+ lower_16_bits(pbus_address));
-+ if (ret < 0)
-+ return ret;
-+
-+ pbus_data_high = __phy_read(phydev, AIR_BPBUS_RD_DATA_HIGH);
-+ if (pbus_data_high < 0)
-+ return ret;
-+
-+ pbus_data_low = __phy_read(phydev, AIR_BPBUS_RD_DATA_LOW);
-+ if (pbus_data_low < 0)
-+ return ret;
-+
-+ pbus_data_old = pbus_data_low | (pbus_data_high << 16);
-+ pbus_data_new = (pbus_data_old & ~mask) | set;
-+ if (pbus_data_new == pbus_data_old)
-+ return 0;
-+
-+ ret = __phy_write(phydev, AIR_BPBUS_WR_ADDR_HIGH,
-+ upper_16_bits(pbus_address));
-+ if (ret < 0)
-+ return ret;
-+
-+ ret = __phy_write(phydev, AIR_BPBUS_WR_ADDR_LOW,
-+ lower_16_bits(pbus_address));
-+ if (ret < 0)
-+ return ret;
-+
-+ ret = __phy_write(phydev, AIR_BPBUS_WR_DATA_HIGH,
-+ upper_16_bits(pbus_data_new));
-+ if (ret < 0)
-+ return ret;
-+
-+ ret = __phy_write(phydev, AIR_BPBUS_WR_DATA_LOW,
-+ lower_16_bits(pbus_data_new));
-+ if (ret < 0)
-+ return ret;
-+
-+ return 0;
-+}
-+
-+static int air_buckpbus_reg_modify(struct phy_device *phydev,
-+ u32 pbus_address, u32 mask, u32 set)
-+{
-+ int saved_page;
-+ int ret = 0;
-+
-+ saved_page = phy_select_page(phydev, AIR_PHY_PAGE_EXTENDED_4);
-+
-+ if (saved_page >= 0) {
-+ ret = __air_buckpbus_reg_modify(phydev, pbus_address, mask,
-+ set);
-+ if (ret < 0)
-+ phydev_err(phydev, "%s 0x%08x failed: %d\n", __func__,
-+ pbus_address, ret);
-+ }
-+
-+ return phy_restore_page(phydev, saved_page, ret);
-+}
-+
-+static int __air_write_buf(struct phy_device *phydev, u32 address,
-+ const struct firmware *fw)
-+{
-+ unsigned int offset;
-+ int ret;
-+ u16 val;
-+
-+ ret = __phy_write(phydev, AIR_BPBUS_MODE, AIR_BPBUS_MODE_ADDR_INCR);
-+ if (ret < 0)
-+ return ret;
-+
-+ ret = __phy_write(phydev, AIR_BPBUS_WR_ADDR_HIGH,
-+ upper_16_bits(address));
-+ if (ret < 0)
-+ return ret;
-+
-+ ret = __phy_write(phydev, AIR_BPBUS_WR_ADDR_LOW,
-+ lower_16_bits(address));
-+ if (ret < 0)
-+ return ret;
-+
-+ for (offset = 0; offset < fw->size; offset += 4) {
-+ val = get_unaligned_le16(&fw->data[offset + 2]);
-+ ret = __phy_write(phydev, AIR_BPBUS_WR_DATA_HIGH, val);
-+ if (ret < 0)
-+ return ret;
-+
-+ val = get_unaligned_le16(&fw->data[offset]);
-+ ret = __phy_write(phydev, AIR_BPBUS_WR_DATA_LOW, val);
-+ if (ret < 0)
-+ return ret;
-+ }
-+
-+ return 0;
-+}
-+
-+static int air_write_buf(struct phy_device *phydev, u32 address,
-+ const struct firmware *fw)
-+{
-+ int saved_page;
-+ int ret = 0;
-+
-+ saved_page = phy_select_page(phydev, AIR_PHY_PAGE_EXTENDED_4);
-+
-+ if (saved_page >= 0) {
-+ ret = __air_write_buf(phydev, address, fw);
-+ if (ret < 0)
-+ phydev_err(phydev, "%s 0x%08x failed: %d\n", __func__,
-+ address, ret);
-+ }
-+
-+ return phy_restore_page(phydev, saved_page, ret);
-+}
-+
-+static int en8811h_wait_mcu_ready(struct phy_device *phydev)
-+{
-+ int ret, reg_value;
-+
-+ /* Because of mdio-lock, may have to wait for multiple loads */
-+ ret = phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND1,
-+ EN8811H_PHY_FW_STATUS, reg_value,
-+ reg_value == EN8811H_PHY_READY,
-+ 20000, 7500000, true);
-+ if (ret) {
-+ phydev_err(phydev, "MCU not ready: 0x%x\n", reg_value);
-+ return -ENODEV;
-+ }
-+
-+ return 0;
-+}
-+
-+static int en8811h_load_firmware(struct phy_device *phydev)
-+{
-+ struct en8811h_priv *priv = phydev->priv;
-+ struct device *dev = &phydev->mdio.dev;
-+ const struct firmware *fw1, *fw2;
-+ int ret;
-+
-+ ret = request_firmware_direct(&fw1, EN8811H_MD32_DM, dev);
-+ if (ret < 0)
-+ return ret;
-+
-+ ret = request_firmware_direct(&fw2, EN8811H_MD32_DSP, dev);
-+ if (ret < 0)
-+ goto en8811h_load_firmware_rel1;
-+
-+ ret = air_buckpbus_reg_write(phydev, EN8811H_FW_CTRL_1,
-+ EN8811H_FW_CTRL_1_START);
-+ if (ret < 0)
-+ goto en8811h_load_firmware_out;
-+
-+ ret = air_buckpbus_reg_modify(phydev, EN8811H_FW_CTRL_2,
-+ EN8811H_FW_CTRL_2_LOADING,
-+ EN8811H_FW_CTRL_2_LOADING);
-+ if (ret < 0)
-+ goto en8811h_load_firmware_out;
-+
-+ ret = air_write_buf(phydev, AIR_FW_ADDR_DM, fw1);
-+ if (ret < 0)
-+ goto en8811h_load_firmware_out;
-+
-+ ret = air_write_buf(phydev, AIR_FW_ADDR_DSP, fw2);
-+ if (ret < 0)
-+ goto en8811h_load_firmware_out;
-+
-+ ret = air_buckpbus_reg_modify(phydev, EN8811H_FW_CTRL_2,
-+ EN8811H_FW_CTRL_2_LOADING, 0);
-+ if (ret < 0)
-+ goto en8811h_load_firmware_out;
-+
-+ ret = air_buckpbus_reg_write(phydev, EN8811H_FW_CTRL_1,
-+ EN8811H_FW_CTRL_1_FINISH);
-+ if (ret < 0)
-+ goto en8811h_load_firmware_out;
-+
-+ ret = en8811h_wait_mcu_ready(phydev);
-+
-+ air_buckpbus_reg_read(phydev, EN8811H_FW_VERSION,
-+ &priv->firmware_version);
-+ phydev_info(phydev, "MD32 firmware version: %08x\n",
-+ priv->firmware_version);
-+
-+en8811h_load_firmware_out:
-+ release_firmware(fw2);
-+
-+en8811h_load_firmware_rel1:
-+ release_firmware(fw1);
-+
-+ if (ret < 0)
-+ phydev_err(phydev, "Load firmware failed: %d\n", ret);
-+
-+ return ret;
-+}
-+
-+static int en8811h_restart_mcu(struct phy_device *phydev)
-+{
-+ int ret;
-+
-+ ret = air_buckpbus_reg_write(phydev, EN8811H_FW_CTRL_1,
-+ EN8811H_FW_CTRL_1_START);
-+ if (ret < 0)
-+ return ret;
-+
-+ ret = air_buckpbus_reg_write(phydev, EN8811H_FW_CTRL_1,
-+ EN8811H_FW_CTRL_1_FINISH);
-+ if (ret < 0)
-+ return ret;
-+
-+ return en8811h_wait_mcu_ready(phydev);
-+}
-+
-+static int air_hw_led_on_set(struct phy_device *phydev, u8 index, bool on)
-+{
-+ struct en8811h_priv *priv = phydev->priv;
-+ bool changed;
-+
-+ if (index >= EN8811H_LED_COUNT)
-+ return -EINVAL;
-+
-+ if (on)
-+ changed = !test_and_set_bit(AIR_PHY_LED_STATE_FORCE_ON,
-+ &priv->led[index].state);
-+ else
-+ changed = !!test_and_clear_bit(AIR_PHY_LED_STATE_FORCE_ON,
-+ &priv->led[index].state);
-+
-+ changed |= (priv->led[index].rules != 0);
-+
-+ if (changed)
-+ return phy_modify_mmd(phydev, MDIO_MMD_VEND2,
-+ AIR_PHY_LED_ON(index),
-+ AIR_PHY_LED_ON_MASK,
-+ on ? AIR_PHY_LED_ON_FORCE_ON : 0);
-+
-+ return 0;
-+}
-+
-+static int air_hw_led_blink_set(struct phy_device *phydev, u8 index,
-+ bool blinking)
-+{
-+ struct en8811h_priv *priv = phydev->priv;
-+ bool changed;
-+
-+ if (index >= EN8811H_LED_COUNT)
-+ return -EINVAL;
-+
-+ if (blinking)
-+ changed = !test_and_set_bit(AIR_PHY_LED_STATE_FORCE_BLINK,
-+ &priv->led[index].state);
-+ else
-+ changed = !!test_and_clear_bit(AIR_PHY_LED_STATE_FORCE_BLINK,
-+ &priv->led[index].state);
-+
-+ changed |= (priv->led[index].rules != 0);
-+
-+ if (changed)
-+ return phy_write_mmd(phydev, MDIO_MMD_VEND2,
-+ AIR_PHY_LED_BLINK(index),
-+ blinking ?
-+ AIR_PHY_LED_BLINK_FORCE_BLINK : 0);
-+ else
-+ return 0;
-+}
-+
-+static int air_led_blink_set(struct phy_device *phydev, u8 index,
-+ unsigned long *delay_on,
-+ unsigned long *delay_off)
-+{
-+ struct en8811h_priv *priv = phydev->priv;
-+ bool blinking = false;
-+ int err;
-+
-+ if (index >= EN8811H_LED_COUNT)
-+ return -EINVAL;
-+
-+ if (delay_on && delay_off && (*delay_on > 0) && (*delay_off > 0)) {
-+ blinking = true;
-+ *delay_on = 50;
-+ *delay_off = 50;
-+ }
-+
-+ err = air_hw_led_blink_set(phydev, index, blinking);
-+ if (err)
-+ return err;
-+
-+ /* led-blink set, so switch led-on off */
-+ err = air_hw_led_on_set(phydev, index, false);
-+ if (err)
-+ return err;
-+
-+ /* hw-control is off*/
-+ if (!!test_bit(AIR_PHY_LED_STATE_FORCE_BLINK, &priv->led[index].state))
-+ priv->led[index].rules = 0;
-+
-+ return 0;
-+}
-+
-+static int air_led_brightness_set(struct phy_device *phydev, u8 index,
-+ enum led_brightness value)
-+{
-+ struct en8811h_priv *priv = phydev->priv;
-+ int err;
-+
-+ if (index >= EN8811H_LED_COUNT)
-+ return -EINVAL;
-+
-+ /* led-on set, so switch led-blink off */
-+ err = air_hw_led_blink_set(phydev, index, false);
-+ if (err)
-+ return err;
-+
-+ err = air_hw_led_on_set(phydev, index, (value != LED_OFF));
-+ if (err)
-+ return err;
-+
-+ /* hw-control is off */
-+ if (!!test_bit(AIR_PHY_LED_STATE_FORCE_ON, &priv->led[index].state))
-+ priv->led[index].rules = 0;
-+
-+ return 0;
-+}
-+
-+static int air_led_hw_control_get(struct phy_device *phydev, u8 index,
-+ unsigned long *rules)
-+{
-+ struct en8811h_priv *priv = phydev->priv;
-+
-+ if (index >= EN8811H_LED_COUNT)
-+ return -EINVAL;
-+
-+ *rules = priv->led[index].rules;
-+
-+ return 0;
-+};
-+
-+static int air_led_hw_control_set(struct phy_device *phydev, u8 index,
-+ unsigned long rules)
-+{
-+ struct en8811h_priv *priv = phydev->priv;
-+ u16 on = 0, blink = 0;
-+ int ret;
-+
-+ if (index >= EN8811H_LED_COUNT)
-+ return -EINVAL;
-+
-+ priv->led[index].rules = rules;
-+
-+ if (rules & BIT(TRIGGER_NETDEV_FULL_DUPLEX))
-+ on |= AIR_PHY_LED_ON_FDX;
-+
-+ if (rules & (BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_LINK)))
-+ on |= AIR_PHY_LED_ON_LINK10;
-+
-+ if (rules & (BIT(TRIGGER_NETDEV_LINK_100) | BIT(TRIGGER_NETDEV_LINK)))
-+ on |= AIR_PHY_LED_ON_LINK100;
-+
-+ if (rules & (BIT(TRIGGER_NETDEV_LINK_1000) | BIT(TRIGGER_NETDEV_LINK)))
-+ on |= AIR_PHY_LED_ON_LINK1000;
-+
-+ if (rules & (BIT(TRIGGER_NETDEV_LINK_2500) | BIT(TRIGGER_NETDEV_LINK)))
-+ on |= AIR_PHY_LED_ON_LINK2500;
-+
-+ if (rules & BIT(TRIGGER_NETDEV_RX)) {
-+ blink |= AIR_PHY_LED_BLINK_10RX |
-+ AIR_PHY_LED_BLINK_100RX |
-+ AIR_PHY_LED_BLINK_1000RX |
-+ AIR_PHY_LED_BLINK_2500RX;
-+ }
-+
-+ if (rules & BIT(TRIGGER_NETDEV_TX)) {
-+ blink |= AIR_PHY_LED_BLINK_10TX |
-+ AIR_PHY_LED_BLINK_100TX |
-+ AIR_PHY_LED_BLINK_1000TX |
-+ AIR_PHY_LED_BLINK_2500TX;
-+ }
-+
-+ if (blink || on) {
-+ /* switch hw-control on, so led-on and led-blink are off */
-+ clear_bit(AIR_PHY_LED_STATE_FORCE_ON,
-+ &priv->led[index].state);
-+ clear_bit(AIR_PHY_LED_STATE_FORCE_BLINK,
-+ &priv->led[index].state);
-+ } else {
-+ priv->led[index].rules = 0;
-+ }
-+
-+ ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, AIR_PHY_LED_ON(index),
-+ AIR_PHY_LED_ON_MASK, on);
-+
-+ if (ret < 0)
-+ return ret;
-+
-+ return phy_write_mmd(phydev, MDIO_MMD_VEND2, AIR_PHY_LED_BLINK(index),
-+ blink);
-+};
-+
-+static int air_led_init(struct phy_device *phydev, u8 index, u8 state, u8 pol)
-+{
-+ int val = 0;
-+ int err;
-+
-+ if (index >= EN8811H_LED_COUNT)
-+ return -EINVAL;
-+
-+ if (state == AIR_LED_ENABLE)
-+ val |= AIR_PHY_LED_ON_ENABLE;
-+ else
-+ val &= ~AIR_PHY_LED_ON_ENABLE;
-+
-+ if (pol == AIR_ACTIVE_HIGH)
-+ val |= AIR_PHY_LED_ON_POLARITY;
-+ else
-+ val &= ~AIR_PHY_LED_ON_POLARITY;
-+
-+ err = phy_modify_mmd(phydev, MDIO_MMD_VEND2, AIR_PHY_LED_ON(index),
-+ AIR_PHY_LED_ON_ENABLE |
-+ AIR_PHY_LED_ON_POLARITY, val);
-+
-+ if (err < 0)
-+ return err;
-+
-+ return 0;
-+}
-+
-+static int air_leds_init(struct phy_device *phydev, int num, int dur, int mode)
-+{
-+ struct en8811h_priv *priv = phydev->priv;
-+ int ret, i;
-+
-+ ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, AIR_PHY_LED_DUR_BLINK,
-+ dur);
-+ if (ret < 0)
-+ return ret;
-+
-+ ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, AIR_PHY_LED_DUR_ON,
-+ dur >> 1);
-+ if (ret < 0)
-+ return ret;
-+
-+ switch (mode) {
-+ case AIR_LED_MODE_DISABLE:
-+ ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, AIR_PHY_LED_BCR,
-+ AIR_PHY_LED_BCR_EXT_CTRL |
-+ AIR_PHY_LED_BCR_MODE_MASK, 0);
-+ if (ret < 0)
-+ return ret;
-+ break;
-+ case AIR_LED_MODE_USER_DEFINE:
-+ ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, AIR_PHY_LED_BCR,
-+ AIR_PHY_LED_BCR_EXT_CTRL |
-+ AIR_PHY_LED_BCR_CLK_EN,
-+ AIR_PHY_LED_BCR_EXT_CTRL |
-+ AIR_PHY_LED_BCR_CLK_EN);
-+ if (ret < 0)
-+ return ret;
-+ break;
-+ default:
-+ phydev_err(phydev, "LED mode %d is not supported\n", mode);
-+ return -EINVAL;
-+ }
-+
-+ for (i = 0; i < num; ++i) {
-+ ret = air_led_init(phydev, i, AIR_LED_ENABLE, AIR_ACTIVE_HIGH);
-+ if (ret < 0) {
-+ phydev_err(phydev, "LED%d init failed: %d\n", i, ret);
-+ return ret;
-+ }
-+ air_led_hw_control_set(phydev, i, priv->led[i].rules);
-+ }
-+
-+ return 0;
-+}
-+
-+static int en8811h_led_hw_is_supported(struct phy_device *phydev, u8 index,
-+ unsigned long rules)
-+{
-+ if (index >= EN8811H_LED_COUNT)
-+ return -EINVAL;
-+
-+ /* All combinations of the supported triggers are allowed */
-+ if (rules & ~en8811h_led_trig)
-+ return -EOPNOTSUPP;
-+
-+ return 0;
-+};
-+
-+static int en8811h_probe(struct phy_device *phydev)
-+{
-+ struct en8811h_priv *priv;
-+ int ret;
-+
-+ priv = devm_kzalloc(&phydev->mdio.dev, sizeof(struct en8811h_priv),
-+ GFP_KERNEL);
-+ if (!priv)
-+ return -ENOMEM;
-+ phydev->priv = priv;
-+
-+ ret = en8811h_load_firmware(phydev);
-+ if (ret < 0)
-+ return ret;
-+
-+ /* mcu has just restarted after firmware load */
-+ priv->mcu_needs_restart = false;
-+
-+ priv->led[0].rules = AIR_DEFAULT_TRIGGER_LED0;
-+ priv->led[1].rules = AIR_DEFAULT_TRIGGER_LED1;
-+ priv->led[2].rules = AIR_DEFAULT_TRIGGER_LED2;
-+
-+ /* MDIO_DEVS1/2 empty, so set mmds_present bits here */
-+ phydev->c45_ids.mmds_present |= MDIO_DEVS_PMAPMD | MDIO_DEVS_AN;
-+
-+ ret = air_leds_init(phydev, EN8811H_LED_COUNT, AIR_PHY_LED_DUR,
-+ AIR_LED_MODE_DISABLE);
-+ if (ret < 0) {
-+ phydev_err(phydev, "Failed to disable leds: %d\n", ret);
-+ return ret;
-+ }
-+
-+ /* Configure led gpio pins as output */
-+ ret = air_buckpbus_reg_modify(phydev, EN8811H_GPIO_OUTPUT,
-+ EN8811H_GPIO_OUTPUT_345,
-+ EN8811H_GPIO_OUTPUT_345);
-+ if (ret < 0)
-+ return ret;
-+
-+ return 0;
-+}
-+
-+static int en8811h_config_init(struct phy_device *phydev)
-+{
-+ struct en8811h_priv *priv = phydev->priv;
-+ struct device *dev = &phydev->mdio.dev;
-+ u32 pbus_value;
-+ int ret;
-+
-+ /* If restart happened in .probe(), no need to restart now */
-+ if (priv->mcu_needs_restart) {
-+ ret = en8811h_restart_mcu(phydev);
-+ if (ret < 0)
-+ return ret;
-+ } else {
-+ /* Next calls to .config_init() mcu needs to restart */
-+ priv->mcu_needs_restart = true;
-+ }
-+
-+ /* Select mode 1, the only mode supported.
-+ * Configures the SerDes for 2500Base-X with rate adaptation
-+ */
-+ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, AIR_PHY_MCU_CMD_1,
-+ AIR_PHY_MCU_CMD_1_MODE1);
-+ if (ret < 0)
-+ return ret;
-+ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, AIR_PHY_MCU_CMD_2,
-+ AIR_PHY_MCU_CMD_2_MODE1);
-+ if (ret < 0)
-+ return ret;
-+ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, AIR_PHY_MCU_CMD_3,
-+ AIR_PHY_MCU_CMD_3_MODE1);
-+ if (ret < 0)
-+ return ret;
-+ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, AIR_PHY_MCU_CMD_4,
-+ AIR_PHY_MCU_CMD_4_MODE1);
-+ if (ret < 0)
-+ return ret;
-+
-+ /* Serdes polarity */
-+ pbus_value = 0;
-+ if (device_property_read_bool(dev, "airoha,pnswap-rx"))
-+ pbus_value |= EN8811H_POLARITY_RX_REVERSE;
-+ else
-+ pbus_value &= ~EN8811H_POLARITY_RX_REVERSE;
-+ if (device_property_read_bool(dev, "airoha,pnswap-tx"))
-+ pbus_value &= ~EN8811H_POLARITY_TX_NORMAL;
-+ else
-+ pbus_value |= EN8811H_POLARITY_TX_NORMAL;
-+ ret = air_buckpbus_reg_modify(phydev, EN8811H_POLARITY,
-+ EN8811H_POLARITY_RX_REVERSE |
-+ EN8811H_POLARITY_TX_NORMAL, pbus_value);
-+ if (ret < 0)
-+ return ret;
-+
-+ ret = air_leds_init(phydev, EN8811H_LED_COUNT, AIR_PHY_LED_DUR,
-+ AIR_LED_MODE_USER_DEFINE);
-+ if (ret < 0) {
-+ phydev_err(phydev, "Failed to initialize leds: %d\n", ret);
-+ return ret;
-+ }
-+
-+ return 0;
-+}
-+
-+static int en8811h_get_features(struct phy_device *phydev)
-+{
-+ linkmode_set_bit_array(phy_basic_ports_array,
-+ ARRAY_SIZE(phy_basic_ports_array),
-+ phydev->supported);
-+
-+ return genphy_c45_pma_read_abilities(phydev);
-+}
-+
-+static int en8811h_get_rate_matching(struct phy_device *phydev,
-+ phy_interface_t iface)
-+{
-+ return RATE_MATCH_PAUSE;
-+}
-+
-+static int en8811h_config_aneg(struct phy_device *phydev)
-+{
-+ bool changed = false;
-+ int ret;
-+ u32 adv;
-+
-+ if (phydev->autoneg == AUTONEG_DISABLE) {
-+ phydev_warn(phydev, "Disabling autoneg is not supported\n");
-+ return -EINVAL;
-+ }
-+
-+ adv = linkmode_adv_to_mii_10gbt_adv_t(phydev->advertising);
-+
-+ ret = phy_modify_mmd_changed(phydev, MDIO_MMD_AN, MDIO_AN_10GBT_CTRL,
-+ MDIO_AN_10GBT_CTRL_ADV2_5G, adv);
-+ if (ret < 0)
-+ return ret;
-+ if (ret > 0)
-+ changed = true;
-+
-+ return __genphy_config_aneg(phydev, changed);
-+}
-+
-+static int en8811h_read_status(struct phy_device *phydev)
-+{
-+ struct en8811h_priv *priv = phydev->priv;
-+ u32 pbus_value;
-+ int ret, val;
-+
-+ ret = genphy_update_link(phydev);
-+ if (ret)
-+ return ret;
-+
-+ phydev->master_slave_get = MASTER_SLAVE_CFG_UNSUPPORTED;
-+ phydev->master_slave_state = MASTER_SLAVE_STATE_UNSUPPORTED;
-+ phydev->speed = SPEED_UNKNOWN;
-+ phydev->duplex = DUPLEX_UNKNOWN;
-+ phydev->pause = 0;
-+ phydev->asym_pause = 0;
-+ phydev->rate_matching = RATE_MATCH_PAUSE;
-+
-+ ret = genphy_read_master_slave(phydev);
-+ if (ret < 0)
-+ return ret;
-+
-+ ret = genphy_read_lpa(phydev);
-+ if (ret < 0)
-+ return ret;
-+
-+ /* Get link partner 2.5GBASE-T ability from vendor register */
-+ ret = air_buckpbus_reg_read(phydev, EN8811H_2P5G_LPA, &pbus_value);
-+ if (ret < 0)
-+ return ret;
-+ linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
-+ phydev->lp_advertising,
-+ pbus_value & EN8811H_2P5G_LPA_2P5G);
-+
-+ if (phydev->autoneg_complete)
-+ phy_resolve_aneg_pause(phydev);
-+
-+ if (!phydev->link)
-+ return 0;
-+
-+ /* Get real speed from vendor register */
-+ val = phy_read(phydev, AIR_AUX_CTRL_STATUS);
-+ if (val < 0)
-+ return val;
-+ switch (val & AIR_AUX_CTRL_STATUS_SPEED_MASK) {
-+ case AIR_AUX_CTRL_STATUS_SPEED_2500:
-+ phydev->speed = SPEED_2500;
-+ break;
-+ case AIR_AUX_CTRL_STATUS_SPEED_1000:
-+ phydev->speed = SPEED_1000;
-+ break;
-+ case AIR_AUX_CTRL_STATUS_SPEED_100:
-+ phydev->speed = SPEED_100;
-+ break;
-+ }
-+
-+ /* Firmware before version 24011202 has no vendor register 2P5G_LPA.
-+ * Assume link partner advertised it if connected at 2500Mbps.
-+ */
-+ if (priv->firmware_version < 0x24011202) {
-+ linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
-+ phydev->lp_advertising,
-+ phydev->speed == SPEED_2500);
-+ }
-+
-+ /* Only supports full duplex */
-+ phydev->duplex = DUPLEX_FULL;
-+
-+ return 0;
-+}
-+
-+static int en8811h_clear_intr(struct phy_device *phydev)
-+{
-+ int ret;
-+
-+ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, AIR_PHY_MCU_CMD_3,
-+ AIR_PHY_MCU_CMD_3_DOCMD);
-+ if (ret < 0)
-+ return ret;
-+
-+ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, AIR_PHY_MCU_CMD_4,
-+ AIR_PHY_MCU_CMD_4_INTCLR);
-+ if (ret < 0)
-+ return ret;
-+
-+ return 0;
-+}
-+
-+static irqreturn_t en8811h_handle_interrupt(struct phy_device *phydev)
-+{
-+ int ret;
-+
-+ ret = en8811h_clear_intr(phydev);
-+ if (ret < 0) {
-+ phy_error(phydev);
-+ return IRQ_NONE;
-+ }
-+
-+ phy_trigger_machine(phydev);
-+
-+ return IRQ_HANDLED;
-+}
-+
-+static struct phy_driver en8811h_driver[] = {
-+{
-+ PHY_ID_MATCH_MODEL(EN8811H_PHY_ID),
-+ .name = "Airoha EN8811H",
-+ .probe = en8811h_probe,
-+ .get_features = en8811h_get_features,
-+ .config_init = en8811h_config_init,
-+ .get_rate_matching = en8811h_get_rate_matching,
-+ .config_aneg = en8811h_config_aneg,
-+ .read_status = en8811h_read_status,
-+ .config_intr = en8811h_clear_intr,
-+ .handle_interrupt = en8811h_handle_interrupt,
-+ .led_hw_is_supported = en8811h_led_hw_is_supported,
-+ .read_page = air_phy_read_page,
-+ .write_page = air_phy_write_page,
-+ .led_blink_set = air_led_blink_set,
-+ .led_brightness_set = air_led_brightness_set,
-+ .led_hw_control_set = air_led_hw_control_set,
-+ .led_hw_control_get = air_led_hw_control_get,
-+} };
-+
-+module_phy_driver(en8811h_driver);
-+
-+static struct mdio_device_id __maybe_unused en8811h_tbl[] = {
-+ { PHY_ID_MATCH_MODEL(EN8811H_PHY_ID) },
-+ { }
-+};
-+
-+MODULE_DEVICE_TABLE(mdio, en8811h_tbl);
-+MODULE_FIRMWARE(EN8811H_MD32_DM);
-+MODULE_FIRMWARE(EN8811H_MD32_DSP);
-+
-+MODULE_DESCRIPTION("Airoha EN8811H PHY drivers");
-+MODULE_AUTHOR("Airoha");
-+MODULE_LICENSE("GPL");
+++ /dev/null
-From 87c33315af380ca12a2e59ac94edad4fe0481b4c Mon Sep 17 00:00:00 2001
-Date: Fri, 5 Apr 2024 13:08:59 +0300
-Subject: [PATCH] net: phy: air_en8811h: fix some error codes
-
-These error paths accidentally return "ret" which is zero/success
-instead of the correct error code.
-
-Fixes: 71e79430117d ("net: phy: air_en8811h: Add the Airoha EN8811H PHY driver")
----
- drivers/net/phy/air_en8811h.c | 8 ++++----
- 1 file changed, 4 insertions(+), 4 deletions(-)
-
---- a/drivers/net/phy/air_en8811h.c
-+++ b/drivers/net/phy/air_en8811h.c
-@@ -272,11 +272,11 @@ static int __air_buckpbus_reg_read(struc
-
- pbus_data_high = __phy_read(phydev, AIR_BPBUS_RD_DATA_HIGH);
- if (pbus_data_high < 0)
-- return ret;
-+ return pbus_data_high;
-
- pbus_data_low = __phy_read(phydev, AIR_BPBUS_RD_DATA_LOW);
- if (pbus_data_low < 0)
-- return ret;
-+ return pbus_data_low;
-
- *pbus_data = pbus_data_low | (pbus_data_high << 16);
- return 0;
-@@ -323,11 +323,11 @@ static int __air_buckpbus_reg_modify(str
-
- pbus_data_high = __phy_read(phydev, AIR_BPBUS_RD_DATA_HIGH);
- if (pbus_data_high < 0)
-- return ret;
-+ return pbus_data_high;
-
- pbus_data_low = __phy_read(phydev, AIR_BPBUS_RD_DATA_LOW);
- if (pbus_data_low < 0)
-- return ret;
-+ return pbus_data_low;
-
- pbus_data_old = pbus_data_low | (pbus_data_high << 16);
- pbus_data_new = (pbus_data_old & ~mask) | set;
+++ /dev/null
-From 9be9a00adfac8118b6d685e71696f83187308c66 Mon Sep 17 00:00:00 2001
-Message-ID: <9be9a00adfac8118b6d685e71696f83187308c66.1715125851.git.daniel@makrotopia.org>
-Date: Tue, 7 May 2024 22:43:30 +0100
-Subject: [PATCH net] net: phy: air_en8811h: reset netdev rules when LED is set
- manually
-
-Setting LED_OFF via the brightness_set should deactivate hw control,
-so make sure netdev trigger rules also get cleared in that case.
-
-Fixes: 71e79430117d ("net: phy: air_en8811h: Add the Airoha EN8811H PHY driver")
----
-This is basically a stop-gap measure until unified LED handling has
-been implemented accross all MediaTek and Airoha PHYs.
-See also
-
- drivers/net/phy/air_en8811h.c | 4 ++++
- 1 file changed, 4 insertions(+)
-
---- a/drivers/net/phy/air_en8811h.c
-+++ b/drivers/net/phy/air_en8811h.c
-@@ -544,6 +544,10 @@ static int air_hw_led_on_set(struct phy_
-
- changed |= (priv->led[index].rules != 0);
-
-+ /* clear netdev trigger rules in case LED_OFF has been set */
-+ if (!on)
-+ priv->led[index].rules = 0;
-+
- if (changed)
- return phy_modify_mmd(phydev, MDIO_MMD_VEND2,
- AIR_PHY_LED_ON(index),
+++ /dev/null
-From ec18a2a83b8b9f7e39c80105ea148c769c46227b Mon Sep 17 00:00:00 2001
-Date: Wed, 17 Jan 2024 16:17:36 +0100
-Subject: [PATCH] dt-bindings: leds: Add FUNCTION defines for per-band WLANs
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Most wireless routers and access points can operate in multiple bands
-simultaneously. Vendors often equip their devices with per-band LEDs.
-
-Add defines for those very common functions to allow cleaner & clearer
-bindings.
-
----
- include/dt-bindings/leds/common.h | 3 +++
- 1 file changed, 3 insertions(+)
-
---- a/include/dt-bindings/leds/common.h
-+++ b/include/dt-bindings/leds/common.h
-@@ -101,6 +101,9 @@
- #define LED_FUNCTION_USB "usb"
- #define LED_FUNCTION_WAN "wan"
- #define LED_FUNCTION_WLAN "wlan"
-+#define LED_FUNCTION_WLAN_2GHZ "wlan-2ghz"
-+#define LED_FUNCTION_WLAN_5GHZ "wlan-5ghz"
-+#define LED_FUNCTION_WLAN_6GHZ "wlan-6ghz"
- #define LED_FUNCTION_WPS "wps"
-
- #endif /* __DT_BINDINGS_LEDS_H */
+++ /dev/null
-From 64e558500d2d04878b8a6d6578850c475171d6ba Mon Sep 17 00:00:00 2001
-Date: Fri, 23 Feb 2024 12:22:23 +0100
-Subject: [PATCH] dt-bindings: leds: Add LED_FUNCTION_WAN_ONLINE for Internet
- access
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-It's common for routers to have LED indicating link on the WAN port.
-
-Some devices however have an extra LED that's meant to be used if WAN
-connection is actually "online" (there is Internet access available).
-
-It was suggested to add #define for such use case.
-
----
- include/dt-bindings/leds/common.h | 1 +
- 1 file changed, 1 insertion(+)
-
---- a/include/dt-bindings/leds/common.h
-+++ b/include/dt-bindings/leds/common.h
-@@ -100,6 +100,7 @@
- #define LED_FUNCTION_TX "tx"
- #define LED_FUNCTION_USB "usb"
- #define LED_FUNCTION_WAN "wan"
-+#define LED_FUNCTION_WAN_ONLINE "wan-online"
- #define LED_FUNCTION_WLAN "wlan"
- #define LED_FUNCTION_WLAN_2GHZ "wlan-2ghz"
- #define LED_FUNCTION_WLAN_5GHZ "wlan-5ghz"
+++ /dev/null
-From 32596b101f6cd87ab1f6e6a1c2a44c70546dde48 Mon Sep 17 00:00:00 2001
-Date: Sat, 18 Nov 2023 00:23:52 +0100
-Subject: [PATCH] ARM: dts: nxp: imx7d-pico: add cpu-supply nodes
-
-The PICO-IMX7D SoM has the usual power supply configuration using
-output sw1a of PF3000 PMIC, which was defined in downstream derivative
-of linux-imx (see link) in the sources for "Android Things" devkit.
-It is required to support CPU frequency scaling.
-
-Map the respective "cpu-supply" nodes of each core to sw1a of the PMIC.
-
-Enabling them causes cpufreq-dt, and imx-thermal drivers to probe
-successfully, and CPU frequency scaling to function.
-
-Link: https://android.googlesource.com/platform/hardware/bsp/kernel/nxp/imx-v4.1/+/o-iot-preview-5/arch/arm/boot/dts/imx7d-pico.dtsi#849
-
----
- arch/arm/boot/dts/nxp/imx/imx7d-pico.dtsi | 8 ++++++++
- 1 file changed, 8 insertions(+)
-
---- a/arch/arm/boot/dts/nxp/imx/imx7d-pico.dtsi
-+++ b/arch/arm/boot/dts/nxp/imx/imx7d-pico.dtsi
-@@ -108,6 +108,14 @@
- assigned-clock-rates = <0>, <32768>;
- };
-
-+&cpu0 {
-+ cpu-supply = <&sw1a_reg>;
-+};
-+
-+&cpu1 {
-+ cpu-supply = <&sw1a_reg>;
-+};
-+
- &ecspi3 {
- cs-gpios = <&gpio4 11 GPIO_ACTIVE_LOW>;
- pinctrl-names = "default";
+++ /dev/null
-From 7d36c3573391dcf0da089298a4b5a25c39f7289d Mon Sep 17 00:00:00 2001
-Date: Sat, 23 Mar 2024 16:36:09 +0900
-Subject: [PATCH] dt-bindings: leds: Add LED_FUNCTION_MOBILE for mobile network
-
-Add LED_FUNCTION_MOBILE for LEDs that indicate status of mobile network
-connection. This is useful to distinguish those LEDs from LEDs that
-indicates status of wired "wan" connection.
-
-example (on stock fw):
-
-IIJ SA-W2 has "Mobile" LEDs that indicate status (no signal, too low,
-low, good) of mobile network connection via dongle connected to USB
-port.
-
-- no signal: (none, turned off)
-- too low: green:mobile & red:mobile (amber, blink)
-- low: green:mobile & red:mobile (amber, turned on)
-- good: green:mobile (turned on)
-
----
- include/dt-bindings/leds/common.h | 1 +
- 1 file changed, 1 insertion(+)
-
---- a/include/dt-bindings/leds/common.h
-+++ b/include/dt-bindings/leds/common.h
-@@ -90,6 +90,7 @@
- #define LED_FUNCTION_INDICATOR "indicator"
- #define LED_FUNCTION_LAN "lan"
- #define LED_FUNCTION_MAIL "mail"
-+#define LED_FUNCTION_MOBILE "mobile"
- #define LED_FUNCTION_MTD "mtd"
- #define LED_FUNCTION_PANIC "panic"
- #define LED_FUNCTION_PROGRAMMING "programming"
+++ /dev/null
-From 77b9f2d6fd9bf34ec810de6bdad42d7d0a47d31b Mon Sep 17 00:00:00 2001
-Date: Sat, 23 Mar 2024 16:36:10 +0900
-Subject: [PATCH] dt-bindings: leds: Add LED_FUNCTION_SPEED_* for link speed on
- LAN/WAN
-
-Add LED_FUNCTION_SPEED_LAN and LED_FUNCTION_SPEED_WAN for LEDs that
-indicate link speed of ethernet ports on LAN/WAN. This is useful to
-distinguish those LEDs from LEDs that indicate link status (up/down).
-
-example:
-
-Fortinet FortiGate 30E/50E have LEDs that indicate link speed on each
-of the ethernet ports in addition to LEDs that indicate link status
-(up/down).
-
-- 1000 Mbps: green:speed-(lan|wan)-N
-- 100 Mbps: amber:speed-(lan|wan)-N
-- 10 Mbps: (none, turned off)
-
----
- include/dt-bindings/leds/common.h | 2 ++
- 1 file changed, 2 insertions(+)
-
---- a/include/dt-bindings/leds/common.h
-+++ b/include/dt-bindings/leds/common.h
-@@ -96,6 +96,8 @@
- #define LED_FUNCTION_PROGRAMMING "programming"
- #define LED_FUNCTION_RX "rx"
- #define LED_FUNCTION_SD "sd"
-+#define LED_FUNCTION_SPEED_LAN "speed-lan"
-+#define LED_FUNCTION_SPEED_WAN "speed-wan"
- #define LED_FUNCTION_STANDBY "standby"
- #define LED_FUNCTION_TORCH "torch"
- #define LED_FUNCTION_TX "tx"
+++ /dev/null
-From d6b2b694dd536d16566424c395d5642783ed6f34 Mon Sep 17 00:00:00 2001
-Date: Mon, 29 Apr 2024 17:02:43 +0300
-Subject: [PATCH] xhci: pci: Use PCI_VENDOR_ID_RENESAS
-
-Instead of plain hexadecimal, use already defined PCI_VENDOR_ID_RENESAS.
-
----
- drivers/usb/host/xhci-pci.c | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
---- a/drivers/usb/host/xhci-pci.c
-+++ b/drivers/usb/host/xhci-pci.c
-@@ -991,10 +991,10 @@ static const struct xhci_driver_data ren
-
- /* PCI driver selection metadata; PCI hotplugging uses this */
- static const struct pci_device_id pci_ids[] = {
-- { PCI_DEVICE(0x1912, 0x0014),
-+ { PCI_DEVICE(PCI_VENDOR_ID_RENESAS, 0x0014),
- .driver_data = (unsigned long)&reneses_data,
- },
-- { PCI_DEVICE(0x1912, 0x0015),
-+ { PCI_DEVICE(PCI_VENDOR_ID_RENESAS, 0x0015),
- .driver_data = (unsigned long)&reneses_data,
- },
- /* handle any USB 3.0 xHCI controller */
+++ /dev/null
-From 9fdce69f674e49be669e97919d24b1ab5d2c9684 Mon Sep 17 00:00:00 2001
-Date: Tue, 11 Jun 2024 17:53:37 -0700
-Subject: [PATCH] usb: host: add missing MODULE_DESCRIPTION() macros
-
-With ARCH=x86, make allmodconfig && make W=1 C=1 reports:
-WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/usb/host/ohci-exynos.o
-WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/usb/host/xhci-pci-renesas.o
-
-Add the missing invocations of the MODULE_DESCRIPTION() macro.
-
----
- drivers/usb/host/ohci-exynos.c | 1 +
- drivers/usb/host/xhci-pci-renesas.c | 1 +
- 2 files changed, 2 insertions(+)
-
---- a/drivers/usb/host/ohci-exynos.c
-+++ b/drivers/usb/host/ohci-exynos.c
-@@ -308,4 +308,5 @@ module_exit(ohci_exynos_cleanup);
-
- MODULE_ALIAS("platform:exynos-ohci");
-+MODULE_DESCRIPTION("OHCI support for Samsung S5P/Exynos SoC Series");
- MODULE_LICENSE("GPL v2");
---- a/drivers/usb/host/xhci-pci-renesas.c
-+++ b/drivers/usb/host/xhci-pci-renesas.c
-@@ -628,4 +628,5 @@ exit:
- }
- EXPORT_SYMBOL_GPL(renesas_xhci_check_request_fw);
-
-+MODULE_DESCRIPTION("Support for Renesas xHCI controller with firmware");
- MODULE_LICENSE("GPL v2");
+++ /dev/null
-From 25f51b76f90f10f9bf2fbc05fc51cf685da7ccad Mon Sep 17 00:00:00 2001
-Date: Wed, 31 Jul 2024 22:32:29 +0200
-Subject: [PATCH] xhci-pci: Make xhci-pci-renesas a proper modular driver
-
-If CONFIG_USB_XHCI_PCI_RENESAS is enabled, xhci-pci conditionally
-calls into the xhci-pci-renesas module, which means both modules must
-be loaded to use any xHCI PCI controller.
-
-The MODULE_FIRMWARE declaration in the base xhci-pci module causes
-initramfs-tools to check for and warn about missing firmware for the
-Renesas xHCI controllers, when any xHCI PCI controller is present.
-And because of the previous oddity, simply moving this declaration to
-xhci-pci-renesas wouldn't help.
-
-To fix this, reverse the relationship between the modules:
-
-- Remove the quirk for the Renesas xHCIs, and the driver_data
- structure used only for them
-- In xhci-pci:
- - Rename xhci_pci_probe() to xhci_pci_common_probe()
- - Export xhci_pci_common_probe() and xhci_pci_remove()
- - Use a new probe function that rejects the Renesas xHCIs and then
- calls the common probe function
-- In xhci-pci-renesas:
- - Stop exporting renesas_xhci_check_request_fw()
- - Add a probe function that calls renesas_xhci_check_request_fw()
- followed by xhci_pci_common_probe()
- - Add and register a new pci_driver matching only the Renesas xHCIs
- and using its own probe function, but with other operations the
- same as in xhci-pci
-- Make CONFIG_USB_XHCI_PCI_RENESAS depend on CONFIG_USB_XHCI_PCI,
- not the other way around
-
-Finally, move the MODULE_FIRMWARE declaration to xhci-pci-renesas.
-
----
- drivers/usb/host/Kconfig | 2 +-
- drivers/usb/host/xhci-pci-renesas.c | 48 ++++++++++++++++++++----
- drivers/usb/host/xhci-pci.c | 57 ++++++++++-------------------
- drivers/usb/host/xhci-pci.h | 19 +---------
- drivers/usb/host/xhci.h | 2 +-
- 5 files changed, 64 insertions(+), 64 deletions(-)
-
---- a/drivers/usb/host/Kconfig
-+++ b/drivers/usb/host/Kconfig
-@@ -40,11 +40,11 @@ config USB_XHCI_DBGCAP
- config USB_XHCI_PCI
- tristate
- depends on USB_PCI
-- depends on USB_XHCI_PCI_RENESAS || !USB_XHCI_PCI_RENESAS
- default y
-
- config USB_XHCI_PCI_RENESAS
- tristate "Support for additional Renesas xHCI controller with firmware"
-+ depends on USB_XHCI_PCI
- help
- Say 'Y' to enable the support for the Renesas xHCI controller with
- firmware. Make sure you have the firmware for the device and
---- a/drivers/usb/host/xhci-pci-renesas.c
-+++ b/drivers/usb/host/xhci-pci-renesas.c
-@@ -51,6 +51,8 @@
- #define RENESAS_CHIP_ERASE_RETRY 500000 /* 500000 * RENESAS_DELAY ~= 5s */
- #define RENESAS_DELAY 10
-
-+#define RENESAS_FW_NAME "renesas_usb_fw.mem"
-+
- static int renesas_fw_download_image(struct pci_dev *dev,
- const u32 *fw, size_t step, bool rom)
- {
-@@ -574,12 +576,10 @@ exit:
- return err;
- }
-
--int renesas_xhci_check_request_fw(struct pci_dev *pdev,
-- const struct pci_device_id *id)
-+static int renesas_xhci_check_request_fw(struct pci_dev *pdev,
-+ const struct pci_device_id *id)
- {
-- struct xhci_driver_data *driver_data =
-- (struct xhci_driver_data *)id->driver_data;
-- const char *fw_name = driver_data->firmware;
-+ const char fw_name[] = RENESAS_FW_NAME;
- const struct firmware *fw;
- bool has_rom;
- int err;
-@@ -626,7 +626,41 @@ exit:
- release_firmware(fw);
- return err;
- }
--EXPORT_SYMBOL_GPL(renesas_xhci_check_request_fw);
-
--MODULE_DESCRIPTION("Support for Renesas xHCI controller with firmware");
-+static int
-+xhci_pci_renesas_probe(struct pci_dev *dev, const struct pci_device_id *id)
-+{
-+ int retval;
-+
-+ retval = renesas_xhci_check_request_fw(dev, id);
-+ if (retval)
-+ return retval;
-+
-+ return xhci_pci_common_probe(dev, id);
-+}
-+
-+static const struct pci_device_id pci_ids[] = {
-+ { PCI_DEVICE(PCI_VENDOR_ID_RENESAS, 0x0014) },
-+ { PCI_DEVICE(PCI_VENDOR_ID_RENESAS, 0x0015) },
-+ { /* end: all zeroes */ }
-+};
-+MODULE_DEVICE_TABLE(pci, pci_ids);
-+
-+static struct pci_driver xhci_renesas_pci_driver = {
-+ .name = "xhci-pci-renesas",
-+ .id_table = pci_ids,
-+
-+ .probe = xhci_pci_renesas_probe,
-+ .remove = xhci_pci_remove,
-+
-+ .shutdown = usb_hcd_pci_shutdown,
-+ .driver = {
-+ .pm = pm_ptr(&usb_hcd_pci_pm_ops),
-+ },
-+};
-+module_pci_driver(xhci_renesas_pci_driver);
-+
-+MODULE_DESCRIPTION("Renesas xHCI PCI Host Controller Driver");
-+MODULE_FIRMWARE(RENESAS_FW_NAME);
-+MODULE_IMPORT_NS(xhci);
- MODULE_LICENSE("GPL v2");
---- a/drivers/usb/host/xhci-pci.c
-+++ b/drivers/usb/host/xhci-pci.c
-@@ -310,15 +310,6 @@ static int xhci_pci_reinit(struct xhci_h
- static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
- {
- struct pci_dev *pdev = to_pci_dev(dev);
-- struct xhci_driver_data *driver_data;
-- const struct pci_device_id *id;
--
-- id = pci_match_id(to_pci_driver(pdev->dev.driver)->id_table, pdev);
--
-- if (id && id->driver_data) {
-- driver_data = (struct xhci_driver_data *)id->driver_data;
-- xhci->quirks |= driver_data->quirks;
-- }
-
- /* Look for vendor-specific quirks */
- if (pdev->vendor == PCI_VENDOR_ID_FRESCO_LOGIC &&
-@@ -668,21 +659,13 @@ static int xhci_pci_update_hub_device(st
- * We need to register our own PCI probe function (instead of the USB core's
- * function) in order to create a second roothub under xHCI.
- */
--static int xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
-+int xhci_pci_common_probe(struct pci_dev *dev, const struct pci_device_id *id)
- {
- int retval;
- struct xhci_hcd *xhci;
- struct usb_hcd *hcd;
-- struct xhci_driver_data *driver_data;
- struct reset_control *reset;
-
-- driver_data = (struct xhci_driver_data *)id->driver_data;
-- if (driver_data && driver_data->quirks & XHCI_RENESAS_FW_QUIRK) {
-- retval = renesas_xhci_check_request_fw(dev, id);
-- if (retval)
-- return retval;
-- }
--
- reset = devm_reset_control_get_optional_exclusive(&dev->dev, NULL);
- if (IS_ERR(reset))
- return PTR_ERR(reset);
-@@ -747,8 +730,24 @@ put_runtime_pm:
- pm_runtime_put_noidle(&dev->dev);
- return retval;
- }
-+EXPORT_SYMBOL_NS_GPL(xhci_pci_common_probe, xhci);
-+
-+static const struct pci_device_id pci_ids_reject[] = {
-+ /* handled by xhci-pci-renesas */
-+ { PCI_DEVICE(PCI_VENDOR_ID_RENESAS, 0x0014) },
-+ { PCI_DEVICE(PCI_VENDOR_ID_RENESAS, 0x0015) },
-+ { /* end: all zeroes */ }
-+};
-+
-+static int xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
-+{
-+ if (pci_match_id(pci_ids_reject, dev))
-+ return -ENODEV;
-+
-+ return xhci_pci_common_probe(dev, id);
-+}
-
--static void xhci_pci_remove(struct pci_dev *dev)
-+void xhci_pci_remove(struct pci_dev *dev)
- {
- struct xhci_hcd *xhci;
- bool set_power_d3;
-@@ -775,6 +774,7 @@ static void xhci_pci_remove(struct pci_d
- if (set_power_d3)
- pci_set_power_state(dev, PCI_D3hot);
- }
-+EXPORT_SYMBOL_NS_GPL(xhci_pci_remove, xhci);
-
- /*
- * In some Intel xHCI controllers, in order to get D3 working,
-@@ -984,19 +984,8 @@ static void xhci_pci_shutdown(struct usb
-
- /*-------------------------------------------------------------------------*/
-
--static const struct xhci_driver_data reneses_data = {
-- .quirks = XHCI_RENESAS_FW_QUIRK,
-- .firmware = "renesas_usb_fw.mem",
--};
--
- /* PCI driver selection metadata; PCI hotplugging uses this */
- static const struct pci_device_id pci_ids[] = {
-- { PCI_DEVICE(PCI_VENDOR_ID_RENESAS, 0x0014),
-- .driver_data = (unsigned long)&reneses_data,
-- },
-- { PCI_DEVICE(PCI_VENDOR_ID_RENESAS, 0x0015),
-- .driver_data = (unsigned long)&reneses_data,
-- },
- /* handle any USB 3.0 xHCI controller */
- { PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_USB_XHCI, ~0),
- },
-@@ -1004,14 +993,6 @@ static const struct pci_device_id pci_id
- };
- MODULE_DEVICE_TABLE(pci, pci_ids);
-
--/*
-- * Without CONFIG_USB_XHCI_PCI_RENESAS renesas_xhci_check_request_fw() won't
-- * load firmware, so don't encumber the xhci-pci driver with it.
-- */
--#if IS_ENABLED(CONFIG_USB_XHCI_PCI_RENESAS)
--MODULE_FIRMWARE("renesas_usb_fw.mem");
--#endif
--
- /* pci driver glue; this is a "new style" PCI driver module */
- static struct pci_driver xhci_pci_driver = {
- .name = hcd_name,
---- a/drivers/usb/host/xhci-pci.h
-+++ b/drivers/usb/host/xhci-pci.h
-@@ -4,22 +4,7 @@
- #ifndef XHCI_PCI_H
- #define XHCI_PCI_H
-
--#if IS_ENABLED(CONFIG_USB_XHCI_PCI_RENESAS)
--int renesas_xhci_check_request_fw(struct pci_dev *dev,
-- const struct pci_device_id *id);
--
--#else
--static int renesas_xhci_check_request_fw(struct pci_dev *dev,
-- const struct pci_device_id *id)
--{
-- return 0;
--}
--
--#endif
--
--struct xhci_driver_data {
-- u64 quirks;
-- const char *firmware;
--};
-+int xhci_pci_common_probe(struct pci_dev *dev, const struct pci_device_id *id);
-+void xhci_pci_remove(struct pci_dev *dev);
-
- #endif
---- a/drivers/usb/host/xhci.h
-+++ b/drivers/usb/host/xhci.h
-@@ -1645,7 +1645,7 @@ struct xhci_hcd {
- #define XHCI_DEFAULT_PM_RUNTIME_ALLOW BIT_ULL(33)
- #define XHCI_RESET_PLL_ON_DISCONNECT BIT_ULL(34)
- #define XHCI_SNPS_BROKEN_SUSPEND BIT_ULL(35)
--#define XHCI_RENESAS_FW_QUIRK BIT_ULL(36)
-+/* Reserved. It was XHCI_RENESAS_FW_QUIRK */
- #define XHCI_SKIP_PHY_INIT BIT_ULL(37)
- #define XHCI_DISABLE_SPARSE BIT_ULL(38)
- #define XHCI_SG_TRB_CACHE_SIZE_QUIRK BIT_ULL(39)
+++ /dev/null
-From 77f5bb150132bbbcd6bc37ffdc80c9e140e373a4 Mon Sep 17 00:00:00 2001
-Date: Wed, 16 Apr 2025 15:27:41 -0700
-Subject: [PATCH] power: supply: sysfs: Remove duplicate NUL termination
-
-GCC 15's new -Wunterminated-string-initialization notices that one of
-the sysfs attr strings would lack the implicit trailing NUL byte during
-initialization:
-
-drivers/power/supply/power_supply_sysfs.c:183:57: warning: initializer-string for array of 'char' truncates NUL terminator but destination lacks 'nonstring' attribute (32 chars into 31 available) [-Wunterminated-string-initialization]
- 183 | POWER_SUPPLY_ATTR(CHARGE_CONTROL_START_THRESHOLD),
- | ^
-drivers/power/supply/power_supply_sysfs.c:36:23: note: in definition of macro '_POWER_SUPPLY_ATTR'
- 36 | .attr_name = #_name "\0", \
- | ^~~~~
-drivers/power/supply/power_supply_sysfs.c:183:9: note: in expansion of macro 'POWER_SUPPLY_ATTR'
- 183 | POWER_SUPPLY_ATTR(CHARGE_CONTROL_START_THRESHOLD),
- | ^~~~~~~~~~~~~~~~~
-
-However, the macro used was explicitly adding a trailing NUL byte (which
-is not needed). Remove this to avoid the GCC warning. No binary
-differences are seen after this change (there was always run for a NUL
-byte, it's just that the _second_ NUL byte was getting truncated).
-
-
---- a/drivers/power/supply/power_supply_sysfs.c
-+++ b/drivers/power/supply/power_supply_sysfs.c
-@@ -32,7 +32,7 @@ struct power_supply_attr {
- [POWER_SUPPLY_PROP_ ## _name] = \
- { \
- .prop_name = #_name, \
-- .attr_name = #_name "\0", \
-+ .attr_name = #_name, \
- .text_values = _text, \
- .text_values_len = _len, \
- }
+++ /dev/null
-From 6ce402327a6fb714a9f40a0bb59bcbfe383839a5 Mon Sep 17 00:00:00 2001
-Date: Tue, 4 Jun 2024 18:43:43 +0200
-Subject: [PATCH] hwmon: g672: add support for g761
-
-Add support for g761 PWM Fan Controller.
-
-The g761 is a copy of the g763 with the only difference of supporting
-and internal clock. The internal clock is used if no clocks property is
-defined in device node and in such case the required bit is enabled and
-clock handling is skipped.
-
-The internal clock oscillator runs at 31KHz.
-
----
- drivers/hwmon/g762.c | 33 ++++++++++++++++++++++++++++++---
- 1 file changed, 30 insertions(+), 3 deletions(-)
-
---- a/drivers/hwmon/g762.c
-+++ b/drivers/hwmon/g762.c
-@@ -69,6 +69,7 @@ enum g762_regs {
- #define G762_REG_FAN_CMD1_PWM_POLARITY 0x02 /* PWM polarity */
- #define G762_REG_FAN_CMD1_PULSE_PER_REV 0x01 /* pulse per fan revolution */
-
-+#define G761_REG_FAN_CMD2_FAN_CLOCK 0x20 /* choose internal clock*/
- #define G762_REG_FAN_CMD2_GEAR_MODE_1 0x08 /* fan gear mode */
- #define G762_REG_FAN_CMD2_GEAR_MODE_0 0x04
- #define G762_REG_FAN_CMD2_FAN_STARTV_1 0x02 /* fan startup voltage */
-@@ -115,6 +116,7 @@ enum g762_regs {
-
- struct g762_data {
- struct i2c_client *client;
-+ bool internal_clock;
- struct clk *clk;
-
- /* update mutex */
-@@ -566,6 +568,7 @@ static int do_set_fan_startv(struct devi
-
- #ifdef CONFIG_OF
- static const struct of_device_id g762_dt_match[] = {
-+ { .compatible = "gmt,g761" },
- { .compatible = "gmt,g762" },
- { .compatible = "gmt,g763" },
- { },
-@@ -597,6 +600,21 @@ static int g762_of_clock_enable(struct i
- if (!client->dev.of_node)
- return 0;
-
-+ data = i2c_get_clientdata(client);
-+
-+ /*
-+ * Skip CLK detection and handling if we use internal clock.
-+ * This is only valid for g761.
-+ */
-+ data->internal_clock = of_device_is_compatible(client->dev.of_node,
-+ "gmt,g761") &&
-+ !of_property_present(client->dev.of_node,
-+ "clocks");
-+ if (data->internal_clock) {
-+ do_set_clk_freq(&client->dev, 32768);
-+ return 0;
-+ }
-+
- clk = of_clk_get(client->dev.of_node, 0);
- if (IS_ERR(clk)) {
- dev_err(&client->dev, "failed to get clock\n");
-@@ -616,7 +634,6 @@ static int g762_of_clock_enable(struct i
- goto clk_unprep;
- }
-
-- data = i2c_get_clientdata(client);
- data->clk = clk;
-
- ret = devm_add_action(&client->dev, g762_of_clock_disable, data);
-@@ -1025,16 +1042,26 @@ ATTRIBUTE_GROUPS(g762);
- static inline int g762_fan_init(struct device *dev)
- {
- struct g762_data *data = g762_update_client(dev);
-+ int ret;
-
- if (IS_ERR(data))
- return PTR_ERR(data);
-
-+ /* internal_clock can only be set with compatible g761 */
-+ if (data->internal_clock)
-+ data->fan_cmd2 |= G761_REG_FAN_CMD2_FAN_CLOCK;
-+
- data->fan_cmd1 |= G762_REG_FAN_CMD1_DET_FAN_FAIL;
- data->fan_cmd1 |= G762_REG_FAN_CMD1_DET_FAN_OOC;
- data->valid = false;
-
-- return i2c_smbus_write_byte_data(data->client, G762_REG_FAN_CMD1,
-- data->fan_cmd1);
-+ ret = i2c_smbus_write_byte_data(data->client, G762_REG_FAN_CMD1,
-+ data->fan_cmd1);
-+ if (ret)
-+ return ret;
-+
-+ return i2c_smbus_write_byte_data(data->client, G762_REG_FAN_CMD2,
-+ data->fan_cmd2);
- }
-
- static int g762_probe(struct i2c_client *client)
+++ /dev/null
-From a64c3c1357275b1fd61bc9734f638cdb5d8a8bbb Mon Sep 17 00:00:00 2001
-Date: Mon, 18 Sep 2023 18:11:02 +0200
-Subject: [PATCH 4/6] leds: turris-omnia: Make set_brightness() more efficient
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Implement caching of the LED color and state values that are sent to MCU
-in order to make the set_brightness() operation more efficient by
-avoiding I2C transactions which are not needed.
-
-On Turris Omnia's MCU, which acts as the RGB LED controller, each LED
-has a RGB color, and a ON/OFF state, which are configurable via I2C
-commands CMD_LED_COLOR and CMD_LED_STATE.
-
-The CMD_LED_COLOR command sends 5 bytes and the CMD_LED_STATE command 2
-bytes over the I2C bus, which operates at 100 kHz. With I2C overhead
-this allows ~1670 color changing commands and ~3200 state changing
-commands per second (or around 1000 color + state changes per second).
-This may seem more than enough, but the issue is that the I2C bus is
-shared with another peripheral, the MCU. The MCU exposes an interrupt
-interface, and it can trigger hundreds of interrupts per second. Each
-time, we need to read the interrupt state register over this I2C bus.
-Whenever we are sending a LED color/state changing command, the
-interrupt reading is waiting.
-
-Currently, every time LED brightness or LED multi intensity is changed,
-we send a CMD_LED_STATE command, and if the computed color (brightness
-adjusted multi_intensity) is non-zero, we also send a CMD_LED_COLOR
-command.
-
-Consider for example the situation when we have a netdev trigger enabled
-for a LED. The netdev trigger does not change the LED color, only the
-brightness (either to 0 or to currently configured brightness), and so
-there is no need to send the CMD_LED_COLOR command. But each change of
-brightness to 0 sends one CMD_LED_STATE command, and each change of
-brightness to max_brightness sends one CMD_LED_STATE command and one
-CMD_LED_COLOR command:
- set_brightness(0) -> CMD_LED_STATE
- set_brightness(255) -> CMD_LED_STATE + CMD_LED_COLOR
- (unnecessary)
-
-We can avoid the unnecessary I2C transactions if we cache the values of
-state and color that are sent to the controller. If the color does not
-change from the one previously sent, there is no need to do the
-CMD_LED_COLOR I2C transaction, and if the state does not change, there
-is no need to do the CMD_LED_STATE transaction.
-
-Because we need to make sure that our cached values are consistent with
-the controller state, add explicit setting of the LED color to white at
-probe time (this is the default setting when MCU resets, but does not
-necessarily need to be the case, for example if U-Boot played with the
-LED colors).
-
----
- drivers/leds/leds-turris-omnia.c | 96 ++++++++++++++++++++++++++------
- 1 file changed, 78 insertions(+), 18 deletions(-)
-
---- a/drivers/leds/leds-turris-omnia.c
-+++ b/drivers/leds/leds-turris-omnia.c
-@@ -30,6 +30,8 @@
- struct omnia_led {
- struct led_classdev_mc mc_cdev;
- struct mc_subled subled_info[OMNIA_LED_NUM_CHANNELS];
-+ u8 cached_channels[OMNIA_LED_NUM_CHANNELS];
-+ bool on;
- int reg;
- };
-
-@@ -72,36 +74,82 @@ static int omnia_cmd_read_u8(const struc
- return -EIO;
- }
-
-+static int omnia_led_send_color_cmd(const struct i2c_client *client,
-+ struct omnia_led *led)
-+{
-+ char cmd[5];
-+ int ret;
-+
-+ cmd[0] = CMD_LED_COLOR;
-+ cmd[1] = led->reg;
-+ cmd[2] = led->subled_info[0].brightness;
-+ cmd[3] = led->subled_info[1].brightness;
-+ cmd[4] = led->subled_info[2].brightness;
-+
-+ /* Send the color change command */
-+ ret = i2c_master_send(client, cmd, 5);
-+ if (ret < 0)
-+ return ret;
-+
-+ /* Cache the RGB channel brightnesses */
-+ for (int i = 0; i < OMNIA_LED_NUM_CHANNELS; ++i)
-+ led->cached_channels[i] = led->subled_info[i].brightness;
-+
-+ return 0;
-+}
-+
-+/* Determine if the computed RGB channels are different from the cached ones */
-+static bool omnia_led_channels_changed(struct omnia_led *led)
-+{
-+ for (int i = 0; i < OMNIA_LED_NUM_CHANNELS; ++i)
-+ if (led->subled_info[i].brightness != led->cached_channels[i])
-+ return true;
-+
-+ return false;
-+}
-+
- static int omnia_led_brightness_set_blocking(struct led_classdev *cdev,
- enum led_brightness brightness)
- {
- struct led_classdev_mc *mc_cdev = lcdev_to_mccdev(cdev);
- struct omnia_leds *leds = dev_get_drvdata(cdev->dev->parent);
- struct omnia_led *led = to_omnia_led(mc_cdev);
-- u8 buf[5], state;
-- int ret;
-+ int err = 0;
-
- mutex_lock(&leds->lock);
-
-- led_mc_calc_color_components(&led->mc_cdev, brightness);
-+ /*
-+ * Only recalculate RGB brightnesses from intensities if brightness is
-+ * non-zero. Otherwise we won't be using them and we can save ourselves
-+ * some software divisions (Omnia's CPU does not implement the division
-+ * instruction).
-+ */
-+ if (brightness) {
-+ led_mc_calc_color_components(mc_cdev, brightness);
-+
-+ /*
-+ * Send color command only if brightness is non-zero and the RGB
-+ * channel brightnesses changed.
-+ */
-+ if (omnia_led_channels_changed(led))
-+ err = omnia_led_send_color_cmd(leds->client, led);
-+ }
-
-- buf[0] = CMD_LED_COLOR;
-- buf[1] = led->reg;
-- buf[2] = mc_cdev->subled_info[0].brightness;
-- buf[3] = mc_cdev->subled_info[1].brightness;
-- buf[4] = mc_cdev->subled_info[2].brightness;
--
-- state = CMD_LED_STATE_LED(led->reg);
-- if (buf[2] || buf[3] || buf[4])
-- state |= CMD_LED_STATE_ON;
--
-- ret = omnia_cmd_write_u8(leds->client, CMD_LED_STATE, state);
-- if (ret >= 0 && (state & CMD_LED_STATE_ON))
-- ret = i2c_master_send(leds->client, buf, 5);
-+ /* Send on/off state change only if (bool)brightness changed */
-+ if (!err && !brightness != !led->on) {
-+ u8 state = CMD_LED_STATE_LED(led->reg);
-+
-+ if (brightness)
-+ state |= CMD_LED_STATE_ON;
-+
-+ err = omnia_cmd_write_u8(leds->client, CMD_LED_STATE, state);
-+ if (!err)
-+ led->on = !!brightness;
-+ }
-
- mutex_unlock(&leds->lock);
-
-- return ret;
-+ return err;
- }
-
- static int omnia_led_register(struct i2c_client *client, struct omnia_led *led,
-@@ -129,11 +177,15 @@ static int omnia_led_register(struct i2c
- }
-
- led->subled_info[0].color_index = LED_COLOR_ID_RED;
-- led->subled_info[0].channel = 0;
- led->subled_info[1].color_index = LED_COLOR_ID_GREEN;
-- led->subled_info[1].channel = 1;
- led->subled_info[2].color_index = LED_COLOR_ID_BLUE;
-- led->subled_info[2].channel = 2;
-+
-+ /* Initial color is white */
-+ for (int i = 0; i < OMNIA_LED_NUM_CHANNELS; ++i) {
-+ led->subled_info[i].intensity = 255;
-+ led->subled_info[i].brightness = 255;
-+ led->subled_info[i].channel = i;
-+ }
-
- led->mc_cdev.subled_info = led->subled_info;
- led->mc_cdev.num_colors = OMNIA_LED_NUM_CHANNELS;
-@@ -162,6 +214,14 @@ static int omnia_led_register(struct i2c
- return ret;
- }
-
-+ /* Set initial color and cache it */
-+ ret = omnia_led_send_color_cmd(client, led);
-+ if (ret < 0) {
-+ dev_err(dev, "Cannot set LED %pOF initial color: %i\n", np,
-+ ret);
-+ return ret;
-+ }
-+
- ret = devm_led_classdev_multicolor_register_ext(dev, &led->mc_cdev,
- &init_data);
- if (ret < 0) {
+++ /dev/null
-From e965e0f6de60874fc0a0caed9a9e0122999e0c7b Mon Sep 17 00:00:00 2001
-Date: Mon, 18 Sep 2023 18:11:03 +0200
-Subject: [PATCH 5/6] leds: turris-omnia: Support HW controlled mode via
- private trigger
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Add support for enabling MCU controlled mode of the Turris Omnia LEDs
-via a LED private trigger called "omnia-mcu". Recall that private LED
-triggers will only be listed in the sysfs trigger file for LEDs that
-support them (currently there is no user of this mechanism).
-
-When in MCU controlled mode, the user can still set LED color, but the
-blinking is done by MCU, which does different things for different LEDs:
-- WAN LED is blinked according to the LED[0] pin of the WAN PHY
-- LAN LEDs are blinked according to the LED[0] output of the
- corresponding port of the LAN switch
-- PCIe LEDs are blinked according to the logical OR of the MiniPCIe port
- LED pins
-
-In the future I want to make the netdev trigger to transparently offload
-the blinking to the HW if user sets compatible settings for the netdev
-trigger (for LEDs associated with network devices).
-There was some work on this already, and hopefully we will be able to
-complete it sometime, but for now there are still multiple blockers for
-this, and even if there weren't, we still would not be able to configure
-HW controlled mode for the LEDs associated with MiniPCIe ports.
-
-In the meantime let's support HW controlled mode via the private LED
-trigger mechanism. If, in the future, we manage to complete the netdev
-trigger offloading, we can still keep this private trigger for backwards
-compatibility, if needed.
-
-We also set "omnia-mcu" to cdev->default_trigger, so that the MCU keeps
-control until the user first wants to take over it. If a different
-default trigger is specified in device-tree via the
-'linux,default-trigger' property, LED class will overwrite
-cdev->default_trigger, and so the DT property will be respected.
-
----
- drivers/leds/Kconfig | 1 +
- drivers/leds/leds-turris-omnia.c | 98 +++++++++++++++++++++++++++++---
- 2 files changed, 91 insertions(+), 8 deletions(-)
-
---- a/drivers/leds/Kconfig
-+++ b/drivers/leds/Kconfig
-@@ -188,6 +188,7 @@ config LEDS_TURRIS_OMNIA
- depends on I2C
- depends on MACH_ARMADA_38X || COMPILE_TEST
- depends on OF
-+ select LEDS_TRIGGERS
- help
- This option enables basic support for the LEDs found on the front
- side of CZ.NIC's Turris Omnia router. There are 12 RGB LEDs on the
---- a/drivers/leds/leds-turris-omnia.c
-+++ b/drivers/leds/leds-turris-omnia.c
-@@ -31,7 +31,7 @@ struct omnia_led {
- struct led_classdev_mc mc_cdev;
- struct mc_subled subled_info[OMNIA_LED_NUM_CHANNELS];
- u8 cached_channels[OMNIA_LED_NUM_CHANNELS];
-- bool on;
-+ bool on, hwtrig;
- int reg;
- };
-
-@@ -120,12 +120,14 @@ static int omnia_led_brightness_set_bloc
-
- /*
- * Only recalculate RGB brightnesses from intensities if brightness is
-- * non-zero. Otherwise we won't be using them and we can save ourselves
-- * some software divisions (Omnia's CPU does not implement the division
-- * instruction).
-+ * non-zero (if it is zero and the LED is in HW blinking mode, we use
-+ * max_brightness as brightness). Otherwise we won't be using them and
-+ * we can save ourselves some software divisions (Omnia's CPU does not
-+ * implement the division instruction).
- */
-- if (brightness) {
-- led_mc_calc_color_components(mc_cdev, brightness);
-+ if (brightness || led->hwtrig) {
-+ led_mc_calc_color_components(mc_cdev, brightness ?:
-+ cdev->max_brightness);
-
- /*
- * Send color command only if brightness is non-zero and the RGB
-@@ -135,8 +137,11 @@ static int omnia_led_brightness_set_bloc
- err = omnia_led_send_color_cmd(leds->client, led);
- }
-
-- /* Send on/off state change only if (bool)brightness changed */
-- if (!err && !brightness != !led->on) {
-+ /*
-+ * Send on/off state change only if (bool)brightness changed and the LED
-+ * is not being blinked by HW.
-+ */
-+ if (!err && !led->hwtrig && !brightness != !led->on) {
- u8 state = CMD_LED_STATE_LED(led->reg);
-
- if (brightness)
-@@ -152,6 +157,71 @@ static int omnia_led_brightness_set_bloc
- return err;
- }
-
-+static struct led_hw_trigger_type omnia_hw_trigger_type;
-+
-+static int omnia_hwtrig_activate(struct led_classdev *cdev)
-+{
-+ struct led_classdev_mc *mc_cdev = lcdev_to_mccdev(cdev);
-+ struct omnia_leds *leds = dev_get_drvdata(cdev->dev->parent);
-+ struct omnia_led *led = to_omnia_led(mc_cdev);
-+ int err = 0;
-+
-+ mutex_lock(&leds->lock);
-+
-+ if (!led->on) {
-+ /*
-+ * If the LED is off (brightness was set to 0), the last
-+ * configured color was not necessarily sent to the MCU.
-+ * Recompute with max_brightness and send if needed.
-+ */
-+ led_mc_calc_color_components(mc_cdev, cdev->max_brightness);
-+
-+ if (omnia_led_channels_changed(led))
-+ err = omnia_led_send_color_cmd(leds->client, led);
-+ }
-+
-+ if (!err) {
-+ /* Put the LED into MCU controlled mode */
-+ err = omnia_cmd_write_u8(leds->client, CMD_LED_MODE,
-+ CMD_LED_MODE_LED(led->reg));
-+ if (!err)
-+ led->hwtrig = true;
-+ }
-+
-+ mutex_unlock(&leds->lock);
-+
-+ return err;
-+}
-+
-+static void omnia_hwtrig_deactivate(struct led_classdev *cdev)
-+{
-+ struct omnia_leds *leds = dev_get_drvdata(cdev->dev->parent);
-+ struct omnia_led *led = to_omnia_led(lcdev_to_mccdev(cdev));
-+ int err;
-+
-+ mutex_lock(&leds->lock);
-+
-+ led->hwtrig = false;
-+
-+ /* Put the LED into software mode */
-+ err = omnia_cmd_write_u8(leds->client, CMD_LED_MODE,
-+ CMD_LED_MODE_LED(led->reg) |
-+ CMD_LED_MODE_USER);
-+
-+ mutex_unlock(&leds->lock);
-+
-+ if (err < 0)
-+ dev_err(cdev->dev, "Cannot put LED to software mode: %i\n",
-+ err);
-+}
-+
-+static struct led_trigger omnia_hw_trigger = {
-+ .name = "omnia-mcu",
-+ .activate = omnia_hwtrig_activate,
-+ .deactivate = omnia_hwtrig_deactivate,
-+ .trigger_type = &omnia_hw_trigger_type,
-+};
-+
- static int omnia_led_register(struct i2c_client *client, struct omnia_led *led,
- struct device_node *np)
- {
-@@ -195,6 +265,12 @@ static int omnia_led_register(struct i2c
- cdev = &led->mc_cdev.led_cdev;
- cdev->max_brightness = 255;
- cdev->brightness_set_blocking = omnia_led_brightness_set_blocking;
-+ cdev->trigger_type = &omnia_hw_trigger_type;
-+ /*
-+ * Use the omnia-mcu trigger as the default trigger. It may be rewritten
-+ * by LED class from the linux,default-trigger property.
-+ */
-+ cdev->default_trigger = omnia_hw_trigger.name;
-
- /* put the LED into software mode */
- ret = omnia_cmd_write_u8(client, CMD_LED_MODE,
-@@ -308,6 +384,12 @@ static int omnia_leds_probe(struct i2c_c
-
- mutex_init(&leds->lock);
-
-+ ret = devm_led_trigger_register(dev, &omnia_hw_trigger);
-+ if (ret < 0) {
-+ dev_err(dev, "Cannot register private LED trigger: %d\n", ret);
-+ return ret;
-+ }
-+
- led = &leds->leds[0];
- for_each_available_child_of_node(np, child) {
- ret = omnia_led_register(client, led, child);
+++ /dev/null
-From 0efb3f9609d3de5a7d8c31e3835d7eb3e6adce79 Mon Sep 17 00:00:00 2001
-Date: Mon, 18 Sep 2023 18:11:04 +0200
-Subject: [PATCH 6/6] leds: turris-omnia: Add support for enabling/disabling HW
- gamma correction
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-If the MCU on Turris Omnia is running newer firmware versions, the LED
-controller supports RGB gamma correction (and enables it by default for
-newer boards).
-
-Determine whether the gamma correction setting feature is supported and
-add the ability to set it via sysfs attribute file.
-
----
- .../sysfs-class-led-driver-turris-omnia | 14 ++
- drivers/leds/leds-turris-omnia.c | 137 +++++++++++++++---
- 2 files changed, 134 insertions(+), 17 deletions(-)
-
---- a/Documentation/ABI/testing/sysfs-class-led-driver-turris-omnia
-+++ b/Documentation/ABI/testing/sysfs-class-led-driver-turris-omnia
-@@ -12,3 +12,17 @@ Description: (RW) On the front panel of
- able to change this setting from software.
-
- Format: %i
-+
-+What: /sys/class/leds/<led>/device/gamma_correction
-+Date: August 2023
-+KernelVersion: 6.6
-+Description: (RW) Newer versions of the microcontroller firmware of the
-+ Turris Omnia router support gamma correction for the RGB LEDs.
-+ This feature can be enabled/disabled by writing to this file.
-+
-+ If the feature is not supported because the MCU firmware is too
-+ old, the file always reads as 0, and writing to the file results
-+ in the EOPNOTSUPP error.
-+
-+ Format: %i
---- a/drivers/leds/leds-turris-omnia.c
-+++ b/drivers/leds/leds-turris-omnia.c
-@@ -15,17 +15,30 @@
- #define OMNIA_BOARD_LEDS 12
- #define OMNIA_LED_NUM_CHANNELS 3
-
--#define CMD_LED_MODE 3
--#define CMD_LED_MODE_LED(l) ((l) & 0x0f)
--#define CMD_LED_MODE_USER 0x10
--
--#define CMD_LED_STATE 4
--#define CMD_LED_STATE_LED(l) ((l) & 0x0f)
--#define CMD_LED_STATE_ON 0x10
--
--#define CMD_LED_COLOR 5
--#define CMD_LED_SET_BRIGHTNESS 7
--#define CMD_LED_GET_BRIGHTNESS 8
-+/* MCU controller commands at I2C address 0x2a */
-+#define OMNIA_MCU_I2C_ADDR 0x2a
-+
-+#define CMD_GET_STATUS_WORD 0x01
-+#define STS_FEATURES_SUPPORTED BIT(2)
-+
-+#define CMD_GET_FEATURES 0x10
-+#define FEAT_LED_GAMMA_CORRECTION BIT(5)
-+
-+/* LED controller commands at I2C address 0x2b */
-+#define CMD_LED_MODE 0x03
-+#define CMD_LED_MODE_LED(l) ((l) & 0x0f)
-+#define CMD_LED_MODE_USER 0x10
-+
-+#define CMD_LED_STATE 0x04
-+#define CMD_LED_STATE_LED(l) ((l) & 0x0f)
-+#define CMD_LED_STATE_ON 0x10
-+
-+#define CMD_LED_COLOR 0x05
-+#define CMD_LED_SET_BRIGHTNESS 0x07
-+#define CMD_LED_GET_BRIGHTNESS 0x08
-+
-+#define CMD_SET_GAMMA_CORRECTION 0x30
-+#define CMD_GET_GAMMA_CORRECTION 0x31
-
- struct omnia_led {
- struct led_classdev_mc mc_cdev;
-@@ -40,6 +53,7 @@ struct omnia_led {
- struct omnia_leds {
- struct i2c_client *client;
- struct mutex lock;
-+ bool has_gamma_correction;
- struct omnia_led leds[];
- };
-
-@@ -50,30 +64,42 @@ static int omnia_cmd_write_u8(const stru
- return i2c_master_send(client, buf, sizeof(buf));
- }
-
--static int omnia_cmd_read_u8(const struct i2c_client *client, u8 cmd)
-+static int omnia_cmd_read_raw(struct i2c_adapter *adapter, u8 addr, u8 cmd,
-+ void *reply, size_t len)
- {
- struct i2c_msg msgs[2];
-- u8 reply;
- int ret;
-
-- msgs[0].addr = client->addr;
-+ msgs[0].addr = addr;
- msgs[0].flags = 0;
- msgs[0].len = 1;
- msgs[0].buf = &cmd;
-- msgs[1].addr = client->addr;
-+ msgs[1].addr = addr;
- msgs[1].flags = I2C_M_RD;
-- msgs[1].len = 1;
-- msgs[1].buf = &reply;
-+ msgs[1].len = len;
-+ msgs[1].buf = reply;
-
-- ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
-+ ret = i2c_transfer(adapter, msgs, ARRAY_SIZE(msgs));
- if (likely(ret == ARRAY_SIZE(msgs)))
-- return reply;
-+ return len;
- else if (ret < 0)
- return ret;
- else
- return -EIO;
- }
-
-+static int omnia_cmd_read_u8(const struct i2c_client *client, u8 cmd)
-+{
-+ u8 reply;
-+ int ret;
-+
-+ ret = omnia_cmd_read_raw(client->adapter, client->addr, cmd, &reply, 1);
-+ if (ret < 0)
-+ return ret;
-+
-+ return reply;
-+}
-+
- static int omnia_led_send_color_cmd(const struct i2c_client *client,
- struct omnia_led *led)
- {
-@@ -352,12 +378,74 @@ static ssize_t brightness_store(struct d
- }
- static DEVICE_ATTR_RW(brightness);
-
-+static ssize_t gamma_correction_show(struct device *dev,
-+ struct device_attribute *a, char *buf)
-+{
-+ struct i2c_client *client = to_i2c_client(dev);
-+ struct omnia_leds *leds = i2c_get_clientdata(client);
-+ int ret;
-+
-+ if (leds->has_gamma_correction) {
-+ ret = omnia_cmd_read_u8(client, CMD_GET_GAMMA_CORRECTION);
-+ if (ret < 0)
-+ return ret;
-+ } else {
-+ ret = 0;
-+ }
-+
-+ return sysfs_emit(buf, "%d\n", !!ret);
-+}
-+
-+static ssize_t gamma_correction_store(struct device *dev,
-+ struct device_attribute *a,
-+ const char *buf, size_t count)
-+{
-+ struct i2c_client *client = to_i2c_client(dev);
-+ struct omnia_leds *leds = i2c_get_clientdata(client);
-+ bool val;
-+ int ret;
-+
-+ if (!leds->has_gamma_correction)
-+ return -EOPNOTSUPP;
-+
-+ if (kstrtobool(buf, &val) < 0)
-+ return -EINVAL;
-+
-+ ret = omnia_cmd_write_u8(client, CMD_SET_GAMMA_CORRECTION, val);
-+
-+ return ret < 0 ? ret : count;
-+}
-+static DEVICE_ATTR_RW(gamma_correction);
-+
- static struct attribute *omnia_led_controller_attrs[] = {
- &dev_attr_brightness.attr,
-+ &dev_attr_gamma_correction.attr,
- NULL,
- };
- ATTRIBUTE_GROUPS(omnia_led_controller);
-
-+static int omnia_mcu_get_features(const struct i2c_client *client)
-+{
-+ u16 reply;
-+ int err;
-+
-+ err = omnia_cmd_read_raw(client->adapter, OMNIA_MCU_I2C_ADDR,
-+ CMD_GET_STATUS_WORD, &reply, sizeof(reply));
-+ if (err < 0)
-+ return err;
-+
-+ /* Check whether MCU firmware supports the CMD_GET_FEAUTRES command */
-+ if (!(le16_to_cpu(reply) & STS_FEATURES_SUPPORTED))
-+ return 0;
-+
-+ err = omnia_cmd_read_raw(client->adapter, OMNIA_MCU_I2C_ADDR,
-+ CMD_GET_FEATURES, &reply, sizeof(reply));
-+ if (err < 0)
-+ return err;
-+
-+ return le16_to_cpu(reply);
-+}
-+
- static int omnia_leds_probe(struct i2c_client *client)
- {
- struct device *dev = &client->dev;
-@@ -382,6 +470,21 @@ static int omnia_leds_probe(struct i2c_c
- leds->client = client;
- i2c_set_clientdata(client, leds);
-
-+ ret = omnia_mcu_get_features(client);
-+ if (ret < 0) {
-+ dev_err(dev, "Cannot determine MCU supported features: %d\n",
-+ ret);
-+ return ret;
-+ }
-+
-+ leds->has_gamma_correction = ret & FEAT_LED_GAMMA_CORRECTION;
-+ if (!leds->has_gamma_correction) {
-+ dev_info(dev,
-+ "Your board's MCU firmware does not support the LED gamma correction feature.\n");
-+ dev_info(dev,
-+ "Consider upgrading MCU firmware with the omnia-mcutool utility.\n");
-+ }
-+
- mutex_init(&leds->lock);
-
- ret = devm_led_trigger_register(dev, &omnia_hw_trigger);
+++ /dev/null
-From ffec49d391c5f0195360912b216aa24dbc9b53c8 Mon Sep 17 00:00:00 2001
-Date: Mon, 16 Oct 2023 16:15:38 +0200
-Subject: [PATCH] leds: turris-omnia: Fix brightness setting and trigger
- activating
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-I have improperly refactored commits
- 4d5ed2621c24 ("leds: turris-omnia: Make set_brightness() more efficient")
-and
- aaf38273cf76 ("leds: turris-omnia: Support HW controlled mode via private trigger")
-after Lee requested a change in API semantics of the new functions I
-introduced in commit
- 28350bc0ac77 ("leds: turris-omnia: Do not use SMBUS calls").
-
-Before the change, the function omnia_cmd_write_u8() returned 0 on
-success, and afterwards it returned a positive value (number of bytes
-written). The latter version was applied, but the following commits did
-not properly account for this change.
-
-This results in non-functional LED's .brightness_set_blocking() and
-trigger's .activate() methods.
-
-The main reasoning behind the semantics change was that read/write
-methods should return the number of read/written bytes on success.
-It was pointed to me [1] that this is not always true (for example the
-regmap API does not do so), and since the driver never uses this number
-of read/written bytes information, I decided to fix this issue by
-changing the functions to the original semantics (return 0 on success).
-
-
-Fixes: 28350bc0ac77 ("leds: turris-omnia: Do not use SMBUS calls")
----
- drivers/leds/leds-turris-omnia.c | 37 +++++++++++++++++---------------
- 1 file changed, 20 insertions(+), 17 deletions(-)
-
---- a/drivers/leds/leds-turris-omnia.c
-+++ b/drivers/leds/leds-turris-omnia.c
-@@ -60,8 +60,11 @@ struct omnia_leds {
- static int omnia_cmd_write_u8(const struct i2c_client *client, u8 cmd, u8 val)
- {
- u8 buf[2] = { cmd, val };
-+ int ret;
-+
-+ ret = i2c_master_send(client, buf, sizeof(buf));
-
-- return i2c_master_send(client, buf, sizeof(buf));
-+ return ret < 0 ? ret : 0;
- }
-
- static int omnia_cmd_read_raw(struct i2c_adapter *adapter, u8 addr, u8 cmd,
-@@ -81,7 +84,7 @@ static int omnia_cmd_read_raw(struct i2c
-
- ret = i2c_transfer(adapter, msgs, ARRAY_SIZE(msgs));
- if (likely(ret == ARRAY_SIZE(msgs)))
-- return len;
-+ return 0;
- else if (ret < 0)
- return ret;
- else
-@@ -91,11 +94,11 @@ static int omnia_cmd_read_raw(struct i2c
- static int omnia_cmd_read_u8(const struct i2c_client *client, u8 cmd)
- {
- u8 reply;
-- int ret;
-+ int err;
-
-- ret = omnia_cmd_read_raw(client->adapter, client->addr, cmd, &reply, 1);
-- if (ret < 0)
-- return ret;
-+ err = omnia_cmd_read_raw(client->adapter, client->addr, cmd, &reply, 1);
-+ if (err)
-+ return err;
-
- return reply;
- }
-@@ -236,7 +239,7 @@ static void omnia_hwtrig_deactivate(stru
-
- mutex_unlock(&leds->lock);
-
-- if (err < 0)
-+ if (err)
- dev_err(cdev->dev, "Cannot put LED to software mode: %i\n",
- err);
- }
-@@ -302,7 +305,7 @@ static int omnia_led_register(struct i2c
- ret = omnia_cmd_write_u8(client, CMD_LED_MODE,
- CMD_LED_MODE_LED(led->reg) |
- CMD_LED_MODE_USER);
-- if (ret < 0) {
-+ if (ret) {
- dev_err(dev, "Cannot set LED %pOF to software mode: %i\n", np,
- ret);
- return ret;
-@@ -311,7 +314,7 @@ static int omnia_led_register(struct i2c
- /* disable the LED */
- ret = omnia_cmd_write_u8(client, CMD_LED_STATE,
- CMD_LED_STATE_LED(led->reg));
-- if (ret < 0) {
-+ if (ret) {
- dev_err(dev, "Cannot set LED %pOF brightness: %i\n", np, ret);
- return ret;
- }
-@@ -364,7 +367,7 @@ static ssize_t brightness_store(struct d
- {
- struct i2c_client *client = to_i2c_client(dev);
- unsigned long brightness;
-- int ret;
-+ int err;
-
- if (kstrtoul(buf, 10, &brightness))
- return -EINVAL;
-@@ -372,9 +375,9 @@ static ssize_t brightness_store(struct d
- if (brightness > 100)
- return -EINVAL;
-
-- ret = omnia_cmd_write_u8(client, CMD_LED_SET_BRIGHTNESS, brightness);
-+ err = omnia_cmd_write_u8(client, CMD_LED_SET_BRIGHTNESS, brightness);
-
-- return ret < 0 ? ret : count;
-+ return err ?: count;
- }
- static DEVICE_ATTR_RW(brightness);
-
-@@ -403,7 +406,7 @@ static ssize_t gamma_correction_store(st
- struct i2c_client *client = to_i2c_client(dev);
- struct omnia_leds *leds = i2c_get_clientdata(client);
- bool val;
-- int ret;
-+ int err;
-
- if (!leds->has_gamma_correction)
- return -EOPNOTSUPP;
-@@ -411,9 +414,9 @@ static ssize_t gamma_correction_store(st
- if (kstrtobool(buf, &val) < 0)
- return -EINVAL;
-
-- ret = omnia_cmd_write_u8(client, CMD_SET_GAMMA_CORRECTION, val);
-+ err = omnia_cmd_write_u8(client, CMD_SET_GAMMA_CORRECTION, val);
-
-- return ret < 0 ? ret : count;
-+ return err ?: count;
- }
- static DEVICE_ATTR_RW(gamma_correction);
-
-@@ -431,7 +434,7 @@ static int omnia_mcu_get_features(const
-
- err = omnia_cmd_read_raw(client->adapter, OMNIA_MCU_I2C_ADDR,
- CMD_GET_STATUS_WORD, &reply, sizeof(reply));
-- if (err < 0)
-+ if (err)
- return err;
-
- /* Check whether MCU firmware supports the CMD_GET_FEAUTRES command */
-@@ -440,7 +443,7 @@ static int omnia_mcu_get_features(const
-
- err = omnia_cmd_read_raw(client->adapter, OMNIA_MCU_I2C_ADDR,
- CMD_GET_FEATURES, &reply, sizeof(reply));
-- if (err < 0)
-+ if (err)
- return err;
-
- return le16_to_cpu(reply);
+++ /dev/null
-From 16724d6ea40a2c9315f5a0d81005dfa4d7a6da24 Mon Sep 17 00:00:00 2001
-Date: Fri, 20 Oct 2023 11:55:40 +0100
-Subject: [PATCH] nvmem: qfprom: Mark core clk as optional
-
-On some platforms like sc7280 on non-ChromeOS devices the core clock
-cannot be touched by Linux so we cannot provide it. Mark it as optional
-as accessing qfprom for reading works without it but we still prohibit
-writing if we cannot provide the clock.
-
----
- drivers/nvmem/qfprom.c | 6 +++---
- 1 file changed, 3 insertions(+), 3 deletions(-)
-
---- a/drivers/nvmem/qfprom.c
-+++ b/drivers/nvmem/qfprom.c
-@@ -438,12 +438,12 @@ static int qfprom_probe(struct platform_
- if (IS_ERR(priv->vcc))
- return PTR_ERR(priv->vcc);
-
-- priv->secclk = devm_clk_get(dev, "core");
-+ priv->secclk = devm_clk_get_optional(dev, "core");
- if (IS_ERR(priv->secclk))
- return dev_err_probe(dev, PTR_ERR(priv->secclk), "Error getting clock\n");
-
-- /* Only enable writing if we have SoC data. */
-- if (priv->soc_data)
-+ /* Only enable writing if we have SoC data and a valid clock */
-+ if (priv->soc_data && priv->secclk)
- econfig.reg_write = qfprom_reg_write;
- }
-
+++ /dev/null
-From 0720219f4d34a88a9badb4de70cfad7585687d48 Mon Sep 17 00:00:00 2001
-Date: Fri, 20 Oct 2023 11:55:45 +0100
-Subject: [PATCH] nvmem: Use device_get_match_data()
-
-Use preferred device_get_match_data() instead of of_match_device() to
-get the driver match data. With this, adjust the includes to explicitly
-include the correct headers.
-
----
- drivers/nvmem/mxs-ocotp.c | 10 ++++------
- drivers/nvmem/stm32-romem.c | 7 ++++---
- 2 files changed, 8 insertions(+), 9 deletions(-)
-
---- a/drivers/nvmem/mxs-ocotp.c
-+++ b/drivers/nvmem/mxs-ocotp.c
-@@ -13,8 +13,9 @@
- #include <linux/io.h>
- #include <linux/module.h>
- #include <linux/nvmem-provider.h>
--#include <linux/of_device.h>
-+#include <linux/of.h>
- #include <linux/platform_device.h>
-+#include <linux/property.h>
- #include <linux/slab.h>
- #include <linux/stmp_device.h>
-
-@@ -140,11 +141,10 @@ static int mxs_ocotp_probe(struct platfo
- struct device *dev = &pdev->dev;
- const struct mxs_data *data;
- struct mxs_ocotp *otp;
-- const struct of_device_id *match;
- int ret;
-
-- match = of_match_device(dev->driver->of_match_table, dev);
-- if (!match || !match->data)
-+ data = device_get_match_data(dev);
-+ if (!data)
- return -EINVAL;
-
- otp = devm_kzalloc(dev, sizeof(*otp), GFP_KERNEL);
-@@ -169,8 +169,6 @@ static int mxs_ocotp_probe(struct platfo
- if (ret)
- return ret;
-
-- data = match->data;
--
- ocotp_config.size = data->size;
- ocotp_config.priv = otp;
- ocotp_config.dev = dev;
---- a/drivers/nvmem/stm32-romem.c
-+++ b/drivers/nvmem/stm32-romem.c
-@@ -10,7 +10,9 @@
- #include <linux/io.h>
- #include <linux/module.h>
- #include <linux/nvmem-provider.h>
--#include <linux/of_device.h>
-+#include <linux/of.h>
-+#include <linux/platform_device.h>
-+#include <linux/property.h>
- #include <linux/tee_drv.h>
-
- #include "stm32-bsec-optee-ta.h"
-@@ -211,8 +213,7 @@ static int stm32_romem_probe(struct plat
-
- priv->lower = 0;
-
-- cfg = (const struct stm32_romem_cfg *)
-- of_match_device(dev->driver->of_match_table, dev)->data;
-+ cfg = device_get_match_data(dev);
- if (!cfg) {
- priv->cfg.read_only = true;
- priv->cfg.size = resource_size(res);
+++ /dev/null
-From f4cf4e5db331a5ce69e3f0b21d322cac0f4e4b5d Mon Sep 17 00:00:00 2001
-Date: Mon, 23 Oct 2023 12:27:59 +0200
-Subject: [PATCH] Revert "nvmem: add new config option"
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-This reverts commit 517f14d9cf3533d5ab4fded195ab6f80a92e378f.
-
-Config option "no_of_node" is no longer needed since adding a more
-explicit and targeted option "add_legacy_fixed_of_cells".
-
-That "no_of_node" config option was needed *earlier* to help mtd's case.
-
-DT nodes of MTD partitions (that are also NVMEM devices) may contain
-subnodes. Those SHOULD NOT be treated as NVMEM fixed cells.
-
-To prevent NVMEM core code from parsing subnodes a "no_of_node" option
-was added (and set to true in mtd) to make for_each_child_of_node() in
-NVMEM a no-op. That was a bit hacky because it was messing with
-"of_node" pointer to achieve some side-effect.
-
-With the introduction of "add_legacy_fixed_of_cells" config option
-things got more explicit. MTD subsystem simply tells NVMEM when to look
-for fixed cells and there is no need to hack "of_node" pointer anymore.
-
----
- drivers/mtd/mtdcore.c | 1 -
- drivers/nvmem/core.c | 2 +-
- include/linux/nvmem-provider.h | 2 --
- 3 files changed, 1 insertion(+), 4 deletions(-)
-
---- a/drivers/mtd/mtdcore.c
-+++ b/drivers/mtd/mtdcore.c
-@@ -560,7 +560,6 @@ static int mtd_nvmem_add(struct mtd_info
- config.read_only = true;
- config.root_only = true;
- config.ignore_wp = true;
-- config.no_of_node = !of_device_is_compatible(node, "nvmem-cells");
- config.priv = mtd;
-
- mtd->nvmem = nvmem_register(&config);
---- a/drivers/nvmem/core.c
-+++ b/drivers/nvmem/core.c
-@@ -932,7 +932,7 @@ struct nvmem_device *nvmem_register(cons
- nvmem->nkeepout = config->nkeepout;
- if (config->of_node)
- nvmem->dev.of_node = config->of_node;
-- else if (!config->no_of_node)
-+ else
- nvmem->dev.of_node = config->dev->of_node;
-
- switch (config->id) {
---- a/include/linux/nvmem-provider.h
-+++ b/include/linux/nvmem-provider.h
-@@ -91,7 +91,6 @@ struct nvmem_cell_info {
- * @read_only: Device is read-only.
- * @root_only: Device is accessibly to root only.
- * @of_node: If given, this will be used instead of the parent's of_node.
-- * @no_of_node: Device should not use the parent's of_node even if it's !NULL.
- * @reg_read: Callback to read data.
- * @reg_write: Callback to write data.
- * @size: Device size.
-@@ -126,7 +125,6 @@ struct nvmem_config {
- bool ignore_wp;
- struct nvmem_layout *layout;
- struct device_node *of_node;
-- bool no_of_node;
- nvmem_reg_read_t reg_read;
- nvmem_reg_write_t reg_write;
- int size;
+++ /dev/null
-From e20cd62b1f1708a4dec7ff4beb9e748a0bdb5716 Mon Sep 17 00:00:00 2001
-Date: Wed, 17 Jan 2024 09:32:06 +0100
-Subject: [PATCH] of: property: Make 'no port node found' output a debug
- message
-
-There are cases where an unavailable port is not an error, making this
-error message a false-positive. Since commit d56de8c9a17d8 ("usb: typec:
-tcpm: try to get role switch from tcpc fwnode") the role switch is tried
-on the port dev first and tcpc fwnode afterwards. If using the latter
-bindings getting from port dev fails every time. The kernel log is flooded
-with the messages like:
- OF: graph: no port node found in /soc@0/bus@42000000/i2c@42530000/usb-typec@50
-Silence this message by making it a debug message.
-
----
- drivers/of/property.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/of/property.c
-+++ b/drivers/of/property.c
-@@ -664,7 +664,7 @@ struct device_node *of_graph_get_next_en
- of_node_put(node);
-
- if (!port) {
-- pr_err("graph: no port node found in %pOF\n", parent);
-+ pr_debug("graph: no port node found in %pOF\n", parent);
- return NULL;
- }
- } else {
+++ /dev/null
-From 7f38b70042fcaa49219045bd1a9a2836e27a58ac Mon Sep 17 00:00:00 2001
-Date: Fri, 15 Dec 2023 11:15:27 +0000
-Subject: [PATCH] of: device: Export of_device_make_bus_id()
-
-This helper is really handy to create unique device names based on their
-device tree path, we may need it outside of the OF core (in the NVMEM
-subsystem) so let's export it. As this helper has nothing patform
-specific, let's move it to of/device.c instead of of/platform.c so we
-can add its prototype to of_device.h.
-
----
- drivers/of/device.c | 41 +++++++++++++++++++++++++++++++++++++++
- drivers/of/platform.c | 40 --------------------------------------
- include/linux/of_device.h | 6 ++++++
- 3 files changed, 47 insertions(+), 40 deletions(-)
-
---- a/drivers/of/device.c
-+++ b/drivers/of/device.c
-@@ -304,3 +304,44 @@ int of_device_uevent_modalias(const stru
- return 0;
- }
- EXPORT_SYMBOL_GPL(of_device_uevent_modalias);
-+
-+/**
-+ * of_device_make_bus_id - Use the device node data to assign a unique name
-+ * @dev: pointer to device structure that is linked to a device tree node
-+ *
-+ * This routine will first try using the translated bus address to
-+ * derive a unique name. If it cannot, then it will prepend names from
-+ * parent nodes until a unique name can be derived.
-+ */
-+void of_device_make_bus_id(struct device *dev)
-+{
-+ struct device_node *node = dev->of_node;
-+ const __be32 *reg;
-+ u64 addr;
-+ u32 mask;
-+
-+ /* Construct the name, using parent nodes if necessary to ensure uniqueness */
-+ while (node->parent) {
-+ /*
-+ * If the address can be translated, then that is as much
-+ * uniqueness as we need. Make it the first component and return
-+ */
-+ reg = of_get_property(node, "reg", NULL);
-+ if (reg && (addr = of_translate_address(node, reg)) != OF_BAD_ADDR) {
-+ if (!of_property_read_u32(node, "mask", &mask))
-+ dev_set_name(dev, dev_name(dev) ? "%llx.%x.%pOFn:%s" : "%llx.%x.%pOFn",
-+ addr, ffs(mask) - 1, node, dev_name(dev));
-+
-+ else
-+ dev_set_name(dev, dev_name(dev) ? "%llx.%pOFn:%s" : "%llx.%pOFn",
-+ addr, node, dev_name(dev));
-+ return;
-+ }
-+
-+ /* format arguments only used if dev_name() resolves to NULL */
-+ dev_set_name(dev, dev_name(dev) ? "%s:%s" : "%s",
-+ kbasename(node->full_name), dev_name(dev));
-+ node = node->parent;
-+ }
-+}
-+EXPORT_SYMBOL_GPL(of_device_make_bus_id);
---- a/drivers/of/platform.c
-+++ b/drivers/of/platform.c
-@@ -98,46 +98,6 @@ static const struct of_device_id of_skip
- */
-
- /**
-- * of_device_make_bus_id - Use the device node data to assign a unique name
-- * @dev: pointer to device structure that is linked to a device tree node
-- *
-- * This routine will first try using the translated bus address to
-- * derive a unique name. If it cannot, then it will prepend names from
-- * parent nodes until a unique name can be derived.
-- */
--static void of_device_make_bus_id(struct device *dev)
--{
-- struct device_node *node = dev->of_node;
-- const __be32 *reg;
-- u64 addr;
-- u32 mask;
--
-- /* Construct the name, using parent nodes if necessary to ensure uniqueness */
-- while (node->parent) {
-- /*
-- * If the address can be translated, then that is as much
-- * uniqueness as we need. Make it the first component and return
-- */
-- reg = of_get_property(node, "reg", NULL);
-- if (reg && (addr = of_translate_address(node, reg)) != OF_BAD_ADDR) {
-- if (!of_property_read_u32(node, "mask", &mask))
-- dev_set_name(dev, dev_name(dev) ? "%llx.%x.%pOFn:%s" : "%llx.%x.%pOFn",
-- addr, ffs(mask) - 1, node, dev_name(dev));
--
-- else
-- dev_set_name(dev, dev_name(dev) ? "%llx.%pOFn:%s" : "%llx.%pOFn",
-- addr, node, dev_name(dev));
-- return;
-- }
--
-- /* format arguments only used if dev_name() resolves to NULL */
-- dev_set_name(dev, dev_name(dev) ? "%s:%s" : "%s",
-- kbasename(node->full_name), dev_name(dev));
-- node = node->parent;
-- }
--}
--
--/**
- * of_device_alloc - Allocate and initialize an of_device
- * @np: device node to assign to device
- * @bus_id: Name to assign to the device. May be null to use default name.
---- a/include/linux/of_device.h
-+++ b/include/linux/of_device.h
-@@ -40,6 +40,9 @@ static inline int of_dma_configure(struc
- {
- return of_dma_configure_id(dev, np, force_dma, NULL);
- }
-+
-+void of_device_make_bus_id(struct device *dev);
-+
- #else /* CONFIG_OF */
-
- static inline int of_driver_match_device(struct device *dev,
-@@ -82,6 +85,9 @@ static inline int of_dma_configure(struc
- {
- return 0;
- }
-+
-+static inline void of_device_make_bus_id(struct device *dev) {}
-+
- #endif /* CONFIG_OF */
-
- #endif /* _LINUX_OF_DEVICE_H */
+++ /dev/null
-From 4a1a40233b4a9fc159a5c7a27dc34c5c7bc5be55 Mon Sep 17 00:00:00 2001
-Date: Fri, 15 Dec 2023 11:15:28 +0000
-Subject: [PATCH] nvmem: Move of_nvmem_layout_get_container() in another header
-
-nvmem-consumer.h is included by consumer devices, extracting data from
-NVMEM devices whereas nvmem-provider.h is included by devices providing
-NVMEM content.
-
-The only users of of_nvmem_layout_get_container() outside of the core
-are layout drivers, so better move its prototype to nvmem-provider.h.
-
-While we do so, we also move the kdoc associated with the function to
-the header rather than the .c file.
-
----
- drivers/nvmem/core.c | 8 --------
- include/linux/nvmem-consumer.h | 7 -------
- include/linux/nvmem-provider.h | 21 +++++++++++++++++++++
- 3 files changed, 21 insertions(+), 15 deletions(-)
-
---- a/drivers/nvmem/core.c
-+++ b/drivers/nvmem/core.c
-@@ -837,14 +837,6 @@ static int nvmem_add_cells_from_layout(s
- }
-
- #if IS_ENABLED(CONFIG_OF)
--/**
-- * of_nvmem_layout_get_container() - Get OF node to layout container.
-- *
-- * @nvmem: nvmem device.
-- *
-- * Return: a node pointer with refcount incremented or NULL if no
-- * container exists. Use of_node_put() on it when done.
-- */
- struct device_node *of_nvmem_layout_get_container(struct nvmem_device *nvmem)
- {
- return of_get_child_by_name(nvmem->dev.of_node, "nvmem-layout");
---- a/include/linux/nvmem-consumer.h
-+++ b/include/linux/nvmem-consumer.h
-@@ -242,7 +242,6 @@ struct nvmem_cell *of_nvmem_cell_get(str
- const char *id);
- struct nvmem_device *of_nvmem_device_get(struct device_node *np,
- const char *name);
--struct device_node *of_nvmem_layout_get_container(struct nvmem_device *nvmem);
- #else
- static inline struct nvmem_cell *of_nvmem_cell_get(struct device_node *np,
- const char *id)
-@@ -255,12 +254,6 @@ static inline struct nvmem_device *of_nv
- {
- return ERR_PTR(-EOPNOTSUPP);
- }
--
--static inline struct device_node *
--of_nvmem_layout_get_container(struct nvmem_device *nvmem)
--{
-- return NULL;
--}
- #endif /* CONFIG_NVMEM && CONFIG_OF */
-
- #endif /* ifndef _LINUX_NVMEM_CONSUMER_H */
---- a/include/linux/nvmem-provider.h
-+++ b/include/linux/nvmem-provider.h
-@@ -241,6 +241,27 @@ nvmem_layout_get_match_data(struct nvmem
-
- #endif /* CONFIG_NVMEM */
-
-+#if IS_ENABLED(CONFIG_NVMEM) && IS_ENABLED(CONFIG_OF)
-+
-+/**
-+ * of_nvmem_layout_get_container() - Get OF node of layout container
-+ *
-+ * @nvmem: nvmem device
-+ *
-+ * Return: a node pointer with refcount incremented or NULL if no
-+ * container exists. Use of_node_put() on it when done.
-+ */
-+struct device_node *of_nvmem_layout_get_container(struct nvmem_device *nvmem);
-+
-+#else /* CONFIG_NVMEM && CONFIG_OF */
-+
-+static inline struct device_node *of_nvmem_layout_get_container(struct nvmem_device *nvmem)
-+{
-+ return NULL;
-+}
-+
-+#endif /* CONFIG_NVMEM && CONFIG_OF */
-+
- #define module_nvmem_layout_driver(__layout_driver) \
- module_driver(__layout_driver, nvmem_layout_register, \
- nvmem_layout_unregister)
+++ /dev/null
-From fc29fd821d9ac2ae3d32a722fac39ce874efb883 Mon Sep 17 00:00:00 2001
-Date: Fri, 15 Dec 2023 11:15:32 +0000
-Subject: [PATCH] nvmem: core: Rework layouts to become regular devices
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Current layout support was initially written without modules support in
-mind. When the requirement for module support rose, the existing base
-was improved to adopt modularization support, but kind of a design flaw
-was introduced. With the existing implementation, when a storage device
-registers into NVMEM, the core tries to hook a layout (if any) and
-populates its cells immediately. This means, if the hardware description
-expects a layout to be hooked up, but no driver was provided for that,
-the storage medium will fail to probe and try later from
-scratch. Even if we consider that the hardware description shall be
-correct, we could still probe the storage device (especially if it
-contains the rootfs).
-
-One way to overcome this situation is to consider the layouts as
-devices, and leverage the native notifier mechanism. When a new NVMEM
-device is registered, we can populate its nvmem-layout child, if any,
-and wait for the matching to be done in order to get the cells (the
-waiting can be easily done with the NVMEM notifiers). If the layout
-driver is compiled as a module, it should automatically be loaded. This
-way, there is no strong order to enforce, any NVMEM device creation
-or NVMEM layout driver insertion will be observed as a new event which
-may lead to the creation of additional cells, without disturbing the
-probes with costly (and sometimes endless) deferrals.
-
-In order to achieve that goal we create a new bus for the nvmem-layouts
-with minimal logic to match nvmem-layout devices with nvmem-layout
-drivers. All this infrastructure code is created in the layouts.c file.
-
----
- drivers/nvmem/Kconfig | 1 +
- drivers/nvmem/Makefile | 2 +
- drivers/nvmem/core.c | 170 ++++++++++----------------
- drivers/nvmem/internals.h | 21 ++++
- drivers/nvmem/layouts.c | 201 +++++++++++++++++++++++++++++++
- drivers/nvmem/layouts/Kconfig | 8 ++
- drivers/nvmem/layouts/onie-tlv.c | 24 +++-
- drivers/nvmem/layouts/sl28vpd.c | 24 +++-
- include/linux/nvmem-provider.h | 38 +++---
- 9 files changed, 354 insertions(+), 135 deletions(-)
- create mode 100644 drivers/nvmem/layouts.c
-
---- a/drivers/nvmem/Kconfig
-+++ b/drivers/nvmem/Kconfig
-@@ -1,6 +1,7 @@
- # SPDX-License-Identifier: GPL-2.0-only
- menuconfig NVMEM
- bool "NVMEM Support"
-+ imply NVMEM_LAYOUTS
- help
- Support for NVMEM(Non Volatile Memory) devices like EEPROM, EFUSES...
-
---- a/drivers/nvmem/Makefile
-+++ b/drivers/nvmem/Makefile
-@@ -5,6 +5,8 @@
-
- obj-$(CONFIG_NVMEM) += nvmem_core.o
- nvmem_core-y := core.o
-+obj-$(CONFIG_NVMEM_LAYOUTS) += nvmem_layouts.o
-+nvmem_layouts-y := layouts.o
- obj-y += layouts/
-
- # Devices
---- a/drivers/nvmem/core.c
-+++ b/drivers/nvmem/core.c
-@@ -55,9 +55,6 @@ static LIST_HEAD(nvmem_lookup_list);
-
- static BLOCKING_NOTIFIER_HEAD(nvmem_notifier);
-
--static DEFINE_SPINLOCK(nvmem_layout_lock);
--static LIST_HEAD(nvmem_layouts);
--
- static int __nvmem_reg_read(struct nvmem_device *nvmem, unsigned int offset,
- void *val, size_t bytes)
- {
-@@ -753,97 +750,22 @@ static int nvmem_add_cells_from_fixed_la
- return err;
- }
-
--int __nvmem_layout_register(struct nvmem_layout *layout, struct module *owner)
-+int nvmem_layout_register(struct nvmem_layout *layout)
- {
-- layout->owner = owner;
--
-- spin_lock(&nvmem_layout_lock);
-- list_add(&layout->node, &nvmem_layouts);
-- spin_unlock(&nvmem_layout_lock);
--
-- blocking_notifier_call_chain(&nvmem_notifier, NVMEM_LAYOUT_ADD, layout);
-+ if (!layout->add_cells)
-+ return -EINVAL;
-
-- return 0;
-+ /* Populate the cells */
-+ return layout->add_cells(&layout->nvmem->dev, layout->nvmem);
- }
--EXPORT_SYMBOL_GPL(__nvmem_layout_register);
-+EXPORT_SYMBOL_GPL(nvmem_layout_register);
-
- void nvmem_layout_unregister(struct nvmem_layout *layout)
- {
-- blocking_notifier_call_chain(&nvmem_notifier, NVMEM_LAYOUT_REMOVE, layout);
--
-- spin_lock(&nvmem_layout_lock);
-- list_del(&layout->node);
-- spin_unlock(&nvmem_layout_lock);
-+ /* Keep the API even with an empty stub in case we need it later */
- }
- EXPORT_SYMBOL_GPL(nvmem_layout_unregister);
-
--static struct nvmem_layout *nvmem_layout_get(struct nvmem_device *nvmem)
--{
-- struct device_node *layout_np;
-- struct nvmem_layout *l, *layout = ERR_PTR(-EPROBE_DEFER);
--
-- layout_np = of_nvmem_layout_get_container(nvmem);
-- if (!layout_np)
-- return NULL;
--
-- /* Fixed layouts don't have a matching driver */
-- if (of_device_is_compatible(layout_np, "fixed-layout")) {
-- of_node_put(layout_np);
-- return NULL;
-- }
--
-- /*
-- * In case the nvmem device was built-in while the layout was built as a
-- * module, we shall manually request the layout driver loading otherwise
-- * we'll never have any match.
-- */
-- of_request_module(layout_np);
--
-- spin_lock(&nvmem_layout_lock);
--
-- list_for_each_entry(l, &nvmem_layouts, node) {
-- if (of_match_node(l->of_match_table, layout_np)) {
-- if (try_module_get(l->owner))
-- layout = l;
--
-- break;
-- }
-- }
--
-- spin_unlock(&nvmem_layout_lock);
-- of_node_put(layout_np);
--
-- return layout;
--}
--
--static void nvmem_layout_put(struct nvmem_layout *layout)
--{
-- if (layout)
-- module_put(layout->owner);
--}
--
--static int nvmem_add_cells_from_layout(struct nvmem_device *nvmem)
--{
-- struct nvmem_layout *layout = nvmem->layout;
-- int ret;
--
-- if (layout && layout->add_cells) {
-- ret = layout->add_cells(&nvmem->dev, nvmem);
-- if (ret)
-- return ret;
-- }
--
-- return 0;
--}
--
--#if IS_ENABLED(CONFIG_OF)
--struct device_node *of_nvmem_layout_get_container(struct nvmem_device *nvmem)
--{
-- return of_get_child_by_name(nvmem->dev.of_node, "nvmem-layout");
--}
--EXPORT_SYMBOL_GPL(of_nvmem_layout_get_container);
--#endif
--
- const void *nvmem_layout_get_match_data(struct nvmem_device *nvmem,
- struct nvmem_layout *layout)
- {
-@@ -851,7 +773,7 @@ const void *nvmem_layout_get_match_data(
- const struct of_device_id *match;
-
- layout_np = of_nvmem_layout_get_container(nvmem);
-- match = of_match_node(layout->of_match_table, layout_np);
-+ match = of_match_node(layout->dev.driver->of_match_table, layout_np);
-
- return match ? match->data : NULL;
- }
-@@ -963,19 +885,6 @@ struct nvmem_device *nvmem_register(cons
- goto err_put_device;
- }
-
-- /*
-- * If the driver supplied a layout by config->layout, the module
-- * pointer will be NULL and nvmem_layout_put() will be a noop.
-- */
-- nvmem->layout = config->layout ?: nvmem_layout_get(nvmem);
-- if (IS_ERR(nvmem->layout)) {
-- rval = PTR_ERR(nvmem->layout);
-- nvmem->layout = NULL;
--
-- if (rval == -EPROBE_DEFER)
-- goto err_teardown_compat;
-- }
--
- if (config->cells) {
- rval = nvmem_add_cells(nvmem, config->cells, config->ncells);
- if (rval)
-@@ -996,24 +905,24 @@ struct nvmem_device *nvmem_register(cons
- if (rval)
- goto err_remove_cells;
-
-- rval = nvmem_add_cells_from_layout(nvmem);
-- if (rval)
-- goto err_remove_cells;
--
- dev_dbg(&nvmem->dev, "Registering nvmem device %s\n", config->name);
-
- rval = device_add(&nvmem->dev);
- if (rval)
- goto err_remove_cells;
-
-+ rval = nvmem_populate_layout(nvmem);
-+ if (rval)
-+ goto err_remove_dev;
-+
- blocking_notifier_call_chain(&nvmem_notifier, NVMEM_ADD, nvmem);
-
- return nvmem;
-
-+err_remove_dev:
-+ device_del(&nvmem->dev);
- err_remove_cells:
- nvmem_device_remove_all_cells(nvmem);
-- nvmem_layout_put(nvmem->layout);
--err_teardown_compat:
- if (config->compat)
- nvmem_sysfs_remove_compat(nvmem, config);
- err_put_device:
-@@ -1035,7 +944,7 @@ static void nvmem_device_release(struct
- device_remove_bin_file(nvmem->base_dev, &nvmem->eeprom);
-
- nvmem_device_remove_all_cells(nvmem);
-- nvmem_layout_put(nvmem->layout);
-+ nvmem_destroy_layout(nvmem);
- device_unregister(&nvmem->dev);
- }
-
-@@ -1337,6 +1246,12 @@ nvmem_cell_get_from_lookup(struct device
- return cell;
- }
-
-+static void nvmem_layout_module_put(struct nvmem_device *nvmem)
-+{
-+ if (nvmem->layout && nvmem->layout->dev.driver)
-+ module_put(nvmem->layout->dev.driver->owner);
-+}
-+
- #if IS_ENABLED(CONFIG_OF)
- static struct nvmem_cell_entry *
- nvmem_find_cell_entry_by_node(struct nvmem_device *nvmem, struct device_node *np)
-@@ -1355,6 +1270,18 @@ nvmem_find_cell_entry_by_node(struct nvm
- return cell;
- }
-
-+static int nvmem_layout_module_get_optional(struct nvmem_device *nvmem)
-+{
-+ if (!nvmem->layout)
-+ return 0;
-+
-+ if (!nvmem->layout->dev.driver ||
-+ !try_module_get(nvmem->layout->dev.driver->owner))
-+ return -EPROBE_DEFER;
-+
-+ return 0;
-+}
-+
- /**
- * of_nvmem_cell_get() - Get a nvmem cell from given device node and cell id
- *
-@@ -1417,16 +1344,29 @@ struct nvmem_cell *of_nvmem_cell_get(str
- return ERR_CAST(nvmem);
- }
-
-+ ret = nvmem_layout_module_get_optional(nvmem);
-+ if (ret) {
-+ of_node_put(cell_np);
-+ __nvmem_device_put(nvmem);
-+ return ERR_PTR(ret);
-+ }
-+
- cell_entry = nvmem_find_cell_entry_by_node(nvmem, cell_np);
- of_node_put(cell_np);
- if (!cell_entry) {
- __nvmem_device_put(nvmem);
-- return ERR_PTR(-ENOENT);
-+ nvmem_layout_module_put(nvmem);
-+ if (nvmem->layout)
-+ return ERR_PTR(-EPROBE_DEFER);
-+ else
-+ return ERR_PTR(-ENOENT);
- }
-
- cell = nvmem_create_cell(cell_entry, id, cell_index);
-- if (IS_ERR(cell))
-+ if (IS_ERR(cell)) {
- __nvmem_device_put(nvmem);
-+ nvmem_layout_module_put(nvmem);
-+ }
-
- return cell;
- }
-@@ -1540,6 +1480,7 @@ void nvmem_cell_put(struct nvmem_cell *c
-
- kfree(cell);
- __nvmem_device_put(nvmem);
-+ nvmem_layout_module_put(nvmem);
- }
- EXPORT_SYMBOL_GPL(nvmem_cell_put);
-
-@@ -2132,11 +2073,22 @@ EXPORT_SYMBOL_GPL(nvmem_dev_size);
-
- static int __init nvmem_init(void)
- {
-- return bus_register(&nvmem_bus_type);
-+ int ret;
-+
-+ ret = bus_register(&nvmem_bus_type);
-+ if (ret)
-+ return ret;
-+
-+ ret = nvmem_layout_bus_register();
-+ if (ret)
-+ bus_unregister(&nvmem_bus_type);
-+
-+ return ret;
- }
-
- static void __exit nvmem_exit(void)
- {
-+ nvmem_layout_bus_unregister();
- bus_unregister(&nvmem_bus_type);
- }
-
---- a/drivers/nvmem/internals.h
-+++ b/drivers/nvmem/internals.h
-@@ -34,4 +34,25 @@ struct nvmem_device {
- void *priv;
- };
-
-+#if IS_ENABLED(CONFIG_OF)
-+int nvmem_layout_bus_register(void);
-+void nvmem_layout_bus_unregister(void);
-+int nvmem_populate_layout(struct nvmem_device *nvmem);
-+void nvmem_destroy_layout(struct nvmem_device *nvmem);
-+#else /* CONFIG_OF */
-+static inline int nvmem_layout_bus_register(void)
-+{
-+ return 0;
-+}
-+
-+static inline void nvmem_layout_bus_unregister(void) {}
-+
-+static inline int nvmem_populate_layout(struct nvmem_device *nvmem)
-+{
-+ return 0;
-+}
-+
-+static inline void nvmem_destroy_layout(struct nvmem_device *nvmem) { }
-+#endif /* CONFIG_OF */
-+
- #endif /* ifndef _LINUX_NVMEM_INTERNALS_H */
---- /dev/null
-+++ b/drivers/nvmem/layouts.c
-@@ -0,0 +1,201 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/*
-+ * NVMEM layout bus handling
-+ *
-+ * Copyright (C) 2023 Bootlin
-+ */
-+
-+#include <linux/device.h>
-+#include <linux/dma-mapping.h>
-+#include <linux/nvmem-consumer.h>
-+#include <linux/nvmem-provider.h>
-+#include <linux/of.h>
-+#include <linux/of_device.h>
-+#include <linux/of_irq.h>
-+
-+#include "internals.h"
-+
-+#define to_nvmem_layout_driver(drv) \
-+ (container_of((drv), struct nvmem_layout_driver, driver))
-+#define to_nvmem_layout_device(_dev) \
-+ container_of((_dev), struct nvmem_layout, dev)
-+
-+static int nvmem_layout_bus_match(struct device *dev, struct device_driver *drv)
-+{
-+ return of_driver_match_device(dev, drv);
-+}
-+
-+static int nvmem_layout_bus_probe(struct device *dev)
-+{
-+ struct nvmem_layout_driver *drv = to_nvmem_layout_driver(dev->driver);
-+ struct nvmem_layout *layout = to_nvmem_layout_device(dev);
-+
-+ if (!drv->probe || !drv->remove)
-+ return -EINVAL;
-+
-+ return drv->probe(layout);
-+}
-+
-+static void nvmem_layout_bus_remove(struct device *dev)
-+{
-+ struct nvmem_layout_driver *drv = to_nvmem_layout_driver(dev->driver);
-+ struct nvmem_layout *layout = to_nvmem_layout_device(dev);
-+
-+ return drv->remove(layout);
-+}
-+
-+static struct bus_type nvmem_layout_bus_type = {
-+ .name = "nvmem-layout",
-+ .match = nvmem_layout_bus_match,
-+ .probe = nvmem_layout_bus_probe,
-+ .remove = nvmem_layout_bus_remove,
-+};
-+
-+int nvmem_layout_driver_register(struct nvmem_layout_driver *drv)
-+{
-+ drv->driver.bus = &nvmem_layout_bus_type;
-+
-+ return driver_register(&drv->driver);
-+}
-+EXPORT_SYMBOL_GPL(nvmem_layout_driver_register);
-+
-+void nvmem_layout_driver_unregister(struct nvmem_layout_driver *drv)
-+{
-+ driver_unregister(&drv->driver);
-+}
-+EXPORT_SYMBOL_GPL(nvmem_layout_driver_unregister);
-+
-+static void nvmem_layout_release_device(struct device *dev)
-+{
-+ struct nvmem_layout *layout = to_nvmem_layout_device(dev);
-+
-+ of_node_put(layout->dev.of_node);
-+ kfree(layout);
-+}
-+
-+static int nvmem_layout_create_device(struct nvmem_device *nvmem,
-+ struct device_node *np)
-+{
-+ struct nvmem_layout *layout;
-+ struct device *dev;
-+ int ret;
-+
-+ layout = kzalloc(sizeof(*layout), GFP_KERNEL);
-+ if (!layout)
-+ return -ENOMEM;
-+
-+ /* Create a bidirectional link */
-+ layout->nvmem = nvmem;
-+ nvmem->layout = layout;
-+
-+ /* Device model registration */
-+ dev = &layout->dev;
-+ device_initialize(dev);
-+ dev->parent = &nvmem->dev;
-+ dev->bus = &nvmem_layout_bus_type;
-+ dev->release = nvmem_layout_release_device;
-+ dev->coherent_dma_mask = DMA_BIT_MASK(32);
-+ dev->dma_mask = &dev->coherent_dma_mask;
-+ device_set_node(dev, of_fwnode_handle(of_node_get(np)));
-+ of_device_make_bus_id(dev);
-+ of_msi_configure(dev, dev->of_node);
-+
-+ ret = device_add(dev);
-+ if (ret) {
-+ put_device(dev);
-+ return ret;
-+ }
-+
-+ return 0;
-+}
-+
-+static const struct of_device_id of_nvmem_layout_skip_table[] = {
-+ { .compatible = "fixed-layout", },
-+ {}
-+};
-+
-+static int nvmem_layout_bus_populate(struct nvmem_device *nvmem,
-+ struct device_node *layout_dn)
-+{
-+ int ret;
-+
-+ /* Make sure it has a compatible property */
-+ if (!of_get_property(layout_dn, "compatible", NULL)) {
-+ pr_debug("%s() - skipping %pOF, no compatible prop\n",
-+ __func__, layout_dn);
-+ return 0;
-+ }
-+
-+ /* Fixed layouts are parsed manually somewhere else for now */
-+ if (of_match_node(of_nvmem_layout_skip_table, layout_dn)) {
-+ pr_debug("%s() - skipping %pOF node\n", __func__, layout_dn);
-+ return 0;
-+ }
-+
-+ if (of_node_check_flag(layout_dn, OF_POPULATED_BUS)) {
-+ pr_debug("%s() - skipping %pOF, already populated\n",
-+ __func__, layout_dn);
-+
-+ return 0;
-+ }
-+
-+ /* NVMEM layout buses expect only a single device representing the layout */
-+ ret = nvmem_layout_create_device(nvmem, layout_dn);
-+ if (ret)
-+ return ret;
-+
-+ of_node_set_flag(layout_dn, OF_POPULATED_BUS);
-+
-+ return 0;
-+}
-+
-+struct device_node *of_nvmem_layout_get_container(struct nvmem_device *nvmem)
-+{
-+ return of_get_child_by_name(nvmem->dev.of_node, "nvmem-layout");
-+}
-+EXPORT_SYMBOL_GPL(of_nvmem_layout_get_container);
-+
-+/*
-+ * Returns the number of devices populated, 0 if the operation was not relevant
-+ * for this nvmem device, an error code otherwise.
-+ */
-+int nvmem_populate_layout(struct nvmem_device *nvmem)
-+{
-+ struct device_node *layout_dn;
-+ int ret;
-+
-+ layout_dn = of_nvmem_layout_get_container(nvmem);
-+ if (!layout_dn)
-+ return 0;
-+
-+ /* Populate the layout device */
-+ device_links_supplier_sync_state_pause();
-+ ret = nvmem_layout_bus_populate(nvmem, layout_dn);
-+ device_links_supplier_sync_state_resume();
-+
-+ of_node_put(layout_dn);
-+ return ret;
-+}
-+
-+void nvmem_destroy_layout(struct nvmem_device *nvmem)
-+{
-+ struct device *dev;
-+
-+ if (!nvmem->layout)
-+ return;
-+
-+ dev = &nvmem->layout->dev;
-+ of_node_clear_flag(dev->of_node, OF_POPULATED_BUS);
-+ device_unregister(dev);
-+}
-+
-+int nvmem_layout_bus_register(void)
-+{
-+ return bus_register(&nvmem_layout_bus_type);
-+}
-+
-+void nvmem_layout_bus_unregister(void)
-+{
-+ bus_unregister(&nvmem_layout_bus_type);
-+}
---- a/drivers/nvmem/layouts/Kconfig
-+++ b/drivers/nvmem/layouts/Kconfig
-@@ -1,5 +1,11 @@
- # SPDX-License-Identifier: GPL-2.0
-
-+config NVMEM_LAYOUTS
-+ bool
-+ depends on OF
-+
-+if NVMEM_LAYOUTS
-+
- menu "Layout Types"
-
- config NVMEM_LAYOUT_SL28_VPD
-@@ -21,3 +27,5 @@ config NVMEM_LAYOUT_ONIE_TLV
- If unsure, say N.
-
- endmenu
-+
-+endif
---- a/drivers/nvmem/layouts/onie-tlv.c
-+++ b/drivers/nvmem/layouts/onie-tlv.c
-@@ -225,16 +225,32 @@ static int onie_tlv_parse_table(struct d
- return 0;
- }
-
-+static int onie_tlv_probe(struct nvmem_layout *layout)
-+{
-+ layout->add_cells = onie_tlv_parse_table;
-+
-+ return nvmem_layout_register(layout);
-+}
-+
-+static void onie_tlv_remove(struct nvmem_layout *layout)
-+{
-+ nvmem_layout_unregister(layout);
-+}
-+
- static const struct of_device_id onie_tlv_of_match_table[] = {
- { .compatible = "onie,tlv-layout", },
- {},
- };
- MODULE_DEVICE_TABLE(of, onie_tlv_of_match_table);
-
--static struct nvmem_layout onie_tlv_layout = {
-- .name = "ONIE tlv layout",
-- .of_match_table = onie_tlv_of_match_table,
-- .add_cells = onie_tlv_parse_table,
-+static struct nvmem_layout_driver onie_tlv_layout = {
-+ .driver = {
-+ .owner = THIS_MODULE,
-+ .name = "onie-tlv-layout",
-+ .of_match_table = onie_tlv_of_match_table,
-+ },
-+ .probe = onie_tlv_probe,
-+ .remove = onie_tlv_remove,
- };
- module_nvmem_layout_driver(onie_tlv_layout);
-
---- a/drivers/nvmem/layouts/sl28vpd.c
-+++ b/drivers/nvmem/layouts/sl28vpd.c
-@@ -134,16 +134,32 @@ static int sl28vpd_add_cells(struct devi
- return 0;
- }
-
-+static int sl28vpd_probe(struct nvmem_layout *layout)
-+{
-+ layout->add_cells = sl28vpd_add_cells;
-+
-+ return nvmem_layout_register(layout);
-+}
-+
-+static void sl28vpd_remove(struct nvmem_layout *layout)
-+{
-+ nvmem_layout_unregister(layout);
-+}
-+
- static const struct of_device_id sl28vpd_of_match_table[] = {
- { .compatible = "kontron,sl28-vpd" },
- {},
- };
- MODULE_DEVICE_TABLE(of, sl28vpd_of_match_table);
-
--static struct nvmem_layout sl28vpd_layout = {
-- .name = "sl28-vpd",
-- .of_match_table = sl28vpd_of_match_table,
-- .add_cells = sl28vpd_add_cells,
-+static struct nvmem_layout_driver sl28vpd_layout = {
-+ .driver = {
-+ .owner = THIS_MODULE,
-+ .name = "kontron-sl28vpd-layout",
-+ .of_match_table = sl28vpd_of_match_table,
-+ },
-+ .probe = sl28vpd_probe,
-+ .remove = sl28vpd_remove,
- };
- module_nvmem_layout_driver(sl28vpd_layout);
-
---- a/include/linux/nvmem-provider.h
-+++ b/include/linux/nvmem-provider.h
-@@ -9,6 +9,7 @@
- #ifndef _LINUX_NVMEM_PROVIDER_H
- #define _LINUX_NVMEM_PROVIDER_H
-
-+#include <linux/device.h>
- #include <linux/device/driver.h>
- #include <linux/err.h>
- #include <linux/errno.h>
-@@ -158,12 +159,11 @@ struct nvmem_cell_table {
- /**
- * struct nvmem_layout - NVMEM layout definitions
- *
-- * @name: Layout name.
-- * @of_match_table: Open firmware match table.
-- * @add_cells: Called to populate the layout using
-- * nvmem_add_one_cell().
-- * @owner: Pointer to struct module.
-- * @node: List node.
-+ * @dev: Device-model layout device.
-+ * @nvmem: The underlying NVMEM device
-+ * @add_cells: Will be called if a nvmem device is found which
-+ * has this layout. The function will add layout
-+ * specific cells with nvmem_add_one_cell().
- *
- * A nvmem device can hold a well defined structure which can just be
- * evaluated during runtime. For example a TLV list, or a list of "name=val"
-@@ -171,13 +171,15 @@ struct nvmem_cell_table {
- * cells.
- */
- struct nvmem_layout {
-- const char *name;
-- const struct of_device_id *of_match_table;
-+ struct device dev;
-+ struct nvmem_device *nvmem;
- int (*add_cells)(struct device *dev, struct nvmem_device *nvmem);
-+};
-
-- /* private */
-- struct module *owner;
-- struct list_head node;
-+struct nvmem_layout_driver {
-+ struct device_driver driver;
-+ int (*probe)(struct nvmem_layout *layout);
-+ void (*remove)(struct nvmem_layout *layout);
- };
-
- #if IS_ENABLED(CONFIG_NVMEM)
-@@ -194,11 +196,15 @@ void nvmem_del_cell_table(struct nvmem_c
- int nvmem_add_one_cell(struct nvmem_device *nvmem,
- const struct nvmem_cell_info *info);
-
--int __nvmem_layout_register(struct nvmem_layout *layout, struct module *owner);
--#define nvmem_layout_register(layout) \
-- __nvmem_layout_register(layout, THIS_MODULE)
-+int nvmem_layout_register(struct nvmem_layout *layout);
- void nvmem_layout_unregister(struct nvmem_layout *layout);
-
-+int nvmem_layout_driver_register(struct nvmem_layout_driver *drv);
-+void nvmem_layout_driver_unregister(struct nvmem_layout_driver *drv);
-+#define module_nvmem_layout_driver(__nvmem_layout_driver) \
-+ module_driver(__nvmem_layout_driver, nvmem_layout_driver_register, \
-+ nvmem_layout_driver_unregister)
-+
- const void *nvmem_layout_get_match_data(struct nvmem_device *nvmem,
- struct nvmem_layout *layout);
-
-@@ -262,8 +268,4 @@ static inline struct device_node *of_nvm
-
- #endif /* CONFIG_NVMEM && CONFIG_OF */
-
--#define module_nvmem_layout_driver(__layout_driver) \
-- module_driver(__layout_driver, nvmem_layout_register, \
-- nvmem_layout_unregister)
--
- #endif /* ifndef _LINUX_NVMEM_PROVIDER_H */
+++ /dev/null
-From 0331c611949fffdf486652450901a4dc52bc5cca Mon Sep 17 00:00:00 2001
-Date: Fri, 15 Dec 2023 11:15:34 +0000
-Subject: [PATCH] nvmem: core: Expose cells through sysfs
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-The binary content of nvmem devices is available to the user so in the
-easiest cases, finding the content of a cell is rather easy as it is
-just a matter of looking at a known and fixed offset. However, nvmem
-layouts have been recently introduced to cope with more advanced
-situations, where the offset and size of the cells is not known in
-advance or is dynamic. When using layouts, more advanced parsers are
-used by the kernel in order to give direct access to the content of each
-cell, regardless of its position/size in the underlying
-device. Unfortunately, these information are not accessible by users,
-unless by fully re-implementing the parser logic in userland.
-
-Let's expose the cells and their content through sysfs to avoid these
-situations. Of course the relevant NVMEM sysfs Kconfig option must be
-enabled for this support to be available.
-
-Not all nvmem devices expose cells. Indeed, the .bin_attrs attribute
-group member will be filled at runtime only when relevant and will
-remain empty otherwise. In this case, as the cells attribute group will
-be empty, it will not lead to any additional folder/file creation.
-
-Exposed cells are read-only. There is, in practice, everything in the
-core to support a write path, but as I don't see any need for that, I
-prefer to keep the interface simple (and probably safer). The interface
-is documented as being in the "testing" state which means we can later
-add a write attribute if though relevant.
-
----
- drivers/nvmem/core.c | 135 +++++++++++++++++++++++++++++++++++++-
- drivers/nvmem/internals.h | 1 +
- 2 files changed, 135 insertions(+), 1 deletion(-)
-
---- a/drivers/nvmem/core.c
-+++ b/drivers/nvmem/core.c
-@@ -299,6 +299,43 @@ static umode_t nvmem_bin_attr_is_visible
- return nvmem_bin_attr_get_umode(nvmem);
- }
-
-+static struct nvmem_cell *nvmem_create_cell(struct nvmem_cell_entry *entry,
-+ const char *id, int index);
-+
-+static ssize_t nvmem_cell_attr_read(struct file *filp, struct kobject *kobj,
-+ struct bin_attribute *attr, char *buf,
-+ loff_t pos, size_t count)
-+{
-+ struct nvmem_cell_entry *entry;
-+ struct nvmem_cell *cell = NULL;
-+ size_t cell_sz, read_len;
-+ void *content;
-+
-+ entry = attr->private;
-+ cell = nvmem_create_cell(entry, entry->name, 0);
-+ if (IS_ERR(cell))
-+ return PTR_ERR(cell);
-+
-+ if (!cell)
-+ return -EINVAL;
-+
-+ content = nvmem_cell_read(cell, &cell_sz);
-+ if (IS_ERR(content)) {
-+ read_len = PTR_ERR(content);
-+ goto destroy_cell;
-+ }
-+
-+ read_len = min_t(unsigned int, cell_sz - pos, count);
-+ memcpy(buf, content + pos, read_len);
-+ kfree(content);
-+
-+destroy_cell:
-+ kfree_const(cell->id);
-+ kfree(cell);
-+
-+ return read_len;
-+}
-+
- /* default read/write permissions */
- static struct bin_attribute bin_attr_rw_nvmem = {
- .attr = {
-@@ -320,11 +357,21 @@ static const struct attribute_group nvme
- .is_bin_visible = nvmem_bin_attr_is_visible,
- };
-
-+/* Cell attributes will be dynamically allocated */
-+static struct attribute_group nvmem_cells_group = {
-+ .name = "cells",
-+};
-+
- static const struct attribute_group *nvmem_dev_groups[] = {
- &nvmem_bin_group,
- NULL,
- };
-
-+static const struct attribute_group *nvmem_cells_groups[] = {
-+ &nvmem_cells_group,
-+ NULL,
-+};
-+
- static struct bin_attribute bin_attr_nvmem_eeprom_compat = {
- .attr = {
- .name = "eeprom",
-@@ -379,6 +426,68 @@ static void nvmem_sysfs_remove_compat(st
- device_remove_bin_file(nvmem->base_dev, &nvmem->eeprom);
- }
-
-+static int nvmem_populate_sysfs_cells(struct nvmem_device *nvmem)
-+{
-+ struct bin_attribute **cells_attrs, *attrs;
-+ struct nvmem_cell_entry *entry;
-+ unsigned int ncells = 0, i = 0;
-+ int ret = 0;
-+
-+ mutex_lock(&nvmem_mutex);
-+
-+ if (list_empty(&nvmem->cells) || nvmem->sysfs_cells_populated) {
-+ nvmem_cells_group.bin_attrs = NULL;
-+ goto unlock_mutex;
-+ }
-+
-+ /* Allocate an array of attributes with a sentinel */
-+ ncells = list_count_nodes(&nvmem->cells);
-+ cells_attrs = devm_kcalloc(&nvmem->dev, ncells + 1,
-+ sizeof(struct bin_attribute *), GFP_KERNEL);
-+ if (!cells_attrs) {
-+ ret = -ENOMEM;
-+ goto unlock_mutex;
-+ }
-+
-+ attrs = devm_kcalloc(&nvmem->dev, ncells, sizeof(struct bin_attribute), GFP_KERNEL);
-+ if (!attrs) {
-+ ret = -ENOMEM;
-+ goto unlock_mutex;
-+ }
-+
-+ /* Initialize each attribute to take the name and size of the cell */
-+ list_for_each_entry(entry, &nvmem->cells, node) {
-+ sysfs_bin_attr_init(&attrs[i]);
-+ attrs[i].attr.name = devm_kasprintf(&nvmem->dev, GFP_KERNEL,
-+ "%s@%x", entry->name,
-+ entry->offset);
-+ attrs[i].attr.mode = 0444;
-+ attrs[i].size = entry->bytes;
-+ attrs[i].read = &nvmem_cell_attr_read;
-+ attrs[i].private = entry;
-+ if (!attrs[i].attr.name) {
-+ ret = -ENOMEM;
-+ goto unlock_mutex;
-+ }
-+
-+ cells_attrs[i] = &attrs[i];
-+ i++;
-+ }
-+
-+ nvmem_cells_group.bin_attrs = cells_attrs;
-+
-+ ret = devm_device_add_groups(&nvmem->dev, nvmem_cells_groups);
-+ if (ret)
-+ goto unlock_mutex;
-+
-+ nvmem->sysfs_cells_populated = true;
-+
-+unlock_mutex:
-+ mutex_unlock(&nvmem_mutex);
-+
-+ return ret;
-+}
-+
- #else /* CONFIG_NVMEM_SYSFS */
-
- static int nvmem_sysfs_setup_compat(struct nvmem_device *nvmem,
-@@ -752,11 +861,25 @@ static int nvmem_add_cells_from_fixed_la
-
- int nvmem_layout_register(struct nvmem_layout *layout)
- {
-+ int ret;
-+
- if (!layout->add_cells)
- return -EINVAL;
-
- /* Populate the cells */
-- return layout->add_cells(&layout->nvmem->dev, layout->nvmem);
-+ ret = layout->add_cells(&layout->nvmem->dev, layout->nvmem);
-+ if (ret)
-+ return ret;
-+
-+#ifdef CONFIG_NVMEM_SYSFS
-+ ret = nvmem_populate_sysfs_cells(layout->nvmem);
-+ if (ret) {
-+ nvmem_device_remove_all_cells(layout->nvmem);
-+ return ret;
-+ }
-+#endif
-+
-+ return 0;
- }
- EXPORT_SYMBOL_GPL(nvmem_layout_register);
-
-@@ -915,10 +1038,20 @@ struct nvmem_device *nvmem_register(cons
- if (rval)
- goto err_remove_dev;
-
-+#ifdef CONFIG_NVMEM_SYSFS
-+ rval = nvmem_populate_sysfs_cells(nvmem);
-+ if (rval)
-+ goto err_destroy_layout;
-+#endif
-+
- blocking_notifier_call_chain(&nvmem_notifier, NVMEM_ADD, nvmem);
-
- return nvmem;
-
-+#ifdef CONFIG_NVMEM_SYSFS
-+err_destroy_layout:
-+ nvmem_destroy_layout(nvmem);
-+#endif
- err_remove_dev:
- device_del(&nvmem->dev);
- err_remove_cells:
---- a/drivers/nvmem/internals.h
-+++ b/drivers/nvmem/internals.h
-@@ -32,6 +32,7 @@ struct nvmem_device {
- struct gpio_desc *wp_gpio;
- struct nvmem_layout *layout;
- void *priv;
-+ bool sysfs_cells_populated;
- };
-
- #if IS_ENABLED(CONFIG_OF)
+++ /dev/null
-From f0ac5b23039610619ca4a4805528553ecb6bc815 Mon Sep 17 00:00:00 2001
-Date: Fri, 15 Dec 2023 11:15:36 +0000
-Subject: [PATCH] nvmem: stm32: add support for STM32MP25 BSEC to control OTP
- data
-
-On STM32MP25, OTP area may be read/written by using BSEC (boot, security
-and OTP control). The BSEC internal peripheral is only managed by the
-secure world.
-
-The 12 Kbits of OTP (effective) are organized into the following regions:
-- lower OTP (OTP0 to OTP127) = 4096 lower OTP bits,
- bitwise (1-bit) programmable
-- mid OTP (OTP128 to OTP255) = 4096 middle OTP bits,
- bulk (32-bit) programmable
-- upper OTP (OTP256 to OTP383) = 4096 upper OTP bits,
- bulk (32-bit) programmable,
- only accessible when BSEC is in closed state.
-
-As HWKEY and ECIES key are only accessible by ROM code;
-only 368 OTP words are managed in this driver (OTP0 to OTP267).
-
-This patch adds the STM32MP25 configuration for reading and writing
-the OTP data using the OP-TEE BSEC TA services.
-
----
- drivers/nvmem/stm32-romem.c | 16 ++++++++++++++++
- 1 file changed, 16 insertions(+)
-
---- a/drivers/nvmem/stm32-romem.c
-+++ b/drivers/nvmem/stm32-romem.c
-@@ -269,6 +269,19 @@ static const struct stm32_romem_cfg stm3
- .ta = true,
- };
-
-+/*
-+ * STM32MP25 BSEC OTP: 3 regions of 32-bits data words
-+ * lower OTP (OTP0 to OTP127), bitwise (1-bit) programmable
-+ * mid OTP (OTP128 to OTP255), bulk (32-bit) programmable
-+ * upper OTP (OTP256 to OTP383), bulk (32-bit) programmable
-+ * but no access to HWKEY and ECIES key: limited at OTP367
-+ */
-+static const struct stm32_romem_cfg stm32mp25_bsec_cfg = {
-+ .size = 368 * 4,
-+ .lower = 127,
-+ .ta = true,
-+};
-+
- static const struct of_device_id stm32_romem_of_match[] __maybe_unused = {
- { .compatible = "st,stm32f4-otp", }, {
- .compatible = "st,stm32mp15-bsec",
-@@ -276,6 +289,9 @@ static const struct of_device_id stm32_r
- }, {
- .compatible = "st,stm32mp13-bsec",
- .data = (void *)&stm32mp13_bsec_cfg,
-+ }, {
-+ .compatible = "st,stm32mp25-bsec",
-+ .data = (void *)&stm32mp25_bsec_cfg,
- },
- { /* sentinel */ },
- };
+++ /dev/null
-From 401df0d4f4098ecc9c5278da2f50756d62e5b37d Mon Sep 17 00:00:00 2001
-Date: Tue, 19 Dec 2023 13:01:03 +0100
-Subject: [PATCH] nvmem: layouts: refactor .add_cells() callback arguments
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Simply pass whole "struct nvmem_layout" instead of single variables.
-There is nothing in "struct nvmem_layout" that we have to hide from
-layout drivers. They also access it during .probe() and .remove().
-
-Thanks to this change:
-
-1. API gets more consistent
- All layouts drivers callbacks get the same argument
-
-2. Layouts get correct device
- Before this change NVMEM core code was passing NVMEM device instead
- of layout device. That resulted in:
- * Confusing prints
- * Calling devm_*() helpers on wrong device
- * Helpers like of_device_get_match_data() dereferencing NULLs
-
-3. It gets possible to get match data
- First of all nvmem_layout_get_match_data() requires passing "struct
- nvmem_layout" which .add_cells() callback didn't have before this. It
- doesn't matter much as it's rather useless now anyway (and will be
- dropped).
- What's more important however is that of_device_get_match_data() can
- be used now thanks to owning a proper device pointer.
-
----
- drivers/nvmem/core.c | 2 +-
- drivers/nvmem/layouts/onie-tlv.c | 4 +++-
- drivers/nvmem/layouts/sl28vpd.c | 4 +++-
- include/linux/nvmem-provider.h | 2 +-
- 4 files changed, 8 insertions(+), 4 deletions(-)
-
---- a/drivers/nvmem/core.c
-+++ b/drivers/nvmem/core.c
-@@ -867,7 +867,7 @@ int nvmem_layout_register(struct nvmem_l
- return -EINVAL;
-
- /* Populate the cells */
-- ret = layout->add_cells(&layout->nvmem->dev, layout->nvmem);
-+ ret = layout->add_cells(layout);
- if (ret)
- return ret;
-
---- a/drivers/nvmem/layouts/onie-tlv.c
-+++ b/drivers/nvmem/layouts/onie-tlv.c
-@@ -182,8 +182,10 @@ static bool onie_tlv_crc_is_valid(struct
- return true;
- }
-
--static int onie_tlv_parse_table(struct device *dev, struct nvmem_device *nvmem)
-+static int onie_tlv_parse_table(struct nvmem_layout *layout)
- {
-+ struct nvmem_device *nvmem = layout->nvmem;
-+ struct device *dev = &layout->dev;
- struct onie_tlv_hdr hdr;
- size_t table_len, data_len, hdr_len;
- u8 *table, *data;
---- a/drivers/nvmem/layouts/sl28vpd.c
-+++ b/drivers/nvmem/layouts/sl28vpd.c
-@@ -80,8 +80,10 @@ static int sl28vpd_v1_check_crc(struct d
- return 0;
- }
-
--static int sl28vpd_add_cells(struct device *dev, struct nvmem_device *nvmem)
-+static int sl28vpd_add_cells(struct nvmem_layout *layout)
- {
-+ struct nvmem_device *nvmem = layout->nvmem;
-+ struct device *dev = &layout->dev;
- const struct nvmem_cell_info *pinfo;
- struct nvmem_cell_info info = {0};
- struct device_node *layout_np;
---- a/include/linux/nvmem-provider.h
-+++ b/include/linux/nvmem-provider.h
-@@ -173,7 +173,7 @@ struct nvmem_cell_table {
- struct nvmem_layout {
- struct device dev;
- struct nvmem_device *nvmem;
-- int (*add_cells)(struct device *dev, struct nvmem_device *nvmem);
-+ int (*add_cells)(struct nvmem_layout *layout);
- };
-
- struct nvmem_layout_driver {
+++ /dev/null
-From 43f60e3fb62edc7bd8891de8779fb422f4ae23ae Mon Sep 17 00:00:00 2001
-Date: Tue, 19 Dec 2023 13:01:04 +0100
-Subject: [PATCH] nvmem: drop nvmem_layout_get_match_data()
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Thanks for layouts refactoring we now have "struct device" associated
-with layout. Also its OF pointer points directly to the "nvmem-layout"
-DT node.
-
-All it takes to get match data is a generic of_device_get_match_data().
-
----
- drivers/nvmem/core.c | 13 -------------
- include/linux/nvmem-provider.h | 10 ----------
- 2 files changed, 23 deletions(-)
-
---- a/drivers/nvmem/core.c
-+++ b/drivers/nvmem/core.c
-@@ -889,19 +889,6 @@ void nvmem_layout_unregister(struct nvme
- }
- EXPORT_SYMBOL_GPL(nvmem_layout_unregister);
-
--const void *nvmem_layout_get_match_data(struct nvmem_device *nvmem,
-- struct nvmem_layout *layout)
--{
-- struct device_node __maybe_unused *layout_np;
-- const struct of_device_id *match;
--
-- layout_np = of_nvmem_layout_get_container(nvmem);
-- match = of_match_node(layout->dev.driver->of_match_table, layout_np);
--
-- return match ? match->data : NULL;
--}
--EXPORT_SYMBOL_GPL(nvmem_layout_get_match_data);
--
- /**
- * nvmem_register() - Register a nvmem device for given nvmem_config.
- * Also creates a binary entry in /sys/bus/nvmem/devices/dev-name/nvmem
---- a/include/linux/nvmem-provider.h
-+++ b/include/linux/nvmem-provider.h
-@@ -205,9 +205,6 @@ void nvmem_layout_driver_unregister(stru
- module_driver(__nvmem_layout_driver, nvmem_layout_driver_register, \
- nvmem_layout_driver_unregister)
-
--const void *nvmem_layout_get_match_data(struct nvmem_device *nvmem,
-- struct nvmem_layout *layout);
--
- #else
-
- static inline struct nvmem_device *nvmem_register(const struct nvmem_config *c)
-@@ -238,13 +235,6 @@ static inline int nvmem_layout_register(
-
- static inline void nvmem_layout_unregister(struct nvmem_layout *layout) {}
-
--static inline const void *
--nvmem_layout_get_match_data(struct nvmem_device *nvmem,
-- struct nvmem_layout *layout)
--{
-- return NULL;
--}
--
- #endif /* CONFIG_NVMEM */
-
- #if IS_ENABLED(CONFIG_NVMEM) && IS_ENABLED(CONFIG_OF)
+++ /dev/null
-From 998f0633773b3432829fe45d2cd2ffb842f3c78e Mon Sep 17 00:00:00 2001
-Date: Sat, 24 Feb 2024 11:45:07 +0000
-Subject: [PATCH] nvmem: mtk-efuse: Register MediaTek socinfo driver from efuse
-
-The socinfo driver reads chip information from eFuses and does not need
-any devicetree node. Register it from mtk-efuse.
-
-While at it, also add the name for this driver's nvmem_config.
-
----
- drivers/nvmem/mtk-efuse.c | 21 ++++++++++++++++++++-
- 1 file changed, 20 insertions(+), 1 deletion(-)
-
---- a/drivers/nvmem/mtk-efuse.c
-+++ b/drivers/nvmem/mtk-efuse.c
-@@ -68,6 +68,7 @@ static int mtk_efuse_probe(struct platfo
- struct nvmem_config econfig = {};
- struct mtk_efuse_priv *priv;
- const struct mtk_efuse_pdata *pdata;
-+ struct platform_device *socinfo;
-
- priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
- if (!priv)
-@@ -85,11 +86,20 @@ static int mtk_efuse_probe(struct platfo
- econfig.size = resource_size(res);
- econfig.priv = priv;
- econfig.dev = dev;
-+ econfig.name = "mtk-efuse";
- if (pdata->uses_post_processing)
- econfig.fixup_dt_cell_info = &mtk_efuse_fixup_dt_cell_info;
- nvmem = devm_nvmem_register(dev, &econfig);
-+ if (IS_ERR(nvmem))
-+ return PTR_ERR(nvmem);
-
-- return PTR_ERR_OR_ZERO(nvmem);
-+ socinfo = platform_device_register_data(&pdev->dev, "mtk-socinfo",
-+ PLATFORM_DEVID_AUTO, NULL, 0);
-+ if (IS_ERR(socinfo))
-+ dev_info(dev, "MediaTek SoC Information will be unavailable\n");
-+
-+ platform_set_drvdata(pdev, socinfo);
-+ return 0;
- }
-
- static const struct mtk_efuse_pdata mtk_mt8186_efuse_pdata = {
-@@ -108,8 +118,17 @@ static const struct of_device_id mtk_efu
- };
- MODULE_DEVICE_TABLE(of, mtk_efuse_of_match);
-
-+static void mtk_efuse_remove(struct platform_device *pdev)
-+{
-+ struct platform_device *socinfo = platform_get_drvdata(pdev);
-+
-+ if (!IS_ERR_OR_NULL(socinfo))
-+ platform_device_unregister(socinfo);
-+}
-+
- static struct platform_driver mtk_efuse_driver = {
- .probe = mtk_efuse_probe,
-+ .remove_new = mtk_efuse_remove,
- .driver = {
- .name = "mediatek,efuse",
- .of_match_table = mtk_efuse_of_match,
+++ /dev/null
-From 29be47fcd6a06ea2e79eeeca6e69ad1e23254a69 Mon Sep 17 00:00:00 2001
-Date: Sat, 24 Feb 2024 11:45:11 +0000
-Subject: [PATCH] nvmem: zynqmp_nvmem: zynqmp_nvmem_probe cleanup
-
-- Remove static nvmem_config declaration
-- Remove zynqmp_nvmem_data
-
----
- drivers/nvmem/zynqmp_nvmem.c | 37 ++++++++++++------------------------
- 1 file changed, 12 insertions(+), 25 deletions(-)
-
---- a/drivers/nvmem/zynqmp_nvmem.c
-+++ b/drivers/nvmem/zynqmp_nvmem.c
-@@ -1,6 +1,7 @@
- // SPDX-License-Identifier: GPL-2.0+
- /*
- * Copyright (C) 2019 Xilinx, Inc.
-+ * Copyright (C) 2022 - 2023, Advanced Micro Devices, Inc.
- */
-
- #include <linux/module.h>
-@@ -11,36 +12,25 @@
-
- #define SILICON_REVISION_MASK 0xF
-
--struct zynqmp_nvmem_data {
-- struct device *dev;
-- struct nvmem_device *nvmem;
--};
-
- static int zynqmp_nvmem_read(void *context, unsigned int offset,
- void *val, size_t bytes)
- {
-+ struct device *dev = context;
- int ret;
-- int idcode, version;
-- struct zynqmp_nvmem_data *priv = context;
-+ int idcode;
-+ int version;
-
- ret = zynqmp_pm_get_chipid(&idcode, &version);
- if (ret < 0)
- return ret;
-
-- dev_dbg(priv->dev, "Read chipid val %x %x\n", idcode, version);
-+ dev_dbg(dev, "Read chipid val %x %x\n", idcode, version);
- *(int *)val = version & SILICON_REVISION_MASK;
-
- return 0;
- }
-
--static struct nvmem_config econfig = {
-- .name = "zynqmp-nvmem",
-- .owner = THIS_MODULE,
-- .word_size = 1,
-- .size = 1,
-- .read_only = true,
--};
--
- static const struct of_device_id zynqmp_nvmem_match[] = {
- { .compatible = "xlnx,zynqmp-nvmem-fw", },
- { /* sentinel */ },
-@@ -50,21 +40,18 @@ MODULE_DEVICE_TABLE(of, zynqmp_nvmem_mat
- static int zynqmp_nvmem_probe(struct platform_device *pdev)
- {
- struct device *dev = &pdev->dev;
-- struct zynqmp_nvmem_data *priv;
-+ struct nvmem_config econfig = {};
-
-- priv = devm_kzalloc(dev, sizeof(struct zynqmp_nvmem_data), GFP_KERNEL);
-- if (!priv)
-- return -ENOMEM;
--
-- priv->dev = dev;
-+ econfig.name = "zynqmp-nvmem";
-+ econfig.owner = THIS_MODULE;
-+ econfig.word_size = 1;
-+ econfig.size = 1;
- econfig.dev = dev;
- econfig.add_legacy_fixed_of_cells = true;
-+ econfig.read_only = true;
- econfig.reg_read = zynqmp_nvmem_read;
-- econfig.priv = priv;
--
-- priv->nvmem = devm_nvmem_register(dev, &econfig);
-
-- return PTR_ERR_OR_ZERO(priv->nvmem);
-+ return PTR_ERR_OR_ZERO(devm_nvmem_register(dev, &econfig));
- }
-
- static struct platform_driver zynqmp_nvmem_driver = {
+++ /dev/null
-From 737c0c8d07b5f671c0a33cec95965fcb2d2ea893 Mon Sep 17 00:00:00 2001
-Date: Sat, 24 Feb 2024 11:45:12 +0000
-Subject: [PATCH] nvmem: zynqmp_nvmem: Add support to access efuse
-
-Add support to read/write efuse memory map of ZynqMP.
-Below are the offsets of ZynqMP efuse memory map
- 0 - SOC version(read only)
- 0xC - 0xFC -ZynqMP specific purpose efuses
- 0x100 - 0x17F - Physical Unclonable Function(PUF)
- efuses repurposed as user efuses
-
----
- drivers/nvmem/zynqmp_nvmem.c | 186 +++++++++++++++++++++++++++++++++--
- 1 file changed, 176 insertions(+), 10 deletions(-)
-
---- a/drivers/nvmem/zynqmp_nvmem.c
-+++ b/drivers/nvmem/zynqmp_nvmem.c
-@@ -4,6 +4,7 @@
- * Copyright (C) 2022 - 2023, Advanced Micro Devices, Inc.
- */
-
-+#include <linux/dma-mapping.h>
- #include <linux/module.h>
- #include <linux/nvmem-provider.h>
- #include <linux/of.h>
-@@ -11,24 +12,189 @@
- #include <linux/firmware/xlnx-zynqmp.h>
-
- #define SILICON_REVISION_MASK 0xF
-+#define P_USER_0_64_UPPER_MASK GENMASK(31, 16)
-+#define P_USER_127_LOWER_4_BIT_MASK GENMASK(3, 0)
-+#define WORD_INBYTES 4
-+#define SOC_VER_SIZE 0x4
-+#define EFUSE_MEMORY_SIZE 0x177
-+#define UNUSED_SPACE 0x8
-+#define ZYNQMP_NVMEM_SIZE (SOC_VER_SIZE + UNUSED_SPACE + \
-+ EFUSE_MEMORY_SIZE)
-+#define SOC_VERSION_OFFSET 0x0
-+#define EFUSE_START_OFFSET 0xC
-+#define EFUSE_END_OFFSET 0xFC
-+#define EFUSE_PUF_START_OFFSET 0x100
-+#define EFUSE_PUF_MID_OFFSET 0x140
-+#define EFUSE_PUF_END_OFFSET 0x17F
-+#define EFUSE_NOT_ENABLED 29
-
-+/*
-+ * efuse access type
-+ */
-+enum efuse_access {
-+ EFUSE_READ = 0,
-+ EFUSE_WRITE
-+};
-+
-+/**
-+ * struct xilinx_efuse - the basic structure
-+ * @src: address of the buffer to store the data to be write/read
-+ * @size: read/write word count
-+ * @offset: read/write offset
-+ * @flag: 0 - represents efuse read and 1- represents efuse write
-+ * @pufuserfuse:0 - represents non-puf efuses, offset is used for read/write
-+ * 1 - represents puf user fuse row number.
-+ *
-+ * this structure stores all the required details to
-+ * read/write efuse memory.
-+ */
-+struct xilinx_efuse {
-+ u64 src;
-+ u32 size;
-+ u32 offset;
-+ enum efuse_access flag;
-+ u32 pufuserfuse;
-+};
-+
-+static int zynqmp_efuse_access(void *context, unsigned int offset,
-+ void *val, size_t bytes, enum efuse_access flag,
-+ unsigned int pufflag)
-+{
-+ struct device *dev = context;
-+ struct xilinx_efuse *efuse;
-+ dma_addr_t dma_addr;
-+ dma_addr_t dma_buf;
-+ size_t words = bytes / WORD_INBYTES;
-+ int ret;
-+ int value;
-+ char *data;
-
--static int zynqmp_nvmem_read(void *context, unsigned int offset,
-- void *val, size_t bytes)
-+ if (bytes % WORD_INBYTES != 0) {
-+ dev_err(dev, "Bytes requested should be word aligned\n");
-+ return -EOPNOTSUPP;
-+ }
-+
-+ if (pufflag == 0 && offset % WORD_INBYTES) {
-+ dev_err(dev, "Offset requested should be word aligned\n");
-+ return -EOPNOTSUPP;
-+ }
-+
-+ if (pufflag == 1 && flag == EFUSE_WRITE) {
-+ memcpy(&value, val, bytes);
-+ if ((offset == EFUSE_PUF_START_OFFSET ||
-+ offset == EFUSE_PUF_MID_OFFSET) &&
-+ value & P_USER_0_64_UPPER_MASK) {
-+ dev_err(dev, "Only lower 4 bytes are allowed to be programmed in P_USER_0 & P_USER_64\n");
-+ return -EOPNOTSUPP;
-+ }
-+
-+ if (offset == EFUSE_PUF_END_OFFSET &&
-+ (value & P_USER_127_LOWER_4_BIT_MASK)) {
-+ dev_err(dev, "Only MSB 28 bits are allowed to be programmed for P_USER_127\n");
-+ return -EOPNOTSUPP;
-+ }
-+ }
-+
-+ efuse = dma_alloc_coherent(dev, sizeof(struct xilinx_efuse),
-+ &dma_addr, GFP_KERNEL);
-+ if (!efuse)
-+ return -ENOMEM;
-+
-+ data = dma_alloc_coherent(dev, sizeof(bytes),
-+ &dma_buf, GFP_KERNEL);
-+ if (!data) {
-+ ret = -ENOMEM;
-+ goto efuse_data_fail;
-+ }
-+
-+ if (flag == EFUSE_WRITE) {
-+ memcpy(data, val, bytes);
-+ efuse->flag = EFUSE_WRITE;
-+ } else {
-+ efuse->flag = EFUSE_READ;
-+ }
-+
-+ efuse->src = dma_buf;
-+ efuse->size = words;
-+ efuse->offset = offset;
-+ efuse->pufuserfuse = pufflag;
-+
-+ zynqmp_pm_efuse_access(dma_addr, (u32 *)&ret);
-+ if (ret != 0) {
-+ if (ret == EFUSE_NOT_ENABLED) {
-+ dev_err(dev, "efuse access is not enabled\n");
-+ ret = -EOPNOTSUPP;
-+ } else {
-+ dev_err(dev, "Error in efuse read %x\n", ret);
-+ ret = -EPERM;
-+ }
-+ goto efuse_access_err;
-+ }
-+
-+ if (flag == EFUSE_READ)
-+ memcpy(val, data, bytes);
-+efuse_access_err:
-+ dma_free_coherent(dev, sizeof(bytes),
-+ data, dma_buf);
-+efuse_data_fail:
-+ dma_free_coherent(dev, sizeof(struct xilinx_efuse),
-+ efuse, dma_addr);
-+
-+ return ret;
-+}
-+
-+static int zynqmp_nvmem_read(void *context, unsigned int offset, void *val, size_t bytes)
- {
- struct device *dev = context;
- int ret;
-+ int pufflag = 0;
- int idcode;
- int version;
-
-- ret = zynqmp_pm_get_chipid(&idcode, &version);
-- if (ret < 0)
-- return ret;
-+ if (offset >= EFUSE_PUF_START_OFFSET && offset <= EFUSE_PUF_END_OFFSET)
-+ pufflag = 1;
-+
-+ switch (offset) {
-+ /* Soc version offset is zero */
-+ case SOC_VERSION_OFFSET:
-+ if (bytes != SOC_VER_SIZE)
-+ return -EOPNOTSUPP;
-+
-+ ret = zynqmp_pm_get_chipid((u32 *)&idcode, (u32 *)&version);
-+ if (ret < 0)
-+ return ret;
-+
-+ dev_dbg(dev, "Read chipid val %x %x\n", idcode, version);
-+ *(int *)val = version & SILICON_REVISION_MASK;
-+ break;
-+ /* Efuse offset starts from 0xc */
-+ case EFUSE_START_OFFSET ... EFUSE_END_OFFSET:
-+ case EFUSE_PUF_START_OFFSET ... EFUSE_PUF_END_OFFSET:
-+ ret = zynqmp_efuse_access(context, offset, val,
-+ bytes, EFUSE_READ, pufflag);
-+ break;
-+ default:
-+ *(u32 *)val = 0xDEADBEEF;
-+ ret = 0;
-+ break;
-+ }
-+
-+ return ret;
-+}
-+
-+static int zynqmp_nvmem_write(void *context,
-+ unsigned int offset, void *val, size_t bytes)
-+{
-+ int pufflag = 0;
-+
-+ if (offset < EFUSE_START_OFFSET || offset > EFUSE_PUF_END_OFFSET)
-+ return -EOPNOTSUPP;
-
-- dev_dbg(dev, "Read chipid val %x %x\n", idcode, version);
-- *(int *)val = version & SILICON_REVISION_MASK;
-+ if (offset >= EFUSE_PUF_START_OFFSET && offset <= EFUSE_PUF_END_OFFSET)
-+ pufflag = 1;
-
-- return 0;
-+ return zynqmp_efuse_access(context, offset,
-+ val, bytes, EFUSE_WRITE, pufflag);
- }
-
- static const struct of_device_id zynqmp_nvmem_match[] = {
-@@ -45,11 +211,11 @@ static int zynqmp_nvmem_probe(struct pla
- econfig.name = "zynqmp-nvmem";
- econfig.owner = THIS_MODULE;
- econfig.word_size = 1;
-- econfig.size = 1;
-+ econfig.size = ZYNQMP_NVMEM_SIZE;
- econfig.dev = dev;
- econfig.add_legacy_fixed_of_cells = true;
-- econfig.read_only = true;
- econfig.reg_read = zynqmp_nvmem_read;
-+ econfig.reg_write = zynqmp_nvmem_write;
-
- return PTR_ERR_OR_ZERO(devm_nvmem_register(dev, &econfig));
- }
+++ /dev/null
-From 76c345edef754b16cab81ad9452cc49c09e67066 Mon Sep 17 00:00:00 2001
-Date: Sat, 24 Feb 2024 11:45:14 +0000
-Subject: [PATCH] nvmem: mtk-efuse: Drop NVMEM device name
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-The MT8183 has not one but two efuse devices. The static name and ID
-causes the second efuse device to fail to probe, due to duplicate sysfs
-entries.
-
-With the rework of the mtk-socinfo driver, lookup by name is no longer
-necessary. The custom name can simply be dropped.
-
----
- drivers/nvmem/mtk-efuse.c | 1 -
- 1 file changed, 1 deletion(-)
-
---- a/drivers/nvmem/mtk-efuse.c
-+++ b/drivers/nvmem/mtk-efuse.c
-@@ -86,7 +86,6 @@ static int mtk_efuse_probe(struct platfo
- econfig.size = resource_size(res);
- econfig.priv = priv;
- econfig.dev = dev;
-- econfig.name = "mtk-efuse";
- if (pdata->uses_post_processing)
- econfig.fixup_dt_cell_info = &mtk_efuse_fixup_dt_cell_info;
- nvmem = devm_nvmem_register(dev, &econfig);
+++ /dev/null
-From 8ec0faf2572216b4e25d6829cd41cf3ee2dab979 Mon Sep 17 00:00:00 2001
-Date: Sat, 24 Feb 2024 11:45:15 +0000
-Subject: [PATCH] nvmem: core: make nvmem_layout_bus_type const
-
-Since commit d492cc2573a0 ("driver core: device.h: make struct bus_type
-a const *"), the driver core can properly handle constant struct
-bus_type, move the nvmem_layout_bus_type variable to be a constant
-structure as well, placing it into read-only memory which can not be
-modified at runtime.
-
----
- drivers/nvmem/layouts.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/nvmem/layouts.c
-+++ b/drivers/nvmem/layouts.c
-@@ -45,7 +45,7 @@ static void nvmem_layout_bus_remove(stru
- return drv->remove(layout);
- }
-
--static struct bus_type nvmem_layout_bus_type = {
-+static const struct bus_type nvmem_layout_bus_type = {
- .name = "nvmem-layout",
- .match = nvmem_layout_bus_match,
- .probe = nvmem_layout_bus_probe,
+++ /dev/null
-From def3173d4f17b37cecbd74d7c269a080b0b01598 Mon Sep 17 00:00:00 2001
-Date: Sat, 24 Feb 2024 11:45:16 +0000
-Subject: [PATCH] nvmem: core: Print error on wrong bits DT property
-
-The algorithms in nvmem core are built with the constraint that
-bit_offset < 8. If bit_offset is greater the results are wrong. Print an
-error if the devicetree 'bits' property is outside of the valid range
-and abort parsing.
-
----
- drivers/nvmem/core.c | 5 +++++
- 1 file changed, 5 insertions(+)
-
---- a/drivers/nvmem/core.c
-+++ b/drivers/nvmem/core.c
-@@ -819,6 +819,11 @@ static int nvmem_add_cells_from_dt(struc
- if (addr && len == (2 * sizeof(u32))) {
- info.bit_offset = be32_to_cpup(addr++);
- info.nbits = be32_to_cpup(addr);
-+ if (info.bit_offset >= BITS_PER_BYTE || info.nbits < 1) {
-+ dev_err(dev, "nvmem: invalid bits on %pOF\n", child);
-+ of_node_put(child);
-+ return -EINVAL;
-+ }
- }
-
- info.np = of_node_get(child);
+++ /dev/null
-From 6d0ca4a2a7e25f9ad07c1f335f20b4d9e048cdd5 Mon Sep 17 00:00:00 2001
-Date: Tue, 30 Apr 2024 09:49:11 +0100
-Subject: [PATCH] nvmem: layouts: store owner from modules with
- nvmem_layout_driver_register()
-
-Modules registering driver with nvmem_layout_driver_register() might
-forget to set .owner field. The field is used by some of other kernel
-parts for reference counting (try_module_get()), so it is expected that
-drivers will set it.
-
-Solve the problem by moving this task away from the drivers to the core
-code, just like we did for platform_driver in
-commit 9447057eaff8 ("platform_device: use a macro instead of
-platform_driver_register").
-
----
- drivers/nvmem/layouts.c | 6 ++++--
- include/linux/nvmem-provider.h | 5 ++++-
- 2 files changed, 8 insertions(+), 3 deletions(-)
-
---- a/drivers/nvmem/layouts.c
-+++ b/drivers/nvmem/layouts.c
-@@ -52,13 +52,15 @@ static const struct bus_type nvmem_layou
- .remove = nvmem_layout_bus_remove,
- };
-
--int nvmem_layout_driver_register(struct nvmem_layout_driver *drv)
-+int __nvmem_layout_driver_register(struct nvmem_layout_driver *drv,
-+ struct module *owner)
- {
- drv->driver.bus = &nvmem_layout_bus_type;
-+ drv->driver.owner = owner;
-
- return driver_register(&drv->driver);
- }
--EXPORT_SYMBOL_GPL(nvmem_layout_driver_register);
-+EXPORT_SYMBOL_GPL(__nvmem_layout_driver_register);
-
- void nvmem_layout_driver_unregister(struct nvmem_layout_driver *drv)
- {
---- a/include/linux/nvmem-provider.h
-+++ b/include/linux/nvmem-provider.h
-@@ -199,7 +199,10 @@ int nvmem_add_one_cell(struct nvmem_devi
- int nvmem_layout_register(struct nvmem_layout *layout);
- void nvmem_layout_unregister(struct nvmem_layout *layout);
-
--int nvmem_layout_driver_register(struct nvmem_layout_driver *drv);
-+#define nvmem_layout_driver_register(drv) \
-+ __nvmem_layout_driver_register(drv, THIS_MODULE)
-+int __nvmem_layout_driver_register(struct nvmem_layout_driver *drv,
-+ struct module *owner);
- void nvmem_layout_driver_unregister(struct nvmem_layout_driver *drv);
- #define module_nvmem_layout_driver(__nvmem_layout_driver) \
- module_driver(__nvmem_layout_driver, nvmem_layout_driver_register, \
+++ /dev/null
-From 21833338eccb91194fec6ba7548d9c454824eca0 Mon Sep 17 00:00:00 2001
-Date: Tue, 30 Apr 2024 09:49:12 +0100
-Subject: [PATCH] nvmem: layouts: onie-tlv: drop driver owner initialization
-
-Core in nvmem_layout_driver_register() already sets the .owner, so
-driver does not need to.
-
----
- drivers/nvmem/layouts/onie-tlv.c | 1 -
- 1 file changed, 1 deletion(-)
-
---- a/drivers/nvmem/layouts/onie-tlv.c
-+++ b/drivers/nvmem/layouts/onie-tlv.c
-@@ -247,7 +247,6 @@ MODULE_DEVICE_TABLE(of, onie_tlv_of_matc
-
- static struct nvmem_layout_driver onie_tlv_layout = {
- .driver = {
-- .owner = THIS_MODULE,
- .name = "onie-tlv-layout",
- .of_match_table = onie_tlv_of_match_table,
- },
+++ /dev/null
-From 23fd602f21953c03c0714257d36685cd6b486f04 Mon Sep 17 00:00:00 2001
-Date: Tue, 30 Apr 2024 09:49:13 +0100
-Subject: [PATCH] nvmem: layouts: sl28vpd: drop driver owner initialization
-
-Core in nvmem_layout_driver_register() already sets the .owner, so
-driver does not need to.
-
----
- drivers/nvmem/layouts/sl28vpd.c | 1 -
- 1 file changed, 1 deletion(-)
-
---- a/drivers/nvmem/layouts/sl28vpd.c
-+++ b/drivers/nvmem/layouts/sl28vpd.c
-@@ -156,7 +156,6 @@ MODULE_DEVICE_TABLE(of, sl28vpd_of_match
-
- static struct nvmem_layout_driver sl28vpd_layout = {
- .driver = {
-- .owner = THIS_MODULE,
- .name = "kontron-sl28vpd-layout",
- .of_match_table = sl28vpd_of_match_table,
- },
+++ /dev/null
-From dc3d88ade857ba3dca34f008e0b0aed3ef79cb15 Mon Sep 17 00:00:00 2001
-Date: Tue, 30 Apr 2024 09:49:14 +0100
-Subject: [PATCH] nvmem: sc27xx: fix module autoloading
-
-Add MODULE_DEVICE_TABLE(), so the module could be properly autoloaded
-based on the alias from of_device_id table.
-
----
- drivers/nvmem/sc27xx-efuse.c | 1 +
- 1 file changed, 1 insertion(+)
-
---- a/drivers/nvmem/sc27xx-efuse.c
-+++ b/drivers/nvmem/sc27xx-efuse.c
-@@ -262,6 +262,7 @@ static const struct of_device_id sc27xx_
- { .compatible = "sprd,sc2730-efuse", .data = &sc2730_edata},
- { }
- };
-+MODULE_DEVICE_TABLE(of, sc27xx_efuse_of_match);
-
- static struct platform_driver sc27xx_efuse_driver = {
- .probe = sc27xx_efuse_probe,
+++ /dev/null
-From 154c1ec943e34f3188c9305b0c91d5e7dc1373b8 Mon Sep 17 00:00:00 2001
-Date: Tue, 30 Apr 2024 09:49:15 +0100
-Subject: [PATCH] nvmem: sprd: fix module autoloading
-
-Add MODULE_DEVICE_TABLE(), so the module could be properly autoloaded
-based on the alias from of_device_id table.
-
----
- drivers/nvmem/sprd-efuse.c | 1 +
- 1 file changed, 1 insertion(+)
-
---- a/drivers/nvmem/sprd-efuse.c
-+++ b/drivers/nvmem/sprd-efuse.c
-@@ -426,6 +426,7 @@ static const struct of_device_id sprd_ef
- { .compatible = "sprd,ums312-efuse", .data = &ums312_data },
- { }
- };
-+MODULE_DEVICE_TABLE(of, sprd_efuse_of_match);
-
- static struct platform_driver sprd_efuse_driver = {
- .probe = sprd_efuse_probe,
+++ /dev/null
-From 8d8fc146dd7a0d6a6b37695747a524310dfb9d57 Mon Sep 17 00:00:00 2001
-Date: Tue, 30 Apr 2024 09:49:16 +0100
-Subject: [PATCH] nvmem: core: switch to use device_add_groups()
-
-devm_device_add_groups() is being removed from the kernel, so move the
-nvmem driver to use device_add_groups() instead. The logic is
-identical, when the device is removed the driver core will properly
-clean up and remove the groups, and the memory used by the attribute
-groups will be freed because it was created with dev_* calls, so this is
-functionally identical overall.
-
----
- drivers/nvmem/core.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/nvmem/core.c
-+++ b/drivers/nvmem/core.c
-@@ -476,7 +476,7 @@ static int nvmem_populate_sysfs_cells(st
-
- nvmem_cells_group.bin_attrs = cells_attrs;
-
-- ret = devm_device_add_groups(&nvmem->dev, nvmem_cells_groups);
-+ ret = device_add_groups(&nvmem->dev, nvmem_cells_groups);
- if (ret)
- goto unlock_mutex;
-
+++ /dev/null
-From 693d2f629962628ddefc88f4b6b453edda5ac32e Mon Sep 17 00:00:00 2001
-Date: Tue, 30 Apr 2024 09:49:17 +0100
-Subject: [PATCH] nvmem: lpc18xx_eeprom: Convert to platform remove callback
- returning void
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-The .remove() callback for a platform driver returns an int which makes
-many driver authors wrongly assume it's possible to do error handling by
-returning an error code. However the value returned is ignored (apart
-from emitting a warning) and this typically results in resource leaks.
-
-To improve here there is a quest to make the remove callback return
-void. In the first step of this quest all drivers are converted to
-.remove_new(), which already returns void. Eventually after all drivers
-are converted, .remove_new() will be renamed to .remove().
-
-Trivially convert this driver from always returning zero in the remove
-callback to the void returning variant.
-
----
- drivers/nvmem/lpc18xx_eeprom.c | 6 ++----
- 1 file changed, 2 insertions(+), 4 deletions(-)
-
---- a/drivers/nvmem/lpc18xx_eeprom.c
-+++ b/drivers/nvmem/lpc18xx_eeprom.c
-@@ -249,13 +249,11 @@ err_clk:
- return ret;
- }
-
--static int lpc18xx_eeprom_remove(struct platform_device *pdev)
-+static void lpc18xx_eeprom_remove(struct platform_device *pdev)
- {
- struct lpc18xx_eeprom_dev *eeprom = platform_get_drvdata(pdev);
-
- clk_disable_unprepare(eeprom->clk);
--
-- return 0;
- }
-
- static const struct of_device_id lpc18xx_eeprom_of_match[] = {
-@@ -266,7 +264,7 @@ MODULE_DEVICE_TABLE(of, lpc18xx_eeprom_o
-
- static struct platform_driver lpc18xx_eeprom_driver = {
- .probe = lpc18xx_eeprom_probe,
-- .remove = lpc18xx_eeprom_remove,
-+ .remove_new = lpc18xx_eeprom_remove,
- .driver = {
- .name = "lpc18xx-eeprom",
- .of_match_table = lpc18xx_eeprom_of_match,
+++ /dev/null
-From 2a1ad6b75292d38aa2f6ded7335979e0632521da Mon Sep 17 00:00:00 2001
-Date: Tue, 30 Apr 2024 09:49:21 +0100
-Subject: [PATCH] nvmem: meson-mx-efuse: Remove nvmem_device from efuse struct
-
-nvmem_device is used at one place while registering nvmem
-device and it is not required to be present in efuse struct
-for just this purpose.
-
-Drop nvmem_device and manage with nvmem device stack variable.
-
----
- drivers/nvmem/meson-mx-efuse.c | 6 +++---
- 1 file changed, 3 insertions(+), 3 deletions(-)
-
---- a/drivers/nvmem/meson-mx-efuse.c
-+++ b/drivers/nvmem/meson-mx-efuse.c
-@@ -43,7 +43,6 @@ struct meson_mx_efuse_platform_data {
- struct meson_mx_efuse {
- void __iomem *base;
- struct clk *core_clk;
-- struct nvmem_device *nvmem;
- struct nvmem_config config;
- };
-
-@@ -193,6 +192,7 @@ static int meson_mx_efuse_probe(struct p
- {
- const struct meson_mx_efuse_platform_data *drvdata;
- struct meson_mx_efuse *efuse;
-+ struct nvmem_device *nvmem;
-
- drvdata = of_device_get_match_data(&pdev->dev);
- if (!drvdata)
-@@ -223,9 +223,9 @@ static int meson_mx_efuse_probe(struct p
- return PTR_ERR(efuse->core_clk);
- }
-
-- efuse->nvmem = devm_nvmem_register(&pdev->dev, &efuse->config);
-+ nvmem = devm_nvmem_register(&pdev->dev, &efuse->config);
-
-- return PTR_ERR_OR_ZERO(efuse->nvmem);
-+ return PTR_ERR_OR_ZERO(nvmem);
- }
-
- static struct platform_driver meson_mx_efuse_driver = {
+++ /dev/null
-From c553bad4c5fc5ae44bd2fcaa73e1d6bedfb1c35c Mon Sep 17 00:00:00 2001
-Date: Fri, 5 Jul 2024 08:48:38 +0100
-Subject: [PATCH] nvmem: add missing MODULE_DESCRIPTION() macros
-
-make allmodconfig && make W=1 C=1 reports:
-WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/nvmem/nvmem-apple-efuses.o
-WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/nvmem/nvmem_brcm_nvram.o
-WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/nvmem/nvmem_u-boot-env.o
-
-Add the missing invocations of the MODULE_DESCRIPTION() macro.
-
----
- drivers/nvmem/apple-efuses.c | 1 +
- drivers/nvmem/brcm_nvram.c | 1 +
- drivers/nvmem/u-boot-env.c | 1 +
- 3 files changed, 3 insertions(+)
-
---- a/drivers/nvmem/apple-efuses.c
-+++ b/drivers/nvmem/apple-efuses.c
-@@ -78,4 +78,5 @@ static struct platform_driver apple_efus
- module_platform_driver(apple_efuses_driver);
-
-+MODULE_DESCRIPTION("Apple SoC eFuse driver");
- MODULE_LICENSE("GPL");
---- a/drivers/nvmem/brcm_nvram.c
-+++ b/drivers/nvmem/brcm_nvram.c
-@@ -253,5 +253,6 @@ static int __init brcm_nvram_init(void)
- subsys_initcall_sync(brcm_nvram_init);
-
- MODULE_AUTHOR("Rafał Miłecki");
-+MODULE_DESCRIPTION("Broadcom I/O-mapped NVRAM support driver");
- MODULE_LICENSE("GPL");
- MODULE_DEVICE_TABLE(of, brcm_nvram_of_match_table);
---- a/drivers/nvmem/u-boot-env.c
-+++ b/drivers/nvmem/u-boot-env.c
-@@ -256,5 +256,6 @@ static struct platform_driver u_boot_env
- module_platform_driver(u_boot_env_driver);
-
- MODULE_AUTHOR("Rafał Miłecki");
-+MODULE_DESCRIPTION("U-Boot environment variables support module");
- MODULE_LICENSE("GPL");
- MODULE_DEVICE_TABLE(of, u_boot_env_of_match_table);
+++ /dev/null
-From 5fecb932607d83d37a703c731268e9d9051457f5 Mon Sep 17 00:00:00 2001
-Date: Fri, 5 Jul 2024 08:48:40 +0100
-Subject: [PATCH] nvmem: meson-efuse: Replacing the use of of_node_put to
- __free
-
-Use __free for device_node values, and thus drop calls to
-of_node_put.
-
-The goal is to reduce memory management issues by using this
-scope-based of_node_put() cleanup to simplify function exit
-handling. When using __free a resource is allocated within a
-block, it is automatically freed at the end of the block.
-
----
- drivers/nvmem/meson-efuse.c | 5 ++---
- 1 file changed, 2 insertions(+), 3 deletions(-)
-
---- a/drivers/nvmem/meson-efuse.c
-+++ b/drivers/nvmem/meson-efuse.c
-@@ -48,20 +48,19 @@ static int meson_efuse_probe(struct plat
- {
- struct device *dev = &pdev->dev;
- struct meson_sm_firmware *fw;
-- struct device_node *sm_np;
- struct nvmem_device *nvmem;
- struct nvmem_config *econfig;
- struct clk *clk;
- unsigned int size;
-+ struct device_node *sm_np __free(device_node) =
-+ of_parse_phandle(pdev->dev.of_node, "secure-monitor", 0);
-
-- sm_np = of_parse_phandle(pdev->dev.of_node, "secure-monitor", 0);
- if (!sm_np) {
- dev_err(&pdev->dev, "no secure-monitor node\n");
- return -ENODEV;
- }
-
- fw = meson_sm_get(sm_np);
-- of_node_put(sm_np);
- if (!fw)
- return -EPROBE_DEFER;
-
+++ /dev/null
-From 39f95600d8c53355b212a117e91a6ba15e0cac47 Mon Sep 17 00:00:00 2001
-Date: Fri, 5 Jul 2024 08:48:42 +0100
-Subject: [PATCH] nvmem: rockchip-otp: Set type to OTP
-
-The Rockchip OTP is obviously an OTP memory, so document this fact.
-
----
- drivers/nvmem/rockchip-otp.c | 1 +
- 1 file changed, 1 insertion(+)
-
---- a/drivers/nvmem/rockchip-otp.c
-+++ b/drivers/nvmem/rockchip-otp.c
-@@ -256,6 +256,7 @@ static struct nvmem_config otp_config =
- .name = "rockchip-otp",
- .owner = THIS_MODULE,
- .add_legacy_fixed_of_cells = true,
-+ .type = NVMEM_TYPE_OTP,
- .read_only = true,
- .stride = 1,
- .word_size = 1,
+++ /dev/null
-From ba64a04474d2989f397982c48e405cfd785e2dd5 Mon Sep 17 00:00:00 2001
-Date: Fri, 5 Jul 2024 08:48:43 +0100
-Subject: [PATCH] nvmem: rockchip-efuse: set type to OTP
-
-This device currently reports an "Unknown" type in sysfs.
-Since it is an eFuse hardware device, set its type to OTP.
-
----
- drivers/nvmem/rockchip-efuse.c | 1 +
- 1 file changed, 1 insertion(+)
-
---- a/drivers/nvmem/rockchip-efuse.c
-+++ b/drivers/nvmem/rockchip-efuse.c
-@@ -206,6 +206,7 @@ static int rockchip_rk3399_efuse_read(vo
- static struct nvmem_config econfig = {
- .name = "rockchip-efuse",
- .add_legacy_fixed_of_cells = true,
-+ .type = NVMEM_TYPE_OTP,
- .stride = 1,
- .word_size = 1,
- .read_only = true,
+++ /dev/null
-From 6188f233161c6a5b2d1c396a221dfafc77dc9eec Mon Sep 17 00:00:00 2001
-Date: Fri, 5 Jul 2024 08:48:46 +0100
-Subject: [PATCH] nvmem: core: add single sysfs group
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-The sysfs core provides a function to easily register a single group.
-Use it and remove the now unnecessary nvmem_cells_groups array.
-
----
- drivers/nvmem/core.c | 7 +------
- 1 file changed, 1 insertion(+), 6 deletions(-)
-
---- a/drivers/nvmem/core.c
-+++ b/drivers/nvmem/core.c
-@@ -367,11 +367,6 @@ static const struct attribute_group *nvm
- NULL,
- };
-
--static const struct attribute_group *nvmem_cells_groups[] = {
-- &nvmem_cells_group,
-- NULL,
--};
--
- static struct bin_attribute bin_attr_nvmem_eeprom_compat = {
- .attr = {
- .name = "eeprom",
-@@ -476,7 +471,7 @@ static int nvmem_populate_sysfs_cells(st
-
- nvmem_cells_group.bin_attrs = cells_attrs;
-
-- ret = device_add_groups(&nvmem->dev, nvmem_cells_groups);
-+ ret = device_add_group(&nvmem->dev, &nvmem_cells_group);
- if (ret)
- goto unlock_mutex;
-
+++ /dev/null
-From 6839fed062b7898665983368c88269a6fb1fc10f Mon Sep 17 00:00:00 2001
-Date: Fri, 5 Jul 2024 08:48:47 +0100
-Subject: [PATCH] nvmem: core: remove global nvmem_cells_group
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-nvmem_cells_groups is a global variable that is also mutated.
-This is complicated and error-prone.
-
-Instead use a normal stack variable.
-
----
- drivers/nvmem/core.c | 26 ++++++++++----------------
- 1 file changed, 10 insertions(+), 16 deletions(-)
-
---- a/drivers/nvmem/core.c
-+++ b/drivers/nvmem/core.c
-@@ -357,11 +357,6 @@ static const struct attribute_group nvme
- .is_bin_visible = nvmem_bin_attr_is_visible,
- };
-
--/* Cell attributes will be dynamically allocated */
--static struct attribute_group nvmem_cells_group = {
-- .name = "cells",
--};
--
- static const struct attribute_group *nvmem_dev_groups[] = {
- &nvmem_bin_group,
- NULL,
-@@ -423,23 +418,24 @@ static void nvmem_sysfs_remove_compat(st
-
- static int nvmem_populate_sysfs_cells(struct nvmem_device *nvmem)
- {
-- struct bin_attribute **cells_attrs, *attrs;
-+ struct attribute_group group = {
-+ .name = "cells",
-+ };
- struct nvmem_cell_entry *entry;
-+ struct bin_attribute *attrs;
- unsigned int ncells = 0, i = 0;
- int ret = 0;
-
- mutex_lock(&nvmem_mutex);
-
-- if (list_empty(&nvmem->cells) || nvmem->sysfs_cells_populated) {
-- nvmem_cells_group.bin_attrs = NULL;
-+ if (list_empty(&nvmem->cells) || nvmem->sysfs_cells_populated)
- goto unlock_mutex;
-- }
-
- /* Allocate an array of attributes with a sentinel */
- ncells = list_count_nodes(&nvmem->cells);
-- cells_attrs = devm_kcalloc(&nvmem->dev, ncells + 1,
-- sizeof(struct bin_attribute *), GFP_KERNEL);
-- if (!cells_attrs) {
-+ group.bin_attrs = devm_kcalloc(&nvmem->dev, ncells + 1,
-+ sizeof(struct bin_attribute *), GFP_KERNEL);
-+ if (!group.bin_attrs) {
- ret = -ENOMEM;
- goto unlock_mutex;
- }
-@@ -465,13 +461,11 @@ static int nvmem_populate_sysfs_cells(st
- goto unlock_mutex;
- }
-
-- cells_attrs[i] = &attrs[i];
-+ group.bin_attrs[i] = &attrs[i];
- i++;
- }
-
-- nvmem_cells_group.bin_attrs = cells_attrs;
--
-- ret = device_add_group(&nvmem->dev, &nvmem_cells_group);
-+ ret = device_add_group(&nvmem->dev, &group);
- if (ret)
- goto unlock_mutex;
-
+++ /dev/null
-From 588773802c386d38f9c4e91acd47369e89d95a30 Mon Sep 17 00:00:00 2001
-Date: Fri, 5 Jul 2024 08:48:48 +0100
-Subject: [PATCH] nvmem: core: drop unnecessary range checks in sysfs callbacks
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-The same checks have already been done in sysfs_kf_bin_write() and
-sysfs_kf_bin_read() just before the callbacks are invoked.
-
----
- drivers/nvmem/core.c | 14 --------------
- 1 file changed, 14 deletions(-)
-
---- a/drivers/nvmem/core.c
-+++ b/drivers/nvmem/core.c
-@@ -203,19 +203,12 @@ static ssize_t bin_attr_nvmem_read(struc
- dev = kobj_to_dev(kobj);
- nvmem = to_nvmem_device(dev);
-
-- /* Stop the user from reading */
-- if (pos >= nvmem->size)
-- return 0;
--
- if (!IS_ALIGNED(pos, nvmem->stride))
- return -EINVAL;
-
- if (count < nvmem->word_size)
- return -EINVAL;
-
-- if (pos + count > nvmem->size)
-- count = nvmem->size - pos;
--
- count = round_down(count, nvmem->word_size);
-
- if (!nvmem->reg_read)
-@@ -243,19 +236,12 @@ static ssize_t bin_attr_nvmem_write(stru
- dev = kobj_to_dev(kobj);
- nvmem = to_nvmem_device(dev);
-
-- /* Stop the user from writing */
-- if (pos >= nvmem->size)
-- return -EFBIG;
--
- if (!IS_ALIGNED(pos, nvmem->stride))
- return -EINVAL;
-
- if (count < nvmem->word_size)
- return -EINVAL;
-
-- if (pos + count > nvmem->size)
-- count = nvmem->size - pos;
--
- count = round_down(count, nvmem->word_size);
-
- if (!nvmem->reg_write)
+++ /dev/null
-From 08c367e45b6d322956878774f0b88bf5e52c6d54 Mon Sep 17 00:00:00 2001
-Date: Fri, 5 Jul 2024 08:48:51 +0100
-Subject: [PATCH] nvmem: Use sysfs_emit() for type attribute
-
-Use sysfs_emit() instead of sprintf() to follow best practice per
-Documentation/filesystems/sysfs.rst
-"
-show() should only use sysfs_emit()...
-"
-
----
- drivers/nvmem/core.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/nvmem/core.c
-+++ b/drivers/nvmem/core.c
-@@ -179,7 +179,7 @@ static ssize_t type_show(struct device *
- {
- struct nvmem_device *nvmem = to_nvmem_device(dev);
-
-- return sprintf(buf, "%s\n", nvmem_type_str[nvmem->type]);
-+ return sysfs_emit(buf, "%s\n", nvmem_type_str[nvmem->type]);
- }
-
- static DEVICE_ATTR_RO(type);
+++ /dev/null
-From 9d7eb234ac7a56b88aea8a52ed81553a730fe25c Mon Sep 17 00:00:00 2001
-Date: Fri, 5 Jul 2024 08:48:52 +0100
-Subject: [PATCH] nvmem: core: Implement force_ro sysfs attribute
-
-Implement "force_ro" sysfs attribute to allow users to set read-write
-devices as read-only and back to read-write from userspace. The choice
-of the name is based on MMC core 'force_ro' attribute.
-
-This solves a situation where an AT24 I2C EEPROM with GPIO based nWP
-signal may have to be occasionally updated. Such I2C EEPROM device is
-usually set as read-only during most of the regular system operation,
-but in case it has to be updated in a controlled manner, it could be
-unlocked using this new "force_ro" sysfs attribute and then re-locked
-again.
-
-The "read-only" DT property and config->read_only configuration is
-respected and is used to set default state of the device, read-only
-or read-write, for devices which do implement .reg_write function.
-For devices which do not implement .reg_write function, the device
-is unconditionally read-only and the "force_ro" attribute is not
-visible.
-
----
- Documentation/ABI/stable/sysfs-bus-nvmem | 17 ++++++++++
- drivers/nvmem/core.c | 43 ++++++++++++++++++++++++
- 2 files changed, 60 insertions(+)
-
---- a/Documentation/ABI/stable/sysfs-bus-nvmem
-+++ b/Documentation/ABI/stable/sysfs-bus-nvmem
-@@ -1,3 +1,20 @@
-+What: /sys/bus/nvmem/devices/.../force_ro
-+Date: June 2024
-+KernelVersion: 6.11
-+Description:
-+ This read/write attribute allows users to set read-write
-+ devices as read-only and back to read-write from userspace.
-+ This can be used to unlock and relock write-protection of
-+ devices which are generally locked, except during sporadic
-+ programming operation.
-+ Read returns '0' or '1' for read-write or read-only modes
-+ respectively.
-+ Write parses one of 'YyTt1NnFf0', or [oO][NnFf] for "on"
-+ and "off", i.e. what kstrbool() supports.
-+ Note: This file is only present if CONFIG_NVMEM_SYSFS
-+ is enabled.
-+
- What: /sys/bus/nvmem/devices/.../nvmem
- Date: July 2015
- KernelVersion: 4.2
---- a/drivers/nvmem/core.c
-+++ b/drivers/nvmem/core.c
-@@ -184,7 +184,30 @@ static ssize_t type_show(struct device *
-
- static DEVICE_ATTR_RO(type);
-
-+static ssize_t force_ro_show(struct device *dev, struct device_attribute *attr,
-+ char *buf)
-+{
-+ struct nvmem_device *nvmem = to_nvmem_device(dev);
-+
-+ return sysfs_emit(buf, "%d\n", nvmem->read_only);
-+}
-+
-+static ssize_t force_ro_store(struct device *dev, struct device_attribute *attr,
-+ const char *buf, size_t count)
-+{
-+ struct nvmem_device *nvmem = to_nvmem_device(dev);
-+ int ret = kstrtobool(buf, &nvmem->read_only);
-+
-+ if (ret < 0)
-+ return ret;
-+
-+ return count;
-+}
-+
-+static DEVICE_ATTR_RW(force_ro);
-+
- static struct attribute *nvmem_attrs[] = {
-+ &dev_attr_force_ro.attr,
- &dev_attr_type.attr,
- NULL,
- };
-@@ -285,6 +308,25 @@ static umode_t nvmem_bin_attr_is_visible
- return nvmem_bin_attr_get_umode(nvmem);
- }
-
-+static umode_t nvmem_attr_is_visible(struct kobject *kobj,
-+ struct attribute *attr, int i)
-+{
-+ struct device *dev = kobj_to_dev(kobj);
-+ struct nvmem_device *nvmem = to_nvmem_device(dev);
-+
-+ /*
-+ * If the device has no .reg_write operation, do not allow
-+ * configuration as read-write.
-+ * If the device is set as read-only by configuration, it
-+ * can be forced into read-write mode using the 'force_ro'
-+ * attribute.
-+ */
-+ if (attr == &dev_attr_force_ro.attr && !nvmem->reg_write)
-+ return 0; /* Attribute not visible */
-+
-+ return attr->mode;
-+}
-+
- static struct nvmem_cell *nvmem_create_cell(struct nvmem_cell_entry *entry,
- const char *id, int index);
-
-@@ -341,6 +383,7 @@ static const struct attribute_group nvme
- .bin_attrs = nvmem_bin_attributes,
- .attrs = nvmem_attrs,
- .is_bin_visible = nvmem_bin_attr_is_visible,
-+ .is_visible = nvmem_attr_is_visible,
- };
-
- static const struct attribute_group *nvmem_dev_groups[] = {
+++ /dev/null
-From c3f9b7b4e5f9de319d00784577cda42036ff243a Mon Sep 17 00:00:00 2001
-Date: Mon, 2 Sep 2024 15:29:45 +0100
-Subject: [PATCH] nvmem: imx-ocotp-ele: support i.MX95
-
-i.MX95 OCOTP has same accessing method, so add an entry for i.MX95, but
-some fuse has ECC feature, so only read out the lower 16bits for ECC fuses.
-
----
- drivers/nvmem/imx-ocotp-ele.c | 32 +++++++++++++++++++++++++++++---
- 1 file changed, 29 insertions(+), 3 deletions(-)
-
---- a/drivers/nvmem/imx-ocotp-ele.c
-+++ b/drivers/nvmem/imx-ocotp-ele.c
-@@ -15,8 +15,9 @@
- #include <linux/if_ether.h> /* ETH_ALEN */
-
- enum fuse_type {
-- FUSE_FSB = 1,
-- FUSE_ELE = 2,
-+ FUSE_FSB = BIT(0),
-+ FUSE_ELE = BIT(1),
-+ FUSE_ECC = BIT(2),
- FUSE_INVALID = -1
- };
-
-@@ -96,7 +97,10 @@ static int imx_ocotp_reg_read(void *cont
- continue;
- }
-
-- *buf++ = readl_relaxed(reg + (i << 2));
-+ if (type & FUSE_ECC)
-+ *buf++ = readl_relaxed(reg + (i << 2)) & GENMASK(15, 0);
-+ else
-+ *buf++ = readl_relaxed(reg + (i << 2));
- }
-
- memcpy(val, ((u8 *)p) + skipbytes, bytes);
-@@ -182,8 +186,30 @@ static const struct ocotp_devtype_data i
- },
- };
-
-+static const struct ocotp_devtype_data imx95_ocotp_data = {
-+ .reg_off = 0x8000,
-+ .reg_read = imx_ocotp_reg_read,
-+ .size = 2048,
-+ .num_entry = 12,
-+ .entry = {
-+ { 0, 1, FUSE_FSB | FUSE_ECC },
-+ { 7, 1, FUSE_FSB | FUSE_ECC },
-+ { 9, 3, FUSE_FSB | FUSE_ECC },
-+ { 12, 24, FUSE_FSB },
-+ { 36, 2, FUSE_FSB | FUSE_ECC },
-+ { 38, 14, FUSE_FSB },
-+ { 63, 1, FUSE_ELE },
-+ { 128, 16, FUSE_ELE },
-+ { 188, 1, FUSE_ELE },
-+ { 317, 2, FUSE_FSB | FUSE_ECC },
-+ { 320, 7, FUSE_FSB },
-+ { 328, 184, FUSE_FSB }
-+ },
-+};
-+
- static const struct of_device_id imx_ele_ocotp_dt_ids[] = {
- { .compatible = "fsl,imx93-ocotp", .data = &imx93_ocotp_data, },
-+ { .compatible = "fsl,imx95-ocotp", .data = &imx95_ocotp_data, },
- {},
- };
- MODULE_DEVICE_TABLE(of, imx_ele_ocotp_dt_ids);
+++ /dev/null
-From 98ee46391baf35987227236d0c3bb30ab6e758c8 Mon Sep 17 00:00:00 2001
-Date: Mon, 2 Sep 2024 15:29:50 +0100
-Subject: [PATCH] nvmem: sunplus-ocotp: Use
- devm_platform_ioremap_resource_byname() helper function
-
-platform_get_resource_byname() and devm_ioremap_resource() can be
-replaced by devm_platform_ioremap_resource_byname(), which can
-simplify the code logic a bit, No functional change here.
-
----
- drivers/nvmem/sunplus-ocotp.c | 7 ++-----
- 1 file changed, 2 insertions(+), 5 deletions(-)
-
---- a/drivers/nvmem/sunplus-ocotp.c
-+++ b/drivers/nvmem/sunplus-ocotp.c
-@@ -159,7 +159,6 @@ static int sp_ocotp_probe(struct platfor
- struct device *dev = &pdev->dev;
- struct nvmem_device *nvmem;
- struct sp_ocotp_priv *otp;
-- struct resource *res;
- int ret;
-
- otp = devm_kzalloc(dev, sizeof(*otp), GFP_KERNEL);
-@@ -168,13 +167,11 @@ static int sp_ocotp_probe(struct platfor
-
- otp->dev = dev;
-
-- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "hb_gpio");
-- otp->base[HB_GPIO] = devm_ioremap_resource(dev, res);
-+ otp->base[HB_GPIO] = devm_platform_ioremap_resource_byname(pdev, "hb_gpio");
- if (IS_ERR(otp->base[HB_GPIO]))
- return PTR_ERR(otp->base[HB_GPIO]);
-
-- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "otprx");
-- otp->base[OTPRX] = devm_ioremap_resource(dev, res);
-+ otp->base[OTPRX] = devm_platform_ioremap_resource_byname(pdev, "otprx");
- if (IS_ERR(otp->base[OTPRX]))
- return PTR_ERR(otp->base[OTPRX]);
-
+++ /dev/null
-From 5f15811286aff4664bf275a7ede64e1b8858151b Mon Sep 17 00:00:00 2001
-Date: Mon, 2 Sep 2024 15:29:47 +0100
-Subject: [PATCH] nvmem: layouts: add U-Boot env layout
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-U-Boot environment variables are stored in a specific format. Actual
-data can be placed in various storage sources (MTD, UBI volume, EEPROM,
-NVRAM, etc.).
-
-Move all generic (NVMEM device independent) code from NVMEM device
-driver to an NVMEM layout driver. Then add a simple NVMEM layout code on
-top of it.
-
-This allows using NVMEM layout for parsing U-Boot env data stored in any
-kind of NVMEM device.
-
-The old NVMEM glue driver stays in place for handling bindings in the
-MTD context. To avoid code duplication it uses exported layout parsing
-function. Please note that handling MTD & NVMEM layout bindings may be
-refactored in the future.
-
----
- MAINTAINERS | 1 +
- drivers/nvmem/Kconfig | 3 +-
- drivers/nvmem/layouts/Kconfig | 11 ++
- drivers/nvmem/layouts/Makefile | 1 +
- drivers/nvmem/layouts/u-boot-env.c | 211 +++++++++++++++++++++++++++++
- drivers/nvmem/layouts/u-boot-env.h | 15 ++
- drivers/nvmem/u-boot-env.c | 165 +---------------------
- 7 files changed, 242 insertions(+), 165 deletions(-)
- create mode 100644 drivers/nvmem/layouts/u-boot-env.c
- create mode 100644 drivers/nvmem/layouts/u-boot-env.h
-
---- a/MAINTAINERS
-+++ b/MAINTAINERS
-@@ -21991,6 +21991,7 @@ U-BOOT ENVIRONMENT VARIABLES
- S: Maintained
- F: Documentation/devicetree/bindings/nvmem/u-boot,env.yaml
-+F: drivers/nvmem/layouts/u-boot-env.c
- F: drivers/nvmem/u-boot-env.c
-
- UACCE ACCELERATOR FRAMEWORK
---- a/drivers/nvmem/Kconfig
-+++ b/drivers/nvmem/Kconfig
-@@ -363,8 +363,7 @@ config NVMEM_SUNXI_SID
- config NVMEM_U_BOOT_ENV
- tristate "U-Boot environment variables support"
- depends on OF && MTD
-- select CRC32
-- select GENERIC_NET_UTILS
-+ select NVMEM_LAYOUT_U_BOOT_ENV
- help
- U-Boot stores its setup as environment variables. This driver adds
- support for verifying & exporting such data. It also exposes variables
---- a/drivers/nvmem/layouts/Kconfig
-+++ b/drivers/nvmem/layouts/Kconfig
-@@ -26,6 +26,17 @@ config NVMEM_LAYOUT_ONIE_TLV
-
- If unsure, say N.
-
-+config NVMEM_LAYOUT_U_BOOT_ENV
-+ tristate "U-Boot environment variables layout"
-+ select CRC32
-+ select GENERIC_NET_UTILS
-+ help
-+ U-Boot stores its setup as environment variables. This driver adds
-+ support for verifying & exporting such data. It also exposes variables
-+ as NVMEM cells so they can be referenced by other drivers.
-+
-+ If unsure, say N.
-+
- endmenu
-
- endif
---- a/drivers/nvmem/layouts/Makefile
-+++ b/drivers/nvmem/layouts/Makefile
-@@ -5,3 +5,4 @@
-
- obj-$(CONFIG_NVMEM_LAYOUT_SL28_VPD) += sl28vpd.o
- obj-$(CONFIG_NVMEM_LAYOUT_ONIE_TLV) += onie-tlv.o
-+obj-$(CONFIG_NVMEM_LAYOUT_U_BOOT_ENV) += u-boot-env.o
---- /dev/null
-+++ b/drivers/nvmem/layouts/u-boot-env.c
-@@ -0,0 +1,211 @@
-+// SPDX-License-Identifier: GPL-2.0-only
-+/*
-+ */
-+
-+#include <linux/crc32.h>
-+#include <linux/etherdevice.h>
-+#include <linux/export.h>
-+#include <linux/if_ether.h>
-+#include <linux/nvmem-consumer.h>
-+#include <linux/nvmem-provider.h>
-+#include <linux/of.h>
-+#include <linux/slab.h>
-+
-+#include "u-boot-env.h"
-+
-+struct u_boot_env_image_single {
-+ __le32 crc32;
-+ uint8_t data[];
-+} __packed;
-+
-+struct u_boot_env_image_redundant {
-+ __le32 crc32;
-+ u8 mark;
-+ uint8_t data[];
-+} __packed;
-+
-+struct u_boot_env_image_broadcom {
-+ __le32 magic;
-+ __le32 len;
-+ __le32 crc32;
-+ DECLARE_FLEX_ARRAY(uint8_t, data);
-+} __packed;
-+
-+static int u_boot_env_read_post_process_ethaddr(void *context, const char *id, int index,
-+ unsigned int offset, void *buf, size_t bytes)
-+{
-+ u8 mac[ETH_ALEN];
-+
-+ if (bytes != 3 * ETH_ALEN - 1)
-+ return -EINVAL;
-+
-+ if (!mac_pton(buf, mac))
-+ return -EINVAL;
-+
-+ if (index)
-+ eth_addr_add(mac, index);
-+
-+ ether_addr_copy(buf, mac);
-+
-+ return 0;
-+}
-+
-+static int u_boot_env_parse_cells(struct device *dev, struct nvmem_device *nvmem, uint8_t *buf,
-+ size_t data_offset, size_t data_len)
-+{
-+ char *data = buf + data_offset;
-+ char *var, *value, *eq;
-+
-+ for (var = data;
-+ var < data + data_len && *var;
-+ var = value + strlen(value) + 1) {
-+ struct nvmem_cell_info info = {};
-+
-+ eq = strchr(var, '=');
-+ if (!eq)
-+ break;
-+ *eq = '\0';
-+ value = eq + 1;
-+
-+ info.name = devm_kstrdup(dev, var, GFP_KERNEL);
-+ if (!info.name)
-+ return -ENOMEM;
-+ info.offset = data_offset + value - data;
-+ info.bytes = strlen(value);
-+ info.np = of_get_child_by_name(dev->of_node, info.name);
-+ if (!strcmp(var, "ethaddr")) {
-+ info.raw_len = strlen(value);
-+ info.bytes = ETH_ALEN;
-+ info.read_post_process = u_boot_env_read_post_process_ethaddr;
-+ }
-+
-+ nvmem_add_one_cell(nvmem, &info);
-+ }
-+
-+ return 0;
-+}
-+
-+int u_boot_env_parse(struct device *dev, struct nvmem_device *nvmem,
-+ enum u_boot_env_format format)
-+{
-+ size_t crc32_data_offset;
-+ size_t crc32_data_len;
-+ size_t crc32_offset;
-+ uint32_t *crc32_addr;
-+ size_t data_offset;
-+ size_t data_len;
-+ size_t dev_size;
-+ uint32_t crc32;
-+ uint32_t calc;
-+ uint8_t *buf;
-+ int bytes;
-+ int err;
-+
-+ dev_size = nvmem_dev_size(nvmem);
-+
-+ buf = kzalloc(dev_size, GFP_KERNEL);
-+ if (!buf) {
-+ err = -ENOMEM;
-+ goto err_out;
-+ }
-+
-+ bytes = nvmem_device_read(nvmem, 0, dev_size, buf);
-+ if (bytes < 0) {
-+ err = bytes;
-+ goto err_kfree;
-+ } else if (bytes != dev_size) {
-+ err = -EIO;
-+ goto err_kfree;
-+ }
-+
-+ switch (format) {
-+ case U_BOOT_FORMAT_SINGLE:
-+ crc32_offset = offsetof(struct u_boot_env_image_single, crc32);
-+ crc32_data_offset = offsetof(struct u_boot_env_image_single, data);
-+ data_offset = offsetof(struct u_boot_env_image_single, data);
-+ break;
-+ case U_BOOT_FORMAT_REDUNDANT:
-+ crc32_offset = offsetof(struct u_boot_env_image_redundant, crc32);
-+ crc32_data_offset = offsetof(struct u_boot_env_image_redundant, data);
-+ data_offset = offsetof(struct u_boot_env_image_redundant, data);
-+ break;
-+ case U_BOOT_FORMAT_BROADCOM:
-+ crc32_offset = offsetof(struct u_boot_env_image_broadcom, crc32);
-+ crc32_data_offset = offsetof(struct u_boot_env_image_broadcom, data);
-+ data_offset = offsetof(struct u_boot_env_image_broadcom, data);
-+ break;
-+ }
-+
-+ if (dev_size < data_offset) {
-+ dev_err(dev, "Device too small for u-boot-env\n");
-+ err = -EIO;
-+ goto err_kfree;
-+ }
-+
-+ crc32_addr = (uint32_t *)(buf + crc32_offset);
-+ crc32 = *crc32_addr;
-+ crc32_data_len = dev_size - crc32_data_offset;
-+ data_len = dev_size - data_offset;
-+
-+ calc = crc32(~0, buf + crc32_data_offset, crc32_data_len) ^ ~0L;
-+ if (calc != crc32) {
-+ dev_err(dev, "Invalid calculated CRC32: 0x%08x (expected: 0x%08x)\n", calc, crc32);
-+ err = -EINVAL;
-+ goto err_kfree;
-+ }
-+
-+ buf[dev_size - 1] = '\0';
-+ err = u_boot_env_parse_cells(dev, nvmem, buf, data_offset, data_len);
-+
-+err_kfree:
-+ kfree(buf);
-+err_out:
-+ return err;
-+}
-+EXPORT_SYMBOL_GPL(u_boot_env_parse);
-+
-+static int u_boot_env_add_cells(struct nvmem_layout *layout)
-+{
-+ struct device *dev = &layout->dev;
-+ enum u_boot_env_format format;
-+
-+ format = (uintptr_t)device_get_match_data(dev);
-+
-+ return u_boot_env_parse(dev, layout->nvmem, format);
-+}
-+
-+static int u_boot_env_probe(struct nvmem_layout *layout)
-+{
-+ layout->add_cells = u_boot_env_add_cells;
-+
-+ return nvmem_layout_register(layout);
-+}
-+
-+static void u_boot_env_remove(struct nvmem_layout *layout)
-+{
-+ nvmem_layout_unregister(layout);
-+}
-+
-+static const struct of_device_id u_boot_env_of_match_table[] = {
-+ { .compatible = "u-boot,env", .data = (void *)U_BOOT_FORMAT_SINGLE, },
-+ { .compatible = "u-boot,env-redundant-bool", .data = (void *)U_BOOT_FORMAT_REDUNDANT, },
-+ { .compatible = "u-boot,env-redundant-count", .data = (void *)U_BOOT_FORMAT_REDUNDANT, },
-+ { .compatible = "brcm,env", .data = (void *)U_BOOT_FORMAT_BROADCOM, },
-+ {},
-+};
-+
-+static struct nvmem_layout_driver u_boot_env_layout = {
-+ .driver = {
-+ .name = "u-boot-env-layout",
-+ .of_match_table = u_boot_env_of_match_table,
-+ },
-+ .probe = u_boot_env_probe,
-+ .remove = u_boot_env_remove,
-+};
-+module_nvmem_layout_driver(u_boot_env_layout);
-+
-+MODULE_AUTHOR("Rafał Miłecki");
-+MODULE_LICENSE("GPL");
-+MODULE_DEVICE_TABLE(of, u_boot_env_of_match_table);
-+MODULE_DESCRIPTION("NVMEM layout driver for U-Boot environment variables");
---- /dev/null
-+++ b/drivers/nvmem/layouts/u-boot-env.h
-@@ -0,0 +1,15 @@
-+/* SPDX-License-Identifier: GPL-2.0-only */
-+
-+#ifndef _LINUX_NVMEM_LAYOUTS_U_BOOT_ENV_H
-+#define _LINUX_NVMEM_LAYOUTS_U_BOOT_ENV_H
-+
-+enum u_boot_env_format {
-+ U_BOOT_FORMAT_SINGLE,
-+ U_BOOT_FORMAT_REDUNDANT,
-+ U_BOOT_FORMAT_BROADCOM,
-+};
-+
-+int u_boot_env_parse(struct device *dev, struct nvmem_device *nvmem,
-+ enum u_boot_env_format format);
-+
-+#endif /* ifndef _LINUX_NVMEM_LAYOUTS_U_BOOT_ENV_H */
---- a/drivers/nvmem/u-boot-env.c
-+++ b/drivers/nvmem/u-boot-env.c
-@@ -3,23 +3,15 @@
- */
-
--#include <linux/crc32.h>
--#include <linux/etherdevice.h>
--#include <linux/if_ether.h>
- #include <linux/mod_devicetable.h>
- #include <linux/module.h>
- #include <linux/mtd/mtd.h>
--#include <linux/nvmem-consumer.h>
- #include <linux/nvmem-provider.h>
- #include <linux/of.h>
- #include <linux/platform_device.h>
- #include <linux/slab.h>
-
--enum u_boot_env_format {
-- U_BOOT_FORMAT_SINGLE,
-- U_BOOT_FORMAT_REDUNDANT,
-- U_BOOT_FORMAT_BROADCOM,
--};
-+#include "layouts/u-boot-env.h"
-
- struct u_boot_env {
- struct device *dev;
-@@ -29,24 +21,6 @@ struct u_boot_env {
- struct mtd_info *mtd;
- };
-
--struct u_boot_env_image_single {
-- __le32 crc32;
-- uint8_t data[];
--} __packed;
--
--struct u_boot_env_image_redundant {
-- __le32 crc32;
-- u8 mark;
-- uint8_t data[];
--} __packed;
--
--struct u_boot_env_image_broadcom {
-- __le32 magic;
-- __le32 len;
-- __le32 crc32;
-- DECLARE_FLEX_ARRAY(uint8_t, data);
--} __packed;
--
- static int u_boot_env_read(void *context, unsigned int offset, void *val,
- size_t bytes)
- {
-@@ -69,141 +43,6 @@ static int u_boot_env_read(void *context
- return 0;
- }
-
--static int u_boot_env_read_post_process_ethaddr(void *context, const char *id, int index,
-- unsigned int offset, void *buf, size_t bytes)
--{
-- u8 mac[ETH_ALEN];
--
-- if (bytes != 3 * ETH_ALEN - 1)
-- return -EINVAL;
--
-- if (!mac_pton(buf, mac))
-- return -EINVAL;
--
-- if (index)
-- eth_addr_add(mac, index);
--
-- ether_addr_copy(buf, mac);
--
-- return 0;
--}
--
--static int u_boot_env_add_cells(struct u_boot_env *priv, uint8_t *buf,
-- size_t data_offset, size_t data_len)
--{
-- struct nvmem_device *nvmem = priv->nvmem;
-- struct device *dev = priv->dev;
-- char *data = buf + data_offset;
-- char *var, *value, *eq;
--
-- for (var = data;
-- var < data + data_len && *var;
-- var = value + strlen(value) + 1) {
-- struct nvmem_cell_info info = {};
--
-- eq = strchr(var, '=');
-- if (!eq)
-- break;
-- *eq = '\0';
-- value = eq + 1;
--
-- info.name = devm_kstrdup(dev, var, GFP_KERNEL);
-- if (!info.name)
-- return -ENOMEM;
-- info.offset = data_offset + value - data;
-- info.bytes = strlen(value);
-- info.np = of_get_child_by_name(dev->of_node, info.name);
-- if (!strcmp(var, "ethaddr")) {
-- info.raw_len = strlen(value);
-- info.bytes = ETH_ALEN;
-- info.read_post_process = u_boot_env_read_post_process_ethaddr;
-- }
--
-- nvmem_add_one_cell(nvmem, &info);
-- }
--
-- return 0;
--}
--
--static int u_boot_env_parse(struct u_boot_env *priv)
--{
-- struct nvmem_device *nvmem = priv->nvmem;
-- struct device *dev = priv->dev;
-- size_t crc32_data_offset;
-- size_t crc32_data_len;
-- size_t crc32_offset;
-- uint32_t *crc32_addr;
-- size_t data_offset;
-- size_t data_len;
-- size_t dev_size;
-- uint32_t crc32;
-- uint32_t calc;
-- uint8_t *buf;
-- int bytes;
-- int err;
--
-- dev_size = nvmem_dev_size(nvmem);
--
-- buf = kzalloc(dev_size, GFP_KERNEL);
-- if (!buf) {
-- err = -ENOMEM;
-- goto err_out;
-- }
--
-- bytes = nvmem_device_read(nvmem, 0, dev_size, buf);
-- if (bytes < 0) {
-- err = bytes;
-- goto err_kfree;
-- } else if (bytes != dev_size) {
-- err = -EIO;
-- goto err_kfree;
-- }
--
-- switch (priv->format) {
-- case U_BOOT_FORMAT_SINGLE:
-- crc32_offset = offsetof(struct u_boot_env_image_single, crc32);
-- crc32_data_offset = offsetof(struct u_boot_env_image_single, data);
-- data_offset = offsetof(struct u_boot_env_image_single, data);
-- break;
-- case U_BOOT_FORMAT_REDUNDANT:
-- crc32_offset = offsetof(struct u_boot_env_image_redundant, crc32);
-- crc32_data_offset = offsetof(struct u_boot_env_image_redundant, data);
-- data_offset = offsetof(struct u_boot_env_image_redundant, data);
-- break;
-- case U_BOOT_FORMAT_BROADCOM:
-- crc32_offset = offsetof(struct u_boot_env_image_broadcom, crc32);
-- crc32_data_offset = offsetof(struct u_boot_env_image_broadcom, data);
-- data_offset = offsetof(struct u_boot_env_image_broadcom, data);
-- break;
-- }
--
-- if (dev_size < data_offset) {
-- dev_err(dev, "Device too small for u-boot-env\n");
-- err = -EIO;
-- goto err_kfree;
-- }
--
-- crc32_addr = (uint32_t *)(buf + crc32_offset);
-- crc32 = *crc32_addr;
-- crc32_data_len = dev_size - crc32_data_offset;
-- data_len = dev_size - data_offset;
--
-- calc = crc32(~0, buf + crc32_data_offset, crc32_data_len) ^ ~0L;
-- if (calc != crc32) {
-- dev_err(dev, "Invalid calculated CRC32: 0x%08x (expected: 0x%08x)\n", calc, crc32);
-- err = -EINVAL;
-- goto err_kfree;
-- }
--
-- buf[dev_size - 1] = '\0';
-- err = u_boot_env_add_cells(priv, buf, data_offset, data_len);
--
--err_kfree:
-- kfree(buf);
--err_out:
-- return err;
--}
--
- static int u_boot_env_probe(struct platform_device *pdev)
- {
- struct nvmem_config config = {
-@@ -235,7 +74,7 @@ static int u_boot_env_probe(struct platf
- if (IS_ERR(priv->nvmem))
- return PTR_ERR(priv->nvmem);
-
-- return u_boot_env_parse(priv);
-+ return u_boot_env_parse(dev, priv->nvmem, priv->format);
- }
-
- static const struct of_device_id u_boot_env_of_match_table[] = {
+++ /dev/null
-From edd25a77e69b7c546c28077e5dffe72c54c0afe8 Mon Sep 17 00:00:00 2001
-Date: Thu, 21 Sep 2023 22:18:12 +0200
-Subject: [PATCH 2/4] rtc: rtc7301: Support byte-addressed IO
-
-The old RTC7301 driver in OpenWrt used byte access, but the
-current mainline Linux driver uses 32bit word access.
-
-Make this configurable using device properties using the
-standard property "reg-io-width" in e.g. device tree.
-
-This is needed for the USRobotics USR8200 which has the
-chip connected using byte accesses.
-
-Debugging and testing by Howard Harte.
-
----
- drivers/rtc/rtc-r7301.c | 35 +++++++++++++++++++++++++++++++++--
- 1 file changed, 33 insertions(+), 2 deletions(-)
-
---- a/drivers/rtc/rtc-r7301.c
-+++ b/drivers/rtc/rtc-r7301.c
-@@ -14,6 +14,7 @@
- #include <linux/module.h>
- #include <linux/mod_devicetable.h>
- #include <linux/delay.h>
-+#include <linux/property.h>
- #include <linux/regmap.h>
- #include <linux/platform_device.h>
- #include <linux/rtc.h>
-@@ -55,12 +56,23 @@ struct rtc7301_priv {
- u8 bank;
- };
-
--static const struct regmap_config rtc7301_regmap_config = {
-+/*
-+ * When the device is memory-mapped, some platforms pack the registers into
-+ * 32-bit access using the lower 8 bits at each 4-byte stride, while others
-+ * expose them as simply consecutive bytes.
-+ */
-+static const struct regmap_config rtc7301_regmap_32_config = {
- .reg_bits = 32,
- .val_bits = 8,
- .reg_stride = 4,
- };
-
-+static const struct regmap_config rtc7301_regmap_8_config = {
-+ .reg_bits = 8,
-+ .val_bits = 8,
-+ .reg_stride = 1,
-+};
-+
- static u8 rtc7301_read(struct rtc7301_priv *priv, unsigned int reg)
- {
- int reg_stride = regmap_get_reg_stride(priv->regmap);
-@@ -356,7 +368,9 @@ static int __init rtc7301_rtc_probe(stru
- void __iomem *regs;
- struct rtc7301_priv *priv;
- struct rtc_device *rtc;
-+ static const struct regmap_config *mapconf;
- int ret;
-+ u32 val;
-
- priv = devm_kzalloc(&dev->dev, sizeof(*priv), GFP_KERNEL);
- if (!priv)
-@@ -366,8 +380,25 @@ static int __init rtc7301_rtc_probe(stru
- if (IS_ERR(regs))
- return PTR_ERR(regs);
-
-+ ret = device_property_read_u32(&dev->dev, "reg-io-width", &val);
-+ if (ret)
-+ /* Default to 32bit accesses */
-+ val = 4;
-+
-+ switch (val) {
-+ case 1:
-+ mapconf = &rtc7301_regmap_8_config;
-+ break;
-+ case 4:
-+ mapconf = &rtc7301_regmap_32_config;
-+ break;
-+ default:
-+ dev_err(&dev->dev, "invalid reg-io-width %d\n", val);
-+ return -EINVAL;
-+ }
-+
- priv->regmap = devm_regmap_init_mmio(&dev->dev, regs,
-- &rtc7301_regmap_config);
-+ mapconf);
- if (IS_ERR(priv->regmap))
- return PTR_ERR(priv->regmap);
-
+++ /dev/null
-From 49e5663b505070424e18099841943f34342aa405 Mon Sep 17 00:00:00 2001
-Date: Sun, 24 Sep 2023 01:09:01 +0200
-Subject: [PATCH] net: phy: amd: Support the Altima AMI101L
-
-The Altima AC101L is obviously compatible with the AMD PHY,
-as seen by reading the datasheet.
-
-Datasheet: https://docs.broadcom.com/doc/AC101L-DS05-405-RDS.pdf
-
----
- drivers/net/phy/Kconfig | 4 ++--
- drivers/net/phy/amd.c | 33 +++++++++++++++++++++++----------
- 2 files changed, 25 insertions(+), 12 deletions(-)
-
---- a/drivers/net/phy/Kconfig
-+++ b/drivers/net/phy/Kconfig
-@@ -86,9 +86,9 @@ config AIR_EN8811H_PHY
- Currently supports the Airoha EN8811H PHY.
-
- config AMD_PHY
-- tristate "AMD PHYs"
-+ tristate "AMD and Altima PHYs"
- help
-- Currently supports the am79c874
-+ Currently supports the AMD am79c874 and Altima AC101L.
-
- config MESON_GXL_PHY
- tristate "Amlogic Meson GXL Internal PHY"
---- a/drivers/net/phy/amd.c
-+++ b/drivers/net/phy/amd.c
-@@ -13,6 +13,7 @@
- #include <linux/mii.h>
- #include <linux/phy.h>
-
-+#define PHY_ID_AC101L 0x00225520
- #define PHY_ID_AM79C874 0x0022561b
-
- #define MII_AM79C_IR 17 /* Interrupt Status/Control Register */
-@@ -87,19 +88,31 @@ static irqreturn_t am79c_handle_interrup
- return IRQ_HANDLED;
- }
-
--static struct phy_driver am79c_driver[] = { {
-- .phy_id = PHY_ID_AM79C874,
-- .name = "AM79C874",
-- .phy_id_mask = 0xfffffff0,
-- /* PHY_BASIC_FEATURES */
-- .config_init = am79c_config_init,
-- .config_intr = am79c_config_intr,
-- .handle_interrupt = am79c_handle_interrupt,
--} };
-+static struct phy_driver am79c_drivers[] = {
-+ {
-+ .phy_id = PHY_ID_AM79C874,
-+ .name = "AM79C874",
-+ .phy_id_mask = 0xfffffff0,
-+ /* PHY_BASIC_FEATURES */
-+ .config_init = am79c_config_init,
-+ .config_intr = am79c_config_intr,
-+ .handle_interrupt = am79c_handle_interrupt,
-+ },
-+ {
-+ .phy_id = PHY_ID_AC101L,
-+ .name = "AC101L",
-+ .phy_id_mask = 0xfffffff0,
-+ /* PHY_BASIC_FEATURES */
-+ .config_init = am79c_config_init,
-+ .config_intr = am79c_config_intr,
-+ .handle_interrupt = am79c_handle_interrupt,
-+ },
-+};
-
--module_phy_driver(am79c_driver);
-+module_phy_driver(am79c_drivers);
-
- static struct mdio_device_id __maybe_unused amd_tbl[] = {
-+ { PHY_ID_AC101L, 0xfffffff0 },
- { PHY_ID_AM79C874, 0xfffffff0 },
- { }
- };
+++ /dev/null
-From a067943129b4ec6b835e02cfd5fbef01093c1471 Mon Sep 17 00:00:00 2001
-Date: Sun, 8 Oct 2023 16:40:13 +0200
-Subject: [PATCH] leds: core: Add more colors from DT bindings to led_colors
-
-The colors are already part of DT bindings. Make sure the kernel is
-able to convert them to strings.
-
----
- drivers/leds/led-core.c | 5 +++++
- 1 file changed, 5 insertions(+)
-
---- a/drivers/leds/led-core.c
-+++ b/drivers/leds/led-core.c
-@@ -36,6 +36,11 @@ const char * const led_colors[LED_COLOR_
- [LED_COLOR_ID_IR] = "ir",
- [LED_COLOR_ID_MULTI] = "multicolor",
- [LED_COLOR_ID_RGB] = "rgb",
-+ [LED_COLOR_ID_PURPLE] = "purple",
-+ [LED_COLOR_ID_ORANGE] = "orange",
-+ [LED_COLOR_ID_PINK] = "pink",
-+ [LED_COLOR_ID_CYAN] = "cyan",
-+ [LED_COLOR_ID_LIME] = "lime",
- };
- EXPORT_SYMBOL_GPL(led_colors);
-
+++ /dev/null
-From bc8e1da69a68d9871773b657d18400a7941cbdef Mon Sep 17 00:00:00 2001
-Date: Tue, 28 Nov 2023 04:00:10 +0000
-Subject: [PATCH] leds: trigger: netdev: Extend speeds up to 10G
-
-Add 2.5G, 5G and 10G as available speeds to the netdev LED trigger.
-
-Link: https://lore.kernel.org/r/99e7d3304c6bba7f4863a4a80764a869855f2085.1701143925.git.daniel@makrotopia.org
----
- drivers/leds/trigger/ledtrig-netdev.c | 32 ++++++++++++++++++++++++++-
- include/linux/leds.h | 3 +++
- 2 files changed, 34 insertions(+), 1 deletion(-)
-
---- a/drivers/leds/trigger/ledtrig-netdev.c
-+++ b/drivers/leds/trigger/ledtrig-netdev.c
-@@ -99,6 +99,18 @@ static void set_baseline_state(struct le
- trigger_data->link_speed == SPEED_1000)
- blink_on = true;
-
-+ if (test_bit(TRIGGER_NETDEV_LINK_2500, &trigger_data->mode) &&
-+ trigger_data->link_speed == SPEED_2500)
-+ blink_on = true;
-+
-+ if (test_bit(TRIGGER_NETDEV_LINK_5000, &trigger_data->mode) &&
-+ trigger_data->link_speed == SPEED_5000)
-+ blink_on = true;
-+
-+ if (test_bit(TRIGGER_NETDEV_LINK_10000, &trigger_data->mode) &&
-+ trigger_data->link_speed == SPEED_10000)
-+ blink_on = true;
-+
- if (test_bit(TRIGGER_NETDEV_HALF_DUPLEX, &trigger_data->mode) &&
- trigger_data->duplex == DUPLEX_HALF)
- blink_on = true;
-@@ -289,6 +301,9 @@ static ssize_t netdev_led_attr_show(stru
- case TRIGGER_NETDEV_LINK_10:
- case TRIGGER_NETDEV_LINK_100:
- case TRIGGER_NETDEV_LINK_1000:
-+ case TRIGGER_NETDEV_LINK_2500:
-+ case TRIGGER_NETDEV_LINK_5000:
-+ case TRIGGER_NETDEV_LINK_10000:
- case TRIGGER_NETDEV_HALF_DUPLEX:
- case TRIGGER_NETDEV_FULL_DUPLEX:
- case TRIGGER_NETDEV_TX:
-@@ -319,6 +334,9 @@ static ssize_t netdev_led_attr_store(str
- case TRIGGER_NETDEV_LINK_10:
- case TRIGGER_NETDEV_LINK_100:
- case TRIGGER_NETDEV_LINK_1000:
-+ case TRIGGER_NETDEV_LINK_2500:
-+ case TRIGGER_NETDEV_LINK_5000:
-+ case TRIGGER_NETDEV_LINK_10000:
- case TRIGGER_NETDEV_HALF_DUPLEX:
- case TRIGGER_NETDEV_FULL_DUPLEX:
- case TRIGGER_NETDEV_TX:
-@@ -337,7 +355,10 @@ static ssize_t netdev_led_attr_store(str
- if (test_bit(TRIGGER_NETDEV_LINK, &mode) &&
- (test_bit(TRIGGER_NETDEV_LINK_10, &mode) ||
- test_bit(TRIGGER_NETDEV_LINK_100, &mode) ||
-- test_bit(TRIGGER_NETDEV_LINK_1000, &mode)))
-+ test_bit(TRIGGER_NETDEV_LINK_1000, &mode) ||
-+ test_bit(TRIGGER_NETDEV_LINK_2500, &mode) ||
-+ test_bit(TRIGGER_NETDEV_LINK_5000, &mode) ||
-+ test_bit(TRIGGER_NETDEV_LINK_10000, &mode)))
- return -EINVAL;
-
- cancel_delayed_work_sync(&trigger_data->work);
-@@ -367,6 +388,9 @@ DEFINE_NETDEV_TRIGGER(link, TRIGGER_NETD
- DEFINE_NETDEV_TRIGGER(link_10, TRIGGER_NETDEV_LINK_10);
- DEFINE_NETDEV_TRIGGER(link_100, TRIGGER_NETDEV_LINK_100);
- DEFINE_NETDEV_TRIGGER(link_1000, TRIGGER_NETDEV_LINK_1000);
-+DEFINE_NETDEV_TRIGGER(link_2500, TRIGGER_NETDEV_LINK_2500);
-+DEFINE_NETDEV_TRIGGER(link_5000, TRIGGER_NETDEV_LINK_5000);
-+DEFINE_NETDEV_TRIGGER(link_10000, TRIGGER_NETDEV_LINK_10000);
- DEFINE_NETDEV_TRIGGER(half_duplex, TRIGGER_NETDEV_HALF_DUPLEX);
- DEFINE_NETDEV_TRIGGER(full_duplex, TRIGGER_NETDEV_FULL_DUPLEX);
- DEFINE_NETDEV_TRIGGER(tx, TRIGGER_NETDEV_TX);
-@@ -425,6 +449,9 @@ static struct attribute *netdev_trig_att
- &dev_attr_link_10.attr,
- &dev_attr_link_100.attr,
- &dev_attr_link_1000.attr,
-+ &dev_attr_link_2500.attr,
-+ &dev_attr_link_5000.attr,
-+ &dev_attr_link_10000.attr,
- &dev_attr_full_duplex.attr,
- &dev_attr_half_duplex.attr,
- &dev_attr_rx.attr,
-@@ -522,6 +549,9 @@ static void netdev_trig_work(struct work
- test_bit(TRIGGER_NETDEV_LINK_10, &trigger_data->mode) ||
- test_bit(TRIGGER_NETDEV_LINK_100, &trigger_data->mode) ||
- test_bit(TRIGGER_NETDEV_LINK_1000, &trigger_data->mode) ||
-+ test_bit(TRIGGER_NETDEV_LINK_2500, &trigger_data->mode) ||
-+ test_bit(TRIGGER_NETDEV_LINK_5000, &trigger_data->mode) ||
-+ test_bit(TRIGGER_NETDEV_LINK_10000, &trigger_data->mode) ||
- test_bit(TRIGGER_NETDEV_HALF_DUPLEX, &trigger_data->mode) ||
- test_bit(TRIGGER_NETDEV_FULL_DUPLEX, &trigger_data->mode);
- interval = jiffies_to_msecs(
---- a/include/linux/leds.h
-+++ b/include/linux/leds.h
-@@ -586,6 +586,9 @@ enum led_trigger_netdev_modes {
- TRIGGER_NETDEV_LINK_10,
- TRIGGER_NETDEV_LINK_100,
- TRIGGER_NETDEV_LINK_1000,
-+ TRIGGER_NETDEV_LINK_2500,
-+ TRIGGER_NETDEV_LINK_5000,
-+ TRIGGER_NETDEV_LINK_10000,
- TRIGGER_NETDEV_HALF_DUPLEX,
- TRIGGER_NETDEV_FULL_DUPLEX,
- TRIGGER_NETDEV_TX,
+++ /dev/null
-From 7ae215ee7bb855f13c80565470fc7f67db4ba82f Mon Sep 17 00:00:00 2001
-Date: Thu, 25 Jan 2024 21:36:59 +0100
-Subject: [PATCH 3/5] net: phy: add support for PHY LEDs polarity modes
-
-Add support for PHY LEDs polarity modes. Some PHY require LED to be set
-to active low to be turned ON. Adds support for this by declaring
-active-low property in DT.
-
-PHY driver needs to declare .led_polarity_set() to configure LED
-polarity modes. Function will pass the index with the LED index and a
-bitmap with all the required modes to set.
-
-Current supported modes are:
-- active-low with the flag PHY_LED_ACTIVE_LOW. LED is set to active-low
- to turn it ON.
-- inactive-high-impedance with the flag PHY_LED_INACTIVE_HIGH_IMPEDANCE.
- LED is set to high impedance to turn it OFF.
-
----
- drivers/net/phy/phy_device.c | 16 ++++++++++++++++
- include/linux/phy.h | 22 ++++++++++++++++++++++
- 2 files changed, 38 insertions(+)
-
---- a/drivers/net/phy/phy_device.c
-+++ b/drivers/net/phy/phy_device.c
-@@ -3226,6 +3226,7 @@ static int of_phy_led(struct phy_device
- struct device *dev = &phydev->mdio.dev;
- struct led_init_data init_data = {};
- struct led_classdev *cdev;
-+ unsigned long modes = 0;
- struct phy_led *phyled;
- u32 index;
- int err;
-@@ -3243,6 +3244,21 @@ static int of_phy_led(struct phy_device
- if (index > U8_MAX)
- return -EINVAL;
-
-+ if (of_property_read_bool(led, "active-low"))
-+ set_bit(PHY_LED_ACTIVE_LOW, &modes);
-+ if (of_property_read_bool(led, "inactive-high-impedance"))
-+ set_bit(PHY_LED_INACTIVE_HIGH_IMPEDANCE, &modes);
-+
-+ if (modes) {
-+ /* Return error if asked to set polarity modes but not supported */
-+ if (!phydev->drv->led_polarity_set)
-+ return -EINVAL;
-+
-+ err = phydev->drv->led_polarity_set(phydev, index, modes);
-+ if (err)
-+ return err;
-+ }
-+
- phyled->index = index;
- if (phydev->drv->led_brightness_set)
- cdev->brightness_set_blocking = phy_led_set_brightness;
---- a/include/linux/phy.h
-+++ b/include/linux/phy.h
-@@ -885,6 +885,15 @@ struct phy_led {
-
- #define to_phy_led(d) container_of(d, struct phy_led, led_cdev)
-
-+/* Modes for PHY LED configuration */
-+enum phy_led_modes {
-+ PHY_LED_ACTIVE_LOW = 0,
-+ PHY_LED_INACTIVE_HIGH_IMPEDANCE = 1,
-+
-+ /* keep it last */
-+ __PHY_LED_MODES_NUM,
-+};
-+
- /**
- * struct phy_driver - Driver structure for a particular PHY type
- *
-@@ -1175,6 +1184,19 @@ struct phy_driver {
- int (*led_hw_control_get)(struct phy_device *dev, u8 index,
- unsigned long *rules);
-
-+ /**
-+ * @led_polarity_set: Set the LED polarity modes
-+ * @dev: PHY device which has the LED
-+ * @index: Which LED of the PHY device
-+ * @modes: bitmap of LED polarity modes
-+ *
-+ * Configure LED with all the required polarity modes in @modes
-+ * to make it correctly turn ON or OFF.
-+ *
-+ * Returns 0, or an error code.
-+ */
-+ int (*led_polarity_set)(struct phy_device *dev, int index,
-+ unsigned long modes);
- };
- #define to_phy_driver(d) container_of(to_mdio_common_driver(d), \
- struct phy_driver, mdiodrv)
+++ /dev/null
-From cffac22c9215f1883d3848c788f9b03656dced27 Mon Sep 17 00:00:00 2001
-Date: Sun, 11 Feb 2024 18:39:19 +0100
-Subject: [PATCH] net: phy: aquantia: clear PMD Global Transmit Disable bit
- during init
-
-PMD Global Transmit Disable bit should be cleared for normal operation.
-This should be HW default, however I found that on Asus RT-AX89X that uses
-AQR113C PHY and firmware 5.4 this bit is set by default.
-
-With this bit set the AQR cannot achieve a link with its link-partner and
-it took me multiple hours of digging through the vendor GPL source to find
-this out, so lets always clear this bit during .config_init() to avoid a
-situation like this in the future.
-
-aqr107_wait_processor_intensive_op() is moved up because datasheet notes
-that any changes to this bit are processor intensive.
-
----
- drivers/net/phy/aquantia/aquantia_main.c | 57 ++++++++++++++----------
- 1 file changed, 33 insertions(+), 24 deletions(-)
-
---- a/drivers/net/phy/aquantia/aquantia_main.c
-+++ b/drivers/net/phy/aquantia/aquantia_main.c
-@@ -473,6 +473,30 @@ static void aqr107_chip_info(struct phy_
- fw_major, fw_minor, build_id, prov_id);
- }
-
-+static int aqr107_wait_processor_intensive_op(struct phy_device *phydev)
-+{
-+ int val, err;
-+
-+ /* The datasheet notes to wait at least 1ms after issuing a
-+ * processor intensive operation before checking.
-+ * We cannot use the 'sleep_before_read' parameter of read_poll_timeout
-+ * because that just determines the maximum time slept, not the minimum.
-+ */
-+ usleep_range(1000, 5000);
-+
-+ err = phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND1,
-+ VEND1_GLOBAL_GEN_STAT2, val,
-+ !(val & VEND1_GLOBAL_GEN_STAT2_OP_IN_PROG),
-+ AQR107_OP_IN_PROG_SLEEP,
-+ AQR107_OP_IN_PROG_TIMEOUT, false);
-+ if (err) {
-+ phydev_err(phydev, "timeout: processor-intensive MDIO operation\n");
-+ return err;
-+ }
-+
-+ return 0;
-+}
-+
- static int aqr107_config_init(struct phy_device *phydev)
- {
- struct aqr107_priv *priv = phydev->priv;
-@@ -498,6 +522,15 @@ static int aqr107_config_init(struct phy
- if (!ret)
- aqr107_chip_info(phydev);
-
-+ ret = phy_clear_bits_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_TXDIS,
-+ MDIO_PMD_TXDIS_GLOBAL);
-+ if (ret)
-+ return ret;
-+
-+ ret = aqr107_wait_processor_intensive_op(phydev);
-+ if (ret)
-+ return ret;
-+
- ret = aqr107_set_downshift(phydev, MDIO_AN_VEND_PROV_DOWNSHIFT_DFLT);
- if (ret)
- return ret;
-@@ -580,30 +613,6 @@ static void aqr107_link_change_notify(st
- phydev_info(phydev, "Aquantia 1000Base-T2 mode active\n");
- }
-
--static int aqr107_wait_processor_intensive_op(struct phy_device *phydev)
--{
-- int val, err;
--
-- /* The datasheet notes to wait at least 1ms after issuing a
-- * processor intensive operation before checking.
-- * We cannot use the 'sleep_before_read' parameter of read_poll_timeout
-- * because that just determines the maximum time slept, not the minimum.
-- */
-- usleep_range(1000, 5000);
--
-- err = phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND1,
-- VEND1_GLOBAL_GEN_STAT2, val,
-- !(val & VEND1_GLOBAL_GEN_STAT2_OP_IN_PROG),
-- AQR107_OP_IN_PROG_SLEEP,
-- AQR107_OP_IN_PROG_TIMEOUT, false);
-- if (err) {
-- phydev_err(phydev, "timeout: processor-intensive MDIO operation\n");
-- return err;
-- }
--
-- return 0;
--}
--
- static int aqr107_get_rate_matching(struct phy_device *phydev,
- phy_interface_t iface)
- {
+++ /dev/null
-From patchwork Tue Sep 17 13:49:40 2024
-Content-Type: text/plain; charset="utf-8"
-MIME-Version: 1.0
-Content-Transfer-Encoding: 7bit
-X-Patchwork-Id: 13806176
-Date: Tue, 17 Sep 2024 14:49:40 +0100
-Subject: [PATCH net 1/2] net: phy: aquantia: fix setting active_low bit
-Message-ID:
- <ab963584b0a7e3b4dac39472a4b82ca264d79630.1726580902.git.daniel@makrotopia.org>
-Precedence: bulk
-List-Id: <netdev.vger.kernel.org>
-MIME-Version: 1.0
-Content-Disposition: inline
-
-phy_modify_mmd was used wrongly in aqr_phy_led_active_low_set() resulting
-in a no-op instead of setting the VEND1_GLOBAL_LED_DRIVE_VDD bit.
-Correctly set VEND1_GLOBAL_LED_DRIVE_VDD bit.
-
-Fixes: 61578f679378 ("net: phy: aquantia: add support for PHY LEDs")
----
- drivers/net/phy/aquantia/aquantia_leds.c | 3 ++-
- 1 file changed, 2 insertions(+), 1 deletion(-)
-
---- a/drivers/net/phy/aquantia/aquantia_leds.c
-+++ b/drivers/net/phy/aquantia/aquantia_leds.c
-@@ -120,7 +120,8 @@ int aqr_phy_led_hw_control_set(struct ph
- int aqr_phy_led_active_low_set(struct phy_device *phydev, int index, bool enable)
- {
- return phy_modify_mmd(phydev, MDIO_MMD_VEND1, AQR_LED_DRIVE(index),
-- VEND1_GLOBAL_LED_DRIVE_VDD, enable);
-+ VEND1_GLOBAL_LED_DRIVE_VDD,
-+ enable ? VEND1_GLOBAL_LED_DRIVE_VDD : 0);
- }
-
- int aqr_phy_led_polarity_set(struct phy_device *phydev, int index, unsigned long modes)
+++ /dev/null
-From patchwork Tue Sep 17 13:49:55 2024
-Content-Type: text/plain; charset="utf-8"
-MIME-Version: 1.0
-Content-Transfer-Encoding: 7bit
-X-Patchwork-Id: 13806177
-Date: Tue, 17 Sep 2024 14:49:55 +0100
-Subject: [PATCH net 2/2] net: phy: aquantia: fix applying active_low bit
- after reset
-Message-ID:
- <9b1f0cd91f4cda54c8be56b4fe780480baf4aa0f.1726580902.git.daniel@makrotopia.org>
-References:
- <ab963584b0a7e3b4dac39472a4b82ca264d79630.1726580902.git.daniel@makrotopia.org>
-Precedence: bulk
-List-Id: <netdev.vger.kernel.org>
-MIME-Version: 1.0
-Content-Disposition: inline
-In-Reply-To:
- <ab963584b0a7e3b4dac39472a4b82ca264d79630.1726580902.git.daniel@makrotopia.org>
-
-for_each_set_bit was used wrongly in aqr107_config_init() when iterating
-over LEDs. Drop misleading 'index' variable and call
-aqr_phy_led_active_low_set() for each set bit representing an LED which
-is driven by VDD instead of GND pin.
-
-Fixes: 61578f679378 ("net: phy: aquantia: add support for PHY LEDs")
----
- drivers/net/phy/aquantia/aquantia_main.c | 5 ++---
- 1 file changed, 2 insertions(+), 3 deletions(-)
-
---- a/drivers/net/phy/aquantia/aquantia_main.c
-+++ b/drivers/net/phy/aquantia/aquantia_main.c
-@@ -501,7 +501,7 @@ static int aqr107_config_init(struct phy
- {
- struct aqr107_priv *priv = phydev->priv;
- u32 led_active_low;
-- int ret, index = 0;
-+ int ret;
-
- /* Check that the PHY interface type is compatible */
- if (phydev->interface != PHY_INTERFACE_MODE_SGMII &&
-@@ -537,10 +537,9 @@ static int aqr107_config_init(struct phy
-
- /* Restore LED polarity state after reset */
- for_each_set_bit(led_active_low, &priv->leds_active_low, AQR_MAX_LEDS) {
-- ret = aqr_phy_led_active_low_set(phydev, index, led_active_low);
-+ ret = aqr_phy_led_active_low_set(phydev, led_active_low, true);
- if (ret)
- return ret;
-- index++;
- }
-
- return 0;
+++ /dev/null
-From a2e1ba275eae96a8171deb19e9c7c2f5978fee7b Mon Sep 17 00:00:00 2001
-Date: Fri, 4 Oct 2024 17:18:16 +0100
-Subject: [PATCH] net: phy: aquantia: allow forcing order of MDI pairs
-
-Despite supporting Auto MDI-X, it looks like Aquantia only supports
-swapping pair (1,2) with pair (3,6) like it used to be for MDI-X on
-100MBit/s networks.
-
-When all 4 pairs are in use (for 1000MBit/s or faster) the link does not
-come up with pair order is not configured correctly, either using
-MDI_CFG pin or using the "PMA Receive Reserved Vendor Provisioning 1"
-register.
-
-Normally, the order of MDI pairs being either ABCD or DCBA is configured
-by pulling the MDI_CFG pin.
-
-However, some hardware designs require overriding the value configured
-by that bootstrap pin. The PHY allows doing that by setting a bit in
-"PMA Receive Reserved Vendor Provisioning 1" register which allows
-ignoring the state of the MDI_CFG pin and another bit configuring
-whether the order of MDI pairs should be normal (ABCD) or reverse
-(DCBA). Pair polarity is not affected and remains identical in both
-settings.
-
-Introduce property "marvell,mdi-cfg-order" which allows forcing either
-normal or reverse order of the MDI pairs from DT.
-
-If the property isn't present, the behavior is unchanged and MDI pair
-order configuration is untouched (ie. either the result of MDI_CFG pin
-pull-up/pull-down, or pair order override already configured by the
-bootloader before Linux is started).
-
-Forcing normal pair order is required on the Adtran SDG-8733A Wi-Fi 7
-residential gateway.
-
-Link: https://patch.msgid.link/9ed760ff87d5fc456f31e407ead548bbb754497d.1728058550.git.daniel@makrotopia.org
----
- drivers/net/phy/aquantia/aquantia_main.c | 33 ++++++++++++++++++++++++
- 1 file changed, 33 insertions(+)
-
---- a/drivers/net/phy/aquantia/aquantia_main.c
-+++ b/drivers/net/phy/aquantia/aquantia_main.c
-@@ -11,6 +11,7 @@
- #include <linux/module.h>
- #include <linux/delay.h>
- #include <linux/bitfield.h>
-+#include <linux/of.h>
- #include <linux/phy.h>
-
- #include "aquantia.h"
-@@ -70,6 +71,11 @@
- #define MDIO_AN_TX_VEND_INT_MASK2 0xd401
- #define MDIO_AN_TX_VEND_INT_MASK2_LINK BIT(0)
-
-+#define PMAPMD_RSVD_VEND_PROV 0xe400
-+#define PMAPMD_RSVD_VEND_PROV_MDI_CONF GENMASK(1, 0)
-+#define PMAPMD_RSVD_VEND_PROV_MDI_REVERSE BIT(0)
-+#define PMAPMD_RSVD_VEND_PROV_MDI_FORCE BIT(1)
-+
- #define MDIO_AN_RX_LP_STAT1 0xe820
- #define MDIO_AN_RX_LP_STAT1_1000BASET_FULL BIT(15)
- #define MDIO_AN_RX_LP_STAT1_1000BASET_HALF BIT(14)
-@@ -497,6 +503,29 @@ static int aqr107_wait_processor_intensi
- return 0;
- }
-
-+static int aqr107_config_mdi(struct phy_device *phydev)
-+{
-+ struct device_node *np = phydev->mdio.dev.of_node;
-+ u32 mdi_conf;
-+ int ret;
-+
-+ ret = of_property_read_u32(np, "marvell,mdi-cfg-order", &mdi_conf);
-+
-+ /* Do nothing in case property "marvell,mdi-cfg-order" is not present */
-+ if (ret == -ENOENT)
-+ return 0;
-+
-+ if (ret)
-+ return ret;
-+
-+ if (mdi_conf & ~PMAPMD_RSVD_VEND_PROV_MDI_REVERSE)
-+ return -EINVAL;
-+
-+ return phy_modify_mmd(phydev, MDIO_MMD_PMAPMD, PMAPMD_RSVD_VEND_PROV,
-+ PMAPMD_RSVD_VEND_PROV_MDI_CONF,
-+ mdi_conf | PMAPMD_RSVD_VEND_PROV_MDI_FORCE);
-+}
-+
- static int aqr107_config_init(struct phy_device *phydev)
- {
- struct aqr107_priv *priv = phydev->priv;
-@@ -535,6 +564,10 @@ static int aqr107_config_init(struct phy
- if (ret)
- return ret;
-
-+ ret = aqr107_config_mdi(phydev);
-+ if (ret)
-+ return ret;
-+
- /* Restore LED polarity state after reset */
- for_each_set_bit(led_active_low, &priv->leds_active_low, AQR_MAX_LEDS) {
- ret = aqr_phy_led_active_low_set(phydev, led_active_low, true);
+++ /dev/null
-From ce21b8fb255ebf0b49913fb4c62741d7eb05c6f6 Mon Sep 17 00:00:00 2001
-Date: Fri, 11 Oct 2024 22:28:43 +0100
-Subject: [PATCH] net: phy: aquantia: fix return value check in
- aqr107_config_mdi()
-
-of_property_read_u32() returns -EINVAL in case the property cannot be
-found rather than -ENOENT. Fix the check to not abort probing in case
-of the property being missing, and also in case CONFIG_OF is not set
-which will result in -ENOSYS.
-
-Fixes: a2e1ba275eae ("net: phy: aquantia: allow forcing order of MDI pairs")
----
- drivers/net/phy/aquantia/aquantia_main.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/net/phy/aquantia/aquantia_main.c
-+++ b/drivers/net/phy/aquantia/aquantia_main.c
-@@ -512,7 +512,7 @@ static int aqr107_config_mdi(struct phy_
- ret = of_property_read_u32(np, "marvell,mdi-cfg-order", &mdi_conf);
-
- /* Do nothing in case property "marvell,mdi-cfg-order" is not present */
-- if (ret == -ENOENT)
-+ if (ret == -EINVAL || ret == -ENOSYS)
- return 0;
-
- if (ret)
+++ /dev/null
-From a274465cc3bef2dfd9c9ea5100848dda0a8641e1 Mon Sep 17 00:00:00 2001
-Date: Thu, 10 Oct 2024 13:54:19 +0100
-Subject: [PATCH 1/4] net: phy: support 'active-high' property for PHY LEDs
-
-In addition to 'active-low' and 'inactive-high-impedance' also
-support 'active-high' property for PHY LED pin configuration.
-As only either 'active-high' or 'active-low' can be set at the
-same time, WARN and return an error in case both are set.
-
-Link: https://patch.msgid.link/91598487773d768f254d5faf06cf65b13e972f0e.1728558223.git.daniel@makrotopia.org
----
- drivers/net/phy/phy_device.c | 6 ++++++
- include/linux/phy.h | 5 +++--
- 2 files changed, 9 insertions(+), 2 deletions(-)
-
---- a/drivers/net/phy/phy_device.c
-+++ b/drivers/net/phy/phy_device.c
-@@ -3244,11 +3244,17 @@ static int of_phy_led(struct phy_device
- if (index > U8_MAX)
- return -EINVAL;
-
-+ if (of_property_read_bool(led, "active-high"))
-+ set_bit(PHY_LED_ACTIVE_HIGH, &modes);
- if (of_property_read_bool(led, "active-low"))
- set_bit(PHY_LED_ACTIVE_LOW, &modes);
- if (of_property_read_bool(led, "inactive-high-impedance"))
- set_bit(PHY_LED_INACTIVE_HIGH_IMPEDANCE, &modes);
-
-+ if (WARN_ON(modes & BIT(PHY_LED_ACTIVE_LOW) &&
-+ modes & BIT(PHY_LED_ACTIVE_HIGH)))
-+ return -EINVAL;
-+
- if (modes) {
- /* Return error if asked to set polarity modes but not supported */
- if (!phydev->drv->led_polarity_set)
---- a/include/linux/phy.h
-+++ b/include/linux/phy.h
-@@ -887,8 +887,9 @@ struct phy_led {
-
- /* Modes for PHY LED configuration */
- enum phy_led_modes {
-- PHY_LED_ACTIVE_LOW = 0,
-- PHY_LED_INACTIVE_HIGH_IMPEDANCE = 1,
-+ PHY_LED_ACTIVE_HIGH = 0,
-+ PHY_LED_ACTIVE_LOW = 1,
-+ PHY_LED_INACTIVE_HIGH_IMPEDANCE = 2,
-
- /* keep it last */
- __PHY_LED_MODES_NUM,
+++ /dev/null
-From 9d55e68b19f222e6334ef4021c5527998f5ab537 Mon Sep 17 00:00:00 2001
-Date: Thu, 10 Oct 2024 13:55:00 +0100
-Subject: [PATCH 2/4] net: phy: aquantia: correctly describe LED polarity
- override
-
-Use newly defined 'active-high' property to set the
-VEND1_GLOBAL_LED_DRIVE_VDD bit and let 'active-low' clear that bit. This
-reflects the technical reality which was inverted in the previous
-description in which the 'active-low' property was used to actually set
-the VEND1_GLOBAL_LED_DRIVE_VDD bit, which means that VDD (ie. supply
-voltage) of the LED is driven rather than GND.
-
-Link: https://patch.msgid.link/86a413b4387c42dcb54f587cc2433a06f16aae83.1728558223.git.daniel@makrotopia.org
----
- drivers/net/phy/aquantia/aquantia.h | 1 +
- drivers/net/phy/aquantia/aquantia_leds.c | 19 ++++++++++++++-----
- drivers/net/phy/aquantia/aquantia_main.c | 12 +++++++++---
- 3 files changed, 24 insertions(+), 8 deletions(-)
-
---- a/drivers/net/phy/aquantia/aquantia.h
-+++ b/drivers/net/phy/aquantia/aquantia.h
-@@ -169,6 +169,7 @@ static const struct aqr107_hw_stat aqr10
- struct aqr107_priv {
- u64 sgmii_stats[AQR107_SGMII_STAT_SZ];
- unsigned long leds_active_low;
-+ unsigned long leds_active_high;
- };
-
- #if IS_REACHABLE(CONFIG_HWMON)
---- a/drivers/net/phy/aquantia/aquantia_leds.c
-+++ b/drivers/net/phy/aquantia/aquantia_leds.c
-@@ -121,13 +121,13 @@ int aqr_phy_led_active_low_set(struct ph
- {
- return phy_modify_mmd(phydev, MDIO_MMD_VEND1, AQR_LED_DRIVE(index),
- VEND1_GLOBAL_LED_DRIVE_VDD,
-- enable ? VEND1_GLOBAL_LED_DRIVE_VDD : 0);
-+ enable ? 0 : VEND1_GLOBAL_LED_DRIVE_VDD);
- }
-
- int aqr_phy_led_polarity_set(struct phy_device *phydev, int index, unsigned long modes)
- {
-+ bool force_active_low = false, force_active_high = false;
- struct aqr107_priv *priv = phydev->priv;
-- bool active_low = false;
- u32 mode;
-
- if (index >= AQR_MAX_LEDS)
-@@ -136,7 +136,10 @@ int aqr_phy_led_polarity_set(struct phy_
- for_each_set_bit(mode, &modes, __PHY_LED_MODES_NUM) {
- switch (mode) {
- case PHY_LED_ACTIVE_LOW:
-- active_low = true;
-+ force_active_low = true;
-+ break;
-+ case PHY_LED_ACTIVE_HIGH:
-+ force_active_high = true;
- break;
- default:
- return -EINVAL;
-@@ -144,8 +147,14 @@ int aqr_phy_led_polarity_set(struct phy_
- }
-
- /* Save LED driver vdd state to restore on SW reset */
-- if (active_low)
-+ if (force_active_low)
- priv->leds_active_low |= BIT(index);
-
-- return aqr_phy_led_active_low_set(phydev, index, active_low);
-+ if (force_active_high)
-+ priv->leds_active_high |= BIT(index);
-+
-+ if (force_active_high || force_active_low)
-+ return aqr_phy_led_active_low_set(phydev, index, force_active_low);
-+
-+ unreachable();
- }
---- a/drivers/net/phy/aquantia/aquantia_main.c
-+++ b/drivers/net/phy/aquantia/aquantia_main.c
-@@ -529,7 +529,7 @@ static int aqr107_config_mdi(struct phy_
- static int aqr107_config_init(struct phy_device *phydev)
- {
- struct aqr107_priv *priv = phydev->priv;
-- u32 led_active_low;
-+ u32 led_idx;
- int ret;
-
- /* Check that the PHY interface type is compatible */
-@@ -569,8 +569,14 @@ static int aqr107_config_init(struct phy
- return ret;
-
- /* Restore LED polarity state after reset */
-- for_each_set_bit(led_active_low, &priv->leds_active_low, AQR_MAX_LEDS) {
-- ret = aqr_phy_led_active_low_set(phydev, led_active_low, true);
-+ for_each_set_bit(led_idx, &priv->leds_active_low, AQR_MAX_LEDS) {
-+ ret = aqr_phy_led_active_low_set(phydev, led_idx, true);
-+ if (ret)
-+ return ret;
-+ }
-+
-+ for_each_set_bit(led_idx, &priv->leds_active_high, AQR_MAX_LEDS) {
-+ ret = aqr_phy_led_active_low_set(phydev, led_idx, false);
- if (ret)
- return ret;
- }
+++ /dev/null
-From 78997e9a5e4d8a4df561e083a92c91ae23010e07 Mon Sep 17 00:00:00 2001
-Date: Tue, 1 Oct 2024 01:17:18 +0100
-Subject: [PATCH] net: phy: mxl-gpy: add basic LED support
-
-Add basic support for LEDs connected to MaxLinear GPY2xx and GPY115 PHYs.
-The PHYs allow up to 4 LEDs to be connected.
-Implement controlling LEDs in software as well as netdev trigger offloading
-and LED polarity setup.
-
-The hardware claims to support 16 PWM brightness levels but there is no
-documentation on how to use that feature, hence this is not supported.
-
-Link: https://patch.msgid.link/b6ec9050339f8244ff898898a1cecc33b13a48fc.1727741563.git.daniel@makrotopia.org
----
- drivers/net/phy/mxl-gpy.c | 218 ++++++++++++++++++++++++++++++++++++++
- 1 file changed, 218 insertions(+)
-
---- a/drivers/net/phy/mxl-gpy.c
-+++ b/drivers/net/phy/mxl-gpy.c
-@@ -38,6 +38,7 @@
- #define PHY_MIISTAT 0x18 /* MII state */
- #define PHY_IMASK 0x19 /* interrupt mask */
- #define PHY_ISTAT 0x1A /* interrupt status */
-+#define PHY_LED 0x1B /* LEDs */
- #define PHY_FWV 0x1E /* firmware version */
-
- #define PHY_MIISTAT_SPD_MASK GENMASK(2, 0)
-@@ -61,6 +62,11 @@
- PHY_IMASK_ADSC | \
- PHY_IMASK_ANC)
-
-+#define GPY_MAX_LEDS 4
-+#define PHY_LED_POLARITY(idx) BIT(12 + (idx))
-+#define PHY_LED_HWCONTROL(idx) BIT(8 + (idx))
-+#define PHY_LED_ON(idx) BIT(idx)
-+
- #define PHY_FWV_REL_MASK BIT(15)
- #define PHY_FWV_MAJOR_MASK GENMASK(11, 8)
- #define PHY_FWV_MINOR_MASK GENMASK(7, 0)
-@@ -72,6 +78,23 @@
- #define PHY_MDI_MDI_X_CD 0x1
- #define PHY_MDI_MDI_X_CROSS 0x0
-
-+/* LED */
-+#define VSPEC1_LED(idx) (1 + (idx))
-+#define VSPEC1_LED_BLINKS GENMASK(15, 12)
-+#define VSPEC1_LED_PULSE GENMASK(11, 8)
-+#define VSPEC1_LED_CON GENMASK(7, 4)
-+#define VSPEC1_LED_BLINKF GENMASK(3, 0)
-+
-+#define VSPEC1_LED_LINK10 BIT(0)
-+#define VSPEC1_LED_LINK100 BIT(1)
-+#define VSPEC1_LED_LINK1000 BIT(2)
-+#define VSPEC1_LED_LINK2500 BIT(3)
-+
-+#define VSPEC1_LED_TXACT BIT(0)
-+#define VSPEC1_LED_RXACT BIT(1)
-+#define VSPEC1_LED_COL BIT(2)
-+#define VSPEC1_LED_NO_CON BIT(3)
-+
- /* SGMII */
- #define VSPEC1_SGMII_CTRL 0x08
- #define VSPEC1_SGMII_CTRL_ANEN BIT(12) /* Aneg enable */
-@@ -827,6 +850,156 @@ static int gpy115_loopback(struct phy_de
- return genphy_soft_reset(phydev);
- }
-
-+static int gpy_led_brightness_set(struct phy_device *phydev,
-+ u8 index, enum led_brightness value)
-+{
-+ int ret;
-+
-+ if (index >= GPY_MAX_LEDS)
-+ return -EINVAL;
-+
-+ /* clear HWCONTROL and set manual LED state */
-+ ret = phy_modify(phydev, PHY_LED,
-+ ((value == LED_OFF) ? PHY_LED_HWCONTROL(index) : 0) |
-+ PHY_LED_ON(index),
-+ (value == LED_OFF) ? 0 : PHY_LED_ON(index));
-+ if (ret)
-+ return ret;
-+
-+ /* ToDo: set PWM brightness */
-+
-+ /* clear HW LED setup */
-+ if (value == LED_OFF)
-+ return phy_write_mmd(phydev, MDIO_MMD_VEND1, VSPEC1_LED(index), 0);
-+ else
-+ return 0;
-+}
-+
-+static const unsigned long supported_triggers = (BIT(TRIGGER_NETDEV_LINK) |
-+ BIT(TRIGGER_NETDEV_LINK_100) |
-+ BIT(TRIGGER_NETDEV_LINK_1000) |
-+ BIT(TRIGGER_NETDEV_LINK_2500) |
-+ BIT(TRIGGER_NETDEV_RX) |
-+ BIT(TRIGGER_NETDEV_TX));
-+
-+static int gpy_led_hw_is_supported(struct phy_device *phydev, u8 index,
-+ unsigned long rules)
-+{
-+ if (index >= GPY_MAX_LEDS)
-+ return -EINVAL;
-+
-+ /* All combinations of the supported triggers are allowed */
-+ if (rules & ~supported_triggers)
-+ return -EOPNOTSUPP;
-+
-+ return 0;
-+}
-+
-+static int gpy_led_hw_control_get(struct phy_device *phydev, u8 index,
-+ unsigned long *rules)
-+{
-+ int val;
-+
-+ if (index >= GPY_MAX_LEDS)
-+ return -EINVAL;
-+
-+ val = phy_read_mmd(phydev, MDIO_MMD_VEND1, VSPEC1_LED(index));
-+ if (val < 0)
-+ return val;
-+
-+ if (FIELD_GET(VSPEC1_LED_CON, val) & VSPEC1_LED_LINK10)
-+ *rules |= BIT(TRIGGER_NETDEV_LINK_10);
-+
-+ if (FIELD_GET(VSPEC1_LED_CON, val) & VSPEC1_LED_LINK100)
-+ *rules |= BIT(TRIGGER_NETDEV_LINK_100);
-+
-+ if (FIELD_GET(VSPEC1_LED_CON, val) & VSPEC1_LED_LINK1000)
-+ *rules |= BIT(TRIGGER_NETDEV_LINK_1000);
-+
-+ if (FIELD_GET(VSPEC1_LED_CON, val) & VSPEC1_LED_LINK2500)
-+ *rules |= BIT(TRIGGER_NETDEV_LINK_2500);
-+
-+ if (FIELD_GET(VSPEC1_LED_CON, val) == (VSPEC1_LED_LINK10 |
-+ VSPEC1_LED_LINK100 |
-+ VSPEC1_LED_LINK1000 |
-+ VSPEC1_LED_LINK2500))
-+ *rules |= BIT(TRIGGER_NETDEV_LINK);
-+
-+ if (FIELD_GET(VSPEC1_LED_PULSE, val) & VSPEC1_LED_TXACT)
-+ *rules |= BIT(TRIGGER_NETDEV_TX);
-+
-+ if (FIELD_GET(VSPEC1_LED_PULSE, val) & VSPEC1_LED_RXACT)
-+ *rules |= BIT(TRIGGER_NETDEV_RX);
-+
-+ return 0;
-+}
-+
-+static int gpy_led_hw_control_set(struct phy_device *phydev, u8 index,
-+ unsigned long rules)
-+{
-+ u16 val = 0;
-+ int ret;
-+
-+ if (index >= GPY_MAX_LEDS)
-+ return -EINVAL;
-+
-+ if (rules & BIT(TRIGGER_NETDEV_LINK) ||
-+ rules & BIT(TRIGGER_NETDEV_LINK_10))
-+ val |= FIELD_PREP(VSPEC1_LED_CON, VSPEC1_LED_LINK10);
-+
-+ if (rules & BIT(TRIGGER_NETDEV_LINK) ||
-+ rules & BIT(TRIGGER_NETDEV_LINK_100))
-+ val |= FIELD_PREP(VSPEC1_LED_CON, VSPEC1_LED_LINK100);
-+
-+ if (rules & BIT(TRIGGER_NETDEV_LINK) ||
-+ rules & BIT(TRIGGER_NETDEV_LINK_1000))
-+ val |= FIELD_PREP(VSPEC1_LED_CON, VSPEC1_LED_LINK1000);
-+
-+ if (rules & BIT(TRIGGER_NETDEV_LINK) ||
-+ rules & BIT(TRIGGER_NETDEV_LINK_2500))
-+ val |= FIELD_PREP(VSPEC1_LED_CON, VSPEC1_LED_LINK2500);
-+
-+ if (rules & BIT(TRIGGER_NETDEV_TX))
-+ val |= FIELD_PREP(VSPEC1_LED_PULSE, VSPEC1_LED_TXACT);
-+
-+ if (rules & BIT(TRIGGER_NETDEV_RX))
-+ val |= FIELD_PREP(VSPEC1_LED_PULSE, VSPEC1_LED_RXACT);
-+
-+ /* allow RX/TX pulse without link indication */
-+ if ((rules & BIT(TRIGGER_NETDEV_TX) || rules & BIT(TRIGGER_NETDEV_RX)) &&
-+ !(val & VSPEC1_LED_CON))
-+ val |= FIELD_PREP(VSPEC1_LED_PULSE, VSPEC1_LED_NO_CON) | VSPEC1_LED_CON;
-+
-+ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, VSPEC1_LED(index), val);
-+ if (ret)
-+ return ret;
-+
-+ return phy_set_bits(phydev, PHY_LED, PHY_LED_HWCONTROL(index));
-+}
-+
-+static int gpy_led_polarity_set(struct phy_device *phydev, int index,
-+ unsigned long modes)
-+{
-+ bool active_low = false;
-+ u32 mode;
-+
-+ if (index >= GPY_MAX_LEDS)
-+ return -EINVAL;
-+
-+ for_each_set_bit(mode, &modes, __PHY_LED_MODES_NUM) {
-+ switch (mode) {
-+ case PHY_LED_ACTIVE_LOW:
-+ active_low = true;
-+ break;
-+ default:
-+ return -EINVAL;
-+ }
-+ }
-+
-+ return phy_modify(phydev, PHY_LED, PHY_LED_POLARITY(index),
-+ active_low ? 0 : PHY_LED_POLARITY(index));
-+}
-+
- static struct phy_driver gpy_drivers[] = {
- {
- PHY_ID_MATCH_MODEL(PHY_ID_GPY2xx),
-@@ -844,6 +1017,11 @@ static struct phy_driver gpy_drivers[] =
- .set_wol = gpy_set_wol,
- .get_wol = gpy_get_wol,
- .set_loopback = gpy_loopback,
-+ .led_brightness_set = gpy_led_brightness_set,
-+ .led_hw_is_supported = gpy_led_hw_is_supported,
-+ .led_hw_control_get = gpy_led_hw_control_get,
-+ .led_hw_control_set = gpy_led_hw_control_set,
-+ .led_polarity_set = gpy_led_polarity_set,
- },
- {
- .phy_id = PHY_ID_GPY115B,
-@@ -862,6 +1040,11 @@ static struct phy_driver gpy_drivers[] =
- .set_wol = gpy_set_wol,
- .get_wol = gpy_get_wol,
- .set_loopback = gpy115_loopback,
-+ .led_brightness_set = gpy_led_brightness_set,
-+ .led_hw_is_supported = gpy_led_hw_is_supported,
-+ .led_hw_control_get = gpy_led_hw_control_get,
-+ .led_hw_control_set = gpy_led_hw_control_set,
-+ .led_polarity_set = gpy_led_polarity_set,
- },
- {
- PHY_ID_MATCH_MODEL(PHY_ID_GPY115C),
-@@ -879,6 +1062,11 @@ static struct phy_driver gpy_drivers[] =
- .set_wol = gpy_set_wol,
- .get_wol = gpy_get_wol,
- .set_loopback = gpy115_loopback,
-+ .led_brightness_set = gpy_led_brightness_set,
-+ .led_hw_is_supported = gpy_led_hw_is_supported,
-+ .led_hw_control_get = gpy_led_hw_control_get,
-+ .led_hw_control_set = gpy_led_hw_control_set,
-+ .led_polarity_set = gpy_led_polarity_set,
- },
- {
- .phy_id = PHY_ID_GPY211B,
-@@ -897,6 +1085,11 @@ static struct phy_driver gpy_drivers[] =
- .set_wol = gpy_set_wol,
- .get_wol = gpy_get_wol,
- .set_loopback = gpy_loopback,
-+ .led_brightness_set = gpy_led_brightness_set,
-+ .led_hw_is_supported = gpy_led_hw_is_supported,
-+ .led_hw_control_get = gpy_led_hw_control_get,
-+ .led_hw_control_set = gpy_led_hw_control_set,
-+ .led_polarity_set = gpy_led_polarity_set,
- },
- {
- PHY_ID_MATCH_MODEL(PHY_ID_GPY211C),
-@@ -914,6 +1107,11 @@ static struct phy_driver gpy_drivers[] =
- .set_wol = gpy_set_wol,
- .get_wol = gpy_get_wol,
- .set_loopback = gpy_loopback,
-+ .led_brightness_set = gpy_led_brightness_set,
-+ .led_hw_is_supported = gpy_led_hw_is_supported,
-+ .led_hw_control_get = gpy_led_hw_control_get,
-+ .led_hw_control_set = gpy_led_hw_control_set,
-+ .led_polarity_set = gpy_led_polarity_set,
- },
- {
- .phy_id = PHY_ID_GPY212B,
-@@ -932,6 +1130,11 @@ static struct phy_driver gpy_drivers[] =
- .set_wol = gpy_set_wol,
- .get_wol = gpy_get_wol,
- .set_loopback = gpy_loopback,
-+ .led_brightness_set = gpy_led_brightness_set,
-+ .led_hw_is_supported = gpy_led_hw_is_supported,
-+ .led_hw_control_get = gpy_led_hw_control_get,
-+ .led_hw_control_set = gpy_led_hw_control_set,
-+ .led_polarity_set = gpy_led_polarity_set,
- },
- {
- PHY_ID_MATCH_MODEL(PHY_ID_GPY212C),
-@@ -949,6 +1152,11 @@ static struct phy_driver gpy_drivers[] =
- .set_wol = gpy_set_wol,
- .get_wol = gpy_get_wol,
- .set_loopback = gpy_loopback,
-+ .led_brightness_set = gpy_led_brightness_set,
-+ .led_hw_is_supported = gpy_led_hw_is_supported,
-+ .led_hw_control_get = gpy_led_hw_control_get,
-+ .led_hw_control_set = gpy_led_hw_control_set,
-+ .led_polarity_set = gpy_led_polarity_set,
- },
- {
- .phy_id = PHY_ID_GPY215B,
-@@ -967,6 +1175,11 @@ static struct phy_driver gpy_drivers[] =
- .set_wol = gpy_set_wol,
- .get_wol = gpy_get_wol,
- .set_loopback = gpy_loopback,
-+ .led_brightness_set = gpy_led_brightness_set,
-+ .led_hw_is_supported = gpy_led_hw_is_supported,
-+ .led_hw_control_get = gpy_led_hw_control_get,
-+ .led_hw_control_set = gpy_led_hw_control_set,
-+ .led_polarity_set = gpy_led_polarity_set,
- },
- {
- PHY_ID_MATCH_MODEL(PHY_ID_GPY215C),
-@@ -984,6 +1197,11 @@ static struct phy_driver gpy_drivers[] =
- .set_wol = gpy_set_wol,
- .get_wol = gpy_get_wol,
- .set_loopback = gpy_loopback,
-+ .led_brightness_set = gpy_led_brightness_set,
-+ .led_hw_is_supported = gpy_led_hw_is_supported,
-+ .led_hw_control_get = gpy_led_hw_control_get,
-+ .led_hw_control_set = gpy_led_hw_control_set,
-+ .led_polarity_set = gpy_led_polarity_set,
- },
- {
- PHY_ID_MATCH_MODEL(PHY_ID_GPY241B),
+++ /dev/null
-From f95b4725e796b12e5f347a0d161e1d3843142aa8 Mon Sep 17 00:00:00 2001
-Date: Fri, 4 Oct 2024 16:56:35 +0100
-Subject: [PATCH] net: phy: mxl-gpy: add missing support for
- TRIGGER_NETDEV_LINK_10
-
-The PHY also support 10MBit/s links as well as the corresponding link
-indication trigger to be offloaded. Add TRIGGER_NETDEV_LINK_10 to the
-supported triggers.
-
-Link: https://patch.msgid.link/cc5da0a989af8b0d49d823656d88053c4de2ab98.1728057367.git.daniel@makrotopia.org
----
- drivers/net/phy/mxl-gpy.c | 1 +
- 1 file changed, 1 insertion(+)
-
---- a/drivers/net/phy/mxl-gpy.c
-+++ b/drivers/net/phy/mxl-gpy.c
-@@ -876,6 +876,7 @@ static int gpy_led_brightness_set(struct
- }
-
- static const unsigned long supported_triggers = (BIT(TRIGGER_NETDEV_LINK) |
-+ BIT(TRIGGER_NETDEV_LINK_10) |
- BIT(TRIGGER_NETDEV_LINK_100) |
- BIT(TRIGGER_NETDEV_LINK_1000) |
- BIT(TRIGGER_NETDEV_LINK_2500) |
+++ /dev/null
-From eb89c79c1b8f17fc1611540768678e60df89ac42 Mon Sep 17 00:00:00 2001
-Date: Thu, 10 Oct 2024 13:55:17 +0100
-Subject: [PATCH 3/4] net: phy: mxl-gpy: correctly describe LED polarity
-
-According the datasheet covering the LED (0x1b) register:
-0B Active High LEDx pin driven high when activated
-1B Active Low LEDx pin driven low when activated
-
-Make use of the now available 'active-high' property and correctly
-reflect the polarity setting which was previously inverted.
-
-Link: https://patch.msgid.link/180ccafa837f09908b852a8a874a3808c5ecd2d0.1728558223.git.daniel@makrotopia.org
----
- drivers/net/phy/mxl-gpy.c | 16 ++++++++++++----
- 1 file changed, 12 insertions(+), 4 deletions(-)
-
---- a/drivers/net/phy/mxl-gpy.c
-+++ b/drivers/net/phy/mxl-gpy.c
-@@ -981,7 +981,7 @@ static int gpy_led_hw_control_set(struct
- static int gpy_led_polarity_set(struct phy_device *phydev, int index,
- unsigned long modes)
- {
-- bool active_low = false;
-+ bool force_active_low = false, force_active_high = false;
- u32 mode;
-
- if (index >= GPY_MAX_LEDS)
-@@ -990,15 +990,23 @@ static int gpy_led_polarity_set(struct p
- for_each_set_bit(mode, &modes, __PHY_LED_MODES_NUM) {
- switch (mode) {
- case PHY_LED_ACTIVE_LOW:
-- active_low = true;
-+ force_active_low = true;
-+ break;
-+ case PHY_LED_ACTIVE_HIGH:
-+ force_active_high = true;
- break;
- default:
- return -EINVAL;
- }
- }
-
-- return phy_modify(phydev, PHY_LED, PHY_LED_POLARITY(index),
-- active_low ? 0 : PHY_LED_POLARITY(index));
-+ if (force_active_low)
-+ return phy_set_bits(phydev, PHY_LED, PHY_LED_POLARITY(index));
-+
-+ if (force_active_high)
-+ return phy_clear_bits(phydev, PHY_LED, PHY_LED_POLARITY(index));
-+
-+ unreachable();
- }
-
- static struct phy_driver gpy_drivers[] = {
+++ /dev/null
-From 1758af47b98c17da464cb45f476875150955dd48 Mon Sep 17 00:00:00 2001
-Date: Thu, 10 Oct 2024 13:55:29 +0100
-Subject: [PATCH 4/4] net: phy: intel-xway: add support for PHY LEDs
-
-The intel-xway PHY driver predates the PHY LED framework and currently
-initializes all LED pins to equal default values.
-
-Add PHY LED functions to the drivers and don't set default values if
-LEDs are defined in device tree.
-
-According the datasheets 3 LEDs are supported on all Intel XWAY PHYs.
-
-Link: https://patch.msgid.link/81f4717ab9acf38f3239727a4540ae96fd01109b.1728558223.git.daniel@makrotopia.org
----
- drivers/net/phy/intel-xway.c | 253 +++++++++++++++++++++++++++++++++--
- 1 file changed, 244 insertions(+), 9 deletions(-)
-
---- a/drivers/net/phy/intel-xway.c
-+++ b/drivers/net/phy/intel-xway.c
-@@ -151,6 +151,13 @@
- #define XWAY_MMD_LED3H 0x01E8
- #define XWAY_MMD_LED3L 0x01E9
-
-+#define XWAY_GPHY_MAX_LEDS 3
-+#define XWAY_GPHY_LED_INV(idx) BIT(12 + (idx))
-+#define XWAY_GPHY_LED_EN(idx) BIT(8 + (idx))
-+#define XWAY_GPHY_LED_DA(idx) BIT(idx)
-+#define XWAY_MMD_LEDxH(idx) (XWAY_MMD_LED0H + 2 * (idx))
-+#define XWAY_MMD_LEDxL(idx) (XWAY_MMD_LED0L + 2 * (idx))
-+
- #define PHY_ID_PHY11G_1_3 0x030260D1
- #define PHY_ID_PHY22F_1_3 0x030260E1
- #define PHY_ID_PHY11G_1_4 0xD565A400
-@@ -229,20 +236,12 @@ static int xway_gphy_rgmii_init(struct p
- XWAY_MDIO_MIICTRL_TXSKEW_MASK, val);
- }
-
--static int xway_gphy_config_init(struct phy_device *phydev)
-+static int xway_gphy_init_leds(struct phy_device *phydev)
- {
- int err;
- u32 ledxh;
- u32 ledxl;
-
-- /* Mask all interrupts */
-- err = phy_write(phydev, XWAY_MDIO_IMASK, 0);
-- if (err)
-- return err;
--
-- /* Clear all pending interrupts */
-- phy_read(phydev, XWAY_MDIO_ISTAT);
--
- /* Ensure that integrated led function is enabled for all leds */
- err = phy_write(phydev, XWAY_MDIO_LED,
- XWAY_MDIO_LED_LED0_EN |
-@@ -276,6 +275,26 @@ static int xway_gphy_config_init(struct
- phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LED2H, ledxh);
- phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LED2L, ledxl);
-
-+ return 0;
-+}
-+
-+static int xway_gphy_config_init(struct phy_device *phydev)
-+{
-+ struct device_node *np = phydev->mdio.dev.of_node;
-+ int err;
-+
-+ /* Mask all interrupts */
-+ err = phy_write(phydev, XWAY_MDIO_IMASK, 0);
-+ if (err)
-+ return err;
-+
-+ /* Use default LED configuration if 'leds' node isn't defined */
-+ if (!of_get_child_by_name(np, "leds"))
-+ xway_gphy_init_leds(phydev);
-+
-+ /* Clear all pending interrupts */
-+ phy_read(phydev, XWAY_MDIO_ISTAT);
-+
- err = xway_gphy_rgmii_init(phydev);
- if (err)
- return err;
-@@ -347,6 +366,172 @@ static irqreturn_t xway_gphy_handle_inte
- return IRQ_HANDLED;
- }
-
-+static int xway_gphy_led_brightness_set(struct phy_device *phydev,
-+ u8 index, enum led_brightness value)
-+{
-+ int ret;
-+
-+ if (index >= XWAY_GPHY_MAX_LEDS)
-+ return -EINVAL;
-+
-+ /* clear EN and set manual LED state */
-+ ret = phy_modify(phydev, XWAY_MDIO_LED,
-+ ((value == LED_OFF) ? XWAY_GPHY_LED_EN(index) : 0) |
-+ XWAY_GPHY_LED_DA(index),
-+ (value == LED_OFF) ? 0 : XWAY_GPHY_LED_DA(index));
-+ if (ret)
-+ return ret;
-+
-+ /* clear HW LED setup */
-+ if (value == LED_OFF) {
-+ ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LEDxH(index), 0);
-+ if (ret)
-+ return ret;
-+
-+ return phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LEDxL(index), 0);
-+ } else {
-+ return 0;
-+ }
-+}
-+
-+static const unsigned long supported_triggers = (BIT(TRIGGER_NETDEV_LINK) |
-+ BIT(TRIGGER_NETDEV_LINK_10) |
-+ BIT(TRIGGER_NETDEV_LINK_100) |
-+ BIT(TRIGGER_NETDEV_LINK_1000) |
-+ BIT(TRIGGER_NETDEV_RX) |
-+ BIT(TRIGGER_NETDEV_TX));
-+
-+static int xway_gphy_led_hw_is_supported(struct phy_device *phydev, u8 index,
-+ unsigned long rules)
-+{
-+ if (index >= XWAY_GPHY_MAX_LEDS)
-+ return -EINVAL;
-+
-+ /* activity triggers are not possible without combination with a link
-+ * trigger.
-+ */
-+ if (rules & (BIT(TRIGGER_NETDEV_RX) | BIT(TRIGGER_NETDEV_TX)) &&
-+ !(rules & (BIT(TRIGGER_NETDEV_LINK) |
-+ BIT(TRIGGER_NETDEV_LINK_10) |
-+ BIT(TRIGGER_NETDEV_LINK_100) |
-+ BIT(TRIGGER_NETDEV_LINK_1000))))
-+ return -EOPNOTSUPP;
-+
-+ /* All other combinations of the supported triggers are allowed */
-+ if (rules & ~supported_triggers)
-+ return -EOPNOTSUPP;
-+
-+ return 0;
-+}
-+
-+static int xway_gphy_led_hw_control_get(struct phy_device *phydev, u8 index,
-+ unsigned long *rules)
-+{
-+ int lval, hval;
-+
-+ if (index >= XWAY_GPHY_MAX_LEDS)
-+ return -EINVAL;
-+
-+ hval = phy_read_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LEDxH(index));
-+ if (hval < 0)
-+ return hval;
-+
-+ lval = phy_read_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LEDxL(index));
-+ if (lval < 0)
-+ return lval;
-+
-+ if (hval & XWAY_MMD_LEDxH_CON_LINK10)
-+ *rules |= BIT(TRIGGER_NETDEV_LINK_10);
-+
-+ if (hval & XWAY_MMD_LEDxH_CON_LINK100)
-+ *rules |= BIT(TRIGGER_NETDEV_LINK_100);
-+
-+ if (hval & XWAY_MMD_LEDxH_CON_LINK1000)
-+ *rules |= BIT(TRIGGER_NETDEV_LINK_1000);
-+
-+ if ((hval & XWAY_MMD_LEDxH_CON_LINK10) &&
-+ (hval & XWAY_MMD_LEDxH_CON_LINK100) &&
-+ (hval & XWAY_MMD_LEDxH_CON_LINK1000))
-+ *rules |= BIT(TRIGGER_NETDEV_LINK);
-+
-+ if (lval & XWAY_MMD_LEDxL_PULSE_TXACT)
-+ *rules |= BIT(TRIGGER_NETDEV_TX);
-+
-+ if (lval & XWAY_MMD_LEDxL_PULSE_RXACT)
-+ *rules |= BIT(TRIGGER_NETDEV_RX);
-+
-+ return 0;
-+}
-+
-+static int xway_gphy_led_hw_control_set(struct phy_device *phydev, u8 index,
-+ unsigned long rules)
-+{
-+ u16 hval = 0, lval = 0;
-+ int ret;
-+
-+ if (index >= XWAY_GPHY_MAX_LEDS)
-+ return -EINVAL;
-+
-+ if (rules & BIT(TRIGGER_NETDEV_LINK) ||
-+ rules & BIT(TRIGGER_NETDEV_LINK_10))
-+ hval |= XWAY_MMD_LEDxH_CON_LINK10;
-+
-+ if (rules & BIT(TRIGGER_NETDEV_LINK) ||
-+ rules & BIT(TRIGGER_NETDEV_LINK_100))
-+ hval |= XWAY_MMD_LEDxH_CON_LINK100;
-+
-+ if (rules & BIT(TRIGGER_NETDEV_LINK) ||
-+ rules & BIT(TRIGGER_NETDEV_LINK_1000))
-+ hval |= XWAY_MMD_LEDxH_CON_LINK1000;
-+
-+ if (rules & BIT(TRIGGER_NETDEV_TX))
-+ lval |= XWAY_MMD_LEDxL_PULSE_TXACT;
-+
-+ if (rules & BIT(TRIGGER_NETDEV_RX))
-+ lval |= XWAY_MMD_LEDxL_PULSE_RXACT;
-+
-+ ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LEDxH(index), hval);
-+ if (ret)
-+ return ret;
-+
-+ ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LEDxL(index), lval);
-+ if (ret)
-+ return ret;
-+
-+ return phy_set_bits(phydev, XWAY_MDIO_LED, XWAY_GPHY_LED_EN(index));
-+}
-+
-+static int xway_gphy_led_polarity_set(struct phy_device *phydev, int index,
-+ unsigned long modes)
-+{
-+ bool force_active_low = false, force_active_high = false;
-+ u32 mode;
-+
-+ if (index >= XWAY_GPHY_MAX_LEDS)
-+ return -EINVAL;
-+
-+ for_each_set_bit(mode, &modes, __PHY_LED_MODES_NUM) {
-+ switch (mode) {
-+ case PHY_LED_ACTIVE_LOW:
-+ force_active_low = true;
-+ break;
-+ case PHY_LED_ACTIVE_HIGH:
-+ force_active_high = true;
-+ break;
-+ default:
-+ return -EINVAL;
-+ }
-+ }
-+
-+ if (force_active_low)
-+ return phy_set_bits(phydev, XWAY_MDIO_LED, XWAY_GPHY_LED_INV(index));
-+
-+ if (force_active_high)
-+ return phy_clear_bits(phydev, XWAY_MDIO_LED, XWAY_GPHY_LED_INV(index));
-+
-+ unreachable();
-+}
-+
- static struct phy_driver xway_gphy[] = {
- {
- .phy_id = PHY_ID_PHY11G_1_3,
-@@ -359,6 +544,11 @@ static struct phy_driver xway_gphy[] = {
- .config_intr = xway_gphy_config_intr,
- .suspend = genphy_suspend,
- .resume = genphy_resume,
-+ .led_brightness_set = xway_gphy_led_brightness_set,
-+ .led_hw_is_supported = xway_gphy_led_hw_is_supported,
-+ .led_hw_control_get = xway_gphy_led_hw_control_get,
-+ .led_hw_control_set = xway_gphy_led_hw_control_set,
-+ .led_polarity_set = xway_gphy_led_polarity_set,
- }, {
- .phy_id = PHY_ID_PHY22F_1_3,
- .phy_id_mask = 0xffffffff,
-@@ -370,6 +560,11 @@ static struct phy_driver xway_gphy[] = {
- .config_intr = xway_gphy_config_intr,
- .suspend = genphy_suspend,
- .resume = genphy_resume,
-+ .led_brightness_set = xway_gphy_led_brightness_set,
-+ .led_hw_is_supported = xway_gphy_led_hw_is_supported,
-+ .led_hw_control_get = xway_gphy_led_hw_control_get,
-+ .led_hw_control_set = xway_gphy_led_hw_control_set,
-+ .led_polarity_set = xway_gphy_led_polarity_set,
- }, {
- .phy_id = PHY_ID_PHY11G_1_4,
- .phy_id_mask = 0xffffffff,
-@@ -381,6 +576,11 @@ static struct phy_driver xway_gphy[] = {
- .config_intr = xway_gphy_config_intr,
- .suspend = genphy_suspend,
- .resume = genphy_resume,
-+ .led_brightness_set = xway_gphy_led_brightness_set,
-+ .led_hw_is_supported = xway_gphy_led_hw_is_supported,
-+ .led_hw_control_get = xway_gphy_led_hw_control_get,
-+ .led_hw_control_set = xway_gphy_led_hw_control_set,
-+ .led_polarity_set = xway_gphy_led_polarity_set,
- }, {
- .phy_id = PHY_ID_PHY22F_1_4,
- .phy_id_mask = 0xffffffff,
-@@ -392,6 +592,11 @@ static struct phy_driver xway_gphy[] = {
- .config_intr = xway_gphy_config_intr,
- .suspend = genphy_suspend,
- .resume = genphy_resume,
-+ .led_brightness_set = xway_gphy_led_brightness_set,
-+ .led_hw_is_supported = xway_gphy_led_hw_is_supported,
-+ .led_hw_control_get = xway_gphy_led_hw_control_get,
-+ .led_hw_control_set = xway_gphy_led_hw_control_set,
-+ .led_polarity_set = xway_gphy_led_polarity_set,
- }, {
- .phy_id = PHY_ID_PHY11G_1_5,
- .phy_id_mask = 0xffffffff,
-@@ -402,6 +607,11 @@ static struct phy_driver xway_gphy[] = {
- .config_intr = xway_gphy_config_intr,
- .suspend = genphy_suspend,
- .resume = genphy_resume,
-+ .led_brightness_set = xway_gphy_led_brightness_set,
-+ .led_hw_is_supported = xway_gphy_led_hw_is_supported,
-+ .led_hw_control_get = xway_gphy_led_hw_control_get,
-+ .led_hw_control_set = xway_gphy_led_hw_control_set,
-+ .led_polarity_set = xway_gphy_led_polarity_set,
- }, {
- .phy_id = PHY_ID_PHY22F_1_5,
- .phy_id_mask = 0xffffffff,
-@@ -412,6 +622,11 @@ static struct phy_driver xway_gphy[] = {
- .config_intr = xway_gphy_config_intr,
- .suspend = genphy_suspend,
- .resume = genphy_resume,
-+ .led_brightness_set = xway_gphy_led_brightness_set,
-+ .led_hw_is_supported = xway_gphy_led_hw_is_supported,
-+ .led_hw_control_get = xway_gphy_led_hw_control_get,
-+ .led_hw_control_set = xway_gphy_led_hw_control_set,
-+ .led_polarity_set = xway_gphy_led_polarity_set,
- }, {
- .phy_id = PHY_ID_PHY11G_VR9_1_1,
- .phy_id_mask = 0xffffffff,
-@@ -422,6 +637,11 @@ static struct phy_driver xway_gphy[] = {
- .config_intr = xway_gphy_config_intr,
- .suspend = genphy_suspend,
- .resume = genphy_resume,
-+ .led_brightness_set = xway_gphy_led_brightness_set,
-+ .led_hw_is_supported = xway_gphy_led_hw_is_supported,
-+ .led_hw_control_get = xway_gphy_led_hw_control_get,
-+ .led_hw_control_set = xway_gphy_led_hw_control_set,
-+ .led_polarity_set = xway_gphy_led_polarity_set,
- }, {
- .phy_id = PHY_ID_PHY22F_VR9_1_1,
- .phy_id_mask = 0xffffffff,
-@@ -432,6 +652,11 @@ static struct phy_driver xway_gphy[] = {
- .config_intr = xway_gphy_config_intr,
- .suspend = genphy_suspend,
- .resume = genphy_resume,
-+ .led_brightness_set = xway_gphy_led_brightness_set,
-+ .led_hw_is_supported = xway_gphy_led_hw_is_supported,
-+ .led_hw_control_get = xway_gphy_led_hw_control_get,
-+ .led_hw_control_set = xway_gphy_led_hw_control_set,
-+ .led_polarity_set = xway_gphy_led_polarity_set,
- }, {
- .phy_id = PHY_ID_PHY11G_VR9_1_2,
- .phy_id_mask = 0xffffffff,
-@@ -442,6 +667,11 @@ static struct phy_driver xway_gphy[] = {
- .config_intr = xway_gphy_config_intr,
- .suspend = genphy_suspend,
- .resume = genphy_resume,
-+ .led_brightness_set = xway_gphy_led_brightness_set,
-+ .led_hw_is_supported = xway_gphy_led_hw_is_supported,
-+ .led_hw_control_get = xway_gphy_led_hw_control_get,
-+ .led_hw_control_set = xway_gphy_led_hw_control_set,
-+ .led_polarity_set = xway_gphy_led_polarity_set,
- }, {
- .phy_id = PHY_ID_PHY22F_VR9_1_2,
- .phy_id_mask = 0xffffffff,
-@@ -452,6 +682,11 @@ static struct phy_driver xway_gphy[] = {
- .config_intr = xway_gphy_config_intr,
- .suspend = genphy_suspend,
- .resume = genphy_resume,
-+ .led_brightness_set = xway_gphy_led_brightness_set,
-+ .led_hw_is_supported = xway_gphy_led_hw_is_supported,
-+ .led_hw_control_get = xway_gphy_led_hw_control_get,
-+ .led_hw_control_set = xway_gphy_led_hw_control_set,
-+ .led_polarity_set = xway_gphy_led_polarity_set,
- },
- };
- module_phy_driver(xway_gphy);
+++ /dev/null
-From 6ab3d50b106c9aea123a80551a6c9deace83b914 Mon Sep 17 00:00:00 2001
-Date: Tue, 7 Nov 2023 16:14:49 +0800
-Subject: [PATCH] bus: mhi: host: Add a separate timeout parameter for waiting
- ready
-
-Some devices(eg. SDX75) take longer than expected (default, 8 seconds) to
-set ready after reboot. Hence add optional ready timeout parameter and pass
-the appropriate timeout value to mhi_poll_reg_field() to wait enough for
-device ready as part of power up sequence.
-
----
- drivers/bus/mhi/host/init.c | 1 +
- drivers/bus/mhi/host/internal.h | 2 +-
- drivers/bus/mhi/host/main.c | 5 +++--
- drivers/bus/mhi/host/pm.c | 24 +++++++++++++++++-------
- include/linux/mhi.h | 4 ++++
- 5 files changed, 26 insertions(+), 10 deletions(-)
-
---- a/drivers/bus/mhi/host/init.c
-+++ b/drivers/bus/mhi/host/init.c
-@@ -881,6 +881,7 @@ static int parse_config(struct mhi_contr
- if (!mhi_cntrl->timeout_ms)
- mhi_cntrl->timeout_ms = MHI_TIMEOUT_MS;
-
-+ mhi_cntrl->ready_timeout_ms = config->ready_timeout_ms;
- mhi_cntrl->bounce_buf = config->use_bounce_buf;
- mhi_cntrl->buffer_len = config->buf_len;
- if (!mhi_cntrl->buffer_len)
---- a/drivers/bus/mhi/host/internal.h
-+++ b/drivers/bus/mhi/host/internal.h
-@@ -324,7 +324,7 @@ int __must_check mhi_read_reg_field(stru
- u32 *out);
- int __must_check mhi_poll_reg_field(struct mhi_controller *mhi_cntrl,
- void __iomem *base, u32 offset, u32 mask,
-- u32 val, u32 delayus);
-+ u32 val, u32 delayus, u32 timeout_ms);
- void mhi_write_reg(struct mhi_controller *mhi_cntrl, void __iomem *base,
- u32 offset, u32 val);
- int __must_check mhi_write_reg_field(struct mhi_controller *mhi_cntrl,
---- a/drivers/bus/mhi/host/main.c
-+++ b/drivers/bus/mhi/host/main.c
-@@ -40,10 +40,11 @@ int __must_check mhi_read_reg_field(stru
-
- int __must_check mhi_poll_reg_field(struct mhi_controller *mhi_cntrl,
- void __iomem *base, u32 offset,
-- u32 mask, u32 val, u32 delayus)
-+ u32 mask, u32 val, u32 delayus,
-+ u32 timeout_ms)
- {
- int ret;
-- u32 out, retry = (mhi_cntrl->timeout_ms * 1000) / delayus;
-+ u32 out, retry = (timeout_ms * 1000) / delayus;
-
- while (retry--) {
- ret = mhi_read_reg_field(mhi_cntrl, base, offset, mask, &out);
---- a/drivers/bus/mhi/host/pm.c
-+++ b/drivers/bus/mhi/host/pm.c
-@@ -171,6 +171,7 @@ int mhi_ready_state_transition(struct mh
- enum mhi_pm_state cur_state;
- struct device *dev = &mhi_cntrl->mhi_dev->dev;
- u32 interval_us = 25000; /* poll register field every 25 milliseconds */
-+ u32 timeout_ms;
- int ret, i;
-
- /* Check if device entered error state */
-@@ -181,14 +182,18 @@ int mhi_ready_state_transition(struct mh
-
- /* Wait for RESET to be cleared and READY bit to be set by the device */
- ret = mhi_poll_reg_field(mhi_cntrl, mhi_cntrl->regs, MHICTRL,
-- MHICTRL_RESET_MASK, 0, interval_us);
-+ MHICTRL_RESET_MASK, 0, interval_us,
-+ mhi_cntrl->timeout_ms);
- if (ret) {
- dev_err(dev, "Device failed to clear MHI Reset\n");
- return ret;
- }
-
-+ timeout_ms = mhi_cntrl->ready_timeout_ms ?
-+ mhi_cntrl->ready_timeout_ms : mhi_cntrl->timeout_ms;
- ret = mhi_poll_reg_field(mhi_cntrl, mhi_cntrl->regs, MHISTATUS,
-- MHISTATUS_READY_MASK, 1, interval_us);
-+ MHISTATUS_READY_MASK, 1, interval_us,
-+ timeout_ms);
- if (ret) {
- dev_err(dev, "Device failed to enter MHI Ready\n");
- return ret;
-@@ -487,7 +492,7 @@ static void mhi_pm_disable_transition(st
-
- /* Wait for the reset bit to be cleared by the device */
- ret = mhi_poll_reg_field(mhi_cntrl, mhi_cntrl->regs, MHICTRL,
-- MHICTRL_RESET_MASK, 0, 25000);
-+ MHICTRL_RESET_MASK, 0, 25000, mhi_cntrl->timeout_ms);
- if (ret)
- dev_err(dev, "Device failed to clear MHI Reset\n");
-
-@@ -500,8 +505,8 @@ static void mhi_pm_disable_transition(st
- if (!MHI_IN_PBL(mhi_get_exec_env(mhi_cntrl))) {
- /* wait for ready to be set */
- ret = mhi_poll_reg_field(mhi_cntrl, mhi_cntrl->regs,
-- MHISTATUS,
-- MHISTATUS_READY_MASK, 1, 25000);
-+ MHISTATUS, MHISTATUS_READY_MASK,
-+ 1, 25000, mhi_cntrl->timeout_ms);
- if (ret)
- dev_err(dev, "Device failed to enter READY state\n");
- }
-@@ -1141,7 +1146,8 @@ int mhi_async_power_up(struct mhi_contro
- if (state == MHI_STATE_SYS_ERR) {
- mhi_set_mhi_state(mhi_cntrl, MHI_STATE_RESET);
- ret = mhi_poll_reg_field(mhi_cntrl, mhi_cntrl->regs, MHICTRL,
-- MHICTRL_RESET_MASK, 0, interval_us);
-+ MHICTRL_RESET_MASK, 0, interval_us,
-+ mhi_cntrl->timeout_ms);
- if (ret) {
- dev_info(dev, "Failed to reset MHI due to syserr state\n");
- goto error_exit;
-@@ -1232,14 +1238,18 @@ EXPORT_SYMBOL_GPL(mhi_power_down);
- int mhi_sync_power_up(struct mhi_controller *mhi_cntrl)
- {
- int ret = mhi_async_power_up(mhi_cntrl);
-+ u32 timeout_ms;
-
- if (ret)
- return ret;
-
-+ /* Some devices need more time to set ready during power up */
-+ timeout_ms = mhi_cntrl->ready_timeout_ms ?
-+ mhi_cntrl->ready_timeout_ms : mhi_cntrl->timeout_ms;
- wait_event_timeout(mhi_cntrl->state_event,
- MHI_IN_MISSION_MODE(mhi_cntrl->ee) ||
- MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state),
-- msecs_to_jiffies(mhi_cntrl->timeout_ms));
-+ msecs_to_jiffies(timeout_ms));
-
- ret = (MHI_IN_MISSION_MODE(mhi_cntrl->ee)) ? 0 : -ETIMEDOUT;
- if (ret)
---- a/include/linux/mhi.h
-+++ b/include/linux/mhi.h
-@@ -266,6 +266,7 @@ struct mhi_event_config {
- * struct mhi_controller_config - Root MHI controller configuration
- * @max_channels: Maximum number of channels supported
- * @timeout_ms: Timeout value for operations. 0 means use default
-+ * @ready_timeout_ms: Timeout value for waiting device to be ready (optional)
- * @buf_len: Size of automatically allocated buffers. 0 means use default
- * @num_channels: Number of channels defined in @ch_cfg
- * @ch_cfg: Array of defined channels
-@@ -277,6 +278,7 @@ struct mhi_event_config {
- struct mhi_controller_config {
- u32 max_channels;
- u32 timeout_ms;
-+ u32 ready_timeout_ms;
- u32 buf_len;
- u32 num_channels;
- const struct mhi_channel_config *ch_cfg;
-@@ -330,6 +332,7 @@ struct mhi_controller_config {
- * @pm_mutex: Mutex for suspend/resume operation
- * @pm_lock: Lock for protecting MHI power management state
- * @timeout_ms: Timeout in ms for state transitions
-+ * @ready_timeout_ms: Timeout in ms for waiting device to be ready (optional)
- * @pm_state: MHI power management state
- * @db_access: DB access states
- * @ee: MHI device execution environment
-@@ -419,6 +422,7 @@ struct mhi_controller {
- struct mutex pm_mutex;
- rwlock_t pm_lock;
- u32 timeout_ms;
-+ u32 ready_timeout_ms;
- u32 pm_state;
- u32 db_access;
- enum mhi_ee_type ee;
+++ /dev/null
-From 4dc9c850a974ba7db2091ce73bcffe631aafe144 Mon Sep 17 00:00:00 2001
-Date: Tue, 7 Nov 2023 16:14:50 +0800
-Subject: [PATCH 1/2] bus: mhi: host: pci_generic: Add SDX75 based modem
- support
-
-Add generic info for SDX75 based modems. SDX75 takes longer to set ready
-during power up. Hence use separate configuration.
-
----
- drivers/bus/mhi/host/pci_generic.c | 22 ++++++++++++++++++++++
- 1 file changed, 22 insertions(+)
-
---- a/drivers/bus/mhi/host/pci_generic.c
-+++ b/drivers/bus/mhi/host/pci_generic.c
-@@ -269,6 +269,16 @@ static struct mhi_event_config modem_qco
- MHI_EVENT_CONFIG_HW_DATA(5, 2048, 101)
- };
-
-+static const struct mhi_controller_config modem_qcom_v2_mhiv_config = {
-+ .max_channels = 128,
-+ .timeout_ms = 8000,
-+ .ready_timeout_ms = 50000,
-+ .num_channels = ARRAY_SIZE(modem_qcom_v1_mhi_channels),
-+ .ch_cfg = modem_qcom_v1_mhi_channels,
-+ .num_events = ARRAY_SIZE(modem_qcom_v1_mhi_events),
-+ .event_cfg = modem_qcom_v1_mhi_events,
-+};
-+
- static const struct mhi_controller_config modem_qcom_v1_mhiv_config = {
- .max_channels = 128,
- .timeout_ms = 8000,
-@@ -278,6 +288,16 @@ static const struct mhi_controller_confi
- .event_cfg = modem_qcom_v1_mhi_events,
- };
-
-+static const struct mhi_pci_dev_info mhi_qcom_sdx75_info = {
-+ .name = "qcom-sdx75m",
-+ .fw = "qcom/sdx75m/xbl.elf",
-+ .edl = "qcom/sdx75m/edl.mbn",
-+ .config = &modem_qcom_v2_mhiv_config,
-+ .bar_num = MHI_PCI_DEFAULT_BAR_NUM,
-+ .dma_data_width = 32,
-+ .sideband_wake = false,
-+};
-+
- static const struct mhi_pci_dev_info mhi_qcom_sdx65_info = {
- .name = "qcom-sdx65m",
- .fw = "qcom/sdx65m/xbl.elf",
-@@ -609,6 +629,8 @@ static const struct pci_device_id mhi_pc
- .driver_data = (kernel_ulong_t) &mhi_telit_fe990a_info },
- { PCI_DEVICE(PCI_VENDOR_ID_QCOM, 0x0308),
- .driver_data = (kernel_ulong_t) &mhi_qcom_sdx65_info },
-+ { PCI_DEVICE(PCI_VENDOR_ID_QCOM, 0x0309),
-+ .driver_data = (kernel_ulong_t) &mhi_qcom_sdx75_info },
- { PCI_DEVICE(PCI_VENDOR_ID_QUECTEL, 0x1001), /* EM120R-GL (sdx24) */
- .driver_data = (kernel_ulong_t) &mhi_quectel_em1xx_info },
- { PCI_DEVICE(PCI_VENDOR_ID_QUECTEL, 0x1002), /* EM160R-GL (sdx24) */
+++ /dev/null
-From 2f5e59d70566902d7b4e13c6af3f042f5d28b78b Mon Sep 17 00:00:00 2001
-Date: Thu, 22 Feb 2024 18:00:23 -0800
-Subject: [PATCH 2/2] bus: mhi: host: pci_generic: constify
- modem_telit_fn980_hw_v1_config
-
-MHI expects the controller configs to be const, and all of the other ones
-in this file already are, so constify modem_telit_fn980_hw_v1_config.
-
-Link: https://lore.kernel.org/r/20240222-mhi-const-bus-mhi-host-pci_generic-v1-1-d4c9b0b0a7a5@quicinc.com
----
- drivers/bus/mhi/host/pci_generic.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/bus/mhi/host/pci_generic.c
-+++ b/drivers/bus/mhi/host/pci_generic.c
-@@ -538,7 +538,7 @@ static struct mhi_event_config mhi_telit
- MHI_EVENT_CONFIG_HW_DATA(2, 2048, 101)
- };
-
--static struct mhi_controller_config modem_telit_fn980_hw_v1_config = {
-+static const struct mhi_controller_config modem_telit_fn980_hw_v1_config = {
- .max_channels = 128,
- .timeout_ms = 20000,
- .num_channels = ARRAY_SIZE(mhi_telit_fn980_hw_v1_channels),
+++ /dev/null
-From 3471bba1b33a8b54cb0be9d30b7aac4fb2766365 Mon Sep 17 00:00:00 2001
-Date: Tue, 5 Mar 2024 10:13:18 +0800
-Subject: [PATCH] bus: mhi: host: Add mhi_power_down_keep_dev() API to support
- system suspend/hibernation
-
-Currently, ath11k fails to resume from system suspend/hibernation on some
-the x86 host machines with below error message:
-
-```
-ath11k_pci 0000:06:00.0: timeout while waiting for restart complete
-```
-
-This happens because, ath11k powers down the MHI stack during suspend and
-that leads to destruction of the struct device associated with the MHI
-channels. And during resume, ath11k calls calling mhi_sync_power_up() to
-power up the MHI subsystem and that eventually calls the driver framework's
-device_add() API from mhi_create_devices(). But the PM framework blocks the
-struct device creation during device_add() and this leads to probe deferral
-as below:
-
-```
-mhi mhi0_IPCR: Driver qcom_mhi_qrtr force probe deferral
-```
-
-The reason for deferring device creation during resume is explained in
-dpm_prepare():
-
- /*
- * It is unsafe if probing of devices will happen during suspend or
- * hibernation and system behavior will be unpredictable in this
- * case. So, let's prohibit device's probing here and defer their
- * probes instead. The normal behavior will be restored in
- * dpm_complete().
- */
-
-Due to the device probe deferral, qcom_mhi_qrtr_probe() API is not getting
-called during resume and thus MHI channels are not prepared. So this blocks
-the QMI messages from being transferred between ath11k and firmware,
-resulting in a firmware initialization failure.
-
-After consulting with Rafael, it was decided to not destroy the struct
-device for the MHI channels during system suspend/hibernation because the
-device is bound to appear again during resume.
-
-So to achieve this, a new API called mhi_power_down_keep_dev() is
-introduced for MHI controllers to keep the struct device when required.
-This API is similar to the existing mhi_power_down() API, except that it
-keeps the struct device associated with MHI channels instead of destroying
-them.
-
-Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.30
-
-[mani: reworded the commit message and subject]
----
- drivers/bus/mhi/host/init.c | 1 +
- drivers/bus/mhi/host/internal.h | 1 +
- drivers/bus/mhi/host/pm.c | 42 ++++++++++++++++++++++++++++-----
- include/linux/mhi.h | 18 +++++++++++++-
- 4 files changed, 55 insertions(+), 7 deletions(-)
-
---- a/drivers/bus/mhi/host/init.c
-+++ b/drivers/bus/mhi/host/init.c
-@@ -43,6 +43,7 @@ const char * const dev_state_tran_str[DE
- [DEV_ST_TRANSITION_FP] = "FLASH PROGRAMMER",
- [DEV_ST_TRANSITION_SYS_ERR] = "SYS ERROR",
- [DEV_ST_TRANSITION_DISABLE] = "DISABLE",
-+ [DEV_ST_TRANSITION_DISABLE_DESTROY_DEVICE] = "DISABLE (DESTROY DEVICE)",
- };
-
- const char * const mhi_ch_state_type_str[MHI_CH_STATE_TYPE_MAX] = {
---- a/drivers/bus/mhi/host/internal.h
-+++ b/drivers/bus/mhi/host/internal.h
-@@ -69,6 +69,7 @@ enum dev_st_transition {
- DEV_ST_TRANSITION_FP,
- DEV_ST_TRANSITION_SYS_ERR,
- DEV_ST_TRANSITION_DISABLE,
-+ DEV_ST_TRANSITION_DISABLE_DESTROY_DEVICE,
- DEV_ST_TRANSITION_MAX,
- };
-
---- a/drivers/bus/mhi/host/pm.c
-+++ b/drivers/bus/mhi/host/pm.c
-@@ -466,7 +466,8 @@ error_mission_mode:
- }
-
- /* Handle shutdown transitions */
--static void mhi_pm_disable_transition(struct mhi_controller *mhi_cntrl)
-+static void mhi_pm_disable_transition(struct mhi_controller *mhi_cntrl,
-+ bool destroy_device)
- {
- enum mhi_pm_state cur_state;
- struct mhi_event *mhi_event;
-@@ -528,8 +529,16 @@ skip_mhi_reset:
- dev_dbg(dev, "Waiting for all pending threads to complete\n");
- wake_up_all(&mhi_cntrl->state_event);
-
-- dev_dbg(dev, "Reset all active channels and remove MHI devices\n");
-- device_for_each_child(&mhi_cntrl->mhi_dev->dev, NULL, mhi_destroy_device);
-+ /*
-+ * Only destroy the 'struct device' for channels if indicated by the
-+ * 'destroy_device' flag. Because, during system suspend or hibernation
-+ * state, there is no need to destroy the 'struct device' as the endpoint
-+ * device would still be physically attached to the machine.
-+ */
-+ if (destroy_device) {
-+ dev_dbg(dev, "Reset all active channels and remove MHI devices\n");
-+ device_for_each_child(&mhi_cntrl->mhi_dev->dev, NULL, mhi_destroy_device);
-+ }
-
- mutex_lock(&mhi_cntrl->pm_mutex);
-
-@@ -836,7 +845,10 @@ void mhi_pm_st_worker(struct work_struct
- mhi_pm_sys_error_transition(mhi_cntrl);
- break;
- case DEV_ST_TRANSITION_DISABLE:
-- mhi_pm_disable_transition(mhi_cntrl);
-+ mhi_pm_disable_transition(mhi_cntrl, false);
-+ break;
-+ case DEV_ST_TRANSITION_DISABLE_DESTROY_DEVICE:
-+ mhi_pm_disable_transition(mhi_cntrl, true);
- break;
- default:
- break;
-@@ -1190,7 +1202,8 @@ error_exit:
- }
- EXPORT_SYMBOL_GPL(mhi_async_power_up);
-
--void mhi_power_down(struct mhi_controller *mhi_cntrl, bool graceful)
-+static void __mhi_power_down(struct mhi_controller *mhi_cntrl, bool graceful,
-+ bool destroy_device)
- {
- enum mhi_pm_state cur_state, transition_state;
- struct device *dev = &mhi_cntrl->mhi_dev->dev;
-@@ -1226,15 +1239,32 @@ void mhi_power_down(struct mhi_controlle
- write_unlock_irq(&mhi_cntrl->pm_lock);
- mutex_unlock(&mhi_cntrl->pm_mutex);
-
-- mhi_queue_state_transition(mhi_cntrl, DEV_ST_TRANSITION_DISABLE);
-+ if (destroy_device)
-+ mhi_queue_state_transition(mhi_cntrl,
-+ DEV_ST_TRANSITION_DISABLE_DESTROY_DEVICE);
-+ else
-+ mhi_queue_state_transition(mhi_cntrl,
-+ DEV_ST_TRANSITION_DISABLE);
-
- /* Wait for shutdown to complete */
- flush_work(&mhi_cntrl->st_worker);
-
- disable_irq(mhi_cntrl->irq[0]);
- }
-+
-+void mhi_power_down(struct mhi_controller *mhi_cntrl, bool graceful)
-+{
-+ __mhi_power_down(mhi_cntrl, graceful, true);
-+}
- EXPORT_SYMBOL_GPL(mhi_power_down);
-
-+void mhi_power_down_keep_dev(struct mhi_controller *mhi_cntrl,
-+ bool graceful)
-+{
-+ __mhi_power_down(mhi_cntrl, graceful, false);
-+}
-+EXPORT_SYMBOL_GPL(mhi_power_down_keep_dev);
-+
- int mhi_sync_power_up(struct mhi_controller *mhi_cntrl)
- {
- int ret = mhi_async_power_up(mhi_cntrl);
---- a/include/linux/mhi.h
-+++ b/include/linux/mhi.h
-@@ -649,13 +649,29 @@ int mhi_async_power_up(struct mhi_contro
- int mhi_sync_power_up(struct mhi_controller *mhi_cntrl);
-
- /**
-- * mhi_power_down - Start MHI power down sequence
-+ * mhi_power_down - Power down the MHI device and also destroy the
-+ * 'struct device' for the channels associated with it.
-+ * See also mhi_power_down_keep_dev() which is a variant
-+ * of this API that keeps the 'struct device' for channels
-+ * (useful during suspend/hibernation).
- * @mhi_cntrl: MHI controller
- * @graceful: Link is still accessible, so do a graceful shutdown process
- */
- void mhi_power_down(struct mhi_controller *mhi_cntrl, bool graceful);
-
- /**
-+ * mhi_power_down_keep_dev - Power down the MHI device but keep the 'struct
-+ * device' for the channels associated with it.
-+ * This is a variant of 'mhi_power_down()' and
-+ * useful in scenarios such as suspend/hibernation
-+ * where destroying of the 'struct device' is not
-+ * needed.
-+ * @mhi_cntrl: MHI controller
-+ * @graceful: Link is still accessible, so do a graceful shutdown process
-+ */
-+void mhi_power_down_keep_dev(struct mhi_controller *mhi_cntrl, bool graceful);
-+
-+/**
- * mhi_unprepare_after_power_down - Free any allocated memory after power down
- * @mhi_cntrl: MHI controller
- */
+++ /dev/null
-From 0ebdb7210943eb345992bea9892adbd15a206193 Mon Sep 17 00:00:00 2001
-Date: Mon, 2 Oct 2023 18:48:28 +0200
-Subject: leds: Add ktd202x driver
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-This commit adds support for Kinetic KTD2026/7 RGB/White LED driver.
-
----
- drivers/leds/rgb/Kconfig | 13 +
- drivers/leds/rgb/Makefile | 1 +
- drivers/leds/rgb/leds-ktd202x.c | 625 ++++++++++++++++++++++++++++++++++++++++
- 3 files changed, 639 insertions(+)
- create mode 100644 drivers/leds/rgb/leds-ktd202x.c
-
-(limited to 'drivers/leds/rgb')
-
---- a/drivers/leds/rgb/Kconfig
-+++ b/drivers/leds/rgb/Kconfig
-@@ -14,6 +14,19 @@ config LEDS_GROUP_MULTICOLOR
- To compile this driver as a module, choose M here: the module
- will be called leds-group-multicolor.
-
-+config LEDS_KTD202X
-+ tristate "LED support for KTD202x Chips"
-+ depends on I2C
-+ depends on OF
-+ select REGMAP_I2C
-+ help
-+ This option enables support for the Kinetic KTD2026/KTD2027
-+ RGB/White LED driver found in different BQ mobile phones.
-+ It is a 3 or 4 channel LED driver programmed via an I2C interface.
-+
-+ To compile this driver as a module, choose M here: the module
-+ will be called leds-ktd202x.
-+
- config LEDS_PWM_MULTICOLOR
- tristate "PWM driven multi-color LED Support"
- depends on PWM
---- a/drivers/leds/rgb/Makefile
-+++ b/drivers/leds/rgb/Makefile
-@@ -1,6 +1,7 @@
- # SPDX-License-Identifier: GPL-2.0
-
- obj-$(CONFIG_LEDS_GROUP_MULTICOLOR) += leds-group-multicolor.o
-+obj-$(CONFIG_LEDS_KTD202X) += leds-ktd202x.o
- obj-$(CONFIG_LEDS_PWM_MULTICOLOR) += leds-pwm-multicolor.o
- obj-$(CONFIG_LEDS_QCOM_LPG) += leds-qcom-lpg.o
- obj-$(CONFIG_LEDS_MT6370_RGB) += leds-mt6370-rgb.o
---- /dev/null
-+++ b/drivers/leds/rgb/leds-ktd202x.c
-@@ -0,0 +1,625 @@
-+// SPDX-License-Identifier: GPL-2.0-or-later
-+/*
-+ * Kinetic KTD2026/7 RGB/White LED driver with I2C interface
-+ *
-+ *
-+ * Datasheet: https://www.kinet-ic.com/uploads/KTD2026-7-04h.pdf
-+ */
-+
-+#include <linux/i2c.h>
-+#include <linux/led-class-multicolor.h>
-+#include <linux/module.h>
-+#include <linux/mutex.h>
-+#include <linux/of.h>
-+#include <linux/of_device.h>
-+#include <linux/regmap.h>
-+#include <linux/regulator/consumer.h>
-+
-+#define KTD2026_NUM_LEDS 3
-+#define KTD2027_NUM_LEDS 4
-+#define KTD202X_MAX_LEDS 4
-+
-+/* Register bank */
-+#define KTD202X_REG_RESET_CONTROL 0x00
-+#define KTD202X_REG_FLASH_PERIOD 0x01
-+#define KTD202X_REG_PWM1_TIMER 0x02
-+#define KTD202X_REG_PWM2_TIMER 0x03
-+#define KTD202X_REG_CHANNEL_CTRL 0x04
-+#define KTD202X_REG_TRISE_FALL 0x05
-+#define KTD202X_REG_LED_IOUT(x) (0x06 + (x))
-+
-+/* Register 0 */
-+#define KTD202X_TIMER_SLOT_CONTROL_TSLOT1 0x00
-+#define KTD202X_TIMER_SLOT_CONTROL_TSLOT2 0x01
-+#define KTD202X_TIMER_SLOT_CONTROL_TSLOT3 0x02
-+#define KTD202X_TIMER_SLOT_CONTROL_TSLOT4 0x03
-+#define KTD202X_RSTR_RESET 0x07
-+
-+#define KTD202X_ENABLE_CTRL_WAKE 0x00 /* SCL High & SDA High */
-+#define KTD202X_ENABLE_CTRL_SLEEP 0x08 /* SCL High & SDA Toggling */
-+
-+#define KTD202X_TRISE_FALL_SCALE_NORMAL 0x00
-+#define KTD202X_TRISE_FALL_SCALE_SLOW_X2 0x20
-+#define KTD202X_TRISE_FALL_SCALE_SLOW_X4 0x40
-+#define KTD202X_TRISE_FALL_SCALE_FAST_X8 0x60
-+
-+/* Register 1 */
-+#define KTD202X_FLASH_PERIOD_256_MS_LOG_RAMP 0x00
-+
-+/* Register 2-3 */
-+#define KTD202X_FLASH_ON_TIME_0_4_PERCENT 0x01
-+
-+/* Register 4 */
-+#define KTD202X_CHANNEL_CTRL_MASK(x) (BIT(2 * (x)) | BIT(2 * (x) + 1))
-+#define KTD202X_CHANNEL_CTRL_OFF 0x00
-+#define KTD202X_CHANNEL_CTRL_ON(x) BIT(2 * (x))
-+#define KTD202X_CHANNEL_CTRL_PWM1(x) BIT(2 * (x) + 1)
-+#define KTD202X_CHANNEL_CTRL_PWM2(x) (BIT(2 * (x)) | BIT(2 * (x) + 1))
-+
-+/* Register 5 */
-+#define KTD202X_RAMP_TIMES_2_MS 0x00
-+
-+/* Register 6-9 */
-+#define KTD202X_LED_CURRENT_10_mA 0x4f
-+
-+#define KTD202X_FLASH_PERIOD_MIN_MS 256
-+#define KTD202X_FLASH_PERIOD_STEP_MS 128
-+#define KTD202X_FLASH_PERIOD_MAX_STEPS 126
-+#define KTD202X_FLASH_ON_MAX 256
-+
-+#define KTD202X_MAX_BRIGHTNESS 192
-+
-+static const struct reg_default ktd202x_reg_defaults[] = {
-+ { KTD202X_REG_RESET_CONTROL, KTD202X_TIMER_SLOT_CONTROL_TSLOT1 |
-+ KTD202X_ENABLE_CTRL_WAKE | KTD202X_TRISE_FALL_SCALE_NORMAL },
-+ { KTD202X_REG_FLASH_PERIOD, KTD202X_FLASH_PERIOD_256_MS_LOG_RAMP },
-+ { KTD202X_REG_PWM1_TIMER, KTD202X_FLASH_ON_TIME_0_4_PERCENT },
-+ { KTD202X_REG_PWM2_TIMER, KTD202X_FLASH_ON_TIME_0_4_PERCENT },
-+ { KTD202X_REG_CHANNEL_CTRL, KTD202X_CHANNEL_CTRL_OFF },
-+ { KTD202X_REG_TRISE_FALL, KTD202X_RAMP_TIMES_2_MS },
-+ { KTD202X_REG_LED_IOUT(0), KTD202X_LED_CURRENT_10_mA },
-+ { KTD202X_REG_LED_IOUT(1), KTD202X_LED_CURRENT_10_mA },
-+ { KTD202X_REG_LED_IOUT(2), KTD202X_LED_CURRENT_10_mA },
-+ { KTD202X_REG_LED_IOUT(3), KTD202X_LED_CURRENT_10_mA },
-+};
-+
-+struct ktd202x_led {
-+ struct ktd202x *chip;
-+ union {
-+ struct led_classdev cdev;
-+ struct led_classdev_mc mcdev;
-+ };
-+ u32 index;
-+};
-+
-+struct ktd202x {
-+ struct mutex mutex;
-+ struct regulator_bulk_data regulators[2];
-+ struct device *dev;
-+ struct regmap *regmap;
-+ bool enabled;
-+ int num_leds;
-+ struct ktd202x_led leds[] __counted_by(num_leds);
-+};
-+
-+static int ktd202x_chip_disable(struct ktd202x *chip)
-+{
-+ int ret;
-+
-+ if (!chip->enabled)
-+ return 0;
-+
-+ regmap_write(chip->regmap, KTD202X_REG_RESET_CONTROL, KTD202X_ENABLE_CTRL_SLEEP);
-+
-+ ret = regulator_bulk_disable(ARRAY_SIZE(chip->regulators), chip->regulators);
-+ if (ret) {
-+ dev_err(chip->dev, "Failed to disable regulators: %d\n", ret);
-+ return ret;
-+ }
-+
-+ chip->enabled = false;
-+ return 0;
-+}
-+
-+static int ktd202x_chip_enable(struct ktd202x *chip)
-+{
-+ int ret;
-+
-+ if (chip->enabled)
-+ return 0;
-+
-+ ret = regulator_bulk_enable(ARRAY_SIZE(chip->regulators), chip->regulators);
-+ if (ret) {
-+ dev_err(chip->dev, "Failed to enable regulators: %d\n", ret);
-+ return ret;
-+ }
-+ chip->enabled = true;
-+
-+ ret = regmap_write(chip->regmap, KTD202X_REG_RESET_CONTROL, KTD202X_ENABLE_CTRL_WAKE);
-+
-+ if (ret) {
-+ dev_err(chip->dev, "Failed to enable the chip: %d\n", ret);
-+ ktd202x_chip_disable(chip);
-+ }
-+
-+ return ret;
-+}
-+
-+static bool ktd202x_chip_in_use(struct ktd202x *chip)
-+{
-+ int i;
-+
-+ for (i = 0; i < chip->num_leds; i++) {
-+ if (chip->leds[i].cdev.brightness)
-+ return true;
-+ }
-+
-+ return false;
-+}
-+
-+static int ktd202x_brightness_set(struct ktd202x_led *led,
-+ struct mc_subled *subleds,
-+ unsigned int num_channels)
-+{
-+ bool mode_blink = false;
-+ int channel;
-+ int state;
-+ int ret;
-+ int i;
-+
-+ if (ktd202x_chip_in_use(led->chip)) {
-+ ret = ktd202x_chip_enable(led->chip);
-+ if (ret)
-+ return ret;
-+ }
-+
-+ ret = regmap_read(led->chip->regmap, KTD202X_REG_CHANNEL_CTRL, &state);
-+ if (ret)
-+ return ret;
-+
-+ /*
-+ * In multicolor case, assume blink mode if PWM is set for at least one
-+ * channel because another channel cannot be in state ON at the same time
-+ */
-+ for (i = 0; i < num_channels; i++) {
-+ int channel_state;
-+
-+ channel = subleds[i].channel;
-+ channel_state = (state >> 2 * channel) & KTD202X_CHANNEL_CTRL_MASK(0);
-+ if (channel_state == KTD202X_CHANNEL_CTRL_OFF)
-+ continue;
-+ mode_blink = channel_state == KTD202X_CHANNEL_CTRL_PWM1(0);
-+ break;
-+ }
-+
-+ for (i = 0; i < num_channels; i++) {
-+ enum led_brightness brightness;
-+ int mode;
-+
-+ brightness = subleds[i].brightness;
-+ channel = subleds[i].channel;
-+
-+ if (brightness) {
-+ /* Register expects brightness between 0 and MAX_BRIGHTNESS - 1 */
-+ ret = regmap_write(led->chip->regmap, KTD202X_REG_LED_IOUT(channel),
-+ brightness - 1);
-+ if (ret)
-+ return ret;
-+
-+ if (mode_blink)
-+ mode = KTD202X_CHANNEL_CTRL_PWM1(channel);
-+ else
-+ mode = KTD202X_CHANNEL_CTRL_ON(channel);
-+ } else {
-+ mode = KTD202X_CHANNEL_CTRL_OFF;
-+ }
-+ ret = regmap_update_bits(led->chip->regmap, KTD202X_REG_CHANNEL_CTRL,
-+ KTD202X_CHANNEL_CTRL_MASK(channel), mode);
-+ if (ret)
-+ return ret;
-+ }
-+
-+ if (!ktd202x_chip_in_use(led->chip))
-+ return ktd202x_chip_disable(led->chip);
-+
-+ return 0;
-+}
-+
-+static int ktd202x_brightness_single_set(struct led_classdev *cdev,
-+ enum led_brightness value)
-+{
-+ struct ktd202x_led *led = container_of(cdev, struct ktd202x_led, cdev);
-+ struct mc_subled info;
-+ int ret;
-+
-+ cdev->brightness = value;
-+
-+ mutex_lock(&led->chip->mutex);
-+
-+ info.brightness = value;
-+ info.channel = led->index;
-+ ret = ktd202x_brightness_set(led, &info, 1);
-+
-+ mutex_unlock(&led->chip->mutex);
-+
-+ return ret;
-+}
-+
-+static int ktd202x_brightness_mc_set(struct led_classdev *cdev,
-+ enum led_brightness value)
-+{
-+ struct led_classdev_mc *mc = lcdev_to_mccdev(cdev);
-+ struct ktd202x_led *led = container_of(mc, struct ktd202x_led, mcdev);
-+ int ret;
-+
-+ cdev->brightness = value;
-+
-+ mutex_lock(&led->chip->mutex);
-+
-+ led_mc_calc_color_components(mc, value);
-+ ret = ktd202x_brightness_set(led, mc->subled_info, mc->num_colors);
-+
-+ mutex_unlock(&led->chip->mutex);
-+
-+ return ret;
-+}
-+
-+static int ktd202x_blink_set(struct ktd202x_led *led, unsigned long *delay_on,
-+ unsigned long *delay_off, struct mc_subled *subleds,
-+ unsigned int num_channels)
-+{
-+ unsigned long delay_total_ms;
-+ int ret, num_steps, on;
-+ u8 ctrl_mask = 0;
-+ u8 ctrl_pwm1 = 0;
-+ u8 ctrl_on = 0;
-+ int i;
-+
-+ mutex_lock(&led->chip->mutex);
-+
-+ for (i = 0; i < num_channels; i++) {
-+ int channel = subleds[i].channel;
-+
-+ ctrl_mask |= KTD202X_CHANNEL_CTRL_MASK(channel);
-+ ctrl_on |= KTD202X_CHANNEL_CTRL_ON(channel);
-+ ctrl_pwm1 |= KTD202X_CHANNEL_CTRL_PWM1(channel);
-+ }
-+
-+ /* Never off - brightness is already set, disable blinking */
-+ if (!*delay_off) {
-+ ret = regmap_update_bits(led->chip->regmap, KTD202X_REG_CHANNEL_CTRL,
-+ ctrl_mask, ctrl_on);
-+ goto out;
-+ }
-+
-+ /* Convert into values the HW will understand. */
-+
-+ /* Integer representation of time of flash period */
-+ num_steps = (*delay_on + *delay_off - KTD202X_FLASH_PERIOD_MIN_MS) /
-+ KTD202X_FLASH_PERIOD_STEP_MS;
-+ num_steps = clamp(num_steps, 0, KTD202X_FLASH_PERIOD_MAX_STEPS);
-+
-+ /* Integer representation of percentage of LED ON time */
-+ on = (*delay_on * KTD202X_FLASH_ON_MAX) / (*delay_on + *delay_off);
-+
-+ /* Actually used delay_{on,off} values */
-+ delay_total_ms = num_steps * KTD202X_FLASH_PERIOD_STEP_MS + KTD202X_FLASH_PERIOD_MIN_MS;
-+ *delay_on = (delay_total_ms * on) / KTD202X_FLASH_ON_MAX;
-+ *delay_off = delay_total_ms - *delay_on;
-+
-+ /* Set timings */
-+ ret = regmap_write(led->chip->regmap, KTD202X_REG_FLASH_PERIOD, num_steps);
-+ if (ret)
-+ goto out;
-+
-+ ret = regmap_write(led->chip->regmap, KTD202X_REG_PWM1_TIMER, on);
-+ if (ret)
-+ goto out;
-+
-+ ret = regmap_update_bits(led->chip->regmap, KTD202X_REG_CHANNEL_CTRL,
-+ ctrl_mask, ctrl_pwm1);
-+out:
-+ mutex_unlock(&led->chip->mutex);
-+ return ret;
-+}
-+
-+static int ktd202x_blink_single_set(struct led_classdev *cdev,
-+ unsigned long *delay_on,
-+ unsigned long *delay_off)
-+{
-+ struct ktd202x_led *led = container_of(cdev, struct ktd202x_led, cdev);
-+ struct mc_subled info;
-+ int ret;
-+
-+ if (!cdev->brightness) {
-+ ret = ktd202x_brightness_single_set(cdev, KTD202X_MAX_BRIGHTNESS);
-+ if (ret)
-+ return ret;
-+ }
-+
-+ /* If no blink specified, default to 1 Hz. */
-+ if (!*delay_off && !*delay_on) {
-+ *delay_off = 500;
-+ *delay_on = 500;
-+ }
-+
-+ /* Never on - just set to off */
-+ if (!*delay_on)
-+ return ktd202x_brightness_single_set(cdev, LED_OFF);
-+
-+ info.channel = led->index;
-+
-+ return ktd202x_blink_set(led, delay_on, delay_off, &info, 1);
-+}
-+
-+static int ktd202x_blink_mc_set(struct led_classdev *cdev,
-+ unsigned long *delay_on,
-+ unsigned long *delay_off)
-+{
-+ struct led_classdev_mc *mc = lcdev_to_mccdev(cdev);
-+ struct ktd202x_led *led = container_of(mc, struct ktd202x_led, mcdev);
-+ int ret;
-+
-+ if (!cdev->brightness) {
-+ ret = ktd202x_brightness_mc_set(cdev, KTD202X_MAX_BRIGHTNESS);
-+ if (ret)
-+ return ret;
-+ }
-+
-+ /* If no blink specified, default to 1 Hz. */
-+ if (!*delay_off && !*delay_on) {
-+ *delay_off = 500;
-+ *delay_on = 500;
-+ }
-+
-+ /* Never on - just set to off */
-+ if (!*delay_on)
-+ return ktd202x_brightness_mc_set(cdev, LED_OFF);
-+
-+ return ktd202x_blink_set(led, delay_on, delay_off, mc->subled_info,
-+ mc->num_colors);
-+}
-+
-+static int ktd202x_setup_led_rgb(struct ktd202x *chip, struct device_node *np,
-+ struct ktd202x_led *led, struct led_init_data *init_data)
-+{
-+ struct led_classdev *cdev;
-+ struct device_node *child;
-+ struct mc_subled *info;
-+ int num_channels;
-+ int i = 0;
-+
-+ num_channels = of_get_available_child_count(np);
-+ if (!num_channels || num_channels > chip->num_leds)
-+ return -EINVAL;
-+
-+ info = devm_kcalloc(chip->dev, num_channels, sizeof(*info), GFP_KERNEL);
-+ if (!info)
-+ return -ENOMEM;
-+
-+ for_each_available_child_of_node(np, child) {
-+ u32 mono_color;
-+ u32 reg;
-+ int ret;
-+
-+ ret = of_property_read_u32(child, "reg", ®);
-+ if (ret != 0 || reg >= chip->num_leds) {
-+ dev_err(chip->dev, "invalid 'reg' of %pOFn\n", child);
-+ of_node_put(child);
-+ return -EINVAL;
-+ }
-+
-+ ret = of_property_read_u32(child, "color", &mono_color);
-+ if (ret < 0 && ret != -EINVAL) {
-+ dev_err(chip->dev, "failed to parse 'color' of %pOF\n", child);
-+ of_node_put(child);
-+ return ret;
-+ }
-+
-+ info[i].color_index = mono_color;
-+ info[i].channel = reg;
-+ info[i].intensity = KTD202X_MAX_BRIGHTNESS;
-+ i++;
-+ }
-+
-+ led->mcdev.subled_info = info;
-+ led->mcdev.num_colors = num_channels;
-+
-+ cdev = &led->mcdev.led_cdev;
-+ cdev->brightness_set_blocking = ktd202x_brightness_mc_set;
-+ cdev->blink_set = ktd202x_blink_mc_set;
-+
-+ return devm_led_classdev_multicolor_register_ext(chip->dev, &led->mcdev, init_data);
-+}
-+
-+static int ktd202x_setup_led_single(struct ktd202x *chip, struct device_node *np,
-+ struct ktd202x_led *led, struct led_init_data *init_data)
-+{
-+ struct led_classdev *cdev;
-+ u32 reg;
-+ int ret;
-+
-+ ret = of_property_read_u32(np, "reg", ®);
-+ if (ret != 0 || reg >= chip->num_leds) {
-+ dev_err(chip->dev, "invalid 'reg' of %pOFn\n", np);
-+ return -EINVAL;
-+ }
-+ led->index = reg;
-+
-+ cdev = &led->cdev;
-+ cdev->brightness_set_blocking = ktd202x_brightness_single_set;
-+ cdev->blink_set = ktd202x_blink_single_set;
-+
-+ return devm_led_classdev_register_ext(chip->dev, &led->cdev, init_data);
-+}
-+
-+static int ktd202x_add_led(struct ktd202x *chip, struct device_node *np, unsigned int index)
-+{
-+ struct ktd202x_led *led = &chip->leds[index];
-+ struct led_init_data init_data = {};
-+ struct led_classdev *cdev;
-+ u32 color;
-+ int ret;
-+
-+ /* Color property is optional in single color case */
-+ ret = of_property_read_u32(np, "color", &color);
-+ if (ret < 0 && ret != -EINVAL) {
-+ dev_err(chip->dev, "failed to parse 'color' of %pOF\n", np);
-+ return ret;
-+ }
-+
-+ led->chip = chip;
-+ init_data.fwnode = of_fwnode_handle(np);
-+
-+ if (color == LED_COLOR_ID_RGB) {
-+ cdev = &led->mcdev.led_cdev;
-+ ret = ktd202x_setup_led_rgb(chip, np, led, &init_data);
-+ } else {
-+ cdev = &led->cdev;
-+ ret = ktd202x_setup_led_single(chip, np, led, &init_data);
-+ }
-+
-+ if (ret) {
-+ dev_err(chip->dev, "unable to register %s\n", cdev->name);
-+ return ret;
-+ }
-+
-+ cdev->max_brightness = KTD202X_MAX_BRIGHTNESS;
-+
-+ return 0;
-+}
-+
-+static int ktd202x_probe_dt(struct ktd202x *chip)
-+{
-+ struct device_node *np = dev_of_node(chip->dev), *child;
-+ int count;
-+ int i = 0;
-+
-+ chip->num_leds = (int)(unsigned long)of_device_get_match_data(chip->dev);
-+
-+ count = of_get_available_child_count(np);
-+ if (!count || count > chip->num_leds)
-+ return -EINVAL;
-+
-+ regmap_write(chip->regmap, KTD202X_REG_RESET_CONTROL, KTD202X_RSTR_RESET);
-+
-+ /* Allow the device to execute the complete reset */
-+ usleep_range(200, 300);
-+
-+ for_each_available_child_of_node(np, child) {
-+ int ret = ktd202x_add_led(chip, child, i);
-+
-+ if (ret) {
-+ of_node_put(child);
-+ return ret;
-+ }
-+ i++;
-+ }
-+
-+ return 0;
-+}
-+
-+static const struct regmap_config ktd202x_regmap_config = {
-+ .reg_bits = 8,
-+ .val_bits = 8,
-+ .max_register = 0x09,
-+ .cache_type = REGCACHE_FLAT,
-+ .reg_defaults = ktd202x_reg_defaults,
-+ .num_reg_defaults = ARRAY_SIZE(ktd202x_reg_defaults),
-+};
-+
-+static int ktd202x_probe(struct i2c_client *client)
-+{
-+ struct device *dev = &client->dev;
-+ struct ktd202x *chip;
-+ int count;
-+ int ret;
-+
-+ count = device_get_child_node_count(dev);
-+ if (!count || count > KTD202X_MAX_LEDS)
-+ return dev_err_probe(dev, -EINVAL, "Incorrect number of leds (%d)", count);
-+
-+ chip = devm_kzalloc(dev, struct_size(chip, leds, count), GFP_KERNEL);
-+ if (!chip)
-+ return -ENOMEM;
-+
-+ chip->dev = dev;
-+ i2c_set_clientdata(client, chip);
-+
-+ chip->regmap = devm_regmap_init_i2c(client, &ktd202x_regmap_config);
-+ if (IS_ERR(chip->regmap)) {
-+ ret = dev_err_probe(dev, PTR_ERR(chip->regmap),
-+ "Failed to allocate register map.\n");
-+ return ret;
-+ }
-+
-+ chip->regulators[0].supply = "vin";
-+ chip->regulators[1].supply = "vio";
-+ ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(chip->regulators), chip->regulators);
-+ if (ret < 0) {
-+ dev_err_probe(dev, ret, "Failed to request regulators.\n");
-+ return ret;
-+ }
-+
-+ ret = regulator_bulk_enable(ARRAY_SIZE(chip->regulators), chip->regulators);
-+ if (ret) {
-+ dev_err_probe(dev, ret, "Failed to enable regulators.\n");
-+ return ret;
-+ }
-+
-+ ret = ktd202x_probe_dt(chip);
-+ if (ret < 0) {
-+ regulator_bulk_disable(ARRAY_SIZE(chip->regulators), chip->regulators);
-+ return ret;
-+ }
-+
-+ ret = regulator_bulk_disable(ARRAY_SIZE(chip->regulators), chip->regulators);
-+ if (ret) {
-+ dev_err_probe(dev, ret, "Failed to disable regulators.\n");
-+ return ret;
-+ }
-+
-+ mutex_init(&chip->mutex);
-+
-+ return 0;
-+}
-+
-+static void ktd202x_remove(struct i2c_client *client)
-+{
-+ struct ktd202x *chip = i2c_get_clientdata(client);
-+
-+ ktd202x_chip_disable(chip);
-+
-+ mutex_destroy(&chip->mutex);
-+}
-+
-+static void ktd202x_shutdown(struct i2c_client *client)
-+{
-+ struct ktd202x *chip = i2c_get_clientdata(client);
-+
-+ /* Reset registers to make sure all LEDs are off before shutdown */
-+ regmap_write(chip->regmap, KTD202X_REG_RESET_CONTROL, KTD202X_RSTR_RESET);
-+}
-+
-+static const struct of_device_id ktd202x_match_table[] = {
-+ { .compatible = "kinetic,ktd2026", .data = (void *)KTD2026_NUM_LEDS },
-+ { .compatible = "kinetic,ktd2027", .data = (void *)KTD2027_NUM_LEDS },
-+ {},
-+};
-+MODULE_DEVICE_TABLE(of, ktd202x_match_table);
-+
-+static struct i2c_driver ktd202x_driver = {
-+ .driver = {
-+ .name = "leds-ktd202x",
-+ .of_match_table = ktd202x_match_table,
-+ },
-+ .probe = ktd202x_probe,
-+ .remove = ktd202x_remove,
-+ .shutdown = ktd202x_shutdown,
-+};
-+module_i2c_driver(ktd202x_driver);
-+
-+MODULE_DESCRIPTION("Kinetic KTD2026/7 LED driver");
-+MODULE_LICENSE("GPL");
+++ /dev/null
-From f14aa5ea415b8add245e976bfab96a12986c6843 Mon Sep 17 00:00:00 2001
-Date: Fri, 31 May 2024 13:41:19 +0200
-Subject: leds: rgb: leds-ktd202x: Get device properties through fwnode to
- support ACPI
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-This LED controller is installed on a Xiaomi pad2 and it is an x86
-platform. The original driver is based on the device tree and can't be
-used for this ACPI based system. This patch migrated the driver to use
-fwnode to access the properties. Moreover, the fwnode API supports the
-device tree so this work won't affect the original implementations.
-
----
- drivers/leds/rgb/Kconfig | 1 -
- drivers/leds/rgb/leds-ktd202x.c | 64 ++++++++++++++++++++++-------------------
- 2 files changed, 34 insertions(+), 31 deletions(-)
-
-(limited to 'drivers/leds/rgb')
-
---- a/drivers/leds/rgb/Kconfig
-+++ b/drivers/leds/rgb/Kconfig
-@@ -17,7 +17,6 @@ config LEDS_GROUP_MULTICOLOR
- config LEDS_KTD202X
- tristate "LED support for KTD202x Chips"
- depends on I2C
-- depends on OF
- select REGMAP_I2C
- help
- This option enables support for the Kinetic KTD2026/KTD2027
---- a/drivers/leds/rgb/leds-ktd202x.c
-+++ b/drivers/leds/rgb/leds-ktd202x.c
-@@ -99,7 +99,7 @@ struct ktd202x {
- struct device *dev;
- struct regmap *regmap;
- bool enabled;
-- int num_leds;
-+ unsigned long num_leds;
- struct ktd202x_led leds[] __counted_by(num_leds);
- };
-
-@@ -381,16 +381,19 @@ static int ktd202x_blink_mc_set(struct l
- mc->num_colors);
- }
-
--static int ktd202x_setup_led_rgb(struct ktd202x *chip, struct device_node *np,
-+static int ktd202x_setup_led_rgb(struct ktd202x *chip, struct fwnode_handle *fwnode,
- struct ktd202x_led *led, struct led_init_data *init_data)
- {
-+ struct fwnode_handle *child;
- struct led_classdev *cdev;
-- struct device_node *child;
- struct mc_subled *info;
- int num_channels;
- int i = 0;
-
-- num_channels = of_get_available_child_count(np);
-+ num_channels = 0;
-+ fwnode_for_each_available_child_node(fwnode, child)
-+ num_channels++;
-+
- if (!num_channels || num_channels > chip->num_leds)
- return -EINVAL;
-
-@@ -398,22 +401,22 @@ static int ktd202x_setup_led_rgb(struct
- if (!info)
- return -ENOMEM;
-
-- for_each_available_child_of_node(np, child) {
-+ fwnode_for_each_available_child_node(fwnode, child) {
- u32 mono_color;
- u32 reg;
- int ret;
-
-- ret = of_property_read_u32(child, "reg", ®);
-+ ret = fwnode_property_read_u32(child, "reg", ®);
- if (ret != 0 || reg >= chip->num_leds) {
-- dev_err(chip->dev, "invalid 'reg' of %pOFn\n", child);
-- of_node_put(child);
-- return -EINVAL;
-+ dev_err(chip->dev, "invalid 'reg' of %pfw\n", child);
-+ fwnode_handle_put(child);
-+ return ret;
- }
-
-- ret = of_property_read_u32(child, "color", &mono_color);
-+ ret = fwnode_property_read_u32(child, "color", &mono_color);
- if (ret < 0 && ret != -EINVAL) {
-- dev_err(chip->dev, "failed to parse 'color' of %pOF\n", child);
-- of_node_put(child);
-+ dev_err(chip->dev, "failed to parse 'color' of %pfw\n", child);
-+ fwnode_handle_put(child);
- return ret;
- }
-
-@@ -433,16 +436,16 @@ static int ktd202x_setup_led_rgb(struct
- return devm_led_classdev_multicolor_register_ext(chip->dev, &led->mcdev, init_data);
- }
-
--static int ktd202x_setup_led_single(struct ktd202x *chip, struct device_node *np,
-+static int ktd202x_setup_led_single(struct ktd202x *chip, struct fwnode_handle *fwnode,
- struct ktd202x_led *led, struct led_init_data *init_data)
- {
- struct led_classdev *cdev;
- u32 reg;
- int ret;
-
-- ret = of_property_read_u32(np, "reg", ®);
-+ ret = fwnode_property_read_u32(fwnode, "reg", ®);
- if (ret != 0 || reg >= chip->num_leds) {
-- dev_err(chip->dev, "invalid 'reg' of %pOFn\n", np);
-+ dev_err(chip->dev, "invalid 'reg' of %pfw\n", fwnode);
- return -EINVAL;
- }
- led->index = reg;
-@@ -454,7 +457,7 @@ static int ktd202x_setup_led_single(stru
- return devm_led_classdev_register_ext(chip->dev, &led->cdev, init_data);
- }
-
--static int ktd202x_add_led(struct ktd202x *chip, struct device_node *np, unsigned int index)
-+static int ktd202x_add_led(struct ktd202x *chip, struct fwnode_handle *fwnode, unsigned int index)
- {
- struct ktd202x_led *led = &chip->leds[index];
- struct led_init_data init_data = {};
-@@ -463,21 +466,21 @@ static int ktd202x_add_led(struct ktd202
- int ret;
-
- /* Color property is optional in single color case */
-- ret = of_property_read_u32(np, "color", &color);
-+ ret = fwnode_property_read_u32(fwnode, "color", &color);
- if (ret < 0 && ret != -EINVAL) {
-- dev_err(chip->dev, "failed to parse 'color' of %pOF\n", np);
-+ dev_err(chip->dev, "failed to parse 'color' of %pfw\n", fwnode);
- return ret;
- }
-
- led->chip = chip;
-- init_data.fwnode = of_fwnode_handle(np);
-+ init_data.fwnode = fwnode;
-
- if (color == LED_COLOR_ID_RGB) {
- cdev = &led->mcdev.led_cdev;
-- ret = ktd202x_setup_led_rgb(chip, np, led, &init_data);
-+ ret = ktd202x_setup_led_rgb(chip, fwnode, led, &init_data);
- } else {
- cdev = &led->cdev;
-- ret = ktd202x_setup_led_single(chip, np, led, &init_data);
-+ ret = ktd202x_setup_led_single(chip, fwnode, led, &init_data);
- }
-
- if (ret) {
-@@ -490,15 +493,14 @@ static int ktd202x_add_led(struct ktd202
- return 0;
- }
-
--static int ktd202x_probe_dt(struct ktd202x *chip)
-+static int ktd202x_probe_fw(struct ktd202x *chip)
- {
-- struct device_node *np = dev_of_node(chip->dev), *child;
-+ struct fwnode_handle *child;
-+ struct device *dev = chip->dev;
- int count;
- int i = 0;
-
-- chip->num_leds = (int)(unsigned long)of_device_get_match_data(chip->dev);
--
-- count = of_get_available_child_count(np);
-+ count = device_get_child_node_count(dev);
- if (!count || count > chip->num_leds)
- return -EINVAL;
-
-@@ -507,11 +509,11 @@ static int ktd202x_probe_dt(struct ktd20
- /* Allow the device to execute the complete reset */
- usleep_range(200, 300);
-
-- for_each_available_child_of_node(np, child) {
-+ device_for_each_child_node(dev, child) {
- int ret = ktd202x_add_led(chip, child, i);
-
- if (ret) {
-- of_node_put(child);
-+ fwnode_handle_put(child);
- return ret;
- }
- i++;
-@@ -554,6 +556,8 @@ static int ktd202x_probe(struct i2c_clie
- return ret;
- }
-
-+ chip->num_leds = (unsigned long)i2c_get_match_data(client);
-+
- chip->regulators[0].supply = "vin";
- chip->regulators[1].supply = "vio";
- ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(chip->regulators), chip->regulators);
-@@ -568,7 +572,7 @@ static int ktd202x_probe(struct i2c_clie
- return ret;
- }
-
-- ret = ktd202x_probe_dt(chip);
-+ ret = ktd202x_probe_fw(chip);
- if (ret < 0) {
- regulator_bulk_disable(ARRAY_SIZE(chip->regulators), chip->regulators);
- return ret;
-@@ -605,7 +609,7 @@ static void ktd202x_shutdown(struct i2c_
- static const struct of_device_id ktd202x_match_table[] = {
- { .compatible = "kinetic,ktd2026", .data = (void *)KTD2026_NUM_LEDS },
- { .compatible = "kinetic,ktd2027", .data = (void *)KTD2027_NUM_LEDS },
-- {},
-+ {}
- };
- MODULE_DEVICE_TABLE(of, ktd202x_match_table);
-
+++ /dev/null
-From 75bd07aef47e1a984229e6ec702e8b9aee0226e4 Mon Sep 17 00:00:00 2001
-Date: Fri, 31 May 2024 13:41:20 +0200
-Subject: leds: rgb: leds-ktd202x: I2C ID tables for KTD2026 and 2027
-
-Add an i2c_device_id id_table to match manually instantiated
-(non device-tree / ACPI instantiated) KTD202x controllers as
-found on some x86 boards.
-
-This table shows the maximum support LED channel for KTD2026
-(three LEDs) and KTD-2027 (4 LEDs).
-
-Link: https://www.kinet-ic.com/uploads/KTD2026-7-04h.pdf
----
- drivers/leds/rgb/leds-ktd202x.c | 8 ++++++++
- 1 file changed, 8 insertions(+)
-
-(limited to 'drivers/leds/rgb')
-
---- a/drivers/leds/rgb/leds-ktd202x.c
-+++ b/drivers/leds/rgb/leds-ktd202x.c
-@@ -606,6 +606,13 @@ static void ktd202x_shutdown(struct i2c_
- regmap_write(chip->regmap, KTD202X_REG_RESET_CONTROL, KTD202X_RSTR_RESET);
- }
-
-+static const struct i2c_device_id ktd202x_id[] = {
-+ {"ktd2026", KTD2026_NUM_LEDS},
-+ {"ktd2027", KTD2027_NUM_LEDS},
-+ {}
-+};
-+MODULE_DEVICE_TABLE(i2c, ktd202x_id);
-+
- static const struct of_device_id ktd202x_match_table[] = {
- { .compatible = "kinetic,ktd2026", .data = (void *)KTD2026_NUM_LEDS },
- { .compatible = "kinetic,ktd2027", .data = (void *)KTD2027_NUM_LEDS },
-@@ -621,6 +628,7 @@ static struct i2c_driver ktd202x_driver
- .probe = ktd202x_probe,
- .remove = ktd202x_remove,
- .shutdown = ktd202x_shutdown,
-+ .id_table = ktd202x_id,
- };
- module_i2c_driver(ktd202x_driver);
-
+++ /dev/null
-From e1b08c6f5b92d408a9fcc1030a340caeb9852250 Mon Sep 17 00:00:00 2001
-Date: Fri, 31 May 2024 13:41:21 +0200
-Subject: leds: rgb: leds-ktd202x: Initialize mutex earlier
-
-The mutex must be initialized before the LED class device is registered
-otherwise there is a race where it may get used before it is initialized:
-
- DEBUG_LOCKS_WARN_ON(lock->magic != lock)
- WARNING: CPU: 2 PID: 2045 at kernel/locking/mutex.c:587 __mutex_lock
- ...
- RIP: 0010:__mutex_lock+0x7db/0xc10
- ...
- set_brightness_delayed_set_brightness.part.0+0x17/0x60
- set_brightness_delayed+0xf1/0x100
- process_one_work+0x222/0x5a0
-
-Move the mutex_init() call earlier to avoid this race condition and
-switch to devm_mutex_init() to avoid the need to add error-exit
-cleanup to probe() if probe() fails later on.
-
----
- drivers/leds/rgb/leds-ktd202x.c | 8 ++++----
- 1 file changed, 4 insertions(+), 4 deletions(-)
-
-(limited to 'drivers/leds/rgb')
-
---- a/drivers/leds/rgb/leds-ktd202x.c
-+++ b/drivers/leds/rgb/leds-ktd202x.c
-@@ -556,6 +556,10 @@ static int ktd202x_probe(struct i2c_clie
- return ret;
- }
-
-+ ret = devm_mutex_init(dev, &chip->mutex);
-+ if (ret)
-+ return ret;
-+
- chip->num_leds = (unsigned long)i2c_get_match_data(client);
-
- chip->regulators[0].supply = "vin";
-@@ -584,8 +588,6 @@ static int ktd202x_probe(struct i2c_clie
- return ret;
- }
-
-- mutex_init(&chip->mutex);
--
- return 0;
- }
-
-@@ -594,8 +596,6 @@ static void ktd202x_remove(struct i2c_cl
- struct ktd202x *chip = i2c_get_clientdata(client);
-
- ktd202x_chip_disable(chip);
--
-- mutex_destroy(&chip->mutex);
- }
-
- static void ktd202x_shutdown(struct i2c_client *client)
+++ /dev/null
-From a78794562fcb2659c976388b1285eddda97e9954 Mon Sep 17 00:00:00 2001
-Date: Tue, 10 Oct 2023 21:29:13 +0530
-Subject: [PATCH] PCI: dwc: Add host_post_init() callback
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-This callback can be used by the platform drivers to do configuration
-once all the devices are scanned. Like changing LNKCTL of all downstream
-devices to enable ASPM etc...
-
----
- drivers/pci/controller/dwc/pcie-designware-host.c | 3 +++
- drivers/pci/controller/dwc/pcie-designware.h | 1 +
- 2 files changed, 4 insertions(+)
-
---- a/drivers/pci/controller/dwc/pcie-designware-host.c
-+++ b/drivers/pci/controller/dwc/pcie-designware-host.c
-@@ -502,6 +502,9 @@ int dw_pcie_host_init(struct dw_pcie_rp
- if (ret)
- goto err_stop_link;
-
-+ if (pp->ops->host_post_init)
-+ pp->ops->host_post_init(pp);
-+
- return 0;
-
- err_stop_link:
---- a/drivers/pci/controller/dwc/pcie-designware.h
-+++ b/drivers/pci/controller/dwc/pcie-designware.h
-@@ -301,6 +301,7 @@ enum dw_pcie_ltssm {
- struct dw_pcie_host_ops {
- int (*host_init)(struct dw_pcie_rp *pp);
- void (*host_deinit)(struct dw_pcie_rp *pp);
-+ void (*host_post_init)(struct dw_pcie_rp *pp);
- int (*msi_host_init)(struct dw_pcie_rp *pp);
- void (*pme_turn_off)(struct dw_pcie_rp *pp);
- };
+++ /dev/null
-From 9f4f3dfad8cf08208fbb78b1b9cbf957c12618b9 Mon Sep 17 00:00:00 2001
-Date: Tue, 10 Oct 2023 21:29:14 +0530
-Subject: [PATCH] PCI: qcom: Enable ASPM for platforms supporting 1.9.0 ops
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-ASPM is supported by Qcom host controllers/bridges on most of the recent
-platforms and so the devices tested so far. But for enabling ASPM by
-default (without using Kconfig, kernel command-line or sysfs), BIOS has
-to enable ASPM on both host bridge and downstream devices during boot.
-
-Unfortunately, none of the BIOS available on Qcom platforms enables
-ASPM. Due to this, the platforms making use of Qcom SoCs draw high power
-during runtime.
-
-To fix this power draw issue, users have to enable ASPM using Kconfig,
-kernel command-line, sysfs or the BIOS has to start enabling ASPM.
-
-The latter may happen in the future, but that won't address the issue on
-current platforms. Also, asking users to enable a feature to get the power
-management right would provide an unpleasant out-of-the-box experience.
-
-So the apt solution is to enable ASPM in the controller driver itself. And
-this is being accomplished by calling pci_enable_link_state() in the newly
-introduced host_post_init() callback for all the devices connected to the
-bus. This function enables all supported link low power states for both
-host bridge and the downstream devices.
-
-Due to limited testing, ASPM is only enabled for platforms making use of
-ops_1_9_0 callbacks.
-
-[kwilczynski: commit log]
----
- drivers/pci/controller/dwc/pcie-qcom.c | 28 ++++++++++++++++++++++++++
- 1 file changed, 28 insertions(+)
-
---- a/drivers/pci/controller/dwc/pcie-qcom.c
-+++ b/drivers/pci/controller/dwc/pcie-qcom.c
-@@ -222,6 +222,7 @@ struct qcom_pcie_ops {
- int (*get_resources)(struct qcom_pcie *pcie);
- int (*init)(struct qcom_pcie *pcie);
- int (*post_init)(struct qcom_pcie *pcie);
-+ void (*host_post_init)(struct qcom_pcie *pcie);
- void (*deinit)(struct qcom_pcie *pcie);
- void (*ltssm_enable)(struct qcom_pcie *pcie);
- int (*config_sid)(struct qcom_pcie *pcie);
-@@ -966,6 +967,22 @@ static int qcom_pcie_post_init_2_7_0(str
- return 0;
- }
-
-+static int qcom_pcie_enable_aspm(struct pci_dev *pdev, void *userdata)
-+{
-+ /* Downstream devices need to be in D0 state before enabling PCI PM substates */
-+ pci_set_power_state(pdev, PCI_D0);
-+ pci_enable_link_state(pdev, PCIE_LINK_STATE_ALL);
-+
-+ return 0;
-+}
-+
-+static void qcom_pcie_host_post_init_2_7_0(struct qcom_pcie *pcie)
-+{
-+ struct dw_pcie_rp *pp = &pcie->pci->pp;
-+
-+ pci_walk_bus(pp->bridge->bus, qcom_pcie_enable_aspm, NULL);
-+}
-+
- static void qcom_pcie_deinit_2_7_0(struct qcom_pcie *pcie)
- {
- struct qcom_pcie_resources_2_7_0 *res = &pcie->res.v2_7_0;
-@@ -1224,9 +1241,19 @@ static void qcom_pcie_host_deinit(struct
- pcie->cfg->ops->deinit(pcie);
- }
-
-+static void qcom_pcie_host_post_init(struct dw_pcie_rp *pp)
-+{
-+ struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
-+ struct qcom_pcie *pcie = to_qcom_pcie(pci);
-+
-+ if (pcie->cfg->ops->host_post_init)
-+ pcie->cfg->ops->host_post_init(pcie);
-+}
-+
- static const struct dw_pcie_host_ops qcom_pcie_dw_ops = {
- .host_init = qcom_pcie_host_init,
- .host_deinit = qcom_pcie_host_deinit,
-+ .host_post_init = qcom_pcie_host_post_init,
- };
-
- /* Qcom IP rev.: 2.1.0 Synopsys IP rev.: 4.01a */
-@@ -1288,6 +1315,7 @@ static const struct qcom_pcie_ops ops_1_
- .get_resources = qcom_pcie_get_resources_2_7_0,
- .init = qcom_pcie_init_2_7_0,
- .post_init = qcom_pcie_post_init_2_7_0,
-+ .host_post_init = qcom_pcie_host_post_init_2_7_0,
- .deinit = qcom_pcie_deinit_2_7_0,
- .ltssm_enable = qcom_pcie_2_3_2_ltssm_enable,
- .config_sid = qcom_pcie_config_sid_1_9_0,
+++ /dev/null
-From b0fa00fe38f673c986633c11087274deeb7ce7b0 Mon Sep 17 00:00:00 2001
-Date: Tue, 7 Jan 2025 21:16:20 +0100
-Subject: [PATCH] gpio: regmap: Use generic request/free ops
-
-Set the gpiochip request and free ops to the generic implementations.
-This way a user can provide a gpio-ranges property defined for a pinmux,
-easing muxing of gpio functions. Provided that the pin controller
-implementents the pinmux op .gpio_request_enable(), pins will
-automatically be muxed to their GPIO function when requested.
-
----
- drivers/gpio/gpio-regmap.c | 2 ++
- 1 file changed, 2 insertions(+)
-
---- a/drivers/gpio/gpio-regmap.c
-+++ b/drivers/gpio/gpio-regmap.c
-@@ -276,6 +276,8 @@ struct gpio_regmap *gpio_regmap_register
- chip->label = config->label ?: dev_name(config->parent);
- chip->can_sleep = regmap_might_sleep(config->regmap);
-
-+ chip->request = gpiochip_generic_request;
-+ chip->free = gpiochip_generic_free;
- chip->get = gpio_regmap_get;
- if (gpio->reg_set_base && gpio->reg_clr_base)
- chip->set = gpio_regmap_set_with_clear;
+++ /dev/null
-From d33d1214a1ddf9e7e4d14c62637518252927f0be Mon Sep 17 00:00:00 2001
-Date: Wed, 12 Jun 2024 16:36:40 +0100
-Subject: [PATCH] leds: core: Omit set_brightness error message for a LED
- supporting hw trigger only
-
-If both set_brightness functions return -ENOTSUPP, then the LED doesn't
-support setting a fixed brightness value, and the error message isn't
-helpful. This can be the case e.g. for LEDs supporting a specific hw
-trigger only.
-
-Pinched the subject line and commit message from Heiner:
-
-Reworked the function to provide Heiner's required semantics whilst
-simultaneously increasing readability and flow.
-
----
- drivers/leds/led-core.c | 19 +++++++++++++------
- 1 file changed, 13 insertions(+), 6 deletions(-)
-
---- a/drivers/leds/led-core.c
-+++ b/drivers/leds/led-core.c
-@@ -122,15 +122,22 @@ static void led_timer_function(struct ti
- static void set_brightness_delayed_set_brightness(struct led_classdev *led_cdev,
- unsigned int value)
- {
-- int ret = 0;
-+ int ret;
-
- ret = __led_set_brightness(led_cdev, value);
-- if (ret == -ENOTSUPP)
-+ if (ret == -ENOTSUPP) {
- ret = __led_set_brightness_blocking(led_cdev, value);
-- if (ret < 0 &&
-- /* LED HW might have been unplugged, therefore don't warn */
-- !(ret == -ENODEV && (led_cdev->flags & LED_UNREGISTERING) &&
-- (led_cdev->flags & LED_HW_PLUGGABLE)))
-+ if (ret == -ENOTSUPP)
-+ /* No back-end support to set a fixed brightness value */
-+ return;
-+ }
-+
-+ /* LED HW might have been unplugged, therefore don't warn */
-+ if (ret == -ENODEV && led_cdev->flags & LED_UNREGISTERING &&
-+ led_cdev->flags & LED_HW_PLUGGABLE)
-+ return;
-+
-+ if (ret < 0)
- dev_err(led_cdev->dev,
- "Setting an LED's brightness failed (%d)\n", ret);
- }
+++ /dev/null
-From d48a5472b8f2b29800bb25913f9403765005f1bc Mon Sep 17 00:00:00 2001
-Date: Mon, 18 Sep 2023 21:19:14 +0200
-Subject: [PATCH] net: dsa: realtek: Convert to platform remove callback
- returning void
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-The .remove() callback for a platform driver returns an int which makes
-many driver authors wrongly assume it's possible to do error handling by
-returning an error code. However the value returned is ignored (apart
-from emitting a warning) and this typically results in resource leaks.
-To improve here there is a quest to make the remove callback return
-void. In the first step of this quest all drivers are converted to
-.remove_new() which already returns void. Eventually after all drivers
-are converted, .remove_new() is renamed to .remove().
-
-Trivially convert this driver from always returning zero in the remove
-callback to the void returning variant.
-
----
- drivers/net/dsa/realtek/realtek-smi.c | 8 +++-----
- 1 file changed, 3 insertions(+), 5 deletions(-)
-
---- a/drivers/net/dsa/realtek/realtek-smi.c
-+++ b/drivers/net/dsa/realtek/realtek-smi.c
-@@ -506,12 +506,12 @@ static int realtek_smi_probe(struct plat
- return 0;
- }
-
--static int realtek_smi_remove(struct platform_device *pdev)
-+static void realtek_smi_remove(struct platform_device *pdev)
- {
- struct realtek_priv *priv = platform_get_drvdata(pdev);
-
- if (!priv)
-- return 0;
-+ return;
-
- dsa_unregister_switch(priv->ds);
- if (priv->slave_mii_bus)
-@@ -520,8 +520,6 @@ static int realtek_smi_remove(struct pla
- /* leave the device reset asserted */
- if (priv->reset)
- gpiod_set_value(priv->reset, 1);
--
-- return 0;
- }
-
- static void realtek_smi_shutdown(struct platform_device *pdev)
-@@ -559,7 +557,7 @@ static struct platform_driver realtek_sm
- .of_match_table = realtek_smi_of_match,
- },
- .probe = realtek_smi_probe,
-- .remove = realtek_smi_remove,
-+ .remove_new = realtek_smi_remove,
- .shutdown = realtek_smi_shutdown,
- };
- module_platform_driver(realtek_smi_driver);
+++ /dev/null
-From mboxrd@z Thu Jan 1 00:00:00 1970
-Authentication-Results: smtp.subspace.kernel.org;
-Received: from mail-yb1-xb49.google.com (mail-yb1-xb49.google.com [IPv6:2607:f8b0:4864:20::b49])
- by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 84BB8D6D
-Received: by mail-yb1-xb49.google.com with SMTP id 3f1490d57ef6-db5416d0fccso403298276.1
-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
- d=google.com; s=20230601; t=1701904575; x=1702509375; darn=vger.kernel.org;
- h=cc:to:from:subject:message-id:references:mime-version:in-reply-to
- :date:from:to:cc:subject:date:message-id:reply-to;
- bh=/7eYcPC4ZNNyPcPPs0B5tDplF0arxw3r0vINNNou0rY=;
- b=sMUeie/TxdytzC0EyT11QWi1TqTtiv7KCTs1F2vLmUUvPKNA3+1MHFo8ECW+0gQuDE
- FGrgdZKGK5mXQgkF0N3JiSLvKO8tpQOIB57JLCG5IVy5dr2vVv0ExU3Dag2Cc4oBIBIO
- w/cH95O1oPlvluIpATmAsxenVr7mFomU63BqYiRGLaEhWeb2hJ636GO8lubtsDfdFFoi
- GPOL2tQwV93VnqmywBBpFaNAULN0UoCFhfkKv5prvpkXq19sWI7zyorVZ+rdTYem5m4T
- dXsDaLXPtC3Dh2JOad1duSQIah/wCHYYUcV3IoFhwj2y0Uk/TTCrnZPORweSADcEy6Ho
- vDrA==
-X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
- d=1e100.net; s=20230601; t=1701904575; x=1702509375;
- h=cc:to:from:subject:message-id:references:mime-version:in-reply-to
- :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to;
- bh=/7eYcPC4ZNNyPcPPs0B5tDplF0arxw3r0vINNNou0rY=;
- b=Dmc6aSntxPlxAk72zVO1G9WoZnFtLolxENlLscYYAHG3VE+PQ8gGN2rPzcGoKb2Btb
- 4b0PvjOzSlPQyghahdhdlz04RtAeeGG/MkfNiYjFql5OifIoovb51kroiPYrVsa7Ps7Y
- +Pxug0+NPdTm5s9TNz940ZKl3GRME8UTmVxpWJRX03XMOqb6Wgsh2SK9ahXKc4yRsi62
- 3a3J72WmmSgvimxwM/99fXwvoUQpiv2J1xCoqc1Ng4q4qSuZvzmHN7ZTGaUhLxOqLeLK
- 3W4RKHW6rZ7UjppuB6I3NXW+D344By2rdKp1sRXpjdQ0GS3YUcvlRETcJBXJudHfQP5Y
- CLOw==
-X-Gm-Message-State: AOJu0YzdCTLdwny+N99zeMgyKqFsEZhfIhL2cbgKA6zC1U/OLkxxRLoM
- XrYVBC9DmxCGmP4o+M/Z/kHUew/9faHlCiLGxw==
-X-Google-Smtp-Source: AGHT+IFRXxBV6JuX5Cl/k2o1+WKkCwkR8j20MJSkmoGCedPAtqFttH8OVh1/6vdfnq8MPN++A2h89peZQhyG8OsJ8A==
-X-Received: from jstitt-linux1.c.googlers.com ([fda3:e722:ac3:cc00:2b:ff92:c0a8:23b5])
- (user=justinstitt job=sendgmr) by 2002:a25:dac7:0:b0:da0:3117:f35 with SMTP
- id n190-20020a25dac7000000b00da031170f35mr28652ybf.3.1701904575576; Wed, 06
- Dec 2023 15:16:15 -0800 (PST)
-Date: Wed, 06 Dec 2023 23:16:10 +0000
-Precedence: bulk
-List-Id: <bpf.vger.kernel.org>
-Mime-Version: 1.0
-X-Developer-Key:
[email protected]; a=ed25519; pk=tC3hNkJQTpNX/gLKxTNQKDmiQl6QjBNCGKJINqAdJsE=
-X-Developer-Signature: v=1; a=ed25519-sha256; t=1701904573; l=1840;
- bh=UMdetIL2ZsPIkSodqhw2fM21NHJVjCu0lRImFuNhVoM=; b=a8rMnXfVVQ5gsxHWG4WRMwOLxZgflqXZtNuKx26vv4DwYvvCtCiYjl3f1frOjV/Ul2kaxq5g/
- b/UOv678JKCDASVokxG5GJifAnU7/kqRxdhcwfRkrD8RUfcsmiZOfyF
-X-Mailer: b4 0.12.3
-Subject: [PATCH net-next v5 1/3] ethtool: Implement ethtool_puts()
-Content-Type: text/plain; charset="utf-8"
-
-Use strscpy() to implement ethtool_puts().
-
-Functionally the same as ethtool_sprintf() when it's used with two
-arguments or with just "%s" format specifier.
-
----
- include/linux/ethtool.h | 13 +++++++++++++
- net/ethtool/ioctl.c | 7 +++++++
- 2 files changed, 20 insertions(+)
-
---- a/include/linux/ethtool.h
-+++ b/include/linux/ethtool.h
-@@ -1052,4 +1052,17 @@ static inline int ethtool_mm_frag_size_m
- * next string.
- */
- extern __printf(2, 3) void ethtool_sprintf(u8 **data, const char *fmt, ...);
-+
-+/**
-+ * ethtool_puts - Write string to ethtool string data
-+ * @data: Pointer to a pointer to the start of string to update
-+ * @str: String to write
-+ *
-+ * Write string to *data without a trailing newline. Update *data
-+ * to point at start of next string.
-+ *
-+ * Prefer this function to ethtool_sprintf() when given only
-+ * two arguments or if @fmt is just "%s".
-+ */
-+extern void ethtool_puts(u8 **data, const char *str);
- #endif /* _LINUX_ETHTOOL_H */
---- a/net/ethtool/ioctl.c
-+++ b/net/ethtool/ioctl.c
-@@ -1994,6 +1994,13 @@ __printf(2, 3) void ethtool_sprintf(u8 *
- }
- EXPORT_SYMBOL(ethtool_sprintf);
-
-+void ethtool_puts(u8 **data, const char *str)
-+{
-+ strscpy(*data, str, ETH_GSTRING_LEN);
-+ *data += ETH_GSTRING_LEN;
-+}
-+EXPORT_SYMBOL(ethtool_puts);
-+
- static int ethtool_phys_id(struct net_device *dev, void __user *useraddr)
- {
- struct ethtool_value id;
+++ /dev/null
-From 1a7aa058bc92f0edae7a0d1ef1a7b05aec0c643a Mon Sep 17 00:00:00 2001
-Date: Fri, 24 Nov 2023 12:27:52 +0000
-Subject: [PATCH 1/7] net: phy: add possible interfaces
-
-Add a possible_interfaces member to struct phy_device to indicate which
-interfaces a clause 45 PHY may switch between depending on the media.
-This must be populated by the PHY driver by the time the .config_init()
-method completes according to the PHYs host-side configuration.
-
-For example, the Marvell 88x3310 PHY can switch between 10GBASE-R,
-5GBASE-R, 2500BASE-X, and SGMII on the host side depending on the media
-side speed, so all these interface modes are set in the
-possible_interfaces member.
-
-This allows phylib users (such as phylink) to know in advance which
-interface modes to expect, which allows them to appropriately restrict
-the advertised link modes according to the capabilities of other parts
-of the link.
-
----
- drivers/net/phy/phy_device.c | 2 ++
- include/linux/phy.h | 3 +++
- 2 files changed, 5 insertions(+)
-
---- a/drivers/net/phy/phy_device.c
-+++ b/drivers/net/phy/phy_device.c
-@@ -1269,6 +1269,8 @@ int phy_init_hw(struct phy_device *phyde
- if (ret < 0)
- return ret;
-
-+ phy_interface_zero(phydev->possible_interfaces);
-+
- if (phydev->drv->config_init) {
- ret = phydev->drv->config_init(phydev);
- if (ret < 0)
---- a/include/linux/phy.h
-+++ b/include/linux/phy.h
-@@ -609,6 +609,8 @@ struct macsec_ops;
- * @irq_rerun: Flag indicating interrupts occurred while PHY was suspended,
- * requiring a rerun of the interrupt handler after resume
- * @interface: enum phy_interface_t value
-+ * @possible_interfaces: bitmap if interface modes that the attached PHY
-+ * will switch between depending on media speed.
- * @skb: Netlink message for cable diagnostics
- * @nest: Netlink nest used for cable diagnostics
- * @ehdr: nNtlink header for cable diagnostics
-@@ -678,6 +680,7 @@ struct phy_device {
- u32 dev_flags;
-
- phy_interface_t interface;
-+ DECLARE_PHY_INTERFACE_MASK(possible_interfaces);
-
- /*
- * forced speed & duplex (no autoneg)
+++ /dev/null
-From 85631f5b33f2acce7d42dec1d0a062ab40de95b8 Mon Sep 17 00:00:00 2001
-Date: Sun, 19 Nov 2023 21:07:43 +0000
-Subject: [PATCH 2/7] net: phylink: use for_each_set_bit()
-
-Use for_each_set_bit() rather than open coding the for() test_bit()
-loop.
-
----
- drivers/net/phy/phylink.c | 18 ++++++++----------
- 1 file changed, 8 insertions(+), 10 deletions(-)
-
---- a/drivers/net/phy/phylink.c
-+++ b/drivers/net/phy/phylink.c
-@@ -732,18 +732,16 @@ static int phylink_validate_mask(struct
- __ETHTOOL_DECLARE_LINK_MODE_MASK(all_s) = { 0, };
- __ETHTOOL_DECLARE_LINK_MODE_MASK(s);
- struct phylink_link_state t;
-- int intf;
-+ int interface;
-
-- for (intf = 0; intf < PHY_INTERFACE_MODE_MAX; intf++) {
-- if (test_bit(intf, interfaces)) {
-- linkmode_copy(s, supported);
-+ for_each_set_bit(interface, interfaces, PHY_INTERFACE_MODE_MAX) {
-+ linkmode_copy(s, supported);
-
-- t = *state;
-- t.interface = intf;
-- if (!phylink_validate_mac_and_pcs(pl, s, &t)) {
-- linkmode_or(all_s, all_s, s);
-- linkmode_or(all_adv, all_adv, t.advertising);
-- }
-+ t = *state;
-+ t.interface = interface;
-+ if (!phylink_validate_mac_and_pcs(pl, s, &t)) {
-+ linkmode_or(all_s, all_s, s);
-+ linkmode_or(all_adv, all_adv, t.advertising);
- }
- }
-
+++ /dev/null
-From d4788b4383ce5caeb4e68818357c81a02117a3f9 Mon Sep 17 00:00:00 2001
-Date: Fri, 24 Nov 2023 12:28:19 +0000
-Subject: [PATCH 3/7] net: phylink: split out per-interface validation
-
-Split out the internals of phylink_validate_mask() to make the code
-easier to read.
-
----
- drivers/net/phy/phylink.c | 42 ++++++++++++++++++++++++++++-----------
- 1 file changed, 30 insertions(+), 12 deletions(-)
-
---- a/drivers/net/phy/phylink.c
-+++ b/drivers/net/phy/phylink.c
-@@ -724,26 +724,44 @@ static int phylink_validate_mac_and_pcs(
- return phylink_is_empty_linkmode(supported) ? -EINVAL : 0;
- }
-
-+static void phylink_validate_one(struct phylink *pl,
-+ const unsigned long *supported,
-+ const struct phylink_link_state *state,
-+ phy_interface_t interface,
-+ unsigned long *accum_supported,
-+ unsigned long *accum_advertising)
-+{
-+ __ETHTOOL_DECLARE_LINK_MODE_MASK(tmp_supported);
-+ struct phylink_link_state tmp_state;
-+
-+ linkmode_copy(tmp_supported, supported);
-+
-+ tmp_state = *state;
-+ tmp_state.interface = interface;
-+
-+ if (!phylink_validate_mac_and_pcs(pl, tmp_supported, &tmp_state)) {
-+ phylink_dbg(pl, " interface %u (%s) rate match %s supports %*pbl\n",
-+ interface, phy_modes(interface),
-+ phy_rate_matching_to_str(tmp_state.rate_matching),
-+ __ETHTOOL_LINK_MODE_MASK_NBITS, tmp_supported);
-+
-+ linkmode_or(accum_supported, accum_supported, tmp_supported);
-+ linkmode_or(accum_advertising, accum_advertising,
-+ tmp_state.advertising);
-+ }
-+}
-+
- static int phylink_validate_mask(struct phylink *pl, unsigned long *supported,
- struct phylink_link_state *state,
- const unsigned long *interfaces)
- {
- __ETHTOOL_DECLARE_LINK_MODE_MASK(all_adv) = { 0, };
- __ETHTOOL_DECLARE_LINK_MODE_MASK(all_s) = { 0, };
-- __ETHTOOL_DECLARE_LINK_MODE_MASK(s);
-- struct phylink_link_state t;
- int interface;
-
-- for_each_set_bit(interface, interfaces, PHY_INTERFACE_MODE_MAX) {
-- linkmode_copy(s, supported);
--
-- t = *state;
-- t.interface = interface;
-- if (!phylink_validate_mac_and_pcs(pl, s, &t)) {
-- linkmode_or(all_s, all_s, s);
-- linkmode_or(all_adv, all_adv, t.advertising);
-- }
-- }
-+ for_each_set_bit(interface, interfaces, PHY_INTERFACE_MODE_MAX)
-+ phylink_validate_one(pl, supported, state, interface,
-+ all_s, all_adv);
-
- linkmode_copy(supported, all_s);
- linkmode_copy(state->advertising, all_adv);
+++ /dev/null
-From ce7273c31fadb3143fc80c96a72a42adc19c2757 Mon Sep 17 00:00:00 2001
-Date: Fri, 24 Nov 2023 12:28:24 +0000
-Subject: [PATCH 4/7] net: phylink: pass PHY into phylink_validate_one()
-
-Pass the phy (if any) into phylink_validate_one() so that we can
-validate each interface with its rate matching setting.
-
----
- drivers/net/phy/phylink.c | 7 +++++--
- 1 file changed, 5 insertions(+), 2 deletions(-)
-
---- a/drivers/net/phy/phylink.c
-+++ b/drivers/net/phy/phylink.c
-@@ -724,7 +724,7 @@ static int phylink_validate_mac_and_pcs(
- return phylink_is_empty_linkmode(supported) ? -EINVAL : 0;
- }
-
--static void phylink_validate_one(struct phylink *pl,
-+static void phylink_validate_one(struct phylink *pl, struct phy_device *phy,
- const unsigned long *supported,
- const struct phylink_link_state *state,
- phy_interface_t interface,
-@@ -739,6 +739,9 @@ static void phylink_validate_one(struct
- tmp_state = *state;
- tmp_state.interface = interface;
-
-+ if (phy)
-+ tmp_state.rate_matching = phy_get_rate_matching(phy, interface);
-+
- if (!phylink_validate_mac_and_pcs(pl, tmp_supported, &tmp_state)) {
- phylink_dbg(pl, " interface %u (%s) rate match %s supports %*pbl\n",
- interface, phy_modes(interface),
-@@ -760,7 +763,7 @@ static int phylink_validate_mask(struct
- int interface;
-
- for_each_set_bit(interface, interfaces, PHY_INTERFACE_MODE_MAX)
-- phylink_validate_one(pl, supported, state, interface,
-+ phylink_validate_one(pl, NULL, supported, state, interface,
- all_s, all_adv);
-
- linkmode_copy(supported, all_s);
+++ /dev/null
-From c6fec66d3cd76d797f70b30f1511bed10ba45a96 Mon Sep 17 00:00:00 2001
-Date: Fri, 24 Nov 2023 12:28:29 +0000
-Subject: [PATCH 5/7] net: phylink: pass PHY into phylink_validate_mask()
-
-Pass the phy (if any) into phylink_validate_mask() so that we can
-validate each interface with its rate matching setting.
-
----
- drivers/net/phy/phylink.c | 11 +++++++----
- 1 file changed, 7 insertions(+), 4 deletions(-)
-
---- a/drivers/net/phy/phylink.c
-+++ b/drivers/net/phy/phylink.c
-@@ -754,7 +754,8 @@ static void phylink_validate_one(struct
- }
- }
-
--static int phylink_validate_mask(struct phylink *pl, unsigned long *supported,
-+static int phylink_validate_mask(struct phylink *pl, struct phy_device *phy,
-+ unsigned long *supported,
- struct phylink_link_state *state,
- const unsigned long *interfaces)
- {
-@@ -763,7 +764,7 @@ static int phylink_validate_mask(struct
- int interface;
-
- for_each_set_bit(interface, interfaces, PHY_INTERFACE_MODE_MAX)
-- phylink_validate_one(pl, NULL, supported, state, interface,
-+ phylink_validate_one(pl, phy, supported, state, interface,
- all_s, all_adv);
-
- linkmode_copy(supported, all_s);
-@@ -778,7 +779,8 @@ static int phylink_validate(struct phyli
- const unsigned long *interfaces = pl->config->supported_interfaces;
-
- if (state->interface == PHY_INTERFACE_MODE_NA)
-- return phylink_validate_mask(pl, supported, state, interfaces);
-+ return phylink_validate_mask(pl, NULL, supported, state,
-+ interfaces);
-
- if (!test_bit(state->interface, interfaces))
- return -EINVAL;
-@@ -3465,7 +3467,8 @@ static int phylink_sfp_config_optical(st
- /* For all the interfaces that are supported, reduce the sfp_support
- * mask to only those link modes that can be supported.
- */
-- ret = phylink_validate_mask(pl, pl->sfp_support, &config, interfaces);
-+ ret = phylink_validate_mask(pl, NULL, pl->sfp_support, &config,
-+ interfaces);
- if (ret) {
- phylink_err(pl, "unsupported SFP module: validation with support %*pb failed\n",
- __ETHTOOL_LINK_MODE_MASK_NBITS, support);
+++ /dev/null
-From ee0e0ddb910e7e989b65a19d72b6435baa641fc7 Mon Sep 17 00:00:00 2001
-Date: Fri, 24 Nov 2023 12:28:34 +0000
-Subject: [PATCH 6/7] net: phylink: split out PHY validation from
- phylink_bringup_phy()
-
-When bringing up a PHY, we need to work out which ethtool link modes it
-should support and advertise. Clause 22 PHYs operate in a single
-interface mode, which can be easily dealt with. However, clause 45 PHYs
-tend to switch interface mode depending on the media. We need more
-flexible validation at this point, so this patch splits out that code
-in preparation to changing it.
-
----
- drivers/net/phy/phylink.c | 56 ++++++++++++++++++++++-----------------
- 1 file changed, 31 insertions(+), 25 deletions(-)
-
---- a/drivers/net/phy/phylink.c
-+++ b/drivers/net/phy/phylink.c
-@@ -2019,6 +2019,35 @@ static void phylink_phy_change(struct ph
- phylink_pause_to_str(pl->phy_state.pause));
- }
-
-+static int phylink_validate_phy(struct phylink *pl, struct phy_device *phy,
-+ unsigned long *supported,
-+ struct phylink_link_state *state)
-+{
-+ /* Check whether we would use rate matching for the proposed interface
-+ * mode.
-+ */
-+ state->rate_matching = phy_get_rate_matching(phy, state->interface);
-+
-+ /* Clause 45 PHYs may switch their Serdes lane between, e.g. 10GBASE-R,
-+ * 5GBASE-R, 2500BASE-X and SGMII if they are not using rate matching.
-+ * For some interface modes (e.g. RXAUI, XAUI and USXGMII) switching
-+ * their Serdes is either unnecessary or not reasonable.
-+ *
-+ * For these which switch interface modes, we really need to know which
-+ * interface modes the PHY supports to properly work out which ethtool
-+ * linkmodes can be supported. For now, as a work-around, we validate
-+ * against all interface modes, which may lead to more ethtool link
-+ * modes being advertised than are actually supported.
-+ */
-+ if (phy->is_c45 && state->rate_matching == RATE_MATCH_NONE &&
-+ state->interface != PHY_INTERFACE_MODE_RXAUI &&
-+ state->interface != PHY_INTERFACE_MODE_XAUI &&
-+ state->interface != PHY_INTERFACE_MODE_USXGMII)
-+ state->interface = PHY_INTERFACE_MODE_NA;
-+
-+ return phylink_validate(pl, supported, state);
-+}
-+
- static int phylink_bringup_phy(struct phylink *pl, struct phy_device *phy,
- phy_interface_t interface)
- {
-@@ -2039,32 +2068,9 @@ static int phylink_bringup_phy(struct ph
- memset(&config, 0, sizeof(config));
- linkmode_copy(supported, phy->supported);
- linkmode_copy(config.advertising, phy->advertising);
-+ config.interface = interface;
-
-- /* Check whether we would use rate matching for the proposed interface
-- * mode.
-- */
-- config.rate_matching = phy_get_rate_matching(phy, interface);
--
-- /* Clause 45 PHYs may switch their Serdes lane between, e.g. 10GBASE-R,
-- * 5GBASE-R, 2500BASE-X and SGMII if they are not using rate matching.
-- * For some interface modes (e.g. RXAUI, XAUI and USXGMII) switching
-- * their Serdes is either unnecessary or not reasonable.
-- *
-- * For these which switch interface modes, we really need to know which
-- * interface modes the PHY supports to properly work out which ethtool
-- * linkmodes can be supported. For now, as a work-around, we validate
-- * against all interface modes, which may lead to more ethtool link
-- * modes being advertised than are actually supported.
-- */
-- if (phy->is_c45 && config.rate_matching == RATE_MATCH_NONE &&
-- interface != PHY_INTERFACE_MODE_RXAUI &&
-- interface != PHY_INTERFACE_MODE_XAUI &&
-- interface != PHY_INTERFACE_MODE_USXGMII)
-- config.interface = PHY_INTERFACE_MODE_NA;
-- else
-- config.interface = interface;
--
-- ret = phylink_validate(pl, supported, &config);
-+ ret = phylink_validate_phy(pl, phy, supported, &config);
- if (ret) {
- phylink_warn(pl, "validation of %s with support %*pb and advertisement %*pb failed: %pe\n",
- phy_modes(config.interface),
+++ /dev/null
-From 8f7a9799c5949f94ecc3acfd71b36437a7ade73b Mon Sep 17 00:00:00 2001
-Date: Fri, 24 Nov 2023 12:28:39 +0000
-Subject: [PATCH 7/7] net: phylink: use the PHY's possible_interfaces if
- populated
-
-Some PHYs such as Aquantia, Broadcom 84881, and Marvell 88X33x0 can
-switch between a set of interface types depending on the negotiated
-media speed, or can use rate adaption for some or all of these
-interface types.
-
-We currently assume that these are Clause 45 PHYs that are configured
-not to use a specific set of interface modes, which has worked so far,
-but is just a work-around. In this workaround, we validate using all
-interfaces that the MAC supports, which can lead to extra modes being
-advertised that can not be supported.
-
-To properly address this, switch to using the newly introduced PHY
-possible_interfaces bitmap which indicates which interface modes will
-be used by the PHY as configured. We calculate the union of the PHY's
-possible interfaces and MACs supported interfaces, checking that is
-non-empty. If the PHY is on a SFP, we further reduce the set by those
-which can be used on a SFP module, again checking that is non-empty.
-Finally, we validate the subset of interfaces, taking account of
-whether rate matching will be used for each individual interface mode.
-
-This becomes independent of whether the PHY is clause 22 or clause 45.
-
-It is encouraged that all PHYs that switch interface modes or use
-rate matching should populate phydev->possible_interfaces.
-
----
- drivers/net/phy/phylink.c | 67 +++++++++++++++++++++++++++++++--------
- 1 file changed, 54 insertions(+), 13 deletions(-)
-
---- a/drivers/net/phy/phylink.c
-+++ b/drivers/net/phy/phylink.c
-@@ -123,6 +123,19 @@ do { \
- })
- #endif
-
-+static const phy_interface_t phylink_sfp_interface_preference[] = {
-+ PHY_INTERFACE_MODE_25GBASER,
-+ PHY_INTERFACE_MODE_USXGMII,
-+ PHY_INTERFACE_MODE_10GBASER,
-+ PHY_INTERFACE_MODE_5GBASER,
-+ PHY_INTERFACE_MODE_2500BASEX,
-+ PHY_INTERFACE_MODE_SGMII,
-+ PHY_INTERFACE_MODE_1000BASEX,
-+ PHY_INTERFACE_MODE_100BASEX,
-+};
-+
-+static DECLARE_PHY_INTERFACE_MASK(phylink_sfp_interfaces);
-+
- /**
- * phylink_set_port_modes() - set the port type modes in the ethtool mask
- * @mask: ethtool link mode mask
-@@ -2023,6 +2036,47 @@ static int phylink_validate_phy(struct p
- unsigned long *supported,
- struct phylink_link_state *state)
- {
-+ DECLARE_PHY_INTERFACE_MASK(interfaces);
-+
-+ /* If the PHY provides a bitmap of the interfaces it will be using
-+ * depending on the negotiated media speeds, use this to validate
-+ * which ethtool link modes can be used.
-+ */
-+ if (!phy_interface_empty(phy->possible_interfaces)) {
-+ /* We only care about the union of the PHY's interfaces and
-+ * those which the host supports.
-+ */
-+ phy_interface_and(interfaces, phy->possible_interfaces,
-+ pl->config->supported_interfaces);
-+
-+ if (phy_interface_empty(interfaces)) {
-+ phylink_err(pl, "PHY has no common interfaces\n");
-+ return -EINVAL;
-+ }
-+
-+ if (phy_on_sfp(phy)) {
-+ /* If the PHY is on a SFP, limit the interfaces to
-+ * those that can be used with a SFP module.
-+ */
-+ phy_interface_and(interfaces, interfaces,
-+ phylink_sfp_interfaces);
-+
-+ if (phy_interface_empty(interfaces)) {
-+ phylink_err(pl, "SFP PHY's possible interfaces becomes empty\n");
-+ return -EINVAL;
-+ }
-+ }
-+
-+ phylink_dbg(pl, "PHY %s uses interfaces %*pbl, validating %*pbl\n",
-+ phydev_name(phy),
-+ (int)PHY_INTERFACE_MODE_MAX,
-+ phy->possible_interfaces,
-+ (int)PHY_INTERFACE_MODE_MAX, interfaces);
-+
-+ return phylink_validate_mask(pl, phy, supported, state,
-+ interfaces);
-+ }
-+
- /* Check whether we would use rate matching for the proposed interface
- * mode.
- */
-@@ -3318,19 +3372,6 @@ static void phylink_sfp_detach(void *ups
- pl->netdev->sfp_bus = NULL;
- }
-
--static const phy_interface_t phylink_sfp_interface_preference[] = {
-- PHY_INTERFACE_MODE_25GBASER,
-- PHY_INTERFACE_MODE_USXGMII,
-- PHY_INTERFACE_MODE_10GBASER,
-- PHY_INTERFACE_MODE_5GBASER,
-- PHY_INTERFACE_MODE_2500BASEX,
-- PHY_INTERFACE_MODE_SGMII,
-- PHY_INTERFACE_MODE_1000BASEX,
-- PHY_INTERFACE_MODE_100BASEX,
--};
--
--static DECLARE_PHY_INTERFACE_MASK(phylink_sfp_interfaces);
--
- static phy_interface_t phylink_choose_sfp_interface(struct phylink *pl,
- const unsigned long *intf)
- {
+++ /dev/null
-From 5c5b0c444be3e851046f1c1074459b8d15d2a0f9 Mon Sep 17 00:00:00 2001
-Date: Tue, 27 Feb 2024 18:54:21 +0100
-Subject: [PATCH 1/2] net: dsa: mv88e6xxx: rename
- mv88e6xxx_g2_scratch_gpio_set_smi
-
-The name mv88e6xxx_g2_scratch_gpio_set_smi is a bit ambiguous as it appears
-to only be applicable to the 6390 family, so lets rename it to
-mv88e6390_g2_scratch_gpio_set_smi to make it more obvious.
-
----
- drivers/net/dsa/mv88e6xxx/chip.c | 2 +-
- drivers/net/dsa/mv88e6xxx/global2.h | 2 +-
- drivers/net/dsa/mv88e6xxx/global2_scratch.c | 4 ++--
- 3 files changed, 4 insertions(+), 4 deletions(-)
-
---- a/drivers/net/dsa/mv88e6xxx/chip.c
-+++ b/drivers/net/dsa/mv88e6xxx/chip.c
-@@ -3725,7 +3725,7 @@ static int mv88e6xxx_mdio_register(struc
-
- if (external) {
- mv88e6xxx_reg_lock(chip);
-- err = mv88e6xxx_g2_scratch_gpio_set_smi(chip, true);
-+ err = mv88e6390_g2_scratch_gpio_set_smi(chip, true);
- mv88e6xxx_reg_unlock(chip);
-
- if (err)
---- a/drivers/net/dsa/mv88e6xxx/global2.h
-+++ b/drivers/net/dsa/mv88e6xxx/global2.h
-@@ -378,7 +378,7 @@ extern const struct mv88e6xxx_avb_ops mv
-
- extern const struct mv88e6xxx_gpio_ops mv88e6352_gpio_ops;
-
--int mv88e6xxx_g2_scratch_gpio_set_smi(struct mv88e6xxx_chip *chip,
-+int mv88e6390_g2_scratch_gpio_set_smi(struct mv88e6xxx_chip *chip,
- bool external);
- int mv88e6352_g2_scratch_port_has_serdes(struct mv88e6xxx_chip *chip, int port);
- int mv88e6xxx_g2_atu_stats_set(struct mv88e6xxx_chip *chip, u16 kind, u16 bin);
---- a/drivers/net/dsa/mv88e6xxx/global2_scratch.c
-+++ b/drivers/net/dsa/mv88e6xxx/global2_scratch.c
-@@ -240,7 +240,7 @@ const struct mv88e6xxx_gpio_ops mv88e635
- };
-
- /**
-- * mv88e6xxx_g2_scratch_gpio_set_smi - set gpio muxing for external smi
-+ * mv88e6390_g2_scratch_gpio_set_smi - set gpio muxing for external smi
- * @chip: chip private data
- * @external: set mux for external smi, or free for gpio usage
- *
-@@ -248,7 +248,7 @@ const struct mv88e6xxx_gpio_ops mv88e635
- * an external SMI interface, or they may be made free for other
- * GPIO uses.
- */
--int mv88e6xxx_g2_scratch_gpio_set_smi(struct mv88e6xxx_chip *chip,
-+int mv88e6390_g2_scratch_gpio_set_smi(struct mv88e6xxx_chip *chip,
- bool external)
- {
- int misc_cfg = MV88E6352_G2_SCRATCH_MISC_CFG;
+++ /dev/null
-From e3ab3267a0bbedc37725bb845a332ec33b247263 Mon Sep 17 00:00:00 2001
-Date: Tue, 27 Feb 2024 18:54:22 +0100
-Subject: [PATCH 2/2] net: dsa: mv88e6xxx: add Amethyst specific SMI GPIO
- function
-
-The existing mv88e6390_g2_scratch_gpio_set_smi() cannot be used on the
-88E6393X as it requires certain P0_MODE, it also checks the CPU mode
-as it impacts the bit setting value.
-
-This is all irrelevant for Amethyst (MV88E6191X/6193X/6393X) as only
-the default value of the SMI_PHY Config bit is set to CPU_MGD bootstrap
-pin value but it can be changed without restrictions so that GPIO pins
-9 and 10 are used as SMI pins.
-
-So, introduce Amethyst specific function and call that if the Amethyst
-family wants to setup the external PHY.
-
----
- drivers/net/dsa/mv88e6xxx/chip.c | 5 +++-
- drivers/net/dsa/mv88e6xxx/global2.h | 2 ++
- drivers/net/dsa/mv88e6xxx/global2_scratch.c | 31 +++++++++++++++++++++
- 3 files changed, 37 insertions(+), 1 deletion(-)
-
---- a/drivers/net/dsa/mv88e6xxx/chip.c
-+++ b/drivers/net/dsa/mv88e6xxx/chip.c
-@@ -3725,7 +3725,10 @@ static int mv88e6xxx_mdio_register(struc
-
- if (external) {
- mv88e6xxx_reg_lock(chip);
-- err = mv88e6390_g2_scratch_gpio_set_smi(chip, true);
-+ if (chip->info->family == MV88E6XXX_FAMILY_6393)
-+ err = mv88e6393x_g2_scratch_gpio_set_smi(chip, true);
-+ else
-+ err = mv88e6390_g2_scratch_gpio_set_smi(chip, true);
- mv88e6xxx_reg_unlock(chip);
-
- if (err)
---- a/drivers/net/dsa/mv88e6xxx/global2.h
-+++ b/drivers/net/dsa/mv88e6xxx/global2.h
-@@ -380,6 +380,8 @@ extern const struct mv88e6xxx_gpio_ops m
-
- int mv88e6390_g2_scratch_gpio_set_smi(struct mv88e6xxx_chip *chip,
- bool external);
-+int mv88e6393x_g2_scratch_gpio_set_smi(struct mv88e6xxx_chip *chip,
-+ bool external);
- int mv88e6352_g2_scratch_port_has_serdes(struct mv88e6xxx_chip *chip, int port);
- int mv88e6xxx_g2_atu_stats_set(struct mv88e6xxx_chip *chip, u16 kind, u16 bin);
- int mv88e6xxx_g2_atu_stats_get(struct mv88e6xxx_chip *chip, u16 *stats);
---- a/drivers/net/dsa/mv88e6xxx/global2_scratch.c
-+++ b/drivers/net/dsa/mv88e6xxx/global2_scratch.c
-@@ -291,6 +291,37 @@ int mv88e6390_g2_scratch_gpio_set_smi(st
- }
-
- /**
-+ * mv88e6393x_g2_scratch_gpio_set_smi - set gpio muxing for external smi
-+ * @chip: chip private data
-+ * @external: set mux for external smi, or free for gpio usage
-+ *
-+ * MV88E6191X/6193X/6393X GPIO pins 9 and 10 can be configured as an
-+ * external SMI interface or as regular GPIO-s.
-+ *
-+ * They however have a different register layout then the existing
-+ * function.
-+ */
-+
-+int mv88e6393x_g2_scratch_gpio_set_smi(struct mv88e6xxx_chip *chip,
-+ bool external)
-+{
-+ int misc_cfg = MV88E6352_G2_SCRATCH_MISC_CFG;
-+ int err;
-+ u8 val;
-+
-+ err = mv88e6xxx_g2_scratch_read(chip, misc_cfg, &val);
-+ if (err)
-+ return err;
-+
-+ if (external)
-+ val &= ~MV88E6352_G2_SCRATCH_MISC_CFG_NORMALSMI;
-+ else
-+ val |= MV88E6352_G2_SCRATCH_MISC_CFG_NORMALSMI;
-+
-+ return mv88e6xxx_g2_scratch_write(chip, misc_cfg, val);
-+}
-+
-+/**
- * mv88e6352_g2_scratch_port_has_serdes - indicate if a port can have a serdes
- * @chip: chip private data
- * @port: port number to check for serdes
+++ /dev/null
-From 33f4336cbd32c21717b60d013693a0bd51a27db6 Mon Sep 17 00:00:00 2001
-Date: Fri, 9 Feb 2024 02:03:37 -0300
-Subject: net: dsa: realtek: drop cleanup from realtek_ops
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-It was never used and never referenced.
-
----
- drivers/net/dsa/realtek/realtek.h | 1 -
- 1 file changed, 1 deletion(-)
-
---- a/drivers/net/dsa/realtek/realtek.h
-+++ b/drivers/net/dsa/realtek/realtek.h
-@@ -91,7 +91,6 @@ struct realtek_ops {
- int (*detect)(struct realtek_priv *priv);
- int (*reset_chip)(struct realtek_priv *priv);
- int (*setup)(struct realtek_priv *priv);
-- void (*cleanup)(struct realtek_priv *priv);
- int (*get_mib_counter)(struct realtek_priv *priv,
- int port,
- struct rtl8366_mib_counter *mib,
+++ /dev/null
-From ded3813b44fe11a3bbd2c9d7df8870e8c19a7ccd Mon Sep 17 00:00:00 2001
-Date: Fri, 9 Feb 2024 02:03:38 -0300
-Subject: net: dsa: realtek: introduce REALTEK_DSA namespace
-
-Create a namespace to group the exported symbols.
-
----
- drivers/net/dsa/realtek/realtek-mdio.c | 1 +
- drivers/net/dsa/realtek/realtek-smi.c | 1 +
- drivers/net/dsa/realtek/rtl8365mb.c | 1 +
- drivers/net/dsa/realtek/rtl8366-core.c | 22 +++++++++++-----------
- drivers/net/dsa/realtek/rtl8366rb.c | 1 +
- 5 files changed, 15 insertions(+), 11 deletions(-)
-
---- a/drivers/net/dsa/realtek/realtek-mdio.c
-+++ b/drivers/net/dsa/realtek/realtek-mdio.c
-@@ -288,3 +288,4 @@ mdio_module_driver(realtek_mdio_driver);
- MODULE_DESCRIPTION("Driver for Realtek ethernet switch connected via MDIO interface");
- MODULE_LICENSE("GPL");
-+MODULE_IMPORT_NS(REALTEK_DSA);
---- a/drivers/net/dsa/realtek/realtek-smi.c
-+++ b/drivers/net/dsa/realtek/realtek-smi.c
-@@ -565,3 +565,4 @@ module_platform_driver(realtek_smi_drive
- MODULE_DESCRIPTION("Driver for Realtek ethernet switch connected via SMI interface");
- MODULE_LICENSE("GPL");
-+MODULE_IMPORT_NS(REALTEK_DSA);
---- a/drivers/net/dsa/realtek/rtl8365mb.c
-+++ b/drivers/net/dsa/realtek/rtl8365mb.c
-@@ -2178,3 +2178,4 @@ EXPORT_SYMBOL_GPL(rtl8365mb_variant);
- MODULE_DESCRIPTION("Driver for RTL8365MB-VC ethernet switch");
- MODULE_LICENSE("GPL");
-+MODULE_IMPORT_NS(REALTEK_DSA);
---- a/drivers/net/dsa/realtek/rtl8366-core.c
-+++ b/drivers/net/dsa/realtek/rtl8366-core.c
-@@ -34,7 +34,7 @@ int rtl8366_mc_is_used(struct realtek_pr
-
- return 0;
- }
--EXPORT_SYMBOL_GPL(rtl8366_mc_is_used);
-+EXPORT_SYMBOL_NS_GPL(rtl8366_mc_is_used, REALTEK_DSA);
-
- /**
- * rtl8366_obtain_mc() - retrieve or allocate a VLAN member configuration
-@@ -187,7 +187,7 @@ int rtl8366_set_vlan(struct realtek_priv
-
- return ret;
- }
--EXPORT_SYMBOL_GPL(rtl8366_set_vlan);
-+EXPORT_SYMBOL_NS_GPL(rtl8366_set_vlan, REALTEK_DSA);
-
- int rtl8366_set_pvid(struct realtek_priv *priv, unsigned int port,
- unsigned int vid)
-@@ -217,7 +217,7 @@ int rtl8366_set_pvid(struct realtek_priv
-
- return 0;
- }
--EXPORT_SYMBOL_GPL(rtl8366_set_pvid);
-+EXPORT_SYMBOL_NS_GPL(rtl8366_set_pvid, REALTEK_DSA);
-
- int rtl8366_enable_vlan4k(struct realtek_priv *priv, bool enable)
- {
-@@ -243,7 +243,7 @@ int rtl8366_enable_vlan4k(struct realtek
- priv->vlan4k_enabled = enable;
- return 0;
- }
--EXPORT_SYMBOL_GPL(rtl8366_enable_vlan4k);
-+EXPORT_SYMBOL_NS_GPL(rtl8366_enable_vlan4k, REALTEK_DSA);
-
- int rtl8366_enable_vlan(struct realtek_priv *priv, bool enable)
- {
-@@ -265,7 +265,7 @@ int rtl8366_enable_vlan(struct realtek_p
-
- return ret;
- }
--EXPORT_SYMBOL_GPL(rtl8366_enable_vlan);
-+EXPORT_SYMBOL_NS_GPL(rtl8366_enable_vlan, REALTEK_DSA);
-
- int rtl8366_reset_vlan(struct realtek_priv *priv)
- {
-@@ -290,7 +290,7 @@ int rtl8366_reset_vlan(struct realtek_pr
-
- return 0;
- }
--EXPORT_SYMBOL_GPL(rtl8366_reset_vlan);
-+EXPORT_SYMBOL_NS_GPL(rtl8366_reset_vlan, REALTEK_DSA);
-
- int rtl8366_vlan_add(struct dsa_switch *ds, int port,
- const struct switchdev_obj_port_vlan *vlan,
-@@ -345,7 +345,7 @@ int rtl8366_vlan_add(struct dsa_switch *
-
- return 0;
- }
--EXPORT_SYMBOL_GPL(rtl8366_vlan_add);
-+EXPORT_SYMBOL_NS_GPL(rtl8366_vlan_add, REALTEK_DSA);
-
- int rtl8366_vlan_del(struct dsa_switch *ds, int port,
- const struct switchdev_obj_port_vlan *vlan)
-@@ -389,7 +389,7 @@ int rtl8366_vlan_del(struct dsa_switch *
-
- return 0;
- }
--EXPORT_SYMBOL_GPL(rtl8366_vlan_del);
-+EXPORT_SYMBOL_NS_GPL(rtl8366_vlan_del, REALTEK_DSA);
-
- void rtl8366_get_strings(struct dsa_switch *ds, int port, u32 stringset,
- uint8_t *data)
-@@ -407,7 +407,7 @@ void rtl8366_get_strings(struct dsa_swit
- mib->name, ETH_GSTRING_LEN);
- }
- }
--EXPORT_SYMBOL_GPL(rtl8366_get_strings);
-+EXPORT_SYMBOL_NS_GPL(rtl8366_get_strings, REALTEK_DSA);
-
- int rtl8366_get_sset_count(struct dsa_switch *ds, int port, int sset)
- {
-@@ -421,7 +421,7 @@ int rtl8366_get_sset_count(struct dsa_sw
-
- return priv->num_mib_counters;
- }
--EXPORT_SYMBOL_GPL(rtl8366_get_sset_count);
-+EXPORT_SYMBOL_NS_GPL(rtl8366_get_sset_count, REALTEK_DSA);
-
- void rtl8366_get_ethtool_stats(struct dsa_switch *ds, int port, uint64_t *data)
- {
-@@ -445,4 +445,4 @@ void rtl8366_get_ethtool_stats(struct ds
- data[i] = mibvalue;
- }
- }
--EXPORT_SYMBOL_GPL(rtl8366_get_ethtool_stats);
-+EXPORT_SYMBOL_NS_GPL(rtl8366_get_ethtool_stats, REALTEK_DSA);
---- a/drivers/net/dsa/realtek/rtl8366rb.c
-+++ b/drivers/net/dsa/realtek/rtl8366rb.c
-@@ -1852,3 +1852,4 @@ EXPORT_SYMBOL_GPL(rtl8366rb_variant);
- MODULE_DESCRIPTION("Driver for RTL8366RB ethernet switch");
- MODULE_LICENSE("GPL");
-+MODULE_IMPORT_NS(REALTEK_DSA);
+++ /dev/null
-From bce254b839abe67577bebdef0838796af409c229 Mon Sep 17 00:00:00 2001
-Date: Fri, 9 Feb 2024 02:03:39 -0300
-Subject: net: dsa: realtek: convert variants into real drivers
-
-Previously, the interface modules realtek-smi and realtek-mdio served as
-a platform and an MDIO driver, respectively. Each interface module
-redundantly specified the same compatible strings for both variants and
-referenced symbols from the variants.
-
-Now, each variant module has been transformed into a unified driver
-serving both as a platform and an MDIO driver. This modification
-reverses the relationship between the interface and variant modules,
-with the variant module now utilizing symbols from the interface
-modules.
-
----
- drivers/net/dsa/realtek/Kconfig | 20 +++----
- drivers/net/dsa/realtek/realtek-mdio.c | 68 +++++++++++++++---------
- drivers/net/dsa/realtek/realtek-mdio.h | 48 +++++++++++++++++
- drivers/net/dsa/realtek/realtek-smi.c | 73 +++++++++++++++-----------
- drivers/net/dsa/realtek/realtek-smi.h | 48 +++++++++++++++++
- drivers/net/dsa/realtek/rtl8365mb.c | 54 ++++++++++++++++++-
- drivers/net/dsa/realtek/rtl8366rb.c | 54 ++++++++++++++++++-
- 7 files changed, 292 insertions(+), 73 deletions(-)
- create mode 100644 drivers/net/dsa/realtek/realtek-mdio.h
- create mode 100644 drivers/net/dsa/realtek/realtek-smi.h
-
---- a/drivers/net/dsa/realtek/Kconfig
-+++ b/drivers/net/dsa/realtek/Kconfig
-@@ -16,37 +16,29 @@ menuconfig NET_DSA_REALTEK
- if NET_DSA_REALTEK
-
- config NET_DSA_REALTEK_MDIO
-- tristate "Realtek MDIO interface driver"
-+ tristate "Realtek MDIO interface support"
- depends on OF
-- depends on NET_DSA_REALTEK_RTL8365MB || NET_DSA_REALTEK_RTL8366RB
-- depends on NET_DSA_REALTEK_RTL8365MB || !NET_DSA_REALTEK_RTL8365MB
-- depends on NET_DSA_REALTEK_RTL8366RB || !NET_DSA_REALTEK_RTL8366RB
- help
- Select to enable support for registering switches configured
- through MDIO.
-
- config NET_DSA_REALTEK_SMI
-- tristate "Realtek SMI interface driver"
-+ tristate "Realtek SMI interface support"
- depends on OF
-- depends on NET_DSA_REALTEK_RTL8365MB || NET_DSA_REALTEK_RTL8366RB
-- depends on NET_DSA_REALTEK_RTL8365MB || !NET_DSA_REALTEK_RTL8365MB
-- depends on NET_DSA_REALTEK_RTL8366RB || !NET_DSA_REALTEK_RTL8366RB
- help
- Select to enable support for registering switches connected
- through SMI.
-
- config NET_DSA_REALTEK_RTL8365MB
-- tristate "Realtek RTL8365MB switch subdriver"
-- imply NET_DSA_REALTEK_SMI
-- imply NET_DSA_REALTEK_MDIO
-+ tristate "Realtek RTL8365MB switch driver"
-+ depends on NET_DSA_REALTEK_SMI || NET_DSA_REALTEK_MDIO
- select NET_DSA_TAG_RTL8_4
- help
- Select to enable support for Realtek RTL8365MB-VC and RTL8367S.
-
- config NET_DSA_REALTEK_RTL8366RB
-- tristate "Realtek RTL8366RB switch subdriver"
-- imply NET_DSA_REALTEK_SMI
-- imply NET_DSA_REALTEK_MDIO
-+ tristate "Realtek RTL8366RB switch driver"
-+ depends on NET_DSA_REALTEK_SMI || NET_DSA_REALTEK_MDIO
- select NET_DSA_TAG_RTL4_A
- help
- Select to enable support for Realtek RTL8366RB.
---- a/drivers/net/dsa/realtek/realtek-mdio.c
-+++ b/drivers/net/dsa/realtek/realtek-mdio.c
-@@ -25,6 +25,7 @@
- #include <linux/regmap.h>
-
- #include "realtek.h"
-+#include "realtek-mdio.h"
-
- /* Read/write via mdiobus */
- #define REALTEK_MDIO_CTRL0_REG 31
-@@ -140,7 +141,19 @@ static const struct regmap_config realte
- .disable_locking = true,
- };
-
--static int realtek_mdio_probe(struct mdio_device *mdiodev)
-+/**
-+ * realtek_mdio_probe() - Probe a platform device for an MDIO-connected switch
-+ * @mdiodev: mdio_device to probe on.
-+ *
-+ * This function should be used as the .probe in an mdio_driver. It
-+ * initializes realtek_priv and read data from the device-tree node. The switch
-+ * is hard reset if a method is provided. It checks the switch chip ID and,
-+ * finally, a DSA switch is registered.
-+ *
-+ * Context: Can sleep. Takes and releases priv->map_lock.
-+ * Return: Returns 0 on success, a negative error on failure.
-+ */
-+int realtek_mdio_probe(struct mdio_device *mdiodev)
- {
- struct realtek_priv *priv;
- struct device *dev = &mdiodev->dev;
-@@ -235,8 +248,20 @@ static int realtek_mdio_probe(struct mdi
-
- return 0;
- }
-+EXPORT_SYMBOL_NS_GPL(realtek_mdio_probe, REALTEK_DSA);
-
--static void realtek_mdio_remove(struct mdio_device *mdiodev)
-+/**
-+ * realtek_mdio_remove() - Remove the driver of an MDIO-connected switch
-+ * @mdiodev: mdio_device to be removed.
-+ *
-+ * This function should be used as the .remove_new in an mdio_driver. First
-+ * it unregisters the DSA switch and cleans internal data. If a method is
-+ * provided, the hard reset is asserted to avoid traffic leakage.
-+ *
-+ * Context: Can sleep.
-+ * Return: Nothing.
-+ */
-+void realtek_mdio_remove(struct mdio_device *mdiodev)
- {
- struct realtek_priv *priv = dev_get_drvdata(&mdiodev->dev);
-
-@@ -249,8 +274,21 @@ static void realtek_mdio_remove(struct m
- if (priv->reset)
- gpiod_set_value(priv->reset, 1);
- }
-+EXPORT_SYMBOL_NS_GPL(realtek_mdio_remove, REALTEK_DSA);
-
--static void realtek_mdio_shutdown(struct mdio_device *mdiodev)
-+/**
-+ * realtek_mdio_shutdown() - Shutdown the driver of a MDIO-connected switch
-+ * @mdiodev: mdio_device shutting down.
-+ *
-+ * This function should be used as the .shutdown in an mdio_driver. It shuts
-+ * down the DSA switch and cleans the platform driver data, to prevent
-+ * realtek_mdio_remove() from running afterwards, which is possible if the
-+ * parent bus implements its own .shutdown() as .remove().
-+ *
-+ * Context: Can sleep.
-+ * Return: Nothing.
-+ */
-+void realtek_mdio_shutdown(struct mdio_device *mdiodev)
- {
- struct realtek_priv *priv = dev_get_drvdata(&mdiodev->dev);
-
-@@ -261,29 +299,7 @@ static void realtek_mdio_shutdown(struct
-
- dev_set_drvdata(&mdiodev->dev, NULL);
- }
--
--static const struct of_device_id realtek_mdio_of_match[] = {
--#if IS_ENABLED(CONFIG_NET_DSA_REALTEK_RTL8366RB)
-- { .compatible = "realtek,rtl8366rb", .data = &rtl8366rb_variant, },
--#endif
--#if IS_ENABLED(CONFIG_NET_DSA_REALTEK_RTL8365MB)
-- { .compatible = "realtek,rtl8365mb", .data = &rtl8365mb_variant, },
--#endif
-- { /* sentinel */ },
--};
--MODULE_DEVICE_TABLE(of, realtek_mdio_of_match);
--
--static struct mdio_driver realtek_mdio_driver = {
-- .mdiodrv.driver = {
-- .name = "realtek-mdio",
-- .of_match_table = realtek_mdio_of_match,
-- },
-- .probe = realtek_mdio_probe,
-- .remove = realtek_mdio_remove,
-- .shutdown = realtek_mdio_shutdown,
--};
--
--mdio_module_driver(realtek_mdio_driver);
-+EXPORT_SYMBOL_NS_GPL(realtek_mdio_shutdown, REALTEK_DSA);
-
- MODULE_DESCRIPTION("Driver for Realtek ethernet switch connected via MDIO interface");
---- /dev/null
-+++ b/drivers/net/dsa/realtek/realtek-mdio.h
-@@ -0,0 +1,48 @@
-+/* SPDX-License-Identifier: GPL-2.0+ */
-+
-+#ifndef _REALTEK_MDIO_H
-+#define _REALTEK_MDIO_H
-+
-+#if IS_ENABLED(CONFIG_NET_DSA_REALTEK_MDIO)
-+
-+static inline int realtek_mdio_driver_register(struct mdio_driver *drv)
-+{
-+ return mdio_driver_register(drv);
-+}
-+
-+static inline void realtek_mdio_driver_unregister(struct mdio_driver *drv)
-+{
-+ mdio_driver_unregister(drv);
-+}
-+
-+int realtek_mdio_probe(struct mdio_device *mdiodev);
-+void realtek_mdio_remove(struct mdio_device *mdiodev);
-+void realtek_mdio_shutdown(struct mdio_device *mdiodev);
-+
-+#else /* IS_ENABLED(CONFIG_NET_DSA_REALTEK_MDIO) */
-+
-+static inline int realtek_mdio_driver_register(struct mdio_driver *drv)
-+{
-+ return 0;
-+}
-+
-+static inline void realtek_mdio_driver_unregister(struct mdio_driver *drv)
-+{
-+}
-+
-+static inline int realtek_mdio_probe(struct mdio_device *mdiodev)
-+{
-+ return -ENOENT;
-+}
-+
-+static inline void realtek_mdio_remove(struct mdio_device *mdiodev)
-+{
-+}
-+
-+static inline void realtek_mdio_shutdown(struct mdio_device *mdiodev)
-+{
-+}
-+
-+#endif /* IS_ENABLED(CONFIG_NET_DSA_REALTEK_MDIO) */
-+
-+#endif /* _REALTEK_MDIO_H */
---- a/drivers/net/dsa/realtek/realtek-smi.c
-+++ b/drivers/net/dsa/realtek/realtek-smi.c
-@@ -40,6 +40,7 @@
- #include <linux/if_bridge.h>
-
- #include "realtek.h"
-+#include "realtek-smi.h"
-
- #define REALTEK_SMI_ACK_RETRY_COUNT 5
-
-@@ -408,7 +409,19 @@ err_put_node:
- return ret;
- }
-
--static int realtek_smi_probe(struct platform_device *pdev)
-+/**
-+ * realtek_smi_probe() - Probe a platform device for an SMI-connected switch
-+ * @pdev: platform_device to probe on.
-+ *
-+ * This function should be used as the .probe in a platform_driver. It
-+ * initializes realtek_priv and read data from the device-tree node. The switch
-+ * is hard reset if a method is provided. It checks the switch chip ID and,
-+ * finally, a DSA switch is registered.
-+ *
-+ * Context: Can sleep. Takes and releases priv->map_lock.
-+ * Return: Returns 0 on success, a negative error on failure.
-+ */
-+int realtek_smi_probe(struct platform_device *pdev)
- {
- const struct realtek_variant *var;
- struct device *dev = &pdev->dev;
-@@ -505,8 +518,20 @@ static int realtek_smi_probe(struct plat
- }
- return 0;
- }
-+EXPORT_SYMBOL_NS_GPL(realtek_smi_probe, REALTEK_DSA);
-
--static void realtek_smi_remove(struct platform_device *pdev)
-+/**
-+ * realtek_smi_remove() - Remove the driver of a SMI-connected switch
-+ * @pdev: platform_device to be removed.
-+ *
-+ * This function should be used as the .remove_new in a platform_driver. First
-+ * it unregisters the DSA switch and cleans internal data. If a method is
-+ * provided, the hard reset is asserted to avoid traffic leakage.
-+ *
-+ * Context: Can sleep.
-+ * Return: Nothing.
-+ */
-+void realtek_smi_remove(struct platform_device *pdev)
- {
- struct realtek_priv *priv = platform_get_drvdata(pdev);
-
-@@ -521,8 +546,21 @@ static void realtek_smi_remove(struct pl
- if (priv->reset)
- gpiod_set_value(priv->reset, 1);
- }
-+EXPORT_SYMBOL_NS_GPL(realtek_smi_remove, REALTEK_DSA);
-
--static void realtek_smi_shutdown(struct platform_device *pdev)
-+/**
-+ * realtek_smi_shutdown() - Shutdown the driver of a SMI-connected switch
-+ * @pdev: platform_device shutting down.
-+ *
-+ * This function should be used as the .shutdown in a platform_driver. It shuts
-+ * down the DSA switch and cleans the platform driver data, to prevent
-+ * realtek_smi_remove() from running afterwards, which is possible if the
-+ * parent bus implements its own .shutdown() as .remove().
-+ *
-+ * Context: Can sleep.
-+ * Return: Nothing.
-+ */
-+void realtek_smi_shutdown(struct platform_device *pdev)
- {
- struct realtek_priv *priv = platform_get_drvdata(pdev);
-
-@@ -533,34 +571,7 @@ static void realtek_smi_shutdown(struct
-
- platform_set_drvdata(pdev, NULL);
- }
--
--static const struct of_device_id realtek_smi_of_match[] = {
--#if IS_ENABLED(CONFIG_NET_DSA_REALTEK_RTL8366RB)
-- {
-- .compatible = "realtek,rtl8366rb",
-- .data = &rtl8366rb_variant,
-- },
--#endif
--#if IS_ENABLED(CONFIG_NET_DSA_REALTEK_RTL8365MB)
-- {
-- .compatible = "realtek,rtl8365mb",
-- .data = &rtl8365mb_variant,
-- },
--#endif
-- { /* sentinel */ },
--};
--MODULE_DEVICE_TABLE(of, realtek_smi_of_match);
--
--static struct platform_driver realtek_smi_driver = {
-- .driver = {
-- .name = "realtek-smi",
-- .of_match_table = realtek_smi_of_match,
-- },
-- .probe = realtek_smi_probe,
-- .remove_new = realtek_smi_remove,
-- .shutdown = realtek_smi_shutdown,
--};
--module_platform_driver(realtek_smi_driver);
-+EXPORT_SYMBOL_NS_GPL(realtek_smi_shutdown, REALTEK_DSA);
-
- MODULE_DESCRIPTION("Driver for Realtek ethernet switch connected via SMI interface");
---- /dev/null
-+++ b/drivers/net/dsa/realtek/realtek-smi.h
-@@ -0,0 +1,48 @@
-+/* SPDX-License-Identifier: GPL-2.0+ */
-+
-+#ifndef _REALTEK_SMI_H
-+#define _REALTEK_SMI_H
-+
-+#if IS_ENABLED(CONFIG_NET_DSA_REALTEK_SMI)
-+
-+static inline int realtek_smi_driver_register(struct platform_driver *drv)
-+{
-+ return platform_driver_register(drv);
-+}
-+
-+static inline void realtek_smi_driver_unregister(struct platform_driver *drv)
-+{
-+ platform_driver_unregister(drv);
-+}
-+
-+int realtek_smi_probe(struct platform_device *pdev);
-+void realtek_smi_remove(struct platform_device *pdev);
-+void realtek_smi_shutdown(struct platform_device *pdev);
-+
-+#else /* IS_ENABLED(CONFIG_NET_DSA_REALTEK_SMI) */
-+
-+static inline int realtek_smi_driver_register(struct platform_driver *drv)
-+{
-+ return 0;
-+}
-+
-+static inline void realtek_smi_driver_unregister(struct platform_driver *drv)
-+{
-+}
-+
-+static inline int realtek_smi_probe(struct platform_device *pdev)
-+{
-+ return -ENOENT;
-+}
-+
-+static inline void realtek_smi_remove(struct platform_device *pdev)
-+{
-+}
-+
-+static inline void realtek_smi_shutdown(struct platform_device *pdev)
-+{
-+}
-+
-+#endif /* IS_ENABLED(CONFIG_NET_DSA_REALTEK_SMI) */
-+
-+#endif /* _REALTEK_SMI_H */
---- a/drivers/net/dsa/realtek/rtl8365mb.c
-+++ b/drivers/net/dsa/realtek/rtl8365mb.c
-@@ -101,6 +101,8 @@
- #include <linux/if_vlan.h>
-
- #include "realtek.h"
-+#include "realtek-smi.h"
-+#include "realtek-mdio.h"
-
- /* Family-specific data and limits */
- #define RTL8365MB_PHYADDRMAX 7
-@@ -2173,7 +2175,57 @@ const struct realtek_variant rtl8365mb_v
- .cmd_write = 0xb8,
- .chip_data_sz = sizeof(struct rtl8365mb),
- };
--EXPORT_SYMBOL_GPL(rtl8365mb_variant);
-+
-+static const struct of_device_id rtl8365mb_of_match[] = {
-+ { .compatible = "realtek,rtl8365mb", .data = &rtl8365mb_variant, },
-+ { /* sentinel */ },
-+};
-+MODULE_DEVICE_TABLE(of, rtl8365mb_of_match);
-+
-+static struct platform_driver rtl8365mb_smi_driver = {
-+ .driver = {
-+ .name = "rtl8365mb-smi",
-+ .of_match_table = rtl8365mb_of_match,
-+ },
-+ .probe = realtek_smi_probe,
-+ .remove_new = realtek_smi_remove,
-+ .shutdown = realtek_smi_shutdown,
-+};
-+
-+static struct mdio_driver rtl8365mb_mdio_driver = {
-+ .mdiodrv.driver = {
-+ .name = "rtl8365mb-mdio",
-+ .of_match_table = rtl8365mb_of_match,
-+ },
-+ .probe = realtek_mdio_probe,
-+ .remove = realtek_mdio_remove,
-+ .shutdown = realtek_mdio_shutdown,
-+};
-+
-+static int rtl8365mb_init(void)
-+{
-+ int ret;
-+
-+ ret = realtek_mdio_driver_register(&rtl8365mb_mdio_driver);
-+ if (ret)
-+ return ret;
-+
-+ ret = realtek_smi_driver_register(&rtl8365mb_smi_driver);
-+ if (ret) {
-+ realtek_mdio_driver_unregister(&rtl8365mb_mdio_driver);
-+ return ret;
-+ }
-+
-+ return 0;
-+}
-+module_init(rtl8365mb_init);
-+
-+static void __exit rtl8365mb_exit(void)
-+{
-+ realtek_smi_driver_unregister(&rtl8365mb_smi_driver);
-+ realtek_mdio_driver_unregister(&rtl8365mb_mdio_driver);
-+}
-+module_exit(rtl8365mb_exit);
-
- MODULE_DESCRIPTION("Driver for RTL8365MB-VC ethernet switch");
---- a/drivers/net/dsa/realtek/rtl8366rb.c
-+++ b/drivers/net/dsa/realtek/rtl8366rb.c
-@@ -22,6 +22,8 @@
- #include <linux/regmap.h>
-
- #include "realtek.h"
-+#include "realtek-smi.h"
-+#include "realtek-mdio.h"
-
- #define RTL8366RB_PORT_NUM_CPU 5
- #define RTL8366RB_NUM_PORTS 6
-@@ -1847,7 +1849,57 @@ const struct realtek_variant rtl8366rb_v
- .cmd_write = 0xa8,
- .chip_data_sz = sizeof(struct rtl8366rb),
- };
--EXPORT_SYMBOL_GPL(rtl8366rb_variant);
-+
-+static const struct of_device_id rtl8366rb_of_match[] = {
-+ { .compatible = "realtek,rtl8366rb", .data = &rtl8366rb_variant, },
-+ { /* sentinel */ },
-+};
-+MODULE_DEVICE_TABLE(of, rtl8366rb_of_match);
-+
-+static struct platform_driver rtl8366rb_smi_driver = {
-+ .driver = {
-+ .name = "rtl8366rb-smi",
-+ .of_match_table = rtl8366rb_of_match,
-+ },
-+ .probe = realtek_smi_probe,
-+ .remove_new = realtek_smi_remove,
-+ .shutdown = realtek_smi_shutdown,
-+};
-+
-+static struct mdio_driver rtl8366rb_mdio_driver = {
-+ .mdiodrv.driver = {
-+ .name = "rtl8366rb-mdio",
-+ .of_match_table = rtl8366rb_of_match,
-+ },
-+ .probe = realtek_mdio_probe,
-+ .remove = realtek_mdio_remove,
-+ .shutdown = realtek_mdio_shutdown,
-+};
-+
-+static int rtl8366rb_init(void)
-+{
-+ int ret;
-+
-+ ret = realtek_mdio_driver_register(&rtl8366rb_mdio_driver);
-+ if (ret)
-+ return ret;
-+
-+ ret = realtek_smi_driver_register(&rtl8366rb_smi_driver);
-+ if (ret) {
-+ realtek_mdio_driver_unregister(&rtl8366rb_mdio_driver);
-+ return ret;
-+ }
-+
-+ return 0;
-+}
-+module_init(rtl8366rb_init);
-+
-+static void __exit rtl8366rb_exit(void)
-+{
-+ realtek_smi_driver_unregister(&rtl8366rb_smi_driver);
-+ realtek_mdio_driver_unregister(&rtl8366rb_mdio_driver);
-+}
-+module_exit(rtl8366rb_exit);
-
- MODULE_DESCRIPTION("Driver for RTL8366RB ethernet switch");
+++ /dev/null
-From 4667a1db2f550d23e01ba655fce331196ead6e92 Mon Sep 17 00:00:00 2001
-Date: Fri, 9 Feb 2024 02:03:40 -0300
-Subject: net: dsa: realtek: keep variant reference in
- realtek_priv
-
-Instead of copying values from the variant, we can keep a reference in
-realtek_priv.
-
-This is a preliminary change for sharing code betwen interfaces. It will
-allow to move most of the probe into a common module while still allow
-code specific to each interface to read variant fields.
-
----
- drivers/net/dsa/realtek/realtek-mdio.c | 4 +---
- drivers/net/dsa/realtek/realtek-smi.c | 10 ++++------
- drivers/net/dsa/realtek/realtek.h | 5 ++---
- 3 files changed, 7 insertions(+), 12 deletions(-)
-
---- a/drivers/net/dsa/realtek/realtek-mdio.c
-+++ b/drivers/net/dsa/realtek/realtek-mdio.c
-@@ -196,9 +196,7 @@ int realtek_mdio_probe(struct mdio_devic
- priv->dev = &mdiodev->dev;
- priv->chip_data = (void *)priv + sizeof(*priv);
-
-- priv->clk_delay = var->clk_delay;
-- priv->cmd_read = var->cmd_read;
-- priv->cmd_write = var->cmd_write;
-+ priv->variant = var;
- priv->ops = var->ops;
-
- priv->write_reg_noack = realtek_mdio_write;
---- a/drivers/net/dsa/realtek/realtek-smi.c
-+++ b/drivers/net/dsa/realtek/realtek-smi.c
-@@ -46,7 +46,7 @@
-
- static inline void realtek_smi_clk_delay(struct realtek_priv *priv)
- {
-- ndelay(priv->clk_delay);
-+ ndelay(priv->variant->clk_delay);
- }
-
- static void realtek_smi_start(struct realtek_priv *priv)
-@@ -209,7 +209,7 @@ static int realtek_smi_read_reg(struct r
- realtek_smi_start(priv);
-
- /* Send READ command */
-- ret = realtek_smi_write_byte(priv, priv->cmd_read);
-+ ret = realtek_smi_write_byte(priv, priv->variant->cmd_read);
- if (ret)
- goto out;
-
-@@ -250,7 +250,7 @@ static int realtek_smi_write_reg(struct
- realtek_smi_start(priv);
-
- /* Send WRITE command */
-- ret = realtek_smi_write_byte(priv, priv->cmd_write);
-+ ret = realtek_smi_write_byte(priv, priv->variant->cmd_write);
- if (ret)
- goto out;
-
-@@ -459,9 +459,7 @@ int realtek_smi_probe(struct platform_de
-
- /* Link forward and backward */
- priv->dev = dev;
-- priv->clk_delay = var->clk_delay;
-- priv->cmd_read = var->cmd_read;
-- priv->cmd_write = var->cmd_write;
-+ priv->variant = var;
- priv->ops = var->ops;
-
- priv->setup_interface = realtek_smi_setup_mdio;
---- a/drivers/net/dsa/realtek/realtek.h
-+++ b/drivers/net/dsa/realtek/realtek.h
-@@ -58,9 +58,8 @@ struct realtek_priv {
- struct mii_bus *bus;
- int mdio_addr;
-
-- unsigned int clk_delay;
-- u8 cmd_read;
-- u8 cmd_write;
-+ const struct realtek_variant *variant;
-+
- spinlock_t lock; /* Locks around command writes */
- struct dsa_switch *ds;
- struct irq_domain *irqdomain;
+++ /dev/null
-From 8be040ecd94c1a9a137927d18534edfae0a9b68a Mon Sep 17 00:00:00 2001
-Date: Fri, 9 Feb 2024 02:03:41 -0300
-Subject: net: dsa: realtek: common rtl83xx module
-
-Some code can be shared between both interface modules (MDIO and SMI)
-and among variants. These interface functions migrated to a common
-module:
-
-- rtl83xx_lock
-- rtl83xx_unlock
-- rtl83xx_probe
-- rtl83xx_register_switch
-- rtl83xx_unregister_switch
-- rtl83xx_shutdown
-- rtl83xx_remove
-
-The reset during probe was moved to the end of the common probe. This way,
-we avoid a reset if anything else fails.
-
----
- drivers/net/dsa/realtek/Makefile | 2 +
- drivers/net/dsa/realtek/realtek-mdio.c | 152 +++-------------
- drivers/net/dsa/realtek/realtek-smi.c | 166 ++++-------------
- drivers/net/dsa/realtek/realtek.h | 1 +
- drivers/net/dsa/realtek/rtl8365mb.c | 9 +-
- drivers/net/dsa/realtek/rtl8366rb.c | 9 +-
- drivers/net/dsa/realtek/rtl83xx.c | 235 +++++++++++++++++++++++++
- drivers/net/dsa/realtek/rtl83xx.h | 21 +++
- 8 files changed, 322 insertions(+), 273 deletions(-)
- create mode 100644 drivers/net/dsa/realtek/rtl83xx.c
- create mode 100644 drivers/net/dsa/realtek/rtl83xx.h
-
---- a/drivers/net/dsa/realtek/Makefile
-+++ b/drivers/net/dsa/realtek/Makefile
-@@ -1,4 +1,6 @@
- # SPDX-License-Identifier: GPL-2.0
-+obj-$(CONFIG_NET_DSA_REALTEK) += realtek_dsa.o
-+realtek_dsa-objs := rtl83xx.o
- obj-$(CONFIG_NET_DSA_REALTEK_MDIO) += realtek-mdio.o
- obj-$(CONFIG_NET_DSA_REALTEK_SMI) += realtek-smi.o
- obj-$(CONFIG_NET_DSA_REALTEK_RTL8366RB) += rtl8366.o
---- a/drivers/net/dsa/realtek/realtek-mdio.c
-+++ b/drivers/net/dsa/realtek/realtek-mdio.c
-@@ -26,6 +26,7 @@
-
- #include "realtek.h"
- #include "realtek-mdio.h"
-+#include "rtl83xx.h"
-
- /* Read/write via mdiobus */
- #define REALTEK_MDIO_CTRL0_REG 31
-@@ -100,147 +101,41 @@ out_unlock:
- return ret;
- }
-
--static void realtek_mdio_lock(void *ctx)
--{
-- struct realtek_priv *priv = ctx;
--
-- mutex_lock(&priv->map_lock);
--}
--
--static void realtek_mdio_unlock(void *ctx)
--{
-- struct realtek_priv *priv = ctx;
--
-- mutex_unlock(&priv->map_lock);
--}
--
--static const struct regmap_config realtek_mdio_regmap_config = {
-- .reg_bits = 10, /* A4..A0 R4..R0 */
-- .val_bits = 16,
-- .reg_stride = 1,
-- /* PHY regs are at 0x8000 */
-- .max_register = 0xffff,
-- .reg_format_endian = REGMAP_ENDIAN_BIG,
-+static const struct realtek_interface_info realtek_mdio_info = {
- .reg_read = realtek_mdio_read,
- .reg_write = realtek_mdio_write,
-- .cache_type = REGCACHE_NONE,
-- .lock = realtek_mdio_lock,
-- .unlock = realtek_mdio_unlock,
--};
--
--static const struct regmap_config realtek_mdio_nolock_regmap_config = {
-- .reg_bits = 10, /* A4..A0 R4..R0 */
-- .val_bits = 16,
-- .reg_stride = 1,
-- /* PHY regs are at 0x8000 */
-- .max_register = 0xffff,
-- .reg_format_endian = REGMAP_ENDIAN_BIG,
-- .reg_read = realtek_mdio_read,
-- .reg_write = realtek_mdio_write,
-- .cache_type = REGCACHE_NONE,
-- .disable_locking = true,
- };
-
- /**
- * realtek_mdio_probe() - Probe a platform device for an MDIO-connected switch
- * @mdiodev: mdio_device to probe on.
- *
-- * This function should be used as the .probe in an mdio_driver. It
-- * initializes realtek_priv and read data from the device-tree node. The switch
-- * is hard reset if a method is provided. It checks the switch chip ID and,
-- * finally, a DSA switch is registered.
-+ * This function should be used as the .probe in an mdio_driver. After
-+ * calling the common probe function for both interfaces, it initializes the
-+ * values specific for MDIO-connected devices. Finally, it calls a common
-+ * function to register the DSA switch.
- *
- * Context: Can sleep. Takes and releases priv->map_lock.
- * Return: Returns 0 on success, a negative error on failure.
- */
- int realtek_mdio_probe(struct mdio_device *mdiodev)
- {
-- struct realtek_priv *priv;
- struct device *dev = &mdiodev->dev;
-- const struct realtek_variant *var;
-- struct regmap_config rc;
-- struct device_node *np;
-+ struct realtek_priv *priv;
- int ret;
-
-- var = of_device_get_match_data(dev);
-- if (!var)
-- return -EINVAL;
--
-- priv = devm_kzalloc(&mdiodev->dev,
-- size_add(sizeof(*priv), var->chip_data_sz),
-- GFP_KERNEL);
-- if (!priv)
-- return -ENOMEM;
--
-- mutex_init(&priv->map_lock);
--
-- rc = realtek_mdio_regmap_config;
-- rc.lock_arg = priv;
-- priv->map = devm_regmap_init(dev, NULL, priv, &rc);
-- if (IS_ERR(priv->map)) {
-- ret = PTR_ERR(priv->map);
-- dev_err(dev, "regmap init failed: %d\n", ret);
-- return ret;
-- }
-+ priv = rtl83xx_probe(dev, &realtek_mdio_info);
-+ if (IS_ERR(priv))
-+ return PTR_ERR(priv);
-
-- rc = realtek_mdio_nolock_regmap_config;
-- priv->map_nolock = devm_regmap_init(dev, NULL, priv, &rc);
-- if (IS_ERR(priv->map_nolock)) {
-- ret = PTR_ERR(priv->map_nolock);
-- dev_err(dev, "regmap init failed: %d\n", ret);
-- return ret;
-- }
--
-- priv->mdio_addr = mdiodev->addr;
- priv->bus = mdiodev->bus;
-- priv->dev = &mdiodev->dev;
-- priv->chip_data = (void *)priv + sizeof(*priv);
--
-- priv->variant = var;
-- priv->ops = var->ops;
--
-+ priv->mdio_addr = mdiodev->addr;
- priv->write_reg_noack = realtek_mdio_write;
-+ priv->ds_ops = priv->variant->ds_ops_mdio;
-
-- np = dev->of_node;
--
-- dev_set_drvdata(dev, priv);
--
-- /* TODO: if power is software controlled, set up any regulators here */
-- priv->leds_disabled = of_property_read_bool(np, "realtek,disable-leds");
--
-- priv->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
-- if (IS_ERR(priv->reset)) {
-- dev_err(dev, "failed to get RESET GPIO\n");
-- return PTR_ERR(priv->reset);
-- }
--
-- if (priv->reset) {
-- gpiod_set_value(priv->reset, 1);
-- dev_dbg(dev, "asserted RESET\n");
-- msleep(REALTEK_HW_STOP_DELAY);
-- gpiod_set_value(priv->reset, 0);
-- msleep(REALTEK_HW_START_DELAY);
-- dev_dbg(dev, "deasserted RESET\n");
-- }
--
-- ret = priv->ops->detect(priv);
-- if (ret) {
-- dev_err(dev, "unable to detect switch\n");
-- return ret;
-- }
--
-- priv->ds = devm_kzalloc(dev, sizeof(*priv->ds), GFP_KERNEL);
-- if (!priv->ds)
-- return -ENOMEM;
--
-- priv->ds->dev = dev;
-- priv->ds->num_ports = priv->num_ports;
-- priv->ds->priv = priv;
-- priv->ds->ops = var->ds_ops_mdio;
--
-- ret = dsa_register_switch(priv->ds);
-+ ret = rtl83xx_register_switch(priv);
- if (ret) {
-- dev_err(priv->dev, "unable to register switch ret = %d\n", ret);
-+ rtl83xx_remove(priv);
- return ret;
- }
-
-@@ -253,8 +148,7 @@ EXPORT_SYMBOL_NS_GPL(realtek_mdio_probe,
- * @mdiodev: mdio_device to be removed.
- *
- * This function should be used as the .remove_new in an mdio_driver. First
-- * it unregisters the DSA switch and cleans internal data. If a method is
-- * provided, the hard reset is asserted to avoid traffic leakage.
-+ * it unregisters the DSA switch and then it calls the common remove function.
- *
- * Context: Can sleep.
- * Return: Nothing.
-@@ -266,11 +160,9 @@ void realtek_mdio_remove(struct mdio_dev
- if (!priv)
- return;
-
-- dsa_unregister_switch(priv->ds);
-+ rtl83xx_unregister_switch(priv);
-
-- /* leave the device reset asserted */
-- if (priv->reset)
-- gpiod_set_value(priv->reset, 1);
-+ rtl83xx_remove(priv);
- }
- EXPORT_SYMBOL_NS_GPL(realtek_mdio_remove, REALTEK_DSA);
-
-@@ -278,10 +170,8 @@ EXPORT_SYMBOL_NS_GPL(realtek_mdio_remove
- * realtek_mdio_shutdown() - Shutdown the driver of a MDIO-connected switch
- * @mdiodev: mdio_device shutting down.
- *
-- * This function should be used as the .shutdown in an mdio_driver. It shuts
-- * down the DSA switch and cleans the platform driver data, to prevent
-- * realtek_mdio_remove() from running afterwards, which is possible if the
-- * parent bus implements its own .shutdown() as .remove().
-+ * This function should be used as the .shutdown in a platform_driver. It calls
-+ * the common shutdown function.
- *
- * Context: Can sleep.
- * Return: Nothing.
-@@ -293,9 +183,7 @@ void realtek_mdio_shutdown(struct mdio_d
- if (!priv)
- return;
-
-- dsa_switch_shutdown(priv->ds);
--
-- dev_set_drvdata(&mdiodev->dev, NULL);
-+ rtl83xx_shutdown(priv);
- }
- EXPORT_SYMBOL_NS_GPL(realtek_mdio_shutdown, REALTEK_DSA);
-
---- a/drivers/net/dsa/realtek/realtek-smi.c
-+++ b/drivers/net/dsa/realtek/realtek-smi.c
-@@ -41,6 +41,7 @@
-
- #include "realtek.h"
- #include "realtek-smi.h"
-+#include "rtl83xx.h"
-
- #define REALTEK_SMI_ACK_RETRY_COUNT 5
-
-@@ -311,47 +312,6 @@ static int realtek_smi_read(void *ctx, u
- return realtek_smi_read_reg(priv, reg, val);
- }
-
--static void realtek_smi_lock(void *ctx)
--{
-- struct realtek_priv *priv = ctx;
--
-- mutex_lock(&priv->map_lock);
--}
--
--static void realtek_smi_unlock(void *ctx)
--{
-- struct realtek_priv *priv = ctx;
--
-- mutex_unlock(&priv->map_lock);
--}
--
--static const struct regmap_config realtek_smi_regmap_config = {
-- .reg_bits = 10, /* A4..A0 R4..R0 */
-- .val_bits = 16,
-- .reg_stride = 1,
-- /* PHY regs are at 0x8000 */
-- .max_register = 0xffff,
-- .reg_format_endian = REGMAP_ENDIAN_BIG,
-- .reg_read = realtek_smi_read,
-- .reg_write = realtek_smi_write,
-- .cache_type = REGCACHE_NONE,
-- .lock = realtek_smi_lock,
-- .unlock = realtek_smi_unlock,
--};
--
--static const struct regmap_config realtek_smi_nolock_regmap_config = {
-- .reg_bits = 10, /* A4..A0 R4..R0 */
-- .val_bits = 16,
-- .reg_stride = 1,
-- /* PHY regs are at 0x8000 */
-- .max_register = 0xffff,
-- .reg_format_endian = REGMAP_ENDIAN_BIG,
-- .reg_read = realtek_smi_read,
-- .reg_write = realtek_smi_write,
-- .cache_type = REGCACHE_NONE,
-- .disable_locking = true,
--};
--
- static int realtek_smi_mdio_read(struct mii_bus *bus, int addr, int regnum)
- {
- struct realtek_priv *priv = bus->priv;
-@@ -409,111 +369,56 @@ err_put_node:
- return ret;
- }
-
-+static const struct realtek_interface_info realtek_smi_info = {
-+ .reg_read = realtek_smi_read,
-+ .reg_write = realtek_smi_write,
-+};
-+
- /**
- * realtek_smi_probe() - Probe a platform device for an SMI-connected switch
- * @pdev: platform_device to probe on.
- *
-- * This function should be used as the .probe in a platform_driver. It
-- * initializes realtek_priv and read data from the device-tree node. The switch
-- * is hard reset if a method is provided. It checks the switch chip ID and,
-- * finally, a DSA switch is registered.
-+ * This function should be used as the .probe in a platform_driver. After
-+ * calling the common probe function for both interfaces, it initializes the
-+ * values specific for SMI-connected devices. Finally, it calls a common
-+ * function to register the DSA switch.
- *
- * Context: Can sleep. Takes and releases priv->map_lock.
- * Return: Returns 0 on success, a negative error on failure.
- */
- int realtek_smi_probe(struct platform_device *pdev)
- {
-- const struct realtek_variant *var;
- struct device *dev = &pdev->dev;
- struct realtek_priv *priv;
-- struct regmap_config rc;
-- struct device_node *np;
- int ret;
-
-- var = of_device_get_match_data(dev);
-- np = dev->of_node;
--
-- priv = devm_kzalloc(dev, sizeof(*priv) + var->chip_data_sz, GFP_KERNEL);
-- if (!priv)
-- return -ENOMEM;
-- priv->chip_data = (void *)priv + sizeof(*priv);
--
-- mutex_init(&priv->map_lock);
--
-- rc = realtek_smi_regmap_config;
-- rc.lock_arg = priv;
-- priv->map = devm_regmap_init(dev, NULL, priv, &rc);
-- if (IS_ERR(priv->map)) {
-- ret = PTR_ERR(priv->map);
-- dev_err(dev, "regmap init failed: %d\n", ret);
-- return ret;
-- }
--
-- rc = realtek_smi_nolock_regmap_config;
-- priv->map_nolock = devm_regmap_init(dev, NULL, priv, &rc);
-- if (IS_ERR(priv->map_nolock)) {
-- ret = PTR_ERR(priv->map_nolock);
-- dev_err(dev, "regmap init failed: %d\n", ret);
-- return ret;
-- }
--
-- /* Link forward and backward */
-- priv->dev = dev;
-- priv->variant = var;
-- priv->ops = var->ops;
--
-- priv->setup_interface = realtek_smi_setup_mdio;
-- priv->write_reg_noack = realtek_smi_write_reg_noack;
--
-- dev_set_drvdata(dev, priv);
-- spin_lock_init(&priv->lock);
--
-- /* TODO: if power is software controlled, set up any regulators here */
--
-- priv->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
-- if (IS_ERR(priv->reset)) {
-- dev_err(dev, "failed to get RESET GPIO\n");
-- return PTR_ERR(priv->reset);
-- }
-- if (priv->reset) {
-- gpiod_set_value(priv->reset, 1);
-- dev_dbg(dev, "asserted RESET\n");
-- msleep(REALTEK_HW_STOP_DELAY);
-- gpiod_set_value(priv->reset, 0);
-- msleep(REALTEK_HW_START_DELAY);
-- dev_dbg(dev, "deasserted RESET\n");
-- }
-+ priv = rtl83xx_probe(dev, &realtek_smi_info);
-+ if (IS_ERR(priv))
-+ return PTR_ERR(priv);
-
- /* Fetch MDIO pins */
- priv->mdc = devm_gpiod_get_optional(dev, "mdc", GPIOD_OUT_LOW);
-- if (IS_ERR(priv->mdc))
-+ if (IS_ERR(priv->mdc)) {
-+ rtl83xx_remove(priv);
- return PTR_ERR(priv->mdc);
-+ }
-+
- priv->mdio = devm_gpiod_get_optional(dev, "mdio", GPIOD_OUT_LOW);
-- if (IS_ERR(priv->mdio))
-+ if (IS_ERR(priv->mdio)) {
-+ rtl83xx_remove(priv);
- return PTR_ERR(priv->mdio);
--
-- priv->leds_disabled = of_property_read_bool(np, "realtek,disable-leds");
--
-- ret = priv->ops->detect(priv);
-- if (ret) {
-- dev_err(dev, "unable to detect switch\n");
-- return ret;
- }
-
-- priv->ds = devm_kzalloc(dev, sizeof(*priv->ds), GFP_KERNEL);
-- if (!priv->ds)
-- return -ENOMEM;
--
-- priv->ds->dev = dev;
-- priv->ds->num_ports = priv->num_ports;
-- priv->ds->priv = priv;
-+ priv->write_reg_noack = realtek_smi_write_reg_noack;
-+ priv->setup_interface = realtek_smi_setup_mdio;
-+ priv->ds_ops = priv->variant->ds_ops_smi;
-
-- priv->ds->ops = var->ds_ops_smi;
-- ret = dsa_register_switch(priv->ds);
-+ ret = rtl83xx_register_switch(priv);
- if (ret) {
-- dev_err_probe(dev, ret, "unable to register switch\n");
-+ rtl83xx_remove(priv);
- return ret;
- }
-+
- return 0;
- }
- EXPORT_SYMBOL_NS_GPL(realtek_smi_probe, REALTEK_DSA);
-@@ -523,8 +428,8 @@ EXPORT_SYMBOL_NS_GPL(realtek_smi_probe,
- * @pdev: platform_device to be removed.
- *
- * This function should be used as the .remove_new in a platform_driver. First
-- * it unregisters the DSA switch and cleans internal data. If a method is
-- * provided, the hard reset is asserted to avoid traffic leakage.
-+ * it unregisters the DSA switch and cleans internal data. Finally, it calls
-+ * the common remove function.
- *
- * Context: Can sleep.
- * Return: Nothing.
-@@ -536,13 +441,12 @@ void realtek_smi_remove(struct platform_
- if (!priv)
- return;
-
-- dsa_unregister_switch(priv->ds);
-+ rtl83xx_unregister_switch(priv);
-+
- if (priv->slave_mii_bus)
- of_node_put(priv->slave_mii_bus->dev.of_node);
-
-- /* leave the device reset asserted */
-- if (priv->reset)
-- gpiod_set_value(priv->reset, 1);
-+ rtl83xx_remove(priv);
- }
- EXPORT_SYMBOL_NS_GPL(realtek_smi_remove, REALTEK_DSA);
-
-@@ -550,10 +454,8 @@ EXPORT_SYMBOL_NS_GPL(realtek_smi_remove,
- * realtek_smi_shutdown() - Shutdown the driver of a SMI-connected switch
- * @pdev: platform_device shutting down.
- *
-- * This function should be used as the .shutdown in a platform_driver. It shuts
-- * down the DSA switch and cleans the platform driver data, to prevent
-- * realtek_smi_remove() from running afterwards, which is possible if the
-- * parent bus implements its own .shutdown() as .remove().
-+ * This function should be used as the .shutdown in a platform_driver. It calls
-+ * the common shutdown function.
- *
- * Context: Can sleep.
- * Return: Nothing.
-@@ -565,9 +467,7 @@ void realtek_smi_shutdown(struct platfor
- if (!priv)
- return;
-
-- dsa_switch_shutdown(priv->ds);
--
-- platform_set_drvdata(pdev, NULL);
-+ rtl83xx_shutdown(priv);
- }
- EXPORT_SYMBOL_NS_GPL(realtek_smi_shutdown, REALTEK_DSA);
-
---- a/drivers/net/dsa/realtek/realtek.h
-+++ b/drivers/net/dsa/realtek/realtek.h
-@@ -62,6 +62,7 @@ struct realtek_priv {
-
- spinlock_t lock; /* Locks around command writes */
- struct dsa_switch *ds;
-+ const struct dsa_switch_ops *ds_ops;
- struct irq_domain *irqdomain;
- bool leds_disabled;
-
---- a/drivers/net/dsa/realtek/rtl8365mb.c
-+++ b/drivers/net/dsa/realtek/rtl8365mb.c
-@@ -103,6 +103,7 @@
- #include "realtek.h"
- #include "realtek-smi.h"
- #include "realtek-mdio.h"
-+#include "rtl83xx.h"
-
- /* Family-specific data and limits */
- #define RTL8365MB_PHYADDRMAX 7
-@@ -691,7 +692,7 @@ static int rtl8365mb_phy_ocp_read(struct
- u32 val;
- int ret;
-
-- mutex_lock(&priv->map_lock);
-+ rtl83xx_lock(priv);
-
- ret = rtl8365mb_phy_poll_busy(priv);
- if (ret)
-@@ -724,7 +725,7 @@ static int rtl8365mb_phy_ocp_read(struct
- *data = val & 0xFFFF;
-
- out:
-- mutex_unlock(&priv->map_lock);
-+ rtl83xx_unlock(priv);
-
- return ret;
- }
-@@ -735,7 +736,7 @@ static int rtl8365mb_phy_ocp_write(struc
- u32 val;
- int ret;
-
-- mutex_lock(&priv->map_lock);
-+ rtl83xx_lock(priv);
-
- ret = rtl8365mb_phy_poll_busy(priv);
- if (ret)
-@@ -766,7 +767,7 @@ static int rtl8365mb_phy_ocp_write(struc
- goto out;
-
- out:
-- mutex_unlock(&priv->map_lock);
-+ rtl83xx_unlock(priv);
-
- return 0;
- }
---- a/drivers/net/dsa/realtek/rtl8366rb.c
-+++ b/drivers/net/dsa/realtek/rtl8366rb.c
-@@ -24,6 +24,7 @@
- #include "realtek.h"
- #include "realtek-smi.h"
- #include "realtek-mdio.h"
-+#include "rtl83xx.h"
-
- #define RTL8366RB_PORT_NUM_CPU 5
- #define RTL8366RB_NUM_PORTS 6
-@@ -1634,7 +1635,7 @@ static int rtl8366rb_phy_read(struct rea
- if (phy > RTL8366RB_PHY_NO_MAX)
- return -EINVAL;
-
-- mutex_lock(&priv->map_lock);
-+ rtl83xx_lock(priv);
-
- ret = regmap_write(priv->map_nolock, RTL8366RB_PHY_ACCESS_CTRL_REG,
- RTL8366RB_PHY_CTRL_READ);
-@@ -1662,7 +1663,7 @@ static int rtl8366rb_phy_read(struct rea
- phy, regnum, reg, val);
-
- out:
-- mutex_unlock(&priv->map_lock);
-+ rtl83xx_unlock(priv);
-
- return ret;
- }
-@@ -1676,7 +1677,7 @@ static int rtl8366rb_phy_write(struct re
- if (phy > RTL8366RB_PHY_NO_MAX)
- return -EINVAL;
-
-- mutex_lock(&priv->map_lock);
-+ rtl83xx_lock(priv);
-
- ret = regmap_write(priv->map_nolock, RTL8366RB_PHY_ACCESS_CTRL_REG,
- RTL8366RB_PHY_CTRL_WRITE);
-@@ -1693,7 +1694,7 @@ static int rtl8366rb_phy_write(struct re
- goto out;
-
- out:
-- mutex_unlock(&priv->map_lock);
-+ rtl83xx_unlock(priv);
-
- return ret;
- }
---- /dev/null
-+++ b/drivers/net/dsa/realtek/rtl83xx.c
-@@ -0,0 +1,236 @@
-+// SPDX-License-Identifier: GPL-2.0+
-+
-+#include <linux/module.h>
-+#include <linux/regmap.h>
-+#include <linux/of_device.h> /* krnl 6.1 only */
-+
-+#include "realtek.h"
-+#include "rtl83xx.h"
-+
-+/**
-+ * rtl83xx_lock() - Locks the mutex used by regmaps
-+ * @ctx: realtek_priv pointer
-+ *
-+ * This function is passed to regmap to be used as the lock function.
-+ * It is also used externally to block regmap before executing multiple
-+ * operations that must happen in sequence (which will use
-+ * realtek_priv.map_nolock instead).
-+ *
-+ * Context: Can sleep. Holds priv->map_lock lock.
-+ * Return: nothing
-+ */
-+void rtl83xx_lock(void *ctx)
-+{
-+ struct realtek_priv *priv = ctx;
-+
-+ mutex_lock(&priv->map_lock);
-+}
-+EXPORT_SYMBOL_NS_GPL(rtl83xx_lock, REALTEK_DSA);
-+
-+/**
-+ * rtl83xx_unlock() - Unlocks the mutex used by regmaps
-+ * @ctx: realtek_priv pointer
-+ *
-+ * This function unlocks the lock acquired by rtl83xx_lock.
-+ *
-+ * Context: Releases priv->map_lock lock.
-+ * Return: nothing
-+ */
-+void rtl83xx_unlock(void *ctx)
-+{
-+ struct realtek_priv *priv = ctx;
-+
-+ mutex_unlock(&priv->map_lock);
-+}
-+EXPORT_SYMBOL_NS_GPL(rtl83xx_unlock, REALTEK_DSA);
-+
-+/**
-+ * rtl83xx_probe() - probe a Realtek switch
-+ * @dev: the device being probed
-+ * @interface_info: specific management interface info.
-+ *
-+ * This function initializes realtek_priv and reads data from the device tree
-+ * node. The switch is hard resetted if a method is provided.
-+ *
-+ * Context: Can sleep.
-+ * Return: Pointer to the realtek_priv or ERR_PTR() in case of failure.
-+ *
-+ * The realtek_priv pointer does not need to be freed as it is controlled by
-+ * devres.
-+ */
-+struct realtek_priv *
-+rtl83xx_probe(struct device *dev,
-+ const struct realtek_interface_info *interface_info)
-+{
-+ const struct realtek_variant *var;
-+ struct realtek_priv *priv;
-+ struct regmap_config rc = {
-+ .reg_bits = 10, /* A4..A0 R4..R0 */
-+ .val_bits = 16,
-+ .reg_stride = 1,
-+ .max_register = 0xffff,
-+ .reg_format_endian = REGMAP_ENDIAN_BIG,
-+ .reg_read = interface_info->reg_read,
-+ .reg_write = interface_info->reg_write,
-+ .cache_type = REGCACHE_NONE,
-+ .lock = rtl83xx_lock,
-+ .unlock = rtl83xx_unlock,
-+ };
-+ int ret;
-+
-+ var = of_device_get_match_data(dev);
-+ if (!var)
-+ return ERR_PTR(-EINVAL);
-+
-+ priv = devm_kzalloc(dev, size_add(sizeof(*priv), var->chip_data_sz),
-+ GFP_KERNEL);
-+ if (!priv)
-+ return ERR_PTR(-ENOMEM);
-+
-+ mutex_init(&priv->map_lock);
-+
-+ rc.lock_arg = priv;
-+ priv->map = devm_regmap_init(dev, NULL, priv, &rc);
-+ if (IS_ERR(priv->map)) {
-+ ret = PTR_ERR(priv->map);
-+ dev_err(dev, "regmap init failed: %d\n", ret);
-+ return ERR_PTR(ret);
-+ }
-+
-+ rc.disable_locking = true;
-+ priv->map_nolock = devm_regmap_init(dev, NULL, priv, &rc);
-+ if (IS_ERR(priv->map_nolock)) {
-+ ret = PTR_ERR(priv->map_nolock);
-+ dev_err(dev, "regmap init failed: %d\n", ret);
-+ return ERR_PTR(ret);
-+ }
-+
-+ /* Link forward and backward */
-+ priv->dev = dev;
-+ priv->variant = var;
-+ priv->ops = var->ops;
-+ priv->chip_data = (void *)priv + sizeof(*priv);
-+
-+ spin_lock_init(&priv->lock);
-+
-+ priv->leds_disabled = of_property_read_bool(dev->of_node,
-+ "realtek,disable-leds");
-+
-+ /* TODO: if power is software controlled, set up any regulators here */
-+ priv->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
-+ if (IS_ERR(priv->reset)) {
-+ dev_err(dev, "failed to get RESET GPIO\n");
-+ return ERR_CAST(priv->reset);
-+ }
-+
-+ dev_set_drvdata(dev, priv);
-+
-+ if (priv->reset) {
-+ gpiod_set_value(priv->reset, 1);
-+ dev_dbg(dev, "asserted RESET\n");
-+ msleep(REALTEK_HW_STOP_DELAY);
-+ gpiod_set_value(priv->reset, 0);
-+ msleep(REALTEK_HW_START_DELAY);
-+ dev_dbg(dev, "deasserted RESET\n");
-+ }
-+
-+ return priv;
-+}
-+EXPORT_SYMBOL_NS_GPL(rtl83xx_probe, REALTEK_DSA);
-+
-+/**
-+ * rtl83xx_register_switch() - detects and register a switch
-+ * @priv: realtek_priv pointer
-+ *
-+ * This function first checks the switch chip ID and register a DSA
-+ * switch.
-+ *
-+ * Context: Can sleep. Takes and releases priv->map_lock.
-+ * Return: 0 on success, negative value for failure.
-+ */
-+int rtl83xx_register_switch(struct realtek_priv *priv)
-+{
-+ struct dsa_switch *ds;
-+ int ret;
-+
-+ ret = priv->ops->detect(priv);
-+ if (ret) {
-+ dev_err_probe(priv->dev, ret, "unable to detect switch\n");
-+ return ret;
-+ }
-+
-+ ds = devm_kzalloc(priv->dev, sizeof(*ds), GFP_KERNEL);
-+ if (!ds)
-+ return -ENOMEM;
-+
-+ ds->priv = priv;
-+ ds->dev = priv->dev;
-+ ds->ops = priv->ds_ops;
-+ ds->num_ports = priv->num_ports;
-+ priv->ds = ds;
-+
-+ ret = dsa_register_switch(ds);
-+ if (ret) {
-+ dev_err_probe(priv->dev, ret, "unable to register switch\n");
-+ return ret;
-+ }
-+
-+ return 0;
-+}
-+EXPORT_SYMBOL_NS_GPL(rtl83xx_register_switch, REALTEK_DSA);
-+
-+/**
-+ * rtl83xx_unregister_switch() - unregister a switch
-+ * @priv: realtek_priv pointer
-+ *
-+ * This function unregister a DSA switch.
-+ *
-+ * Context: Can sleep.
-+ * Return: Nothing.
-+ */
-+void rtl83xx_unregister_switch(struct realtek_priv *priv)
-+{
-+ dsa_unregister_switch(priv->ds);
-+}
-+EXPORT_SYMBOL_NS_GPL(rtl83xx_unregister_switch, REALTEK_DSA);
-+
-+/**
-+ * rtl83xx_shutdown() - shutdown a switch
-+ * @priv: realtek_priv pointer
-+ *
-+ * This function shuts down the DSA switch and cleans the platform driver data,
-+ * to prevent realtek_{smi,mdio}_remove() from running afterwards, which is
-+ * possible if the parent bus implements its own .shutdown() as .remove().
-+ *
-+ * Context: Can sleep.
-+ * Return: Nothing.
-+ */
-+void rtl83xx_shutdown(struct realtek_priv *priv)
-+{
-+ dsa_switch_shutdown(priv->ds);
-+
-+ dev_set_drvdata(priv->dev, NULL);
-+}
-+EXPORT_SYMBOL_NS_GPL(rtl83xx_shutdown, REALTEK_DSA);
-+
-+/**
-+ * rtl83xx_remove() - Cleanup a realtek switch driver
-+ * @priv: realtek_priv pointer
-+ *
-+ * If a method is provided, this function asserts the hard reset of the switch
-+ * in order to avoid leaking traffic when the driver is gone.
-+ *
-+ * Context: Might sleep if priv->gdev->chip->can_sleep.
-+ * Return: nothing
-+ */
-+void rtl83xx_remove(struct realtek_priv *priv)
-+{
-+ /* leave the device reset asserted */
-+ if (priv->reset)
-+ gpiod_set_value(priv->reset, 1);
-+}
-+EXPORT_SYMBOL_NS_GPL(rtl83xx_remove, REALTEK_DSA);
-+
-+MODULE_DESCRIPTION("Realtek DSA switches common module");
-+MODULE_LICENSE("GPL");
---- /dev/null
-+++ b/drivers/net/dsa/realtek/rtl83xx.h
-@@ -0,0 +1,21 @@
-+/* SPDX-License-Identifier: GPL-2.0+ */
-+
-+#ifndef _RTL83XX_H
-+#define _RTL83XX_H
-+
-+struct realtek_interface_info {
-+ int (*reg_read)(void *ctx, u32 reg, u32 *val);
-+ int (*reg_write)(void *ctx, u32 reg, u32 val);
-+};
-+
-+void rtl83xx_lock(void *ctx);
-+void rtl83xx_unlock(void *ctx);
-+struct realtek_priv *
-+rtl83xx_probe(struct device *dev,
-+ const struct realtek_interface_info *interface_info);
-+int rtl83xx_register_switch(struct realtek_priv *priv);
-+void rtl83xx_unregister_switch(struct realtek_priv *priv);
-+void rtl83xx_shutdown(struct realtek_priv *priv);
-+void rtl83xx_remove(struct realtek_priv *priv);
-+
-+#endif /* _RTL83XX_H */
+++ /dev/null
-From 98b75c1c149c653ad11a440636213eb070325158 Mon Sep 17 00:00:00 2001
-Date: Fri, 9 Feb 2024 02:03:42 -0300
-Subject: net: dsa: realtek: merge rtl83xx and interface
- modules into realtek_dsa
-
-Since rtl83xx and realtek-{smi,mdio} are always loaded together,
-we can optimize resource usage by consolidating them into a single
-module.
-
----
- drivers/net/dsa/realtek/Kconfig | 4 ++--
- drivers/net/dsa/realtek/Makefile | 11 +++++++++--
- drivers/net/dsa/realtek/realtek-mdio.c | 5 -----
- drivers/net/dsa/realtek/realtek-smi.c | 5 -----
- drivers/net/dsa/realtek/rtl83xx.c | 1 +
- 5 files changed, 12 insertions(+), 14 deletions(-)
-
---- a/drivers/net/dsa/realtek/Kconfig
-+++ b/drivers/net/dsa/realtek/Kconfig
-@@ -16,14 +16,14 @@ menuconfig NET_DSA_REALTEK
- if NET_DSA_REALTEK
-
- config NET_DSA_REALTEK_MDIO
-- tristate "Realtek MDIO interface support"
-+ bool "Realtek MDIO interface support"
- depends on OF
- help
- Select to enable support for registering switches configured
- through MDIO.
-
- config NET_DSA_REALTEK_SMI
-- tristate "Realtek SMI interface support"
-+ bool "Realtek SMI interface support"
- depends on OF
- help
- Select to enable support for registering switches connected
---- a/drivers/net/dsa/realtek/Makefile
-+++ b/drivers/net/dsa/realtek/Makefile
-@@ -1,8 +1,15 @@
- # SPDX-License-Identifier: GPL-2.0
- obj-$(CONFIG_NET_DSA_REALTEK) += realtek_dsa.o
- realtek_dsa-objs := rtl83xx.o
--obj-$(CONFIG_NET_DSA_REALTEK_MDIO) += realtek-mdio.o
--obj-$(CONFIG_NET_DSA_REALTEK_SMI) += realtek-smi.o
-+
-+ifdef CONFIG_NET_DSA_REALTEK_MDIO
-+realtek_dsa-objs += realtek-mdio.o
-+endif
-+
-+ifdef CONFIG_NET_DSA_REALTEK_SMI
-+realtek_dsa-objs += realtek-smi.o
-+endif
-+
- obj-$(CONFIG_NET_DSA_REALTEK_RTL8366RB) += rtl8366.o
- rtl8366-objs := rtl8366-core.o rtl8366rb.o
- obj-$(CONFIG_NET_DSA_REALTEK_RTL8365MB) += rtl8365mb.o
---- a/drivers/net/dsa/realtek/realtek-mdio.c
-+++ b/drivers/net/dsa/realtek/realtek-mdio.c
-@@ -186,8 +186,3 @@ void realtek_mdio_shutdown(struct mdio_d
- rtl83xx_shutdown(priv);
- }
- EXPORT_SYMBOL_NS_GPL(realtek_mdio_shutdown, REALTEK_DSA);
--
--MODULE_DESCRIPTION("Driver for Realtek ethernet switch connected via MDIO interface");
--MODULE_LICENSE("GPL");
--MODULE_IMPORT_NS(REALTEK_DSA);
---- a/drivers/net/dsa/realtek/realtek-smi.c
-+++ b/drivers/net/dsa/realtek/realtek-smi.c
-@@ -470,8 +470,3 @@ void realtek_smi_shutdown(struct platfor
- rtl83xx_shutdown(priv);
- }
- EXPORT_SYMBOL_NS_GPL(realtek_smi_shutdown, REALTEK_DSA);
--
--MODULE_DESCRIPTION("Driver for Realtek ethernet switch connected via SMI interface");
--MODULE_LICENSE("GPL");
--MODULE_IMPORT_NS(REALTEK_DSA);
---- a/drivers/net/dsa/realtek/rtl83xx.c
-+++ b/drivers/net/dsa/realtek/rtl83xx.c
-@@ -232,5 +232,6 @@ void rtl83xx_remove(struct realtek_priv
- EXPORT_SYMBOL_NS_GPL(rtl83xx_remove, REALTEK_DSA);
-
- MODULE_DESCRIPTION("Realtek DSA switches common module");
- MODULE_LICENSE("GPL");
+++ /dev/null
-From 8685c98d45c54346caf005de69988e13c731c533 Mon Sep 17 00:00:00 2001
-Date: Fri, 9 Feb 2024 02:03:43 -0300
-Subject: net: dsa: realtek: get internal MDIO node by name
-
-The binding docs requires for SMI-connected devices that the switch
-must have a child node named "mdio" and with a compatible string of
-"realtek,smi-mdio". Meanwile, for MDIO-connected switches, the binding
-docs only requires a child node named "mdio".
-
-This patch changes the driver to use the common denominator for both
-interfaces, looking for the MDIO node by name, ignoring the compatible
-string.
-
----
- drivers/net/dsa/realtek/realtek-smi.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/net/dsa/realtek/realtek-smi.c
-+++ b/drivers/net/dsa/realtek/realtek-smi.c
-@@ -333,7 +333,7 @@ static int realtek_smi_setup_mdio(struct
- struct device_node *mdio_np;
- int ret;
-
-- mdio_np = of_get_compatible_child(priv->dev->of_node, "realtek,smi-mdio");
-+ mdio_np = of_get_child_by_name(priv->dev->of_node, "mdio");
- if (!mdio_np) {
- dev_err(priv->dev, "no MDIO bus node\n");
- return -ENODEV;
+++ /dev/null
-From 68c66d8d8a19088967a0ab6bb98cb5ecc80ca0be Mon Sep 17 00:00:00 2001
-Date: Fri, 9 Feb 2024 02:03:44 -0300
-Subject: net: dsa: realtek: clean slave_mii_bus setup
-
-Remove the line assigning dev.of_node in mdio_bus as subsequent
-of_mdiobus_register will always overwrite it.
-
-As discussed in [1], allow the DSA core to be simplified, by not
-assigning ds->slave_mii_bus when the MDIO bus is described in OF, as it
-is unnecessary.
-
-Since commit 3b73a7b8ec38 ("net: mdio_bus: add refcounting for fwnodes
-to mdiobus"), we can put the "mdio" node just after the MDIO bus
-registration.
-
-[1] https://lkml.kernel.org/netdev/20231213120656.x46fyad6ls7sqyzv@skbuf/T/#u
-
----
- drivers/net/dsa/realtek/realtek-smi.c | 13 +++----------
- 1 file changed, 3 insertions(+), 10 deletions(-)
-
---- a/drivers/net/dsa/realtek/realtek-smi.c
-+++ b/drivers/net/dsa/realtek/realtek-smi.c
-@@ -331,7 +331,7 @@ static int realtek_smi_setup_mdio(struct
- {
- struct realtek_priv *priv = ds->priv;
- struct device_node *mdio_np;
-- int ret;
-+ int ret = 0;
-
- mdio_np = of_get_child_by_name(priv->dev->of_node, "mdio");
- if (!mdio_np) {
-@@ -344,15 +344,14 @@ static int realtek_smi_setup_mdio(struct
- ret = -ENOMEM;
- goto err_put_node;
- }
-+
- priv->slave_mii_bus->priv = priv;
- priv->slave_mii_bus->name = "SMI slave MII";
- priv->slave_mii_bus->read = realtek_smi_mdio_read;
- priv->slave_mii_bus->write = realtek_smi_mdio_write;
- snprintf(priv->slave_mii_bus->id, MII_BUS_ID_SIZE, "SMI-%d",
- ds->index);
-- priv->slave_mii_bus->dev.of_node = mdio_np;
- priv->slave_mii_bus->parent = priv->dev;
-- ds->slave_mii_bus = priv->slave_mii_bus;
-
- ret = devm_of_mdiobus_register(priv->dev, priv->slave_mii_bus, mdio_np);
- if (ret) {
-@@ -361,8 +360,6 @@ static int realtek_smi_setup_mdio(struct
- goto err_put_node;
- }
-
-- return 0;
--
- err_put_node:
- of_node_put(mdio_np);
-
-@@ -428,8 +425,7 @@ EXPORT_SYMBOL_NS_GPL(realtek_smi_probe,
- * @pdev: platform_device to be removed.
- *
- * This function should be used as the .remove_new in a platform_driver. First
-- * it unregisters the DSA switch and cleans internal data. Finally, it calls
-- * the common remove function.
-+ * it unregisters the DSA switch and then it calls the common remove function.
- *
- * Context: Can sleep.
- * Return: Nothing.
-@@ -443,9 +439,6 @@ void realtek_smi_remove(struct platform_
-
- rtl83xx_unregister_switch(priv);
-
-- if (priv->slave_mii_bus)
-- of_node_put(priv->slave_mii_bus->dev.of_node);
--
- rtl83xx_remove(priv);
- }
- EXPORT_SYMBOL_NS_GPL(realtek_smi_remove, REALTEK_DSA);
+++ /dev/null
-From b4bd77971f3c290c4694ed710cc6967593b10bc2 Mon Sep 17 00:00:00 2001
-Date: Fri, 9 Feb 2024 02:03:45 -0300
-Subject: net: dsa: realtek: migrate slave_mii_bus setup to
- realtek_dsa
-
-In the user MDIO driver, despite numerous references to SMI, including
-its compatible string, there's nothing inherently specific about the SMI
-interface in the user MDIO bus. Consequently, the code has been migrated
-to the rtl83xx module. All references to SMI have been eliminated.
-
-The MDIO bus id was changed from Realtek-<switch id> to the switch
-devname suffixed with :slave_mii, giving more information about the bus
-it is referencing.
-
----
- drivers/net/dsa/realtek/realtek-smi.c | 57 +---------------------
- drivers/net/dsa/realtek/rtl83xx.c | 68 +++++++++++++++++++++++++++
- drivers/net/dsa/realtek/rtl83xx.h | 1 +
- 3 files changed, 70 insertions(+), 56 deletions(-)
-
---- a/drivers/net/dsa/realtek/realtek-smi.c
-+++ b/drivers/net/dsa/realtek/realtek-smi.c
-@@ -31,7 +31,6 @@
- #include <linux/spinlock.h>
- #include <linux/skbuff.h>
- #include <linux/of.h>
--#include <linux/of_mdio.h>
- #include <linux/delay.h>
- #include <linux/gpio/consumer.h>
- #include <linux/platform_device.h>
-@@ -312,60 +311,6 @@ static int realtek_smi_read(void *ctx, u
- return realtek_smi_read_reg(priv, reg, val);
- }
-
--static int realtek_smi_mdio_read(struct mii_bus *bus, int addr, int regnum)
--{
-- struct realtek_priv *priv = bus->priv;
--
-- return priv->ops->phy_read(priv, addr, regnum);
--}
--
--static int realtek_smi_mdio_write(struct mii_bus *bus, int addr, int regnum,
-- u16 val)
--{
-- struct realtek_priv *priv = bus->priv;
--
-- return priv->ops->phy_write(priv, addr, regnum, val);
--}
--
--static int realtek_smi_setup_mdio(struct dsa_switch *ds)
--{
-- struct realtek_priv *priv = ds->priv;
-- struct device_node *mdio_np;
-- int ret = 0;
--
-- mdio_np = of_get_child_by_name(priv->dev->of_node, "mdio");
-- if (!mdio_np) {
-- dev_err(priv->dev, "no MDIO bus node\n");
-- return -ENODEV;
-- }
--
-- priv->slave_mii_bus = devm_mdiobus_alloc(priv->dev);
-- if (!priv->slave_mii_bus) {
-- ret = -ENOMEM;
-- goto err_put_node;
-- }
--
-- priv->slave_mii_bus->priv = priv;
-- priv->slave_mii_bus->name = "SMI slave MII";
-- priv->slave_mii_bus->read = realtek_smi_mdio_read;
-- priv->slave_mii_bus->write = realtek_smi_mdio_write;
-- snprintf(priv->slave_mii_bus->id, MII_BUS_ID_SIZE, "SMI-%d",
-- ds->index);
-- priv->slave_mii_bus->parent = priv->dev;
--
-- ret = devm_of_mdiobus_register(priv->dev, priv->slave_mii_bus, mdio_np);
-- if (ret) {
-- dev_err(priv->dev, "unable to register MDIO bus %s\n",
-- priv->slave_mii_bus->id);
-- goto err_put_node;
-- }
--
--err_put_node:
-- of_node_put(mdio_np);
--
-- return ret;
--}
--
- static const struct realtek_interface_info realtek_smi_info = {
- .reg_read = realtek_smi_read,
- .reg_write = realtek_smi_write,
-@@ -407,7 +352,7 @@ int realtek_smi_probe(struct platform_de
- }
-
- priv->write_reg_noack = realtek_smi_write_reg_noack;
-- priv->setup_interface = realtek_smi_setup_mdio;
-+ priv->setup_interface = rtl83xx_setup_user_mdio;
- priv->ds_ops = priv->variant->ds_ops_smi;
-
- ret = rtl83xx_register_switch(priv);
---- a/drivers/net/dsa/realtek/rtl83xx.c
-+++ b/drivers/net/dsa/realtek/rtl83xx.c
-@@ -3,6 +3,7 @@
- #include <linux/module.h>
- #include <linux/regmap.h>
- #include <linux/of_device.h> /* krnl 6.1 only */
-+#include <linux/of_mdio.h>
-
- #include "realtek.h"
- #include "rtl83xx.h"
-@@ -44,6 +45,73 @@ void rtl83xx_unlock(void *ctx)
- }
- EXPORT_SYMBOL_NS_GPL(rtl83xx_unlock, REALTEK_DSA);
-
-+static int rtl83xx_user_mdio_read(struct mii_bus *bus, int addr, int regnum)
-+{
-+ struct realtek_priv *priv = bus->priv;
-+
-+ return priv->ops->phy_read(priv, addr, regnum);
-+}
-+
-+static int rtl83xx_user_mdio_write(struct mii_bus *bus, int addr, int regnum,
-+ u16 val)
-+{
-+ struct realtek_priv *priv = bus->priv;
-+
-+ return priv->ops->phy_write(priv, addr, regnum, val);
-+}
-+
-+/**
-+ * rtl83xx_setup_user_mdio() - register the user mii bus driver
-+ * @ds: DSA switch associated with this slave_mii_bus
-+ *
-+ * Registers the MDIO bus for built-in Ethernet PHYs, and associates it with
-+ * the mandatory 'mdio' child OF node of the switch.
-+ *
-+ * Context: Can sleep.
-+ * Return: 0 on success, negative value for failure.
-+ */
-+int rtl83xx_setup_user_mdio(struct dsa_switch *ds)
-+{
-+ struct realtek_priv *priv = ds->priv;
-+ struct device_node *mdio_np;
-+ struct mii_bus *bus;
-+ int ret = 0;
-+
-+ mdio_np = of_get_child_by_name(priv->dev->of_node, "mdio");
-+ if (!mdio_np) {
-+ dev_err(priv->dev, "no MDIO bus node\n");
-+ return -ENODEV;
-+ }
-+
-+ bus = devm_mdiobus_alloc(priv->dev);
-+ if (!bus) {
-+ ret = -ENOMEM;
-+ goto err_put_node;
-+ }
-+
-+ bus->priv = priv;
-+ bus->name = "Realtek user MII";
-+ bus->read = rtl83xx_user_mdio_read;
-+ bus->write = rtl83xx_user_mdio_write;
-+ snprintf(bus->id, MII_BUS_ID_SIZE, "%s:slave_mii", dev_name(priv->dev));
-+ bus->parent = priv->dev;
-+
-+ ret = devm_of_mdiobus_register(priv->dev, bus, mdio_np);
-+ if (ret) {
-+ dev_err(priv->dev, "unable to register MDIO bus %s\n",
-+ bus->id);
-+ goto err_put_node;
-+ }
-+
-+ priv->slave_mii_bus = bus;
-+
-+err_put_node:
-+ of_node_put(mdio_np);
-+
-+ return ret;
-+}
-+EXPORT_SYMBOL_NS_GPL(rtl83xx_setup_user_mdio, REALTEK_DSA);
-+
- /**
- * rtl83xx_probe() - probe a Realtek switch
- * @dev: the device being probed
---- a/drivers/net/dsa/realtek/rtl83xx.h
-+++ b/drivers/net/dsa/realtek/rtl83xx.h
-@@ -10,6 +10,7 @@ struct realtek_interface_info {
-
- void rtl83xx_lock(void *ctx);
- void rtl83xx_unlock(void *ctx);
-+int rtl83xx_setup_user_mdio(struct dsa_switch *ds);
- struct realtek_priv *
- rtl83xx_probe(struct device *dev,
- const struct realtek_interface_info *interface_info);
+++ /dev/null
-From bba140a566ed075304c49c52ab32c0016cab624a Mon Sep 17 00:00:00 2001
-Date: Fri, 9 Feb 2024 02:03:46 -0300
-Subject: net: dsa: realtek: use the same mii bus driver for
- both interfaces
-
-The realtek-mdio will now use this driver instead of the generic DSA
-driver ("dsa user smi"), which should not be used with OF[1].
-
-With a single ds_ops for both interfaces, the ds_ops in realtek_priv is
-no longer necessary. Now, the realtek_variant.ds_ops can be used
-directly.
-
-The realtek_priv.setup_interface() has been removed as we can directly
-call the new common function.
-
-
----
- drivers/net/dsa/realtek/realtek-mdio.c | 1 -
- drivers/net/dsa/realtek/realtek-smi.c | 2 -
- drivers/net/dsa/realtek/realtek.h | 5 +--
- drivers/net/dsa/realtek/rtl8365mb.c | 49 +++---------------------
- drivers/net/dsa/realtek/rtl8366rb.c | 52 +++-----------------------
- drivers/net/dsa/realtek/rtl83xx.c | 2 +-
- 6 files changed, 14 insertions(+), 97 deletions(-)
-
---- a/drivers/net/dsa/realtek/realtek-mdio.c
-+++ b/drivers/net/dsa/realtek/realtek-mdio.c
-@@ -131,7 +131,6 @@ int realtek_mdio_probe(struct mdio_devic
- priv->bus = mdiodev->bus;
- priv->mdio_addr = mdiodev->addr;
- priv->write_reg_noack = realtek_mdio_write;
-- priv->ds_ops = priv->variant->ds_ops_mdio;
-
- ret = rtl83xx_register_switch(priv);
- if (ret) {
---- a/drivers/net/dsa/realtek/realtek-smi.c
-+++ b/drivers/net/dsa/realtek/realtek-smi.c
-@@ -352,8 +352,6 @@ int realtek_smi_probe(struct platform_de
- }
-
- priv->write_reg_noack = realtek_smi_write_reg_noack;
-- priv->setup_interface = rtl83xx_setup_user_mdio;
-- priv->ds_ops = priv->variant->ds_ops_smi;
-
- ret = rtl83xx_register_switch(priv);
- if (ret) {
---- a/drivers/net/dsa/realtek/realtek.h
-+++ b/drivers/net/dsa/realtek/realtek.h
-@@ -62,7 +62,6 @@ struct realtek_priv {
-
- spinlock_t lock; /* Locks around command writes */
- struct dsa_switch *ds;
-- const struct dsa_switch_ops *ds_ops;
- struct irq_domain *irqdomain;
- bool leds_disabled;
-
-@@ -73,7 +72,6 @@ struct realtek_priv {
- struct rtl8366_mib_counter *mib_counters;
-
- const struct realtek_ops *ops;
-- int (*setup_interface)(struct dsa_switch *ds);
- int (*write_reg_noack)(void *ctx, u32 addr, u32 data);
-
- int vlan_enabled;
-@@ -115,8 +113,7 @@ struct realtek_ops {
- };
-
- struct realtek_variant {
-- const struct dsa_switch_ops *ds_ops_smi;
-- const struct dsa_switch_ops *ds_ops_mdio;
-+ const struct dsa_switch_ops *ds_ops;
- const struct realtek_ops *ops;
- unsigned int clk_delay;
- u8 cmd_read;
---- a/drivers/net/dsa/realtek/rtl8365mb.c
-+++ b/drivers/net/dsa/realtek/rtl8365mb.c
-@@ -828,17 +828,6 @@ static int rtl8365mb_phy_write(struct re
- return 0;
- }
-
--static int rtl8365mb_dsa_phy_read(struct dsa_switch *ds, int phy, int regnum)
--{
-- return rtl8365mb_phy_read(ds->priv, phy, regnum);
--}
--
--static int rtl8365mb_dsa_phy_write(struct dsa_switch *ds, int phy, int regnum,
-- u16 val)
--{
-- return rtl8365mb_phy_write(ds->priv, phy, regnum, val);
--}
--
- static const struct rtl8365mb_extint *
- rtl8365mb_get_port_extint(struct realtek_priv *priv, int port)
- {
-@@ -2018,12 +2007,10 @@ static int rtl8365mb_setup(struct dsa_sw
- if (ret)
- goto out_teardown_irq;
-
-- if (priv->setup_interface) {
-- ret = priv->setup_interface(ds);
-- if (ret) {
-- dev_err(priv->dev, "could not set up MDIO bus\n");
-- goto out_teardown_irq;
-- }
-+ ret = rtl83xx_setup_user_mdio(ds);
-+ if (ret) {
-+ dev_err(priv->dev, "could not set up MDIO bus\n");
-+ goto out_teardown_irq;
- }
-
- /* Start statistics counter polling */
-@@ -2117,28 +2104,7 @@ static int rtl8365mb_detect(struct realt
- return 0;
- }
-
--static const struct dsa_switch_ops rtl8365mb_switch_ops_smi = {
-- .get_tag_protocol = rtl8365mb_get_tag_protocol,
-- .change_tag_protocol = rtl8365mb_change_tag_protocol,
-- .setup = rtl8365mb_setup,
-- .teardown = rtl8365mb_teardown,
-- .phylink_get_caps = rtl8365mb_phylink_get_caps,
-- .phylink_mac_config = rtl8365mb_phylink_mac_config,
-- .phylink_mac_link_down = rtl8365mb_phylink_mac_link_down,
-- .phylink_mac_link_up = rtl8365mb_phylink_mac_link_up,
-- .port_stp_state_set = rtl8365mb_port_stp_state_set,
-- .get_strings = rtl8365mb_get_strings,
-- .get_ethtool_stats = rtl8365mb_get_ethtool_stats,
-- .get_sset_count = rtl8365mb_get_sset_count,
-- .get_eth_phy_stats = rtl8365mb_get_phy_stats,
-- .get_eth_mac_stats = rtl8365mb_get_mac_stats,
-- .get_eth_ctrl_stats = rtl8365mb_get_ctrl_stats,
-- .get_stats64 = rtl8365mb_get_stats64,
-- .port_change_mtu = rtl8365mb_port_change_mtu,
-- .port_max_mtu = rtl8365mb_port_max_mtu,
--};
--
--static const struct dsa_switch_ops rtl8365mb_switch_ops_mdio = {
-+static const struct dsa_switch_ops rtl8365mb_switch_ops = {
- .get_tag_protocol = rtl8365mb_get_tag_protocol,
- .change_tag_protocol = rtl8365mb_change_tag_protocol,
- .setup = rtl8365mb_setup,
-@@ -2147,8 +2113,6 @@ static const struct dsa_switch_ops rtl83
- .phylink_mac_config = rtl8365mb_phylink_mac_config,
- .phylink_mac_link_down = rtl8365mb_phylink_mac_link_down,
- .phylink_mac_link_up = rtl8365mb_phylink_mac_link_up,
-- .phy_read = rtl8365mb_dsa_phy_read,
-- .phy_write = rtl8365mb_dsa_phy_write,
- .port_stp_state_set = rtl8365mb_port_stp_state_set,
- .get_strings = rtl8365mb_get_strings,
- .get_ethtool_stats = rtl8365mb_get_ethtool_stats,
-@@ -2168,8 +2132,7 @@ static const struct realtek_ops rtl8365m
- };
-
- const struct realtek_variant rtl8365mb_variant = {
-- .ds_ops_smi = &rtl8365mb_switch_ops_smi,
-- .ds_ops_mdio = &rtl8365mb_switch_ops_mdio,
-+ .ds_ops = &rtl8365mb_switch_ops,
- .ops = &rtl8365mb_ops,
- .clk_delay = 10,
- .cmd_read = 0xb9,
---- a/drivers/net/dsa/realtek/rtl8366rb.c
-+++ b/drivers/net/dsa/realtek/rtl8366rb.c
-@@ -1035,12 +1035,10 @@ static int rtl8366rb_setup(struct dsa_sw
- if (ret)
- dev_info(priv->dev, "no interrupt support\n");
-
-- if (priv->setup_interface) {
-- ret = priv->setup_interface(ds);
-- if (ret) {
-- dev_err(priv->dev, "could not set up MDIO bus\n");
-- return -ENODEV;
-- }
-+ ret = rtl83xx_setup_user_mdio(ds);
-+ if (ret) {
-+ dev_err(priv->dev, "could not set up MDIO bus\n");
-+ return -ENODEV;
- }
-
- return 0;
-@@ -1699,17 +1697,6 @@ out:
- return ret;
- }
-
--static int rtl8366rb_dsa_phy_read(struct dsa_switch *ds, int phy, int regnum)
--{
-- return rtl8366rb_phy_read(ds->priv, phy, regnum);
--}
--
--static int rtl8366rb_dsa_phy_write(struct dsa_switch *ds, int phy, int regnum,
-- u16 val)
--{
-- return rtl8366rb_phy_write(ds->priv, phy, regnum, val);
--}
--
- static int rtl8366rb_reset_chip(struct realtek_priv *priv)
- {
- int timeout = 10;
-@@ -1775,35 +1762,9 @@ static int rtl8366rb_detect(struct realt
- return 0;
- }
-
--static const struct dsa_switch_ops rtl8366rb_switch_ops_smi = {
-- .get_tag_protocol = rtl8366_get_tag_protocol,
-- .setup = rtl8366rb_setup,
-- .phylink_get_caps = rtl8366rb_phylink_get_caps,
-- .phylink_mac_link_up = rtl8366rb_mac_link_up,
-- .phylink_mac_link_down = rtl8366rb_mac_link_down,
-- .get_strings = rtl8366_get_strings,
-- .get_ethtool_stats = rtl8366_get_ethtool_stats,
-- .get_sset_count = rtl8366_get_sset_count,
-- .port_bridge_join = rtl8366rb_port_bridge_join,
-- .port_bridge_leave = rtl8366rb_port_bridge_leave,
-- .port_vlan_filtering = rtl8366rb_vlan_filtering,
-- .port_vlan_add = rtl8366_vlan_add,
-- .port_vlan_del = rtl8366_vlan_del,
-- .port_enable = rtl8366rb_port_enable,
-- .port_disable = rtl8366rb_port_disable,
-- .port_pre_bridge_flags = rtl8366rb_port_pre_bridge_flags,
-- .port_bridge_flags = rtl8366rb_port_bridge_flags,
-- .port_stp_state_set = rtl8366rb_port_stp_state_set,
-- .port_fast_age = rtl8366rb_port_fast_age,
-- .port_change_mtu = rtl8366rb_change_mtu,
-- .port_max_mtu = rtl8366rb_max_mtu,
--};
--
--static const struct dsa_switch_ops rtl8366rb_switch_ops_mdio = {
-+static const struct dsa_switch_ops rtl8366rb_switch_ops = {
- .get_tag_protocol = rtl8366_get_tag_protocol,
- .setup = rtl8366rb_setup,
-- .phy_read = rtl8366rb_dsa_phy_read,
-- .phy_write = rtl8366rb_dsa_phy_write,
- .phylink_get_caps = rtl8366rb_phylink_get_caps,
- .phylink_mac_link_up = rtl8366rb_mac_link_up,
- .phylink_mac_link_down = rtl8366rb_mac_link_down,
-@@ -1842,8 +1803,7 @@ static const struct realtek_ops rtl8366r
- };
-
- const struct realtek_variant rtl8366rb_variant = {
-- .ds_ops_smi = &rtl8366rb_switch_ops_smi,
-- .ds_ops_mdio = &rtl8366rb_switch_ops_mdio,
-+ .ds_ops = &rtl8366rb_switch_ops,
- .ops = &rtl8366rb_ops,
- .clk_delay = 10,
- .cmd_read = 0xa9,
---- a/drivers/net/dsa/realtek/rtl83xx.c
-+++ b/drivers/net/dsa/realtek/rtl83xx.c
-@@ -233,7 +233,7 @@ int rtl83xx_register_switch(struct realt
-
- ds->priv = priv;
- ds->dev = priv->dev;
-- ds->ops = priv->ds_ops;
-+ ds->ops = priv->variant->ds_ops;
- ds->num_ports = priv->num_ports;
- priv->ds = ds;
-
+++ /dev/null
-From 9fc469b2943d9b1ff2a7800f823e7cd7a5cac0ca Mon Sep 17 00:00:00 2001
-Date: Fri, 9 Feb 2024 02:03:47 -0300
-Subject: net: dsa: realtek: embed dsa_switch into realtek_priv
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Embed dsa_switch within realtek_priv to eliminate the need for a second
-memory allocation.
-
----
- drivers/net/dsa/realtek/realtek.h | 2 +-
- drivers/net/dsa/realtek/rtl8365mb.c | 15 +++++++++------
- drivers/net/dsa/realtek/rtl8366rb.c | 3 ++-
- drivers/net/dsa/realtek/rtl83xx.c | 15 +++++++--------
- 4 files changed, 19 insertions(+), 16 deletions(-)
-
---- a/drivers/net/dsa/realtek/realtek.h
-+++ b/drivers/net/dsa/realtek/realtek.h
-@@ -61,7 +61,7 @@ struct realtek_priv {
- const struct realtek_variant *variant;
-
- spinlock_t lock; /* Locks around command writes */
-- struct dsa_switch *ds;
-+ struct dsa_switch ds;
- struct irq_domain *irqdomain;
- bool leds_disabled;
-
---- a/drivers/net/dsa/realtek/rtl8365mb.c
-+++ b/drivers/net/dsa/realtek/rtl8365mb.c
-@@ -870,6 +870,7 @@ static int rtl8365mb_ext_config_rgmii(st
- {
- const struct rtl8365mb_extint *extint =
- rtl8365mb_get_port_extint(priv, port);
-+ struct dsa_switch *ds = &priv->ds;
- struct device_node *dn;
- struct dsa_port *dp;
- int tx_delay = 0;
-@@ -880,7 +881,7 @@ static int rtl8365mb_ext_config_rgmii(st
- if (!extint)
- return -ENODEV;
-
-- dp = dsa_to_port(priv->ds, port);
-+ dp = dsa_to_port(ds, port);
- dn = dp->dn;
-
- /* Set the RGMII TX/RX delay
-@@ -1534,6 +1535,7 @@ static void rtl8365mb_get_stats64(struct
- static void rtl8365mb_stats_setup(struct realtek_priv *priv)
- {
- struct rtl8365mb *mb = priv->chip_data;
-+ struct dsa_switch *ds = &priv->ds;
- int i;
-
- /* Per-chip global mutex to protect MIB counter access, since doing
-@@ -1544,7 +1546,7 @@ static void rtl8365mb_stats_setup(struct
- for (i = 0; i < priv->num_ports; i++) {
- struct rtl8365mb_port *p = &mb->ports[i];
-
-- if (dsa_is_unused_port(priv->ds, i))
-+ if (dsa_is_unused_port(ds, i))
- continue;
-
- /* Per-port spinlock to protect the stats64 data */
-@@ -1560,12 +1562,13 @@ static void rtl8365mb_stats_setup(struct
- static void rtl8365mb_stats_teardown(struct realtek_priv *priv)
- {
- struct rtl8365mb *mb = priv->chip_data;
-+ struct dsa_switch *ds = &priv->ds;
- int i;
-
- for (i = 0; i < priv->num_ports; i++) {
- struct rtl8365mb_port *p = &mb->ports[i];
-
-- if (dsa_is_unused_port(priv->ds, i))
-+ if (dsa_is_unused_port(ds, i))
- continue;
-
- cancel_delayed_work_sync(&p->mib_work);
-@@ -1964,7 +1967,7 @@ static int rtl8365mb_setup(struct dsa_sw
- dev_info(priv->dev, "no interrupt support\n");
-
- /* Configure CPU tagging */
-- dsa_switch_for_each_cpu_port(cpu_dp, priv->ds) {
-+ dsa_switch_for_each_cpu_port(cpu_dp, ds) {
- cpu->mask |= BIT(cpu_dp->index);
-
- if (cpu->trap_port == RTL8365MB_MAX_NUM_PORTS)
-@@ -1979,7 +1982,7 @@ static int rtl8365mb_setup(struct dsa_sw
- for (i = 0; i < priv->num_ports; i++) {
- struct rtl8365mb_port *p = &mb->ports[i];
-
-- if (dsa_is_unused_port(priv->ds, i))
-+ if (dsa_is_unused_port(ds, i))
- continue;
-
- /* Forward only to the CPU */
-@@ -1996,7 +1999,7 @@ static int rtl8365mb_setup(struct dsa_sw
- * ports will still forward frames to the CPU despite being
- * administratively down by default.
- */
-- rtl8365mb_port_stp_state_set(priv->ds, i, BR_STATE_DISABLED);
-+ rtl8365mb_port_stp_state_set(ds, i, BR_STATE_DISABLED);
-
- /* Set up per-port private data */
- p->priv = priv;
---- a/drivers/net/dsa/realtek/rtl8366rb.c
-+++ b/drivers/net/dsa/realtek/rtl8366rb.c
-@@ -1565,6 +1565,7 @@ static int rtl8366rb_get_mc_index(struct
-
- static int rtl8366rb_set_mc_index(struct realtek_priv *priv, int port, int index)
- {
-+ struct dsa_switch *ds = &priv->ds;
- struct rtl8366rb *rb;
- bool pvid_enabled;
- int ret;
-@@ -1589,7 +1590,7 @@ static int rtl8366rb_set_mc_index(struct
- * not drop any untagged or C-tagged frames. Make sure to update the
- * filtering setting.
- */
-- if (dsa_port_is_vlan_filtering(dsa_to_port(priv->ds, port)))
-+ if (dsa_port_is_vlan_filtering(dsa_to_port(ds, port)))
- ret = rtl8366rb_drop_untagged(priv, port, !pvid_enabled);
-
- return ret;
---- a/drivers/net/dsa/realtek/rtl83xx.c
-+++ b/drivers/net/dsa/realtek/rtl83xx.c
-@@ -218,7 +218,7 @@ EXPORT_SYMBOL_NS_GPL(rtl83xx_probe, REAL
- */
- int rtl83xx_register_switch(struct realtek_priv *priv)
- {
-- struct dsa_switch *ds;
-+ struct dsa_switch *ds = &priv->ds;
- int ret;
-
- ret = priv->ops->detect(priv);
-@@ -227,15 +227,10 @@ int rtl83xx_register_switch(struct realt
- return ret;
- }
-
-- ds = devm_kzalloc(priv->dev, sizeof(*ds), GFP_KERNEL);
-- if (!ds)
-- return -ENOMEM;
--
- ds->priv = priv;
- ds->dev = priv->dev;
- ds->ops = priv->variant->ds_ops;
- ds->num_ports = priv->num_ports;
-- priv->ds = ds;
-
- ret = dsa_register_switch(ds);
- if (ret) {
-@@ -258,7 +253,9 @@ EXPORT_SYMBOL_NS_GPL(rtl83xx_register_sw
- */
- void rtl83xx_unregister_switch(struct realtek_priv *priv)
- {
-- dsa_unregister_switch(priv->ds);
-+ struct dsa_switch *ds = &priv->ds;
-+
-+ dsa_unregister_switch(ds);
- }
- EXPORT_SYMBOL_NS_GPL(rtl83xx_unregister_switch, REALTEK_DSA);
-
-@@ -275,7 +272,9 @@ EXPORT_SYMBOL_NS_GPL(rtl83xx_unregister_
- */
- void rtl83xx_shutdown(struct realtek_priv *priv)
- {
-- dsa_switch_shutdown(priv->ds);
-+ struct dsa_switch *ds = &priv->ds;
-+
-+ dsa_switch_shutdown(ds);
-
- dev_set_drvdata(priv->dev, NULL);
- }
+++ /dev/null
-From f058b2dd70b1a5503dff899010aeb53b436091e5 Mon Sep 17 00:00:00 2001
-Date: Wed, 28 Feb 2024 18:24:09 +0100
-Subject: [PATCH 1/2] net: phy: qcom: qca808x: add helper for checking for 1G
- only model
-
-There are 2 versions of QCA808x, one 2.5G capable and one 1G capable.
-Currently, this matter only in the .get_features call however, it will
-be required for filling supported interface modes so lets add a helper
-that can be reused.
-
----
- drivers/net/phy/qcom/qca808x.c | 17 ++++++++++++-----
- 1 file changed, 12 insertions(+), 5 deletions(-)
-
---- a/drivers/net/phy/qcom/qca808x.c
-+++ b/drivers/net/phy/qcom/qca808x.c
-@@ -156,6 +156,17 @@ static bool qca808x_has_fast_retrain_or_
- return linkmode_test_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, phydev->supported);
- }
-
-+static bool qca808x_is_1g_only(struct phy_device *phydev)
-+{
-+ int ret;
-+
-+ ret = phy_read_mmd(phydev, MDIO_MMD_AN, QCA808X_PHY_MMD7_CHIP_TYPE);
-+ if (ret < 0)
-+ return true;
-+
-+ return !!(QCA808X_PHY_CHIP_TYPE_1G & ret);
-+}
-+
- static int qca808x_probe(struct phy_device *phydev)
- {
- struct device *dev = &phydev->mdio.dev;
-@@ -350,11 +361,7 @@ static int qca808x_get_features(struct p
- * existed in the bit0 of MMD1.21, we need to remove it manually if
- * it is the qca8081 1G chip according to the bit0 of MMD7.0x901d.
- */
-- ret = phy_read_mmd(phydev, MDIO_MMD_AN, QCA808X_PHY_MMD7_CHIP_TYPE);
-- if (ret < 0)
-- return ret;
--
-- if (QCA808X_PHY_CHIP_TYPE_1G & ret)
-+ if (qca808x_is_1g_only(phydev))
- linkmode_clear_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, phydev->supported);
-
- return 0;
+++ /dev/null
-From cb28f702960695e26597c332b0e46776e825cc34 Mon Sep 17 00:00:00 2001
-Date: Wed, 28 Feb 2024 18:24:10 +0100
-Subject: [PATCH 2/2] net: phy: qcom: qca808x: fill in possible_interfaces
-
-Currently QCA808x driver does not fill the possible_interfaces.
-2.5G QCA808x support SGMII and 2500Base-X while 1G model only supports
-SGMII, so fill the possible_interfaces accordingly.
-
----
- drivers/net/phy/qcom/qca808x.c | 12 ++++++++++++
- 1 file changed, 12 insertions(+)
-
---- a/drivers/net/phy/qcom/qca808x.c
-+++ b/drivers/net/phy/qcom/qca808x.c
-@@ -167,6 +167,16 @@ static bool qca808x_is_1g_only(struct ph
- return !!(QCA808X_PHY_CHIP_TYPE_1G & ret);
- }
-
-+static void qca808x_fill_possible_interfaces(struct phy_device *phydev)
-+{
-+ unsigned long *possible = phydev->possible_interfaces;
-+
-+ __set_bit(PHY_INTERFACE_MODE_SGMII, possible);
-+
-+ if (!qca808x_is_1g_only(phydev))
-+ __set_bit(PHY_INTERFACE_MODE_2500BASEX, possible);
-+}
-+
- static int qca808x_probe(struct phy_device *phydev)
- {
- struct device *dev = &phydev->mdio.dev;
-@@ -231,6 +241,8 @@ static int qca808x_config_init(struct ph
- }
- }
-
-+ qca808x_fill_possible_interfaces(phydev);
-+
- /* Configure adc threshold as 100mv for the link 10M */
- return at803x_debug_reg_mask(phydev, QCA808X_PHY_DEBUG_ADC_THRESHOLD,
- QCA808X_ADC_THRESHOLD_MASK,
+++ /dev/null
-From 32e4a5447ed9fa904a2dfcf4609c64bce053b4e8 Mon Sep 17 00:00:00 2001
-Date: Mon, 12 Feb 2024 18:34:33 -0300
-Subject: [PATCH] net: dsa: realtek: fix digital interface select macro for
- EXT0
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-While no supported devices currently utilize EXT0, the register reserves
-the bits for an EXT0. EXT0 is utilized by devices from the generation
-prior to rtl8365mb, such as those supported by the driver library
-rtl8367b.
-
----
- drivers/net/dsa/realtek/rtl8365mb.c | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
---- a/drivers/net/dsa/realtek/rtl8365mb.c
-+++ b/drivers/net/dsa/realtek/rtl8365mb.c
-@@ -209,10 +209,10 @@
- #define RTL8365MB_EXT_PORT_MODE_100FX 13
-
- /* External interface mode configuration registers 0~1 */
--#define RTL8365MB_DIGITAL_INTERFACE_SELECT_REG0 0x1305 /* EXT1 */
-+#define RTL8365MB_DIGITAL_INTERFACE_SELECT_REG0 0x1305 /* EXT0,EXT1 */
- #define RTL8365MB_DIGITAL_INTERFACE_SELECT_REG1 0x13C3 /* EXT2 */
- #define RTL8365MB_DIGITAL_INTERFACE_SELECT_REG(_extint) \
-- ((_extint) == 1 ? RTL8365MB_DIGITAL_INTERFACE_SELECT_REG0 : \
-+ ((_extint) <= 1 ? RTL8365MB_DIGITAL_INTERFACE_SELECT_REG0 : \
- (_extint) == 2 ? RTL8365MB_DIGITAL_INTERFACE_SELECT_REG1 : \
- 0x0)
- #define RTL8365MB_DIGITAL_INTERFACE_SELECT_MODE_MASK(_extint) \
+++ /dev/null
-From 6a804fb72de56d6a99b799f565ae45f2cec7cd55 Mon Sep 17 00:00:00 2001
-Date: Thu, 12 Oct 2023 12:11:34 +0530
-Subject: mtd: spinand: winbond: add support for serial NAND flash
-
-Add support for W25N01JW, W25N02JWZEIF, W25N512GW,
-W25N02KWZEIR and W25N01GWZEIG.
-
-W25N02KWZEIR has 8b/512b on-die ECC capability and other
-four has 4b/512b on-die ECC capability.
-
----
- drivers/mtd/nand/spi/winbond.c | 45 ++++++++++++++++++++++++++++++++++++++++++
- 1 file changed, 45 insertions(+)
-
-(limited to 'drivers/mtd/nand/spi/winbond.c')
-
---- a/drivers/mtd/nand/spi/winbond.c
-+++ b/drivers/mtd/nand/spi/winbond.c
-@@ -195,6 +195,51 @@ static const struct spinand_info winbond
- &update_cache_variants),
- 0,
- SPINAND_ECCINFO(&w25n02kv_ooblayout, w25n02kv_ecc_get_status)),
-+ SPINAND_INFO("W25N01JW",
-+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xbc, 0x21),
-+ NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
-+ NAND_ECCREQ(4, 512),
-+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
-+ &write_cache_variants,
-+ &update_cache_variants),
-+ 0,
-+ SPINAND_ECCINFO(&w25m02gv_ooblayout, w25n02kv_ecc_get_status)),
-+ SPINAND_INFO("W25N02JWZEIF",
-+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xbf, 0x22),
-+ NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 2, 1),
-+ NAND_ECCREQ(4, 512),
-+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
-+ &write_cache_variants,
-+ &update_cache_variants),
-+ 0,
-+ SPINAND_ECCINFO(&w25n02kv_ooblayout, w25n02kv_ecc_get_status)),
-+ SPINAND_INFO("W25N512GW",
-+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xba, 0x20),
-+ NAND_MEMORG(1, 2048, 64, 64, 512, 10, 1, 1, 1),
-+ NAND_ECCREQ(4, 512),
-+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
-+ &write_cache_variants,
-+ &update_cache_variants),
-+ 0,
-+ SPINAND_ECCINFO(&w25n02kv_ooblayout, w25n02kv_ecc_get_status)),
-+ SPINAND_INFO("W25N02KWZEIR",
-+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xba, 0x22),
-+ NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),
-+ NAND_ECCREQ(8, 512),
-+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
-+ &write_cache_variants,
-+ &update_cache_variants),
-+ 0,
-+ SPINAND_ECCINFO(&w25n02kv_ooblayout, w25n02kv_ecc_get_status)),
-+ SPINAND_INFO("W25N01GWZEIG",
-+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xba, 0x21),
-+ NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
-+ NAND_ECCREQ(4, 512),
-+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
-+ &write_cache_variants,
-+ &update_cache_variants),
-+ 0,
-+ SPINAND_ECCINFO(&w25m02gv_ooblayout, w25n02kv_ecc_get_status)),
- };
-
- static int winbond_spinand_init(struct spinand_device *spinand)
+++ /dev/null
-From 28001bb1955fcfa63e535848c4289fcd7bb88daf Mon Sep 17 00:00:00 2001
-Date: Sun, 25 Feb 2024 13:29:53 -0300
-Subject: [PATCH 1/3] dt-bindings: net: dsa: realtek: reset-gpios is not
- required
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-The 'reset-gpios' should not be mandatory. although they might be
-required for some devices if the switch reset was left asserted by a
-previous driver, such as the bootloader.
-
----
- Documentation/devicetree/bindings/net/dsa/realtek.yaml | 1 -
- 1 file changed, 1 deletion(-)
-
---- a/Documentation/devicetree/bindings/net/dsa/realtek.yaml
-+++ b/Documentation/devicetree/bindings/net/dsa/realtek.yaml
-@@ -125,7 +125,6 @@ else:
- - mdc-gpios
- - mdio-gpios
- - mdio
-- - reset-gpios
-
- required:
- - compatible
+++ /dev/null
-From 5fc2d68fc81801162188995e4d3dc0b26747dd76 Mon Sep 17 00:00:00 2001
-Date: Sun, 25 Feb 2024 13:29:54 -0300
-Subject: [PATCH 2/3] dt-bindings: net: dsa: realtek: add reset controller
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Realtek switches can use a reset controller instead of reset-gpios.
-
----
- Documentation/devicetree/bindings/net/dsa/realtek.yaml | 3 +++
- 1 file changed, 3 insertions(+)
-
---- a/Documentation/devicetree/bindings/net/dsa/realtek.yaml
-+++ b/Documentation/devicetree/bindings/net/dsa/realtek.yaml
-@@ -59,6 +59,9 @@ properties:
- description: GPIO to be used to reset the whole device
- maxItems: 1
-
-+ resets:
-+ maxItems: 1
-+
- realtek,disable-leds:
- type: boolean
- description: |
+++ /dev/null
-From 56998aa6b7f0f31ce8df23c00701af2d8e8a1f1a Mon Sep 17 00:00:00 2001
-Date: Sun, 25 Feb 2024 13:29:55 -0300
-Subject: [PATCH 3/3] net: dsa: realtek: support reset controller
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Add support for resetting the device using a reset controller,
-complementing the existing GPIO reset functionality (reset-gpios).
-
-Although the reset is optional and the driver performs a soft reset
-during setup, if the initial reset pin state was asserted, the driver
-will not detect the device until the reset is deasserted.
-
----
- drivers/net/dsa/realtek/realtek.h | 2 ++
- drivers/net/dsa/realtek/rtl83xx.c | 42 +++++++++++++++++++++++++++----
- drivers/net/dsa/realtek/rtl83xx.h | 2 ++
- 3 files changed, 41 insertions(+), 5 deletions(-)
-
---- a/drivers/net/dsa/realtek/realtek.h
-+++ b/drivers/net/dsa/realtek/realtek.h
-@@ -12,6 +12,7 @@
- #include <linux/platform_device.h>
- #include <linux/gpio/consumer.h>
- #include <net/dsa.h>
-+#include <linux/reset.h>
-
- #define REALTEK_HW_STOP_DELAY 25 /* msecs */
- #define REALTEK_HW_START_DELAY 100 /* msecs */
-@@ -48,6 +49,7 @@ struct rtl8366_vlan_4k {
-
- struct realtek_priv {
- struct device *dev;
-+ struct reset_control *reset_ctl;
- struct gpio_desc *reset;
- struct gpio_desc *mdc;
- struct gpio_desc *mdio;
---- a/drivers/net/dsa/realtek/rtl83xx.c
-+++ b/drivers/net/dsa/realtek/rtl83xx.c
-@@ -185,6 +185,13 @@ rtl83xx_probe(struct device *dev,
- "realtek,disable-leds");
-
- /* TODO: if power is software controlled, set up any regulators here */
-+ priv->reset_ctl = devm_reset_control_get_optional(dev, NULL);
-+ if (IS_ERR(priv->reset_ctl)) {
-+ ret = PTR_ERR(priv->reset_ctl);
-+ dev_err_probe(dev, ret, "failed to get reset control\n");
-+ return ERR_CAST(priv->reset_ctl);
-+ }
-+
- priv->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
- if (IS_ERR(priv->reset)) {
- dev_err(dev, "failed to get RESET GPIO\n");
-@@ -193,11 +200,11 @@ rtl83xx_probe(struct device *dev,
-
- dev_set_drvdata(dev, priv);
-
-- if (priv->reset) {
-- gpiod_set_value(priv->reset, 1);
-+ if (priv->reset_ctl || priv->reset) {
-+ rtl83xx_reset_assert(priv);
- dev_dbg(dev, "asserted RESET\n");
- msleep(REALTEK_HW_STOP_DELAY);
-- gpiod_set_value(priv->reset, 0);
-+ rtl83xx_reset_deassert(priv);
- msleep(REALTEK_HW_START_DELAY);
- dev_dbg(dev, "deasserted RESET\n");
- }
-@@ -293,11 +300,36 @@ EXPORT_SYMBOL_NS_GPL(rtl83xx_shutdown, R
- void rtl83xx_remove(struct realtek_priv *priv)
- {
- /* leave the device reset asserted */
-- if (priv->reset)
-- gpiod_set_value(priv->reset, 1);
-+ rtl83xx_reset_assert(priv);
- }
- EXPORT_SYMBOL_NS_GPL(rtl83xx_remove, REALTEK_DSA);
-
-+void rtl83xx_reset_assert(struct realtek_priv *priv)
-+{
-+ int ret;
-+
-+ ret = reset_control_assert(priv->reset_ctl);
-+ if (ret)
-+ dev_warn(priv->dev,
-+ "Failed to assert the switch reset control: %pe\n",
-+ ERR_PTR(ret));
-+
-+ gpiod_set_value(priv->reset, true);
-+}
-+
-+void rtl83xx_reset_deassert(struct realtek_priv *priv)
-+{
-+ int ret;
-+
-+ ret = reset_control_deassert(priv->reset_ctl);
-+ if (ret)
-+ dev_warn(priv->dev,
-+ "Failed to deassert the switch reset control: %pe\n",
-+ ERR_PTR(ret));
-+
-+ gpiod_set_value(priv->reset, false);
-+}
-+
- MODULE_DESCRIPTION("Realtek DSA switches common module");
---- a/drivers/net/dsa/realtek/rtl83xx.h
-+++ b/drivers/net/dsa/realtek/rtl83xx.h
-@@ -18,5 +18,7 @@ int rtl83xx_register_switch(struct realt
- void rtl83xx_unregister_switch(struct realtek_priv *priv);
- void rtl83xx_shutdown(struct realtek_priv *priv);
- void rtl83xx_remove(struct realtek_priv *priv);
-+void rtl83xx_reset_assert(struct realtek_priv *priv);
-+void rtl83xx_reset_deassert(struct realtek_priv *priv);
-
- #endif /* _RTL83XX_H */
+++ /dev/null
-From 4f580e9aced1816398c1c64f178302a22b8ea6e2 Mon Sep 17 00:00:00 2001
-Date: Sat, 27 Apr 2024 02:11:29 -0300
-Subject: [PATCH 2/3] net: dsa: realtek: do not assert reset on remove
-
-The necessity of asserting the reset on removal was previously
-questioned, as DSA's own cleanup methods should suffice to prevent
-traffic leakage[1].
-
-When a driver has subdrivers controlled by devres, they will be
-unregistered after the main driver's .remove is executed. If it asserts
-a reset, the subdrivers will be unable to communicate with the hardware
-during their cleanup. For LEDs, this means that they will fail to turn
-off, resulting in a timeout error.
-
-
----
- drivers/net/dsa/realtek/rtl83xx.c | 7 ++-----
- 1 file changed, 2 insertions(+), 5 deletions(-)
-
---- a/drivers/net/dsa/realtek/rtl83xx.c
-+++ b/drivers/net/dsa/realtek/rtl83xx.c
-@@ -291,16 +291,13 @@ EXPORT_SYMBOL_NS_GPL(rtl83xx_shutdown, R
- * rtl83xx_remove() - Cleanup a realtek switch driver
- * @priv: realtek_priv pointer
- *
-- * If a method is provided, this function asserts the hard reset of the switch
-- * in order to avoid leaking traffic when the driver is gone.
-+ * Placehold for common cleanup procedures.
- *
-- * Context: Might sleep if priv->gdev->chip->can_sleep.
-+ * Context: Any
- * Return: nothing
- */
- void rtl83xx_remove(struct realtek_priv *priv)
- {
-- /* leave the device reset asserted */
-- rtl83xx_reset_assert(priv);
- }
- EXPORT_SYMBOL_NS_GPL(rtl83xx_remove, REALTEK_DSA);
-
+++ /dev/null
-From 32d617005475a71ebcc4ec8b2791e8d1481e9a10 Mon Sep 17 00:00:00 2001
-Date: Sat, 27 Apr 2024 02:11:30 -0300
-Subject: [PATCH 3/3] net: dsa: realtek: add LED drivers for rtl8366rb
-
-This commit introduces LED drivers for rtl8366rb, enabling LEDs to be
-described in the device tree using the same format as qca8k. Each port
-can configure up to 4 LEDs.
-
-If all LEDs in a group use the default state "keep", they will use the
-default behavior after a reset. Changing the brightness of one LED,
-either manually or by a trigger, will disable the default hardware
-trigger and switch the entire LED group to manually controlled LEDs.
-Once in this mode, there is no way to revert to hardware-controlled LEDs
-(except by resetting the switch).
-
-Software triggers function as expected with manually controlled LEDs.
-
----
- drivers/net/dsa/realtek/rtl8366rb.c | 304 ++++++++++++++++++++++++----
- 1 file changed, 265 insertions(+), 39 deletions(-)
-
---- a/drivers/net/dsa/realtek/rtl8366rb.c
-+++ b/drivers/net/dsa/realtek/rtl8366rb.c
-@@ -180,6 +180,7 @@
- #define RTL8366RB_VLAN_INGRESS_CTRL2_REG 0x037f
-
- /* LED control registers */
-+/* The LED blink rate is global; it is used by all triggers in all groups. */
- #define RTL8366RB_LED_BLINKRATE_REG 0x0430
- #define RTL8366RB_LED_BLINKRATE_MASK 0x0007
- #define RTL8366RB_LED_BLINKRATE_28MS 0x0000
-@@ -195,31 +196,21 @@
- (4 * (led_group))
- #define RTL8366RB_LED_CTRL_MASK(led_group) \
- (0xf << RTL8366RB_LED_CTRL_OFFSET(led_group))
--#define RTL8366RB_LED_OFF 0x0
--#define RTL8366RB_LED_DUP_COL 0x1
--#define RTL8366RB_LED_LINK_ACT 0x2
--#define RTL8366RB_LED_SPD1000 0x3
--#define RTL8366RB_LED_SPD100 0x4
--#define RTL8366RB_LED_SPD10 0x5
--#define RTL8366RB_LED_SPD1000_ACT 0x6
--#define RTL8366RB_LED_SPD100_ACT 0x7
--#define RTL8366RB_LED_SPD10_ACT 0x8
--#define RTL8366RB_LED_SPD100_10_ACT 0x9
--#define RTL8366RB_LED_FIBER 0xa
--#define RTL8366RB_LED_AN_FAULT 0xb
--#define RTL8366RB_LED_LINK_RX 0xc
--#define RTL8366RB_LED_LINK_TX 0xd
--#define RTL8366RB_LED_MASTER 0xe
--#define RTL8366RB_LED_FORCE 0xf
-
- /* The RTL8366RB_LED_X_X registers are used to manually set the LED state only
- * when the corresponding LED group in RTL8366RB_LED_CTRL_REG is
-- * RTL8366RB_LED_FORCE. Otherwise, it is ignored.
-+ * RTL8366RB_LEDGROUP_FORCE. Otherwise, it is ignored.
- */
- #define RTL8366RB_LED_0_1_CTRL_REG 0x0432
--#define RTL8366RB_LED_1_OFFSET 6
- #define RTL8366RB_LED_2_3_CTRL_REG 0x0433
--#define RTL8366RB_LED_3_OFFSET 6
-+#define RTL8366RB_LED_X_X_CTRL_REG(led_group) \
-+ ((led_group) <= 1 ? \
-+ RTL8366RB_LED_0_1_CTRL_REG : \
-+ RTL8366RB_LED_2_3_CTRL_REG)
-+#define RTL8366RB_LED_0_X_CTRL_MASK GENMASK(5, 0)
-+#define RTL8366RB_LED_X_1_CTRL_MASK GENMASK(11, 6)
-+#define RTL8366RB_LED_2_X_CTRL_MASK GENMASK(5, 0)
-+#define RTL8366RB_LED_X_3_CTRL_MASK GENMASK(11, 6)
-
- #define RTL8366RB_MIB_COUNT 33
- #define RTL8366RB_GLOBAL_MIB_COUNT 1
-@@ -363,14 +354,44 @@
- #define RTL8366RB_GREEN_FEATURE_TX BIT(0)
- #define RTL8366RB_GREEN_FEATURE_RX BIT(2)
-
-+enum rtl8366_ledgroup_mode {
-+ RTL8366RB_LEDGROUP_OFF = 0x0,
-+ RTL8366RB_LEDGROUP_DUP_COL = 0x1,
-+ RTL8366RB_LEDGROUP_LINK_ACT = 0x2,
-+ RTL8366RB_LEDGROUP_SPD1000 = 0x3,
-+ RTL8366RB_LEDGROUP_SPD100 = 0x4,
-+ RTL8366RB_LEDGROUP_SPD10 = 0x5,
-+ RTL8366RB_LEDGROUP_SPD1000_ACT = 0x6,
-+ RTL8366RB_LEDGROUP_SPD100_ACT = 0x7,
-+ RTL8366RB_LEDGROUP_SPD10_ACT = 0x8,
-+ RTL8366RB_LEDGROUP_SPD100_10_ACT = 0x9,
-+ RTL8366RB_LEDGROUP_FIBER = 0xa,
-+ RTL8366RB_LEDGROUP_AN_FAULT = 0xb,
-+ RTL8366RB_LEDGROUP_LINK_RX = 0xc,
-+ RTL8366RB_LEDGROUP_LINK_TX = 0xd,
-+ RTL8366RB_LEDGROUP_MASTER = 0xe,
-+ RTL8366RB_LEDGROUP_FORCE = 0xf,
-+
-+ __RTL8366RB_LEDGROUP_MODE_MAX
-+};
-+
-+struct rtl8366rb_led {
-+ u8 port_num;
-+ u8 led_group;
-+ struct realtek_priv *priv;
-+ struct led_classdev cdev;
-+};
-+
- /**
- * struct rtl8366rb - RTL8366RB-specific data
- * @max_mtu: per-port max MTU setting
- * @pvid_enabled: if PVID is set for respective port
-+ * @leds: per-port and per-ledgroup led info
- */
- struct rtl8366rb {
- unsigned int max_mtu[RTL8366RB_NUM_PORTS];
- bool pvid_enabled[RTL8366RB_NUM_PORTS];
-+ struct rtl8366rb_led leds[RTL8366RB_NUM_PORTS][RTL8366RB_NUM_LEDGROUPS];
- };
-
- static struct rtl8366_mib_counter rtl8366rb_mib_counters[] = {
-@@ -813,6 +834,217 @@ static int rtl8366rb_jam_table(const str
- return 0;
- }
-
-+static int rb8366rb_set_ledgroup_mode(struct realtek_priv *priv,
-+ u8 led_group,
-+ enum rtl8366_ledgroup_mode mode)
-+{
-+ int ret;
-+ u32 val;
-+
-+ val = mode << RTL8366RB_LED_CTRL_OFFSET(led_group);
-+
-+ ret = regmap_update_bits(priv->map,
-+ RTL8366RB_LED_CTRL_REG,
-+ RTL8366RB_LED_CTRL_MASK(led_group),
-+ val);
-+ if (ret)
-+ return ret;
-+
-+ return 0;
-+}
-+
-+static inline u32 rtl8366rb_led_group_port_mask(u8 led_group, u8 port)
-+{
-+ switch (led_group) {
-+ case 0:
-+ return FIELD_PREP(RTL8366RB_LED_0_X_CTRL_MASK, BIT(port));
-+ case 1:
-+ return FIELD_PREP(RTL8366RB_LED_0_X_CTRL_MASK, BIT(port));
-+ case 2:
-+ return FIELD_PREP(RTL8366RB_LED_0_X_CTRL_MASK, BIT(port));
-+ case 3:
-+ return FIELD_PREP(RTL8366RB_LED_0_X_CTRL_MASK, BIT(port));
-+ default:
-+ return 0;
-+ }
-+}
-+
-+static int rb8366rb_get_port_led(struct rtl8366rb_led *led)
-+{
-+ struct realtek_priv *priv = led->priv;
-+ u8 led_group = led->led_group;
-+ u8 port_num = led->port_num;
-+ int ret;
-+ u32 val;
-+
-+ ret = regmap_read(priv->map, RTL8366RB_LED_X_X_CTRL_REG(led_group),
-+ &val);
-+ if (ret) {
-+ dev_err(priv->dev, "error reading LED on port %d group %d\n",
-+ led_group, port_num);
-+ return ret;
-+ }
-+
-+ return !!(val & rtl8366rb_led_group_port_mask(led_group, port_num));
-+}
-+
-+static int rb8366rb_set_port_led(struct rtl8366rb_led *led, bool enable)
-+{
-+ struct realtek_priv *priv = led->priv;
-+ u8 led_group = led->led_group;
-+ u8 port_num = led->port_num;
-+ int ret;
-+
-+ ret = regmap_update_bits(priv->map,
-+ RTL8366RB_LED_X_X_CTRL_REG(led_group),
-+ rtl8366rb_led_group_port_mask(led_group,
-+ port_num),
-+ enable ? 0xffff : 0);
-+ if (ret) {
-+ dev_err(priv->dev, "error updating LED on port %d group %d\n",
-+ led_group, port_num);
-+ return ret;
-+ }
-+
-+ /* Change the LED group to manual controlled LEDs if required */
-+ ret = rb8366rb_set_ledgroup_mode(priv, led_group,
-+ RTL8366RB_LEDGROUP_FORCE);
-+
-+ if (ret) {
-+ dev_err(priv->dev, "error updating LED GROUP group %d\n",
-+ led_group);
-+ return ret;
-+ }
-+
-+ return 0;
-+}
-+
-+static int
-+rtl8366rb_cled_brightness_set_blocking(struct led_classdev *ldev,
-+ enum led_brightness brightness)
-+{
-+ struct rtl8366rb_led *led = container_of(ldev, struct rtl8366rb_led,
-+ cdev);
-+
-+ return rb8366rb_set_port_led(led, brightness == LED_ON);
-+}
-+
-+static int rtl8366rb_setup_led(struct realtek_priv *priv, struct dsa_port *dp,
-+ struct fwnode_handle *led_fwnode)
-+{
-+ struct rtl8366rb *rb = priv->chip_data;
-+ struct led_init_data init_data = { };
-+ enum led_default_state state;
-+ struct rtl8366rb_led *led;
-+ u32 led_group;
-+ int ret;
-+
-+ ret = fwnode_property_read_u32(led_fwnode, "reg", &led_group);
-+ if (ret)
-+ return ret;
-+
-+ if (led_group >= RTL8366RB_NUM_LEDGROUPS) {
-+ dev_warn(priv->dev, "Invalid LED reg %d defined for port %d",
-+ led_group, dp->index);
-+ return -EINVAL;
-+ }
-+
-+ led = &rb->leds[dp->index][led_group];
-+ led->port_num = dp->index;
-+ led->led_group = led_group;
-+ led->priv = priv;
-+
-+ state = led_init_default_state_get(led_fwnode);
-+ switch (state) {
-+ case LEDS_DEFSTATE_ON:
-+ led->cdev.brightness = 1;
-+ rb8366rb_set_port_led(led, 1);
-+ break;
-+ case LEDS_DEFSTATE_KEEP:
-+ led->cdev.brightness =
-+ rb8366rb_get_port_led(led);
-+ break;
-+ case LEDS_DEFSTATE_OFF:
-+ default:
-+ led->cdev.brightness = 0;
-+ rb8366rb_set_port_led(led, 0);
-+ }
-+
-+ led->cdev.max_brightness = 1;
-+ led->cdev.brightness_set_blocking =
-+ rtl8366rb_cled_brightness_set_blocking;
-+ init_data.fwnode = led_fwnode;
-+ init_data.devname_mandatory = true;
-+
-+ init_data.devicename = kasprintf(GFP_KERNEL, "Realtek-%d:0%d:%d",
-+ dp->ds->index, dp->index, led_group);
-+ if (!init_data.devicename)
-+ return -ENOMEM;
-+
-+ ret = devm_led_classdev_register_ext(priv->dev, &led->cdev, &init_data);
-+ if (ret) {
-+ dev_warn(priv->dev, "Failed to init LED %d for port %d",
-+ led_group, dp->index);
-+ return ret;
-+ }
-+
-+ return 0;
-+}
-+
-+static int rtl8366rb_setup_all_leds_off(struct realtek_priv *priv)
-+{
-+ int ret = 0;
-+ int i;
-+
-+ regmap_update_bits(priv->map,
-+ RTL8366RB_INTERRUPT_CONTROL_REG,
-+ RTL8366RB_P4_RGMII_LED,
-+ 0);
-+
-+ for (i = 0; i < RTL8366RB_NUM_LEDGROUPS; i++) {
-+ ret = rb8366rb_set_ledgroup_mode(priv, i,
-+ RTL8366RB_LEDGROUP_OFF);
-+ if (ret)
-+ return ret;
-+ }
-+
-+ return ret;
-+}
-+
-+static int rtl8366rb_setup_leds(struct realtek_priv *priv)
-+{
-+ struct device_node *leds_np, *led_np;
-+ struct dsa_switch *ds = &priv->ds;
-+ struct dsa_port *dp;
-+ int ret = 0;
-+
-+ dsa_switch_for_each_port(dp, ds) {
-+ if (!dp->dn)
-+ continue;
-+
-+ leds_np = of_get_child_by_name(dp->dn, "leds");
-+ if (!leds_np) {
-+ dev_dbg(priv->dev, "No leds defined for port %d",
-+ dp->index);
-+ continue;
-+ }
-+
-+ for_each_child_of_node(leds_np, led_np) {
-+ ret = rtl8366rb_setup_led(priv, dp,
-+ of_fwnode_handle(led_np));
-+ if (ret) {
-+ of_node_put(led_np);
-+ break;
-+ }
-+ }
-+
-+ of_node_put(leds_np);
-+ if (ret)
-+ return ret;
-+ }
-+ return 0;
-+}
-+
- static int rtl8366rb_setup(struct dsa_switch *ds)
- {
- struct realtek_priv *priv = ds->priv;
-@@ -821,7 +1053,6 @@ static int rtl8366rb_setup(struct dsa_sw
- u32 chip_ver = 0;
- u32 chip_id = 0;
- int jam_size;
-- u32 val;
- int ret;
- int i;
-
-@@ -997,7 +1228,9 @@ static int rtl8366rb_setup(struct dsa_sw
- if (ret)
- return ret;
-
-- /* Set blinking, TODO: make this configurable */
-+ /* Set blinking, used by all LED groups using HW triggers.
-+ * TODO: make this configurable
-+ */
- ret = regmap_update_bits(priv->map, RTL8366RB_LED_BLINKRATE_REG,
- RTL8366RB_LED_BLINKRATE_MASK,
- RTL8366RB_LED_BLINKRATE_56MS);
-@@ -1005,26 +1238,19 @@ static int rtl8366rb_setup(struct dsa_sw
- return ret;
-
- /* Set up LED activity:
-- * Each port has 4 LEDs, we configure all ports to the same
-- * behaviour (no individual config) but we can set up each
-- * LED separately.
-+ * Each port has 4 LEDs on fixed groups. Each group shares the same
-+ * hardware trigger across all ports. LEDs can only be indiviually
-+ * controlled setting the LED group to fixed mode and using the driver
-+ * to toggle them LEDs on/off.
- */
- if (priv->leds_disabled) {
-- /* Turn everything off */
-- regmap_update_bits(priv->map,
-- RTL8366RB_INTERRUPT_CONTROL_REG,
-- RTL8366RB_P4_RGMII_LED,
-- 0);
--
-- for (i = 0; i < RTL8366RB_NUM_LEDGROUPS; i++) {
-- val = RTL8366RB_LED_OFF << RTL8366RB_LED_CTRL_OFFSET(i);
-- ret = regmap_update_bits(priv->map,
-- RTL8366RB_LED_CTRL_REG,
-- RTL8366RB_LED_CTRL_MASK(i),
-- val);
-- if (ret)
-- return ret;
-- }
-+ ret = rtl8366rb_setup_all_leds_off(priv);
-+ if (ret)
-+ return ret;
-+ } else {
-+ ret = rtl8366rb_setup_leds(priv);
-+ if (ret)
-+ return ret;
- }
-
- ret = rtl8366_reset_vlan(priv);
+++ /dev/null
-From e0ccf861b80698a5cc6f97c89bf8d5761f465fce Mon Sep 17 00:00:00 2001
-Date: Sun, 7 Jan 2024 14:41:20 +0000
-Subject: mtd: spinand: winbond: add support for W25N04KV
-
-Add support for W25N04KV.
-
-W25N04KV has 8-bit on-die ECC.
-
----
- drivers/mtd/nand/spi/winbond.c | 12 ++++++++++++
- 1 file changed, 12 insertions(+)
-
-(limited to 'drivers/mtd/nand/spi/winbond.c')
-
---- a/drivers/mtd/nand/spi/winbond.c
-+++ b/drivers/mtd/nand/spi/winbond.c
-@@ -15,6 +15,8 @@
-
- #define WINBOND_CFG_BUF_READ BIT(3)
-
-+#define W25N04KV_STATUS_ECC_5_8_BITFLIPS (3 << 4)
-+
- static SPINAND_OP_VARIANTS(read_cache_variants,
- SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
- SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
-@@ -135,6 +137,7 @@ static int w25n02kv_ecc_get_status(struc
- return -EBADMSG;
-
- case STATUS_ECC_HAS_BITFLIPS:
-+ case W25N04KV_STATUS_ECC_5_8_BITFLIPS:
- /*
- * Let's try to retrieve the real maximum number of bitflips
- * in order to avoid forcing the wear-leveling layer to move
-@@ -240,6 +243,15 @@ static const struct spinand_info winbond
- &update_cache_variants),
- 0,
- SPINAND_ECCINFO(&w25m02gv_ooblayout, w25n02kv_ecc_get_status)),
-+ SPINAND_INFO("W25N04KV",
-+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xaa, 0x23),
-+ NAND_MEMORG(1, 2048, 128, 64, 4096, 40, 2, 1, 1),
-+ NAND_ECCREQ(8, 512),
-+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
-+ &write_cache_variants,
-+ &update_cache_variants),
-+ 0,
-+ SPINAND_ECCINFO(&w25n02kv_ooblayout, w25n02kv_ecc_get_status)),
- };
-
- static int winbond_spinand_init(struct spinand_device *spinand)
+++ /dev/null
-From f8d05679fb3faae478d604177b0c188b340371cd Mon Sep 17 00:00:00 2001
-Date: Mon, 22 Apr 2024 05:38:55 -0700
-Subject: [PATCH] net: free_netdev: exit earlier if dummy
-
-For dummy devices, exit earlier at free_netdev() instead of executing
-the whole function. This is necessary, because dummy devices are
-special, and shouldn't have the second part of the function executed.
-
-Otherwise reg_state, which is NETREG_DUMMY, will be overwritten and
-there will be no way to identify that this is a dummy device. Also, this
-device do not need the final put_device(), since dummy devices are not
-registered (through register_netdevice()), where the device reference is
-increased (at netdev_register_kobject()/device_add()).
-
----
- net/core/dev.c | 3 ++-
- 1 file changed, 2 insertions(+), 1 deletion(-)
-
---- a/net/core/dev.c
-+++ b/net/core/dev.c
-@@ -11032,7 +11032,8 @@ void free_netdev(struct net_device *dev)
- dev->xdp_bulkq = NULL;
-
- /* Compatibility with error handling in drivers */
-- if (dev->reg_state == NETREG_UNINITIALIZED) {
-+ if (dev->reg_state == NETREG_UNINITIALIZED ||
-+ dev->reg_state == NETREG_DUMMY) {
- netdev_freemem(dev);
- return;
- }
+++ /dev/null
-From 7b590490e3aa6bfa38bf6e2069a529017fd3c1d2 Mon Sep 17 00:00:00 2001
-Date: Fri, 13 Oct 2023 00:08:35 +0200
-Subject: [PATCH] net: dsa: mv88e6xxx: Support LED control
-
-This adds control over the hardware LEDs in the Marvell
-MV88E6xxx DSA switch and enables it for MV88E6352.
-
-This fixes an imminent problem on the Inteno XG6846 which
-has a WAN LED that simply do not work with hardware
-defaults: driver amendment is necessary.
-
-The patch is modeled after Christian Marangis LED support
-code for the QCA8k DSA switch, I got help with the register
-definitions from Tim Harvey.
-
-After this patch it is possible to activate hardware link
-indication like this (or with a similar script):
-
- cd /sys/class/leds/Marvell\ 88E6352:05:00:green:wan/
- echo netdev > trigger
- echo 1 > link
-
-This makes the green link indicator come up on any link
-speed. It is also possible to be more elaborate, like this:
-
- cd /sys/class/leds/Marvell\ 88E6352:05:00:green:wan/
- echo netdev > trigger
- echo 1 > link_1000
- cd /sys/class/leds/Marvell\ 88E6352:05:01:amber:wan/
- echo netdev > trigger
- echo 1 > link_100
-
-Making the green LED come on for a gigabit link and the
-amber LED come on for a 100 mbit link.
-
-Each port has 2 LED slots (the hardware may use just one or
-none) and the hardware triggers are specified in four bits per
-LED, and some of the hardware triggers are only available on the
-SFP (fiber) uplink. The restrictions are described in the
-port.h header file where the registers are described. For
-example, selector 1 set for LED 1 on port 5 or 6 will indicate
-Fiber 1000 (gigabit) and activity with a blinking LED, but
-ONLY for an SFP connection. If port 5/6 is used with something
-not SFP, this selector is a noop: something else need to be
-selected.
-
-After the previous series rewriting the MV88E6xxx DT
-bindings to use YAML a "leds" subnode is already valid
-for each port, in my scratch device tree it looks like
-this:
-
- leds {
- #address-cells = <1>;
- #size-cells = <0>;
-
- led@0 {
- reg = <0>;
- color = <LED_COLOR_ID_GREEN>;
- function = LED_FUNCTION_LAN;
- default-state = "off";
- linux,default-trigger = "netdev";
- };
- led@1 {
- reg = <1>;
- color = <LED_COLOR_ID_AMBER>;
- function = LED_FUNCTION_LAN;
- default-state = "off";
- };
- };
-
-This DT config is not yet configuring everything: when the netdev
-default trigger is assigned the hw acceleration callbacks are
-not called, and there is no way to set the netdev sub-trigger
-type (such as link_1000) from the device tree, such as if you want
-a gigabit link indicator. This has to be done from userspace at
-this point.
-
-We add LED operations to all switches in the 6352 family:
-6172, 6176, 6240 and 6352.
-
----
- drivers/net/dsa/mv88e6xxx/Kconfig | 10 +
- drivers/net/dsa/mv88e6xxx/Makefile | 1 +
- drivers/net/dsa/mv88e6xxx/chip.c | 38 +-
- drivers/net/dsa/mv88e6xxx/chip.h | 11 +
- drivers/net/dsa/mv88e6xxx/leds.c | 839 +++++++++++++++++++++++++++++
- drivers/net/dsa/mv88e6xxx/port.c | 1 +
- drivers/net/dsa/mv88e6xxx/port.h | 133 +++++
- 7 files changed, 1031 insertions(+), 2 deletions(-)
- create mode 100644 drivers/net/dsa/mv88e6xxx/leds.c
-
---- a/drivers/net/dsa/mv88e6xxx/Kconfig
-+++ b/drivers/net/dsa/mv88e6xxx/Kconfig
-@@ -17,3 +17,13 @@ config NET_DSA_MV88E6XXX_PTP
- help
- Say Y to enable PTP hardware timestamping on Marvell 88E6xxx switch
- chips that support it.
-+
-+config NET_DSA_MV88E6XXX_LEDS
-+ bool "LED support for Marvell 88E6xxx"
-+ default y
-+ depends on NET_DSA_MV88E6XXX
-+ depends on LEDS_CLASS=y || LEDS_CLASS=NET_DSA_MV88E6XXX
-+ depends on LEDS_TRIGGERS
-+ help
-+ This enabled support for controlling the LEDs attached to the
-+ Marvell 88E6xxx switch chips.
---- a/drivers/net/dsa/mv88e6xxx/Makefile
-+++ b/drivers/net/dsa/mv88e6xxx/Makefile
-@@ -9,6 +9,7 @@ mv88e6xxx-objs += global2.o
- mv88e6xxx-objs += global2_avb.o
- mv88e6xxx-objs += global2_scratch.o
- mv88e6xxx-$(CONFIG_NET_DSA_MV88E6XXX_PTP) += hwtstamp.o
-+mv88e6xxx-$(CONFIG_NET_DSA_MV88E6XXX_LEDS) += leds.o
- mv88e6xxx-objs += pcs-6185.o
- mv88e6xxx-objs += pcs-6352.o
- mv88e6xxx-objs += pcs-639x.o
---- a/drivers/net/dsa/mv88e6xxx/chip.c
-+++ b/drivers/net/dsa/mv88e6xxx/chip.c
-@@ -27,6 +27,7 @@
- #include <linux/of_irq.h>
- #include <linux/of_mdio.h>
- #include <linux/platform_data/mv88e6xxx.h>
-+#include <linux/property.h>
- #include <linux/netdevice.h>
- #include <linux/gpio/consumer.h>
- #include <linux/phylink.h>
-@@ -3276,14 +3277,43 @@ static int mv88e6xxx_setup_upstream_port
- static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port)
- {
- struct device_node *phy_handle = NULL;
-+ struct fwnode_handle *ports_fwnode;
-+ struct fwnode_handle *port_fwnode;
- struct dsa_switch *ds = chip->ds;
-+ struct mv88e6xxx_port *p;
- struct dsa_port *dp;
- int tx_amp;
- int err;
- u16 reg;
-+ u32 val;
-
-- chip->ports[port].chip = chip;
-- chip->ports[port].port = port;
-+ p = &chip->ports[port];
-+ p->chip = chip;
-+ p->port = port;
-+
-+ /* Look up corresponding fwnode if any */
-+ ports_fwnode = device_get_named_child_node(chip->dev, "ethernet-ports");
-+ if (!ports_fwnode)
-+ ports_fwnode = device_get_named_child_node(chip->dev, "ports");
-+ if (ports_fwnode) {
-+ fwnode_for_each_child_node(ports_fwnode, port_fwnode) {
-+ if (fwnode_property_read_u32(port_fwnode, "reg", &val))
-+ continue;
-+ if (val == port) {
-+ p->fwnode = port_fwnode;
-+ p->fiber = fwnode_property_present(port_fwnode, "sfp");
-+ break;
-+ }
-+ }
-+ } else {
-+ dev_dbg(chip->dev, "no ethernet ports node defined for the device\n");
-+ }
-+
-+ if (chip->info->ops->port_setup_leds) {
-+ err = chip->info->ops->port_setup_leds(chip, port);
-+ if (err && err != -EOPNOTSUPP)
-+ return err;
-+ }
-
- err = mv88e6xxx_port_setup_mac(chip, port, LINK_UNFORCED,
- SPEED_UNFORCED, DUPLEX_UNFORCED,
-@@ -4517,6 +4547,7 @@ static const struct mv88e6xxx_ops mv88e6
- .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
- .port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
- .port_get_cmode = mv88e6352_port_get_cmode,
-+ .port_setup_leds = mv88e6xxx_port_setup_leds,
- .port_setup_message_port = mv88e6xxx_setup_message_port,
- .stats_snapshot = mv88e6320_g1_stats_snapshot,
- .stats_set_histogram = mv88e6095_g1_stats_set_histogram,
-@@ -4619,6 +4650,7 @@ static const struct mv88e6xxx_ops mv88e6
- .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
- .port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
- .port_get_cmode = mv88e6352_port_get_cmode,
-+ .port_setup_leds = mv88e6xxx_port_setup_leds,
- .port_setup_message_port = mv88e6xxx_setup_message_port,
- .stats_snapshot = mv88e6320_g1_stats_snapshot,
- .stats_set_histogram = mv88e6095_g1_stats_set_histogram,
-@@ -4894,6 +4926,7 @@ static const struct mv88e6xxx_ops mv88e6
- .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
- .port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
- .port_get_cmode = mv88e6352_port_get_cmode,
-+ .port_setup_leds = mv88e6xxx_port_setup_leds,
- .port_setup_message_port = mv88e6xxx_setup_message_port,
- .stats_snapshot = mv88e6320_g1_stats_snapshot,
- .stats_set_histogram = mv88e6095_g1_stats_set_histogram,
-@@ -5324,6 +5357,7 @@ static const struct mv88e6xxx_ops mv88e6
- .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
- .port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
- .port_get_cmode = mv88e6352_port_get_cmode,
-+ .port_setup_leds = mv88e6xxx_port_setup_leds,
- .port_setup_message_port = mv88e6xxx_setup_message_port,
- .stats_snapshot = mv88e6320_g1_stats_snapshot,
- .stats_set_histogram = mv88e6095_g1_stats_set_histogram,
---- a/drivers/net/dsa/mv88e6xxx/chip.h
-+++ b/drivers/net/dsa/mv88e6xxx/chip.h
-@@ -13,7 +13,9 @@
- #include <linux/irq.h>
- #include <linux/gpio/consumer.h>
- #include <linux/kthread.h>
-+#include <linux/leds.h>
- #include <linux/phy.h>
-+#include <linux/property.h>
- #include <linux/ptp_clock_kernel.h>
- #include <linux/timecounter.h>
- #include <net/dsa.h>
-@@ -276,6 +278,7 @@ struct mv88e6xxx_vlan {
- struct mv88e6xxx_port {
- struct mv88e6xxx_chip *chip;
- int port;
-+ struct fwnode_handle *fwnode;
- struct mv88e6xxx_vlan bridge_pvid;
- u64 serdes_stats[2];
- u64 atu_member_violation;
-@@ -290,6 +293,11 @@ struct mv88e6xxx_port {
- struct devlink_region *region;
- void *pcs_private;
-
-+ /* LED related information */
-+ bool fiber;
-+ struct led_classdev led0;
-+ struct led_classdev led1;
-+
- /* MacAuth Bypass control flag */
- bool mab;
- };
-@@ -563,6 +571,9 @@ struct mv88e6xxx_ops {
- phy_interface_t mode);
- int (*port_get_cmode)(struct mv88e6xxx_chip *chip, int port, u8 *cmode);
-
-+ /* LED control */
-+ int (*port_setup_leds)(struct mv88e6xxx_chip *chip, int port);
-+
- /* Some devices have a per port register indicating what is
- * the upstream port this port should forward to.
- */
---- /dev/null
-+++ b/drivers/net/dsa/mv88e6xxx/leds.c
-@@ -0,0 +1,839 @@
-+// SPDX-License-Identifier: GPL-2.0-or-later
-+#include <linux/bitfield.h>
-+#include <linux/leds.h>
-+#include <linux/property.h>
-+
-+#include "chip.h"
-+#include "global2.h"
-+#include "port.h"
-+
-+/* Offset 0x16: LED control */
-+
-+static int mv88e6xxx_port_led_write(struct mv88e6xxx_chip *chip, int port, u16 reg)
-+{
-+ reg |= MV88E6XXX_PORT_LED_CONTROL_UPDATE;
-+
-+ return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_LED_CONTROL, reg);
-+}
-+
-+static int mv88e6xxx_port_led_read(struct mv88e6xxx_chip *chip, int port,
-+ u16 ptr, u16 *val)
-+{
-+ int err;
-+
-+ err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_LED_CONTROL, ptr);
-+ if (err)
-+ return err;
-+
-+ err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_LED_CONTROL, val);
-+ *val &= 0x3ff;
-+
-+ return err;
-+}
-+
-+static int mv88e6xxx_led_brightness_set(struct mv88e6xxx_port *p, int led,
-+ int brightness)
-+{
-+ u16 reg;
-+ int err;
-+
-+ err = mv88e6xxx_port_led_read(p->chip, p->port,
-+ MV88E6XXX_PORT_LED_CONTROL_POINTER_LED01_CTRL,
-+ ®);
-+ if (err)
-+ return err;
-+
-+ if (led == 1)
-+ reg &= ~MV88E6XXX_PORT_LED_CONTROL_LED1_SEL_MASK;
-+ else
-+ reg &= ~MV88E6XXX_PORT_LED_CONTROL_LED0_SEL_MASK;
-+
-+ if (brightness) {
-+ /* Selector 0x0f == Force LED ON */
-+ if (led == 1)
-+ reg |= MV88E6XXX_PORT_LED_CONTROL_LED1_SELF;
-+ else
-+ reg |= MV88E6XXX_PORT_LED_CONTROL_LED0_SELF;
-+ } else {
-+ /* Selector 0x0e == Force LED OFF */
-+ if (led == 1)
-+ reg |= MV88E6XXX_PORT_LED_CONTROL_LED1_SELE;
-+ else
-+ reg |= MV88E6XXX_PORT_LED_CONTROL_LED0_SELE;
-+ }
-+
-+ reg |= MV88E6XXX_PORT_LED_CONTROL_POINTER_LED01_CTRL;
-+
-+ return mv88e6xxx_port_led_write(p->chip, p->port, reg);
-+}
-+
-+static int mv88e6xxx_led0_brightness_set_blocking(struct led_classdev *ldev,
-+ enum led_brightness brightness)
-+{
-+ struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led0);
-+ int err;
-+
-+ mv88e6xxx_reg_lock(p->chip);
-+ err = mv88e6xxx_led_brightness_set(p, 0, brightness);
-+ mv88e6xxx_reg_unlock(p->chip);
-+
-+ return err;
-+}
-+
-+static int mv88e6xxx_led1_brightness_set_blocking(struct led_classdev *ldev,
-+ enum led_brightness brightness)
-+{
-+ struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led1);
-+ int err;
-+
-+ mv88e6xxx_reg_lock(p->chip);
-+ err = mv88e6xxx_led_brightness_set(p, 1, brightness);
-+ mv88e6xxx_reg_unlock(p->chip);
-+
-+ return err;
-+}
-+
-+struct mv88e6xxx_led_hwconfig {
-+ int led;
-+ u8 portmask;
-+ unsigned long rules;
-+ bool fiber;
-+ bool blink_activity;
-+ u16 selector;
-+};
-+
-+/* The following is a lookup table to check what rules we can support on a
-+ * certain LED given restrictions such as that some rules only work with fiber
-+ * (SFP) connections and some blink on activity by default.
-+ */
-+#define MV88E6XXX_PORTS_0_3 (BIT(0) | BIT(1) | BIT(2) | BIT(3))
-+#define MV88E6XXX_PORTS_4_5 (BIT(4) | BIT(5))
-+#define MV88E6XXX_PORT_4 BIT(4)
-+#define MV88E6XXX_PORT_5 BIT(5)
-+
-+/* Entries are listed in selector order.
-+ *
-+ * These configurations vary across different switch families, list
-+ * different tables per-family here.
-+ */
-+static const struct mv88e6xxx_led_hwconfig mv88e6352_led_hwconfigs[] = {
-+ {
-+ .led = 0,
-+ .portmask = MV88E6XXX_PORT_4,
-+ .rules = BIT(TRIGGER_NETDEV_LINK),
-+ .blink_activity = true,
-+ .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SEL0,
-+ },
-+ {
-+ .led = 1,
-+ .portmask = MV88E6XXX_PORT_5,
-+ .rules = BIT(TRIGGER_NETDEV_LINK_1000),
-+ .blink_activity = true,
-+ .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL0,
-+ },
-+ {
-+ .led = 0,
-+ .portmask = MV88E6XXX_PORTS_0_3,
-+ .rules = BIT(TRIGGER_NETDEV_LINK_100) | BIT(TRIGGER_NETDEV_LINK_1000),
-+ .blink_activity = true,
-+ .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SEL1,
-+ },
-+ {
-+ .led = 1,
-+ .portmask = MV88E6XXX_PORTS_0_3,
-+ .rules = BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_LINK_100),
-+ .blink_activity = true,
-+ .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL1,
-+ },
-+ {
-+ .led = 0,
-+ .portmask = MV88E6XXX_PORTS_4_5,
-+ .rules = BIT(TRIGGER_NETDEV_LINK_100),
-+ .blink_activity = true,
-+ .fiber = true,
-+ .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SEL1,
-+ },
-+ {
-+ .led = 1,
-+ .portmask = MV88E6XXX_PORTS_4_5,
-+ .rules = BIT(TRIGGER_NETDEV_LINK_1000),
-+ .blink_activity = true,
-+ .fiber = true,
-+ .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL1,
-+ },
-+ {
-+ .led = 0,
-+ .portmask = MV88E6XXX_PORTS_0_3,
-+ .rules = BIT(TRIGGER_NETDEV_LINK_1000),
-+ .blink_activity = true,
-+ .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SEL2,
-+ },
-+ {
-+ .led = 1,
-+ .portmask = MV88E6XXX_PORTS_0_3,
-+ .rules = BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_LINK_100),
-+ .blink_activity = true,
-+ .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL2,
-+ },
-+ {
-+ .led = 0,
-+ .portmask = MV88E6XXX_PORTS_4_5,
-+ .rules = BIT(TRIGGER_NETDEV_LINK_1000),
-+ .blink_activity = true,
-+ .fiber = true,
-+ .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SEL2,
-+ },
-+ {
-+ .led = 1,
-+ .portmask = MV88E6XXX_PORTS_4_5,
-+ .rules = BIT(TRIGGER_NETDEV_LINK_100),
-+ .blink_activity = true,
-+ .fiber = true,
-+ .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL2,
-+ },
-+ {
-+ .led = 0,
-+ .portmask = MV88E6XXX_PORTS_0_3,
-+ .rules = BIT(TRIGGER_NETDEV_LINK),
-+ .blink_activity = true,
-+ .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SEL3,
-+ },
-+ {
-+ .led = 1,
-+ .portmask = MV88E6XXX_PORTS_0_3,
-+ .rules = BIT(TRIGGER_NETDEV_LINK_1000),
-+ .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL3,
-+ },
-+ {
-+ .led = 1,
-+ .portmask = MV88E6XXX_PORTS_4_5,
-+ .rules = BIT(TRIGGER_NETDEV_LINK),
-+ .fiber = true,
-+ .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL3,
-+ },
-+ {
-+ .led = 1,
-+ .portmask = MV88E6XXX_PORT_4,
-+ .rules = BIT(TRIGGER_NETDEV_LINK),
-+ .blink_activity = true,
-+ .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL4,
-+ },
-+ {
-+ .led = 1,
-+ .portmask = MV88E6XXX_PORT_5,
-+ .rules = BIT(TRIGGER_NETDEV_LINK),
-+ .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL5,
-+ },
-+ {
-+ .led = 0,
-+ .portmask = MV88E6XXX_PORTS_0_3,
-+ .rules = BIT(TRIGGER_NETDEV_FULL_DUPLEX),
-+ .blink_activity = true,
-+ .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SEL6,
-+ },
-+ {
-+ .led = 1,
-+ .portmask = MV88E6XXX_PORTS_0_3,
-+ .rules = BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_LINK_1000),
-+ .blink_activity = true,
-+ .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL6,
-+ },
-+ {
-+ .led = 0,
-+ .portmask = MV88E6XXX_PORT_4,
-+ .rules = BIT(TRIGGER_NETDEV_FULL_DUPLEX),
-+ .blink_activity = true,
-+ .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SEL6,
-+ },
-+ {
-+ .led = 1,
-+ .portmask = MV88E6XXX_PORT_5,
-+ .rules = BIT(TRIGGER_NETDEV_FULL_DUPLEX),
-+ .blink_activity = true,
-+ .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL6,
-+ },
-+ {
-+ .led = 0,
-+ .portmask = MV88E6XXX_PORTS_0_3,
-+ .rules = BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_LINK_1000),
-+ .blink_activity = true,
-+ .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SEL7,
-+ },
-+ {
-+ .led = 1,
-+ .portmask = MV88E6XXX_PORTS_0_3,
-+ .rules = BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_LINK_1000),
-+ .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL7,
-+ },
-+ {
-+ .led = 0,
-+ .portmask = MV88E6XXX_PORTS_0_3,
-+ .rules = BIT(TRIGGER_NETDEV_LINK),
-+ .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SEL8,
-+ },
-+ {
-+ .led = 1,
-+ .portmask = MV88E6XXX_PORTS_0_3,
-+ .rules = BIT(TRIGGER_NETDEV_LINK),
-+ .blink_activity = true,
-+ .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL8,
-+ },
-+ {
-+ .led = 0,
-+ .portmask = MV88E6XXX_PORT_5,
-+ .rules = BIT(TRIGGER_NETDEV_LINK),
-+ .blink_activity = true,
-+ .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SEL8,
-+ },
-+ {
-+ .led = 0,
-+ .portmask = MV88E6XXX_PORTS_0_3,
-+ .rules = BIT(TRIGGER_NETDEV_LINK_10),
-+ .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SEL9,
-+ },
-+ {
-+ .led = 1,
-+ .portmask = MV88E6XXX_PORTS_0_3,
-+ .rules = BIT(TRIGGER_NETDEV_LINK_100),
-+ .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL9,
-+ },
-+ {
-+ .led = 0,
-+ .portmask = MV88E6XXX_PORTS_0_3,
-+ .rules = BIT(TRIGGER_NETDEV_LINK_10),
-+ .blink_activity = true,
-+ .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SELA,
-+ },
-+ {
-+ .led = 1,
-+ .portmask = MV88E6XXX_PORTS_0_3,
-+ .rules = BIT(TRIGGER_NETDEV_LINK_100),
-+ .blink_activity = true,
-+ .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SELA,
-+ },
-+ {
-+ .led = 0,
-+ .portmask = MV88E6XXX_PORTS_0_3,
-+ .rules = BIT(TRIGGER_NETDEV_LINK_100) | BIT(TRIGGER_NETDEV_LINK_1000),
-+ .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SELB,
-+ },
-+ {
-+ .led = 1,
-+ .portmask = MV88E6XXX_PORTS_0_3,
-+ .rules = BIT(TRIGGER_NETDEV_LINK_100) | BIT(TRIGGER_NETDEV_LINK_1000),
-+ .blink_activity = true,
-+ .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SELB,
-+ },
-+};
-+
-+/* mv88e6xxx_led_match_selector() - look up the appropriate LED mode selector
-+ * @p: port state container
-+ * @led: LED number, 0 or 1
-+ * @blink_activity: blink the LED (usually blink on indicated activity)
-+ * @fiber: the link is connected to fiber such as SFP
-+ * @rules: LED status flags from the LED classdev core
-+ * @selector: fill in the selector in this parameter with an OR operation
-+ */
-+static int mv88e6xxx_led_match_selector(struct mv88e6xxx_port *p, int led, bool blink_activity,
-+ bool fiber, unsigned long rules, u16 *selector)
-+{
-+ const struct mv88e6xxx_led_hwconfig *conf;
-+ int i;
-+
-+ /* No rules means we turn the LED off */
-+ if (!rules) {
-+ if (led == 1)
-+ *selector |= MV88E6XXX_PORT_LED_CONTROL_LED1_SELE;
-+ else
-+ *selector |= MV88E6XXX_PORT_LED_CONTROL_LED0_SELE;
-+ return 0;
-+ }
-+
-+ /* TODO: these rules are for MV88E6352, when adding other families,
-+ * think about making sure you select the table that match the
-+ * specific switch family.
-+ */
-+ for (i = 0; i < ARRAY_SIZE(mv88e6352_led_hwconfigs); i++) {
-+ conf = &mv88e6352_led_hwconfigs[i];
-+
-+ if (conf->led != led)
-+ continue;
-+
-+ if (!(conf->portmask & BIT(p->port)))
-+ continue;
-+
-+ if (conf->blink_activity != blink_activity)
-+ continue;
-+
-+ if (conf->fiber != fiber)
-+ continue;
-+
-+ if (conf->rules == rules) {
-+ dev_dbg(p->chip->dev, "port%d LED %d set selector %04x for rules %08lx\n",
-+ p->port, led, conf->selector, rules);
-+ *selector |= conf->selector;
-+ return 0;
-+ }
-+ }
-+
-+ return -EOPNOTSUPP;
-+}
-+
-+/* mv88e6xxx_led_match_selector() - find Linux netdev rules from a selector value
-+ * @p: port state container
-+ * @selector: the selector value from the LED actity register
-+ * @led: LED number, 0 or 1
-+ * @rules: Linux netdev activity rules found from selector
-+ */
-+static int
-+mv88e6xxx_led_match_rule(struct mv88e6xxx_port *p, u16 selector, int led, unsigned long *rules)
-+{
-+ const struct mv88e6xxx_led_hwconfig *conf;
-+ int i;
-+
-+ /* Find the selector in the table, we just look for the right selector
-+ * and ignore if the activity has special properties such as blinking
-+ * or is fiber-only.
-+ */
-+ for (i = 0; i < ARRAY_SIZE(mv88e6352_led_hwconfigs); i++) {
-+ conf = &mv88e6352_led_hwconfigs[i];
-+
-+ if (conf->led != led)
-+ continue;
-+
-+ if (!(conf->portmask & BIT(p->port)))
-+ continue;
-+
-+ if (conf->selector == selector) {
-+ dev_dbg(p->chip->dev, "port%d LED %d has selector %04x, rules %08lx\n",
-+ p->port, led, selector, conf->rules);
-+ *rules = conf->rules;
-+ return 0;
-+ }
-+ }
-+
-+ return -EINVAL;
-+}
-+
-+/* mv88e6xxx_led_get_selector() - get the appropriate LED mode selector
-+ * @p: port state container
-+ * @led: LED number, 0 or 1
-+ * @fiber: the link is connected to fiber such as SFP
-+ * @rules: LED status flags from the LED classdev core
-+ * @selector: fill in the selector in this parameter with an OR operation
-+ */
-+static int mv88e6xxx_led_get_selector(struct mv88e6xxx_port *p, int led,
-+ bool fiber, unsigned long rules, u16 *selector)
-+{
-+ int err;
-+
-+ /* What happens here is that we first try to locate a trigger with solid
-+ * indicator (such as LED is on for a 1000 link) else we try a second
-+ * sweep to find something suitable with a trigger that will blink on
-+ * activity.
-+ */
-+ err = mv88e6xxx_led_match_selector(p, led, false, fiber, rules, selector);
-+ if (err)
-+ return mv88e6xxx_led_match_selector(p, led, true, fiber, rules, selector);
-+
-+ return 0;
-+}
-+
-+/* Sets up the hardware blinking period */
-+static int mv88e6xxx_led_set_blinking_period(struct mv88e6xxx_port *p, int led,
-+ unsigned long delay_on, unsigned long delay_off)
-+{
-+ unsigned long period;
-+ u16 reg;
-+
-+ period = delay_on + delay_off;
-+
-+ reg = 0;
-+
-+ switch (period) {
-+ case 21:
-+ reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_21MS;
-+ break;
-+ case 42:
-+ reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_42MS;
-+ break;
-+ case 84:
-+ reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_84MS;
-+ break;
-+ case 168:
-+ reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_168MS;
-+ break;
-+ case 336:
-+ reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_336MS;
-+ break;
-+ case 672:
-+ reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_672MS;
-+ break;
-+ default:
-+ /* Fall back to software blinking */
-+ return -EINVAL;
-+ }
-+
-+ /* This is essentially PWM duty cycle: how long time of the period
-+ * will the LED be on. Zero isn't great in most cases.
-+ */
-+ switch (delay_on) {
-+ case 0:
-+ /* This is usually pretty useless and will make the LED look OFF */
-+ reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_PULSE_STRETCH_NONE;
-+ break;
-+ case 21:
-+ reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_PULSE_STRETCH_21MS;
-+ break;
-+ case 42:
-+ reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_PULSE_STRETCH_42MS;
-+ break;
-+ case 84:
-+ reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_PULSE_STRETCH_84MS;
-+ break;
-+ case 168:
-+ reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_PULSE_STRETCH_168MS;
-+ break;
-+ default:
-+ /* Just use something non-zero */
-+ reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_PULSE_STRETCH_21MS;
-+ break;
-+ }
-+
-+ /* Set up blink rate */
-+ reg |= MV88E6XXX_PORT_LED_CONTROL_POINTER_STRETCH_BLINK;
-+
-+ return mv88e6xxx_port_led_write(p->chip, p->port, reg);
-+}
-+
-+static int mv88e6xxx_led_blink_set(struct mv88e6xxx_port *p, int led,
-+ unsigned long *delay_on, unsigned long *delay_off)
-+{
-+ u16 reg;
-+ int err;
-+
-+ /* Choose a sensible default 336 ms (~3 Hz) */
-+ if ((*delay_on == 0) && (*delay_off == 0)) {
-+ *delay_on = 168;
-+ *delay_off = 168;
-+ }
-+
-+ /* No off delay is just on */
-+ if (*delay_off == 0)
-+ return mv88e6xxx_led_brightness_set(p, led, 1);
-+
-+ err = mv88e6xxx_led_set_blinking_period(p, led, *delay_on, *delay_off);
-+ if (err)
-+ return err;
-+
-+ err = mv88e6xxx_port_led_read(p->chip, p->port,
-+ MV88E6XXX_PORT_LED_CONTROL_POINTER_LED01_CTRL,
-+ ®);
-+ if (err)
-+ return err;
-+
-+ if (led == 1)
-+ reg &= ~MV88E6XXX_PORT_LED_CONTROL_LED1_SEL_MASK;
-+ else
-+ reg &= ~MV88E6XXX_PORT_LED_CONTROL_LED0_SEL_MASK;
-+
-+ /* This will select the forced blinking status */
-+ if (led == 1)
-+ reg |= MV88E6XXX_PORT_LED_CONTROL_LED1_SELD;
-+ else
-+ reg |= MV88E6XXX_PORT_LED_CONTROL_LED0_SELD;
-+
-+ reg |= MV88E6XXX_PORT_LED_CONTROL_POINTER_LED01_CTRL;
-+
-+ return mv88e6xxx_port_led_write(p->chip, p->port, reg);
-+}
-+
-+static int mv88e6xxx_led0_blink_set(struct led_classdev *ldev,
-+ unsigned long *delay_on,
-+ unsigned long *delay_off)
-+{
-+ struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led0);
-+ int err;
-+
-+ mv88e6xxx_reg_lock(p->chip);
-+ err = mv88e6xxx_led_blink_set(p, 0, delay_on, delay_off);
-+ mv88e6xxx_reg_unlock(p->chip);
-+
-+ return err;
-+}
-+
-+static int mv88e6xxx_led1_blink_set(struct led_classdev *ldev,
-+ unsigned long *delay_on,
-+ unsigned long *delay_off)
-+{
-+ struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led1);
-+ int err;
-+
-+ mv88e6xxx_reg_lock(p->chip);
-+ err = mv88e6xxx_led_blink_set(p, 1, delay_on, delay_off);
-+ mv88e6xxx_reg_unlock(p->chip);
-+
-+ return err;
-+}
-+
-+static int
-+mv88e6xxx_led0_hw_control_is_supported(struct led_classdev *ldev, unsigned long rules)
-+{
-+ struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led0);
-+ u16 selector = 0;
-+
-+ return mv88e6xxx_led_get_selector(p, 0, p->fiber, rules, &selector);
-+}
-+
-+static int
-+mv88e6xxx_led1_hw_control_is_supported(struct led_classdev *ldev, unsigned long rules)
-+{
-+ struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led1);
-+ u16 selector = 0;
-+
-+ return mv88e6xxx_led_get_selector(p, 1, p->fiber, rules, &selector);
-+}
-+
-+static int mv88e6xxx_led_hw_control_set(struct mv88e6xxx_port *p,
-+ int led, unsigned long rules)
-+{
-+ u16 reg;
-+ int err;
-+
-+ err = mv88e6xxx_port_led_read(p->chip, p->port,
-+ MV88E6XXX_PORT_LED_CONTROL_POINTER_LED01_CTRL,
-+ ®);
-+ if (err)
-+ return err;
-+
-+ if (led == 1)
-+ reg &= ~MV88E6XXX_PORT_LED_CONTROL_LED1_SEL_MASK;
-+ else
-+ reg &= ~MV88E6XXX_PORT_LED_CONTROL_LED0_SEL_MASK;
-+
-+ err = mv88e6xxx_led_get_selector(p, led, p->fiber, rules, ®);
-+ if (err)
-+ return err;
-+
-+ reg |= MV88E6XXX_PORT_LED_CONTROL_POINTER_LED01_CTRL;
-+
-+ if (led == 0)
-+ dev_dbg(p->chip->dev, "LED 0 hw control on port %d trigger selector 0x%02x\n",
-+ p->port,
-+ (unsigned int)(reg & MV88E6XXX_PORT_LED_CONTROL_LED0_SEL_MASK));
-+ else
-+ dev_dbg(p->chip->dev, "LED 1 hw control on port %d trigger selector 0x%02x\n",
-+ p->port,
-+ (unsigned int)(reg & MV88E6XXX_PORT_LED_CONTROL_LED1_SEL_MASK) >> 4);
-+
-+ return mv88e6xxx_port_led_write(p->chip, p->port, reg);
-+}
-+
-+static int
-+mv88e6xxx_led_hw_control_get(struct mv88e6xxx_port *p, int led, unsigned long *rules)
-+{
-+ u16 val;
-+ int err;
-+
-+ mv88e6xxx_reg_lock(p->chip);
-+ err = mv88e6xxx_port_led_read(p->chip, p->port,
-+ MV88E6XXX_PORT_LED_CONTROL_POINTER_LED01_CTRL, &val);
-+ mv88e6xxx_reg_unlock(p->chip);
-+ if (err)
-+ return err;
-+
-+ /* Mask out the selector bits for this port */
-+ if (led == 1) {
-+ val &= MV88E6XXX_PORT_LED_CONTROL_LED1_SEL_MASK;
-+ /* It's forced blinking/OFF/ON */
-+ if (val == MV88E6XXX_PORT_LED_CONTROL_LED1_SELD ||
-+ val == MV88E6XXX_PORT_LED_CONTROL_LED1_SELE ||
-+ val == MV88E6XXX_PORT_LED_CONTROL_LED1_SELF) {
-+ *rules = 0;
-+ return 0;
-+ }
-+ } else {
-+ val &= MV88E6XXX_PORT_LED_CONTROL_LED0_SEL_MASK;
-+ /* It's forced blinking/OFF/ON */
-+ if (val == MV88E6XXX_PORT_LED_CONTROL_LED0_SELD ||
-+ val == MV88E6XXX_PORT_LED_CONTROL_LED0_SELE ||
-+ val == MV88E6XXX_PORT_LED_CONTROL_LED0_SELF) {
-+ *rules = 0;
-+ return 0;
-+ }
-+ }
-+
-+ err = mv88e6xxx_led_match_rule(p, val, led, rules);
-+ if (!err)
-+ return 0;
-+
-+ dev_dbg(p->chip->dev, "couldn't find matching selector for %04x\n", val);
-+ *rules = 0;
-+ return 0;
-+}
-+
-+static int
-+mv88e6xxx_led0_hw_control_set(struct led_classdev *ldev, unsigned long rules)
-+{
-+ struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led0);
-+ int err;
-+
-+ mv88e6xxx_reg_lock(p->chip);
-+ err = mv88e6xxx_led_hw_control_set(p, 0, rules);
-+ mv88e6xxx_reg_unlock(p->chip);
-+
-+ return err;
-+}
-+
-+static int
-+mv88e6xxx_led1_hw_control_set(struct led_classdev *ldev, unsigned long rules)
-+{
-+ struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led1);
-+ int err;
-+
-+ mv88e6xxx_reg_lock(p->chip);
-+ err = mv88e6xxx_led_hw_control_set(p, 1, rules);
-+ mv88e6xxx_reg_unlock(p->chip);
-+
-+ return err;
-+}
-+
-+static int
-+mv88e6xxx_led0_hw_control_get(struct led_classdev *ldev, unsigned long *rules)
-+{
-+ struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led0);
-+
-+ return mv88e6xxx_led_hw_control_get(p, 0, rules);
-+}
-+
-+static int
-+mv88e6xxx_led1_hw_control_get(struct led_classdev *ldev, unsigned long *rules)
-+{
-+ struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led1);
-+
-+ return mv88e6xxx_led_hw_control_get(p, 1, rules);
-+}
-+
-+static struct device *mv88e6xxx_led_hw_control_get_device(struct mv88e6xxx_port *p)
-+{
-+ struct dsa_port *dp;
-+
-+ dp = dsa_to_port(p->chip->ds, p->port);
-+ if (!dp)
-+ return NULL;
-+ if (dp->slave)
-+ return &dp->slave->dev;
-+ return NULL;
-+}
-+
-+static struct device *
-+mv88e6xxx_led0_hw_control_get_device(struct led_classdev *ldev)
-+{
-+ struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led0);
-+
-+ return mv88e6xxx_led_hw_control_get_device(p);
-+}
-+
-+static struct device *
-+mv88e6xxx_led1_hw_control_get_device(struct led_classdev *ldev)
-+{
-+ struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led1);
-+
-+ return mv88e6xxx_led_hw_control_get_device(p);
-+}
-+
-+int mv88e6xxx_port_setup_leds(struct mv88e6xxx_chip *chip, int port)
-+{
-+ struct fwnode_handle *led = NULL, *leds = NULL;
-+ struct led_init_data init_data = { };
-+ enum led_default_state state;
-+ struct mv88e6xxx_port *p;
-+ struct led_classdev *l;
-+ struct device *dev;
-+ u32 led_num;
-+ int ret;
-+
-+ /* LEDs are on ports 1,2,3,4, 5 and 6 (index 0..5), no more */
-+ if (port > 5)
-+ return -EOPNOTSUPP;
-+
-+ p = &chip->ports[port];
-+ if (!p->fwnode)
-+ return 0;
-+
-+ dev = chip->dev;
-+
-+ leds = fwnode_get_named_child_node(p->fwnode, "leds");
-+ if (!leds) {
-+ dev_dbg(dev, "No Leds node specified in device tree for port %d!\n",
-+ port);
-+ return 0;
-+ }
-+
-+ fwnode_for_each_child_node(leds, led) {
-+ /* Reg represent the led number of the port, max 2
-+ * LEDs can be connected to each port, in some designs
-+ * only one LED is connected.
-+ */
-+ if (fwnode_property_read_u32(led, "reg", &led_num))
-+ continue;
-+ if (led_num > 1) {
-+ dev_err(dev, "invalid LED specified port %d\n", port);
-+ return -EINVAL;
-+ }
-+
-+ if (led_num == 0)
-+ l = &p->led0;
-+ else
-+ l = &p->led1;
-+
-+ state = led_init_default_state_get(led);
-+ switch (state) {
-+ case LEDS_DEFSTATE_ON:
-+ l->brightness = 1;
-+ mv88e6xxx_led_brightness_set(p, led_num, 1);
-+ break;
-+ case LEDS_DEFSTATE_KEEP:
-+ break;
-+ default:
-+ l->brightness = 0;
-+ mv88e6xxx_led_brightness_set(p, led_num, 0);
-+ }
-+
-+ l->max_brightness = 1;
-+ if (led_num == 0) {
-+ l->brightness_set_blocking = mv88e6xxx_led0_brightness_set_blocking;
-+ l->blink_set = mv88e6xxx_led0_blink_set;
-+ l->hw_control_is_supported = mv88e6xxx_led0_hw_control_is_supported;
-+ l->hw_control_set = mv88e6xxx_led0_hw_control_set;
-+ l->hw_control_get = mv88e6xxx_led0_hw_control_get;
-+ l->hw_control_get_device = mv88e6xxx_led0_hw_control_get_device;
-+ } else {
-+ l->brightness_set_blocking = mv88e6xxx_led1_brightness_set_blocking;
-+ l->blink_set = mv88e6xxx_led1_blink_set;
-+ l->hw_control_is_supported = mv88e6xxx_led1_hw_control_is_supported;
-+ l->hw_control_set = mv88e6xxx_led1_hw_control_set;
-+ l->hw_control_get = mv88e6xxx_led1_hw_control_get;
-+ l->hw_control_get_device = mv88e6xxx_led1_hw_control_get_device;
-+ }
-+ l->hw_control_trigger = "netdev";
-+
-+ init_data.default_label = ":port";
-+ init_data.fwnode = led;
-+ init_data.devname_mandatory = true;
-+ init_data.devicename = kasprintf(GFP_KERNEL, "%s:0%d:0%d", chip->info->name,
-+ port, led_num);
-+ if (!init_data.devicename)
-+ return -ENOMEM;
-+
-+ ret = devm_led_classdev_register_ext(dev, l, &init_data);
-+ kfree(init_data.devicename);
-+
-+ if (ret) {
-+ dev_err(dev, "Failed to init LED %d for port %d", led_num, port);
-+ return ret;
-+ }
-+ }
-+
-+ return 0;
-+}
---- a/drivers/net/dsa/mv88e6xxx/port.c
-+++ b/drivers/net/dsa/mv88e6xxx/port.c
-@@ -12,6 +12,7 @@
- #include <linux/if_bridge.h>
- #include <linux/phy.h>
- #include <linux/phylink.h>
-+#include <linux/property.h>
-
- #include "chip.h"
- #include "global2.h"
---- a/drivers/net/dsa/mv88e6xxx/port.h
-+++ b/drivers/net/dsa/mv88e6xxx/port.h
-@@ -309,6 +309,130 @@
- /* Offset 0x13: OutFiltered Counter */
- #define MV88E6XXX_PORT_OUT_FILTERED 0x13
-
-+/* Offset 0x16: LED Control */
-+#define MV88E6XXX_PORT_LED_CONTROL 0x16
-+#define MV88E6XXX_PORT_LED_CONTROL_UPDATE BIT(15)
-+#define MV88E6XXX_PORT_LED_CONTROL_POINTER_MASK GENMASK(14, 12)
-+#define MV88E6XXX_PORT_LED_CONTROL_POINTER_LED01_CTRL (0x00 << 12) /* Control for LED 0 and 1 */
-+#define MV88E6XXX_PORT_LED_CONTROL_POINTER_STRETCH_BLINK (0x06 << 12) /* Stetch and Blink Rate */
-+#define MV88E6XXX_PORT_LED_CONTROL_POINTER_CNTL_SPECIAL (0x07 << 12) /* Control for the Port's Special LED */
-+#define MV88E6XXX_PORT_LED_CONTROL_DATA_MASK GENMASK(10, 0)
-+/* Selection masks valid for either port 1,2,3,4 or 5 */
-+#define MV88E6XXX_PORT_LED_CONTROL_LED0_SEL_MASK GENMASK(3, 0)
-+#define MV88E6XXX_PORT_LED_CONTROL_LED1_SEL_MASK GENMASK(7, 4)
-+/* Selection control for LED 0 and 1, ports 5 and 6 only has LED 0
-+ * Bits Function
-+ * 0..3 LED 0 control selector on ports 1-5
-+ * 4..7 LED 1 control selector on ports 1-4 on port 5 this controls LED 0 of port 6
-+ *
-+ * Sel Port LED Function for the 6352 family:
-+ * 0 1-4 0 Link/Act/Speed by Blink Rate (off=no link, on=link, blink=activity, blink speed=link speed)
-+ * 1-4 1 Port 2's Special LED
-+ * 5-6 0 Port 5 Link/Act (off=no link, on=link, blink=activity)
-+ * 5-6 1 Port 6 Link/Act (off=no link, on=link 1000, blink=activity)
-+ * 1 1-4 0 100/1000 Link/Act (off=no link, on=100 or 1000 link, blink=activity)
-+ * 1-4 1 10/100 Link Act (off=no link, on=10 or 100 link, blink=activity)
-+ * 5-6 0 Fiber 100 Link/Act (off=no link, on=link 100, blink=activity)
-+ * 5-6 1 Fiber 1000 Link/Act (off=no link, on=link 1000, blink=activity)
-+ * 2 1-4 0 1000 Link/Act (off=no link, on=link 1000, blink=activity)
-+ * 1-4 1 10/100 Link/Act (off=no link, on=10 or 100 link, blink=activity)
-+ * 5-6 0 Fiber 1000 Link/Act (off=no link, on=link 1000, blink=activity)
-+ * 5-6 1 Fiber 100 Link/Act (off=no link, on=link 100, blink=activity)
-+ * 3 1-4 0 Link/Act (off=no link, on=link, blink=activity)
-+ * 1-4 1 1000 Link (off=no link, on=1000 link)
-+ * 5-6 0 Port 0's Special LED
-+ * 5-6 1 Fiber Link (off=no link, on=link)
-+ * 4 1-4 0 Port 0's Special LED
-+ * 1-4 1 Port 1's Special LED
-+ * 5-6 0 Port 1's Special LED
-+ * 5-6 1 Port 5 Link/Act (off=no link, on=link, blink=activity)
-+ * 5 1-4 0 Reserved
-+ * 1-4 1 Reserved
-+ * 5-6 0 Port 2's Special LED
-+ * 5-6 1 Port 6 Link (off=no link, on=link)
-+ * 6 1-4 0 Duplex/Collision (off=half-duplex,on=full-duplex,blink=collision)
-+ * 1-4 1 10/1000 Link/Act (off=no link, on=10 or 1000 link, blink=activity)
-+ * 5-6 0 Port 5 Duplex/Collision (off=half-duplex, on=full-duplex, blink=col)
-+ * 5-6 1 Port 6 Duplex/Collision (off=half-duplex, on=full-duplex, blink=col)
-+ * 7 1-4 0 10/1000 Link/Act (off=no link, on=10 or 1000 link, blink=activity)
-+ * 1-4 1 10/1000 Link (off=no link, on=10 or 1000 link)
-+ * 5-6 0 Port 5 Link/Act/Speed by Blink rate (off=no link, on=link, blink=activity, blink speed=link speed)
-+ * 5-6 1 Port 6 Link/Act/Speed by Blink rate (off=no link, on=link, blink=activity, blink speed=link speed)
-+ * 8 1-4 0 Link (off=no link, on=link)
-+ * 1-4 1 Activity (off=no link, blink on=activity)
-+ * 5-6 0 Port 6 Link/Act (off=no link, on=link, blink=activity)
-+ * 5-6 1 Port 0's Special LED
-+ * 9 1-4 0 10 Link (off=no link, on=10 link)
-+ * 1-4 1 100 Link (off=no link, on=100 link)
-+ * 5-6 0 Reserved
-+ * 5-6 1 Port 1's Special LED
-+ * a 1-4 0 10 Link/Act (off=no link, on=10 link, blink=activity)
-+ * 1-4 1 100 Link/Act (off=no link, on=100 link, blink=activity)
-+ * 5-6 0 Reserved
-+ * 5-6 1 Port 2's Special LED
-+ * b 1-4 0 100/1000 Link (off=no link, on=100 or 1000 link)
-+ * 1-4 1 10/100 Link (off=no link, on=100 link, blink=activity)
-+ * 5-6 0 Reserved
-+ * 5-6 1 Reserved
-+ * c * * PTP Act (blink on=PTP activity)
-+ * d * * Force Blink
-+ * e * * Force Off
-+ * f * * Force On
-+ */
-+/* Select LED0 output */
-+#define MV88E6XXX_PORT_LED_CONTROL_LED0_SEL0 0x0
-+#define MV88E6XXX_PORT_LED_CONTROL_LED0_SEL1 0x1
-+#define MV88E6XXX_PORT_LED_CONTROL_LED0_SEL2 0x2
-+#define MV88E6XXX_PORT_LED_CONTROL_LED0_SEL3 0x3
-+#define MV88E6XXX_PORT_LED_CONTROL_LED0_SEL4 0x4
-+#define MV88E6XXX_PORT_LED_CONTROL_LED0_SEL5 0x5
-+#define MV88E6XXX_PORT_LED_CONTROL_LED0_SEL6 0x6
-+#define MV88E6XXX_PORT_LED_CONTROL_LED0_SEL7 0x7
-+#define MV88E6XXX_PORT_LED_CONTROL_LED0_SEL8 0x8
-+#define MV88E6XXX_PORT_LED_CONTROL_LED0_SEL9 0x9
-+#define MV88E6XXX_PORT_LED_CONTROL_LED0_SELA 0xa
-+#define MV88E6XXX_PORT_LED_CONTROL_LED0_SELB 0xb
-+#define MV88E6XXX_PORT_LED_CONTROL_LED0_SELC 0xc
-+#define MV88E6XXX_PORT_LED_CONTROL_LED0_SELD 0xd
-+#define MV88E6XXX_PORT_LED_CONTROL_LED0_SELE 0xe
-+#define MV88E6XXX_PORT_LED_CONTROL_LED0_SELF 0xf
-+#define MV88E6XXX_PORT_LED_CONTROL_LED1_SEL0 (0x0 << 4)
-+#define MV88E6XXX_PORT_LED_CONTROL_LED1_SEL1 (0x1 << 4)
-+#define MV88E6XXX_PORT_LED_CONTROL_LED1_SEL2 (0x2 << 4)
-+#define MV88E6XXX_PORT_LED_CONTROL_LED1_SEL3 (0x3 << 4)
-+#define MV88E6XXX_PORT_LED_CONTROL_LED1_SEL4 (0x4 << 4)
-+#define MV88E6XXX_PORT_LED_CONTROL_LED1_SEL5 (0x5 << 4)
-+#define MV88E6XXX_PORT_LED_CONTROL_LED1_SEL6 (0x6 << 4)
-+#define MV88E6XXX_PORT_LED_CONTROL_LED1_SEL7 (0x7 << 4)
-+#define MV88E6XXX_PORT_LED_CONTROL_LED1_SEL8 (0x8 << 4)
-+#define MV88E6XXX_PORT_LED_CONTROL_LED1_SEL9 (0x9 << 4)
-+#define MV88E6XXX_PORT_LED_CONTROL_LED1_SELA (0xa << 4)
-+#define MV88E6XXX_PORT_LED_CONTROL_LED1_SELB (0xb << 4)
-+#define MV88E6XXX_PORT_LED_CONTROL_LED1_SELC (0xc << 4)
-+#define MV88E6XXX_PORT_LED_CONTROL_LED1_SELD (0xd << 4)
-+#define MV88E6XXX_PORT_LED_CONTROL_LED1_SELE (0xe << 4)
-+#define MV88E6XXX_PORT_LED_CONTROL_LED1_SELF (0xf << 4)
-+/* Stretch and Blink Rate Control (Index 0x06 of LED Control) */
-+/* Pulse Stretch Selection for all LED's on this port */
-+#define MV88E6XXX_PORT_LED_CONTROL_0x06_PULSE_STRETCH_NONE (0 << 4)
-+#define MV88E6XXX_PORT_LED_CONTROL_0x06_PULSE_STRETCH_21MS (1 << 4)
-+#define MV88E6XXX_PORT_LED_CONTROL_0x06_PULSE_STRETCH_42MS (2 << 4)
-+#define MV88E6XXX_PORT_LED_CONTROL_0x06_PULSE_STRETCH_84MS (3 << 4)
-+#define MV88E6XXX_PORT_LED_CONTROL_0x06_PULSE_STRETCH_168MS (4 << 4)
-+/* Blink Rate Selection for all LEDs on this port */
-+#define MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_21MS 0
-+#define MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_42MS 1
-+#define MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_84MS 2
-+#define MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_168MS 3
-+#define MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_336MS 4
-+#define MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_672MS 5
-+ /* Control for Special LED (Index 0x7 of LED Control on Port0) */
-+#define MV88E6XXX_PORT_LED_CONTROL_0x07_P0_LAN_LINKACT_SHIFT 0 /* bits 6:0 LAN Link Activity LED */
-+/* Control for Special LED (Index 0x7 of LED Control on Port 1) */
-+#define MV88E6XXX_PORT_LED_CONTROL_0x07_P1_WAN_LINKACT_SHIFT 0 /* bits 6:0 WAN Link Activity LED */
-+/* Control for Special LED (Index 0x7 of LED Control on Port 2) */
-+#define MV88E6XXX_PORT_LED_CONTROL_0x07_P2_PTP_ACT 0 /* bits 6:0 PTP Activity */
-+
- /* Offset 0x18: IEEE Priority Mapping Table */
- #define MV88E6390_PORT_IEEE_PRIO_MAP_TABLE 0x18
- #define MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_UPDATE 0x8000
-@@ -457,6 +581,15 @@ int mv88e6393x_port_set_cmode(struct mv8
- phy_interface_t mode);
- int mv88e6185_port_get_cmode(struct mv88e6xxx_chip *chip, int port, u8 *cmode);
- int mv88e6352_port_get_cmode(struct mv88e6xxx_chip *chip, int port, u8 *cmode);
-+#ifdef CONFIG_NET_DSA_MV88E6XXX_LEDS
-+int mv88e6xxx_port_setup_leds(struct mv88e6xxx_chip *chip, int port);
-+#else
-+static inline int mv88e6xxx_port_setup_leds(struct mv88e6xxx_chip *chip,
-+ int port)
-+{
-+ return 0;
-+}
-+#endif
- int mv88e6xxx_port_drop_untagged(struct mv88e6xxx_chip *chip, int port,
- bool drop_untagged);
- int mv88e6xxx_port_set_map_da(struct mv88e6xxx_chip *chip, int port, bool map);
+++ /dev/null
-From 6a9eb32230f33ae273f6ffbabb0aaf560869816e Mon Sep 17 00:00:00 2001
-Date: Mon, 29 Apr 2024 11:23:09 -0700
-Subject: [PATCH] Bluetooth: btsdio: Do not bind to non-removable CYW4373
-
-CYW4373 devices soldered onto the PCB (non-removable),
-use a UART connection for Bluetooth and the advertised btsdio
-support as an SDIO function should be ignored.
-
----
- drivers/bluetooth/btsdio.c | 1 +
- 1 file changed, 1 insertion(+)
-
---- a/drivers/bluetooth/btsdio.c
-+++ b/drivers/bluetooth/btsdio.c
-@@ -295,6 +295,7 @@ static int btsdio_probe(struct sdio_func
- case SDIO_DEVICE_ID_BROADCOM_4345:
- case SDIO_DEVICE_ID_BROADCOM_43455:
- case SDIO_DEVICE_ID_BROADCOM_4356:
-+ case SDIO_DEVICE_ID_BROADCOM_CYPRESS_4373:
- return -ENODEV;
- }
- }
+++ /dev/null
-From 04597c8dd6c4b55e946fec50dc3b14a5d9d54501 Mon Sep 17 00:00:00 2001
-Date: Thu, 21 Sep 2023 13:48:11 +0200
-Subject: [PATCH] crypto: jitter - add RCT/APT support for different OSRs
-
-The oversampling rate (OSR) value specifies the heuristically implied
-entropy in the recorded data - H_submitter = 1/osr. A different entropy
-estimate implies a different APT/RCT cutoff value. This change adds
-support for OSRs 1 through 15. This OSR can be selected by the caller
-of the Jitter RNG.
-
-For this patch, the caller still uses one hard-coded OSR. A subsequent
-patch allows this value to be configured.
-
-In addition, the power-up self test is adjusted as follows:
-
-* It allows the caller to provide an oversampling rate that should be
-tested with - commonly it should be the same as used for the actual
-runtime operation. This makes the power-up testing therefore consistent
-with the runtime operation.
-
-* It calls now jent_measure_jitter (i.e. collects the full entropy
-that can possibly be harvested by the Jitter RNG) instead of only
-jent_condition_data (which only returns the entropy harvested from
-the conditioning component). This should now alleviate reports where
-the Jitter RNG initialization thinks there is too little entropy.
-
-* The power-up test now solely relies on the (enhanced) APT and RCT
-test that is used as a health test at runtime.
-
-The code allowing the different OSRs as well as the power-up test
-changes are present in the user space version of the Jitter RNG 3.4.1
-and thus was already in production use for some time.
-
----
- crypto/jitterentropy-kcapi.c | 4 +-
- crypto/jitterentropy.c | 233 ++++++++++++++++++-----------------
- crypto/jitterentropy.h | 3 +-
- 3 files changed, 123 insertions(+), 117 deletions(-)
-
---- a/crypto/jitterentropy-kcapi.c
-+++ b/crypto/jitterentropy-kcapi.c
-@@ -246,7 +246,7 @@ static int jent_kcapi_init(struct crypto
- crypto_shash_init(sdesc);
- rng->sdesc = sdesc;
-
-- rng->entropy_collector = jent_entropy_collector_alloc(1, 0, sdesc);
-+ rng->entropy_collector = jent_entropy_collector_alloc(0, 0, sdesc);
- if (!rng->entropy_collector) {
- ret = -ENOMEM;
- goto err;
-@@ -335,7 +335,7 @@ static int __init jent_mod_init(void)
-
- desc->tfm = tfm;
- crypto_shash_init(desc);
-- ret = jent_entropy_init(desc);
-+ ret = jent_entropy_init(0, 0, desc);
- shash_desc_zero(desc);
- crypto_free_shash(tfm);
- if (ret) {
---- a/crypto/jitterentropy.c
-+++ b/crypto/jitterentropy.c
-@@ -72,6 +72,8 @@ struct rand_data {
- __u64 prev_time; /* SENSITIVE Previous time stamp */
- __u64 last_delta; /* SENSITIVE stuck test */
- __s64 last_delta2; /* SENSITIVE stuck test */
-+
-+ unsigned int flags; /* Flags used to initialize */
- unsigned int osr; /* Oversample rate */
- #define JENT_MEMORY_BLOCKS 64
- #define JENT_MEMORY_BLOCKSIZE 32
-@@ -88,16 +90,9 @@ struct rand_data {
- /* Repetition Count Test */
- unsigned int rct_count; /* Number of stuck values */
-
-- /* Intermittent health test failure threshold of 2^-30 */
-- /* From an SP800-90B perspective, this RCT cutoff value is equal to 31. */
-- /* However, our RCT implementation starts at 1, so we subtract 1 here. */
--#define JENT_RCT_CUTOFF (31 - 1) /* Taken from SP800-90B sec 4.4.1 */
--#define JENT_APT_CUTOFF 325 /* Taken from SP800-90B sec 4.4.2 */
-- /* Permanent health test failure threshold of 2^-60 */
-- /* From an SP800-90B perspective, this RCT cutoff value is equal to 61. */
-- /* However, our RCT implementation starts at 1, so we subtract 1 here. */
--#define JENT_RCT_CUTOFF_PERMANENT (61 - 1)
--#define JENT_APT_CUTOFF_PERMANENT 355
-+ /* Adaptive Proportion Test cutoff values */
-+ unsigned int apt_cutoff; /* Intermittent health test failure */
-+ unsigned int apt_cutoff_permanent; /* Permanent health test failure */
- #define JENT_APT_WINDOW_SIZE 512 /* Data window size */
- /* LSB of time stamp to process */
- #define JENT_APT_LSB 16
-@@ -122,6 +117,9 @@ struct rand_data {
- * zero). */
- #define JENT_ESTUCK 8 /* Too many stuck results during init. */
- #define JENT_EHEALTH 9 /* Health test failed during initialization */
-+#define JENT_ERCT 10 /* RCT failed during initialization */
-+#define JENT_EHASH 11 /* Hash self test failed */
-+#define JENT_EMEM 12 /* Can't allocate memory for initialization */
-
- /*
- * The output n bits can receive more than n bits of min entropy, of course,
-@@ -148,6 +146,48 @@ struct rand_data {
- ***************************************************************************/
-
- /*
-+ * See the SP 800-90B comment #10b for the corrected cutoff for the SP 800-90B
-+ * APT.
-+ * http://www.untruth.org/~josh/sp80090b/UL%20SP800-90B-final%20comments%20v1.9%2020191212.pdf
-+ * In in the syntax of R, this is C = 2 + qbinom(1 − 2^(−30), 511, 2^(-1/osr)).
-+ * (The original formula wasn't correct because the first symbol must
-+ * necessarily have been observed, so there is no chance of observing 0 of these
-+ * symbols.)
-+ *
-+ * For the alpha < 2^-53, R cannot be used as it uses a float data type without
-+ * arbitrary precision. A SageMath script is used to calculate those cutoff
-+ * values.
-+ *
-+ * For any value above 14, this yields the maximal allowable value of 512
-+ * (by FIPS 140-2 IG 7.19 Resolution # 16, we cannot choose a cutoff value that
-+ * renders the test unable to fail).
-+ */
-+static const unsigned int jent_apt_cutoff_lookup[15] = {
-+ 325, 422, 459, 477, 488, 494, 499, 502,
-+ 505, 507, 508, 509, 510, 511, 512 };
-+static const unsigned int jent_apt_cutoff_permanent_lookup[15] = {
-+ 355, 447, 479, 494, 502, 507, 510, 512,
-+ 512, 512, 512, 512, 512, 512, 512 };
-+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
-+
-+static void jent_apt_init(struct rand_data *ec, unsigned int osr)
-+{
-+ /*
-+ * Establish the apt_cutoff based on the presumed entropy rate of
-+ * 1/osr.
-+ */
-+ if (osr >= ARRAY_SIZE(jent_apt_cutoff_lookup)) {
-+ ec->apt_cutoff = jent_apt_cutoff_lookup[
-+ ARRAY_SIZE(jent_apt_cutoff_lookup) - 1];
-+ ec->apt_cutoff_permanent = jent_apt_cutoff_permanent_lookup[
-+ ARRAY_SIZE(jent_apt_cutoff_permanent_lookup) - 1];
-+ } else {
-+ ec->apt_cutoff = jent_apt_cutoff_lookup[osr - 1];
-+ ec->apt_cutoff_permanent =
-+ jent_apt_cutoff_permanent_lookup[osr - 1];
-+ }
-+}
-+/*
- * Reset the APT counter
- *
- * @ec [in] Reference to entropy collector
-@@ -187,12 +227,12 @@ static void jent_apt_insert(struct rand_
- /* APT health test failure detection */
- static int jent_apt_permanent_failure(struct rand_data *ec)
- {
-- return (ec->apt_count >= JENT_APT_CUTOFF_PERMANENT) ? 1 : 0;
-+ return (ec->apt_count >= ec->apt_cutoff_permanent) ? 1 : 0;
- }
-
- static int jent_apt_failure(struct rand_data *ec)
- {
-- return (ec->apt_count >= JENT_APT_CUTOFF) ? 1 : 0;
-+ return (ec->apt_count >= ec->apt_cutoff) ? 1 : 0;
- }
-
- /***************************************************************************
-@@ -275,15 +315,28 @@ static int jent_stuck(struct rand_data *
- return 0;
- }
-
--/* RCT health test failure detection */
-+/*
-+ * The cutoff value is based on the following consideration:
-+ * alpha = 2^-30 or 2^-60 as recommended in SP800-90B.
-+ * In addition, we require an entropy value H of 1/osr as this is the minimum
-+ * entropy required to provide full entropy.
-+ * Note, we collect (DATA_SIZE_BITS + ENTROPY_SAFETY_FACTOR)*osr deltas for
-+ * inserting them into the entropy pool which should then have (close to)
-+ * DATA_SIZE_BITS bits of entropy in the conditioned output.
-+ *
-+ * Note, ec->rct_count (which equals to value B in the pseudo code of SP800-90B
-+ * section 4.4.1) starts with zero. Hence we need to subtract one from the
-+ * cutoff value as calculated following SP800-90B. Thus
-+ * C = ceil(-log_2(alpha)/H) = 30*osr or 60*osr.
-+ */
- static int jent_rct_permanent_failure(struct rand_data *ec)
- {
-- return (ec->rct_count >= JENT_RCT_CUTOFF_PERMANENT) ? 1 : 0;
-+ return (ec->rct_count >= (60 * ec->osr)) ? 1 : 0;
- }
-
- static int jent_rct_failure(struct rand_data *ec)
- {
-- return (ec->rct_count >= JENT_RCT_CUTOFF) ? 1 : 0;
-+ return (ec->rct_count >= (30 * ec->osr)) ? 1 : 0;
- }
-
- /* Report of health test failures */
-@@ -448,7 +501,7 @@ static void jent_memaccess(struct rand_d
- *
- * @return result of stuck test
- */
--static int jent_measure_jitter(struct rand_data *ec)
-+static int jent_measure_jitter(struct rand_data *ec, __u64 *ret_current_delta)
- {
- __u64 time = 0;
- __u64 current_delta = 0;
-@@ -472,6 +525,10 @@ static int jent_measure_jitter(struct ra
- if (jent_condition_data(ec, current_delta, stuck))
- stuck = 1;
-
-+ /* return the raw entropy value */
-+ if (ret_current_delta)
-+ *ret_current_delta = current_delta;
-+
- return stuck;
- }
-
-@@ -489,11 +546,11 @@ static void jent_gen_entropy(struct rand
- safety_factor = JENT_ENTROPY_SAFETY_FACTOR;
-
- /* priming of the ->prev_time value */
-- jent_measure_jitter(ec);
-+ jent_measure_jitter(ec, NULL);
-
- while (!jent_health_failure(ec)) {
- /* If a stuck measurement is received, repeat measurement */
-- if (jent_measure_jitter(ec))
-+ if (jent_measure_jitter(ec, NULL))
- continue;
-
- /*
-@@ -554,7 +611,8 @@ int jent_read_entropy(struct rand_data *
- * Perform startup health tests and return permanent
- * error if it fails.
- */
-- if (jent_entropy_init(ec->hash_state))
-+ if (jent_entropy_init(ec->osr, ec->flags,
-+ ec->hash_state))
- return -3;
-
- return -2;
-@@ -604,11 +662,15 @@ struct rand_data *jent_entropy_collector
-
- /* verify and set the oversampling rate */
- if (osr == 0)
-- osr = 1; /* minimum sampling rate is 1 */
-+ osr = 1; /* H_submitter = 1 / osr */
- entropy_collector->osr = osr;
-+ entropy_collector->flags = flags;
-
- entropy_collector->hash_state = hash_state;
-
-+ /* Initialize the APT */
-+ jent_apt_init(entropy_collector, osr);
-+
- /* fill the data pad with non-zero values */
- jent_gen_entropy(entropy_collector);
-
-@@ -622,20 +684,14 @@ void jent_entropy_collector_free(struct
- jent_zfree(entropy_collector);
- }
-
--int jent_entropy_init(void *hash_state)
-+int jent_entropy_init(unsigned int osr, unsigned int flags, void *hash_state)
- {
-- int i;
-- __u64 delta_sum = 0;
-- __u64 old_delta = 0;
-- unsigned int nonstuck = 0;
-- int time_backwards = 0;
-- int count_mod = 0;
-- int count_stuck = 0;
-- struct rand_data ec = { 0 };
--
-- /* Required for RCT */
-- ec.osr = 1;
-- ec.hash_state = hash_state;
-+ struct rand_data *ec;
-+ int i, time_backwards = 0, ret = 0;
-+
-+ ec = jent_entropy_collector_alloc(osr, flags, hash_state);
-+ if (!ec)
-+ return JENT_EMEM;
-
- /* We could perform statistical tests here, but the problem is
- * that we only have a few loop counts to do testing. These
-@@ -664,31 +720,28 @@ int jent_entropy_init(void *hash_state)
- #define TESTLOOPCOUNT 1024
- #define CLEARCACHE 100
- for (i = 0; (TESTLOOPCOUNT + CLEARCACHE) > i; i++) {
-- __u64 time = 0;
-- __u64 time2 = 0;
-- __u64 delta = 0;
-- unsigned int lowdelta = 0;
-- int stuck;
-+ __u64 start_time = 0, end_time = 0, delta = 0;
-
- /* Invoke core entropy collection logic */
-- jent_get_nstime(&time);
-- ec.prev_time = time;
-- jent_condition_data(&ec, time, 0);
-- jent_get_nstime(&time2);
-+ jent_measure_jitter(ec, &delta);
-+ end_time = ec->prev_time;
-+ start_time = ec->prev_time - delta;
-
- /* test whether timer works */
-- if (!time || !time2)
-- return JENT_ENOTIME;
-- delta = jent_delta(time, time2);
-+ if (!start_time || !end_time) {
-+ ret = JENT_ENOTIME;
-+ goto out;
-+ }
-+
- /*
- * test whether timer is fine grained enough to provide
- * delta even when called shortly after each other -- this
- * implies that we also have a high resolution timer
- */
-- if (!delta)
-- return JENT_ECOARSETIME;
--
-- stuck = jent_stuck(&ec, delta);
-+ if (!delta || (end_time == start_time)) {
-+ ret = JENT_ECOARSETIME;
-+ goto out;
-+ }
-
- /*
- * up to here we did not modify any variable that will be
-@@ -700,49 +753,9 @@ int jent_entropy_init(void *hash_state)
- if (i < CLEARCACHE)
- continue;
-
-- if (stuck)
-- count_stuck++;
-- else {
-- nonstuck++;
--
-- /*
-- * Ensure that the APT succeeded.
-- *
-- * With the check below that count_stuck must be less
-- * than 10% of the overall generated raw entropy values
-- * it is guaranteed that the APT is invoked at
-- * floor((TESTLOOPCOUNT * 0.9) / 64) == 14 times.
-- */
-- if ((nonstuck % JENT_APT_WINDOW_SIZE) == 0) {
-- jent_apt_reset(&ec,
-- delta & JENT_APT_WORD_MASK);
-- }
-- }
--
-- /* Validate health test result */
-- if (jent_health_failure(&ec))
-- return JENT_EHEALTH;
--
- /* test whether we have an increasing timer */
-- if (!(time2 > time))
-+ if (!(end_time > start_time))
- time_backwards++;
--
-- /* use 32 bit value to ensure compilation on 32 bit arches */
-- lowdelta = time2 - time;
-- if (!(lowdelta % 100))
-- count_mod++;
--
-- /*
-- * ensure that we have a varying delta timer which is necessary
-- * for the calculation of entropy -- perform this check
-- * only after the first loop is executed as we need to prime
-- * the old_data value
-- */
-- if (delta > old_delta)
-- delta_sum += (delta - old_delta);
-- else
-- delta_sum += (old_delta - delta);
-- old_delta = delta;
- }
-
- /*
-@@ -752,31 +765,23 @@ int jent_entropy_init(void *hash_state)
- * should not fail. The value of 3 should cover the NTP case being
- * performed during our test run.
- */
-- if (time_backwards > 3)
-- return JENT_ENOMONOTONIC;
--
-- /*
-- * Variations of deltas of time must on average be larger
-- * than 1 to ensure the entropy estimation
-- * implied with 1 is preserved
-- */
-- if ((delta_sum) <= 1)
-- return JENT_EVARVAR;
-+ if (time_backwards > 3) {
-+ ret = JENT_ENOMONOTONIC;
-+ goto out;
-+ }
-
-- /*
-- * Ensure that we have variations in the time stamp below 10 for at
-- * least 10% of all checks -- on some platforms, the counter increments
-- * in multiples of 100, but not always
-- */
-- if ((TESTLOOPCOUNT/10 * 9) < count_mod)
-- return JENT_ECOARSETIME;
-+ /* Did we encounter a health test failure? */
-+ if (jent_rct_failure(ec)) {
-+ ret = JENT_ERCT;
-+ goto out;
-+ }
-+ if (jent_apt_failure(ec)) {
-+ ret = JENT_EHEALTH;
-+ goto out;
-+ }
-
-- /*
-- * If we have more than 90% stuck results, then this Jitter RNG is
-- * likely to not work well.
-- */
-- if ((TESTLOOPCOUNT/10 * 9) < count_stuck)
-- return JENT_ESTUCK;
-+out:
-+ jent_entropy_collector_free(ec);
-
-- return 0;
-+ return ret;
- }
---- a/crypto/jitterentropy.h
-+++ b/crypto/jitterentropy.h
-@@ -9,7 +9,8 @@ extern int jent_hash_time(void *hash_sta
- int jent_read_random_block(void *hash_state, char *dst, unsigned int dst_len);
-
- struct rand_data;
--extern int jent_entropy_init(void *hash_state);
-+extern int jent_entropy_init(unsigned int osr, unsigned int flags,
-+ void *hash_state);
- extern int jent_read_entropy(struct rand_data *ec, unsigned char *data,
- unsigned int len);
-
+++ /dev/null
-From 59bcfd788552504606e3eb774ae68052379396b6 Mon Sep 17 00:00:00 2001
-Date: Thu, 21 Sep 2023 13:48:33 +0200
-Subject: [PATCH] crypto: jitter - Allow configuration of memory size
-
-The memory size consumed by the Jitter RNG is one contributing factor in
-the amount of entropy that is gathered. As the amount of entropy
-directly correlates with the distance of the memory from the CPU, the
-caches that are possibly present on a given system have an impact on the
-collected entropy.
-
-Thus, the kernel compile time should offer a means to configure the
-amount of memory used by the Jitter RNG. Although this option could be
-turned into a runtime option (e.g. a kernel command line option), it
-should remain a compile time option as otherwise adminsitrators who may
-not have performed an entropy assessment may select a value that is
-inappropriate.
-
-The default value selected by the configuration is identical to the
-current Jitter RNG value. Thus, the patch should not lead to any change
-in the Jitter RNG behavior.
-
-To accommodate larger memory buffers, kvzalloc / kvfree is used.
-
----
- crypto/Kconfig | 43 ++++++++++++++++++++++++++++++++++++
- crypto/jitterentropy-kcapi.c | 11 +++++++++
- crypto/jitterentropy.c | 16 ++++++++------
- crypto/jitterentropy.h | 2 ++
- 4 files changed, 65 insertions(+), 7 deletions(-)
-
---- a/crypto/Kconfig
-+++ b/crypto/Kconfig
-@@ -1297,6 +1297,49 @@ config CRYPTO_JITTERENTROPY
-
- See https://www.chronox.de/jent/
-
-+choice
-+ prompt "CPU Jitter RNG Memory Size"
-+ default CRYPTO_JITTERENTROPY_MEMSIZE_2
-+ depends on CRYPTO_JITTERENTROPY
-+ help
-+ The Jitter RNG measures the execution time of memory accesses.
-+ Multiple consecutive memory accesses are performed. If the memory
-+ size fits into a cache (e.g. L1), only the memory access timing
-+ to that cache is measured. The closer the cache is to the CPU
-+ the less variations are measured and thus the less entropy is
-+ obtained. Thus, if the memory size fits into the L1 cache, the
-+ obtained entropy is less than if the memory size fits within
-+ L1 + L2, which in turn is less if the memory fits into
-+ L1 + L2 + L3. Thus, by selecting a different memory size,
-+ the entropy rate produced by the Jitter RNG can be modified.
-+
-+ config CRYPTO_JITTERENTROPY_MEMSIZE_2
-+ bool "2048 Bytes (default)"
-+
-+ config CRYPTO_JITTERENTROPY_MEMSIZE_128
-+ bool "128 kBytes"
-+
-+ config CRYPTO_JITTERENTROPY_MEMSIZE_1024
-+ bool "1024 kBytes"
-+
-+ config CRYPTO_JITTERENTROPY_MEMSIZE_8192
-+ bool "8192 kBytes"
-+endchoice
-+
-+config CRYPTO_JITTERENTROPY_MEMORY_BLOCKS
-+ int
-+ default 64 if CRYPTO_JITTERENTROPY_MEMSIZE_2
-+ default 512 if CRYPTO_JITTERENTROPY_MEMSIZE_128
-+ default 1024 if CRYPTO_JITTERENTROPY_MEMSIZE_1024
-+ default 4096 if CRYPTO_JITTERENTROPY_MEMSIZE_8192
-+
-+config CRYPTO_JITTERENTROPY_MEMORY_BLOCKSIZE
-+ int
-+ default 32 if CRYPTO_JITTERENTROPY_MEMSIZE_2
-+ default 256 if CRYPTO_JITTERENTROPY_MEMSIZE_128
-+ default 1024 if CRYPTO_JITTERENTROPY_MEMSIZE_1024
-+ default 2048 if CRYPTO_JITTERENTROPY_MEMSIZE_8192
-+
- config CRYPTO_JITTERENTROPY_TESTINTERFACE
- bool "CPU Jitter RNG Test Interface"
- depends on CRYPTO_JITTERENTROPY
---- a/crypto/jitterentropy-kcapi.c
-+++ b/crypto/jitterentropy-kcapi.c
-@@ -54,6 +54,17 @@
- * Helper function
- ***************************************************************************/
-
-+void *jent_kvzalloc(unsigned int len)
-+{
-+ return kvzalloc(len, GFP_KERNEL);
-+}
-+
-+void jent_kvzfree(void *ptr, unsigned int len)
-+{
-+ memzero_explicit(ptr, len);
-+ kvfree(ptr);
-+}
-+
- void *jent_zalloc(unsigned int len)
- {
- return kzalloc(len, GFP_KERNEL);
---- a/crypto/jitterentropy.c
-+++ b/crypto/jitterentropy.c
-@@ -75,10 +75,10 @@ struct rand_data {
-
- unsigned int flags; /* Flags used to initialize */
- unsigned int osr; /* Oversample rate */
--#define JENT_MEMORY_BLOCKS 64
--#define JENT_MEMORY_BLOCKSIZE 32
- #define JENT_MEMORY_ACCESSLOOPS 128
--#define JENT_MEMORY_SIZE (JENT_MEMORY_BLOCKS*JENT_MEMORY_BLOCKSIZE)
-+#define JENT_MEMORY_SIZE \
-+ (CONFIG_CRYPTO_JITTERENTROPY_MEMORY_BLOCKS * \
-+ CONFIG_CRYPTO_JITTERENTROPY_MEMORY_BLOCKSIZE)
- unsigned char *mem; /* Memory access location with size of
- * memblocks * memblocksize */
- unsigned int memlocation; /* Pointer to byte in *mem */
-@@ -650,13 +650,15 @@ struct rand_data *jent_entropy_collector
- /* Allocate memory for adding variations based on memory
- * access
- */
-- entropy_collector->mem = jent_zalloc(JENT_MEMORY_SIZE);
-+ entropy_collector->mem = jent_kvzalloc(JENT_MEMORY_SIZE);
- if (!entropy_collector->mem) {
- jent_zfree(entropy_collector);
- return NULL;
- }
-- entropy_collector->memblocksize = JENT_MEMORY_BLOCKSIZE;
-- entropy_collector->memblocks = JENT_MEMORY_BLOCKS;
-+ entropy_collector->memblocksize =
-+ CONFIG_CRYPTO_JITTERENTROPY_MEMORY_BLOCKSIZE;
-+ entropy_collector->memblocks =
-+ CONFIG_CRYPTO_JITTERENTROPY_MEMORY_BLOCKS;
- entropy_collector->memaccessloops = JENT_MEMORY_ACCESSLOOPS;
- }
-
-@@ -679,7 +681,7 @@ struct rand_data *jent_entropy_collector
-
- void jent_entropy_collector_free(struct rand_data *entropy_collector)
- {
-- jent_zfree(entropy_collector->mem);
-+ jent_kvzfree(entropy_collector->mem, JENT_MEMORY_SIZE);
- entropy_collector->mem = NULL;
- jent_zfree(entropy_collector);
- }
---- a/crypto/jitterentropy.h
-+++ b/crypto/jitterentropy.h
-@@ -1,5 +1,7 @@
- // SPDX-License-Identifier: GPL-2.0-or-later
-
-+extern void *jent_kvzalloc(unsigned int len);
-+extern void jent_kvzfree(void *ptr, unsigned int len);
- extern void *jent_zalloc(unsigned int len);
- extern void jent_zfree(void *ptr);
- extern void jent_get_nstime(__u64 *out);
+++ /dev/null
-From 0baa8fab334a4d7017235b72fa8a547433572109 Mon Sep 17 00:00:00 2001
-Date: Thu, 21 Sep 2023 13:48:59 +0200
-Subject: [PATCH] crypto: jitter - Allow configuration of oversampling rate
-
-The oversampling rate used by the Jitter RNG allows the configuration of
-the heuristically implied entropy in one timing measurement. This
-entropy rate is (1 / OSR) bits of entropy per time stamp.
-
-Considering that the Jitter RNG now support APT/RCT health tests for
-different OSRs, allow this value to be configured at compile time to
-support systems with limited amount of entropy in their timer.
-
-The allowed range of OSR values complies with the APT/RCT cutoff health
-test values which range from 1 through 15.
-
-The default value of the OSR selection support is left at 1 which is the
-current default. Thus, the addition of the configuration support does
-not alter the default Jitter RNG behavior.
-
----
- crypto/Kconfig | 17 +++++++++++++++++
- crypto/jitterentropy-kcapi.c | 6 ++++--
- 2 files changed, 21 insertions(+), 2 deletions(-)
-
---- a/crypto/Kconfig
-+++ b/crypto/Kconfig
-@@ -1340,6 +1340,23 @@ config CRYPTO_JITTERENTROPY_MEMORY_BLOCK
- default 1024 if CRYPTO_JITTERENTROPY_MEMSIZE_1024
- default 2048 if CRYPTO_JITTERENTROPY_MEMSIZE_8192
-
-+config CRYPTO_JITTERENTROPY_OSR
-+ int "CPU Jitter RNG Oversampling Rate"
-+ range 1 15
-+ default 1
-+ depends on CRYPTO_JITTERENTROPY
-+ help
-+ The Jitter RNG allows the specification of an oversampling rate (OSR).
-+ The Jitter RNG operation requires a fixed amount of timing
-+ measurements to produce one output block of random numbers. The
-+ OSR value is multiplied with the amount of timing measurements to
-+ generate one output block. Thus, the timing measurement is oversampled
-+ by the OSR factor. The oversampling allows the Jitter RNG to operate
-+ on hardware whose timers deliver limited amount of entropy (e.g.
-+ the timer is coarse) by setting the OSR to a higher value. The
-+ trade-off, however, is that the Jitter RNG now requires more time
-+ to generate random numbers.
-+
- config CRYPTO_JITTERENTROPY_TESTINTERFACE
- bool "CPU Jitter RNG Test Interface"
- depends on CRYPTO_JITTERENTROPY
---- a/crypto/jitterentropy-kcapi.c
-+++ b/crypto/jitterentropy-kcapi.c
-@@ -257,7 +257,9 @@ static int jent_kcapi_init(struct crypto
- crypto_shash_init(sdesc);
- rng->sdesc = sdesc;
-
-- rng->entropy_collector = jent_entropy_collector_alloc(0, 0, sdesc);
-+ rng->entropy_collector =
-+ jent_entropy_collector_alloc(CONFIG_CRYPTO_JITTERENTROPY_OSR, 0,
-+ sdesc);
- if (!rng->entropy_collector) {
- ret = -ENOMEM;
- goto err;
-@@ -346,7 +348,7 @@ static int __init jent_mod_init(void)
-
- desc->tfm = tfm;
- crypto_shash_init(desc);
-- ret = jent_entropy_init(0, 0, desc);
-+ ret = jent_entropy_init(CONFIG_CRYPTO_JITTERENTROPY_OSR, 0, desc);
- shash_desc_zero(desc);
- crypto_free_shash(tfm);
- if (ret) {
+++ /dev/null
-From 8405ec8e3c02df8b3720874c3e2169fef4553868 Mon Sep 17 00:00:00 2001
-Date: Sat, 7 Oct 2023 09:10:43 +0200
-Subject: [PATCH] crypto: jitter - reuse allocated entropy collector
-
-In case a health test error occurs during runtime, the power-up health
-tests are rerun to verify that the noise source is still good and
-that the reported health test error was an outlier. For performing this
-power-up health test, the already existing entropy collector instance
-is used instead of allocating a new one. This change has the following
-implications:
-
-* The noise that is collected as part of the newly run health tests is
- inserted into the entropy collector and thus stirs the existing
- data present in there further. Thus, the entropy collected during
- the health test is not wasted. This is also allowed by SP800-90B.
-
-* The power-on health test is not affected by the state of the entropy
- collector, because it resets the APT / RCT state. The remainder of
- the state is unrelated to the health test as it is only applied to
- newly obtained time stamps.
-
-This change also fixes a bug report about an allocation while in an
-atomic lock (the lock is taken in jent_kcapi_random, jent_read_entropy
-is called and this can call jent_entropy_init).
-
-Fixes: 04597c8dd6c4 ("jitter - add RCT/APT support for different OSRs")
----
- crypto/jitterentropy-kcapi.c | 2 +-
- crypto/jitterentropy.c | 36 ++++++++++++++++++++++++++----------
- crypto/jitterentropy.h | 2 +-
- 3 files changed, 28 insertions(+), 12 deletions(-)
-
---- a/crypto/jitterentropy-kcapi.c
-+++ b/crypto/jitterentropy-kcapi.c
-@@ -348,7 +348,7 @@ static int __init jent_mod_init(void)
-
- desc->tfm = tfm;
- crypto_shash_init(desc);
-- ret = jent_entropy_init(CONFIG_CRYPTO_JITTERENTROPY_OSR, 0, desc);
-+ ret = jent_entropy_init(CONFIG_CRYPTO_JITTERENTROPY_OSR, 0, desc, NULL);
- shash_desc_zero(desc);
- crypto_free_shash(tfm);
- if (ret) {
---- a/crypto/jitterentropy.c
-+++ b/crypto/jitterentropy.c
-@@ -611,8 +611,7 @@ int jent_read_entropy(struct rand_data *
- * Perform startup health tests and return permanent
- * error if it fails.
- */
-- if (jent_entropy_init(ec->osr, ec->flags,
-- ec->hash_state))
-+ if (jent_entropy_init(0, 0, NULL, ec))
- return -3;
-
- return -2;
-@@ -686,14 +685,30 @@ void jent_entropy_collector_free(struct
- jent_zfree(entropy_collector);
- }
-
--int jent_entropy_init(unsigned int osr, unsigned int flags, void *hash_state)
-+int jent_entropy_init(unsigned int osr, unsigned int flags, void *hash_state,
-+ struct rand_data *p_ec)
- {
-- struct rand_data *ec;
-- int i, time_backwards = 0, ret = 0;
-+ /*
-+ * If caller provides an allocated ec, reuse it which implies that the
-+ * health test entropy data is used to further still the available
-+ * entropy pool.
-+ */
-+ struct rand_data *ec = p_ec;
-+ int i, time_backwards = 0, ret = 0, ec_free = 0;
-
-- ec = jent_entropy_collector_alloc(osr, flags, hash_state);
-- if (!ec)
-- return JENT_EMEM;
-+ if (!ec) {
-+ ec = jent_entropy_collector_alloc(osr, flags, hash_state);
-+ if (!ec)
-+ return JENT_EMEM;
-+ ec_free = 1;
-+ } else {
-+ /* Reset the APT */
-+ jent_apt_reset(ec, 0);
-+ /* Ensure that a new APT base is obtained */
-+ ec->apt_base_set = 0;
-+ /* Reset the RCT */
-+ ec->rct_count = 0;
-+ }
-
- /* We could perform statistical tests here, but the problem is
- * that we only have a few loop counts to do testing. These
-@@ -783,7 +798,8 @@ int jent_entropy_init(unsigned int osr,
- }
-
- out:
-- jent_entropy_collector_free(ec);
-+ if (ec_free)
-+ jent_entropy_collector_free(ec);
-
- return ret;
- }
---- a/crypto/jitterentropy.h
-+++ b/crypto/jitterentropy.h
-@@ -12,7 +12,7 @@ int jent_read_random_block(void *hash_st
-
- struct rand_data;
- extern int jent_entropy_init(unsigned int osr, unsigned int flags,
-- void *hash_state);
-+ void *hash_state, struct rand_data *p_ec);
- extern int jent_read_entropy(struct rand_data *ec, unsigned char *data,
- unsigned int len);
-
+++ /dev/null
-From cf27d9475f37fb69b5bc293e6e6d6c1d03cf7cc6 Mon Sep 17 00:00:00 2001
-Date: Thu, 19 Oct 2023 09:40:42 +0200
-Subject: [PATCH] crypto: jitter - use permanent health test storage
-
-The health test result in the current code is only given for the currently
-processed raw time stamp. This implies to react on the health test error,
-the result must be checked after each raw time stamp being processed. To
-avoid this constant checking requirement, any health test error is recorded
-and stored to be analyzed at a later time, if needed.
-
-This change ensures that the power-up test catches any health test error.
-Without that patch, the power-up health test result is not enforced.
-
-The introduced changes are already in use with the user space version of
-the Jitter RNG.
-
-Fixes: 04597c8dd6c4 ("jitter - add RCT/APT support for different OSRs")
----
- crypto/jitterentropy.c | 125 ++++++++++++++++++++++++-----------------
- 1 file changed, 74 insertions(+), 51 deletions(-)
-
---- a/crypto/jitterentropy.c
-+++ b/crypto/jitterentropy.c
-@@ -100,6 +100,8 @@ struct rand_data {
- unsigned int apt_observations; /* Number of collected observations */
- unsigned int apt_count; /* APT counter */
- unsigned int apt_base; /* APT base reference */
-+ unsigned int health_failure; /* Record health failure */
-+
- unsigned int apt_base_set:1; /* APT base reference set? */
- };
-
-@@ -121,6 +123,13 @@ struct rand_data {
- #define JENT_EHASH 11 /* Hash self test failed */
- #define JENT_EMEM 12 /* Can't allocate memory for initialization */
-
-+#define JENT_RCT_FAILURE 1 /* Failure in RCT health test. */
-+#define JENT_APT_FAILURE 2 /* Failure in APT health test. */
-+#define JENT_PERMANENT_FAILURE_SHIFT 16
-+#define JENT_PERMANENT_FAILURE(x) (x << JENT_PERMANENT_FAILURE_SHIFT)
-+#define JENT_RCT_FAILURE_PERMANENT JENT_PERMANENT_FAILURE(JENT_RCT_FAILURE)
-+#define JENT_APT_FAILURE_PERMANENT JENT_PERMANENT_FAILURE(JENT_APT_FAILURE)
-+
- /*
- * The output n bits can receive more than n bits of min entropy, of course,
- * but the fixed output of the conditioning function can only asymptotically
-@@ -215,26 +224,22 @@ static void jent_apt_insert(struct rand_
- return;
- }
-
-- if (delta_masked == ec->apt_base)
-+ if (delta_masked == ec->apt_base) {
- ec->apt_count++;
-
-+ /* Note, ec->apt_count starts with one. */
-+ if (ec->apt_count >= ec->apt_cutoff_permanent)
-+ ec->health_failure |= JENT_APT_FAILURE_PERMANENT;
-+ else if (ec->apt_count >= ec->apt_cutoff)
-+ ec->health_failure |= JENT_APT_FAILURE;
-+ }
-+
- ec->apt_observations++;
-
- if (ec->apt_observations >= JENT_APT_WINDOW_SIZE)
- jent_apt_reset(ec, delta_masked);
- }
-
--/* APT health test failure detection */
--static int jent_apt_permanent_failure(struct rand_data *ec)
--{
-- return (ec->apt_count >= ec->apt_cutoff_permanent) ? 1 : 0;
--}
--
--static int jent_apt_failure(struct rand_data *ec)
--{
-- return (ec->apt_count >= ec->apt_cutoff) ? 1 : 0;
--}
--
- /***************************************************************************
- * Stuck Test and its use as Repetition Count Test
- *
-@@ -261,6 +266,30 @@ static void jent_rct_insert(struct rand_
- {
- if (stuck) {
- ec->rct_count++;
-+
-+ /*
-+ * The cutoff value is based on the following consideration:
-+ * alpha = 2^-30 or 2^-60 as recommended in SP800-90B.
-+ * In addition, we require an entropy value H of 1/osr as this
-+ * is the minimum entropy required to provide full entropy.
-+ * Note, we collect (DATA_SIZE_BITS + ENTROPY_SAFETY_FACTOR)*osr
-+ * deltas for inserting them into the entropy pool which should
-+ * then have (close to) DATA_SIZE_BITS bits of entropy in the
-+ * conditioned output.
-+ *
-+ * Note, ec->rct_count (which equals to value B in the pseudo
-+ * code of SP800-90B section 4.4.1) starts with zero. Hence
-+ * we need to subtract one from the cutoff value as calculated
-+ * following SP800-90B. Thus C = ceil(-log_2(alpha)/H) = 30*osr
-+ * or 60*osr.
-+ */
-+ if ((unsigned int)ec->rct_count >= (60 * ec->osr)) {
-+ ec->rct_count = -1;
-+ ec->health_failure |= JENT_RCT_FAILURE_PERMANENT;
-+ } else if ((unsigned int)ec->rct_count >= (30 * ec->osr)) {
-+ ec->rct_count = -1;
-+ ec->health_failure |= JENT_RCT_FAILURE;
-+ }
- } else {
- /* Reset RCT */
- ec->rct_count = 0;
-@@ -316,38 +345,24 @@ static int jent_stuck(struct rand_data *
- }
-
- /*
-- * The cutoff value is based on the following consideration:
-- * alpha = 2^-30 or 2^-60 as recommended in SP800-90B.
-- * In addition, we require an entropy value H of 1/osr as this is the minimum
-- * entropy required to provide full entropy.
-- * Note, we collect (DATA_SIZE_BITS + ENTROPY_SAFETY_FACTOR)*osr deltas for
-- * inserting them into the entropy pool which should then have (close to)
-- * DATA_SIZE_BITS bits of entropy in the conditioned output.
-+ * Report any health test failures
- *
-- * Note, ec->rct_count (which equals to value B in the pseudo code of SP800-90B
-- * section 4.4.1) starts with zero. Hence we need to subtract one from the
-- * cutoff value as calculated following SP800-90B. Thus
-- * C = ceil(-log_2(alpha)/H) = 30*osr or 60*osr.
-- */
--static int jent_rct_permanent_failure(struct rand_data *ec)
--{
-- return (ec->rct_count >= (60 * ec->osr)) ? 1 : 0;
--}
--
--static int jent_rct_failure(struct rand_data *ec)
--{
-- return (ec->rct_count >= (30 * ec->osr)) ? 1 : 0;
--}
--
--/* Report of health test failures */
--static int jent_health_failure(struct rand_data *ec)
--{
-- return jent_rct_failure(ec) | jent_apt_failure(ec);
--}
-+ * @ec [in] Reference to entropy collector
-+ *
-+ * @return a bitmask indicating which tests failed
-+ * 0 No health test failure
-+ * 1 RCT failure
-+ * 2 APT failure
-+ * 1<<JENT_PERMANENT_FAILURE_SHIFT RCT permanent failure
-+ * 2<<JENT_PERMANENT_FAILURE_SHIFT APT permanent failure
-+ */
-+static unsigned int jent_health_failure(struct rand_data *ec)
-+{
-+ /* Test is only enabled in FIPS mode */
-+ if (!fips_enabled)
-+ return 0;
-
--static int jent_permanent_health_failure(struct rand_data *ec)
--{
-- return jent_rct_permanent_failure(ec) | jent_apt_permanent_failure(ec);
-+ return ec->health_failure;
- }
-
- /***************************************************************************
-@@ -594,11 +609,12 @@ int jent_read_entropy(struct rand_data *
- return -1;
-
- while (len > 0) {
-- unsigned int tocopy;
-+ unsigned int tocopy, health_test_result;
-
- jent_gen_entropy(ec);
-
-- if (jent_permanent_health_failure(ec)) {
-+ health_test_result = jent_health_failure(ec);
-+ if (health_test_result > JENT_PERMANENT_FAILURE_SHIFT) {
- /*
- * At this point, the Jitter RNG instance is considered
- * as a failed instance. There is no rerun of the
-@@ -606,13 +622,18 @@ int jent_read_entropy(struct rand_data *
- * is assumed to not further use this instance.
- */
- return -3;
-- } else if (jent_health_failure(ec)) {
-+ } else if (health_test_result) {
- /*
- * Perform startup health tests and return permanent
- * error if it fails.
- */
-- if (jent_entropy_init(0, 0, NULL, ec))
-+ if (jent_entropy_init(0, 0, NULL, ec)) {
-+ /* Mark the permanent error */
-+ ec->health_failure &=
-+ JENT_RCT_FAILURE_PERMANENT |
-+ JENT_APT_FAILURE_PERMANENT;
- return -3;
-+ }
-
- return -2;
- }
-@@ -695,6 +716,7 @@ int jent_entropy_init(unsigned int osr,
- */
- struct rand_data *ec = p_ec;
- int i, time_backwards = 0, ret = 0, ec_free = 0;
-+ unsigned int health_test_result;
-
- if (!ec) {
- ec = jent_entropy_collector_alloc(osr, flags, hash_state);
-@@ -708,6 +730,9 @@ int jent_entropy_init(unsigned int osr,
- ec->apt_base_set = 0;
- /* Reset the RCT */
- ec->rct_count = 0;
-+ /* Reset intermittent, leave permanent health test result */
-+ ec->health_failure &= (~JENT_RCT_FAILURE);
-+ ec->health_failure &= (~JENT_APT_FAILURE);
- }
-
- /* We could perform statistical tests here, but the problem is
-@@ -788,12 +813,10 @@ int jent_entropy_init(unsigned int osr,
- }
-
- /* Did we encounter a health test failure? */
-- if (jent_rct_failure(ec)) {
-- ret = JENT_ERCT;
-- goto out;
-- }
-- if (jent_apt_failure(ec)) {
-- ret = JENT_EHEALTH;
-+ health_test_result = jent_health_failure(ec);
-+ if (health_test_result) {
-+ ret = (health_test_result & JENT_RCT_FAILURE) ? JENT_ERCT :
-+ JENT_EHEALTH;
- goto out;
- }
-
+++ /dev/null
-From e7ed6473c2c8c4e45dd861bfa06e96189b11d8db Mon Sep 17 00:00:00 2001
-Date: Mon, 6 Nov 2023 18:00:08 +0800
-Subject: [PATCH] crypto: jitterentropy - Hide esoteric Kconfig options under
- FIPS and EXPERT
-
-As JITTERENTROPY is selected by default if you enable the CRYPTO
-API, any Kconfig options added there will show up for every single
-user. Hide the esoteric options under EXPERT as well as FIPS so
-that only distro makers will see them.
-
----
- crypto/Kconfig | 28 +++++++++++++++++++++++++---
- 1 file changed, 25 insertions(+), 3 deletions(-)
-
---- a/crypto/Kconfig
-+++ b/crypto/Kconfig
-@@ -1297,10 +1297,12 @@ config CRYPTO_JITTERENTROPY
-
- See https://www.chronox.de/jent/
-
-+if CRYPTO_JITTERENTROPY
-+if CRYPTO_FIPS && EXPERT
-+
- choice
- prompt "CPU Jitter RNG Memory Size"
- default CRYPTO_JITTERENTROPY_MEMSIZE_2
-- depends on CRYPTO_JITTERENTROPY
- help
- The Jitter RNG measures the execution time of memory accesses.
- Multiple consecutive memory accesses are performed. If the memory
-@@ -1344,7 +1346,6 @@ config CRYPTO_JITTERENTROPY_OSR
- int "CPU Jitter RNG Oversampling Rate"
- range 1 15
- default 1
-- depends on CRYPTO_JITTERENTROPY
- help
- The Jitter RNG allows the specification of an oversampling rate (OSR).
- The Jitter RNG operation requires a fixed amount of timing
-@@ -1359,7 +1360,6 @@ config CRYPTO_JITTERENTROPY_OSR
-
- config CRYPTO_JITTERENTROPY_TESTINTERFACE
- bool "CPU Jitter RNG Test Interface"
-- depends on CRYPTO_JITTERENTROPY
- help
- The test interface allows a privileged process to capture
- the raw unconditioned high resolution time stamp noise that
-@@ -1377,6 +1377,28 @@ config CRYPTO_JITTERENTROPY_TESTINTERFAC
-
- If unsure, select N.
-
-+endif # if CRYPTO_FIPS && EXPERT
-+
-+if !(CRYPTO_FIPS && EXPERT)
-+
-+config CRYPTO_JITTERENTROPY_MEMORY_BLOCKS
-+ int
-+ default 64
-+
-+config CRYPTO_JITTERENTROPY_MEMORY_BLOCKSIZE
-+ int
-+ default 32
-+
-+config CRYPTO_JITTERENTROPY_OSR
-+ int
-+ default 1
-+
-+config CRYPTO_JITTERENTROPY_TESTINTERFACE
-+ bool
-+
-+endif # if !(CRYPTO_FIPS && EXPERT)
-+endif # if CRYPTO_JITTERENTROPY
-+
- config CRYPTO_KDF800108_CTR
- tristate
- select CRYPTO_HMAC
+++ /dev/null
-From 6e61ee1ca551292d8714c35c92a019c41db79e4e Mon Sep 17 00:00:00 2001
-Date: Wed, 27 Mar 2024 23:25:09 +0100
-Subject: [PATCH] crypto: jitter - Use kvfree_sensitive() to fix Coccinelle
- warning
-
-Replace memzero_explicit() and kvfree() with kvfree_sensitive() to fix
-the following Coccinelle/coccicheck warning reported by
-kfree_sensitive.cocci:
-
- WARNING opportunity for kfree_sensitive/kvfree_sensitive
-
----
- crypto/jitterentropy-kcapi.c | 3 +--
- 1 file changed, 1 insertion(+), 2 deletions(-)
-
---- a/crypto/jitterentropy-kcapi.c
-+++ b/crypto/jitterentropy-kcapi.c
-@@ -61,8 +61,7 @@ void *jent_kvzalloc(unsigned int len)
-
- void jent_kvzfree(void *ptr, unsigned int len)
- {
-- memzero_explicit(ptr, len);
-- kvfree(ptr);
-+ kvfree_sensitive(ptr, len);
- }
-
- void *jent_zalloc(unsigned int len)
+++ /dev/null
-From 95a798d20060d2b648dd604321e347c85edfd783 Mon Sep 17 00:00:00 2001
-Date: Mon, 12 Aug 2024 08:25:42 +0200
-Subject: [PATCH] crypto: jitter - set default OSR to 3
-
-The user space Jitter RNG library uses the oversampling rate of 3 which
-implies that each time stamp is credited with 1/3 bit of entropy. To
-obtain 256 bits of entropy, 768 time stamps need to be sampled. The
-increase in OSR is applied based on a report where the Jitter RNG is
-used on a system exhibiting a challenging environment to collect
-entropy.
-
-This OSR default value is now applied to the Linux kernel version of
-the Jitter RNG as well.
-
-The increase in the OSR from 1 to 3 also implies that the Jitter RNG is
-now slower by default.
-
----
- crypto/Kconfig | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/crypto/Kconfig
-+++ b/crypto/Kconfig
-@@ -1345,7 +1345,7 @@ config CRYPTO_JITTERENTROPY_MEMORY_BLOCK
- config CRYPTO_JITTERENTROPY_OSR
- int "CPU Jitter RNG Oversampling Rate"
- range 1 15
-- default 1
-+ default 3
- help
- The Jitter RNG allows the specification of an oversampling rate (OSR).
- The Jitter RNG operation requires a fixed amount of timing
+++ /dev/null
-From 9da39ef332c417ce52732564c1c682a6e1209302 Mon Sep 17 00:00:00 2001
-Date: Mon, 4 Dec 2023 15:13:35 +0100
-Subject: [PATCH] tools/thermal/tmon: Fix compilation warning for wrong format
-
-The following warnings are shown during compilation:
-
-tui.c: In function 'show_cooling_device':
- tui.c:216:40: warning: format '%d' expects argument of type 'int', but
-argument 7 has type 'long unsigned int' [-Wformat=]
- 216 | "%02d %12.12s%6d %6d",
- | ~~^
- | |
- | int
- | %6ld
- ......
- 219 | ptdata.cdi[j].cur_state,
- | ~~~~~~~~~~~~~~~~~~~~~~~
- | |
- | long unsigned int
- tui.c:216:44: warning: format '%d' expects argument of type 'int', but
-argument 8 has type 'long unsigned int' [-Wformat=]
- 216 | "%02d %12.12s%6d %6d",
- | ~~^
- | |
- | int
- | %6ld
- ......
- 220 | ptdata.cdi[j].max_state);
- | ~~~~~~~~~~~~~~~~~~~~~~~
- | |
- | long unsigned int
-
-To fix this, the correct string format must be used for printing.
-
----
- tools/thermal/tmon/tui.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/tools/thermal/tmon/tui.c
-+++ b/tools/thermal/tmon/tui.c
-@@ -213,7 +213,7 @@ void show_cooling_device(void)
- * cooling device instances. skip unused idr.
- */
- mvwprintw(cooling_device_window, j + 2, 1,
-- "%02d %12.12s%6d %6d",
-+ "%02d %12.12s%6lu %6lu",
- ptdata.cdi[j].instance,
- ptdata.cdi[j].type,
- ptdata.cdi[j].cur_state,
+++ /dev/null
-From f64f610ec6ab59dd0391b03842cea3a4cd8ee34f Mon Sep 17 00:00:00 2001
-Date: Wed, 18 Dec 2024 19:44:33 +0100
-Subject: [PATCH] pmdomain: core: add dummy release function to genpd device
-
-The genpd device, which is really only used as a handle to lookup
-OPP, but not even registered to the device core otherwise and thus
-lifetime linked to the genpd struct it is contained in, is missing
-a release function. After b8f7bbd1f4ec ("pmdomain: core: Add
-missing put_device()") the device will be cleaned up going through
-the driver core device_release() function, which will warn when no
-release callback is present for the device. Add a dummy release
-function to shut up the warning.
-
-Fixes: b8f7bbd1f4ec ("pmdomain: core: Add missing put_device()")
----
- drivers/base/power/domain.c | 6 ++++++
- 1 file changed, 6 insertions(+)
-
---- a/drivers/base/power/domain.c
-+++ b/drivers/base/power/domain.c
-@@ -2040,6 +2040,11 @@ static void genpd_lock_init(struct gener
- }
- }
-
-+static void genpd_provider_release(struct device *dev)
-+{
-+ /* nothing to be done here */
-+}
-+
- /**
- * pm_genpd_init - Initialize a generic I/O PM domain object.
- * @genpd: PM domain object to initialize.
-@@ -2106,6 +2111,7 @@ int pm_genpd_init(struct generic_pm_doma
- return ret;
-
- device_initialize(&genpd->dev);
-+ genpd->dev.release = genpd_provider_release;
- dev_set_name(&genpd->dev, "%s", genpd->name);
-
- mutex_lock(&gpd_list_lock);
+++ /dev/null
-From 51c884291a94fd6598427d7d6c211f1f20780d57 Mon Sep 17 00:00:00 2001
-Date: Fri, 30 Aug 2024 11:13:19 +0800
-Subject: [PATCH 02/12] net: dsa: realtek: Use for_each_child_of_node_scoped()
-
-Avoid need to manually handle of_node_put() by using
-for_each_child_of_node_scoped(), which can simplfy code.
-
----
- drivers/net/dsa/realtek/rtl8366rb.c | 8 +++-----
- 1 file changed, 3 insertions(+), 5 deletions(-)
-
---- a/drivers/net/dsa/realtek/rtl8366rb.c
-+++ b/drivers/net/dsa/realtek/rtl8366rb.c
-@@ -1013,8 +1013,8 @@ static int rtl8366rb_setup_all_leds_off(
-
- static int rtl8366rb_setup_leds(struct realtek_priv *priv)
- {
-- struct device_node *leds_np, *led_np;
- struct dsa_switch *ds = &priv->ds;
-+ struct device_node *leds_np;
- struct dsa_port *dp;
- int ret = 0;
-
-@@ -1029,13 +1029,11 @@ static int rtl8366rb_setup_leds(struct r
- continue;
- }
-
-- for_each_child_of_node(leds_np, led_np) {
-+ for_each_child_of_node_scoped(leds_np, led_np) {
- ret = rtl8366rb_setup_led(priv, dp,
- of_fwnode_handle(led_np));
-- if (ret) {
-- of_node_put(led_np);
-+ if (ret)
- break;
-- }
- }
-
- of_node_put(leds_np);
+++ /dev/null
-From 517c29247557bf4a28065cb758a59ad545fe925d Mon Sep 17 00:00:00 2001
-Date: Wed, 4 Sep 2024 17:10:16 +0200
-Subject: [PATCH 03/12] net: dsa: realtek: rtl8365mb: Make use of
- irq_get_trigger_type()
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Convert irqd_get_trigger_type(irq_get_irq_data(irq)) cases to the more
-simple irq_get_trigger_type(irq).
-
----
- drivers/net/dsa/realtek/rtl8365mb.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/net/dsa/realtek/rtl8365mb.c
-+++ b/drivers/net/dsa/realtek/rtl8365mb.c
-@@ -1735,7 +1735,7 @@ static int rtl8365mb_irq_setup(struct re
- }
-
- /* Configure chip interrupt signal polarity */
-- irq_trig = irqd_get_trigger_type(irq_get_irq_data(irq));
-+ irq_trig = irq_get_trigger_type(irq);
- switch (irq_trig) {
- case IRQF_TRIGGER_RISING:
- case IRQF_TRIGGER_HIGH:
+++ /dev/null
-From 36a5faec5658736e8d3d9047c1387a69ffda3354 Mon Sep 17 00:00:00 2001
-Date: Wed, 4 Sep 2024 17:10:17 +0200
-Subject: [PATCH 04/12] net: dsa: realtek: rtl8366rb: Make use of
- irq_get_trigger_type()
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Convert irqd_get_trigger_type(irq_get_irq_data(irq)) cases to the more
-simple irq_get_trigger_type(irq).
-
----
- drivers/net/dsa/realtek/rtl8366rb.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/net/dsa/realtek/rtl8366rb.c
-+++ b/drivers/net/dsa/realtek/rtl8366rb.c
-@@ -603,7 +603,7 @@ static int rtl8366rb_setup_cascaded_irq(
- }
-
- /* Fetch IRQ edge information from the descriptor */
-- irq_trig = irqd_get_trigger_type(irq_get_irq_data(irq));
-+ irq_trig = irq_get_trigger_type(irq);
- switch (irq_trig) {
- case IRQF_TRIGGER_RISING:
- case IRQF_TRIGGER_HIGH:
+++ /dev/null
-From 9934a1bd45b2b03f6d1204a6ae2780d3b009799f Mon Sep 17 00:00:00 2001
-Date: Mon, 5 Aug 2024 10:57:31 +0200
-Subject: [PATCH] clk: provide devm_clk_get_optional_enabled_with_rate()
-
-There are clock users in the kernel that can't use
-devm_clk_get_optional_enabled() as they need to set rate after getting
-the clock and before enabling it. Provide a managed helper that wraps
-these operations in the correct order.
-
----
- drivers/clk/clk-devres.c | 28 ++++++++++++++++++++++++++++
- include/linux/clk.h | 33 +++++++++++++++++++++++++++++++++
- 2 files changed, 61 insertions(+)
-
---- a/drivers/clk/clk-devres.c
-+++ b/drivers/clk/clk-devres.c
-@@ -99,6 +99,34 @@ struct clk *devm_clk_get_optional_enable
- }
- EXPORT_SYMBOL_GPL(devm_clk_get_optional_enabled);
-
-+struct clk *devm_clk_get_optional_enabled_with_rate(struct device *dev,
-+ const char *id,
-+ unsigned long rate)
-+{
-+ struct clk *clk;
-+ int ret;
-+
-+ clk = __devm_clk_get(dev, id, clk_get_optional, NULL,
-+ clk_disable_unprepare);
-+ if (IS_ERR(clk))
-+ return ERR_CAST(clk);
-+
-+ ret = clk_set_rate(clk, rate);
-+ if (ret)
-+ goto out_put_clk;
-+
-+ ret = clk_prepare_enable(clk);
-+ if (ret)
-+ goto out_put_clk;
-+
-+ return clk;
-+
-+out_put_clk:
-+ devm_clk_put(dev, clk);
-+ return ERR_PTR(ret);
-+}
-+EXPORT_SYMBOL_GPL(devm_clk_get_optional_enabled_with_rate);
-+
- struct clk_bulk_devres {
- struct clk_bulk_data *clks;
- int num_clks;
---- a/include/linux/clk.h
-+++ b/include/linux/clk.h
-@@ -608,6 +608,32 @@ struct clk *devm_clk_get_optional_prepar
- struct clk *devm_clk_get_optional_enabled(struct device *dev, const char *id);
-
- /**
-+ * devm_clk_get_optional_enabled_with_rate - devm_clk_get_optional() +
-+ * clk_set_rate() +
-+ * clk_prepare_enable()
-+ * @dev: device for clock "consumer"
-+ * @id: clock consumer ID
-+ * @rate: new clock rate
-+ *
-+ * Context: May sleep.
-+ *
-+ * Return: a struct clk corresponding to the clock producer, or
-+ * valid IS_ERR() condition containing errno. The implementation
-+ * uses @dev and @id to determine the clock consumer, and thereby
-+ * the clock producer. If no such clk is found, it returns NULL
-+ * which serves as a dummy clk. That's the only difference compared
-+ * to devm_clk_get_enabled().
-+ *
-+ * The returned clk (if valid) is prepared and enabled and rate was set.
-+ *
-+ * The clock will automatically be disabled, unprepared and freed
-+ * when the device is unbound from the bus.
-+ */
-+struct clk *devm_clk_get_optional_enabled_with_rate(struct device *dev,
-+ const char *id,
-+ unsigned long rate);
-+
-+/**
- * devm_get_clk_from_child - lookup and obtain a managed reference to a
- * clock producer from child node.
- * @dev: device for clock "consumer"
-@@ -948,6 +974,13 @@ static inline struct clk *devm_clk_get_o
- {
- return NULL;
- }
-+
-+static inline struct clk *
-+devm_clk_get_optional_enabled_with_rate(struct device *dev, const char *id,
-+ unsigned long rate)
-+{
-+ return NULL;
-+}
-
- static inline int __must_check devm_clk_bulk_get(struct device *dev, int num_clks,
- struct clk_bulk_data *clks)
+++ /dev/null
-# CONFIG_104_QUAD_8 is not set
-CONFIG_32BIT=y
-# CONFIG_6LOWPAN is not set
-# CONFIG_6LOWPAN_DEBUGFS is not set
-# CONFIG_6PACK is not set
-# CONFIG_8139CP is not set
-# CONFIG_8139TOO is not set
-# CONFIG_9P_FS is not set
-# CONFIG_AB8500_CORE is not set
-# CONFIG_ABP060MG is not set
-# CONFIG_ABX500_CORE is not set
-# CONFIG_ACCESSIBILITY is not set
-# CONFIG_ACENIC is not set
-# CONFIG_ACERHDF is not set
-# CONFIG_ACER_WIRELESS is not set
-# CONFIG_ACORN_PARTITION is not set
-# CONFIG_ACPI_AGDI is not set
-# CONFIG_ACPI_ALS is not set
-# CONFIG_ACPI_APEI is not set
-# CONFIG_ACPI_APEI_PCIEAER is not set
-# CONFIG_ACPI_BUTTON is not set
-# CONFIG_ACPI_CONFIGFS is not set
-# CONFIG_ACPI_CUSTOM_METHOD is not set
-# CONFIG_ACPI_EXTLOG is not set
-# CONFIG_ACPI_HED is not set
-# CONFIG_ACPI_NFIT is not set
-# CONFIG_ACPI_REDUCED_HARDWARE_ONLY is not set
-# CONFIG_ACPI_TABLE_UPGRADE is not set
-# CONFIG_ACPI_VIDEO is not set
-# CONFIG_AD2S1200 is not set
-# CONFIG_AD2S1210 is not set
-# CONFIG_AD2S90 is not set
-# CONFIG_AD3552R is not set
-# CONFIG_AD4130 is not set
-# CONFIG_AD5064 is not set
-# CONFIG_AD5110 is not set
-# CONFIG_AD525X_DPOT is not set
-# CONFIG_AD5272 is not set
-# CONFIG_AD5360 is not set
-# CONFIG_AD5380 is not set
-# CONFIG_AD5421 is not set
-# CONFIG_AD5446 is not set
-# CONFIG_AD5449 is not set
-# CONFIG_AD5504 is not set
-# CONFIG_AD5592R is not set
-# CONFIG_AD5593R is not set
-# CONFIG_AD5624R_SPI is not set
-# CONFIG_AD5686 is not set
-# CONFIG_AD5686_SPI is not set
-# CONFIG_AD5696_I2C is not set
-# CONFIG_AD5755 is not set
-# CONFIG_AD5758 is not set
-# CONFIG_AD5761 is not set
-# CONFIG_AD5764 is not set
-# CONFIG_AD5766 is not set
-# CONFIG_AD5770R is not set
-# CONFIG_AD5791 is not set
-# CONFIG_AD5933 is not set
-# CONFIG_AD7091R5 is not set
-# CONFIG_AD7124 is not set
-# CONFIG_AD7150 is not set
-# CONFIG_AD7192 is not set
-# CONFIG_AD7266 is not set
-# CONFIG_AD7280 is not set
-# CONFIG_AD7291 is not set
-# CONFIG_AD7292 is not set
-# CONFIG_AD7293 is not set
-# CONFIG_AD7298 is not set
-# CONFIG_AD7303 is not set
-# CONFIG_AD74115 is not set
-# CONFIG_AD74413R is not set
-# CONFIG_AD7476 is not set
-# CONFIG_AD7606 is not set
-# CONFIG_AD7606_IFACE_PARALLEL is not set
-# CONFIG_AD7606_IFACE_SPI is not set
-# CONFIG_AD7746 is not set
-# CONFIG_AD7766 is not set
-# CONFIG_AD7768_1 is not set
-# CONFIG_AD7780 is not set
-# CONFIG_AD7791 is not set
-# CONFIG_AD7793 is not set
-# CONFIG_AD7816 is not set
-# CONFIG_AD7887 is not set
-# CONFIG_AD7923 is not set
-# CONFIG_AD7949 is not set
-# CONFIG_AD799X is not set
-# CONFIG_AD8366 is not set
-# CONFIG_AD8801 is not set
-# CONFIG_AD9467 is not set
-# CONFIG_AD9523 is not set
-# CONFIG_AD9832 is not set
-# CONFIG_AD9834 is not set
-# CONFIG_ADA4250 is not set
-# CONFIG_ADAPTEC_STARFIRE is not set
-# CONFIG_ADF4350 is not set
-# CONFIG_ADF4371 is not set
-# CONFIG_ADF4377 is not set
-# CONFIG_ADFS_FS is not set
-# CONFIG_ADIN1100_PHY is not set
-# CONFIG_ADIN1110 is not set
-# CONFIG_ADIN_PHY is not set
-# CONFIG_ADIS16080 is not set
-# CONFIG_ADIS16130 is not set
-# CONFIG_ADIS16136 is not set
-# CONFIG_ADIS16201 is not set
-# CONFIG_ADIS16203 is not set
-# CONFIG_ADIS16209 is not set
-# CONFIG_ADIS16240 is not set
-# CONFIG_ADIS16260 is not set
-# CONFIG_ADIS16400 is not set
-# CONFIG_ADIS16460 is not set
-# CONFIG_ADIS16475 is not set
-# CONFIG_ADIS16480 is not set
-# CONFIG_ADI_AXI_ADC is not set
-# CONFIG_ADJD_S311 is not set
-# CONFIG_ADM6996_PHY is not set
-# CONFIG_ADM8211 is not set
-# CONFIG_ADMV1013 is not set
-# CONFIG_ADMV1014 is not set
-# CONFIG_ADMV4420 is not set
-# CONFIG_ADMV8818 is not set
-# CONFIG_ADRF6780 is not set
-# CONFIG_ADT7316 is not set
-# CONFIG_ADUX1020 is not set
-CONFIG_ADVISE_SYSCALLS=y
-# CONFIG_ADXL313_I2C is not set
-# CONFIG_ADXL313_SPI is not set
-# CONFIG_ADXL345_I2C is not set
-# CONFIG_ADXL345_SPI is not set
-# CONFIG_ADXL355_I2C is not set
-# CONFIG_ADXL355_SPI is not set
-# CONFIG_ADXL367_I2C is not set
-# CONFIG_ADXL367_SPI is not set
-# CONFIG_ADXL372_I2C is not set
-# CONFIG_ADXL372_SPI is not set
-# CONFIG_ADXRS290 is not set
-# CONFIG_ADXRS450 is not set
-CONFIG_AEABI=y
-# CONFIG_AFE4403 is not set
-# CONFIG_AFE4404 is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_AFS_DEBUG_CURSOR is not set
-# CONFIG_AFS_FS is not set
-# CONFIG_AF_KCM is not set
-# CONFIG_AF_RXRPC is not set
-# CONFIG_AF_RXRPC_INJECT_LOSS is not set
-# CONFIG_AF_RXRPC_INJECT_RX_DELAY is not set
-# CONFIG_AF_RXRPC_IPV6 is not set
-CONFIG_AF_UNIX_OOB=y
-# CONFIG_AGP is not set
-# CONFIG_AHCI_BRCM is not set
-# CONFIG_AHCI_CEVA is not set
-# CONFIG_AHCI_DWC is not set
-# CONFIG_AHCI_IMX is not set
-# CONFIG_AHCI_MVEBU is not set
-# CONFIG_AHCI_QORIQ is not set
-# CONFIG_AHCI_XGENE is not set
-CONFIG_AIO=y
-# CONFIG_AIRO is not set
-# CONFIG_AIRO_CS is not set
-# CONFIG_AIR_EN8811H_PHY is not set
-# CONFIG_AIX_PARTITION is not set
-# CONFIG_AK09911 is not set
-# CONFIG_AK8974 is not set
-# CONFIG_AK8975 is not set
-# CONFIG_AL3010 is not set
-# CONFIG_AL3320A is not set
-# CONFIG_ALIM7101_WDT is not set
-CONFIG_ALLOW_DEV_COREDUMP=y
-# CONFIG_ALTERA_MBOX is not set
-# CONFIG_ALTERA_MSGDMA is not set
-# CONFIG_ALTERA_STAPL is not set
-# CONFIG_ALTERA_TSE is not set
-# CONFIG_ALX is not set
-# CONFIG_AL_FIC is not set
-# CONFIG_AM2315 is not set
-# CONFIG_AM335X_PHY_USB is not set
-# CONFIG_AMBA_PL08X is not set
-# CONFIG_AMD8111_ETH is not set
-# CONFIG_AMD_MEM_ENCRYPT is not set
-# CONFIG_AMD_PHY is not set
-# CONFIG_AMD_XGBE is not set
-# CONFIG_AMD_XGBE_HAVE_ECC is not set
-# CONFIG_AMIGA_PARTITION is not set
-# CONFIG_AMILO_RFKILL is not set
-# CONFIG_AMPERE_ERRATUM_AC03_CPU_38 is not set
-# CONFIG_AMT is not set
-# CONFIG_ANDROID_BINDER_IPC is not set
-# CONFIG_ANON_VMA_NAME is not set
-# CONFIG_APDS9300 is not set
-# CONFIG_APDS9802ALS is not set
-# CONFIG_APDS9960 is not set
-# CONFIG_APM8018X is not set
-# CONFIG_APM_EMULATION is not set
-# CONFIG_APPLE_GMUX is not set
-# CONFIG_APPLE_MFI_FASTCHARGE is not set
-# CONFIG_APPLE_PROPERTIES is not set
-# CONFIG_APPLICOM is not set
-# CONFIG_AQTION is not set
-# CONFIG_AQUANTIA_PHY is not set
-# CONFIG_AR5523 is not set
-# CONFIG_AR7 is not set
-# CONFIG_AR8216_PHY is not set
-# CONFIG_AR8216_PHY_LEDS is not set
-# CONFIG_ARCH_ACTIONS is not set
-# CONFIG_ARCH_AIROHA is not set
-# CONFIG_ARCH_ALPINE is not set
-# CONFIG_ARCH_APPLE is not set
-# CONFIG_ARCH_ARTPEC is not set
-# CONFIG_ARCH_ASPEED is not set
-# CONFIG_ARCH_AT91 is not set
-# CONFIG_ARCH_AXXIA is not set
-# CONFIG_ARCH_BCM is not set
-# CONFIG_ARCH_BCM2835 is not set
-# CONFIG_ARCH_BCMBCA is not set
-# CONFIG_ARCH_BCM_21664 is not set
-# CONFIG_ARCH_BCM_23550 is not set
-# CONFIG_ARCH_BCM_281XX is not set
-# CONFIG_ARCH_BCM_5301X is not set
-# CONFIG_ARCH_BCM_53573 is not set
-# CONFIG_ARCH_BCM_CYGNUS is not set
-# CONFIG_ARCH_BCM_HR2 is not set
-# CONFIG_ARCH_BCM_IPROC is not set
-# CONFIG_ARCH_BCM_NSP is not set
-# CONFIG_ARCH_BERLIN is not set
-CONFIG_ARCH_BINFMT_ELF_STATE=y
-# CONFIG_ARCH_BITMAIN is not set
-# CONFIG_ARCH_BRCMSTB is not set
-# CONFIG_ARCH_CLPS711X is not set
-# CONFIG_ARCH_DAVINCI is not set
-# CONFIG_ARCH_DIGICOLOR is not set
-# CONFIG_ARCH_DMA_ADDR_T_64BIT is not set
-# CONFIG_ARCH_DOVE is not set
-# CONFIG_ARCH_EP93XX is not set
-# CONFIG_ARCH_EXYNOS is not set
-CONFIG_ARCH_FLATMEM_ENABLE=y
-# CONFIG_ARCH_FOOTBRIDGE is not set
-CONFIG_ARCH_FORCE_MAX_ORDER=11
-# CONFIG_ARCH_GEMINI is not set
-# CONFIG_ARCH_HI3xxx is not set
-# CONFIG_ARCH_HIGHBANK is not set
-# CONFIG_ARCH_HISI is not set
-# CONFIG_ARCH_HPE is not set
-# CONFIG_ARCH_INTEGRATOR is not set
-# CONFIG_ARCH_INTEL_SOCFPGA is not set
-# CONFIG_ARCH_IXP4XX is not set
-# CONFIG_ARCH_K3 is not set
-# CONFIG_ARCH_KEEMBAY is not set
-# CONFIG_ARCH_KEYSTONE is not set
-# CONFIG_ARCH_LAYERSCAPE is not set
-# CONFIG_ARCH_LG1K is not set
-# CONFIG_ARCH_LPC32XX is not set
-# CONFIG_ARCH_MA35 is not set
-# CONFIG_ARCH_MEDIATEK is not set
-# CONFIG_ARCH_MESON is not set
-# CONFIG_ARCH_MILBEAUT is not set
-CONFIG_ARCH_MMAP_RND_BITS=8
-CONFIG_ARCH_MMAP_RND_BITS_MAX=16
-CONFIG_ARCH_MMAP_RND_BITS_MIN=8
-CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MAX=16
-CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MIN=8
-# CONFIG_ARCH_MMP is not set
-# CONFIG_ARCH_MSTARV7 is not set
-# CONFIG_ARCH_MULTIPLATFORM is not set
-# CONFIG_ARCH_MULTI_V6 is not set
-# CONFIG_ARCH_MULTI_V7 is not set
-# CONFIG_ARCH_MV78XX0 is not set
-# CONFIG_ARCH_MVEBU is not set
-# CONFIG_ARCH_MXC is not set
-# CONFIG_ARCH_MXS is not set
-# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set
-# CONFIG_ARCH_NOMADIK is not set
-# CONFIG_ARCH_NPCM is not set
-# CONFIG_ARCH_NSPIRE is not set
-# CONFIG_ARCH_NXP is not set
-# CONFIG_ARCH_OMAP is not set
-# CONFIG_ARCH_OMAP1 is not set
-# CONFIG_ARCH_OMAP2 is not set
-# CONFIG_ARCH_OMAP2PLUS is not set
-# CONFIG_ARCH_OMAP3 is not set
-# CONFIG_ARCH_OMAP4 is not set
-# CONFIG_ARCH_ORION5X is not set
-# CONFIG_ARCH_PXA is not set
-# CONFIG_ARCH_QCOM is not set
-# CONFIG_ARCH_RDA is not set
-# CONFIG_ARCH_REALTEK is not set
-# CONFIG_ARCH_REALVIEW is not set
-# CONFIG_ARCH_RENESAS is not set
-# CONFIG_ARCH_ROCKCHIP is not set
-# CONFIG_ARCH_RPC is not set
-# CONFIG_ARCH_S32 is not set
-# CONFIG_ARCH_S3C64XX is not set
-# CONFIG_ARCH_S5PV210 is not set
-# CONFIG_ARCH_SA1100 is not set
-# CONFIG_ARCH_SEATTLE is not set
-# CONFIG_ARCH_SHMOBILE is not set
-# CONFIG_ARCH_SPARX5 is not set
-# CONFIG_ARCH_SPRD is not set
-# CONFIG_ARCH_STI is not set
-# CONFIG_ARCH_STM32 is not set
-# CONFIG_ARCH_SUNPLUS is not set
-# CONFIG_ARCH_SUNXI is not set
-# CONFIG_ARCH_SYNQUACER is not set
-# CONFIG_ARCH_TEGRA is not set
-# CONFIG_ARCH_THUNDER is not set
-# CONFIG_ARCH_THUNDER2 is not set
-# CONFIG_ARCH_U8500 is not set
-# CONFIG_ARCH_UNIPHIER is not set
-# CONFIG_ARCH_VERSATILE is not set
-# CONFIG_ARCH_VEXPRESS is not set
-# CONFIG_ARCH_VIRT is not set
-# CONFIG_ARCH_VISCONTI is not set
-# CONFIG_ARCH_VT8500 is not set
-# CONFIG_ARCH_WANTS_THP_SWAP is not set
-# CONFIG_ARCH_WM8505 is not set
-# CONFIG_ARCH_WM8750 is not set
-# CONFIG_ARCH_WM8850 is not set
-# CONFIG_ARCH_XGENE is not set
-# CONFIG_ARCH_ZYNQ is not set
-# CONFIG_ARCH_ZYNQMP is not set
-# CONFIG_ARCNET is not set
-# CONFIG_ARC_EMAC is not set
-# CONFIG_ARC_IRQ_NO_AUTOSAVE is not set
-# CONFIG_ARM64_16K_PAGES is not set
-# CONFIG_ARM64_64K_PAGES is not set
-# CONFIG_ARM64_AMU_EXTN is not set
-# CONFIG_ARM64_BTI is not set
-CONFIG_ARM64_CNP=y
-# CONFIG_ARM64_E0PD is not set
-# CONFIG_ARM64_EPAN is not set
-# CONFIG_ARM64_ERRATUM_1024718 is not set
-# CONFIG_ARM64_ERRATUM_1165522 is not set
-# CONFIG_ARM64_ERRATUM_1286807 is not set
-# CONFIG_ARM64_ERRATUM_1319367 is not set
-# CONFIG_ARM64_ERRATUM_1418040 is not set
-# CONFIG_ARM64_ERRATUM_1463225 is not set
-# CONFIG_ARM64_ERRATUM_1508412 is not set
-# CONFIG_ARM64_ERRATUM_1530923 is not set
-# CONFIG_ARM64_ERRATUM_1542419 is not set
-# CONFIG_ARM64_ERRATUM_1742098 is not set
-# CONFIG_ARM64_ERRATUM_2051678 is not set
-# CONFIG_ARM64_ERRATUM_2054223 is not set
-# CONFIG_ARM64_ERRATUM_2067961 is not set
-# CONFIG_ARM64_ERRATUM_2077057 is not set
-# CONFIG_ARM64_ERRATUM_2441007 is not set
-# CONFIG_ARM64_ERRATUM_2441009 is not set
-# CONFIG_ARM64_ERRATUM_2645198 is not set
-# CONFIG_ARM64_ERRATUM_2658417 is not set
-# CONFIG_ARM64_ERRATUM_2966298 is not set
-# CONFIG_ARM64_ERRATUM_3117295 is not set
-# CONFIG_ARM64_ERRATUM_3194386 is not set
-# CONFIG_ARM64_ERRATUM_819472 is not set
-# CONFIG_ARM64_ERRATUM_824069 is not set
-# CONFIG_ARM64_ERRATUM_826319 is not set
-# CONFIG_ARM64_ERRATUM_827319 is not set
-# CONFIG_ARM64_ERRATUM_832075 is not set
-# CONFIG_ARM64_ERRATUM_834220 is not set
-# CONFIG_ARM64_ERRATUM_843419 is not set
-# CONFIG_ARM64_ERRATUM_845719 is not set
-# CONFIG_ARM64_ERRATUM_858921 is not set
-# CONFIG_ARM64_HW_AFDBM is not set
-# CONFIG_ARM64_LSE_ATOMICS is not set
-# CONFIG_ARM64_MTE is not set
-CONFIG_ARM64_PAN=y
-# CONFIG_ARM64_PMEM is not set
-# CONFIG_ARM64_PSEUDO_NMI is not set
-# CONFIG_ARM64_PTR_AUTH is not set
-# CONFIG_ARM64_RAS_EXTN is not set
-# CONFIG_ARM64_RELOC_TEST is not set
-# CONFIG_ARM64_SME is not set
-# CONFIG_ARM64_SVE is not set
-CONFIG_ARM64_SW_TTBR0_PAN=y
-# CONFIG_ARM64_TLB_RANGE is not set
-# CONFIG_ARM64_USE_LSE_ATOMICS is not set
-# CONFIG_ARM64_VA_BITS_48 is not set
-# CONFIG_ARM_APPENDED_DTB is not set
-# CONFIG_ARM_ARCH_TIMER is not set
-# CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_EXTEND is not set
-# CONFIG_ARM_CCI is not set
-# CONFIG_ARM_CCI400_PMU is not set
-# CONFIG_ARM_CCI5xx_PMU is not set
-# CONFIG_ARM_CCI_PMU is not set
-# CONFIG_ARM_CCN is not set
-# CONFIG_ARM_CMN is not set
-# CONFIG_ARM_CORESIGHT_PMU_ARCH_SYSTEM_PMU is not set
-# CONFIG_ARM_CPUIDLE is not set
-CONFIG_ARM_CPU_TOPOLOGY=y
-CONFIG_ARM_DMA_MEM_BUFFERABLE=y
-# CONFIG_ARM_DSU_PMU is not set
-# CONFIG_ARM_ERRATA_326103 is not set
-# CONFIG_ARM_ERRATA_364296 is not set
-# CONFIG_ARM_ERRATA_411920 is not set
-# CONFIG_ARM_ERRATA_430973 is not set
-# CONFIG_ARM_ERRATA_458693 is not set
-# CONFIG_ARM_ERRATA_460075 is not set
-# CONFIG_ARM_ERRATA_643719 is not set
-# CONFIG_ARM_ERRATA_720789 is not set
-# CONFIG_ARM_ERRATA_742230 is not set
-# CONFIG_ARM_ERRATA_742231 is not set
-# CONFIG_ARM_ERRATA_743622 is not set
-# CONFIG_ARM_ERRATA_751472 is not set
-# CONFIG_ARM_ERRATA_754322 is not set
-# CONFIG_ARM_ERRATA_754327 is not set
-# CONFIG_ARM_ERRATA_764319 is not set
-# CONFIG_ARM_ERRATA_764369 is not set
-# CONFIG_ARM_ERRATA_773022 is not set
-# CONFIG_ARM_ERRATA_775420 is not set
-# CONFIG_ARM_ERRATA_798181 is not set
-# CONFIG_ARM_ERRATA_814220 is not set
-# CONFIG_ARM_ERRATA_818325_852422 is not set
-# CONFIG_ARM_ERRATA_821420 is not set
-# CONFIG_ARM_ERRATA_825619 is not set
-# CONFIG_ARM_ERRATA_852421 is not set
-# CONFIG_ARM_ERRATA_852423 is not set
-# CONFIG_ARM_ERRATA_857271 is not set
-# CONFIG_ARM_ERRATA_857272 is not set
-# CONFIG_ARM_FFA_TRANSPORT is not set
-CONFIG_ARM_GIC_MAX_NR=1
-# CONFIG_ARM_KIRKWOOD_CPUFREQ is not set
-# CONFIG_ARM_KPROBES_TEST is not set
-# CONFIG_ARM_LPAE is not set
-# CONFIG_ARM_MEDIATEK_CPUFREQ_HW is not set
-# CONFIG_ARM_MHU is not set
-CONFIG_ARM_MODULE_PLTS=y
-# CONFIG_ARM_PATCH_PHYS_VIRT is not set
-# CONFIG_ARM_PSCI is not set
-# CONFIG_ARM_PSCI_CHECKER is not set
-# CONFIG_ARM_PSCI_CPUIDLE is not set
-# CONFIG_ARM_PTDUMP_DEBUGFS is not set
-# CONFIG_ARM_SBSA_WATCHDOG is not set
-# CONFIG_ARM_SCMI_PROTOCOL is not set
-# CONFIG_ARM_SCPI_PROTOCOL is not set
-# CONFIG_ARM_SDE_INTERFACE is not set
-# CONFIG_ARM_SMCCC_SOC_ID is not set
-# CONFIG_ARM_SMC_WATCHDOG is not set
-# CONFIG_ARM_SMMU_V3_PMU is not set
-# CONFIG_ARM_SP805_WATCHDOG is not set
-# CONFIG_ARM_SPE_PMU is not set
-# CONFIG_ARM_THUMBEE is not set
-# CONFIG_ARM_TIMER_SP804 is not set
-# CONFIG_ARM_UNWIND is not set
-# CONFIG_ARM_VIRT_EXT is not set
-# CONFIG_AS21XXX_PHY is not set
-# CONFIG_AS3935 is not set
-# CONFIG_AS73211 is not set
-# CONFIG_ASM9260_TIMER is not set
-# CONFIG_ASN1 is not set
-# CONFIG_ASUS_LAPTOP is not set
-# CONFIG_ASUS_WIRELESS is not set
-# CONFIG_ASYMMETRIC_KEY_TYPE is not set
-# CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE is not set
-# CONFIG_ASYNC_RAID6_TEST is not set
-# CONFIG_ASYNC_TX_DMA is not set
-# CONFIG_AT76C50X_USB is not set
-# CONFIG_AT803X_PHY is not set
-# CONFIG_AT91_SAMA5D2_ADC is not set
-# CONFIG_ATA is not set
-# CONFIG_ATAGS is not set
-CONFIG_ATAGS_PROC=y
-# CONFIG_ATALK is not set
-# CONFIG_ATARI_PARTITION is not set
-# CONFIG_ATA_ACPI is not set
-CONFIG_ATA_BMDMA=y
-# CONFIG_ATA_FORCE is not set
-# CONFIG_ATA_GENERIC is not set
-# CONFIG_ATA_LEDS is not set
-# CONFIG_ATA_NONSTANDARD is not set
-# CONFIG_ATA_OVER_ETH is not set
-# CONFIG_ATA_PIIX is not set
-CONFIG_ATA_SFF=y
-# CONFIG_ATA_VERBOSE_ERROR is not set
-# CONFIG_ATH10K is not set
-# CONFIG_ATH25 is not set
-# CONFIG_ATH5K is not set
-# CONFIG_ATH6KL is not set
-# CONFIG_ATH79 is not set
-# CONFIG_ATH9K is not set
-# CONFIG_ATH9K_HTC is not set
-# CONFIG_ATH_DEBUG is not set
-# CONFIG_ATL1 is not set
-# CONFIG_ATL1C is not set
-# CONFIG_ATL1E is not set
-# CONFIG_ATL2 is not set
-# CONFIG_ATLAS_EZO_SENSOR is not set
-# CONFIG_ATLAS_PH_SENSOR is not set
-# CONFIG_ATM is not set
-# CONFIG_ATMEL is not set
-# CONFIG_ATMEL_PIT is not set
-# CONFIG_ATMEL_SSC is not set
-# CONFIG_ATM_BR2684 is not set
-CONFIG_ATM_BR2684_IPFILTER=y
-# CONFIG_ATM_CLIP is not set
-CONFIG_ATM_CLIP_NO_ICMP=y
-# CONFIG_ATM_DRIVERS is not set
-# CONFIG_ATM_DUMMY is not set
-# CONFIG_ATM_ENI is not set
-# CONFIG_ATM_FORE200E is not set
-# CONFIG_ATM_HE is not set
-# CONFIG_ATM_IA is not set
-# CONFIG_ATM_IDT77252 is not set
-# CONFIG_ATM_LANAI is not set
-# CONFIG_ATM_LANE is not set
-# CONFIG_ATM_MPOA is not set
-# CONFIG_ATM_NICSTAR is not set
-# CONFIG_ATM_SOLOS is not set
-# CONFIG_ATM_TCP is not set
-# CONFIG_ATOMIC64_SELFTEST is not set
-# CONFIG_ATP is not set
-# CONFIG_AUDIT is not set
-# CONFIG_AUDIT_ARCH_COMPAT_GENERIC is not set
-# CONFIG_AUTOFS_FS is not set
-# CONFIG_AUTO_ZRELADDR is not set
-# CONFIG_AUXDISPLAY is not set
-# CONFIG_AX25 is not set
-# CONFIG_AX25_DAMA_SLAVE is not set
-# CONFIG_AX88796 is not set
-# CONFIG_AX88796B_PHY is not set
-# CONFIG_AXP20X_ADC is not set
-# CONFIG_AXP20X_POWER is not set
-# CONFIG_AXP288_ADC is not set
-# CONFIG_AXP288_FUEL_GAUGE is not set
-# CONFIG_B43 is not set
-# CONFIG_B43LEGACY is not set
-# CONFIG_B44 is not set
-# CONFIG_B53 is not set
-# CONFIG_B53_MDIO_DRIVER is not set
-# CONFIG_B53_MMAP_DRIVER is not set
-# CONFIG_B53_SERDES is not set
-# CONFIG_B53_SPI_DRIVER is not set
-# CONFIG_B53_SRAB_DRIVER is not set
-# CONFIG_BACKLIGHT_ADP8860 is not set
-# CONFIG_BACKLIGHT_ADP8870 is not set
-# CONFIG_BACKLIGHT_APPLE is not set
-# CONFIG_BACKLIGHT_ARCXCNN is not set
-# CONFIG_BACKLIGHT_BD6107 is not set
-# CONFIG_BACKLIGHT_CLASS_DEVICE is not set
-# CONFIG_BACKLIGHT_GPIO is not set
-# CONFIG_BACKLIGHT_KTD253 is not set
-# CONFIG_BACKLIGHT_KTZ8866 is not set
-# CONFIG_BACKLIGHT_LED is not set
-# CONFIG_BACKLIGHT_LM3630A is not set
-# CONFIG_BACKLIGHT_LM3639 is not set
-# CONFIG_BACKLIGHT_LP855X is not set
-# CONFIG_BACKLIGHT_LV5207LP is not set
-# CONFIG_BACKLIGHT_PANDORA is not set
-# CONFIG_BACKLIGHT_PWM is not set
-# CONFIG_BACKLIGHT_QCOM_WLED is not set
-# CONFIG_BACKLIGHT_SAHARA is not set
-# CONFIG_BACKTRACE_SELF_TEST is not set
-# CONFIG_BACKTRACE_VERBOSE is not set
-# CONFIG_BAREUDP is not set
-CONFIG_BASE_FULL=y
-CONFIG_BASE_SMALL=0
-# CONFIG_BATMAN_ADV is not set
-# CONFIG_BATTERY_BQ27XXX is not set
-# CONFIG_BATTERY_BQ27XXX_HDQ is not set
-# CONFIG_BATTERY_CW2015 is not set
-# CONFIG_BATTERY_DS2760 is not set
-# CONFIG_BATTERY_DS2780 is not set
-# CONFIG_BATTERY_DS2781 is not set
-# CONFIG_BATTERY_DS2782 is not set
-# CONFIG_BATTERY_GAUGE_LTC2941 is not set
-# CONFIG_BATTERY_GOLDFISH is not set
-# CONFIG_BATTERY_LEGO_EV3 is not set
-# CONFIG_BATTERY_MAX17040 is not set
-# CONFIG_BATTERY_MAX17042 is not set
-# CONFIG_BATTERY_MAX1721X is not set
-# CONFIG_BATTERY_RT5033 is not set
-# CONFIG_BATTERY_SAMSUNG_SDI is not set
-# CONFIG_BATTERY_SBS is not set
-# CONFIG_BATTERY_UG3105 is not set
-# CONFIG_BAYCOM_EPP is not set
-# CONFIG_BAYCOM_PAR is not set
-# CONFIG_BAYCOM_SER_FDX is not set
-# CONFIG_BAYCOM_SER_HDX is not set
-# CONFIG_BCACHE is not set
-# CONFIG_BCM47XX is not set
-# CONFIG_BCM54140_PHY is not set
-# CONFIG_BCM63XX is not set
-# CONFIG_BCM63XX_PHY is not set
-# CONFIG_BCM7038_L1_IRQ is not set
-# CONFIG_BCM7038_WDT is not set
-# CONFIG_BCM7120_L2_IRQ is not set
-# CONFIG_BCM7XXX_PHY is not set
-# CONFIG_BCM84881_PHY is not set
-# CONFIG_BCM87XX_PHY is not set
-# CONFIG_BCMA is not set
-# CONFIG_BCMA_DRIVER_GPIO is not set
-CONFIG_BCMA_POSSIBLE=y
-# CONFIG_BCMGENET is not set
-# CONFIG_BCM_IPROC_ADC is not set
-# CONFIG_BCM_KONA_USB2_PHY is not set
-# CONFIG_BCM_SBA_RAID is not set
-# CONFIG_BCM_VK is not set
-# CONFIG_BDI_SWITCH is not set
-# CONFIG_BE2ISCSI is not set
-# CONFIG_BE2NET is not set
-# CONFIG_BEFS_FS is not set
-# CONFIG_BFS_FS is not set
-# CONFIG_BGMAC is not set
-# CONFIG_BH1750 is not set
-# CONFIG_BH1780 is not set
-# CONFIG_BIG_KEYS is not set
-# CONFIG_BIG_LITTLE is not set
-CONFIG_BINARY_PRINTF=y
-CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_ELF_FDPIC is not set
-# CONFIG_BINFMT_FLAT is not set
-# CONFIG_BINFMT_MISC is not set
-CONFIG_BINFMT_SCRIPT=y
-CONFIG_BITREVERSE=y
-# CONFIG_BLK_CGROUP_IOCOST is not set
-# CONFIG_BLK_CGROUP_IOLATENCY is not set
-# CONFIG_BLK_CGROUP_IOPRIO is not set
-# CONFIG_BLK_DEBUG_FS is not set
-CONFIG_BLK_DEV=y
-# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
-# CONFIG_BLK_DEV_BSG is not set
-# CONFIG_BLK_DEV_BSGLIB is not set
-# CONFIG_BLK_DEV_COW_COMMON is not set
-# CONFIG_BLK_DEV_DM is not set
-# CONFIG_BLK_DEV_DRBD is not set
-# CONFIG_BLK_DEV_FD is not set
-CONFIG_BLK_DEV_INITRD=y
-# CONFIG_BLK_DEV_INTEGRITY is not set
-# CONFIG_BLK_DEV_IO_TRACE is not set
-# CONFIG_BLK_DEV_LOOP is not set
-CONFIG_BLK_DEV_LOOP_MIN_COUNT=8
-# CONFIG_BLK_DEV_MD is not set
-# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_NULL_BLK is not set
-# CONFIG_BLK_DEV_NVME is not set
-# CONFIG_BLK_DEV_PCIESSD_MTIP32XX is not set
-# CONFIG_BLK_DEV_PMEM is not set
-# CONFIG_BLK_DEV_RAM is not set
-# CONFIG_BLK_DEV_RBD is not set
-# CONFIG_BLK_DEV_SD is not set
-# CONFIG_BLK_DEV_SR is not set
-# CONFIG_BLK_DEV_THROTTLING is not set
-# CONFIG_BLK_DEV_UBLK is not set
-# CONFIG_BLK_DEV_ZONED is not set
-# CONFIG_BLK_INLINE_ENCRYPTION is not set
-# CONFIG_BLK_SED_OPAL is not set
-# CONFIG_BLK_WBT is not set
-CONFIG_BLOCK=y
-# CONFIG_BLOCK_LEGACY_AUTOLOAD is not set
-# CONFIG_BLOCK_NOTIFIERS is not set
-# CONFIG_BMA180 is not set
-# CONFIG_BMA220 is not set
-# CONFIG_BMA400 is not set
-# CONFIG_BMC150_ACCEL is not set
-# CONFIG_BMC150_MAGN is not set
-# CONFIG_BMC150_MAGN_I2C is not set
-# CONFIG_BMC150_MAGN_SPI is not set
-# CONFIG_BME680 is not set
-# CONFIG_BMG160 is not set
-# CONFIG_BMI088_ACCEL is not set
-# CONFIG_BMI160_I2C is not set
-# CONFIG_BMI160_SPI is not set
-# CONFIG_BMIPS_GENERIC is not set
-# CONFIG_BMP280 is not set
-# CONFIG_BNA is not set
-# CONFIG_BNX2 is not set
-# CONFIG_BNX2X is not set
-# CONFIG_BNX2X_SRIOV is not set
-# CONFIG_BNXT is not set
-# CONFIG_BONDING is not set
-# CONFIG_BOOKE_WDT is not set
-CONFIG_BOOKE_WDT_DEFAULT_TIMEOUT=3
-# CONFIG_BOOTPARAM_HARDLOCKUP_PANIC is not set
-# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set
-# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
-# CONFIG_BOOTTIME_TRACING is not set
-# CONFIG_BOOT_CONFIG is not set
-# CONFIG_BOOT_PRINTK_DELAY is not set
-CONFIG_BOOT_RAW=y
-# CONFIG_BOSCH_BNO055_I2C is not set
-# CONFIG_BOSCH_BNO055_SERIAL is not set
-# CONFIG_BOUNCE is not set
-CONFIG_BPF=y
-# CONFIG_BPFILTER is not set
-CONFIG_BPF_JIT=y
-# CONFIG_BPF_JIT_ALWAYS_ON is not set
-CONFIG_BPF_JIT_DEFAULT_ON=y
-# CONFIG_BPF_LSM is not set
-# CONFIG_BPF_PRELOAD is not set
-# CONFIG_BPF_STREAM_PARSER is not set
-CONFIG_BPF_SYSCALL=y
-CONFIG_BPF_UNPRIV_DEFAULT_OFF=y
-# CONFIG_BPQETHER is not set
-CONFIG_BQL=y
-CONFIG_BRANCH_PROFILE_NONE=y
-# CONFIG_BRCMFMAC is not set
-# CONFIG_BRCMSMAC is not set
-# CONFIG_BRCMSTB_GISB_ARB is not set
-# CONFIG_BRCMSTB_L2_IRQ is not set
-CONFIG_BRIDGE=y
-# CONFIG_BRIDGE_CFM is not set
-# CONFIG_BRIDGE_EBT_802_3 is not set
-# CONFIG_BRIDGE_EBT_AMONG is not set
-# CONFIG_BRIDGE_EBT_ARP is not set
-# CONFIG_BRIDGE_EBT_ARPREPLY is not set
-# CONFIG_BRIDGE_EBT_BROUTE is not set
-# CONFIG_BRIDGE_EBT_DNAT is not set
-# CONFIG_BRIDGE_EBT_IP is not set
-# CONFIG_BRIDGE_EBT_IP6 is not set
-# CONFIG_BRIDGE_EBT_LIMIT is not set
-# CONFIG_BRIDGE_EBT_LOG is not set
-# CONFIG_BRIDGE_EBT_MARK is not set
-# CONFIG_BRIDGE_EBT_MARK_T is not set
-# CONFIG_BRIDGE_EBT_NFLOG is not set
-# CONFIG_BRIDGE_EBT_PKTTYPE is not set
-# CONFIG_BRIDGE_EBT_REDIRECT is not set
-# CONFIG_BRIDGE_EBT_SNAT is not set
-# CONFIG_BRIDGE_EBT_STP is not set
-# CONFIG_BRIDGE_EBT_T_FILTER is not set
-# CONFIG_BRIDGE_EBT_T_NAT is not set
-# CONFIG_BRIDGE_EBT_VLAN is not set
-CONFIG_BRIDGE_IGMP_SNOOPING=y
-# CONFIG_BRIDGE_MRP is not set
-# CONFIG_BRIDGE_NETFILTER is not set
-# CONFIG_BRIDGE_NF_EBTABLES is not set
-CONFIG_BRIDGE_VLAN_FILTERING=y
-# CONFIG_BROADCOM_PHY is not set
-CONFIG_BROKEN_ON_SMP=y
-# CONFIG_BSD_DISKLABEL is not set
-# CONFIG_BSD_PROCESS_ACCT is not set
-# CONFIG_BSD_PROCESS_ACCT_V3 is not set
-# CONFIG_BT is not set
-# CONFIG_BTRFS_ASSERT is not set
-# CONFIG_BTRFS_DEBUG is not set
-# CONFIG_BTRFS_FS is not set
-# CONFIG_BTRFS_FS_CHECK_INTEGRITY is not set
-# CONFIG_BTRFS_FS_POSIX_ACL is not set
-# CONFIG_BTRFS_FS_REF_VERIFY is not set
-# CONFIG_BTRFS_FS_RUN_SANITY_TESTS is not set
-# CONFIG_BT_AOSPEXT is not set
-# CONFIG_BT_ATH3K is not set
-# CONFIG_BT_BNEP is not set
-CONFIG_BT_BNEP_MC_FILTER=y
-CONFIG_BT_BNEP_PROTO_FILTER=y
-# CONFIG_BT_BREDR is not set
-# CONFIG_BT_CMTP is not set
-# CONFIG_BT_FEATURE_DEBUG is not set
-# CONFIG_BT_HCIBCM203X is not set
-# CONFIG_BT_HCIBCM4377 is not set
-# CONFIG_BT_HCIBFUSB is not set
-# CONFIG_BT_HCIBLUECARD is not set
-# CONFIG_BT_HCIBPA10X is not set
-# CONFIG_BT_HCIBT3C is not set
-# CONFIG_BT_HCIBTSDIO is not set
-# CONFIG_BT_HCIBTUSB is not set
-# CONFIG_BT_HCIBTUSB_AUTOSUSPEND is not set
-# CONFIG_BT_HCIBTUSB_MTK is not set
-CONFIG_BT_HCIBTUSB_POLL_SYNC=y
-# CONFIG_BT_HCIBTUSB_RTL is not set
-# CONFIG_BT_HCIDTL1 is not set
-# CONFIG_BT_HCIUART is not set
-# CONFIG_BT_HCIUART_3WIRE is not set
-# CONFIG_BT_HCIUART_AG6XX is not set
-# CONFIG_BT_HCIUART_ATH3K is not set
-CONFIG_BT_HCIUART_BCSP=y
-CONFIG_BT_HCIUART_H4=y
-# CONFIG_BT_HCIUART_LL is not set
-# CONFIG_BT_HCIUART_MRVL is not set
-# CONFIG_BT_HCIUART_QCA is not set
-# CONFIG_BT_HCIUART_RTL is not set
-# CONFIG_BT_HCIVHCI is not set
-# CONFIG_BT_HIDP is not set
-# CONFIG_BT_LE is not set
-# CONFIG_BT_LEDS is not set
-CONFIG_BT_LE_L2CAP_ECRED=y
-# CONFIG_BT_MRVL is not set
-# CONFIG_BT_MSFTEXT is not set
-# CONFIG_BT_MTKSDIO is not set
-# CONFIG_BT_MTKUART is not set
-# CONFIG_BT_NXPUART is not set
-# CONFIG_BT_RFCOMM is not set
-CONFIG_BT_RFCOMM_TTY=y
-# CONFIG_BT_SELFTEST is not set
-# CONFIG_BT_VIRTIO is not set
-CONFIG_BUG=y
-# CONFIG_BUG_ON_DATA_CORRUPTION is not set
-CONFIG_BUILDTIME_TABLE_SORT=y
-CONFIG_BUILD_SALT=""
-# CONFIG_C2PORT is not set
-# CONFIG_CACHESTAT_SYSCALL is not set
-CONFIG_CACHE_L2X0_PMU=y
-# CONFIG_CADENCE_WATCHDOG is not set
-# CONFIG_CAIF is not set
-# CONFIG_CAN is not set
-# CONFIG_CAN_BCM is not set
-# CONFIG_CAN_CAN327 is not set
-# CONFIG_CAN_CTUCANFD_PCI is not set
-# CONFIG_CAN_CTUCANFD_PLATFORM is not set
-# CONFIG_CAN_DEBUG_DEVICES is not set
-# CONFIG_CAN_DEV is not set
-# CONFIG_CAN_ESD_USB is not set
-# CONFIG_CAN_ETAS_ES58X is not set
-# CONFIG_CAN_F81604 is not set
-# CONFIG_CAN_GS_USB is not set
-# CONFIG_CAN_GW is not set
-# CONFIG_CAN_HI311X is not set
-# CONFIG_CAN_IFI_CANFD is not set
-# CONFIG_CAN_ISOTP is not set
-# CONFIG_CAN_J1939 is not set
-# CONFIG_CAN_KVASER_PCIEFD is not set
-# CONFIG_CAN_MCBA_USB is not set
-# CONFIG_CAN_MCP251XFD is not set
-# CONFIG_CAN_M_CAN is not set
-# CONFIG_CAN_NETLINK is not set
-# CONFIG_CAN_PEAK_PCIEFD is not set
-# CONFIG_CAN_RAW is not set
-# CONFIG_CAN_RCAR is not set
-# CONFIG_CAN_RCAR_CANFD is not set
-# CONFIG_CAN_SLCAN is not set
-# CONFIG_CAN_SUN4I is not set
-# CONFIG_CAN_UCAN is not set
-# CONFIG_CAN_VCAN is not set
-# CONFIG_CAN_VXCAN is not set
-# CONFIG_CAPI_TRACE is not set
-CONFIG_CARDBUS=y
-# CONFIG_CARL9170 is not set
-# CONFIG_CASSINI is not set
-# CONFIG_CAVIUM_CPT is not set
-# CONFIG_CAVIUM_ERRATUM_22375 is not set
-# CONFIG_CAVIUM_ERRATUM_23144 is not set
-# CONFIG_CAVIUM_ERRATUM_23154 is not set
-# CONFIG_CAVIUM_ERRATUM_27456 is not set
-# CONFIG_CAVIUM_ERRATUM_30115 is not set
-# CONFIG_CAVIUM_OCTEON_SOC is not set
-# CONFIG_CAVIUM_PTP is not set
-# CONFIG_CAVIUM_TX2_ERRATUM_219 is not set
-# CONFIG_CB710_CORE is not set
-# CONFIG_CC10001_ADC is not set
-# CONFIG_CCS811 is not set
-CONFIG_CC_CAN_LINK=y
-CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-# CONFIG_CDROM_PKTCDVD is not set
-# CONFIG_CDX_BUS is not set
-# CONFIG_CEPH_FS is not set
-# CONFIG_CEPH_LIB is not set
-# CONFIG_CFG80211 is not set
-# CONFIG_CFG80211_CERTIFICATION_ONUS is not set
-CONFIG_CFG80211_HEADERS=y
-# CONFIG_CGROUPS is not set
-# CONFIG_CGROUP_FAVOR_DYNMODS is not set
-# CONFIG_CGROUP_MISC is not set
-# CONFIG_CHARGER_ADP5061 is not set
-# CONFIG_CHARGER_BD99954 is not set
-# CONFIG_CHARGER_BQ2415X is not set
-# CONFIG_CHARGER_BQ24190 is not set
-# CONFIG_CHARGER_BQ24257 is not set
-# CONFIG_CHARGER_BQ24735 is not set
-# CONFIG_CHARGER_BQ2515X is not set
-# CONFIG_CHARGER_BQ256XX is not set
-# CONFIG_CHARGER_BQ25890 is not set
-# CONFIG_CHARGER_BQ25980 is not set
-# CONFIG_CHARGER_DETECTOR_MAX14656 is not set
-# CONFIG_CHARGER_GPIO is not set
-# CONFIG_CHARGER_ISP1704 is not set
-# CONFIG_CHARGER_LP8727 is not set
-# CONFIG_CHARGER_LT3651 is not set
-# CONFIG_CHARGER_LTC4162L is not set
-# CONFIG_CHARGER_MANAGER is not set
-# CONFIG_CHARGER_MAX77976 is not set
-# CONFIG_CHARGER_MAX8903 is not set
-# CONFIG_CHARGER_QCOM_SMB2 is not set
-# CONFIG_CHARGER_QCOM_SMBB is not set
-# CONFIG_CHARGER_RT9455 is not set
-# CONFIG_CHARGER_RT9467 is not set
-# CONFIG_CHARGER_RT9471 is not set
-# CONFIG_CHARGER_SBS is not set
-# CONFIG_CHARGER_SMB347 is not set
-# CONFIG_CHARGER_TWL4030 is not set
-# CONFIG_CHARGER_UCS1002 is not set
-# CONFIG_CHECKPOINT_RESTORE is not set
-# CONFIG_CHELSIO_T1 is not set
-# CONFIG_CHELSIO_T3 is not set
-# CONFIG_CHELSIO_T4 is not set
-# CONFIG_CHELSIO_T4VF is not set
-# CONFIG_CHROME_PLATFORMS is not set
-# CONFIG_CHR_DEV_SCH is not set
-# CONFIG_CHR_DEV_SG is not set
-# CONFIG_CHR_DEV_ST is not set
-# CONFIG_CICADA_PHY is not set
-# CONFIG_CIFS is not set
-CONFIG_CIFS_ALLOW_INSECURE_LEGACY=y
-# CONFIG_CIFS_DEBUG is not set
-# CONFIG_CIFS_DEBUG2 is not set
-# CONFIG_CIFS_FSCACHE is not set
-# CONFIG_CIFS_NFSD_EXPORT is not set
-CONFIG_CIFS_POSIX=y
-# CONFIG_CIFS_STATS2 is not set
-# CONFIG_CIFS_SWN_UPCALL is not set
-CONFIG_CIFS_XATTR=y
-# CONFIG_CIO_DAC is not set
-# CONFIG_CLKSRC_PISTACHIO is not set
-# CONFIG_CLKSRC_VERSATILE is not set
-# CONFIG_CLK_GFM_LPASS_SM8250 is not set
-# CONFIG_CLK_HSDK is not set
-# CONFIG_CLK_ICST is not set
-# CONFIG_CLK_QORIQ is not set
-# CONFIG_CLK_SP810 is not set
-CONFIG_CLS_U32_MARK=y
-# CONFIG_CLS_U32_PERF is not set
-# CONFIG_CM32181 is not set
-# CONFIG_CM3232 is not set
-# CONFIG_CM3323 is not set
-# CONFIG_CM3605 is not set
-# CONFIG_CM36651 is not set
-# CONFIG_CMA is not set
-CONFIG_CMDLINE=""
-# CONFIG_CMDLINE_BOOL is not set
-# CONFIG_CMDLINE_EXTEND is not set
-# CONFIG_CMDLINE_FORCE is not set
-# CONFIG_CMDLINE_FROM_BOOTLOADER is not set
-# CONFIG_CMDLINE_PARTITION is not set
-# CONFIG_CNIC is not set
-# CONFIG_CODA_FS is not set
-# CONFIG_CODE_PATCHING_SELFTEST is not set
-# CONFIG_COMEDI is not set
-# CONFIG_COMMON_CLK_AXI_CLKGEN is not set
-# CONFIG_COMMON_CLK_BOSTON is not set
-# CONFIG_COMMON_CLK_CDCE706 is not set
-# CONFIG_COMMON_CLK_CDCE925 is not set
-# CONFIG_COMMON_CLK_CS2000_CP is not set
-# CONFIG_COMMON_CLK_FIXED_MMIO is not set
-# CONFIG_COMMON_CLK_IPROC is not set
-# CONFIG_COMMON_CLK_MAX9485 is not set
-# CONFIG_COMMON_CLK_MEDIATEK_FHCTL is not set
-# CONFIG_COMMON_CLK_MT6765 is not set
-# CONFIG_COMMON_CLK_MT8167 is not set
-# CONFIG_COMMON_CLK_MT8167_AUDSYS is not set
-# CONFIG_COMMON_CLK_MT8167_IMGSYS is not set
-# CONFIG_COMMON_CLK_MT8167_MFGCFG is not set
-# CONFIG_COMMON_CLK_MT8167_MMSYS is not set
-# CONFIG_COMMON_CLK_MT8167_VDECSYS is not set
-# CONFIG_COMMON_CLK_MT8188 is not set
-# CONFIG_COMMON_CLK_MT8192 is not set
-# CONFIG_COMMON_CLK_NXP is not set
-# CONFIG_COMMON_CLK_PIC32 is not set
-# CONFIG_COMMON_CLK_PISTACHIO is not set
-# CONFIG_COMMON_CLK_PWM is not set
-# CONFIG_COMMON_CLK_PXA is not set
-# CONFIG_COMMON_CLK_QCOM is not set
-# CONFIG_COMMON_CLK_RS9_PCIE is not set
-# CONFIG_COMMON_CLK_SI514 is not set
-# CONFIG_COMMON_CLK_SI521XX is not set
-# CONFIG_COMMON_CLK_SI5341 is not set
-# CONFIG_COMMON_CLK_SI5351 is not set
-# CONFIG_COMMON_CLK_SI544 is not set
-# CONFIG_COMMON_CLK_SI570 is not set
-# CONFIG_COMMON_CLK_VC3 is not set
-# CONFIG_COMMON_CLK_VC5 is not set
-# CONFIG_COMMON_CLK_VC7 is not set
-# CONFIG_COMMON_CLK_XGENE is not set
-# CONFIG_COMMON_CLK_XLNX_CLKWZRD is not set
-CONFIG_COMPACTION=y
-# CONFIG_COMPAL_LAPTOP is not set
-# CONFIG_COMPAT is not set
-# CONFIG_COMPAT_BRK is not set
-# CONFIG_COMPILE_TEST is not set
-# CONFIG_CONFIGFS_FS is not set
-# CONFIG_CONNECTOR is not set
-CONFIG_CONSOLE_LOGLEVEL_DEFAULT=7
-CONFIG_CONSOLE_LOGLEVEL_QUIET=4
-CONFIG_CONSTRUCTORS=y
-# CONFIG_CONTEXT_SWITCH_TRACER is not set
-# CONFIG_COPS is not set
-# CONFIG_CORDIC is not set
-# CONFIG_COREDUMP is not set
-# CONFIG_CORESIGHT is not set
-# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
-# CONFIG_CORTINA_PHY is not set
-# CONFIG_COUNTER is not set
-# CONFIG_CPA_DEBUG is not set
-# CONFIG_CPUFREQ_DT is not set
-# CONFIG_CPUFREQ_DT_PLATDEV is not set
-# CONFIG_CPU_BIG_ENDIAN is not set
-# CONFIG_CPU_BPREDICT_DISABLE is not set
-# CONFIG_CPU_DCACHE_DISABLE is not set
-# CONFIG_CPU_FREQ is not set
-# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
-# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set
-# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set
-# CONFIG_CPU_FREQ_DEFAULT_GOV_SCHEDUTIL is not set
-# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
-# CONFIG_CPU_FREQ_GOV_SCHEDUTIL is not set
-# CONFIG_CPU_FREQ_THERMAL is not set
-# CONFIG_CPU_HOTPLUG_STATE_CONTROL is not set
-# CONFIG_CPU_ICACHE_DISABLE is not set
-# CONFIG_CPU_ICACHE_MISMATCH_WORKAROUND is not set
-# CONFIG_CPU_IDLE is not set
-# CONFIG_CPU_IDLE_GOV_LADDER is not set
-# CONFIG_CPU_IDLE_GOV_MENU is not set
-# CONFIG_CPU_IDLE_GOV_TEO is not set
-# CONFIG_CPU_IDLE_MULTIPLE_DRIVERS is not set
-# CONFIG_CPU_ISOLATION is not set
-# CONFIG_CPU_LITTLE_ENDIAN is not set
-# CONFIG_CPU_NO_EFFICIENT_FFS is not set
-CONFIG_CPU_SW_DOMAIN_PAN=y
-# CONFIG_CPU_THERMAL is not set
-# CONFIG_CRAMFS is not set
-CONFIG_CRAMFS_BLOCKDEV=y
-# CONFIG_CRAMFS_MTD is not set
-# CONFIG_CRASH_DUMP is not set
-# CONFIG_CRC16 is not set
-CONFIG_CRC32=y
-# CONFIG_CRC32_BIT is not set
-# CONFIG_CRC32_SARWATE is not set
-# CONFIG_CRC32_SELFTEST is not set
-# CONFIG_CRC32_SLICEBY4 is not set
-CONFIG_CRC32_SLICEBY8=y
-# CONFIG_CRC4 is not set
-# CONFIG_CRC64 is not set
-# CONFIG_CRC64_ROCKSOFT is not set
-# CONFIG_CRC7 is not set
-# CONFIG_CRC8 is not set
-# CONFIG_CRC_CCITT is not set
-# CONFIG_CRC_ITU_T is not set
-# CONFIG_CRC_T10DIF is not set
-# CONFIG_CROSS_MEMORY_ATTACH is not set
-# CONFIG_CROS_HPS_I2C is not set
-CONFIG_CRYPTO=y
-# CONFIG_CRYPTO_842 is not set
-CONFIG_CRYPTO_ACOMP2=y
-# CONFIG_CRYPTO_ADIANTUM is not set
-CONFIG_CRYPTO_AEAD=y
-CONFIG_CRYPTO_AEAD2=y
-# CONFIG_CRYPTO_AEGIS128 is not set
-# CONFIG_CRYPTO_AEGIS128_AESNI_SSE2 is not set
-CONFIG_CRYPTO_AES=y
-# CONFIG_CRYPTO_AES_ARM is not set
-# CONFIG_CRYPTO_AES_ARM64 is not set
-# CONFIG_CRYPTO_AES_ARM64_BS is not set
-# CONFIG_CRYPTO_AES_ARM64_CE is not set
-# CONFIG_CRYPTO_AES_ARM64_CE_BLK is not set
-# CONFIG_CRYPTO_AES_ARM64_CE_CCM is not set
-# CONFIG_CRYPTO_AES_ARM64_NEON_BLK is not set
-# CONFIG_CRYPTO_AES_ARM_BS is not set
-# CONFIG_CRYPTO_AES_ARM_CE is not set
-# CONFIG_CRYPTO_AES_NI_INTEL is not set
-# CONFIG_CRYPTO_AES_TI is not set
-CONFIG_CRYPTO_AKCIPHER=y
-CONFIG_CRYPTO_AKCIPHER2=y
-CONFIG_CRYPTO_ALGAPI=y
-CONFIG_CRYPTO_ALGAPI2=y
-# CONFIG_CRYPTO_ANSI_CPRNG is not set
-# CONFIG_CRYPTO_ANUBIS is not set
-# CONFIG_CRYPTO_ARC4 is not set
-# CONFIG_CRYPTO_ARIA is not set
-# CONFIG_CRYPTO_AUTHENC is not set
-# CONFIG_CRYPTO_BLAKE2B is not set
-# CONFIG_CRYPTO_BLAKE2B_NEON is not set
-# CONFIG_CRYPTO_BLAKE2S_ARM is not set
-# CONFIG_CRYPTO_BLAKE2S_X86 is not set
-# CONFIG_CRYPTO_BLOWFISH is not set
-# CONFIG_CRYPTO_CAMELLIA is not set
-# CONFIG_CRYPTO_CAST5 is not set
-# CONFIG_CRYPTO_CAST6 is not set
-# CONFIG_CRYPTO_CBC is not set
-CONFIG_CRYPTO_CCM=y
-# CONFIG_CRYPTO_CFB is not set
-# CONFIG_CRYPTO_CHACHA20 is not set
-# CONFIG_CRYPTO_CHACHA20POLY1305 is not set
-# CONFIG_CRYPTO_CHACHA20_NEON is not set
-# CONFIG_CRYPTO_CHACHA20_X86_64 is not set
-# CONFIG_CRYPTO_CHACHA_MIPS is not set
-# CONFIG_CRYPTO_CMAC is not set
-# CONFIG_CRYPTO_CRC32 is not set
-# CONFIG_CRYPTO_CRC32C is not set
-# CONFIG_CRYPTO_CRC32C_INTEL is not set
-# CONFIG_CRYPTO_CRC32_ARM_CE is not set
-# CONFIG_CRYPTO_CRCT10DIF is not set
-# CONFIG_CRYPTO_CRCT10DIF_ARM64_CE is not set
-# CONFIG_CRYPTO_CRCT10DIF_ARM_CE is not set
-# CONFIG_CRYPTO_CRYPTD is not set
-CONFIG_CRYPTO_CTR=y
-# CONFIG_CRYPTO_CTS is not set
-# CONFIG_CRYPTO_CURVE25519 is not set
-# CONFIG_CRYPTO_CURVE25519_NEON is not set
-# CONFIG_CRYPTO_CURVE25519_X86 is not set
-# CONFIG_CRYPTO_DEFLATE is not set
-# CONFIG_CRYPTO_DES is not set
-# CONFIG_CRYPTO_DEV_AMLOGIC_GXL is not set
-# CONFIG_CRYPTO_DEV_ATMEL_AES is not set
-# CONFIG_CRYPTO_DEV_ATMEL_AUTHENC is not set
-# CONFIG_CRYPTO_DEV_ATMEL_ECC is not set
-# CONFIG_CRYPTO_DEV_ATMEL_SHA is not set
-# CONFIG_CRYPTO_DEV_ATMEL_SHA204A is not set
-# CONFIG_CRYPTO_DEV_ATMEL_TDES is not set
-# CONFIG_CRYPTO_DEV_CAVIUM_ZIP is not set
-# CONFIG_CRYPTO_DEV_CCP is not set
-# CONFIG_CRYPTO_DEV_CCP_DEBUGFS is not set
-# CONFIG_CRYPTO_DEV_CCREE is not set
-# CONFIG_CRYPTO_DEV_FSL_CAAM is not set
-# CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API_DESC is not set
-# CONFIG_CRYPTO_DEV_FSL_CAAM_DEBUG is not set
-# CONFIG_CRYPTO_DEV_FSL_CAAM_INTC is not set
-# CONFIG_CRYPTO_DEV_FSL_CAAM_RNG_TEST is not set
-# CONFIG_CRYPTO_DEV_HIFN_795X is not set
-# CONFIG_CRYPTO_DEV_HISI_SEC is not set
-# CONFIG_CRYPTO_DEV_HISI_ZIP is not set
-# CONFIG_CRYPTO_DEV_IMGTEC_HASH is not set
-# CONFIG_CRYPTO_DEV_MARVELL_CESA is not set
-# CONFIG_CRYPTO_DEV_MXS_DCP is not set
-# CONFIG_CRYPTO_DEV_NITROX_CNN55XX is not set
-# CONFIG_CRYPTO_DEV_OCTEONTX_CPT is not set
-# CONFIG_CRYPTO_DEV_QAT_4XXX is not set
-# CONFIG_CRYPTO_DEV_QAT_C3XXX is not set
-# CONFIG_CRYPTO_DEV_QAT_C3XXXVF is not set
-# CONFIG_CRYPTO_DEV_QAT_C62X is not set
-# CONFIG_CRYPTO_DEV_QAT_C62XVF is not set
-# CONFIG_CRYPTO_DEV_QAT_DH895xCC is not set
-# CONFIG_CRYPTO_DEV_QAT_DH895xCCVF is not set
-# CONFIG_CRYPTO_DEV_QCE is not set
-# CONFIG_CRYPTO_DEV_S5P is not set
-# CONFIG_CRYPTO_DEV_SAFEXCEL is not set
-# CONFIG_CRYPTO_DEV_SAHARA is not set
-# CONFIG_CRYPTO_DEV_SP_PSP is not set
-# CONFIG_CRYPTO_DEV_TALITOS is not set
-# CONFIG_CRYPTO_DEV_VIRTIO is not set
-# CONFIG_CRYPTO_DH is not set
-# CONFIG_CRYPTO_DRBG_CTR is not set
-# CONFIG_CRYPTO_DRBG_HASH is not set
-# CONFIG_CRYPTO_DRBG_MENU is not set
-# CONFIG_CRYPTO_ECB is not set
-# CONFIG_CRYPTO_ECDH is not set
-# CONFIG_CRYPTO_ECDSA is not set
-# CONFIG_CRYPTO_ECHAINIV is not set
-# CONFIG_CRYPTO_ECRDSA is not set
-# CONFIG_CRYPTO_ESSIV is not set
-# CONFIG_CRYPTO_FCRYPT is not set
-# CONFIG_CRYPTO_FIPS is not set
-CONFIG_CRYPTO_GCM=y
-CONFIG_CRYPTO_GHASH=y
-# CONFIG_CRYPTO_GHASH_ARM64_CE is not set
-# CONFIG_CRYPTO_GHASH_ARM_CE is not set
-# CONFIG_CRYPTO_GHASH_CLMUL_NI_INTEL is not set
-CONFIG_CRYPTO_HASH=y
-CONFIG_CRYPTO_HASH2=y
-# CONFIG_CRYPTO_HCTR2 is not set
-# CONFIG_CRYPTO_HMAC is not set
-# CONFIG_CRYPTO_HW is not set
-# CONFIG_CRYPTO_JITTERENTROPY is not set
-# CONFIG_CRYPTO_JITTERENTROPY_TESTINTERFACE is not set
-# CONFIG_CRYPTO_KEYWRAP is not set
-# CONFIG_CRYPTO_KHAZAD is not set
-CONFIG_CRYPTO_KPP=y
-CONFIG_CRYPTO_KPP2=y
-CONFIG_CRYPTO_LIB_AES=y
-CONFIG_CRYPTO_LIB_ARC4=y
-# CONFIG_CRYPTO_LIB_BLAKE2S_GENERIC is not set
-# CONFIG_CRYPTO_LIB_CHACHA is not set
-# CONFIG_CRYPTO_LIB_CHACHA20POLY1305 is not set
-# CONFIG_CRYPTO_LIB_CURVE25519 is not set
-# CONFIG_CRYPTO_LIB_POLY1305 is not set
-CONFIG_CRYPTO_LIB_POLY1305_RSIZE=9
-# CONFIG_CRYPTO_LRW is not set
-# CONFIG_CRYPTO_LZ4 is not set
-# CONFIG_CRYPTO_LZ4HC is not set
-# CONFIG_CRYPTO_LZO is not set
-CONFIG_CRYPTO_MANAGER=y
-CONFIG_CRYPTO_MANAGER2=y
-CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y
-# CONFIG_CRYPTO_MD4 is not set
-# CONFIG_CRYPTO_MD5 is not set
-# CONFIG_CRYPTO_MICHAEL_MIC is not set
-# CONFIG_CRYPTO_NHPOLY1305_NEON is not set
-CONFIG_CRYPTO_NULL=y
-CONFIG_CRYPTO_NULL2=y
-# CONFIG_CRYPTO_OFB is not set
-# CONFIG_CRYPTO_PCBC is not set
-CONFIG_CRYPTO_PCRYPT=y
-# CONFIG_CRYPTO_POLY1305 is not set
-# CONFIG_CRYPTO_POLY1305_ARM is not set
-# CONFIG_CRYPTO_POLY1305_MIPS is not set
-# CONFIG_CRYPTO_POLY1305_NEON is not set
-# CONFIG_CRYPTO_POLY1305_X86_64 is not set
-# CONFIG_CRYPTO_POLYVAL_ARM64_CE is not set
-# CONFIG_CRYPTO_RMD160 is not set
-# CONFIG_CRYPTO_RNG is not set
-# CONFIG_CRYPTO_RSA is not set
-# CONFIG_CRYPTO_SEED is not set
-# CONFIG_CRYPTO_SEQIV is not set
-# CONFIG_CRYPTO_SERPENT is not set
-# CONFIG_CRYPTO_SHA1 is not set
-# CONFIG_CRYPTO_SHA1_ARM is not set
-# CONFIG_CRYPTO_SHA1_ARM64_CE is not set
-# CONFIG_CRYPTO_SHA1_ARM_CE is not set
-# CONFIG_CRYPTO_SHA1_ARM_NEON is not set
-# CONFIG_CRYPTO_SHA256 is not set
-# CONFIG_CRYPTO_SHA256_ARM is not set
-# CONFIG_CRYPTO_SHA256_ARM64 is not set
-# CONFIG_CRYPTO_SHA2_ARM64_CE is not set
-# CONFIG_CRYPTO_SHA2_ARM_CE is not set
-# CONFIG_CRYPTO_SHA3 is not set
-# CONFIG_CRYPTO_SHA3_ARM64 is not set
-# CONFIG_CRYPTO_SHA512 is not set
-# CONFIG_CRYPTO_SHA512_ARM is not set
-# CONFIG_CRYPTO_SHA512_ARM64 is not set
-# CONFIG_CRYPTO_SHA512_ARM64_CE is not set
-# CONFIG_CRYPTO_SIMD is not set
-CONFIG_CRYPTO_SKCIPHER=y
-CONFIG_CRYPTO_SKCIPHER2=y
-# CONFIG_CRYPTO_SM2 is not set
-# CONFIG_CRYPTO_SM3 is not set
-# CONFIG_CRYPTO_SM3_ARM64_CE is not set
-# CONFIG_CRYPTO_SM3_GENERIC is not set
-# CONFIG_CRYPTO_SM3_NEON is not set
-# CONFIG_CRYPTO_SM4 is not set
-# CONFIG_CRYPTO_SM4_ARM64_CE is not set
-# CONFIG_CRYPTO_SM4_ARM64_CE_BLK is not set
-# CONFIG_CRYPTO_SM4_ARM64_CE_CCM is not set
-# CONFIG_CRYPTO_SM4_ARM64_CE_GCM is not set
-# CONFIG_CRYPTO_SM4_ARM64_NEON_BLK is not set
-# CONFIG_CRYPTO_SM4_GENERIC is not set
-# CONFIG_CRYPTO_STATS is not set
-# CONFIG_CRYPTO_STREEBOG is not set
-# CONFIG_CRYPTO_TEA is not set
-# CONFIG_CRYPTO_TEST is not set
-# CONFIG_CRYPTO_TWOFISH is not set
-# CONFIG_CRYPTO_TWOFISH_586 is not set
-# CONFIG_CRYPTO_TWOFISH_COMMON is not set
-# CONFIG_CRYPTO_USER is not set
-# CONFIG_CRYPTO_USER_API_AEAD is not set
-# CONFIG_CRYPTO_USER_API_ENABLE_OBSOLETE is not set
-# CONFIG_CRYPTO_USER_API_HASH is not set
-# CONFIG_CRYPTO_USER_API_RNG is not set
-# CONFIG_CRYPTO_USER_API_RNG_CAVP is not set
-# CONFIG_CRYPTO_USER_API_SKCIPHER is not set
-# CONFIG_CRYPTO_VMAC is not set
-# CONFIG_CRYPTO_WP512 is not set
-# CONFIG_CRYPTO_XCBC is not set
-# CONFIG_CRYPTO_XTS is not set
-# CONFIG_CRYPTO_XXHASH is not set
-# CONFIG_CRYPTO_ZSTD is not set
-# CONFIG_CS5535_MFGPT is not set
-# CONFIG_CS89x0 is not set
-# CONFIG_CS89x0_PLATFORM is not set
-# CONFIG_CSD_LOCK_WAIT_DEBUG is not set
-# CONFIG_CUSE is not set
-# CONFIG_CW1200 is not set
-# CONFIG_CXD2880_SPI_DRV is not set
-# CONFIG_CXL_BASE is not set
-# CONFIG_CXL_BUS is not set
-# CONFIG_CYPRESS_FIRMWARE is not set
-# CONFIG_CZNIC_PLATFORMS is not set
-# CONFIG_DA280 is not set
-# CONFIG_DA311 is not set
-# CONFIG_DAMON is not set
-# CONFIG_DAVICOM_PHY is not set
-# CONFIG_DAX is not set
-# CONFIG_DCB is not set
-# CONFIG_DDR is not set
-# CONFIG_DEBUG_ALIGN_RODATA is not set
-# CONFIG_DEBUG_ATOMIC_SLEEP is not set
-# CONFIG_DEBUG_BUGVERBOSE is not set
-# CONFIG_DEBUG_CGROUP_REF is not set
-# CONFIG_DEBUG_DEVRES is not set
-# CONFIG_DEBUG_DRIVER is not set
-# CONFIG_DEBUG_EFI is not set
-# CONFIG_DEBUG_FORCE_FUNCTION_ALIGN_64B is not set
-# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
-CONFIG_DEBUG_FS=y
-CONFIG_DEBUG_FS_ALLOW_ALL=y
-# CONFIG_DEBUG_FS_ALLOW_NONE is not set
-# CONFIG_DEBUG_FS_DISALLOW_MOUNT is not set
-# CONFIG_DEBUG_GPIO is not set
-# CONFIG_DEBUG_HIGHMEM is not set
-# CONFIG_DEBUG_ICEDCC is not set
-# CONFIG_DEBUG_INFO is not set
-# CONFIG_DEBUG_INFO_BTF is not set
-CONFIG_DEBUG_INFO_COMPRESSED_NONE=y
-# CONFIG_DEBUG_INFO_COMPRESSED_ZLIB is not set
-# CONFIG_DEBUG_INFO_COMPRESSED_ZSTD is not set
-# CONFIG_DEBUG_INFO_DWARF4 is not set
-# CONFIG_DEBUG_INFO_DWARF5 is not set
-CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y
-# CONFIG_DEBUG_INFO_NONE is not set
-# CONFIG_DEBUG_INFO_REDUCED is not set
-# CONFIG_DEBUG_INFO_SPLIT is not set
-# CONFIG_DEBUG_IRQFLAGS is not set
-CONFIG_DEBUG_KERNEL=y
-# CONFIG_DEBUG_KMAP_LOCAL is not set
-# CONFIG_DEBUG_KMEMLEAK is not set
-# CONFIG_DEBUG_KOBJECT is not set
-# CONFIG_DEBUG_KOBJECT_RELEASE is not set
-# CONFIG_DEBUG_LIST is not set
-# CONFIG_DEBUG_LL is not set
-# CONFIG_DEBUG_LL_UART_8250 is not set
-# CONFIG_DEBUG_LL_UART_PL01X is not set
-# CONFIG_DEBUG_LOCKDEP is not set
-# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
-# CONFIG_DEBUG_LOCK_ALLOC is not set
-# CONFIG_DEBUG_MAPLE_TREE is not set
-# CONFIG_DEBUG_MEMORY_INIT is not set
-# CONFIG_DEBUG_MISC is not set
-# CONFIG_DEBUG_MUTEXES is not set
-# CONFIG_DEBUG_NET is not set
-# CONFIG_DEBUG_NOTIFIERS is not set
-# CONFIG_DEBUG_OBJECTS is not set
-# CONFIG_DEBUG_PAGEALLOC is not set
-# CONFIG_DEBUG_PAGE_REF is not set
-# CONFIG_DEBUG_PERF_USE_VMALLOC is not set
-# CONFIG_DEBUG_PER_CPU_MAPS is not set
-# CONFIG_DEBUG_PINCTRL is not set
-# CONFIG_DEBUG_PLIST is not set
-# CONFIG_DEBUG_PREEMPT is not set
-# CONFIG_DEBUG_RODATA_TEST is not set
-# CONFIG_DEBUG_RSEQ is not set
-# CONFIG_DEBUG_RT_MUTEXES is not set
-# CONFIG_DEBUG_RWSEMS is not set
-# CONFIG_DEBUG_SECTION_MISMATCH is not set
-# CONFIG_DEBUG_SEMIHOSTING is not set
-# CONFIG_DEBUG_SG is not set
-# CONFIG_DEBUG_SHIRQ is not set
-# CONFIG_DEBUG_SLAB is not set
-# CONFIG_DEBUG_SPINLOCK is not set
-# CONFIG_DEBUG_STACKOVERFLOW is not set
-# CONFIG_DEBUG_STACK_USAGE is not set
-# CONFIG_DEBUG_TEST_DRIVER_REMOVE is not set
-# CONFIG_DEBUG_TIMEKEEPING is not set
-# CONFIG_DEBUG_UART_8250_PALMCHIP is not set
-# CONFIG_DEBUG_UART_8250_WORD is not set
-# CONFIG_DEBUG_UART_FLOW_CONTROL is not set
-# CONFIG_DEBUG_USER is not set
-# CONFIG_DEBUG_VIRTUAL is not set
-# CONFIG_DEBUG_VM is not set
-# CONFIG_DEBUG_VM_MAPLE_TREE is not set
-# CONFIG_DEBUG_VM_PGFLAGS is not set
-# CONFIG_DEBUG_VM_PGTABLE is not set
-# CONFIG_DEBUG_VM_RB is not set
-# CONFIG_DEBUG_WQ_FORCE_RR_CPU is not set
-# CONFIG_DEBUG_WW_MUTEX_SLOWPATH is not set
-# CONFIG_DEBUG_WX is not set
-# CONFIG_DEBUG_ZBOOT is not set
-# CONFIG_DEFAULT_CODEL is not set
-CONFIG_DEFAULT_CUBIC=y
-# CONFIG_DEFAULT_FQ is not set
-CONFIG_DEFAULT_FQ_CODEL=y
-# CONFIG_DEFAULT_FQ_PIE is not set
-CONFIG_DEFAULT_HOSTNAME="(none)"
-CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=120
-CONFIG_DEFAULT_INIT=""
-CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
-CONFIG_DEFAULT_NET_SCH="fq_codel"
-# CONFIG_DEFAULT_PFIFO_FAST is not set
-# CONFIG_DEFAULT_RENO is not set
-CONFIG_DEFAULT_SECURITY_DAC=y
-# CONFIG_DEFAULT_SECURITY_SELINUX is not set
-# CONFIG_DEFAULT_SFQ is not set
-CONFIG_DEFAULT_TCP_CONG="cubic"
-# CONFIG_DEFERRED_STRUCT_PAGE_INIT is not set
-# CONFIG_DELL_LAPTOP is not set
-# CONFIG_DELL_RBTN is not set
-# CONFIG_DELL_SMBIOS is not set
-# CONFIG_DELL_SMO8800 is not set
-# CONFIG_DEPRECATED_PARAM_STRUCT is not set
-# CONFIG_DETECT_HUNG_TASK is not set
-# CONFIG_DEVMEM is not set
-CONFIG_DEVPORT=y
-# CONFIG_DEVTMPFS is not set
-# CONFIG_DEVTMPFS_MOUNT is not set
-# CONFIG_DEVTMPFS_SAFE is not set
-# CONFIG_DEV_DAX is not set
-# CONFIG_DHT11 is not set
-# CONFIG_DL2K is not set
-# CONFIG_DLHL60D is not set
-# CONFIG_DLM is not set
-# CONFIG_DM9000 is not set
-# CONFIG_DM9051 is not set
-# CONFIG_DMABUF_DEBUG is not set
-# CONFIG_DMABUF_HEAPS is not set
-# CONFIG_DMABUF_MOVE_NOTIFY is not set
-# CONFIG_DMABUF_SELFTESTS is not set
-# CONFIG_DMABUF_SYSFS_STATS is not set
-# CONFIG_DMADEVICES is not set
-# CONFIG_DMADEVICES_DEBUG is not set
-# CONFIG_DMAPOOL_TEST is not set
-# CONFIG_DMARD06 is not set
-# CONFIG_DMARD09 is not set
-# CONFIG_DMARD10 is not set
-# CONFIG_DMATEST is not set
-# CONFIG_DMA_API_DEBUG is not set
-CONFIG_DMA_COHERENT_POOL=y
-CONFIG_DMA_DECLARE_COHERENT=y
-# CONFIG_DMA_ENGINE is not set
-# CONFIG_DMA_FENCE_TRACE is not set
-# CONFIG_DMA_JZ4780 is not set
-# CONFIG_DMA_MAP_BENCHMARK is not set
-CONFIG_DMA_NONCOHERENT_MMAP=y
-# CONFIG_DMA_RESTRICTED_POOL is not set
-# CONFIG_DMA_SHARED_BUFFER is not set
-# CONFIG_DM_AUDIT is not set
-# CONFIG_DM_CACHE is not set
-# CONFIG_DM_CLONE is not set
-# CONFIG_DM_DEBUG is not set
-# CONFIG_DM_DELAY is not set
-# CONFIG_DM_DUST is not set
-# CONFIG_DM_EBS is not set
-# CONFIG_DM_ERA is not set
-# CONFIG_DM_FLAKEY is not set
-# CONFIG_DM_INTEGRITY is not set
-# CONFIG_DM_LOG_USERSPACE is not set
-# CONFIG_DM_LOG_WRITES is not set
-# CONFIG_DM_MULTIPATH is not set
-# CONFIG_DM_RAID is not set
-# CONFIG_DM_SWITCH is not set
-# CONFIG_DM_THIN_PROVISIONING is not set
-# CONFIG_DM_UEVENT is not set
-# CONFIG_DM_UNSTRIPED is not set
-# CONFIG_DM_VERITY is not set
-# CONFIG_DM_WRITECACHE is not set
-# CONFIG_DM_ZERO is not set
-# CONFIG_DM_ZONED is not set
-# CONFIG_DNET is not set
-# CONFIG_DNOTIFY is not set
-# CONFIG_DNS_RESOLVER is not set
-# CONFIG_DP83640_PHY is not set
-# CONFIG_DP83822_PHY is not set
-# CONFIG_DP83848_PHY is not set
-# CONFIG_DP83867_PHY is not set
-# CONFIG_DP83869_PHY is not set
-# CONFIG_DP83TC811_PHY is not set
-# CONFIG_DP83TD510_PHY is not set
-# CONFIG_DPM_WATCHDOG is not set
-# CONFIG_DPOT_DAC is not set
-# CONFIG_DPS310 is not set
-CONFIG_DQL=y
-# CONFIG_DRAGONRISE_FF is not set
-# CONFIG_DRM is not set
-# CONFIG_DRM_ACCEL is not set
-# CONFIG_DRM_AMDGPU is not set
-# CONFIG_DRM_AMDGPU_CIK is not set
-# CONFIG_DRM_AMDGPU_SI is not set
-# CONFIG_DRM_AMDGPU_USERPTR is not set
-# CONFIG_DRM_AMDGPU_WERROR is not set
-# CONFIG_DRM_AMD_ACP is not set
-# CONFIG_DRM_AMD_DC_SI is not set
-# CONFIG_DRM_AMD_SECURE_DISPLAY is not set
-# CONFIG_DRM_ANALOGIX_ANX6345 is not set
-# CONFIG_DRM_ANALOGIX_ANX7625 is not set
-# CONFIG_DRM_ANALOGIX_ANX78XX is not set
-# CONFIG_DRM_ARCPGU is not set
-# CONFIG_DRM_ARMADA is not set
-# CONFIG_DRM_AST is not set
-# CONFIG_DRM_ATMEL_HLCDC is not set
-# CONFIG_DRM_BOCHS is not set
-# CONFIG_DRM_CDNS_DSI is not set
-# CONFIG_DRM_CDNS_MHDP8546 is not set
-# CONFIG_DRM_CHIPONE_ICN6211 is not set
-# CONFIG_DRM_CHRONTEL_CH7033 is not set
-# CONFIG_DRM_CIRRUS_QEMU is not set
-# CONFIG_DRM_DEBUG_DP_MST_TOPOLOGY_REFS is not set
-# CONFIG_DRM_DEBUG_MM is not set
-# CONFIG_DRM_DEBUG_MODESET_LOCK is not set
-# CONFIG_DRM_DISPLAY_CONNECTOR is not set
-# CONFIG_DRM_DP_AUX_CHARDEV is not set
-# CONFIG_DRM_DP_CEC is not set
-# CONFIG_DRM_DW_HDMI_CEC is not set
-# CONFIG_DRM_ETNAVIV is not set
-# CONFIG_DRM_EXYNOS is not set
-# CONFIG_DRM_FBDEV_EMULATION is not set
-# CONFIG_DRM_FBDEV_LEAK_PHYS_SMEM is not set
-# CONFIG_DRM_FSL_DCU is not set
-# CONFIG_DRM_GM12U320 is not set
-# CONFIG_DRM_GMA500 is not set
-# CONFIG_DRM_GUD is not set
-# CONFIG_DRM_HDLCD is not set
-# CONFIG_DRM_HISI_HIBMC is not set
-# CONFIG_DRM_HISI_KIRIN is not set
-# CONFIG_DRM_I2C_ADV7511 is not set
-# CONFIG_DRM_I2C_CH7006 is not set
-# CONFIG_DRM_I2C_NXP_TDA9950 is not set
-# CONFIG_DRM_I2C_NXP_TDA998X is not set
-# CONFIG_DRM_I2C_SIL164 is not set
-# CONFIG_DRM_I915 is not set
-# CONFIG_DRM_IMX_LCDIF is not set
-# CONFIG_DRM_ITE_IT6505 is not set
-# CONFIG_DRM_ITE_IT66121 is not set
-# CONFIG_DRM_KOMEDA is not set
-# CONFIG_DRM_LEGACY is not set
-# CONFIG_DRM_LIB_RANDOM is not set
-# CONFIG_DRM_LIMA is not set
-# CONFIG_DRM_LOAD_EDID_FIRMWARE is not set
-# CONFIG_DRM_LOGICVC is not set
-# CONFIG_DRM_LONTIUM_LT8912B is not set
-# CONFIG_DRM_LONTIUM_LT9211 is not set
-# CONFIG_DRM_LONTIUM_LT9611 is not set
-# CONFIG_DRM_LONTIUM_LT9611UXC is not set
-# CONFIG_DRM_LOONGSON is not set
-# CONFIG_DRM_LVDS_CODEC is not set
-# CONFIG_DRM_MALI_DISPLAY is not set
-# CONFIG_DRM_MCDE is not set
-# CONFIG_DRM_MEGACHIPS_STDPXXXX_GE_B850V3_FW is not set
-# CONFIG_DRM_MGAG200 is not set
-# CONFIG_DRM_MXSFB is not set
-# CONFIG_DRM_NOUVEAU is not set
-# CONFIG_DRM_NWL_MIPI_DSI is not set
-# CONFIG_DRM_NXP_PTN3460 is not set
-# CONFIG_DRM_OFDRM is not set
-# CONFIG_DRM_OMAP is not set
-# CONFIG_DRM_PANEL_ABT_Y030XX067A is not set
-# CONFIG_DRM_PANEL_ARM_VERSATILE is not set
-# CONFIG_DRM_PANEL_ASUS_Z00T_TM5P5_NT35596 is not set
-# CONFIG_DRM_PANEL_AUO_A030JTN01 is not set
-# CONFIG_DRM_PANEL_BOE_BF060Y8M_AJ0 is not set
-# CONFIG_DRM_PANEL_BOE_HIMAX8279D is not set
-# CONFIG_DRM_PANEL_BOE_TV101WUM_NL6 is not set
-# CONFIG_DRM_PANEL_DSI_CM is not set
-# CONFIG_DRM_PANEL_EBBG_FT8719 is not set
-# CONFIG_DRM_PANEL_EDP is not set
-# CONFIG_DRM_PANEL_ELIDA_KD35T133 is not set
-# CONFIG_DRM_PANEL_FEIXIN_K101_IM2BA02 is not set
-# CONFIG_DRM_PANEL_FEIYANG_FY07024DI26A30D is not set
-# CONFIG_DRM_PANEL_HIMAX_HX8394 is not set
-# CONFIG_DRM_PANEL_ILITEK_IL9322 is not set
-# CONFIG_DRM_PANEL_ILITEK_ILI9341 is not set
-# CONFIG_DRM_PANEL_ILITEK_ILI9881C is not set
-# CONFIG_DRM_PANEL_INNOLUX_EJ030NA is not set
-# CONFIG_DRM_PANEL_INNOLUX_P079ZCA is not set
-# CONFIG_DRM_PANEL_JADARD_JD9365DA_H3 is not set
-# CONFIG_DRM_PANEL_JDI_LT070ME05000 is not set
-# CONFIG_DRM_PANEL_JDI_R63452 is not set
-# CONFIG_DRM_PANEL_KHADAS_TS050 is not set
-# CONFIG_DRM_PANEL_KINGDISPLAY_KD097D04 is not set
-# CONFIG_DRM_PANEL_LEADTEK_LTK050H3146W is not set
-# CONFIG_DRM_PANEL_LEADTEK_LTK500HD1829 is not set
-# CONFIG_DRM_PANEL_LG_LB035Q02 is not set
-# CONFIG_DRM_PANEL_LG_LG4573 is not set
-# CONFIG_DRM_PANEL_LVDS is not set
-# CONFIG_DRM_PANEL_MAGNACHIP_D53E6EA8966 is not set
-# CONFIG_DRM_PANEL_MANTIX_MLAF057WE51 is not set
-# CONFIG_DRM_PANEL_MIPI_DBI is not set
-# CONFIG_DRM_PANEL_NEC_NL8048HL11 is not set
-# CONFIG_DRM_PANEL_NEWVISION_NV3051D is not set
-# CONFIG_DRM_PANEL_NEWVISION_NV3052C is not set
-# CONFIG_DRM_PANEL_NOVATEK_NT35510 is not set
-# CONFIG_DRM_PANEL_NOVATEK_NT35560 is not set
-# CONFIG_DRM_PANEL_NOVATEK_NT35950 is not set
-# CONFIG_DRM_PANEL_NOVATEK_NT36523 is not set
-# CONFIG_DRM_PANEL_NOVATEK_NT36672A is not set
-# CONFIG_DRM_PANEL_NOVATEK_NT39016 is not set
-# CONFIG_DRM_PANEL_OLIMEX_LCD_OLINUXINO is not set
-# CONFIG_DRM_PANEL_ORISETECH_OTA5601A is not set
-# CONFIG_DRM_PANEL_ORISETECH_OTM8009A is not set
-# CONFIG_DRM_PANEL_OSD_OSD101T2587_53TS is not set
-# CONFIG_DRM_PANEL_PANASONIC_VVX10F034N00 is not set
-# CONFIG_DRM_PANEL_RASPBERRYPI_TOUCHSCREEN is not set
-# CONFIG_DRM_PANEL_RAYDIUM_RM67191 is not set
-# CONFIG_DRM_PANEL_RAYDIUM_RM68200 is not set
-# CONFIG_DRM_PANEL_RONBO_RB070D30 is not set
-# CONFIG_DRM_PANEL_SAMSUNG_ATNA33XC20 is not set
-# CONFIG_DRM_PANEL_SAMSUNG_DB7430 is not set
-# CONFIG_DRM_PANEL_SAMSUNG_LD9040 is not set
-# CONFIG_DRM_PANEL_SAMSUNG_S6D16D0 is not set
-# CONFIG_DRM_PANEL_SAMSUNG_S6D27A1 is not set
-# CONFIG_DRM_PANEL_SAMSUNG_S6D7AA0 is not set
-# CONFIG_DRM_PANEL_SAMSUNG_S6E3HA2 is not set
-# CONFIG_DRM_PANEL_SAMSUNG_S6E63J0X03 is not set
-# CONFIG_DRM_PANEL_SAMSUNG_S6E63M0 is not set
-# CONFIG_DRM_PANEL_SAMSUNG_S6E88A0_AMS452EF01 is not set
-# CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0 is not set
-# CONFIG_DRM_PANEL_SAMSUNG_SOFEF00 is not set
-# CONFIG_DRM_PANEL_SEIKO_43WVF1G is not set
-# CONFIG_DRM_PANEL_SHARP_LQ101R1SX01 is not set
-# CONFIG_DRM_PANEL_SHARP_LS037V7DW01 is not set
-# CONFIG_DRM_PANEL_SHARP_LS043T1LE01 is not set
-# CONFIG_DRM_PANEL_SHARP_LS060T1SX01 is not set
-# CONFIG_DRM_PANEL_SIMPLE is not set
-# CONFIG_DRM_PANEL_SITRONIX_ST7701 is not set
-# CONFIG_DRM_PANEL_SITRONIX_ST7703 is not set
-# CONFIG_DRM_PANEL_SITRONIX_ST7789V is not set
-# CONFIG_DRM_PANEL_SONY_ACX565AKM is not set
-# CONFIG_DRM_PANEL_SONY_TD4353_JDI is not set
-# CONFIG_DRM_PANEL_SONY_TULIP_TRULY_NT35521 is not set
-# CONFIG_DRM_PANEL_STARTEK_KD070FHFID015 is not set
-# CONFIG_DRM_PANEL_TDO_TL070WSH30 is not set
-# CONFIG_DRM_PANEL_TPO_TD028TTEC1 is not set
-# CONFIG_DRM_PANEL_TPO_TD043MTEA1 is not set
-# CONFIG_DRM_PANEL_TPO_TPG110 is not set
-# CONFIG_DRM_PANEL_TRULY_NT35597_WQXGA is not set
-# CONFIG_DRM_PANEL_VISIONOX_R66451 is not set
-# CONFIG_DRM_PANEL_VISIONOX_RM69299 is not set
-# CONFIG_DRM_PANEL_VISIONOX_VTDR6130 is not set
-# CONFIG_DRM_PANEL_WIDECHIPS_WS2401 is not set
-# CONFIG_DRM_PANEL_XINPENG_XPP055C272 is not set
-# CONFIG_DRM_PANFROST is not set
-# CONFIG_DRM_PARADE_PS8622 is not set
-# CONFIG_DRM_PARADE_PS8640 is not set
-# CONFIG_DRM_PL111 is not set
-# CONFIG_DRM_QXL is not set
-# CONFIG_DRM_RADEON is not set
-# CONFIG_DRM_RADEON_USERPTR is not set
-# CONFIG_DRM_RCAR_DW_HDMI is not set
-# CONFIG_DRM_RCAR_LVDS is not set
-# CONFIG_DRM_RCAR_USE_LVDS is not set
-# CONFIG_DRM_RCAR_USE_MIPI_DSI is not set
-# CONFIG_DRM_ROCKCHIP is not set
-# CONFIG_DRM_SAMSUNG_DSIM is not set
-# CONFIG_DRM_SII902X is not set
-# CONFIG_DRM_SII9234 is not set
-# CONFIG_DRM_SIL_SII8620 is not set
-# CONFIG_DRM_SIMPLEDRM is not set
-# CONFIG_DRM_SIMPLE_BRIDGE is not set
-# CONFIG_DRM_SSD130X is not set
-# CONFIG_DRM_STI is not set
-# CONFIG_DRM_STM is not set
-# CONFIG_DRM_SUN4I is not set
-# CONFIG_DRM_THINE_THC63LVD1024 is not set
-# CONFIG_DRM_TIDSS is not set
-# CONFIG_DRM_TILCDC is not set
-# CONFIG_DRM_TI_DLPC3433 is not set
-# CONFIG_DRM_TI_SN65DSI83 is not set
-# CONFIG_DRM_TI_SN65DSI86 is not set
-# CONFIG_DRM_TI_TFP410 is not set
-# CONFIG_DRM_TI_TPD12S015 is not set
-# CONFIG_DRM_TOSHIBA_TC358762 is not set
-# CONFIG_DRM_TOSHIBA_TC358764 is not set
-# CONFIG_DRM_TOSHIBA_TC358767 is not set
-# CONFIG_DRM_TOSHIBA_TC358768 is not set
-# CONFIG_DRM_TOSHIBA_TC358775 is not set
-# CONFIG_DRM_TVE200 is not set
-# CONFIG_DRM_UDL is not set
-# CONFIG_DRM_V3D is not set
-# CONFIG_DRM_VBOXVIDEO is not set
-# CONFIG_DRM_VC4_HDMI_CEC is not set
-# CONFIG_DRM_VGEM is not set
-# CONFIG_DRM_VIRTIO_GPU is not set
-# CONFIG_DRM_VKMS is not set
-# CONFIG_DRM_VMWGFX is not set
-# CONFIG_DRM_XEN is not set
-# CONFIG_DRM_XEN_FRONTEND is not set
-# CONFIG_DS1682 is not set
-# CONFIG_DS1803 is not set
-# CONFIG_DS4424 is not set
-# CONFIG_DST_CACHE is not set
-# CONFIG_DTLK is not set
-# CONFIG_DUMMY is not set
-CONFIG_DUMMY_CONSOLE_COLUMNS=80
-CONFIG_DUMMY_CONSOLE_ROWS=25
-# CONFIG_DUMMY_IRQ is not set
-# CONFIG_DVB_A8293 is not set
-# CONFIG_DVB_AF9013 is not set
-# CONFIG_DVB_AF9033 is not set
-# CONFIG_DVB_AS102 is not set
-# CONFIG_DVB_ASCOT2E is not set
-# CONFIG_DVB_ATBM8830 is not set
-# CONFIG_DVB_AU8522_DTV is not set
-# CONFIG_DVB_AU8522_V4L is not set
-# CONFIG_DVB_B2C2_FLEXCOP_PCI is not set
-# CONFIG_DVB_B2C2_FLEXCOP_USB is not set
-# CONFIG_DVB_BCM3510 is not set
-# CONFIG_DVB_CORE is not set
-# CONFIG_DVB_CX22700 is not set
-# CONFIG_DVB_CX22702 is not set
-# CONFIG_DVB_CX24110 is not set
-# CONFIG_DVB_CX24116 is not set
-# CONFIG_DVB_CX24117 is not set
-# CONFIG_DVB_CX24120 is not set
-# CONFIG_DVB_CX24123 is not set
-# CONFIG_DVB_CXD2099 is not set
-# CONFIG_DVB_CXD2820R is not set
-# CONFIG_DVB_CXD2841ER is not set
-# CONFIG_DVB_CXD2880 is not set
-# CONFIG_DVB_DDBRIDGE is not set
-# CONFIG_DVB_DEMUX_SECTION_LOSS_LOG is not set
-# CONFIG_DVB_DIB3000MB is not set
-# CONFIG_DVB_DIB3000MC is not set
-# CONFIG_DVB_DIB7000M is not set
-# CONFIG_DVB_DIB7000P is not set
-# CONFIG_DVB_DIB8000 is not set
-# CONFIG_DVB_DIB9000 is not set
-# CONFIG_DVB_DRX39XYJ is not set
-# CONFIG_DVB_DRXD is not set
-# CONFIG_DVB_DRXK is not set
-# CONFIG_DVB_DS3000 is not set
-# CONFIG_DVB_DUMMY_FE is not set
-# CONFIG_DVB_DYNAMIC_MINORS is not set
-# CONFIG_DVB_EC100 is not set
-# CONFIG_DVB_FIREDTV is not set
-# CONFIG_DVB_HELENE is not set
-# CONFIG_DVB_HORUS3A is not set
-# CONFIG_DVB_ISL6405 is not set
-# CONFIG_DVB_ISL6421 is not set
-# CONFIG_DVB_ISL6423 is not set
-# CONFIG_DVB_IX2505V is not set
-# CONFIG_DVB_L64781 is not set
-# CONFIG_DVB_LG2160 is not set
-# CONFIG_DVB_LGDT3305 is not set
-# CONFIG_DVB_LGDT3306A is not set
-# CONFIG_DVB_LGDT330X is not set
-# CONFIG_DVB_LGS8GL5 is not set
-# CONFIG_DVB_LGS8GXX is not set
-# CONFIG_DVB_LNBH25 is not set
-# CONFIG_DVB_LNBH29 is not set
-# CONFIG_DVB_LNBP21 is not set
-# CONFIG_DVB_LNBP22 is not set
-# CONFIG_DVB_M88DS3103 is not set
-# CONFIG_DVB_M88RS2000 is not set
-CONFIG_DVB_MAX_ADAPTERS=16
-# CONFIG_DVB_MB86A16 is not set
-# CONFIG_DVB_MB86A20S is not set
-# CONFIG_DVB_MMAP is not set
-# CONFIG_DVB_MN88443X is not set
-# CONFIG_DVB_MN88472 is not set
-# CONFIG_DVB_MN88473 is not set
-# CONFIG_DVB_MT312 is not set
-# CONFIG_DVB_MT352 is not set
-# CONFIG_DVB_MXL5XX is not set
-# CONFIG_DVB_MXL692 is not set
-# CONFIG_DVB_NET is not set
-# CONFIG_DVB_NETUP_UNIDVB is not set
-# CONFIG_DVB_NGENE is not set
-# CONFIG_DVB_NXT200X is not set
-# CONFIG_DVB_NXT6000 is not set
-# CONFIG_DVB_OR51132 is not set
-# CONFIG_DVB_OR51211 is not set
-# CONFIG_DVB_PLATFORM_DRIVERS is not set
-# CONFIG_DVB_PLL is not set
-# CONFIG_DVB_PLUTO2 is not set
-# CONFIG_DVB_PT1 is not set
-# CONFIG_DVB_PT3 is not set
-# CONFIG_DVB_RTL2830 is not set
-# CONFIG_DVB_RTL2832 is not set
-# CONFIG_DVB_RTL2832_SDR is not set
-# CONFIG_DVB_S5H1409 is not set
-# CONFIG_DVB_S5H1411 is not set
-# CONFIG_DVB_S5H1420 is not set
-# CONFIG_DVB_S5H1432 is not set
-# CONFIG_DVB_S921 is not set
-# CONFIG_DVB_SI2165 is not set
-# CONFIG_DVB_SI2168 is not set
-# CONFIG_DVB_SI21XX is not set
-# CONFIG_DVB_SP2 is not set
-# CONFIG_DVB_SP8870 is not set
-# CONFIG_DVB_SP887X is not set
-# CONFIG_DVB_STB0899 is not set
-# CONFIG_DVB_STB6000 is not set
-# CONFIG_DVB_STB6100 is not set
-# CONFIG_DVB_STV0288 is not set
-# CONFIG_DVB_STV0297 is not set
-# CONFIG_DVB_STV0299 is not set
-# CONFIG_DVB_STV0367 is not set
-# CONFIG_DVB_STV0900 is not set
-# CONFIG_DVB_STV090x is not set
-# CONFIG_DVB_STV0910 is not set
-# CONFIG_DVB_STV6110 is not set
-# CONFIG_DVB_STV6110x is not set
-# CONFIG_DVB_STV6111 is not set
-# CONFIG_DVB_TC90522 is not set
-# CONFIG_DVB_TDA10021 is not set
-# CONFIG_DVB_TDA10023 is not set
-# CONFIG_DVB_TDA10048 is not set
-# CONFIG_DVB_TDA1004X is not set
-# CONFIG_DVB_TDA10071 is not set
-# CONFIG_DVB_TDA10086 is not set
-# CONFIG_DVB_TDA18271C2DD is not set
-# CONFIG_DVB_TDA665x is not set
-# CONFIG_DVB_TDA8083 is not set
-# CONFIG_DVB_TDA8261 is not set
-# CONFIG_DVB_TDA826X is not set
-# CONFIG_DVB_TEST_DRIVERS is not set
-# CONFIG_DVB_TS2020 is not set
-# CONFIG_DVB_TTUSB_BUDGET is not set
-# CONFIG_DVB_TTUSB_DEC is not set
-# CONFIG_DVB_TUA6100 is not set
-# CONFIG_DVB_TUNER_CX24113 is not set
-# CONFIG_DVB_TUNER_DIB0070 is not set
-# CONFIG_DVB_TUNER_DIB0090 is not set
-# CONFIG_DVB_TUNER_ITD1000 is not set
-# CONFIG_DVB_ULE_DEBUG is not set
-# CONFIG_DVB_USB is not set
-# CONFIG_DVB_USB_V2 is not set
-# CONFIG_DVB_VES1820 is not set
-# CONFIG_DVB_VES1X93 is not set
-# CONFIG_DVB_ZD1301_DEMOD is not set
-# CONFIG_DVB_ZL10036 is not set
-# CONFIG_DVB_ZL10039 is not set
-# CONFIG_DVB_ZL10353 is not set
-# CONFIG_DWC_XLGMAC is not set
-# CONFIG_DWMAC_DWC_QOS_ETH is not set
-# CONFIG_DWMAC_INTEL_PLAT is not set
-# CONFIG_DWMAC_IPQ806X is not set
-# CONFIG_DWMAC_LOONGSON is not set
-# CONFIG_DWMAC_LPC18XX is not set
-# CONFIG_DWMAC_MESON is not set
-# CONFIG_DWMAC_ROCKCHIP is not set
-# CONFIG_DWMAC_SOCFPGA is not set
-# CONFIG_DWMAC_STI is not set
-# CONFIG_DW_AXI_DMAC is not set
-# CONFIG_DW_DMAC is not set
-# CONFIG_DW_DMAC_PCI is not set
-# CONFIG_DW_EDMA is not set
-# CONFIG_DW_EDMA_PCIE is not set
-# CONFIG_DW_WATCHDOG is not set
-# CONFIG_DW_XDATA_PCIE is not set
-# CONFIG_DYNAMIC_DEBUG is not set
-# CONFIG_DYNAMIC_DEBUG_CORE is not set
-# CONFIG_E100 is not set
-# CONFIG_E1000 is not set
-# CONFIG_E1000E is not set
-# CONFIG_E1000E_HWTS is not set
-# CONFIG_EARLY_PRINTK_8250 is not set
-# CONFIG_EARLY_PRINTK_USB_XDBC is not set
-# CONFIG_EBC_C384_WDT is not set
-# CONFIG_ECHO is not set
-# CONFIG_ECRYPT_FS is not set
-# CONFIG_EDAC is not set
-# CONFIG_EEEPC_LAPTOP is not set
-# CONFIG_EEPROM_93CX6 is not set
-# CONFIG_EEPROM_93XX46 is not set
-# CONFIG_EEPROM_AT24 is not set
-# CONFIG_EEPROM_AT25 is not set
-# CONFIG_EEPROM_DIGSY_MTC_CFG is not set
-# CONFIG_EEPROM_EE1004 is not set
-# CONFIG_EEPROM_IDT_89HPESX is not set
-# CONFIG_EEPROM_LEGACY is not set
-# CONFIG_EEPROM_MAX6875 is not set
-# CONFIG_EFI is not set
-CONFIG_EFI_PARTITION=y
-# CONFIG_EFI_VARS_PSTORE is not set
-# CONFIG_EFS_FS is not set
-CONFIG_ELFCORE=y
-# CONFIG_ELF_CORE is not set
-# CONFIG_EMAC_ROCKCHIP is not set
-# CONFIG_EM_TIMER_STI is not set
-# CONFIG_ENA_ETHERNET is not set
-# CONFIG_ENC28J60 is not set
-# CONFIG_ENCLOSURE_SERVICES is not set
-# CONFIG_ENCRYPTED_KEYS is not set
-# CONFIG_ENCX24J600 is not set
-# CONFIG_ENERGY_MODEL is not set
-# CONFIG_ENIC is not set
-# CONFIG_ENVELOPE_DETECTOR is not set
-# CONFIG_EPAPR_PARAVIRT is not set
-# CONFIG_EPIC100 is not set
-CONFIG_EPOLL=y
-# CONFIG_EQUALIZER is not set
-# CONFIG_EROFS_FS is not set
-# CONFIG_EROFS_FS_DEBUG is not set
-# CONFIG_EROFS_FS_ONDEMAND is not set
-CONFIG_EROFS_FS_PCPU_KTHREAD=y
-CONFIG_EROFS_FS_PCPU_KTHREAD_HIPRI=y
-# CONFIG_EROFS_FS_POSIX_ACL is not set
-# CONFIG_EROFS_FS_SECURITY is not set
-# CONFIG_EROFS_FS_XATTR is not set
-# CONFIG_EROFS_FS_ZIP is not set
-# CONFIG_EROFS_FS_ZIP_DEFLATE is not set
-# CONFIG_ET131X is not set
-CONFIG_ETHERNET=y
-# CONFIG_ETHOC is not set
-CONFIG_ETHTOOL_NETLINK=y
-CONFIG_EVENTFD=y
-# CONFIG_EVM is not set
-# CONFIG_EXFAT_FS is not set
-CONFIG_EXPERT=y
-CONFIG_EXPORTFS=y
-# CONFIG_EXPORTFS_BLOCK_OPS is not set
-# CONFIG_EXT2_FS is not set
-CONFIG_EXT2_FS_XATTR=y
-# CONFIG_EXT3_FS is not set
-# CONFIG_EXT4_DEBUG is not set
-# CONFIG_EXT4_FS is not set
-# CONFIG_EXT4_FS_POSIX_ACL is not set
-# CONFIG_EXT4_FS_SECURITY is not set
-CONFIG_EXT4_USE_FOR_EXT2=y
-# CONFIG_EXTCON is not set
-# CONFIG_EXTCON_ADC_JACK is not set
-# CONFIG_EXTCON_AXP288 is not set
-# CONFIG_EXTCON_FSA9480 is not set
-# CONFIG_EXTCON_GPIO is not set
-# CONFIG_EXTCON_INTEL_INT3496 is not set
-# CONFIG_EXTCON_MAX3355 is not set
-# CONFIG_EXTCON_PTN5150 is not set
-# CONFIG_EXTCON_QCOM_SPMI_MISC is not set
-# CONFIG_EXTCON_RT8973A is not set
-# CONFIG_EXTCON_SM5502 is not set
-# CONFIG_EXTCON_USBC_TUSB320 is not set
-# CONFIG_EXTCON_USB_GPIO is not set
-CONFIG_EXTRA_FIRMWARE=""
-CONFIG_EXTRA_TARGETS=""
-# CONFIG_EXYNOS_ADC is not set
-# CONFIG_EZCHIP_NPS_MANAGEMENT_ENET is not set
-# CONFIG_EZX_PCAP is not set
-# CONFIG_F2FS_CHECK_FS is not set
-# CONFIG_F2FS_FAULT_INJECTION is not set
-# CONFIG_F2FS_FS is not set
-# CONFIG_F2FS_FS_COMPRESSION is not set
-# CONFIG_F2FS_FS_POSIX_ACL is not set
-# CONFIG_F2FS_FS_SECURITY is not set
-CONFIG_F2FS_FS_XATTR=y
-# CONFIG_F2FS_IOSTAT is not set
-CONFIG_F2FS_STAT_FS=y
-# CONFIG_F2FS_UNFAIR_RWSEM is not set
-# CONFIG_FAILOVER is not set
-# CONFIG_FAIR_GROUP_SCHED is not set
-# CONFIG_FANOTIFY is not set
-# CONFIG_FANOTIFY_ACCESS_PERMISSIONS is not set
-CONFIG_FAT_DEFAULT_CODEPAGE=437
-CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
-# CONFIG_FAT_DEFAULT_UTF8 is not set
-# CONFIG_FAT_FS is not set
-# CONFIG_FAULT_INJECTION is not set
-# CONFIG_FB is not set
-# CONFIG_FB_3DFX is not set
-# CONFIG_FB_ARC is not set
-# CONFIG_FB_ARK is not set
-# CONFIG_FB_ARMCLCD is not set
-# CONFIG_FB_ASILIANT is not set
-# CONFIG_FB_ATMEL is not set
-# CONFIG_FB_ATY is not set
-# CONFIG_FB_ATY128 is not set
-# CONFIG_FB_BACKLIGHT is not set
-# CONFIG_FB_BIG_ENDIAN is not set
-# CONFIG_FB_BOTH_ENDIAN is not set
-# CONFIG_FB_BROADSHEET is not set
-# CONFIG_FB_CARMINE is not set
-# CONFIG_FB_CFB_COPYAREA is not set
-# CONFIG_FB_CFB_FILLRECT is not set
-# CONFIG_FB_CFB_IMAGEBLIT is not set
-# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
-# CONFIG_FB_CIRRUS is not set
-# CONFIG_FB_CYBER2000 is not set
-# CONFIG_FB_DA8XX is not set
-# CONFIG_FB_DDC is not set
-# CONFIG_FB_DEVICE is not set
-# CONFIG_FB_FOREIGN_ENDIAN is not set
-# CONFIG_FB_FSL_DIU is not set
-# CONFIG_FB_GEODE is not set
-# CONFIG_FB_GOLDFISH is not set
-# CONFIG_FB_HGA is not set
-# CONFIG_FB_I740 is not set
-# CONFIG_FB_IBM_GXT4500 is not set
-# CONFIG_FB_IMSTT is not set
-# CONFIG_FB_IMX is not set
-# CONFIG_FB_INTEL is not set
-# CONFIG_FB_KYRO is not set
-# CONFIG_FB_LE80578 is not set
-# CONFIG_FB_LITTLE_ENDIAN is not set
-# CONFIG_FB_MACMODES is not set
-# CONFIG_FB_MATROX is not set
-# CONFIG_FB_MB862XX is not set
-# CONFIG_FB_METRONOME is not set
-# CONFIG_FB_MODE_HELPERS is not set
-# CONFIG_FB_N411 is not set
-# CONFIG_FB_NEOMAGIC is not set
-CONFIG_FB_NOTIFY=y
-# CONFIG_FB_NVIDIA is not set
-# CONFIG_FB_OF is not set
-# CONFIG_FB_OMAP2 is not set
-# CONFIG_FB_OPENCORES is not set
-# CONFIG_FB_PM2 is not set
-# CONFIG_FB_PM3 is not set
-# CONFIG_FB_PS3 is not set
-# CONFIG_FB_PXA is not set
-# CONFIG_FB_RADEON is not set
-# CONFIG_FB_RIVA is not set
-# CONFIG_FB_S1D13XXX is not set
-# CONFIG_FB_S3 is not set
-# CONFIG_FB_SAVAGE is not set
-# CONFIG_FB_SIMPLE is not set
-# CONFIG_FB_SIS is not set
-# CONFIG_FB_SM712 is not set
-# CONFIG_FB_SM750 is not set
-# CONFIG_FB_SMSCUFX is not set
-# CONFIG_FB_SSD1307 is not set
-# CONFIG_FB_SVGALIB is not set
-# CONFIG_FB_SYS_COPYAREA is not set
-# CONFIG_FB_SYS_FILLRECT is not set
-# CONFIG_FB_SYS_FOPS is not set
-# CONFIG_FB_SYS_IMAGEBLIT is not set
-# CONFIG_FB_TFT is not set
-# CONFIG_FB_TFT_AGM1264K_FL is not set
-# CONFIG_FB_TFT_BD663474 is not set
-# CONFIG_FB_TFT_HX8340BN is not set
-# CONFIG_FB_TFT_HX8347D is not set
-# CONFIG_FB_TFT_HX8353D is not set
-# CONFIG_FB_TFT_HX8357D is not set
-# CONFIG_FB_TFT_ILI9163 is not set
-# CONFIG_FB_TFT_ILI9320 is not set
-# CONFIG_FB_TFT_ILI9325 is not set
-# CONFIG_FB_TFT_ILI9340 is not set
-# CONFIG_FB_TFT_ILI9341 is not set
-# CONFIG_FB_TFT_ILI9481 is not set
-# CONFIG_FB_TFT_ILI9486 is not set
-# CONFIG_FB_TFT_PCD8544 is not set
-# CONFIG_FB_TFT_RA8875 is not set
-# CONFIG_FB_TFT_S6D02A1 is not set
-# CONFIG_FB_TFT_S6D1121 is not set
-# CONFIG_FB_TFT_SEPS525 is not set
-# CONFIG_FB_TFT_SH1106 is not set
-# CONFIG_FB_TFT_SSD1289 is not set
-# CONFIG_FB_TFT_SSD1305 is not set
-# CONFIG_FB_TFT_SSD1306 is not set
-# CONFIG_FB_TFT_SSD1331 is not set
-# CONFIG_FB_TFT_SSD1351 is not set
-# CONFIG_FB_TFT_ST7735R is not set
-# CONFIG_FB_TFT_ST7789V is not set
-# CONFIG_FB_TFT_TINYLCD is not set
-# CONFIG_FB_TFT_TLS8204 is not set
-# CONFIG_FB_TFT_UC1611 is not set
-# CONFIG_FB_TFT_UC1701 is not set
-# CONFIG_FB_TFT_UPD161704 is not set
-# CONFIG_FB_TILEBLITTING is not set
-# CONFIG_FB_TRIDENT is not set
-# CONFIG_FB_UDL is not set
-# CONFIG_FB_UVESA is not set
-# CONFIG_FB_VGA16 is not set
-# CONFIG_FB_VIA is not set
-# CONFIG_FB_VIRTUAL is not set
-# CONFIG_FB_VOODOO1 is not set
-# CONFIG_FB_VT8623 is not set
-# CONFIG_FCOE is not set
-# CONFIG_FCOE_FNIC is not set
-# CONFIG_FDDI is not set
-# CONFIG_FEALNX is not set
-# CONFIG_FHANDLE is not set
-CONFIG_FIB_RULES=y
-# CONFIG_FIELDBUS_DEV is not set
-CONFIG_FILE_LOCKING=y
-# CONFIG_FIND_BIT_BENCHMARK is not set
-# CONFIG_FIREWIRE is not set
-# CONFIG_FIREWIRE_NOSY is not set
-# CONFIG_FIRMWARE_EDID is not set
-# CONFIG_FIRMWARE_MEMMAP is not set
-# CONFIG_FIXED_PHY is not set
-CONFIG_FLATMEM=y
-CONFIG_FLATMEM_MANUAL=y
-# CONFIG_FM10K is not set
-# CONFIG_FONTS is not set
-# CONFIG_FONT_6x8 is not set
-# CONFIG_FONT_TER16x32 is not set
-# CONFIG_FORCEDETH is not set
-# CONFIG_FORCE_NR_CPUS is not set
-CONFIG_FORTIFY_SOURCE=y
-# CONFIG_FPGA is not set
-# CONFIG_FPROBE is not set
-# CONFIG_FRAMEBUFFER_CONSOLE is not set
-# CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER is not set
-# CONFIG_FRAMEBUFFER_CONSOLE_LEGACY_ACCELERATION is not set
-# CONFIG_FRAME_POINTER is not set
-# CONFIG_FREEZER is not set
-# CONFIG_FSCACHE is not set
-# CONFIG_FSI is not set
-# CONFIG_FSL_DPAA2_SWITCH is not set
-# CONFIG_FSL_EDMA is not set
-# CONFIG_FSL_ENETC is not set
-# CONFIG_FSL_ENETC_IERB is not set
-# CONFIG_FSL_ENETC_MDIO is not set
-# CONFIG_FSL_ENETC_VF is not set
-# CONFIG_FSL_ERRATUM_A008585 is not set
-# CONFIG_FSL_MC_BUS is not set
-# CONFIG_FSL_PQ_MDIO is not set
-# CONFIG_FSL_QDMA is not set
-# CONFIG_FSL_RCPM is not set
-# CONFIG_FSL_XGMAC_MDIO is not set
-CONFIG_FSNOTIFY=y
-# CONFIG_FS_DAX is not set
-# CONFIG_FS_ENCRYPTION is not set
-# CONFIG_FS_POSIX_ACL is not set
-# CONFIG_FS_VERITY is not set
-# CONFIG_FTGMAC100 is not set
-# CONFIG_FTL is not set
-# CONFIG_FTMAC100 is not set
-# CONFIG_FTRACE is not set
-# CONFIG_FTRACE_RECORD_RECURSION is not set
-# CONFIG_FTRACE_SORT_STARTUP_TEST is not set
-# CONFIG_FTRACE_STARTUP_TEST is not set
-# CONFIG_FTR_FIXUP_SELFTEST is not set
-# CONFIG_FTWDT010_WATCHDOG is not set
-# CONFIG_FUJITSU_ERRATUM_010001 is not set
-# CONFIG_FUJITSU_ES is not set
-# CONFIG_FUJITSU_LAPTOP is not set
-# CONFIG_FUJITSU_TABLET is not set
-# CONFIG_FUNCTION_ERROR_INJECTION is not set
-# CONFIG_FUNCTION_GRAPH_RETVAL is not set
-# CONFIG_FUNCTION_TRACER is not set
-# CONFIG_FUN_ETH is not set
-# CONFIG_FUSE_FS is not set
-# CONFIG_FUSION is not set
-# CONFIG_FUSION_FC is not set
-# CONFIG_FUSION_SAS is not set
-# CONFIG_FUSION_SPI is not set
-CONFIG_FUTEX=y
-CONFIG_FUTEX_PI=y
-# CONFIG_FW_CFG_SYSFS is not set
-# CONFIG_FW_DEVLINK_SYNC_STATE_TIMEOUT is not set
-CONFIG_FW_LOADER=y
-# CONFIG_FW_LOADER_COMPRESS is not set
-# CONFIG_FW_LOADER_DEBUG is not set
-CONFIG_FW_LOADER_USER_HELPER=y
-CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y
-# CONFIG_FW_UPLOAD is not set
-# CONFIG_FXAS21002C is not set
-# CONFIG_FXLS8962AF_I2C is not set
-# CONFIG_FXLS8962AF_SPI is not set
-# CONFIG_FXOS8700_I2C is not set
-# CONFIG_FXOS8700_SPI is not set
-CONFIG_GACT_PROB=y
-# CONFIG_GADGET_UAC1 is not set
-# CONFIG_GAMEPORT is not set
-# CONFIG_GCC_PLUGINS is not set
-# CONFIG_GCOV is not set
-# CONFIG_GCOV_KERNEL is not set
-# CONFIG_GDB_SCRIPTS is not set
-# CONFIG_GEMINI_ETHERNET is not set
-# CONFIG_GENERIC_ADC_BATTERY is not set
-# CONFIG_GENERIC_ADC_THERMAL is not set
-CONFIG_GENERIC_CALIBRATE_DELAY=y
-# CONFIG_GENERIC_CPU_DEVICES is not set
-CONFIG_GENERIC_HWEIGHT=y
-# CONFIG_GENERIC_IRQ_DEBUGFS is not set
-CONFIG_GENERIC_IRQ_IPI=y
-CONFIG_GENERIC_IRQ_PROBE=y
-CONFIG_GENERIC_NET_UTILS=y
-# CONFIG_GENERIC_PHY is not set
-CONFIG_GENERIC_PTDUMP=y
-CONFIG_GENERIC_VDSO_TIME_NS=y
-# CONFIG_GENEVE is not set
-# CONFIG_GENWQE is not set
-# CONFIG_GFS2_FS is not set
-# CONFIG_GLOB_SELFTEST is not set
-# CONFIG_GNSS is not set
-# CONFIG_GOLDFISH is not set
-# CONFIG_GOOGLE_CBMEM is not set
-# CONFIG_GOOGLE_FIRMWARE is not set
-# CONFIG_GOOGLE_FRAMEBUFFER_COREBOOT is not set
-# CONFIG_GOOGLE_MEMCONSOLE_X86_LEGACY is not set
-# CONFIG_GOOGLE_SMI is not set
-# CONFIG_GP2AP002 is not set
-# CONFIG_GP2AP020A00F is not set
-# CONFIG_GPD_POCKET_FAN is not set
-CONFIG_GPIOLIB=y
-CONFIG_GPIOLIB_FASTPATH_LIMIT=512
-# CONFIG_GPIO_104_DIO_48E is not set
-# CONFIG_GPIO_104_IDIO_16 is not set
-# CONFIG_GPIO_104_IDI_48 is not set
-# CONFIG_GPIO_74X164 is not set
-# CONFIG_GPIO_74XX_MMIO is not set
-# CONFIG_GPIO_ADNP is not set
-# CONFIG_GPIO_AGGREGATOR is not set
-# CONFIG_GPIO_ALTERA is not set
-# CONFIG_GPIO_AMD8111 is not set
-# CONFIG_GPIO_AMDPT is not set
-# CONFIG_GPIO_AMD_FCH is not set
-# CONFIG_GPIO_BCM_KONA is not set
-# CONFIG_GPIO_BRCMSTB is not set
-# CONFIG_GPIO_BT8XX is not set
-# CONFIG_GPIO_CADENCE is not set
-# CONFIG_GPIO_CASCADE is not set
-# CONFIG_GPIO_CDEV is not set
-# CONFIG_GPIO_CDEV_V1 is not set
-# CONFIG_GPIO_CS5535 is not set
-# CONFIG_GPIO_DS4520 is not set
-# CONFIG_GPIO_DWAPB is not set
-# CONFIG_GPIO_EM is not set
-# CONFIG_GPIO_EXAR is not set
-# CONFIG_GPIO_F7188X is not set
-# CONFIG_GPIO_FTGPIO010 is not set
-# CONFIG_GPIO_FXL6408 is not set
-# CONFIG_GPIO_GENERIC_PLATFORM is not set
-# CONFIG_GPIO_GPIO_MM is not set
-# CONFIG_GPIO_GRGPIO is not set
-# CONFIG_GPIO_GW_PLD is not set
-# CONFIG_GPIO_HISI is not set
-# CONFIG_GPIO_HLWD is not set
-# CONFIG_GPIO_ICH is not set
-# CONFIG_GPIO_IT87 is not set
-# CONFIG_GPIO_LATCH is not set
-# CONFIG_GPIO_LOGICVC is not set
-# CONFIG_GPIO_MAX3191X is not set
-# CONFIG_GPIO_MAX7300 is not set
-# CONFIG_GPIO_MAX7301 is not set
-# CONFIG_GPIO_MAX732X is not set
-# CONFIG_GPIO_MB86S7X is not set
-# CONFIG_GPIO_MC33880 is not set
-# CONFIG_GPIO_ML_IOH is not set
-# CONFIG_GPIO_MOCKUP is not set
-# CONFIG_GPIO_MPC8XXX is not set
-# CONFIG_GPIO_PCA953X is not set
-# CONFIG_GPIO_PCA953X_IRQ is not set
-# CONFIG_GPIO_PCA9570 is not set
-# CONFIG_GPIO_PCF857X is not set
-# CONFIG_GPIO_PCH is not set
-# CONFIG_GPIO_PCIE_IDIO_24 is not set
-# CONFIG_GPIO_PCI_IDIO_16 is not set
-# CONFIG_GPIO_PISOSR is not set
-# CONFIG_GPIO_PL061 is not set
-# CONFIG_GPIO_RCAR is not set
-# CONFIG_GPIO_RDC321X is not set
-# CONFIG_GPIO_SAMA5D2_PIOBU is not set
-# CONFIG_GPIO_SCH is not set
-# CONFIG_GPIO_SCH311X is not set
-# CONFIG_GPIO_SIFIVE is not set
-# CONFIG_GPIO_SIM is not set
-# CONFIG_GPIO_SYSCON is not set
-CONFIG_GPIO_SYSFS=y
-# CONFIG_GPIO_TPIC2810 is not set
-# CONFIG_GPIO_TS4900 is not set
-# CONFIG_GPIO_TS5500 is not set
-# CONFIG_GPIO_VIRTIO is not set
-# CONFIG_GPIO_VX855 is not set
-# CONFIG_GPIO_WATCHDOG is not set
-# CONFIG_GPIO_WINBOND is not set
-# CONFIG_GPIO_WS16C48 is not set
-# CONFIG_GPIO_XGENE is not set
-# CONFIG_GPIO_XILINX is not set
-# CONFIG_GPIO_XRA1403 is not set
-# CONFIG_GPIO_ZEVIO is not set
-# CONFIG_GP_PCI1XXXX is not set
-# CONFIG_GREENASIA_FF is not set
-# CONFIG_GREYBUS is not set
-# CONFIG_GTP is not set
-# CONFIG_GUP_TEST is not set
-# CONFIG_GVE is not set
-# CONFIG_HAMACHI is not set
-# CONFIG_HAMRADIO is not set
-# CONFIG_HAPPYMEAL is not set
-CONFIG_HARDENED_USERCOPY=y
-CONFIG_HARDEN_BRANCH_HISTORY=y
-# CONFIG_HARDLOCKUP_DETECTOR is not set
-# CONFIG_HAVE_ARM_ARCH_TIMER is not set
-# CONFIG_HCALL_STATS is not set
-# CONFIG_HDC100X is not set
-# CONFIG_HDC2010 is not set
-# CONFIG_HDLC is not set
-# CONFIG_HDLC_CISCO is not set
-# CONFIG_HDLC_FR is not set
-# CONFIG_HDLC_PPP is not set
-# CONFIG_HDLC_RAW is not set
-# CONFIG_HDLC_RAW_ETH is not set
-# CONFIG_HDMI_LPE_AUDIO is not set
-# CONFIG_HDQ_MASTER_OMAP is not set
-# CONFIG_HEADERS_INSTALL is not set
-# CONFIG_HERMES is not set
-# CONFIG_HFSPLUS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_HI6421V600_IRQ is not set
-# CONFIG_HI8435 is not set
-# CONFIG_HIBERNATION is not set
-# CONFIG_HID is not set
-# CONFIG_HIDRAW is not set
-# CONFIG_HID_A4TECH is not set
-# CONFIG_HID_ACCUTOUCH is not set
-# CONFIG_HID_ACRUX is not set
-# CONFIG_HID_ACRUX_FF is not set
-# CONFIG_HID_ALPS is not set
-# CONFIG_HID_APPLE is not set
-# CONFIG_HID_APPLEIR is not set
-# CONFIG_HID_ASUS is not set
-# CONFIG_HID_AUREAL is not set
-# CONFIG_HID_BATTERY_STRENGTH is not set
-# CONFIG_HID_BELKIN is not set
-# CONFIG_HID_BETOP_FF is not set
-# CONFIG_HID_BIGBEN_FF is not set
-# CONFIG_HID_BPF is not set
-# CONFIG_HID_CHERRY is not set
-# CONFIG_HID_CHICONY is not set
-# CONFIG_HID_CMEDIA is not set
-# CONFIG_HID_CORSAIR is not set
-# CONFIG_HID_COUGAR is not set
-# CONFIG_HID_CP2112 is not set
-# CONFIG_HID_CREATIVE_SB0540 is not set
-# CONFIG_HID_CYPRESS is not set
-# CONFIG_HID_DRAGONRISE is not set
-# CONFIG_HID_ELAN is not set
-# CONFIG_HID_ELECOM is not set
-# CONFIG_HID_ELO is not set
-# CONFIG_HID_EMS_FF is not set
-# CONFIG_HID_EVISION is not set
-# CONFIG_HID_EZKEY is not set
-# CONFIG_HID_FT260 is not set
-# CONFIG_HID_GEMBIRD is not set
-# CONFIG_HID_GENERIC is not set
-# CONFIG_HID_GFRM is not set
-# CONFIG_HID_GLORIOUS is not set
-# CONFIG_HID_GOOGLE_HAMMER is not set
-# CONFIG_HID_GOOGLE_STADIA_FF is not set
-# CONFIG_HID_GREENASIA is not set
-# CONFIG_HID_GT683R is not set
-# CONFIG_HID_GYRATION is not set
-# CONFIG_HID_HOLTEK is not set
-# CONFIG_HID_ICADE is not set
-# CONFIG_HID_ITE is not set
-# CONFIG_HID_JABRA is not set
-# CONFIG_HID_KENSINGTON is not set
-# CONFIG_HID_KEYTOUCH is not set
-# CONFIG_HID_KYE is not set
-# CONFIG_HID_LCPOWER is not set
-# CONFIG_HID_LED is not set
-# CONFIG_HID_LENOVO is not set
-# CONFIG_HID_LETSKETCH is not set
-# CONFIG_HID_LOGITECH is not set
-# CONFIG_HID_LOGITECH_DJ is not set
-# CONFIG_HID_LOGITECH_HIDPP is not set
-# CONFIG_HID_MACALLY is not set
-# CONFIG_HID_MAGICMOUSE is not set
-# CONFIG_HID_MALTRON is not set
-# CONFIG_HID_MAYFLASH is not set
-# CONFIG_HID_MCP2200 is not set
-# CONFIG_HID_MCP2221 is not set
-# CONFIG_HID_MEGAWORLD_FF is not set
-# CONFIG_HID_MICROSOFT is not set
-# CONFIG_HID_MONTEREY is not set
-# CONFIG_HID_MULTITOUCH is not set
-# CONFIG_HID_NINTENDO is not set
-# CONFIG_HID_NTI is not set
-# CONFIG_HID_NTRIG is not set
-# CONFIG_HID_NVIDIA_SHIELD is not set
-# CONFIG_HID_ORTEK is not set
-# CONFIG_HID_PANTHERLORD is not set
-# CONFIG_HID_PENMOUNT is not set
-# CONFIG_HID_PETALYNX is not set
-# CONFIG_HID_PICOLCD is not set
-# CONFIG_HID_PID is not set
-# CONFIG_HID_PLANTRONICS is not set
-# CONFIG_HID_PLAYSTATION is not set
-# CONFIG_HID_PRIMAX is not set
-# CONFIG_HID_PRODIKEYS is not set
-# CONFIG_HID_PXRC is not set
-# CONFIG_HID_RAZER is not set
-# CONFIG_HID_REDRAGON is not set
-# CONFIG_HID_RETRODE is not set
-# CONFIG_HID_RMI is not set
-# CONFIG_HID_ROCCAT is not set
-# CONFIG_HID_SAITEK is not set
-# CONFIG_HID_SAMSUNG is not set
-# CONFIG_HID_SEMITEK is not set
-# CONFIG_HID_SENSOR_HUB is not set
-# CONFIG_HID_SIGMAMICRO is not set
-# CONFIG_HID_SMARTJOYPLUS is not set
-# CONFIG_HID_SONY is not set
-# CONFIG_HID_SPEEDLINK is not set
-# CONFIG_HID_STEAM is not set
-# CONFIG_HID_STEELSERIES is not set
-# CONFIG_HID_SUNPLUS is not set
-# CONFIG_HID_SUPPORT is not set
-# CONFIG_HID_THINGM is not set
-# CONFIG_HID_THRUSTMASTER is not set
-# CONFIG_HID_TIVO is not set
-# CONFIG_HID_TOPRE is not set
-# CONFIG_HID_TOPSEED is not set
-# CONFIG_HID_TWINHAN is not set
-# CONFIG_HID_U2FZERO is not set
-# CONFIG_HID_UCLOGIC is not set
-# CONFIG_HID_UDRAW_PS3 is not set
-# CONFIG_HID_VIEWSONIC is not set
-# CONFIG_HID_VIVALDI is not set
-# CONFIG_HID_VRC2 is not set
-# CONFIG_HID_WACOM is not set
-# CONFIG_HID_WALTOP is not set
-# CONFIG_HID_WIIMOTE is not set
-# CONFIG_HID_XIAOMI is not set
-# CONFIG_HID_XINMO is not set
-# CONFIG_HID_ZEROPLUS is not set
-# CONFIG_HID_ZYDACRON is not set
-# CONFIG_HIGHMEM is not set
-CONFIG_HIGH_RES_TIMERS=y
-# CONFIG_HINIC is not set
-# CONFIG_HIP04_ETH is not set
-# CONFIG_HIPPI is not set
-# CONFIG_HISILICON_ERRATUM_161010101 is not set
-# CONFIG_HISILICON_ERRATUM_161600802 is not set
-# CONFIG_HISI_DMA is not set
-# CONFIG_HISI_FEMAC is not set
-# CONFIG_HISI_HIKEY_USB is not set
-# CONFIG_HISI_PCIE_PMU is not set
-# CONFIG_HISI_PTT is not set
-# CONFIG_HIST_TRIGGERS_DEBUG is not set
-# CONFIG_HIX5HD2_GMAC is not set
-# CONFIG_HMC425 is not set
-# CONFIG_HMC6352 is not set
-# CONFIG_HNS is not set
-# CONFIG_HNS3 is not set
-# CONFIG_HNS3_PMU is not set
-# CONFIG_HNS_DSAF is not set
-# CONFIG_HNS_ENET is not set
-# CONFIG_HOSTAP is not set
-# CONFIG_HOSTAP_CS is not set
-# CONFIG_HOSTAP_PCI is not set
-# CONFIG_HOSTAP_PLX is not set
-# CONFIG_HOTPLUG_CPU is not set
-# CONFIG_HOTPLUG_PCI is not set
-# CONFIG_HP03 is not set
-# CONFIG_HP206C is not set
-CONFIG_HPET_MMAP_DEFAULT=y
-# CONFIG_HPFS_FS is not set
-# CONFIG_HP_ILO is not set
-# CONFIG_HP_WATCHDOG is not set
-# CONFIG_HSA_AMD is not set
-# CONFIG_HSI is not set
-# CONFIG_HSR is not set
-# CONFIG_HTC_EGPIO is not set
-# CONFIG_HTE is not set
-# CONFIG_HTS221 is not set
-# CONFIG_HTU21 is not set
-# CONFIG_HUGETLBFS is not set
-# CONFIG_HUGETLB_PAGE is not set
-# CONFIG_HUGETLB_PAGE_OPTIMIZE_VMEMMAP_DEFAULT_ON is not set
-# CONFIG_HVC_DCC is not set
-# CONFIG_HVC_UDBG is not set
-# CONFIG_HWLAT_TRACER is not set
-# CONFIG_HWMON is not set
-# CONFIG_HWMON_DEBUG_CHIP is not set
-# CONFIG_HWMON_VID is not set
-# CONFIG_HWSPINLOCK is not set
-# CONFIG_HWSPINLOCK_OMAP is not set
-CONFIG_HW_PERF_EVENTS=y
-# CONFIG_HW_RANDOM is not set
-# CONFIG_HW_RANDOM_AMD is not set
-# CONFIG_HW_RANDOM_ARM_SMCCC_TRNG is not set
-# CONFIG_HW_RANDOM_ATMEL is not set
-# CONFIG_HW_RANDOM_BA431 is not set
-# CONFIG_HW_RANDOM_BCM2835 is not set
-# CONFIG_HW_RANDOM_CAVIUM is not set
-# CONFIG_HW_RANDOM_CCTRNG is not set
-# CONFIG_HW_RANDOM_CN10K is not set
-# CONFIG_HW_RANDOM_EXYNOS is not set
-# CONFIG_HW_RANDOM_GEODE is not set
-# CONFIG_HW_RANDOM_INTEL is not set
-# CONFIG_HW_RANDOM_IPROC_RNG200 is not set
-# CONFIG_HW_RANDOM_MTK is not set
-# CONFIG_HW_RANDOM_OMAP is not set
-# CONFIG_HW_RANDOM_OMAP3_ROM is not set
-# CONFIG_HW_RANDOM_PPC4XX is not set
-# CONFIG_HW_RANDOM_TIMERIOMEM is not set
-CONFIG_HW_RANDOM_TPM=y
-# CONFIG_HW_RANDOM_VIA is not set
-# CONFIG_HW_RANDOM_VIRTIO is not set
-# CONFIG_HW_RANDOM_XIPHERA is not set
-# CONFIG_HX711 is not set
-# CONFIG_HYPERV is not set
-CONFIG_HZ=100
-CONFIG_HZ_100=y
-# CONFIG_HZ_1000 is not set
-# CONFIG_HZ_1024 is not set
-# CONFIG_HZ_128 is not set
-# CONFIG_HZ_200 is not set
-# CONFIG_HZ_24 is not set
-# CONFIG_HZ_250 is not set
-# CONFIG_HZ_256 is not set
-# CONFIG_HZ_300 is not set
-# CONFIG_HZ_48 is not set
-# CONFIG_HZ_500 is not set
-# CONFIG_HZ_PERIODIC is not set
-# CONFIG_I2C is not set
-# CONFIG_I2C_ALGOBIT is not set
-# CONFIG_I2C_ALGOPCA is not set
-# CONFIG_I2C_ALGOPCF is not set
-# CONFIG_I2C_ALI1535 is not set
-# CONFIG_I2C_ALI1563 is not set
-# CONFIG_I2C_ALI15X3 is not set
-# CONFIG_I2C_AMD756 is not set
-# CONFIG_I2C_AMD8111 is not set
-# CONFIG_I2C_ARB_GPIO_CHALLENGE is not set
-# CONFIG_I2C_AU1550 is not set
-# CONFIG_I2C_BCM2835 is not set
-# CONFIG_I2C_BCM_IPROC is not set
-# CONFIG_I2C_BRCMSTB is not set
-# CONFIG_I2C_CADENCE is not set
-# CONFIG_I2C_CBUS_GPIO is not set
-# CONFIG_I2C_CHARDEV is not set
-# CONFIG_I2C_COMPAT is not set
-# CONFIG_I2C_CP2615 is not set
-# CONFIG_I2C_DEBUG_ALGO is not set
-# CONFIG_I2C_DEBUG_BUS is not set
-# CONFIG_I2C_DEBUG_CORE is not set
-# CONFIG_I2C_DEMUX_PINCTRL is not set
-# CONFIG_I2C_DESIGNWARE_AMDPSP is not set
-# CONFIG_I2C_DESIGNWARE_BAYTRAIL is not set
-# CONFIG_I2C_DESIGNWARE_PCI is not set
-# CONFIG_I2C_DESIGNWARE_PLATFORM is not set
-# CONFIG_I2C_DESIGNWARE_SLAVE is not set
-# CONFIG_I2C_DIOLAN_U2C is not set
-# CONFIG_I2C_EG20T is not set
-# CONFIG_I2C_ELEKTOR is not set
-# CONFIG_I2C_EMEV2 is not set
-# CONFIG_I2C_GPIO is not set
-# CONFIG_I2C_GPIO_FAULT_INJECTOR is not set
-# CONFIG_I2C_HELPER_AUTO is not set
-# CONFIG_I2C_HID is not set
-# CONFIG_I2C_HID_OF is not set
-# CONFIG_I2C_HID_OF_ELAN is not set
-# CONFIG_I2C_HID_OF_GOODIX is not set
-# CONFIG_I2C_HISI is not set
-# CONFIG_I2C_I801 is not set
-# CONFIG_I2C_IBM_IIC is not set
-# CONFIG_I2C_IMG is not set
-# CONFIG_I2C_ISCH is not set
-# CONFIG_I2C_ISMT is not set
-# CONFIG_I2C_JZ4780 is not set
-# CONFIG_I2C_MLXCPLD is not set
-# CONFIG_I2C_MPC is not set
-# CONFIG_I2C_MT65XX is not set
-# CONFIG_I2C_MUX is not set
-# CONFIG_I2C_MUX_GPIO is not set
-# CONFIG_I2C_MUX_GPMUX is not set
-# CONFIG_I2C_MUX_LTC4306 is not set
-# CONFIG_I2C_MUX_MLXCPLD is not set
-# CONFIG_I2C_MUX_PCA9541 is not set
-# CONFIG_I2C_MUX_PCA954x is not set
-# CONFIG_I2C_MUX_PINCTRL is not set
-# CONFIG_I2C_MUX_REG is not set
-# CONFIG_I2C_MV64XXX is not set
-# CONFIG_I2C_NFORCE2 is not set
-# CONFIG_I2C_NOMADIK is not set
-# CONFIG_I2C_NVIDIA_GPU is not set
-# CONFIG_I2C_OCORES is not set
-# CONFIG_I2C_OCTEON is not set
-# CONFIG_I2C_PARPORT is not set
-# CONFIG_I2C_PCA_ISA is not set
-# CONFIG_I2C_PCA_PLATFORM is not set
-# CONFIG_I2C_PCI1XXXX is not set
-# CONFIG_I2C_PIIX4 is not set
-# CONFIG_I2C_PXA_PCI is not set
-# CONFIG_I2C_PXA_SLAVE is not set
-# CONFIG_I2C_RCAR is not set
-# CONFIG_I2C_RK3X is not set
-# CONFIG_I2C_ROBOTFUZZ_OSIF is not set
-# CONFIG_I2C_S3C2410 is not set
-# CONFIG_I2C_SCMI is not set
-# CONFIG_I2C_SH_MOBILE is not set
-# CONFIG_I2C_SIMTEC is not set
-# CONFIG_I2C_SIS5595 is not set
-# CONFIG_I2C_SIS630 is not set
-# CONFIG_I2C_SIS96X is not set
-# CONFIG_I2C_SLAVE is not set
-# CONFIG_I2C_SLAVE_EEPROM is not set
-# CONFIG_I2C_SMBUS is not set
-# CONFIG_I2C_STUB is not set
-# CONFIG_I2C_TAOS_EVM is not set
-# CONFIG_I2C_THUNDERX is not set
-# CONFIG_I2C_TINY_USB is not set
-# CONFIG_I2C_VERSATILE is not set
-# CONFIG_I2C_VIA is not set
-# CONFIG_I2C_VIAPRO is not set
-# CONFIG_I2C_VIRTIO is not set
-# CONFIG_I2C_XILINX is not set
-# CONFIG_I3C is not set
-# CONFIG_I40E is not set
-# CONFIG_I40EVF is not set
-# CONFIG_I6300ESB_WDT is not set
-# CONFIG_I82092 is not set
-# CONFIG_I82365 is not set
-# CONFIG_IAQCORE is not set
-# CONFIG_IBM_ASM is not set
-# CONFIG_IBM_EMAC_DEBUG is not set
-# CONFIG_IBM_EMAC_EMAC4 is not set
-# CONFIG_IBM_EMAC_MAL_CLR_ICINTSTAT is not set
-# CONFIG_IBM_EMAC_MAL_COMMON_ERR is not set
-# CONFIG_IBM_EMAC_NO_FLOW_CTRL is not set
-# CONFIG_IBM_EMAC_RGMII is not set
-# CONFIG_IBM_EMAC_TAH is not set
-# CONFIG_IBM_EMAC_ZMII is not set
-# CONFIG_ICE is not set
-# CONFIG_ICP10100 is not set
-# CONFIG_ICPLUS_PHY is not set
-# CONFIG_ICS932S401 is not set
-# CONFIG_IDEAPAD_LAPTOP is not set
-# CONFIG_IDLE_PAGE_TRACKING is not set
-# CONFIG_IEEE802154 is not set
-# CONFIG_IEEE802154_ADF7242 is not set
-# CONFIG_IEEE802154_ATUSB is not set
-# CONFIG_IEEE802154_CA8210 is not set
-# CONFIG_IEEE802154_HWSIM is not set
-# CONFIG_IEEE802154_MCR20A is not set
-# CONFIG_IFB is not set
-# CONFIG_IGB is not set
-# CONFIG_IGBVF is not set
-# CONFIG_IGC is not set
-# CONFIG_IIO is not set
-# CONFIG_IIO_BUFFER is not set
-# CONFIG_IIO_BUFFER_CB is not set
-# CONFIG_IIO_BUFFER_DMA is not set
-# CONFIG_IIO_BUFFER_DMAENGINE is not set
-# CONFIG_IIO_BUFFER_HW_CONSUMER is not set
-# CONFIG_IIO_CONFIGFS is not set
-CONFIG_IIO_CONSUMERS_PER_TRIGGER=2
-# CONFIG_IIO_CROS_EC_ACCEL_LEGACY is not set
-# CONFIG_IIO_INTERRUPT_TRIGGER is not set
-# CONFIG_IIO_KX022A_I2C is not set
-# CONFIG_IIO_KX022A_SPI is not set
-# CONFIG_IIO_MUX is not set
-# CONFIG_IIO_RESCALE is not set
-# CONFIG_IIO_SIMPLE_DUMMY is not set
-# CONFIG_IIO_SSP_SENSORHUB is not set
-# CONFIG_IIO_ST_ACCEL_3AXIS is not set
-# CONFIG_IIO_ST_GYRO_3AXIS is not set
-# CONFIG_IIO_ST_LSM6DSX is not set
-# CONFIG_IIO_ST_LSM9DS0 is not set
-# CONFIG_IIO_ST_MAGN_3AXIS is not set
-# CONFIG_IIO_ST_PRESS is not set
-# CONFIG_IIO_SW_DEVICE is not set
-# CONFIG_IIO_SW_TRIGGER is not set
-# CONFIG_IIO_SYSFS_TRIGGER is not set
-# CONFIG_IIO_TRIGGER is not set
-# CONFIG_IIO_TRIGGERED_EVENT is not set
-# CONFIG_IKCONFIG is not set
-# CONFIG_IKCONFIG_PROC is not set
-# CONFIG_IKHEADERS is not set
-# CONFIG_IMA is not set
-# CONFIG_IMGPDC_WDT is not set
-# CONFIG_IMG_MDC_DMA is not set
-# CONFIG_IMX7D_ADC is not set
-# CONFIG_IMX8QXP_ADC is not set
-# CONFIG_IMX93_ADC is not set
-# CONFIG_IMX_IPUV3_CORE is not set
-# CONFIG_IMX_THERMAL is not set
-# CONFIG_INA2XX_ADC is not set
-# CONFIG_INDIRECT_PIO is not set
-CONFIG_INET=y
-# CONFIG_INET6_AH is not set
-# CONFIG_INET6_ESP is not set
-# CONFIG_INET6_ESPINTCP is not set
-# CONFIG_INET6_IPCOMP is not set
-# CONFIG_INET6_TUNNEL is not set
-# CONFIG_INET6_XFRM_TUNNEL is not set
-# CONFIG_INET_AH is not set
-# CONFIG_INET_DIAG is not set
-# CONFIG_INET_ESP is not set
-# CONFIG_INET_ESPINTCP is not set
-# CONFIG_INET_IPCOMP is not set
-CONFIG_INET_TABLE_PERTURB_ORDER=16
-# CONFIG_INET_TCP_DIAG is not set
-# CONFIG_INET_TUNNEL is not set
-# CONFIG_INET_UDP_DIAG is not set
-# CONFIG_INET_XFRM_TUNNEL is not set
-# CONFIG_INFINIBAND is not set
-# CONFIG_INFTL is not set
-# CONFIG_INGENIC_ADC is not set
-# CONFIG_INGENIC_CGU_JZ4725B is not set
-# CONFIG_INGENIC_CGU_JZ4740 is not set
-# CONFIG_INGENIC_CGU_JZ4755 is not set
-# CONFIG_INGENIC_CGU_JZ4760 is not set
-# CONFIG_INGENIC_CGU_JZ4770 is not set
-# CONFIG_INGENIC_CGU_JZ4780 is not set
-# CONFIG_INGENIC_CGU_X1000 is not set
-# CONFIG_INGENIC_CGU_X1830 is not set
-# CONFIG_INGENIC_OST is not set
-# CONFIG_INGENIC_SYSOST is not set
-# CONFIG_INGENIC_TCU_CLK is not set
-# CONFIG_INGENIC_TCU_IRQ is not set
-# CONFIG_INGENIC_TIMER is not set
-# CONFIG_INITRAMFS_PRESERVE_MTIME is not set
-CONFIG_INIT_ENV_ARG_LIMIT=32
-# CONFIG_INIT_ON_ALLOC_DEFAULT_ON is not set
-# CONFIG_INIT_ON_FREE_DEFAULT_ON is not set
-# CONFIG_INIT_STACK_ALL_PATTERN is not set
-# CONFIG_INIT_STACK_ALL_ZERO is not set
-CONFIG_INIT_STACK_NONE=y
-CONFIG_INOTIFY_USER=y
-# CONFIG_INPUT is not set
-# CONFIG_INPUT_AD714X is not set
-# CONFIG_INPUT_ADXL34X is not set
-# CONFIG_INPUT_APANEL is not set
-# CONFIG_INPUT_ATI_REMOTE2 is not set
-# CONFIG_INPUT_ATLAS_BTNS is not set
-# CONFIG_INPUT_ATMEL_CAPTOUCH is not set
-# CONFIG_INPUT_AXP20X_PEK is not set
-# CONFIG_INPUT_BMA150 is not set
-# CONFIG_INPUT_CM109 is not set
-# CONFIG_INPUT_CMA3000 is not set
-# CONFIG_INPUT_DA7280_HAPTICS is not set
-# CONFIG_INPUT_DRV260X_HAPTICS is not set
-# CONFIG_INPUT_DRV2665_HAPTICS is not set
-# CONFIG_INPUT_DRV2667_HAPTICS is not set
-# CONFIG_INPUT_E3X0_BUTTON is not set
-# CONFIG_INPUT_EVBUG is not set
-# CONFIG_INPUT_EVDEV is not set
-# CONFIG_INPUT_FF_MEMLESS is not set
-# CONFIG_INPUT_GPIO_BEEPER is not set
-# CONFIG_INPUT_GPIO_DECODER is not set
-# CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set
-# CONFIG_INPUT_GPIO_VIBRA is not set
-# CONFIG_INPUT_IBM_PANEL is not set
-# CONFIG_INPUT_IDEAPAD_SLIDEBAR is not set
-# CONFIG_INPUT_IMS_PCU is not set
-# CONFIG_INPUT_IQS269A is not set
-# CONFIG_INPUT_IQS626A is not set
-# CONFIG_INPUT_IQS7222 is not set
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_JOYSTICK is not set
-# CONFIG_INPUT_KEYBOARD is not set
-# CONFIG_INPUT_KEYSPAN_REMOTE is not set
-# CONFIG_INPUT_KXTJ9 is not set
-# CONFIG_INPUT_LEDS is not set
-# CONFIG_INPUT_MATRIXKMAP is not set
-# CONFIG_INPUT_MAX8997_HAPTIC is not set
-CONFIG_INPUT_MISC=y
-# CONFIG_INPUT_MMA8450 is not set
-# CONFIG_INPUT_MOUSE is not set
-# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_PALMAS_PWRBUTTON is not set
-# CONFIG_INPUT_PCF8574 is not set
-# CONFIG_INPUT_PCSPKR is not set
-# CONFIG_INPUT_PM8941_PWRKEY is not set
-# CONFIG_INPUT_PM8XXX_VIBRATOR is not set
-# CONFIG_INPUT_POWERMATE is not set
-# CONFIG_INPUT_PWM_BEEPER is not set
-# CONFIG_INPUT_PWM_VIBRA is not set
-# CONFIG_INPUT_REGULATOR_HAPTIC is not set
-# CONFIG_INPUT_SOC_BUTTON_ARRAY is not set
-# CONFIG_INPUT_SPARSEKMAP is not set
-# CONFIG_INPUT_TABLET is not set
-# CONFIG_INPUT_TOUCHSCREEN is not set
-# CONFIG_INPUT_TPS65218_PWRBUTTON is not set
-# CONFIG_INPUT_TWL4030_PWRBUTTON is not set
-# CONFIG_INPUT_TWL4030_VIBRA is not set
-# CONFIG_INPUT_TWL6040_VIBRA is not set
-# CONFIG_INPUT_UINPUT is not set
-# CONFIG_INPUT_WISTRON_BTNS is not set
-# CONFIG_INPUT_YEALINK is not set
-# CONFIG_INT340X_THERMAL is not set
-# CONFIG_INTEGRITY is not set
-# CONFIG_INTEGRITY_AUDIT is not set
-# CONFIG_INTEGRITY_SIGNATURE is not set
-# CONFIG_INTEL_ATOMISP2_LED is not set
-# CONFIG_INTEL_ATOMISP2_PM is not set
-# CONFIG_INTEL_HID_EVENT is not set
-# CONFIG_INTEL_IDLE is not set
-# CONFIG_INTEL_IDMA64 is not set
-# CONFIG_INTEL_INT0002_VGPIO is not set
-# CONFIG_INTEL_IOATDMA is not set
-# CONFIG_INTEL_ISH_HID is not set
-# CONFIG_INTEL_MEI is not set
-# CONFIG_INTEL_MEI_GSC_PROXY is not set
-# CONFIG_INTEL_MEI_HDCP is not set
-# CONFIG_INTEL_MEI_ME is not set
-# CONFIG_INTEL_MEI_PXP is not set
-# CONFIG_INTEL_MEI_TXE is not set
-# CONFIG_INTEL_OAKTRAIL is not set
-# CONFIG_INTEL_PMC_CORE is not set
-# CONFIG_INTEL_PUNIT_IPC is not set
-# CONFIG_INTEL_RST is not set
-# CONFIG_INTEL_SMARTCONNECT is not set
-# CONFIG_INTEL_SOC_PMIC is not set
-# CONFIG_INTEL_SOC_PMIC_CHTDC_TI is not set
-# CONFIG_INTEL_SOC_PMIC_CHTWC is not set
-# CONFIG_INTEL_TH is not set
-# CONFIG_INTEL_VBTN is not set
-# CONFIG_INTEL_XWAY_PHY is not set
-# CONFIG_INTERCONNECT is not set
-# CONFIG_INTERVAL_TREE_TEST is not set
-# CONFIG_INV_ICM42600_I2C is not set
-# CONFIG_INV_ICM42600_SPI is not set
-# CONFIG_INV_MPU6050_I2C is not set
-# CONFIG_INV_MPU6050_IIO is not set
-# CONFIG_INV_MPU6050_SPI is not set
-# CONFIG_IOMMU_SUPPORT is not set
-# CONFIG_IONIC is not set
-# CONFIG_IOSCHED_BFQ is not set
-# CONFIG_IOSM is not set
-CONFIG_IO_STRICT_DEVMEM=y
-# CONFIG_IO_URING is not set
-CONFIG_IO_WQ=y
-# CONFIG_IP17XX_PHY is not set
-# CONFIG_IP5XXX_POWER is not set
-# CONFIG_IP6_NF_FILTER is not set
-# CONFIG_IP6_NF_IPTABLES is not set
-# CONFIG_IP6_NF_MANGLE is not set
-# CONFIG_IP6_NF_MATCH_AH is not set
-# CONFIG_IP6_NF_MATCH_EUI64 is not set
-# CONFIG_IP6_NF_MATCH_FRAG is not set
-# CONFIG_IP6_NF_MATCH_HL is not set
-# CONFIG_IP6_NF_MATCH_IPV6HEADER is not set
-# CONFIG_IP6_NF_MATCH_MH is not set
-# CONFIG_IP6_NF_MATCH_OPTS is not set
-# CONFIG_IP6_NF_MATCH_RPFILTER is not set
-# CONFIG_IP6_NF_MATCH_RT is not set
-# CONFIG_IP6_NF_MATCH_SRH is not set
-# CONFIG_IP6_NF_NAT is not set
-# CONFIG_IP6_NF_RAW is not set
-# CONFIG_IP6_NF_SECURITY is not set
-# CONFIG_IP6_NF_TARGET_HL is not set
-# CONFIG_IP6_NF_TARGET_MASQUERADE is not set
-# CONFIG_IP6_NF_TARGET_REJECT is not set
-# CONFIG_IP6_NF_TARGET_SYNPROXY is not set
-# CONFIG_IPACK_BUS is not set
-# CONFIG_IPC_NS is not set
-# CONFIG_IPMB_DEVICE_INTERFACE is not set
-# CONFIG_IPMI_HANDLER is not set
-# CONFIG_IPU_BRIDGE is not set
-# CONFIG_IPV6 is not set
-# CONFIG_IPV6_FOU is not set
-# CONFIG_IPV6_FOU_TUNNEL is not set
-# CONFIG_IPV6_ILA is not set
-# CONFIG_IPV6_IOAM6_LWTUNNEL is not set
-# CONFIG_IPV6_MIP6 is not set
-# CONFIG_IPV6_MROUTE is not set
-# CONFIG_IPV6_MROUTE_MULTIPLE_TABLES is not set
-# CONFIG_IPV6_MULTIPLE_TABLES is not set
-CONFIG_IPV6_NDISC_NODETYPE=y
-# CONFIG_IPV6_OPTIMISTIC_DAD is not set
-# CONFIG_IPV6_ROUTER_PREF is not set
-# CONFIG_IPV6_ROUTE_INFO is not set
-# CONFIG_IPV6_RPL_LWTUNNEL is not set
-# CONFIG_IPV6_SEG6_HMAC is not set
-# CONFIG_IPV6_SEG6_LWTUNNEL is not set
-# CONFIG_IPV6_SIT is not set
-# CONFIG_IPV6_SIT_6RD is not set
-# CONFIG_IPV6_TUNNEL is not set
-# CONFIG_IPV6_VTI is not set
-# CONFIG_IPVLAN is not set
-# CONFIG_IPVTAP is not set
-# CONFIG_IPW2100 is not set
-# CONFIG_IPW2100_DEBUG is not set
-CONFIG_IPW2100_MONITOR=y
-# CONFIG_IPW2200 is not set
-# CONFIG_IPW2200_DEBUG is not set
-CONFIG_IPW2200_MONITOR=y
-# CONFIG_IPW2200_PROMISCUOUS is not set
-# CONFIG_IPW2200_QOS is not set
-# CONFIG_IPW2200_RADIOTAP is not set
-# CONFIG_IPWIRELESS is not set
-CONFIG_IP_ADVANCED_ROUTER=y
-# CONFIG_IP_DCCP is not set
-# CONFIG_IP_FIB_TRIE_STATS is not set
-# CONFIG_IP_MROUTE is not set
-CONFIG_IP_MROUTE_MULTIPLE_TABLES=y
-CONFIG_IP_MULTICAST=y
-CONFIG_IP_MULTIPLE_TABLES=y
-# CONFIG_IP_NF_ARPFILTER is not set
-# CONFIG_IP_NF_ARPTABLES is not set
-# CONFIG_IP_NF_ARP_MANGLE is not set
-# CONFIG_IP_NF_FILTER is not set
-# CONFIG_IP_NF_IPTABLES is not set
-# CONFIG_IP_NF_MANGLE is not set
-# CONFIG_IP_NF_MATCH_AH is not set
-# CONFIG_IP_NF_MATCH_ECN is not set
-# CONFIG_IP_NF_MATCH_RPFILTER is not set
-# CONFIG_IP_NF_MATCH_TTL is not set
-# CONFIG_IP_NF_RAW is not set
-# CONFIG_IP_NF_SECURITY is not set
-# CONFIG_IP_NF_TARGET_ECN is not set
-# CONFIG_IP_NF_TARGET_MASQUERADE is not set
-# CONFIG_IP_NF_TARGET_NETMAP is not set
-# CONFIG_IP_NF_TARGET_REDIRECT is not set
-# CONFIG_IP_NF_TARGET_REJECT is not set
-# CONFIG_IP_NF_TARGET_SYNPROXY is not set
-# CONFIG_IP_NF_TARGET_TTL is not set
-# CONFIG_IP_PIMSM_V1 is not set
-# CONFIG_IP_PIMSM_V2 is not set
-# CONFIG_IP_PNP is not set
-CONFIG_IP_ROUTE_MULTIPATH=y
-CONFIG_IP_ROUTE_VERBOSE=y
-# CONFIG_IP_SCTP is not set
-# CONFIG_IP_SET is not set
-# CONFIG_IP_SET_HASH_IPMAC is not set
-# CONFIG_IP_VS is not set
-# CONFIG_IP_VS_MH is not set
-CONFIG_IP_VS_MH_TAB_INDEX=10
-# CONFIG_IP_VS_TWOS is not set
-# CONFIG_IRQSOFF_TRACER is not set
-# CONFIG_IRQ_ALL_CPUS is not set
-# CONFIG_IRQ_POLL is not set
-# CONFIG_IRQ_TIME_ACCOUNTING is not set
-# CONFIG_IRSD200 is not set
-# CONFIG_IR_GPIO_CIR is not set
-# CONFIG_IR_HIX5HD2 is not set
-# CONFIG_IR_IGORPLUGUSB is not set
-# CONFIG_IR_IGUANA is not set
-# CONFIG_IR_IMG is not set
-# CONFIG_IR_IMON is not set
-# CONFIG_IR_IMON_RAW is not set
-# CONFIG_IR_JVC_DECODER is not set
-# CONFIG_IR_MCEUSB is not set
-# CONFIG_IR_NEC_DECODER is not set
-# CONFIG_IR_RC5_DECODER is not set
-# CONFIG_IR_RC6_DECODER is not set
-# CONFIG_IR_REDRAT3 is not set
-# CONFIG_IR_SERIAL is not set
-# CONFIG_IR_SONY_DECODER is not set
-# CONFIG_IR_STREAMZAP is not set
-# CONFIG_IR_TOY is not set
-# CONFIG_IR_TTUSBIR is not set
-# CONFIG_ISA_BUS is not set
-# CONFIG_ISA_BUS_API is not set
-# CONFIG_ISCSI_BOOT_SYSFS is not set
-# CONFIG_ISCSI_TCP is not set
-CONFIG_ISDN=y
-# CONFIG_ISDN_CAPI is not set
-# CONFIG_ISL29003 is not set
-# CONFIG_ISL29020 is not set
-# CONFIG_ISL29125 is not set
-# CONFIG_ISL29501 is not set
-# CONFIG_ISO9660_FS is not set
-# CONFIG_ISS4xx is not set
-# CONFIG_ITG3200 is not set
-# CONFIG_IWL3945 is not set
-# CONFIG_IWLWIFI is not set
-# CONFIG_IXGBE is not set
-# CONFIG_IXGBEVF is not set
-# CONFIG_JAILHOUSE_GUEST is not set
-# CONFIG_JBD2_DEBUG is not set
-# CONFIG_JFFS2_CMODE_FAVOURLZO is not set
-# CONFIG_JFFS2_CMODE_NONE is not set
-CONFIG_JFFS2_CMODE_PRIORITY=y
-# CONFIG_JFFS2_CMODE_SIZE is not set
-CONFIG_JFFS2_COMPRESSION_OPTIONS=y
-CONFIG_JFFS2_FS=y
-CONFIG_JFFS2_FS_DEBUG=0
-# CONFIG_JFFS2_FS_POSIX_ACL is not set
-# CONFIG_JFFS2_FS_SECURITY is not set
-# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
-CONFIG_JFFS2_FS_WRITEBUFFER=y
-CONFIG_JFFS2_FS_XATTR=y
-CONFIG_JFFS2_LZMA=y
-# CONFIG_JFFS2_LZO is not set
-CONFIG_JFFS2_RTIME=y
-# CONFIG_JFFS2_RUBIN is not set
-CONFIG_JFFS2_SUMMARY=y
-# CONFIG_JFFS2_ZLIB is not set
-# CONFIG_JFS_DEBUG is not set
-# CONFIG_JFS_FS is not set
-# CONFIG_JFS_POSIX_ACL is not set
-# CONFIG_JFS_SECURITY is not set
-# CONFIG_JFS_STATISTICS is not set
-# CONFIG_JME is not set
-CONFIG_JOLIET=y
-# CONFIG_JSA1212 is not set
-# CONFIG_JUMP_LABEL is not set
-# CONFIG_JZ4740_WDT is not set
-# CONFIG_KALLSYMS is not set
-# CONFIG_KALLSYMS_ABSOLUTE_PERCPU is not set
-# CONFIG_KALLSYMS_ALL is not set
-CONFIG_KALLSYMS_BASE_RELATIVE=y
-# CONFIG_KALLSYMS_SELFTEST is not set
-# CONFIG_KALLSYMS_UNCOMPRESSED is not set
-# CONFIG_KARMA_PARTITION is not set
-# CONFIG_KASAN is not set
-# CONFIG_KASAN_MODULE_TEST is not set
-CONFIG_KASAN_STACK=y
-# CONFIG_KCMP is not set
-# CONFIG_KCOV is not set
-CONFIG_KCOV_IRQ_AREA_SIZE=0x40000
-# CONFIG_KCSAN is not set
-# CONFIG_KERNEL_BZIP2 is not set
-# CONFIG_KERNEL_GZIP is not set
-# CONFIG_KERNEL_LZ4 is not set
-# CONFIG_KERNEL_LZMA is not set
-# CONFIG_KERNEL_LZO is not set
-CONFIG_KERNEL_MODE_NEON=y
-CONFIG_KERNEL_XZ=y
-# CONFIG_KERNEL_ZSTD is not set
-CONFIG_KERNFS=y
-# CONFIG_KEXEC is not set
-# CONFIG_KEXEC_FILE is not set
-# CONFIG_KEXEC_SIG is not set
-# CONFIG_KEYBOARD_ADC is not set
-# CONFIG_KEYBOARD_ADP5588 is not set
-# CONFIG_KEYBOARD_ADP5589 is not set
-# CONFIG_KEYBOARD_APPLESPI is not set
-# CONFIG_KEYBOARD_ATKBD is not set
-# CONFIG_KEYBOARD_BCM is not set
-# CONFIG_KEYBOARD_CAP11XX is not set
-# CONFIG_KEYBOARD_CYPRESS_SF is not set
-# CONFIG_KEYBOARD_DLINK_DIR685 is not set
-# CONFIG_KEYBOARD_GPIO is not set
-# CONFIG_KEYBOARD_GPIO_POLLED is not set
-# CONFIG_KEYBOARD_LKKBD is not set
-# CONFIG_KEYBOARD_LM8323 is not set
-# CONFIG_KEYBOARD_LM8333 is not set
-# CONFIG_KEYBOARD_MATRIX is not set
-# CONFIG_KEYBOARD_MAX7359 is not set
-# CONFIG_KEYBOARD_MCS is not set
-# CONFIG_KEYBOARD_MPR121 is not set
-# CONFIG_KEYBOARD_MT6779 is not set
-# CONFIG_KEYBOARD_NEWTON is not set
-# CONFIG_KEYBOARD_OMAP4 is not set
-# CONFIG_KEYBOARD_OPENCORES is not set
-# CONFIG_KEYBOARD_PINEPHONE is not set
-# CONFIG_KEYBOARD_PXA27x is not set
-# CONFIG_KEYBOARD_QT1050 is not set
-# CONFIG_KEYBOARD_QT1070 is not set
-# CONFIG_KEYBOARD_QT2160 is not set
-# CONFIG_KEYBOARD_SAMSUNG is not set
-# CONFIG_KEYBOARD_SH_KEYSC is not set
-# CONFIG_KEYBOARD_SNVS_PWRKEY is not set
-# CONFIG_KEYBOARD_STMPE is not set
-# CONFIG_KEYBOARD_STOWAWAY is not set
-# CONFIG_KEYBOARD_SUNKBD is not set
-# CONFIG_KEYBOARD_TCA6416 is not set
-# CONFIG_KEYBOARD_TCA8418 is not set
-# CONFIG_KEYBOARD_TEGRA is not set
-# CONFIG_KEYBOARD_TM2_TOUCHKEY is not set
-# CONFIG_KEYBOARD_TWL4030 is not set
-# CONFIG_KEYBOARD_XTKBD is not set
-# CONFIG_KEYS is not set
-# CONFIG_KEYS_REQUEST_CACHE is not set
-# CONFIG_KEY_DH_OPERATIONS is not set
-# CONFIG_KFENCE is not set
-# CONFIG_KGDB is not set
-# CONFIG_KMX61 is not set
-# CONFIG_KPROBES is not set
-# CONFIG_KPROBES_SANITY_TEST is not set
-# CONFIG_KPROBE_EVENTS_ON_NOTRACE is not set
-# CONFIG_KPROBE_EVENT_GEN_TEST is not set
-# CONFIG_KS7010 is not set
-# CONFIG_KS8842 is not set
-# CONFIG_KS8851 is not set
-# CONFIG_KS8851_MLL is not set
-# CONFIG_KSM is not set
-# CONFIG_KSZ884X_PCI is not set
-# CONFIG_KUNIT is not set
-CONFIG_KUSER_HELPERS=y
-# CONFIG_KVM_AMD is not set
-# CONFIG_KVM_AMD_SEV is not set
-# CONFIG_KVM_GUEST is not set
-# CONFIG_KVM_INTEL is not set
-# CONFIG_KVM_WERROR is not set
-# CONFIG_KVM_XEN is not set
-# CONFIG_KXCJK1013 is not set
-# CONFIG_KXSD9 is not set
-# CONFIG_L2TP is not set
-# CONFIG_L2TP_ETH is not set
-# CONFIG_L2TP_IP is not set
-# CONFIG_L2TP_V3 is not set
-# CONFIG_LAN743X is not set
-# CONFIG_LAN966X_SWITCH is not set
-# CONFIG_LANTIQ is not set
-# CONFIG_LAPB is not set
-# CONFIG_LATENCYTOP is not set
-# CONFIG_LATTICE_ECP3_CONFIG is not set
-# CONFIG_LCD_AMS369FG06 is not set
-# CONFIG_LCD_CLASS_DEVICE is not set
-# CONFIG_LCD_HX8357 is not set
-# CONFIG_LCD_ILI922X is not set
-# CONFIG_LCD_ILI9320 is not set
-# CONFIG_LCD_L4F00242T03 is not set
-# CONFIG_LCD_LMS283GF05 is not set
-# CONFIG_LCD_LMS501KF03 is not set
-# CONFIG_LCD_LTV350QV is not set
-# CONFIG_LCD_OTM3225A is not set
-# CONFIG_LCD_TDO24M is not set
-# CONFIG_LCD_VGG2432A4 is not set
-CONFIG_LDISC_AUTOLOAD=y
-# CONFIG_LDM_PARTITION is not set
-CONFIG_LD_DEAD_CODE_DATA_ELIMINATION=y
-# CONFIG_LD_HEAD_STUB_CATCH is not set
-# CONFIG_LEDS_AN30259A is not set
-# CONFIG_LEDS_APU is not set
-# CONFIG_LEDS_AW200XX is not set
-# CONFIG_LEDS_AW2013 is not set
-# CONFIG_LEDS_BCM6328 is not set
-# CONFIG_LEDS_BCM6358 is not set
-# CONFIG_LEDS_BD2606MVV is not set
-# CONFIG_LEDS_BD2802 is not set
-# CONFIG_LEDS_BLINKM is not set
-CONFIG_LEDS_BRIGHTNESS_HW_CHANGED=y
-CONFIG_LEDS_CLASS=y
-# CONFIG_LEDS_CLASS_FLASH is not set
-CONFIG_LEDS_CLASS_MULTICOLOR=y
-# CONFIG_LEDS_CR0014114 is not set
-# CONFIG_LEDS_DAC124S085 is not set
-# CONFIG_LEDS_EL15203000 is not set
-# CONFIG_LEDS_GPIO is not set
-# CONFIG_LEDS_GROUP_MULTICOLOR is not set
-# CONFIG_LEDS_INTEL_SS4200 is not set
-# CONFIG_LEDS_IS31FL319X is not set
-# CONFIG_LEDS_IS31FL32XX is not set
-# CONFIG_LEDS_KTD202X is not set
-# CONFIG_LEDS_LM3530 is not set
-# CONFIG_LEDS_LM3532 is not set
-# CONFIG_LEDS_LM355x is not set
-# CONFIG_LEDS_LM3642 is not set
-# CONFIG_LEDS_LM3692X is not set
-# CONFIG_LEDS_LM3697 is not set
-# CONFIG_LEDS_LP3944 is not set
-# CONFIG_LEDS_LP3952 is not set
-# CONFIG_LEDS_LP50XX is not set
-# CONFIG_LEDS_LP5521 is not set
-# CONFIG_LEDS_LP5523 is not set
-# CONFIG_LEDS_LP5562 is not set
-# CONFIG_LEDS_LP55XX_COMMON is not set
-# CONFIG_LEDS_LP8501 is not set
-# CONFIG_LEDS_LP8860 is not set
-# CONFIG_LEDS_LT3593 is not set
-# CONFIG_LEDS_MLXCPLD is not set
-# CONFIG_LEDS_MLXREG is not set
-# CONFIG_LEDS_NIC78BX is not set
-# CONFIG_LEDS_NS2 is not set
-# CONFIG_LEDS_OT200 is not set
-# CONFIG_LEDS_PCA9532 is not set
-# CONFIG_LEDS_PCA955X is not set
-# CONFIG_LEDS_PCA963X is not set
-# CONFIG_LEDS_PCA995X is not set
-# CONFIG_LEDS_PWM is not set
-# CONFIG_LEDS_PWM_MULTICOLOR is not set
-# CONFIG_LEDS_REGULATOR is not set
-# CONFIG_LEDS_SPI_BYTE is not set
-# CONFIG_LEDS_ST1202 is not set
-# CONFIG_LEDS_SYSCON is not set
-# CONFIG_LEDS_TCA6507 is not set
-# CONFIG_LEDS_TI_LMU_COMMON is not set
-# CONFIG_LEDS_TLC591XX is not set
-CONFIG_LEDS_TRIGGERS=y
-# CONFIG_LEDS_TRIGGER_ACTIVITY is not set
-# CONFIG_LEDS_TRIGGER_AUDIO is not set
-# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set
-# CONFIG_LEDS_TRIGGER_CAMERA is not set
-# CONFIG_LEDS_TRIGGER_CPU is not set
-CONFIG_LEDS_TRIGGER_DEFAULT_ON=y
-# CONFIG_LEDS_TRIGGER_DISK is not set
-# CONFIG_LEDS_TRIGGER_GPIO is not set
-CONFIG_LEDS_TRIGGER_HEARTBEAT=y
-# CONFIG_LEDS_TRIGGER_MTD is not set
-CONFIG_LEDS_TRIGGER_NETDEV=y
-# CONFIG_LEDS_TRIGGER_ONESHOT is not set
-# CONFIG_LEDS_TRIGGER_PANIC is not set
-# CONFIG_LEDS_TRIGGER_PATTERN is not set
-CONFIG_LEDS_TRIGGER_TIMER=y
-# CONFIG_LEDS_TRIGGER_TRANSIENT is not set
-# CONFIG_LEDS_TRIGGER_TTY is not set
-# CONFIG_LEDS_TURRIS_OMNIA is not set
-# CONFIG_LEDS_USER is not set
-# CONFIG_LED_TRIGGER_PHY is not set
-# CONFIG_LEGACY_PTYS is not set
-# CONFIG_LEGACY_TIOCSTI is not set
-# CONFIG_LIB80211 is not set
-# CONFIG_LIB80211_CRYPT_CCMP is not set
-# CONFIG_LIB80211_CRYPT_TKIP is not set
-# CONFIG_LIB80211_CRYPT_WEP is not set
-# CONFIG_LIB80211_DEBUG is not set
-# CONFIG_LIBCRC32C is not set
-# CONFIG_LIBERTAS is not set
-# CONFIG_LIBERTAS_THINFIRM is not set
-# CONFIG_LIBERTAS_USB is not set
-# CONFIG_LIBFC is not set
-# CONFIG_LIBFCOE is not set
-# CONFIG_LIBIPW_DEBUG is not set
-# CONFIG_LIBNVDIMM is not set
-# CONFIG_LIDAR_LITE_V2 is not set
-CONFIG_LINEAR_RANGES=y
-# CONFIG_LIQUIDIO is not set
-# CONFIG_LIQUIDIO_VF is not set
-# CONFIG_LIRC is not set
-CONFIG_LIST_HARDENED=y
-# CONFIG_LITEX_LITEETH is not set
-# CONFIG_LITEX_SOC_CONTROLLER is not set
-# CONFIG_LIVEPATCH is not set
-# CONFIG_LKDTM is not set
-CONFIG_LLC=y
-# CONFIG_LLC2 is not set
-# CONFIG_LMK04832 is not set
-# CONFIG_LMP91000 is not set
-CONFIG_LOCALVERSION=""
-# CONFIG_LOCALVERSION_AUTO is not set
-# CONFIG_LOCKD is not set
-CONFIG_LOCKDEP_BITS=15
-CONFIG_LOCKDEP_CHAINS_BITS=16
-CONFIG_LOCKDEP_CIRCULAR_QUEUE_BITS=12
-CONFIG_LOCKDEP_STACK_TRACE_BITS=19
-CONFIG_LOCKDEP_STACK_TRACE_HASH_BITS=14
-CONFIG_LOCKDEP_SUPPORT=y
-CONFIG_LOCKD_V4=y
-# CONFIG_LOCKUP_DETECTOR is not set
-# CONFIG_LOCK_EVENT_COUNTS is not set
-CONFIG_LOCK_MM_AND_FIND_VMA=y
-# CONFIG_LOCK_STAT is not set
-# CONFIG_LOCK_TORTURE_TEST is not set
-# CONFIG_LOGIG940_FF is not set
-# CONFIG_LOGIRUMBLEPAD2_FF is not set
-# CONFIG_LOGITECH_FF is not set
-# CONFIG_LOGIWHEELS_FF is not set
-# CONFIG_LOGO is not set
-CONFIG_LOG_BUF_SHIFT=17
-CONFIG_LOG_CPU_MAX_BUF_SHIFT=12
-# CONFIG_LOONGSON_MC146818 is not set
-# CONFIG_LPC_ICH is not set
-# CONFIG_LPC_SCH is not set
-# CONFIG_LP_CONSOLE is not set
-CONFIG_LRU_GEN=y
-CONFIG_LRU_GEN_ENABLED=y
-# CONFIG_LRU_GEN_STATS is not set
-# CONFIG_LSI_ET1011C_PHY is not set
-CONFIG_LSM="lockdown,yama,loadpin,safesetid,integrity"
-CONFIG_LSM_MMAP_MIN_ADDR=65536
-# CONFIG_LTC1660 is not set
-# CONFIG_LTC2471 is not set
-# CONFIG_LTC2485 is not set
-# CONFIG_LTC2496 is not set
-# CONFIG_LTC2497 is not set
-# CONFIG_LTC2632 is not set
-# CONFIG_LTC2688 is not set
-# CONFIG_LTC2983 is not set
-# CONFIG_LTE_GDM724X is not set
-CONFIG_LTO_NONE=y
-# CONFIG_LTR501 is not set
-# CONFIG_LTRF216A is not set
-# CONFIG_LV0104CS is not set
-# CONFIG_LWTUNNEL is not set
-# CONFIG_LXT_PHY is not set
-# CONFIG_LZ4HC_COMPRESS is not set
-# CONFIG_LZ4_COMPRESS is not set
-# CONFIG_LZ4_DECOMPRESS is not set
-CONFIG_LZMA_COMPRESS=y
-CONFIG_LZMA_DECOMPRESS=y
-# CONFIG_LZO_COMPRESS is not set
-# CONFIG_LZO_DECOMPRESS is not set
-# CONFIG_M62332 is not set
-# CONFIG_MAC80211 is not set
-# CONFIG_MAC80211_MESSAGE_TRACING is not set
-CONFIG_MAC80211_STA_HASH_MAX_SIZE=0
-# CONFIG_MACB is not set
-# CONFIG_MACH_ASM9260 is not set
-# CONFIG_MACH_DECSTATION is not set
-# CONFIG_MACH_INGENIC is not set
-# CONFIG_MACH_INGENIC_SOC is not set
-# CONFIG_MACH_JAZZ is not set
-# CONFIG_MACH_JZ4740 is not set
-# CONFIG_MACH_LOONGSON2EF is not set
-# CONFIG_MACH_LOONGSON32 is not set
-# CONFIG_MACH_LOONGSON64 is not set
-# CONFIG_MACH_NINTENDO64 is not set
-# CONFIG_MACH_PIC32 is not set
-# CONFIG_MACH_REALTEK_RTL is not set
-# CONFIG_MACH_TX49XX is not set
-# CONFIG_MACINTOSH_DRIVERS is not set
-# CONFIG_MACSEC is not set
-# CONFIG_MACVLAN is not set
-# CONFIG_MACVTAP is not set
-# CONFIG_MAC_EMUMOUSEBTN is not set
-# CONFIG_MAC_PARTITION is not set
-# CONFIG_MAG3110 is not set
-# CONFIG_MAGIC_SYSRQ is not set
-CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0x1
-# CONFIG_MAGIC_SYSRQ_SERIAL is not set
-CONFIG_MAGIC_SYSRQ_SERIAL_SEQUENCE=""
-# CONFIG_MAILBOX is not set
-# CONFIG_MANAGER_SBS is not set
-# CONFIG_MANGLE_BOOTARGS is not set
-# CONFIG_MARVELL_10G_PHY is not set
-# CONFIG_MARVELL_88Q2XXX_PHY is not set
-# CONFIG_MARVELL_88X2222_PHY is not set
-# CONFIG_MARVELL_PHY is not set
-# CONFIG_MAX1027 is not set
-# CONFIG_MAX11100 is not set
-# CONFIG_MAX1118 is not set
-# CONFIG_MAX11205 is not set
-# CONFIG_MAX11410 is not set
-# CONFIG_MAX1241 is not set
-# CONFIG_MAX1363 is not set
-# CONFIG_MAX30100 is not set
-# CONFIG_MAX30102 is not set
-# CONFIG_MAX30208 is not set
-# CONFIG_MAX31827 is not set
-# CONFIG_MAX31856 is not set
-# CONFIG_MAX31865 is not set
-# CONFIG_MAX44000 is not set
-# CONFIG_MAX44009 is not set
-# CONFIG_MAX517 is not set
-# CONFIG_MAX5432 is not set
-# CONFIG_MAX5481 is not set
-# CONFIG_MAX5487 is not set
-# CONFIG_MAX5522 is not set
-# CONFIG_MAX5821 is not set
-# CONFIG_MAX63XX_WATCHDOG is not set
-# CONFIG_MAX9611 is not set
-# CONFIG_MAXIM_THERMOCOUPLE is not set
-# CONFIG_MAXLINEAR_GPHY is not set
-CONFIG_MAX_SKB_FRAGS=17
-# CONFIG_MB1232 is not set
-# CONFIG_MC3230 is not set
-# CONFIG_MCB is not set
-# CONFIG_MCP320X is not set
-# CONFIG_MCP3422 is not set
-# CONFIG_MCP3911 is not set
-# CONFIG_MCP4018 is not set
-# CONFIG_MCP41010 is not set
-# CONFIG_MCP4131 is not set
-# CONFIG_MCP4531 is not set
-# CONFIG_MCP4725 is not set
-# CONFIG_MCP4728 is not set
-# CONFIG_MCP4922 is not set
-# CONFIG_MCPM is not set
-# CONFIG_MCTP is not set
-# CONFIG_MD is not set
-# CONFIG_MDIO_BCM_UNIMAC is not set
-# CONFIG_MDIO_BITBANG is not set
-# CONFIG_MDIO_BUS_MUX_GPIO is not set
-# CONFIG_MDIO_BUS_MUX_MMIOREG is not set
-# CONFIG_MDIO_BUS_MUX_MULTIPLEXER is not set
-# CONFIG_MDIO_DEVICE is not set
-# CONFIG_MDIO_DEVRES is not set
-# CONFIG_MDIO_HISI_FEMAC is not set
-# CONFIG_MDIO_IPQ4019 is not set
-# CONFIG_MDIO_IPQ8064 is not set
-# CONFIG_MDIO_MSCC_MIIM is not set
-# CONFIG_MDIO_MVUSB is not set
-# CONFIG_MDIO_OCTEON is not set
-# CONFIG_MDIO_THUNDER is not set
-# CONFIG_MDM_GCC_9607 is not set
-# CONFIG_MD_BITMAP_FILE is not set
-# CONFIG_MD_FAULTY is not set
-# CONFIG_MEDIATEK_GE_PHY is not set
-# CONFIG_MEDIATEK_MT6577_AUXADC is not set
-# CONFIG_MEDIA_ANALOG_TV_SUPPORT is not set
-# CONFIG_MEDIA_ATTACH is not set
-# CONFIG_MEDIA_CAMERA_SUPPORT is not set
-# CONFIG_MEDIA_CEC_SUPPORT is not set
-# CONFIG_MEDIA_CONTROLLER is not set
-# CONFIG_MEDIA_CONTROLLER_DVB is not set
-# CONFIG_MEDIA_DIGITAL_TV_SUPPORT is not set
-# CONFIG_MEDIA_PCI_SUPPORT is not set
-# CONFIG_MEDIA_PLATFORM_DRIVERS is not set
-# CONFIG_MEDIA_PLATFORM_SUPPORT is not set
-# CONFIG_MEDIA_RADIO_SUPPORT is not set
-# CONFIG_MEDIA_SDR_SUPPORT is not set
-# CONFIG_MEDIA_SUBDRV_AUTOSELECT is not set
-# CONFIG_MEDIA_SUPPORT is not set
-# CONFIG_MEDIA_SUPPORT_FILTER is not set
-# CONFIG_MEDIA_TEST_SUPPORT is not set
-# CONFIG_MEDIA_TUNER_E4000 is not set
-# CONFIG_MEDIA_TUNER_FC0011 is not set
-# CONFIG_MEDIA_TUNER_FC0012 is not set
-# CONFIG_MEDIA_TUNER_FC0013 is not set
-# CONFIG_MEDIA_TUNER_FC2580 is not set
-# CONFIG_MEDIA_TUNER_IT913X is not set
-# CONFIG_MEDIA_TUNER_M88RS6000T is not set
-# CONFIG_MEDIA_TUNER_MAX2165 is not set
-# CONFIG_MEDIA_TUNER_MC44S803 is not set
-# CONFIG_MEDIA_TUNER_MSI001 is not set
-# CONFIG_MEDIA_TUNER_MT2060 is not set
-# CONFIG_MEDIA_TUNER_MT2063 is not set
-# CONFIG_MEDIA_TUNER_MT20XX is not set
-# CONFIG_MEDIA_TUNER_MT2131 is not set
-# CONFIG_MEDIA_TUNER_MT2266 is not set
-# CONFIG_MEDIA_TUNER_MXL301RF is not set
-# CONFIG_MEDIA_TUNER_MXL5005S is not set
-# CONFIG_MEDIA_TUNER_MXL5007T is not set
-# CONFIG_MEDIA_TUNER_QM1D1B0004 is not set
-# CONFIG_MEDIA_TUNER_QM1D1C0042 is not set
-# CONFIG_MEDIA_TUNER_QT1010 is not set
-# CONFIG_MEDIA_TUNER_R820T is not set
-# CONFIG_MEDIA_TUNER_SI2157 is not set
-# CONFIG_MEDIA_TUNER_SIMPLE is not set
-# CONFIG_MEDIA_TUNER_TDA18212 is not set
-# CONFIG_MEDIA_TUNER_TDA18218 is not set
-# CONFIG_MEDIA_TUNER_TDA18250 is not set
-# CONFIG_MEDIA_TUNER_TDA18271 is not set
-# CONFIG_MEDIA_TUNER_TDA827X is not set
-# CONFIG_MEDIA_TUNER_TDA8290 is not set
-# CONFIG_MEDIA_TUNER_TDA9887 is not set
-# CONFIG_MEDIA_TUNER_TEA5761 is not set
-# CONFIG_MEDIA_TUNER_TEA5767 is not set
-# CONFIG_MEDIA_TUNER_TUA9001 is not set
-# CONFIG_MEDIA_TUNER_XC2028 is not set
-# CONFIG_MEDIA_TUNER_XC4000 is not set
-# CONFIG_MEDIA_TUNER_XC5000 is not set
-# CONFIG_MEDIA_USB_SUPPORT is not set
-# CONFIG_MEGARAID_LEGACY is not set
-# CONFIG_MEGARAID_NEWGEN is not set
-# CONFIG_MEGARAID_SAS is not set
-# CONFIG_MELLANOX_PLATFORM is not set
-CONFIG_MEMBARRIER=y
-CONFIG_MEMFD_CREATE=y
-# CONFIG_MEMORY is not set
-# CONFIG_MEMORY_FAILURE is not set
-# CONFIG_MEMORY_HOTPLUG is not set
-# CONFIG_MEMSTICK is not set
-# CONFIG_MEMTEST is not set
-# CONFIG_MEN_A21_WDT is not set
-# CONFIG_MESON_SM is not set
-CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4
-# CONFIG_MFD_88PM800 is not set
-# CONFIG_MFD_88PM805 is not set
-# CONFIG_MFD_88PM860X is not set
-# CONFIG_MFD_AAT2870_CORE is not set
-# CONFIG_MFD_AC100 is not set
-# CONFIG_MFD_ACT8945A is not set
-# CONFIG_MFD_ARIZONA_I2C is not set
-# CONFIG_MFD_ARIZONA_SPI is not set
-# CONFIG_MFD_AS3711 is not set
-# CONFIG_MFD_AS3722 is not set
-# CONFIG_MFD_ATC260X_I2C is not set
-# CONFIG_MFD_ATMEL_FLEXCOM is not set
-# CONFIG_MFD_ATMEL_HLCDC is not set
-# CONFIG_MFD_AXP20X is not set
-# CONFIG_MFD_AXP20X_I2C is not set
-# CONFIG_MFD_BCM590XX is not set
-# CONFIG_MFD_BD9571MWV is not set
-# CONFIG_MFD_CORE is not set
-# CONFIG_MFD_CPCAP is not set
-# CONFIG_MFD_CS42L43_I2C is not set
-# CONFIG_MFD_CS5535 is not set
-# CONFIG_MFD_DA9052_I2C is not set
-# CONFIG_MFD_DA9052_SPI is not set
-# CONFIG_MFD_DA9055 is not set
-# CONFIG_MFD_DA9062 is not set
-# CONFIG_MFD_DA9063 is not set
-# CONFIG_MFD_DA9150 is not set
-# CONFIG_MFD_DLN2 is not set
-# CONFIG_MFD_EXYNOS_LPASS is not set
-# CONFIG_MFD_GATEWORKS_GSC is not set
-# CONFIG_MFD_HI6421_PMIC is not set
-# CONFIG_MFD_INTEL_M10_BMC_SPI is not set
-# CONFIG_MFD_INTEL_QUARK_I2C_GPIO is not set
-# CONFIG_MFD_IQS62X is not set
-# CONFIG_MFD_JANZ_CMODIO is not set
-# CONFIG_MFD_KEMPLD is not set
-# CONFIG_MFD_LM3533 is not set
-# CONFIG_MFD_LOCHNAGAR is not set
-# CONFIG_MFD_LP3943 is not set
-# CONFIG_MFD_LP8788 is not set
-# CONFIG_MFD_MADERA is not set
-# CONFIG_MFD_MAX14577 is not set
-# CONFIG_MFD_MAX5970 is not set
-# CONFIG_MFD_MAX77541 is not set
-# CONFIG_MFD_MAX77620 is not set
-# CONFIG_MFD_MAX77650 is not set
-# CONFIG_MFD_MAX77686 is not set
-# CONFIG_MFD_MAX77693 is not set
-# CONFIG_MFD_MAX77714 is not set
-# CONFIG_MFD_MAX77843 is not set
-# CONFIG_MFD_MAX8907 is not set
-# CONFIG_MFD_MAX8925 is not set
-# CONFIG_MFD_MAX8997 is not set
-# CONFIG_MFD_MAX8998 is not set
-# CONFIG_MFD_MC13XXX is not set
-# CONFIG_MFD_MC13XXX_I2C is not set
-# CONFIG_MFD_MC13XXX_SPI is not set
-# CONFIG_MFD_MENF21BMC is not set
-# CONFIG_MFD_MP2629 is not set
-# CONFIG_MFD_MT6360 is not set
-# CONFIG_MFD_MT6370 is not set
-# CONFIG_MFD_MT6397 is not set
-# CONFIG_MFD_NTXEC is not set
-# CONFIG_MFD_OCELOT is not set
-# CONFIG_MFD_OMAP_USB_HOST is not set
-# CONFIG_MFD_PALMAS is not set
-# CONFIG_MFD_PCF50633 is not set
-# CONFIG_MFD_PM8XXX is not set
-# CONFIG_MFD_QCOM_PM8008 is not set
-# CONFIG_MFD_RC5T583 is not set
-# CONFIG_MFD_RDC321X is not set
-# CONFIG_MFD_RETU is not set
-# CONFIG_MFD_RK8XX_I2C is not set
-# CONFIG_MFD_RK8XX_SPI is not set
-# CONFIG_MFD_RN5T618 is not set
-# CONFIG_MFD_ROHM_BD71828 is not set
-# CONFIG_MFD_ROHM_BD718XX is not set
-# CONFIG_MFD_ROHM_BD957XMUF is not set
-# CONFIG_MFD_RSMU_I2C is not set
-# CONFIG_MFD_RSMU_SPI is not set
-# CONFIG_MFD_RT4831 is not set
-# CONFIG_MFD_RT5033 is not set
-# CONFIG_MFD_RT5120 is not set
-# CONFIG_MFD_SEC_CORE is not set
-# CONFIG_MFD_SI476X_CORE is not set
-# CONFIG_MFD_SKY81452 is not set
-# CONFIG_MFD_SL28CPLD is not set
-# CONFIG_MFD_SM501 is not set
-# CONFIG_MFD_SMPRO is not set
-# CONFIG_MFD_STMFX is not set
-# CONFIG_MFD_STMPE is not set
-# CONFIG_MFD_STPMIC1 is not set
-# CONFIG_MFD_SY7636A is not set
-# CONFIG_MFD_SYSCON is not set
-# CONFIG_MFD_TC3589X is not set
-# CONFIG_MFD_TIMBERDALE is not set
-# CONFIG_MFD_TI_AM335X_TSCADC is not set
-# CONFIG_MFD_TI_LMU is not set
-# CONFIG_MFD_TI_LP873X is not set
-# CONFIG_MFD_TI_LP87565 is not set
-# CONFIG_MFD_TPS65086 is not set
-# CONFIG_MFD_TPS65090 is not set
-# CONFIG_MFD_TPS65217 is not set
-# CONFIG_MFD_TPS65218 is not set
-# CONFIG_MFD_TPS65219 is not set
-# CONFIG_MFD_TPS6586X is not set
-# CONFIG_MFD_TPS65910 is not set
-# CONFIG_MFD_TPS65912 is not set
-# CONFIG_MFD_TPS65912_I2C is not set
-# CONFIG_MFD_TPS65912_SPI is not set
-# CONFIG_MFD_TPS6594_I2C is not set
-# CONFIG_MFD_TPS6594_SPI is not set
-# CONFIG_MFD_TQMX86 is not set
-# CONFIG_MFD_VIPERBOARD is not set
-# CONFIG_MFD_VX855 is not set
-# CONFIG_MFD_WL1273_CORE is not set
-# CONFIG_MFD_WM831X is not set
-# CONFIG_MFD_WM831X_I2C is not set
-# CONFIG_MFD_WM831X_SPI is not set
-# CONFIG_MFD_WM8350_I2C is not set
-# CONFIG_MFD_WM8400 is not set
-# CONFIG_MFD_WM8994 is not set
-# CONFIG_MHI_BUS is not set
-# CONFIG_MHI_BUS_DEBUG is not set
-# CONFIG_MHI_BUS_EP is not set
-# CONFIG_MHI_BUS_PCI_GENERIC is not set
-# CONFIG_MHI_NET is not set
-# CONFIG_MHI_WWAN_CTRL is not set
-# CONFIG_MHI_WWAN_MBIM is not set
-# CONFIG_MICREL_KS8995MA is not set
-# CONFIG_MICREL_PHY is not set
-# CONFIG_MICROCHIP_PHY is not set
-# CONFIG_MICROCHIP_PIT64B is not set
-# CONFIG_MICROCHIP_T1S_PHY is not set
-# CONFIG_MICROCHIP_T1_PHY is not set
-# CONFIG_MICROSEMI_PHY is not set
-# CONFIG_MIGRATION is not set
-CONFIG_MII=y
-# CONFIG_MIKROTIK is not set
-# CONFIG_MIKROTIK_RB532 is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_MINIX_FS_NATIVE_ENDIAN is not set
-# CONFIG_MINIX_SUBPARTITION is not set
-# CONFIG_MIPS32_N32 is not set
-# CONFIG_MIPS32_O32 is not set
-# CONFIG_MIPS_ALCHEMY is not set
-# CONFIG_MIPS_CDMM is not set
-# CONFIG_MIPS_CMDLINE_DTB_EXTEND is not set
-# CONFIG_MIPS_CMDLINE_FROM_DTB is not set
-# CONFIG_MIPS_COBALT is not set
-# CONFIG_MIPS_CPS is not set
-# CONFIG_MIPS_ELF_APPENDED_DTB is not set
-# CONFIG_MIPS_FP_SUPPORT is not set
-# CONFIG_MIPS_GENERIC is not set
-# CONFIG_MIPS_GENERIC_KERNEL is not set
-# CONFIG_MIPS_MALTA is not set
-# CONFIG_MIPS_O32_FP64_SUPPORT is not set
-# CONFIG_MIPS_PLATFORM_DEVICES is not set
-# CONFIG_MIPS_RAW_APPENDED_DTB is not set
-# CONFIG_MIPS_VA_BITS_48 is not set
-# CONFIG_MIPS_VPE_LOADER is not set
-# CONFIG_MISC_ALCOR_PCI is not set
-CONFIG_MISC_FILESYSTEMS=y
-# CONFIG_MISC_RTSX_PCI is not set
-# CONFIG_MISC_RTSX_USB is not set
-# CONFIG_MISDN is not set
-# CONFIG_MISDN_AVMFRITZ is not set
-# CONFIG_MISDN_HFCPCI is not set
-# CONFIG_MISDN_HFCUSB is not set
-# CONFIG_MISDN_INFINEON is not set
-# CONFIG_MISDN_NETJET is not set
-# CONFIG_MISDN_SPEEDFAX is not set
-# CONFIG_MISDN_W6692 is not set
-CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY=y
-# CONFIG_MKISS is not set
-# CONFIG_MLX4_CORE is not set
-# CONFIG_MLX4_EN is not set
-# CONFIG_MLX5_CORE is not set
-# CONFIG_MLX5_MACSEC is not set
-# CONFIG_MLX5_SF is not set
-# CONFIG_MLX5_VFIO_PCI is not set
-# CONFIG_MLX90614 is not set
-# CONFIG_MLX90632 is not set
-# CONFIG_MLXFW is not set
-# CONFIG_MLXSW_CORE is not set
-# CONFIG_MLX_PLATFORM is not set
-# CONFIG_MMA7455_I2C is not set
-# CONFIG_MMA7455_SPI is not set
-# CONFIG_MMA7660 is not set
-# CONFIG_MMA8452 is not set
-# CONFIG_MMA9551 is not set
-# CONFIG_MMA9553 is not set
-# CONFIG_MMC is not set
-# CONFIG_MMC35240 is not set
-# CONFIG_MMC_ARMMMCI is not set
-# CONFIG_MMC_AU1X is not set
-# CONFIG_MMC_BLOCK is not set
-CONFIG_MMC_BLOCK_MINORS=8
-# CONFIG_MMC_CAVIUM_THUNDERX is not set
-# CONFIG_MMC_CB710 is not set
-# CONFIG_MMC_CQHCI is not set
-# CONFIG_MMC_DEBUG is not set
-# CONFIG_MMC_DW is not set
-# CONFIG_MMC_HSQ is not set
-# CONFIG_MMC_JZ4740 is not set
-# CONFIG_MMC_MTK is not set
-# CONFIG_MMC_MVSDIO is not set
-# CONFIG_MMC_SDHCI is not set
-# CONFIG_MMC_SDHCI_ACPI is not set
-# CONFIG_MMC_SDHCI_AM654 is not set
-# CONFIG_MMC_SDHCI_BCM_KONA is not set
-# CONFIG_MMC_SDHCI_BRCMSTB is not set
-# CONFIG_MMC_SDHCI_CADENCE is not set
-# CONFIG_MMC_SDHCI_F_SDH30 is not set
-# CONFIG_MMC_SDHCI_IPROC is not set
-# CONFIG_MMC_SDHCI_MILBEAUT is not set
-# CONFIG_MMC_SDHCI_MSM is not set
-# CONFIG_MMC_SDHCI_OF_ARASAN is not set
-# CONFIG_MMC_SDHCI_OF_ASPEED is not set
-# CONFIG_MMC_SDHCI_OF_AT91 is not set
-# CONFIG_MMC_SDHCI_OF_DWCMSHC is not set
-# CONFIG_MMC_SDHCI_OF_ESDHC is not set
-# CONFIG_MMC_SDHCI_OF_HLWD is not set
-# CONFIG_MMC_SDHCI_OMAP is not set
-# CONFIG_MMC_SDHCI_PXAV2 is not set
-# CONFIG_MMC_SDHCI_PXAV3 is not set
-# CONFIG_MMC_SDHCI_S3C is not set
-# CONFIG_MMC_SDHCI_XENON is not set
-# CONFIG_MMC_SDRICOH_CS is not set
-# CONFIG_MMC_SPI is not set
-# CONFIG_MMC_STM32_SDMMC is not set
-# CONFIG_MMC_TEST is not set
-# CONFIG_MMC_TIFM_SD is not set
-# CONFIG_MMC_TOSHIBA_PCI is not set
-# CONFIG_MMC_USDHI6ROL0 is not set
-# CONFIG_MMC_USHC is not set
-# CONFIG_MMC_VIA_SDMMC is not set
-# CONFIG_MMC_VUB300 is not set
-# CONFIG_MMIOTRACE is not set
-CONFIG_MMU=y
-CONFIG_MMU_GATHER_RCU_TABLE_FREE=y
-CONFIG_MMU_GATHER_TABLE_FREE=y
-CONFIG_MODPROBE_PATH="/sbin/modprobe"
-CONFIG_MODULES=y
-# CONFIG_MODULE_ALLOW_MISSING_NAMESPACE_IMPORTS is not set
-# CONFIG_MODULE_COMPRESS_GZIP is not set
-CONFIG_MODULE_COMPRESS_NONE=y
-# CONFIG_MODULE_COMPRESS_XZ is not set
-# CONFIG_MODULE_COMPRESS_ZSTD is not set
-# CONFIG_MODULE_DEBUG is not set
-# CONFIG_MODULE_FORCE_LOAD is not set
-# CONFIG_MODULE_FORCE_UNLOAD is not set
-# CONFIG_MODULE_SIG is not set
-# CONFIG_MODULE_SRCVERSION_ALL is not set
-CONFIG_MODULE_STRIPPED=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_MODULE_UNLOAD_TAINT_TRACKING is not set
-# CONFIG_MODVERSIONS is not set
-# CONFIG_MOST is not set
-# CONFIG_MOTORCOMM_PHY is not set
-# CONFIG_MOUSE_APPLETOUCH is not set
-# CONFIG_MOUSE_BCM5974 is not set
-# CONFIG_MOUSE_CYAPA is not set
-# CONFIG_MOUSE_ELAN_I2C is not set
-# CONFIG_MOUSE_GPIO is not set
-# CONFIG_MOUSE_INPORT is not set
-# CONFIG_MOUSE_LOGIBM is not set
-# CONFIG_MOUSE_PC110PAD is not set
-# CONFIG_MOUSE_PS2_FOCALTECH is not set
-# CONFIG_MOUSE_PS2_SENTELIC is not set
-# CONFIG_MOUSE_SERIAL is not set
-# CONFIG_MOUSE_SYNAPTICS_I2C is not set
-# CONFIG_MOUSE_SYNAPTICS_USB is not set
-# CONFIG_MOUSE_VSXXXAA is not set
-# CONFIG_MOXTET is not set
-# CONFIG_MPL115 is not set
-# CONFIG_MPL115_I2C is not set
-# CONFIG_MPL115_SPI is not set
-# CONFIG_MPL3115 is not set
-# CONFIG_MPLS is not set
-# CONFIG_MPLS_IPTUNNEL is not set
-# CONFIG_MPLS_ROUTING is not set
-# CONFIG_MPRLS0025PA is not set
-# CONFIG_MPTCP is not set
-# CONFIG_MPU3050_I2C is not set
-# CONFIG_MQ_IOSCHED_DEADLINE is not set
-# CONFIG_MQ_IOSCHED_KYBER is not set
-# CONFIG_MS5611 is not set
-# CONFIG_MS5637 is not set
-# CONFIG_MSA311 is not set
-# CONFIG_MSCC_OCELOT_SWITCH is not set
-# CONFIG_MSDOS_FS is not set
-CONFIG_MSDOS_PARTITION=y
-# CONFIG_MSE102X is not set
-# CONFIG_MSI_BITMAP_SELFTEST is not set
-# CONFIG_MSI_LAPTOP is not set
-# CONFIG_MSM_GCC_8953 is not set
-# CONFIG_MSM_MMCC_8994 is not set
-# CONFIG_MST_IRQ is not set
-CONFIG_MTD=y
-# CONFIG_MTD_ABSENT is not set
-# CONFIG_MTD_AFS_PARTS is not set
-# CONFIG_MTD_AR7_PARTS is not set
-CONFIG_MTD_BLKDEVS=y
-CONFIG_MTD_BLOCK=y
-# CONFIG_MTD_BLOCK2MTD is not set
-CONFIG_MTD_CFI=y
-# CONFIG_MTD_CFI_ADV_OPTIONS is not set
-CONFIG_MTD_CFI_AMDSTD=y
-# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
-CONFIG_MTD_CFI_I1=y
-CONFIG_MTD_CFI_I2=y
-# CONFIG_MTD_CFI_I4 is not set
-# CONFIG_MTD_CFI_I8 is not set
-CONFIG_MTD_CFI_INTELEXT=y
-# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
-CONFIG_MTD_CFI_NOSWAP=y
-# CONFIG_MTD_CFI_STAA is not set
-CONFIG_MTD_CFI_UTIL=y
-# CONFIG_MTD_CMDLINE_PARTS is not set
-CONFIG_MTD_COMPLEX_MAPPINGS=y
-# CONFIG_MTD_DATAFLASH is not set
-# CONFIG_MTD_DOCG3 is not set
-CONFIG_MTD_GEN_PROBE=y
-# CONFIG_MTD_HYPERBUS is not set
-# CONFIG_MTD_IMPA7 is not set
-# CONFIG_MTD_INTEL_VR_NOR is not set
-# CONFIG_MTD_JEDECPROBE is not set
-# CONFIG_MTD_LPDDR is not set
-# CONFIG_MTD_LPDDR2_NVM is not set
-CONFIG_MTD_MAP_BANK_WIDTH_1=y
-# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
-CONFIG_MTD_MAP_BANK_WIDTH_2=y
-# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
-CONFIG_MTD_MAP_BANK_WIDTH_4=y
-# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
-# CONFIG_MTD_MCHP23K256 is not set
-# CONFIG_MTD_MCHP48L640 is not set
-# CONFIG_MTD_MTDRAM is not set
-# CONFIG_MTD_MYLOADER_PARTS is not set
-# CONFIG_MTD_NAND_AMS_DELTA is not set
-# CONFIG_MTD_NAND_ARASAN is not set
-# CONFIG_MTD_NAND_ATMEL is not set
-# CONFIG_MTD_NAND_AU1550 is not set
-# CONFIG_MTD_NAND_BRCMNAND is not set
-# CONFIG_MTD_NAND_BRCMNAND_BCM63XX is not set
-# CONFIG_MTD_NAND_BRCMNAND_BCMBCA is not set
-# CONFIG_MTD_NAND_BRCMNAND_BRCMSTB is not set
-# CONFIG_MTD_NAND_BRCMNAND_IPROC is not set
-# CONFIG_MTD_NAND_CADENCE is not set
-# CONFIG_MTD_NAND_CAFE is not set
-# CONFIG_MTD_NAND_CS553X is not set
-# CONFIG_MTD_NAND_DAVINCI is not set
-# CONFIG_MTD_NAND_DENALI is not set
-# CONFIG_MTD_NAND_DENALI_DT is not set
-# CONFIG_MTD_NAND_DENALI_PCI is not set
-# CONFIG_MTD_NAND_DISKONCHIP is not set
-# CONFIG_MTD_NAND_ECC is not set
-# CONFIG_MTD_NAND_ECC_MXIC is not set
-# CONFIG_MTD_NAND_ECC_SW_BCH is not set
-# CONFIG_MTD_NAND_ECC_SW_HAMMING is not set
-# CONFIG_MTD_NAND_ECC_SW_HAMMING_SMC is not set
-# CONFIG_MTD_NAND_FSL_ELBC is not set
-# CONFIG_MTD_NAND_FSL_IFC is not set
-# CONFIG_MTD_NAND_FSL_UPM is not set
-# CONFIG_MTD_NAND_FSMC is not set
-# CONFIG_MTD_NAND_GPIO is not set
-# CONFIG_MTD_NAND_GPMI_NAND is not set
-# CONFIG_MTD_NAND_HISI504 is not set
-# CONFIG_MTD_NAND_INTEL_LGM is not set
-# CONFIG_MTD_NAND_MPC5121_NFC is not set
-# CONFIG_MTD_NAND_MTK is not set
-# CONFIG_MTD_NAND_MTK_BMT is not set
-# CONFIG_MTD_NAND_MXC is not set
-# CONFIG_MTD_NAND_MXIC is not set
-# CONFIG_MTD_NAND_NANDSIM is not set
-# CONFIG_MTD_NAND_NDFC is not set
-# CONFIG_MTD_NAND_OMAP2 is not set
-# CONFIG_MTD_NAND_OMAP_BCH_BUILD is not set
-# CONFIG_MTD_NAND_ORION is not set
-# CONFIG_MTD_NAND_PASEMI is not set
-# CONFIG_MTD_NAND_PLATFORM is not set
-# CONFIG_MTD_NAND_RICOH is not set
-# CONFIG_MTD_NAND_S3C2410 is not set
-# CONFIG_MTD_NAND_SHARPSL is not set
-# CONFIG_MTD_NAND_SH_FLCTL is not set
-# CONFIG_MTD_NAND_SOCRATES is not set
-# CONFIG_MTD_NAND_TXX9NDFMC is not set
-CONFIG_MTD_OF_PARTS=y
-# CONFIG_MTD_ONENAND is not set
-# CONFIG_MTD_OOPS is not set
-# CONFIG_MTD_OTP is not set
-# CONFIG_MTD_PARSER_TRX is not set
-# CONFIG_MTD_PARTITIONED_MASTER is not set
-# CONFIG_MTD_PCI is not set
-# CONFIG_MTD_PCMCIA is not set
-# CONFIG_MTD_PHRAM is not set
-# CONFIG_MTD_PHYSMAP is not set
-# CONFIG_MTD_PHYSMAP_COMPAT is not set
-# CONFIG_MTD_PHYSMAP_GEMINI is not set
-# CONFIG_MTD_PHYSMAP_GPIO_ADDR is not set
-# CONFIG_MTD_PHYSMAP_IXP4XX is not set
-CONFIG_MTD_PHYSMAP_OF=y
-# CONFIG_MTD_PHYSMAP_VERSATILE is not set
-# CONFIG_MTD_PLATRAM is not set
-# CONFIG_MTD_PMC551 is not set
-# CONFIG_MTD_RAM is not set
-# CONFIG_MTD_RAW_NAND is not set
-CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1
-# CONFIG_MTD_REDBOOT_PARTS is not set
-# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set
-# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set
-# CONFIG_MTD_ROM is not set
-CONFIG_MTD_ROOTFS_ROOT_DEV=y
-# CONFIG_MTD_ROUTERBOOT_PARTS is not set
-# CONFIG_MTD_SERCOMM_PARTS is not set
-# CONFIG_MTD_SLRAM is not set
-# CONFIG_MTD_SM_COMMON is not set
-# CONFIG_MTD_SPI_NAND is not set
-# CONFIG_MTD_SPI_NOR is not set
-# CONFIG_MTD_SPI_NOR_SWP_DISABLE is not set
-CONFIG_MTD_SPI_NOR_SWP_DISABLE_ON_VOLATILE=y
-# CONFIG_MTD_SPI_NOR_SWP_KEEP is not set
-# CONFIG_MTD_SPI_NOR_USE_4K_SECTORS is not set
-# CONFIG_MTD_SPI_NOR_USE_VARIABLE_ERASE is not set
-CONFIG_MTD_SPLIT=y
-# CONFIG_MTD_SPLIT_BCM63XX_FW is not set
-# CONFIG_MTD_SPLIT_BCM_WFI_FW is not set
-# CONFIG_MTD_SPLIT_BRNIMAGE_FW is not set
-# CONFIG_MTD_SPLIT_ELF_FW is not set
-# CONFIG_MTD_SPLIT_EVA_FW is not set
-# CONFIG_MTD_SPLIT_FIRMWARE is not set
-CONFIG_MTD_SPLIT_FIRMWARE_NAME="firmware"
-# CONFIG_MTD_SPLIT_FIT_FW is not set
-# CONFIG_MTD_SPLIT_H3C_VFS is not set
-# CONFIG_MTD_SPLIT_JIMAGE_FW is not set
-# CONFIG_MTD_SPLIT_LZMA_FW is not set
-# CONFIG_MTD_SPLIT_MINOR_FW is not set
-# CONFIG_MTD_SPLIT_MSTC_BOOT is not set
-# CONFIG_MTD_SPLIT_SEAMA_FW is not set
-# CONFIG_MTD_SPLIT_SEIL_FW is not set
-CONFIG_MTD_SPLIT_SQUASHFS_ROOT=y
-CONFIG_MTD_SPLIT_SUPPORT=y
-# CONFIG_MTD_SPLIT_TPLINK_FW is not set
-# CONFIG_MTD_SPLIT_TRX_FW is not set
-# CONFIG_MTD_SPLIT_UIMAGE_FW is not set
-# CONFIG_MTD_SPLIT_WRGG_FW is not set
-# CONFIG_MTD_SST25L is not set
-# CONFIG_MTD_SWAP is not set
-# CONFIG_MTD_TESTS is not set
-# CONFIG_MTD_UBI is not set
-# CONFIG_MTD_UBI_FASTMAP is not set
-# CONFIG_MTD_UBI_GLUEBI is not set
-# CONFIG_MTD_UBI_NVMEM is not set
-# CONFIG_MTD_VIRT_CONCAT is not set
-# CONFIG_MTK_DEVAPC is not set
-# CONFIG_MTK_MMSYS is not set
-# CONFIG_MTK_T7XX is not set
-# CONFIG_MTK_THERMAL is not set
-# CONFIG_MULTIPLEXER is not set
-CONFIG_MULTIUSER=y
-# CONFIG_MUTEX_SPIN_ON_OWNER is not set
-# CONFIG_MUX_ADG792A is not set
-# CONFIG_MUX_ADGS1408 is not set
-# CONFIG_MUX_GPIO is not set
-# CONFIG_MUX_MMIO is not set
-# CONFIG_MV643XX_ETH is not set
-# CONFIG_MVMDIO is not set
-# CONFIG_MVNETA_BM is not set
-# CONFIG_MV_XOR_V2 is not set
-# CONFIG_MWAVE is not set
-# CONFIG_MWL8K is not set
-# CONFIG_MXC4005 is not set
-# CONFIG_MXC6255 is not set
-# CONFIG_MYRI10GE is not set
-# CONFIG_NAMESPACES is not set
-# CONFIG_NATIONAL_PHY is not set
-# CONFIG_NATSEMI is not set
-# CONFIG_NAU7802 is not set
-# CONFIG_NBPFAXI_DMA is not set
-# CONFIG_NCN26000_PHY is not set
-# CONFIG_NE2000 is not set
-# CONFIG_NE2K_PCI is not set
-CONFIG_NET=y
-# CONFIG_NETCONSOLE is not set
-# CONFIG_NETCONSOLE_EXTENDED_LOG is not set
-CONFIG_NETDEVICES=y
-# CONFIG_NETDEVSIM is not set
-# CONFIG_NETFILTER is not set
-# CONFIG_NETFILTER_ADVANCED is not set
-# CONFIG_NETFILTER_EGRESS is not set
-# CONFIG_NETFILTER_INGRESS is not set
-# CONFIG_NETFILTER_NETLINK is not set
-# CONFIG_NETFILTER_NETLINK_ACCT is not set
-# CONFIG_NETFILTER_NETLINK_GLUE_CT is not set
-# CONFIG_NETFILTER_NETLINK_HOOK is not set
-# CONFIG_NETFILTER_NETLINK_LOG is not set
-# CONFIG_NETFILTER_NETLINK_OSF is not set
-# CONFIG_NETFILTER_NETLINK_QUEUE is not set
-# CONFIG_NETFILTER_XTABLES is not set
-# CONFIG_NETFILTER_XTABLES_COMPAT is not set
-# CONFIG_NETFILTER_XT_CONNMARK is not set
-# CONFIG_NETFILTER_XT_MARK is not set
-# CONFIG_NETFILTER_XT_MATCH_ADDRTYPE is not set
-# CONFIG_NETFILTER_XT_MATCH_BPF is not set
-# CONFIG_NETFILTER_XT_MATCH_CGROUP is not set
-# CONFIG_NETFILTER_XT_MATCH_CLUSTER is not set
-# CONFIG_NETFILTER_XT_MATCH_COMMENT is not set
-# CONFIG_NETFILTER_XT_MATCH_CONNBYTES is not set
-# CONFIG_NETFILTER_XT_MATCH_CONNLABEL is not set
-# CONFIG_NETFILTER_XT_MATCH_CONNLIMIT is not set
-# CONFIG_NETFILTER_XT_MATCH_CONNMARK is not set
-# CONFIG_NETFILTER_XT_MATCH_CONNTRACK is not set
-# CONFIG_NETFILTER_XT_MATCH_CPU is not set
-# CONFIG_NETFILTER_XT_MATCH_DCCP is not set
-# CONFIG_NETFILTER_XT_MATCH_DEVGROUP is not set
-# CONFIG_NETFILTER_XT_MATCH_DSCP is not set
-# CONFIG_NETFILTER_XT_MATCH_ECN is not set
-# CONFIG_NETFILTER_XT_MATCH_ESP is not set
-# CONFIG_NETFILTER_XT_MATCH_HASHLIMIT is not set
-# CONFIG_NETFILTER_XT_MATCH_HELPER is not set
-# CONFIG_NETFILTER_XT_MATCH_HL is not set
-# CONFIG_NETFILTER_XT_MATCH_IPCOMP is not set
-# CONFIG_NETFILTER_XT_MATCH_IPRANGE is not set
-# CONFIG_NETFILTER_XT_MATCH_L2TP is not set
-# CONFIG_NETFILTER_XT_MATCH_LENGTH is not set
-# CONFIG_NETFILTER_XT_MATCH_LIMIT is not set
-# CONFIG_NETFILTER_XT_MATCH_MAC is not set
-# CONFIG_NETFILTER_XT_MATCH_MARK is not set
-# CONFIG_NETFILTER_XT_MATCH_MULTIPORT is not set
-# CONFIG_NETFILTER_XT_MATCH_NFACCT is not set
-# CONFIG_NETFILTER_XT_MATCH_OSF is not set
-# CONFIG_NETFILTER_XT_MATCH_OWNER is not set
-# CONFIG_NETFILTER_XT_MATCH_PHYSDEV is not set
-# CONFIG_NETFILTER_XT_MATCH_PKTTYPE is not set
-# CONFIG_NETFILTER_XT_MATCH_POLICY is not set
-# CONFIG_NETFILTER_XT_MATCH_QUOTA is not set
-# CONFIG_NETFILTER_XT_MATCH_RATEEST is not set
-# CONFIG_NETFILTER_XT_MATCH_REALM is not set
-# CONFIG_NETFILTER_XT_MATCH_RECENT is not set
-# CONFIG_NETFILTER_XT_MATCH_SCTP is not set
-# CONFIG_NETFILTER_XT_MATCH_SOCKET is not set
-# CONFIG_NETFILTER_XT_MATCH_STATE is not set
-# CONFIG_NETFILTER_XT_MATCH_STATISTIC is not set
-# CONFIG_NETFILTER_XT_MATCH_STRING is not set
-# CONFIG_NETFILTER_XT_MATCH_TCPMSS is not set
-# CONFIG_NETFILTER_XT_MATCH_TIME is not set
-# CONFIG_NETFILTER_XT_MATCH_U32 is not set
-# CONFIG_NETFILTER_XT_TARGET_AUDIT is not set
-# CONFIG_NETFILTER_XT_TARGET_CHECKSUM is not set
-# CONFIG_NETFILTER_XT_TARGET_CLASSIFY is not set
-# CONFIG_NETFILTER_XT_TARGET_CONNMARK is not set
-# CONFIG_NETFILTER_XT_TARGET_CT is not set
-# CONFIG_NETFILTER_XT_TARGET_DSCP is not set
-# CONFIG_NETFILTER_XT_TARGET_HL is not set
-# CONFIG_NETFILTER_XT_TARGET_HMARK is not set
-# CONFIG_NETFILTER_XT_TARGET_IDLETIMER is not set
-# CONFIG_NETFILTER_XT_TARGET_LED is not set
-# CONFIG_NETFILTER_XT_TARGET_LOG is not set
-# CONFIG_NETFILTER_XT_TARGET_MARK is not set
-# CONFIG_NETFILTER_XT_TARGET_NETMAP is not set
-# CONFIG_NETFILTER_XT_TARGET_NFLOG is not set
-# CONFIG_NETFILTER_XT_TARGET_NFQUEUE is not set
-# CONFIG_NETFILTER_XT_TARGET_NOTRACK is not set
-# CONFIG_NETFILTER_XT_TARGET_RATEEST is not set
-# CONFIG_NETFILTER_XT_TARGET_REDIRECT is not set
-# CONFIG_NETFILTER_XT_TARGET_SECMARK is not set
-# CONFIG_NETFILTER_XT_TARGET_TCPMSS is not set
-# CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP is not set
-# CONFIG_NETFILTER_XT_TARGET_TEE is not set
-# CONFIG_NETFILTER_XT_TARGET_TPROXY is not set
-# CONFIG_NETFILTER_XT_TARGET_TRACE is not set
-# CONFIG_NETFS_STATS is not set
-# CONFIG_NETLABEL is not set
-# CONFIG_NETLINK_DIAG is not set
-# CONFIG_NETPOLL is not set
-# CONFIG_NETROM is not set
-CONFIG_NETWORK_FILESYSTEMS=y
-# CONFIG_NETWORK_PHY_TIMESTAMPING is not set
-# CONFIG_NETWORK_SECMARK is not set
-# CONFIG_NETXEN_NIC is not set
-# CONFIG_NET_9P is not set
-# CONFIG_NET_ACT_BPF is not set
-# CONFIG_NET_ACT_CSUM is not set
-# CONFIG_NET_ACT_CT is not set
-# CONFIG_NET_ACT_GACT is not set
-# CONFIG_NET_ACT_GATE is not set
-# CONFIG_NET_ACT_IFE is not set
-# CONFIG_NET_ACT_IPT is not set
-# CONFIG_NET_ACT_MIRRED is not set
-# CONFIG_NET_ACT_MPLS is not set
-# CONFIG_NET_ACT_NAT is not set
-# CONFIG_NET_ACT_PEDIT is not set
-# CONFIG_NET_ACT_POLICE is not set
-# CONFIG_NET_ACT_SAMPLE is not set
-# CONFIG_NET_ACT_SIMP is not set
-# CONFIG_NET_ACT_SKBEDIT is not set
-# CONFIG_NET_ACT_SKBMOD is not set
-# CONFIG_NET_ACT_TUNNEL_KEY is not set
-# CONFIG_NET_ACT_VLAN is not set
-# CONFIG_NET_CALXEDA_XGMAC is not set
-CONFIG_NET_CLS=y
-# CONFIG_NET_CLS_ACT is not set
-# CONFIG_NET_CLS_BASIC is not set
-# CONFIG_NET_CLS_BPF is not set
-# CONFIG_NET_CLS_FLOW is not set
-# CONFIG_NET_CLS_FLOWER is not set
-# CONFIG_NET_CLS_FW is not set
-# CONFIG_NET_CLS_MATCHALL is not set
-# CONFIG_NET_CLS_ROUTE4 is not set
-# CONFIG_NET_CLS_U32 is not set
-CONFIG_NET_CORE=y
-# CONFIG_NET_DEVLINK is not set
-# CONFIG_NET_DEV_REFCNT_TRACKER is not set
-# CONFIG_NET_DROP_MONITOR is not set
-# CONFIG_NET_DSA is not set
-# CONFIG_NET_DSA_AR9331 is not set
-# CONFIG_NET_DSA_BCM_SF2 is not set
-# CONFIG_NET_DSA_LANTIQ_GSWIP is not set
-# CONFIG_NET_DSA_LOOP is not set
-# CONFIG_NET_DSA_MICROCHIP_KSZ_COMMON is not set
-# CONFIG_NET_DSA_MSCC_FELIX is not set
-# CONFIG_NET_DSA_MSCC_OCELOT_EXT is not set
-# CONFIG_NET_DSA_MSCC_SEVILLE is not set
-# CONFIG_NET_DSA_MT7530 is not set
-# CONFIG_NET_DSA_MV88E6060 is not set
-# CONFIG_NET_DSA_MV88E6XXX is not set
-# CONFIG_NET_DSA_MV88E6XXX_LEDS is not set
-# CONFIG_NET_DSA_MV88E6XXX_PTP is not set
-# CONFIG_NET_DSA_QCA8K is not set
-# CONFIG_NET_DSA_QCA8K_LEDS_SUPPORT is not set
-# CONFIG_NET_DSA_REALTEK is not set
-# CONFIG_NET_DSA_REALTEK_SMI is not set
-# CONFIG_NET_DSA_SJA1105 is not set
-# CONFIG_NET_DSA_SMSC_LAN9303_I2C is not set
-# CONFIG_NET_DSA_SMSC_LAN9303_MDIO is not set
-# CONFIG_NET_DSA_TAG_AR9331 is not set
-# CONFIG_NET_DSA_TAG_BRCM is not set
-# CONFIG_NET_DSA_TAG_BRCM_LEGACY is not set
-# CONFIG_NET_DSA_TAG_BRCM_PREPEND is not set
-# CONFIG_NET_DSA_TAG_DSA is not set
-# CONFIG_NET_DSA_TAG_EDSA is not set
-# CONFIG_NET_DSA_TAG_GSWIP is not set
-# CONFIG_NET_DSA_TAG_HELLCREEK is not set
-# CONFIG_NET_DSA_TAG_KSZ is not set
-# CONFIG_NET_DSA_TAG_LAN9303 is not set
-# CONFIG_NET_DSA_TAG_MTK is not set
-# CONFIG_NET_DSA_TAG_NONE is not set
-# CONFIG_NET_DSA_TAG_OCELOT is not set
-# CONFIG_NET_DSA_TAG_OCELOT_8021Q is not set
-# CONFIG_NET_DSA_TAG_QCA is not set
-# CONFIG_NET_DSA_TAG_RTL4_A is not set
-# CONFIG_NET_DSA_TAG_RTL8_4 is not set
-# CONFIG_NET_DSA_TAG_RZN1_A5PSW is not set
-# CONFIG_NET_DSA_TAG_SJA1105 is not set
-# CONFIG_NET_DSA_TAG_TRAILER is not set
-# CONFIG_NET_DSA_TAG_XRS700X is not set
-# CONFIG_NET_DSA_VITESSE_VSC73XX is not set
-# CONFIG_NET_DSA_VITESSE_VSC73XX_PLATFORM is not set
-# CONFIG_NET_DSA_VITESSE_VSC73XX_SPI is not set
-# CONFIG_NET_DSA_XRS700X_I2C is not set
-# CONFIG_NET_DSA_XRS700X_MDIO is not set
-# CONFIG_NET_EMATCH is not set
-# CONFIG_NET_EMATCH_CANID is not set
-# CONFIG_NET_EMATCH_CMP is not set
-# CONFIG_NET_EMATCH_IPT is not set
-# CONFIG_NET_EMATCH_META is not set
-# CONFIG_NET_EMATCH_NBYTE is not set
-CONFIG_NET_EMATCH_STACK=32
-# CONFIG_NET_EMATCH_TEXT is not set
-# CONFIG_NET_EMATCH_U32 is not set
-# CONFIG_NET_FAILOVER is not set
-# CONFIG_NET_FC is not set
-# CONFIG_NET_FOU is not set
-# CONFIG_NET_FOU_IP_TUNNELS is not set
-# CONFIG_NET_IFE is not set
-# CONFIG_NET_IPGRE is not set
-CONFIG_NET_IPGRE_BROADCAST=y
-# CONFIG_NET_IPGRE_DEMUX is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPVTI is not set
-# CONFIG_NET_IP_TUNNEL is not set
-# CONFIG_NET_KEY is not set
-# CONFIG_NET_KEY_MIGRATE is not set
-# CONFIG_NET_L3_MASTER_DEV is not set
-# CONFIG_NET_MEDIATEK_STAR_EMAC is not set
-# CONFIG_NET_MPLS_GSO is not set
-# CONFIG_NET_NCSI is not set
-# CONFIG_NET_NSH is not set
-# CONFIG_NET_NS_REFCNT_TRACKER is not set
-# CONFIG_NET_PKTGEN is not set
-# CONFIG_NET_POLL_CONTROLLER is not set
-# CONFIG_NET_PTP_CLASSIFY is not set
-CONFIG_NET_RX_BUSY_POLL=y
-# CONFIG_NET_SB1000 is not set
-CONFIG_NET_SCHED=y
-# CONFIG_NET_SCH_CAKE is not set
-# CONFIG_NET_SCH_CBS is not set
-# CONFIG_NET_SCH_CHOKE is not set
-# CONFIG_NET_SCH_CODEL is not set
-CONFIG_NET_SCH_DEFAULT=y
-# CONFIG_NET_SCH_DRR is not set
-# CONFIG_NET_SCH_ETF is not set
-# CONFIG_NET_SCH_ETS is not set
-CONFIG_NET_SCH_FIFO=y
-# CONFIG_NET_SCH_FQ is not set
-CONFIG_NET_SCH_FQ_CODEL=y
-# CONFIG_NET_SCH_FQ_PIE is not set
-# CONFIG_NET_SCH_GRED is not set
-# CONFIG_NET_SCH_HFSC is not set
-# CONFIG_NET_SCH_HHF is not set
-# CONFIG_NET_SCH_HTB is not set
-# CONFIG_NET_SCH_INGRESS is not set
-# CONFIG_NET_SCH_MQPRIO is not set
-# CONFIG_NET_SCH_MULTIQ is not set
-# CONFIG_NET_SCH_NETEM is not set
-# CONFIG_NET_SCH_PIE is not set
-# CONFIG_NET_SCH_PLUG is not set
-# CONFIG_NET_SCH_PRIO is not set
-# CONFIG_NET_SCH_QFQ is not set
-# CONFIG_NET_SCH_RED is not set
-# CONFIG_NET_SCH_SFB is not set
-# CONFIG_NET_SCH_SFQ is not set
-# CONFIG_NET_SCH_SKBPRIO is not set
-# CONFIG_NET_SCH_TAPRIO is not set
-# CONFIG_NET_SCH_TBF is not set
-# CONFIG_NET_SCH_TEQL is not set
-# CONFIG_NET_SELFTESTS is not set
-CONFIG_NET_SOCK_MSG=y
-CONFIG_NET_SWITCHDEV=y
-# CONFIG_NET_TC_SKB_EXT is not set
-# CONFIG_NET_TEAM is not set
-# CONFIG_NET_TULIP is not set
-# CONFIG_NET_UDP_TUNNEL is not set
-CONFIG_NET_VENDOR_3COM=y
-CONFIG_NET_VENDOR_8390=y
-CONFIG_NET_VENDOR_ADAPTEC=y
-CONFIG_NET_VENDOR_ADI=y
-CONFIG_NET_VENDOR_AGERE=y
-CONFIG_NET_VENDOR_ALACRITECH=y
-CONFIG_NET_VENDOR_ALTEON=y
-CONFIG_NET_VENDOR_AMAZON=y
-CONFIG_NET_VENDOR_AMD=y
-CONFIG_NET_VENDOR_AQUANTIA=y
-CONFIG_NET_VENDOR_ARC=y
-# CONFIG_NET_VENDOR_ASIX is not set
-CONFIG_NET_VENDOR_ATHEROS=y
-CONFIG_NET_VENDOR_BROADCOM=y
-CONFIG_NET_VENDOR_BROCADE=y
-CONFIG_NET_VENDOR_CADENCE=y
-CONFIG_NET_VENDOR_CAVIUM=y
-CONFIG_NET_VENDOR_CHELSIO=y
-CONFIG_NET_VENDOR_CIRRUS=y
-CONFIG_NET_VENDOR_CISCO=y
-CONFIG_NET_VENDOR_CORTINA=y
-CONFIG_NET_VENDOR_DAVICOM=y
-CONFIG_NET_VENDOR_DEC=y
-CONFIG_NET_VENDOR_DLINK=y
-CONFIG_NET_VENDOR_EMULEX=y
-# CONFIG_NET_VENDOR_ENGLEDER is not set
-CONFIG_NET_VENDOR_EZCHIP=y
-CONFIG_NET_VENDOR_FARADAY=y
-CONFIG_NET_VENDOR_FREESCALE=y
-CONFIG_NET_VENDOR_FUJITSU=y
-# CONFIG_NET_VENDOR_FUNGIBLE is not set
-CONFIG_NET_VENDOR_GOOGLE=y
-CONFIG_NET_VENDOR_HISILICON=y
-CONFIG_NET_VENDOR_HUAWEI=y
-CONFIG_NET_VENDOR_I825XX=y
-CONFIG_NET_VENDOR_IBM=y
-CONFIG_NET_VENDOR_INTEL=y
-# CONFIG_NET_VENDOR_LITEX is not set
-CONFIG_NET_VENDOR_MARVELL=y
-CONFIG_NET_VENDOR_MELLANOX=y
-CONFIG_NET_VENDOR_MICREL=y
-CONFIG_NET_VENDOR_MICROCHIP=y
-CONFIG_NET_VENDOR_MICROSEMI=y
-# CONFIG_NET_VENDOR_MICROSOFT is not set
-CONFIG_NET_VENDOR_MYRI=y
-CONFIG_NET_VENDOR_NATSEMI=y
-CONFIG_NET_VENDOR_NETERION=y
-CONFIG_NET_VENDOR_NETRONOME=y
-CONFIG_NET_VENDOR_NI=y
-CONFIG_NET_VENDOR_NVIDIA=y
-CONFIG_NET_VENDOR_OKI=y
-CONFIG_NET_VENDOR_PACKET_ENGINES=y
-CONFIG_NET_VENDOR_PENSANDO=y
-CONFIG_NET_VENDOR_QLOGIC=y
-CONFIG_NET_VENDOR_QUALCOMM=y
-CONFIG_NET_VENDOR_RDC=y
-CONFIG_NET_VENDOR_REALTEK=y
-CONFIG_NET_VENDOR_RENESAS=y
-CONFIG_NET_VENDOR_ROCKER=y
-CONFIG_NET_VENDOR_SAMSUNG=y
-CONFIG_NET_VENDOR_SEEQ=y
-CONFIG_NET_VENDOR_SILAN=y
-CONFIG_NET_VENDOR_SIS=y
-CONFIG_NET_VENDOR_SMSC=y
-CONFIG_NET_VENDOR_SOCIONEXT=y
-CONFIG_NET_VENDOR_SOLARFLARE=y
-CONFIG_NET_VENDOR_STMICRO=y
-CONFIG_NET_VENDOR_SUN=y
-CONFIG_NET_VENDOR_SYNOPSYS=y
-CONFIG_NET_VENDOR_TEHUTI=y
-CONFIG_NET_VENDOR_TI=y
-CONFIG_NET_VENDOR_TOSHIBA=y
-# CONFIG_NET_VENDOR_VERTEXCOM is not set
-CONFIG_NET_VENDOR_VIA=y
-# CONFIG_NET_VENDOR_WANGXUN is not set
-CONFIG_NET_VENDOR_WIZNET=y
-CONFIG_NET_VENDOR_XILINX=y
-CONFIG_NET_VENDOR_XIRCOM=y
-# CONFIG_NET_VRF is not set
-# CONFIG_NET_XGENE is not set
-CONFIG_NEW_LEDS=y
-# CONFIG_NFC is not set
-# CONFIG_NFP is not set
-# CONFIG_NFSD is not set
-# CONFIG_NFSD_V2 is not set
-# CONFIG_NFSD_V2_ACL is not set
-# CONFIG_NFSD_V3_ACL is not set
-# CONFIG_NFSD_V4 is not set
-# CONFIG_NFS_ACL_SUPPORT is not set
-CONFIG_NFS_COMMON=y
-# CONFIG_NFS_DISABLE_UDP_SUPPORT is not set
-# CONFIG_NFS_FS is not set
-# CONFIG_NFS_FSCACHE is not set
-# CONFIG_NFS_SWAP is not set
-# CONFIG_NFS_V2 is not set
-CONFIG_NFS_V3=y
-# CONFIG_NFS_V3_ACL is not set
-# CONFIG_NFS_V4 is not set
-# CONFIG_NFS_V4_1 is not set
-# CONFIG_NFTL is not set
-# CONFIG_NFT_BRIDGE_META is not set
-# CONFIG_NFT_BRIDGE_REJECT is not set
-# CONFIG_NFT_CONNLIMIT is not set
-# CONFIG_NFT_DUP_IPV4 is not set
-# CONFIG_NFT_DUP_IPV6 is not set
-# CONFIG_NFT_FIB_IPV4 is not set
-# CONFIG_NFT_FIB_IPV6 is not set
-# CONFIG_NFT_FIB_NETDEV is not set
-# CONFIG_NFT_FLOW_OFFLOAD is not set
-# CONFIG_NFT_OSF is not set
-# CONFIG_NFT_REJECT_NETDEV is not set
-# CONFIG_NFT_SOCKET is not set
-# CONFIG_NFT_SYNPROXY is not set
-# CONFIG_NFT_TPROXY is not set
-# CONFIG_NFT_TUNNEL is not set
-# CONFIG_NFT_XFRM is not set
-# CONFIG_NF_CONNTRACK is not set
-# CONFIG_NF_CONNTRACK_AMANDA is not set
-# CONFIG_NF_CONNTRACK_BRIDGE is not set
-# CONFIG_NF_CONNTRACK_EVENTS is not set
-# CONFIG_NF_CONNTRACK_FTP is not set
-# CONFIG_NF_CONNTRACK_H323 is not set
-# CONFIG_NF_CONNTRACK_IRC is not set
-# CONFIG_NF_CONNTRACK_LABELS is not set
-# CONFIG_NF_CONNTRACK_MARK is not set
-# CONFIG_NF_CONNTRACK_NETBIOS_NS is not set
-# CONFIG_NF_CONNTRACK_PPTP is not set
-CONFIG_NF_CONNTRACK_PROCFS=y
-# CONFIG_NF_CONNTRACK_SANE is not set
-# CONFIG_NF_CONNTRACK_SECMARK is not set
-# CONFIG_NF_CONNTRACK_SIP is not set
-# CONFIG_NF_CONNTRACK_SNMP is not set
-# CONFIG_NF_CONNTRACK_TFTP is not set
-# CONFIG_NF_CONNTRACK_TIMEOUT is not set
-# CONFIG_NF_CONNTRACK_TIMESTAMP is not set
-# CONFIG_NF_CONNTRACK_ZONES is not set
-# CONFIG_NF_CT_NETLINK is not set
-# CONFIG_NF_CT_NETLINK_HELPER is not set
-# CONFIG_NF_CT_NETLINK_TIMEOUT is not set
-# CONFIG_NF_CT_PROTO_DCCP is not set
-# CONFIG_NF_CT_PROTO_GRE is not set
-# CONFIG_NF_CT_PROTO_SCTP is not set
-# CONFIG_NF_CT_PROTO_UDPLITE is not set
-# CONFIG_NF_DEFRAG_IPV4 is not set
-# CONFIG_NF_DUP_IPV4 is not set
-# CONFIG_NF_DUP_IPV6 is not set
-# CONFIG_NF_FLOW_TABLE is not set
-# CONFIG_NF_FLOW_TABLE_PROCFS is not set
-# CONFIG_NF_LOG_ARP is not set
-# CONFIG_NF_LOG_IPV4 is not set
-# CONFIG_NF_LOG_SYSLOG is not set
-# CONFIG_NF_NAT is not set
-# CONFIG_NF_NAT_AMANDA is not set
-# CONFIG_NF_NAT_FTP is not set
-# CONFIG_NF_NAT_H323 is not set
-# CONFIG_NF_NAT_IRC is not set
-# CONFIG_NF_NAT_PPTP is not set
-# CONFIG_NF_NAT_SIP is not set
-# CONFIG_NF_NAT_SNMP_BASIC is not set
-# CONFIG_NF_NAT_TFTP is not set
-# CONFIG_NF_REJECT_IPV4 is not set
-# CONFIG_NF_REJECT_IPV6 is not set
-# CONFIG_NF_SOCKET_IPV4 is not set
-# CONFIG_NF_SOCKET_IPV6 is not set
-# CONFIG_NF_TABLES is not set
-CONFIG_NF_TABLES_ARP=y
-CONFIG_NF_TABLES_BRIDGE=y
-CONFIG_NF_TABLES_INET=y
-CONFIG_NF_TABLES_IPV4=y
-CONFIG_NF_TABLES_IPV6=y
-CONFIG_NF_TABLES_NETDEV=y
-# CONFIG_NF_TPROXY_IPV4 is not set
-# CONFIG_NF_TPROXY_IPV6 is not set
-# CONFIG_NGBE is not set
-# CONFIG_NI903X_WDT is not set
-# CONFIG_NIC7018_WDT is not set
-# CONFIG_NILFS2_FS is not set
-# CONFIG_NIU is not set
-# CONFIG_NI_XGE_MANAGEMENT_ENET is not set
-CONFIG_NLATTR=y
-# CONFIG_NLMON is not set
-# CONFIG_NLS is not set
-# CONFIG_NLS_ASCII is not set
-# CONFIG_NLS_CODEPAGE_1250 is not set
-# CONFIG_NLS_CODEPAGE_1251 is not set
-# CONFIG_NLS_CODEPAGE_437 is not set
-# CONFIG_NLS_CODEPAGE_737 is not set
-# CONFIG_NLS_CODEPAGE_775 is not set
-# CONFIG_NLS_CODEPAGE_850 is not set
-# CONFIG_NLS_CODEPAGE_852 is not set
-# CONFIG_NLS_CODEPAGE_855 is not set
-# CONFIG_NLS_CODEPAGE_857 is not set
-# CONFIG_NLS_CODEPAGE_860 is not set
-# CONFIG_NLS_CODEPAGE_861 is not set
-# CONFIG_NLS_CODEPAGE_862 is not set
-# CONFIG_NLS_CODEPAGE_863 is not set
-# CONFIG_NLS_CODEPAGE_864 is not set
-# CONFIG_NLS_CODEPAGE_865 is not set
-# CONFIG_NLS_CODEPAGE_866 is not set
-# CONFIG_NLS_CODEPAGE_869 is not set
-# CONFIG_NLS_CODEPAGE_874 is not set
-# CONFIG_NLS_CODEPAGE_932 is not set
-# CONFIG_NLS_CODEPAGE_936 is not set
-# CONFIG_NLS_CODEPAGE_949 is not set
-# CONFIG_NLS_CODEPAGE_950 is not set
-CONFIG_NLS_DEFAULT="iso8859-1"
-# CONFIG_NLS_ISO8859_1 is not set
-# CONFIG_NLS_ISO8859_13 is not set
-# CONFIG_NLS_ISO8859_14 is not set
-# CONFIG_NLS_ISO8859_15 is not set
-# CONFIG_NLS_ISO8859_2 is not set
-# CONFIG_NLS_ISO8859_3 is not set
-# CONFIG_NLS_ISO8859_4 is not set
-# CONFIG_NLS_ISO8859_5 is not set
-# CONFIG_NLS_ISO8859_6 is not set
-# CONFIG_NLS_ISO8859_7 is not set
-# CONFIG_NLS_ISO8859_8 is not set
-# CONFIG_NLS_ISO8859_9 is not set
-# CONFIG_NLS_KOI8_R is not set
-# CONFIG_NLS_KOI8_U is not set
-# CONFIG_NLS_MAC_CELTIC is not set
-# CONFIG_NLS_MAC_CENTEURO is not set
-# CONFIG_NLS_MAC_CROATIAN is not set
-# CONFIG_NLS_MAC_CYRILLIC is not set
-# CONFIG_NLS_MAC_GAELIC is not set
-# CONFIG_NLS_MAC_GREEK is not set
-# CONFIG_NLS_MAC_ICELAND is not set
-# CONFIG_NLS_MAC_INUIT is not set
-# CONFIG_NLS_MAC_ROMAN is not set
-# CONFIG_NLS_MAC_ROMANIAN is not set
-# CONFIG_NLS_MAC_TURKISH is not set
-# CONFIG_NLS_UCS2_UTILS is not set
-# CONFIG_NLS_UTF8 is not set
-# CONFIG_NOA1305 is not set
-# CONFIG_NOP_USB_XCEIV is not set
-# CONFIG_NORTEL_HERMES is not set
-# CONFIG_NOTIFIER_ERROR_INJECTION is not set
-# CONFIG_NOZOMI is not set
-# CONFIG_NO_HZ is not set
-# CONFIG_NO_HZ_FULL is not set
-# CONFIG_NO_HZ_IDLE is not set
-# CONFIG_NS83820 is not set
-# CONFIG_NTB is not set
-# CONFIG_NTFS3_64BIT_CLUSTER is not set
-# CONFIG_NTFS3_FS is not set
-# CONFIG_NTFS3_FS_POSIX_ACL is not set
-# CONFIG_NTFS3_LZX_XPRESS is not set
-# CONFIG_NTFS_DEBUG is not set
-# CONFIG_NTFS_FS is not set
-# CONFIG_NTFS_RW is not set
-# CONFIG_NTP_PPS is not set
-# CONFIG_NULL_TTY is not set
-# CONFIG_NUMA is not set
-# CONFIG_NVIDIA_CARMEL_CNP_ERRATUM is not set
-# CONFIG_NVMEM is not set
-# CONFIG_NVMEM_BCM_OCOTP is not set
-# CONFIG_NVMEM_BLOCK is not set
-# CONFIG_NVMEM_IMX_OCOTP is not set
-# CONFIG_NVMEM_LAYOUT_ASCII_ENV is not set
-# CONFIG_NVMEM_LAYOUT_ONIE_TLV is not set
-# CONFIG_NVMEM_LAYOUT_SL28_VPD is not set
-# CONFIG_NVMEM_LAYOUT_U_BOOT_ENV is not set
-# CONFIG_NVMEM_REBOOT_MODE is not set
-# CONFIG_NVMEM_RMEM is not set
-# CONFIG_NVMEM_SYSFS is not set
-# CONFIG_NVMEM_U_BOOT_ENV is not set
-# CONFIG_NVME_AUTH is not set
-# CONFIG_NVME_FC is not set
-# CONFIG_NVME_TARGET is not set
-# CONFIG_NVME_TCP is not set
-# CONFIG_NVME_VERBOSE_ERRORS is not set
-# CONFIG_NVRAM is not set
-# CONFIG_NV_TCO is not set
-# CONFIG_NXP_C45_TJA11XX_PHY is not set
-# CONFIG_NXP_CBTX_PHY is not set
-# CONFIG_NXP_TJA11XX_PHY is not set
-# CONFIG_N_GSM is not set
-# CONFIG_OABI_COMPAT is not set
-# CONFIG_OBS600 is not set
-# CONFIG_OCFS2_FS is not set
-# CONFIG_OCTEONTX2_AF is not set
-# CONFIG_OCTEONTX2_PF is not set
-# CONFIG_OCTEON_EP is not set
-# CONFIG_OF_OVERLAY is not set
-CONFIG_OF_PARTITION=y
-CONFIG_OF_RESERVED_MEM=y
-# CONFIG_OF_UNITTEST is not set
-# CONFIG_OID_REGISTRY is not set
-# CONFIG_OMAP2_DSS_DEBUG is not set
-# CONFIG_OMAP2_DSS_DEBUGFS is not set
-# CONFIG_OMAP2_DSS_SDI is not set
-# CONFIG_OMAP_OCP2SCP is not set
-# CONFIG_OMAP_USB2 is not set
-# CONFIG_OMFS_FS is not set
-# CONFIG_OPENVSWITCH is not set
-# CONFIG_OPEN_DICE is not set
-# CONFIG_OPT3001 is not set
-# CONFIG_OPT4001 is not set
-# CONFIG_ORANGEFS_FS is not set
-# CONFIG_ORION_WATCHDOG is not set
-# CONFIG_OSF_PARTITION is not set
-# CONFIG_OSNOISE_TRACER is not set
-CONFIG_OVERLAY_FS=y
-# CONFIG_OVERLAY_FS_DEBUG is not set
-# CONFIG_OVERLAY_FS_INDEX is not set
-# CONFIG_OVERLAY_FS_METACOPY is not set
-CONFIG_OVERLAY_FS_REDIRECT_ALWAYS_FOLLOW=y
-# CONFIG_OVERLAY_FS_REDIRECT_DIR is not set
-CONFIG_OVERLAY_FS_XINO_AUTO=y
-# CONFIG_P54_COMMON is not set
-# CONFIG_PA12203001 is not set
-CONFIG_PACKET=y
-# CONFIG_PACKET_DIAG is not set
-# CONFIG_PACKING is not set
-# CONFIG_PAGE_EXTENSION is not set
-# CONFIG_PAGE_OWNER is not set
-# CONFIG_PAGE_POISONING is not set
-# CONFIG_PAGE_POOL is not set
-# CONFIG_PAGE_POOL_STATS is not set
-# CONFIG_PAGE_REPORTING is not set
-# CONFIG_PAGE_SIZE_16KB is not set
-# CONFIG_PAGE_SIZE_32KB is not set
-CONFIG_PAGE_SIZE_4KB=y
-# CONFIG_PAGE_SIZE_64KB is not set
-# CONFIG_PAGE_SIZE_8KB is not set
-# CONFIG_PAGE_TABLE_CHECK is not set
-# CONFIG_PALMAS_GPADC is not set
-# CONFIG_PANASONIC_LAPTOP is not set
-# CONFIG_PANEL is not set
-CONFIG_PANIC_ON_OOPS=y
-CONFIG_PANIC_ON_OOPS_VALUE=1
-CONFIG_PANIC_TIMEOUT=1
-# CONFIG_PANTHERLORD_FF is not set
-# CONFIG_PARAVIRT is not set
-# CONFIG_PARAVIRT_TIME_ACCOUNTING is not set
-# CONFIG_PARPORT is not set
-# CONFIG_PARPORT_1284 is not set
-# CONFIG_PARPORT_GSC is not set
-# CONFIG_PARPORT_PC is not set
-CONFIG_PARTITION_ADVANCED=y
-# CONFIG_PATA_ACPI is not set
-# CONFIG_PATA_ALI is not set
-# CONFIG_PATA_AMD is not set
-# CONFIG_PATA_ARASAN_CF is not set
-# CONFIG_PATA_ARTOP is not set
-# CONFIG_PATA_ATIIXP is not set
-# CONFIG_PATA_ATP867X is not set
-# CONFIG_PATA_CMD640_PCI is not set
-# CONFIG_PATA_CMD64X is not set
-# CONFIG_PATA_CS5520 is not set
-# CONFIG_PATA_CS5530 is not set
-# CONFIG_PATA_CS5535 is not set
-# CONFIG_PATA_CS5536 is not set
-# CONFIG_PATA_CYPRESS is not set
-# CONFIG_PATA_EFAR is not set
-# CONFIG_PATA_HPT366 is not set
-# CONFIG_PATA_HPT37X is not set
-# CONFIG_PATA_HPT3X2N is not set
-# CONFIG_PATA_HPT3X3 is not set
-# CONFIG_PATA_IMX is not set
-# CONFIG_PATA_ISAPNP is not set
-# CONFIG_PATA_IT8213 is not set
-# CONFIG_PATA_IT821X is not set
-# CONFIG_PATA_JMICRON is not set
-# CONFIG_PATA_LEGACY is not set
-# CONFIG_PATA_MARVELL is not set
-# CONFIG_PATA_MPIIX is not set
-# CONFIG_PATA_NETCELL is not set
-# CONFIG_PATA_NINJA32 is not set
-# CONFIG_PATA_NS87410 is not set
-# CONFIG_PATA_NS87415 is not set
-# CONFIG_PATA_OCTEON_CF is not set
-# CONFIG_PATA_OF_PLATFORM is not set
-# CONFIG_PATA_OLDPIIX is not set
-# CONFIG_PATA_OPTI is not set
-# CONFIG_PATA_OPTIDMA is not set
-# CONFIG_PATA_PARPORT is not set
-# CONFIG_PATA_PCMCIA is not set
-# CONFIG_PATA_PDC2027X is not set
-# CONFIG_PATA_PDC_OLD is not set
-# CONFIG_PATA_PLATFORM is not set
-# CONFIG_PATA_QDI is not set
-# CONFIG_PATA_RADISYS is not set
-# CONFIG_PATA_RDC is not set
-# CONFIG_PATA_RZ1000 is not set
-# CONFIG_PATA_SC1200 is not set
-# CONFIG_PATA_SCH is not set
-# CONFIG_PATA_SERVERWORKS is not set
-# CONFIG_PATA_SIL680 is not set
-# CONFIG_PATA_SIS is not set
-# CONFIG_PATA_TOSHIBA is not set
-# CONFIG_PATA_TRIFLEX is not set
-# CONFIG_PATA_VIA is not set
-# CONFIG_PATA_WINBOND is not set
-# CONFIG_PATA_WINBOND_VLB is not set
-# CONFIG_PC104 is not set
-# CONFIG_PC300TOO is not set
-# CONFIG_PCCARD is not set
-# CONFIG_PCH_DMA is not set
-# CONFIG_PCH_GBE is not set
-# CONFIG_PCH_PHUB is not set
-# CONFIG_PCI is not set
-# CONFIG_PCI200SYN is not set
-# CONFIG_PCIEAER is not set
-# CONFIG_PCIEAER_INJECT is not set
-# CONFIG_PCIEASPM is not set
-# CONFIG_PCIEPORTBUS is not set
-# CONFIG_PCIE_AL is not set
-# CONFIG_PCIE_ALTERA is not set
-# CONFIG_PCIE_ARMADA_8K is not set
-CONFIG_PCIE_BUS_DEFAULT=y
-# CONFIG_PCIE_BUS_PEER2PEER is not set
-# CONFIG_PCIE_BUS_PERFORMANCE is not set
-# CONFIG_PCIE_BUS_SAFE is not set
-# CONFIG_PCIE_BUS_TUNE_OFF is not set
-# CONFIG_PCIE_CADENCE_HOST is not set
-# CONFIG_PCIE_CADENCE_PLAT_HOST is not set
-# CONFIG_PCIE_DPC is not set
-# CONFIG_PCIE_DW_PLAT is not set
-# CONFIG_PCIE_DW_PLAT_HOST is not set
-# CONFIG_PCIE_ECRC is not set
-# CONFIG_PCIE_IPROC is not set
-# CONFIG_PCIE_KIRIN is not set
-# CONFIG_PCIE_LAYERSCAPE_GEN4 is not set
-# CONFIG_PCIE_MEDIATEK_GEN3 is not set
-# CONFIG_PCIE_MICROCHIP_HOST is not set
-# CONFIG_PCIE_PTM is not set
-# CONFIG_PCIE_XILINX is not set
-# CONFIG_PCIPCWATCHDOG is not set
-# CONFIG_PCI_ATMEL is not set
-# CONFIG_PCI_CNB20LE_QUIRK is not set
-# CONFIG_PCI_DEBUG is not set
-# CONFIG_PCI_DISABLE_COMMON_QUIRKS is not set
-# CONFIG_PCI_DYNAMIC_OF_NODES is not set
-# CONFIG_PCI_ENDPOINT is not set
-# CONFIG_PCI_ENDPOINT_TEST is not set
-# CONFIG_PCI_FTPCI100 is not set
-# CONFIG_PCI_HERMES is not set
-# CONFIG_PCI_HISI is not set
-# CONFIG_PCI_HOST_GENERIC is not set
-# CONFIG_PCI_HOST_THUNDER_ECAM is not set
-# CONFIG_PCI_HOST_THUNDER_PEM is not set
-# CONFIG_PCI_IOV is not set
-# CONFIG_PCI_J721E_HOST is not set
-# CONFIG_PCI_LAYERSCAPE is not set
-# CONFIG_PCI_MESON is not set
-# CONFIG_PCI_MSI is not set
-# CONFIG_PCI_PASID is not set
-# CONFIG_PCI_PF_STUB is not set
-# CONFIG_PCI_PRI is not set
-CONFIG_PCI_QUIRKS=y
-# CONFIG_PCI_REALLOC_ENABLE_AUTO is not set
-# CONFIG_PCI_STUB is not set
-# CONFIG_PCI_SW_SWITCHTEC is not set
-CONFIG_PCI_SYSCALL=y
-# CONFIG_PCI_V3_SEMI is not set
-# CONFIG_PCI_XGENE is not set
-# CONFIG_PCMCIA is not set
-# CONFIG_PCMCIA_3C574 is not set
-# CONFIG_PCMCIA_3C589 is not set
-# CONFIG_PCMCIA_AHA152X is not set
-# CONFIG_PCMCIA_ATMEL is not set
-# CONFIG_PCMCIA_AXNET is not set
-# CONFIG_PCMCIA_DEBUG is not set
-# CONFIG_PCMCIA_FDOMAIN is not set
-# CONFIG_PCMCIA_FMVJ18X is not set
-# CONFIG_PCMCIA_HERMES is not set
-# CONFIG_PCMCIA_LOAD_CIS is not set
-# CONFIG_PCMCIA_NINJA_SCSI is not set
-# CONFIG_PCMCIA_NMCLAN is not set
-# CONFIG_PCMCIA_PCNET is not set
-# CONFIG_PCMCIA_QLOGIC is not set
-# CONFIG_PCMCIA_RAYCS is not set
-# CONFIG_PCMCIA_SMC91C92 is not set
-# CONFIG_PCMCIA_SPECTRUM is not set
-# CONFIG_PCMCIA_SYM53C500 is not set
-# CONFIG_PCMCIA_WL3501 is not set
-# CONFIG_PCMCIA_XIRC2PS is not set
-# CONFIG_PCMCIA_XIRCOM is not set
-# CONFIG_PCNET32 is not set
-CONFIG_PCPU_DEV_REFCNT=y
-CONFIG_PCP_BATCH_SCALE_MAX=5
-# CONFIG_PCSPKR_PLATFORM is not set
-# CONFIG_PCS_MTK_USXGMII is not set
-# CONFIG_PCS_XPCS is not set
-# CONFIG_PD6729 is not set
-# CONFIG_PDC_ADMA is not set
-# CONFIG_PDS_CORE is not set
-# CONFIG_PECI is not set
-# CONFIG_PERCPU_STATS is not set
-# CONFIG_PERCPU_TEST is not set
-# CONFIG_PERF_EVENTS is not set
-# CONFIG_PERF_EVENTS_AMD_POWER is not set
-# CONFIG_PERSISTENT_KEYRINGS is not set
-# CONFIG_PER_VMA_LOCK_STATS is not set
-# CONFIG_PHANTOM is not set
-# CONFIG_PHONET is not set
-# CONFIG_PHYLIB is not set
-# CONFIG_PHYLIB_LEDS is not set
-# CONFIG_PHYS_ADDR_T_64BIT is not set
-# CONFIG_PHY_BRCM_USB is not set
-# CONFIG_PHY_CADENCE_DPHY is not set
-# CONFIG_PHY_CADENCE_DPHY_RX is not set
-# CONFIG_PHY_CADENCE_SALVO is not set
-# CONFIG_PHY_CADENCE_SIERRA is not set
-# CONFIG_PHY_CADENCE_TORRENT is not set
-# CONFIG_PHY_CAN_TRANSCEIVER is not set
-# CONFIG_PHY_CPCAP_USB is not set
-# CONFIG_PHY_EXYNOS_DP_VIDEO is not set
-# CONFIG_PHY_EXYNOS_MIPI_VIDEO is not set
-# CONFIG_PHY_FSL_IMX8MQ_USB is not set
-# CONFIG_PHY_INGENIC_USB is not set
-# CONFIG_PHY_INTEL_KEEMBAY_EMMC is not set
-# CONFIG_PHY_LAN966X_SERDES is not set
-# CONFIG_PHY_MAPPHONE_MDM6600 is not set
-# CONFIG_PHY_MIXEL_MIPI_DPHY is not set
-# CONFIG_PHY_MTK_HDMI is not set
-# CONFIG_PHY_MTK_MIPI_DSI is not set
-# CONFIG_PHY_MTK_XFI_TPHY is not set
-# CONFIG_PHY_MVEBU_CP110_UTMI is not set
-# CONFIG_PHY_OCELOT_SERDES is not set
-# CONFIG_PHY_PISTACHIO_USB is not set
-# CONFIG_PHY_PXA_28NM_HSIC is not set
-# CONFIG_PHY_PXA_28NM_USB2 is not set
-# CONFIG_PHY_QCOM_USB_HS is not set
-# CONFIG_PHY_QCOM_USB_HSIC is not set
-# CONFIG_PHY_SAMSUNG_USB2 is not set
-# CONFIG_PHY_TUSB1210 is not set
-# CONFIG_PHY_XGENE is not set
-# CONFIG_PI433 is not set
-# CONFIG_PID_IN_CONTEXTIDR is not set
-# CONFIG_PID_NS is not set
-CONFIG_PINCONF=y
-# CONFIG_PINCTRL is not set
-# CONFIG_PINCTRL_AMD is not set
-# CONFIG_PINCTRL_AXP209 is not set
-# CONFIG_PINCTRL_CEDARFORK is not set
-# CONFIG_PINCTRL_CY8C95X0 is not set
-# CONFIG_PINCTRL_EXYNOS is not set
-# CONFIG_PINCTRL_ICELAKE is not set
-# CONFIG_PINCTRL_INGENIC is not set
-# CONFIG_PINCTRL_LPASS_LPI is not set
-# CONFIG_PINCTRL_MCP23S08 is not set
-# CONFIG_PINCTRL_MDM9607 is not set
-# CONFIG_PINCTRL_MICROCHIP_SGPIO is not set
-# CONFIG_PINCTRL_MSM8953 is not set
-# CONFIG_PINCTRL_MSM8X74 is not set
-# CONFIG_PINCTRL_MT6779 is not set
-# CONFIG_PINCTRL_MT8167 is not set
-# CONFIG_PINCTRL_MT8192 is not set
-# CONFIG_PINCTRL_MT8195 is not set
-# CONFIG_PINCTRL_MT8365 is not set
-# CONFIG_PINCTRL_MTK_V2 is not set
-# CONFIG_PINCTRL_OCELOT is not set
-# CONFIG_PINCTRL_PISTACHIO is not set
-# CONFIG_PINCTRL_SC7280 is not set
-# CONFIG_PINCTRL_SC8180X is not set
-# CONFIG_PINCTRL_SDX55 is not set
-CONFIG_PINCTRL_SINGLE=y
-# CONFIG_PINCTRL_SM6115 is not set
-# CONFIG_PINCTRL_SM6125 is not set
-# CONFIG_PINCTRL_SM8350 is not set
-# CONFIG_PINCTRL_STMFX is not set
-# CONFIG_PINCTRL_SX150X is not set
-# CONFIG_PING is not set
-CONFIG_PINMUX=y
-# CONFIG_PKCS7_MESSAGE_PARSER is not set
-# CONFIG_PL310_ERRATA_588369 is not set
-# CONFIG_PL310_ERRATA_727915 is not set
-# CONFIG_PL310_ERRATA_753970 is not set
-# CONFIG_PL310_ERRATA_769419 is not set
-# CONFIG_PL320_MBOX is not set
-# CONFIG_PL330_DMA is not set
-# CONFIG_PLATFORM_MHU is not set
-# CONFIG_PLAT_SPEAR is not set
-# CONFIG_PLIP is not set
-# CONFIG_PLX_DMA is not set
-# CONFIG_PLX_HERMES is not set
-# CONFIG_PM is not set
-# CONFIG_PMBUS is not set
-# CONFIG_PMIC_ADP5520 is not set
-# CONFIG_PMIC_DA903X is not set
-# CONFIG_PMS7003 is not set
-# CONFIG_PM_AUTOSLEEP is not set
-# CONFIG_PM_DEBUG is not set
-# CONFIG_PM_DEVFREQ is not set
-# CONFIG_PM_USERSPACE_AUTOSLEEP is not set
-# CONFIG_PM_WAKELOCKS is not set
-# CONFIG_POSIX_MQUEUE is not set
-CONFIG_POSIX_TIMERS=y
-# CONFIG_POWERCAP is not set
-# CONFIG_POWER_RESET is not set
-# CONFIG_POWER_RESET_BRCMKONA is not set
-# CONFIG_POWER_RESET_BRCMSTB is not set
-# CONFIG_POWER_RESET_GPIO is not set
-# CONFIG_POWER_RESET_GPIO_RESTART is not set
-# CONFIG_POWER_RESET_LINKSTATION is not set
-# CONFIG_POWER_RESET_LTC2952 is not set
-# CONFIG_POWER_RESET_PIIX4_POWEROFF is not set
-# CONFIG_POWER_RESET_QNAP is not set
-# CONFIG_POWER_RESET_REGULATOR is not set
-# CONFIG_POWER_RESET_RESTART is not set
-# CONFIG_POWER_RESET_SYSCON is not set
-# CONFIG_POWER_RESET_SYSCON_POWEROFF is not set
-# CONFIG_POWER_RESET_VERSATILE is not set
-# CONFIG_POWER_RESET_XGENE is not set
-# CONFIG_POWER_SUPPLY is not set
-# CONFIG_POWER_SUPPLY_DEBUG is not set
-# CONFIG_POWER_SUPPLY_HWMON is not set
-# CONFIG_PPC4xx_GPIO is not set
-# CONFIG_PPC_16K_PAGES is not set
-# CONFIG_PPC_256K_PAGES is not set
-CONFIG_PPC_4K_PAGES=y
-# CONFIG_PPC_64K_PAGES is not set
-# CONFIG_PPC_DISABLE_WERROR is not set
-# CONFIG_PPC_EMULATED_STATS is not set
-# CONFIG_PPC_EPAPR_HV_BYTECHAN is not set
-# CONFIG_PPC_QUEUED_SPINLOCKS is not set
-# CONFIG_PPP is not set
-# CONFIG_PPPOATM is not set
-# CONFIG_PPPOE is not set
-# CONFIG_PPPOE_HASH_BITS_1 is not set
-# CONFIG_PPPOE_HASH_BITS_2 is not set
-CONFIG_PPPOE_HASH_BITS_4=y
-# CONFIG_PPPOE_HASH_BITS_8 is not set
-# CONFIG_PPPOL2TP is not set
-# CONFIG_PPP_ASYNC is not set
-# CONFIG_PPP_BSDCOMP is not set
-# CONFIG_PPP_DEFLATE is not set
-CONFIG_PPP_FILTER=y
-# CONFIG_PPP_MPPE is not set
-CONFIG_PPP_MULTILINK=y
-# CONFIG_PPP_SYNC_TTY is not set
-# CONFIG_PPS is not set
-# CONFIG_PPS_CLIENT_GPIO is not set
-# CONFIG_PPS_CLIENT_KTIMER is not set
-# CONFIG_PPS_CLIENT_LDISC is not set
-# CONFIG_PPS_CLIENT_PARPORT is not set
-# CONFIG_PPS_DEBUG is not set
-# CONFIG_PPTP is not set
-# CONFIG_PREEMPT is not set
-# CONFIG_PREEMPTIRQ_DELAY_TEST is not set
-# CONFIG_PREEMPT_DYNAMIC is not set
-CONFIG_PREEMPT_NONE=y
-# CONFIG_PREEMPT_TRACER is not set
-# CONFIG_PREEMPT_VOLUNTARY is not set
-# CONFIG_PRESTERA is not set
-CONFIG_PREVENT_FIRMWARE_BUILD=y
-# CONFIG_PRIME_NUMBERS is not set
-CONFIG_PRINTK=y
-# CONFIG_PRINTK_CALLER is not set
-# CONFIG_PRINTK_INDEX is not set
-# CONFIG_PRINTK_TIME is not set
-CONFIG_PRINT_STACK_DEPTH=64
-# CONFIG_PRISM2_USB is not set
-# CONFIG_PROC_CHILDREN is not set
-CONFIG_PROC_FS=y
-# CONFIG_PROC_KCORE is not set
-CONFIG_PROC_MEM_ALWAYS_FORCE=y
-# CONFIG_PROC_MEM_FORCE_PTRACE is not set
-# CONFIG_PROC_MEM_NO_FORCE is not set
-# CONFIG_PROC_PAGE_MONITOR is not set
-# CONFIG_PROC_STRIPPED is not set
-CONFIG_PROC_SYSCTL=y
-# CONFIG_PROC_VMCORE_DEVICE_DUMP is not set
-# CONFIG_PROFILE_ALL_BRANCHES is not set
-# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
-# CONFIG_PROFILING is not set
-# CONFIG_PROVE_LOCKING is not set
-# CONFIG_PROVE_RAW_LOCK_NESTING is not set
-# CONFIG_PROVE_RCU is not set
-# CONFIG_PROVE_RCU_LIST is not set
-# CONFIG_PSAMPLE is not set
-# CONFIG_PSB6970_PHY is not set
-# CONFIG_PSE_CONTROLLER is not set
-# CONFIG_PSI is not set
-# CONFIG_PSI_DEFAULT_DISABLED is not set
-# CONFIG_PSTORE is not set
-# CONFIG_PSTORE_BLK is not set
-# CONFIG_PSTORE_COMPRESS is not set
-# CONFIG_PSTORE_CONSOLE is not set
-CONFIG_PSTORE_DEFAULT_KMSG_BYTES=10240
-# CONFIG_PSTORE_FTRACE is not set
-# CONFIG_PSTORE_PMSG is not set
-# CONFIG_PSTORE_RAM is not set
-# CONFIG_PTDUMP_DEBUGFS is not set
-# CONFIG_PTP_1588_CLOCK is not set
-# CONFIG_PTP_1588_CLOCK_IDT82P33 is not set
-# CONFIG_PTP_1588_CLOCK_IDTCM is not set
-# CONFIG_PTP_1588_CLOCK_IXP46X is not set
-# CONFIG_PTP_1588_CLOCK_KVM is not set
-# CONFIG_PTP_1588_CLOCK_MOCK is not set
-# CONFIG_PTP_1588_CLOCK_OCP is not set
-# CONFIG_PTP_1588_CLOCK_PCH is not set
-# CONFIG_PTP_1588_CLOCK_VMW is not set
-# CONFIG_PVPANIC is not set
-# CONFIG_PWM is not set
-# CONFIG_PWM_ATMEL_TCB is not set
-# CONFIG_PWM_CLK is not set
-# CONFIG_PWM_DEBUG is not set
-# CONFIG_PWM_DWC is not set
-# CONFIG_PWM_FSL_FTM is not set
-# CONFIG_PWM_IMG is not set
-# CONFIG_PWM_JZ4740 is not set
-# CONFIG_PWM_MEDIATEK is not set
-# CONFIG_PWM_PCA9685 is not set
-# CONFIG_PWM_RASPBERRYPI_POE is not set
-# CONFIG_PWM_XILINX is not set
-CONFIG_PWRSEQ_EMMC=y
-# CONFIG_PWRSEQ_SD8787 is not set
-CONFIG_PWRSEQ_SIMPLE=y
-# CONFIG_QCA7000 is not set
-# CONFIG_QCA7000_SPI is not set
-# CONFIG_QCA7000_UART is not set
-# CONFIG_QCA807X_PHY is not set
-# CONFIG_QCA808X_PHY is not set
-# CONFIG_QCA83XX_PHY is not set
-# CONFIG_QCOM_A7PLL is not set
-# CONFIG_QCOM_BAM_DMUX is not set
-# CONFIG_QCOM_EMAC is not set
-# CONFIG_QCOM_FALKOR_ERRATUM_1003 is not set
-# CONFIG_QCOM_FALKOR_ERRATUM_1009 is not set
-# CONFIG_QCOM_FALKOR_ERRATUM_E1041 is not set
-# CONFIG_QCOM_GPI_DMA is not set
-# CONFIG_QCOM_HIDMA is not set
-# CONFIG_QCOM_HIDMA_MGMT is not set
-# CONFIG_QCOM_LMH is not set
-# CONFIG_QCOM_QDF2400_ERRATUM_0065 is not set
-# CONFIG_QCOM_SPMI_ADC5 is not set
-# CONFIG_QCOM_SPMI_ADC_TM5 is not set
-# CONFIG_QCOM_SPMI_IADC is not set
-# CONFIG_QCOM_SPMI_TEMP_ALARM is not set
-# CONFIG_QCOM_SPMI_VADC is not set
-# CONFIG_QCOM_SSC_BLOCK_BUS is not set
-# CONFIG_QED is not set
-# CONFIG_QFMT_V1 is not set
-# CONFIG_QLA3XXX is not set
-# CONFIG_QLCNIC is not set
-# CONFIG_QLGE is not set
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_QNX6FS_FS is not set
-# CONFIG_QORIQ_CPUFREQ is not set
-# CONFIG_QORIQ_THERMAL is not set
-# CONFIG_QRTR is not set
-# CONFIG_QRTR_MHI is not set
-# CONFIG_QRTR_TUN is not set
-# CONFIG_QSEMI_PHY is not set
-# CONFIG_QUICC_ENGINE is not set
-# CONFIG_QUOTA is not set
-# CONFIG_QUOTACTL is not set
-# CONFIG_QUOTA_DEBUG is not set
-# CONFIG_QUOTA_NETLINK_INTERFACE is not set
-# CONFIG_R6040 is not set
-# CONFIG_R8169 is not set
-# CONFIG_R8169_LEDS is not set
-# CONFIG_R8712U is not set
-# CONFIG_RADIO_ADAPTERS is not set
-# CONFIG_RADIO_AZTECH is not set
-# CONFIG_RADIO_CADET is not set
-# CONFIG_RADIO_GEMTEK is not set
-# CONFIG_RADIO_MAXIRADIO is not set
-# CONFIG_RADIO_RTRACK is not set
-# CONFIG_RADIO_RTRACK2 is not set
-# CONFIG_RADIO_SF16FMI is not set
-# CONFIG_RADIO_SF16FMR2 is not set
-# CONFIG_RADIO_TERRATEC is not set
-# CONFIG_RADIO_TRUST is not set
-# CONFIG_RADIO_TYPHOON is not set
-# CONFIG_RADIO_ZOLTRIX is not set
-# CONFIG_RAID6_PQ_BENCHMARK is not set
-# CONFIG_RAID_ATTRS is not set
-# CONFIG_RALINK is not set
-# CONFIG_RANDOM32_SELFTEST is not set
-# CONFIG_RANDOMIZE_BASE is not set
-CONFIG_RANDOMIZE_KSTACK_OFFSET=y
-# CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT is not set
-# CONFIG_RANDOM_KMALLOC_CACHES is not set
-# CONFIG_RANDSTRUCT_NONE is not set
-# CONFIG_RAPIDIO is not set
-# CONFIG_RAS is not set
-# CONFIG_RBTREE_TEST is not set
-# CONFIG_RCU_BOOST is not set
-# CONFIG_RCU_CPU_STALL_CPUTIME is not set
-CONFIG_RCU_CPU_STALL_TIMEOUT=60
-# CONFIG_RCU_EQS_DEBUG is not set
-# CONFIG_RCU_EXPERT is not set
-CONFIG_RCU_EXP_CPU_STALL_TIMEOUT=0
-CONFIG_RCU_NEED_SEGCBLIST=y
-# CONFIG_RCU_REF_SCALE_TEST is not set
-# CONFIG_RCU_SCALE_TEST is not set
-CONFIG_RCU_STALL_COMMON=y
-# CONFIG_RCU_STRICT_GRACE_PERIOD is not set
-# CONFIG_RCU_TORTURE_TEST is not set
-# CONFIG_RCU_TRACE is not set
-# CONFIG_RC_ATI_REMOTE is not set
-# CONFIG_RC_CORE is not set
-# CONFIG_RC_DECODERS is not set
-# CONFIG_RC_LOOPBACK is not set
-# CONFIG_RC_MAP is not set
-# CONFIG_RC_XBOX_DVD is not set
-# CONFIG_RDS is not set
-# CONFIG_RD_BZIP2 is not set
-# CONFIG_RD_GZIP is not set
-# CONFIG_RD_LZ4 is not set
-# CONFIG_RD_LZMA is not set
-# CONFIG_RD_LZO is not set
-# CONFIG_RD_XZ is not set
-# CONFIG_RD_ZSTD is not set
-# CONFIG_READABLE_ASM is not set
-# CONFIG_READ_ONLY_THP_FOR_FS is not set
-# CONFIG_REALTEK_PHY is not set
-# CONFIG_REDWOOD is not set
-# CONFIG_REED_SOLOMON is not set
-# CONFIG_REED_SOLOMON_DEC8 is not set
-# CONFIG_REED_SOLOMON_ENC8 is not set
-# CONFIG_REED_SOLOMON_TEST is not set
-# CONFIG_REGMAP is not set
-# CONFIG_REGMAP_I2C is not set
-# CONFIG_REGMAP_MMIO is not set
-# CONFIG_REGMAP_SPI is not set
-# CONFIG_REGULATOR is not set
-# CONFIG_REGULATOR_88PG86X is not set
-# CONFIG_REGULATOR_ACT8865 is not set
-# CONFIG_REGULATOR_AD5398 is not set
-# CONFIG_REGULATOR_ANATOP is not set
-# CONFIG_REGULATOR_AW37503 is not set
-# CONFIG_REGULATOR_DA9121 is not set
-# CONFIG_REGULATOR_DA9210 is not set
-# CONFIG_REGULATOR_DA9211 is not set
-# CONFIG_REGULATOR_DEBUG is not set
-# CONFIG_REGULATOR_FAN53555 is not set
-# CONFIG_REGULATOR_FAN53880 is not set
-# CONFIG_REGULATOR_FIXED_VOLTAGE is not set
-# CONFIG_REGULATOR_GPIO is not set
-# CONFIG_REGULATOR_ISL6271A is not set
-# CONFIG_REGULATOR_ISL9305 is not set
-# CONFIG_REGULATOR_LP3971 is not set
-# CONFIG_REGULATOR_LP3972 is not set
-# CONFIG_REGULATOR_LP872X is not set
-# CONFIG_REGULATOR_LP8755 is not set
-# CONFIG_REGULATOR_LTC3589 is not set
-# CONFIG_REGULATOR_LTC3676 is not set
-# CONFIG_REGULATOR_MAX1586 is not set
-# CONFIG_REGULATOR_MAX20086 is not set
-# CONFIG_REGULATOR_MAX20411 is not set
-# CONFIG_REGULATOR_MAX77620 is not set
-# CONFIG_REGULATOR_MAX77826 is not set
-# CONFIG_REGULATOR_MAX77857 is not set
-# CONFIG_REGULATOR_MAX8649 is not set
-# CONFIG_REGULATOR_MAX8660 is not set
-# CONFIG_REGULATOR_MAX8893 is not set
-# CONFIG_REGULATOR_MAX8952 is not set
-# CONFIG_REGULATOR_MAX8973 is not set
-# CONFIG_REGULATOR_MCP16502 is not set
-# CONFIG_REGULATOR_MP5416 is not set
-# CONFIG_REGULATOR_MP8859 is not set
-# CONFIG_REGULATOR_MP886X is not set
-# CONFIG_REGULATOR_MPQ7920 is not set
-# CONFIG_REGULATOR_MT6311 is not set
-# CONFIG_REGULATOR_MT6315 is not set
-# CONFIG_REGULATOR_MT6359 is not set
-# CONFIG_REGULATOR_PCA9450 is not set
-# CONFIG_REGULATOR_PF8X00 is not set
-# CONFIG_REGULATOR_PFUZE100 is not set
-# CONFIG_REGULATOR_PV88060 is not set
-# CONFIG_REGULATOR_PV88080 is not set
-# CONFIG_REGULATOR_PV88090 is not set
-# CONFIG_REGULATOR_PWM is not set
-# CONFIG_REGULATOR_QCOM_REFGEN is not set
-# CONFIG_REGULATOR_RAA215300 is not set
-# CONFIG_REGULATOR_RASPBERRYPI_TOUCHSCREEN_ATTINY is not set
-# CONFIG_REGULATOR_RT4801 is not set
-# CONFIG_REGULATOR_RT4803 is not set
-# CONFIG_REGULATOR_RT5190A is not set
-# CONFIG_REGULATOR_RT5739 is not set
-# CONFIG_REGULATOR_RT5759 is not set
-# CONFIG_REGULATOR_RT6160 is not set
-# CONFIG_REGULATOR_RT6190 is not set
-# CONFIG_REGULATOR_RT6245 is not set
-# CONFIG_REGULATOR_RTMV20 is not set
-# CONFIG_REGULATOR_RTQ2134 is not set
-# CONFIG_REGULATOR_RTQ2208 is not set
-# CONFIG_REGULATOR_RTQ6752 is not set
-# CONFIG_REGULATOR_SLG51000 is not set
-# CONFIG_REGULATOR_SY8106A is not set
-# CONFIG_REGULATOR_SY8824X is not set
-# CONFIG_REGULATOR_SY8827N is not set
-# CONFIG_REGULATOR_TI_ABB is not set
-# CONFIG_REGULATOR_TPS51632 is not set
-# CONFIG_REGULATOR_TPS62360 is not set
-# CONFIG_REGULATOR_TPS6286X is not set
-# CONFIG_REGULATOR_TPS6287X is not set
-# CONFIG_REGULATOR_TPS65023 is not set
-# CONFIG_REGULATOR_TPS6507X is not set
-# CONFIG_REGULATOR_TPS65132 is not set
-# CONFIG_REGULATOR_TPS6524X is not set
-# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set
-# CONFIG_REGULATOR_VCTRL is not set
-# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
-# CONFIG_REISERFS_CHECK is not set
-# CONFIG_REISERFS_FS is not set
-# CONFIG_REISERFS_FS_POSIX_ACL is not set
-# CONFIG_REISERFS_FS_SECURITY is not set
-CONFIG_REISERFS_FS_XATTR=y
-# CONFIG_REISERFS_PROC_INFO is not set
-# CONFIG_RELAY is not set
-# CONFIG_RELOCATABLE is not set
-CONFIG_RELR=y
-# CONFIG_REMOTEPROC is not set
-# CONFIG_RENESAS_PHY is not set
-# CONFIG_RESET_ATH79 is not set
-# CONFIG_RESET_BERLIN is not set
-# CONFIG_RESET_BRCMSTB is not set
-# CONFIG_RESET_BRCMSTB_RESCAL is not set
-# CONFIG_RESET_CONTROLLER is not set
-# CONFIG_RESET_IMX7 is not set
-# CONFIG_RESET_INTEL_GW is not set
-# CONFIG_RESET_LANTIQ is not set
-# CONFIG_RESET_LPC18XX is not set
-# CONFIG_RESET_MESON is not set
-# CONFIG_RESET_PISTACHIO is not set
-# CONFIG_RESET_SIMPLE is not set
-# CONFIG_RESET_SOCFPGA is not set
-# CONFIG_RESET_SUNXI is not set
-# CONFIG_RESET_TEGRA_BPMP is not set
-# CONFIG_RESET_TI_SYSCON is not set
-# CONFIG_RESET_TI_TPS380X is not set
-# CONFIG_RESET_ZYNQ is not set
-# CONFIG_RFD77402 is not set
-# CONFIG_RFD_FTL is not set
-CONFIG_RFKILL=y
-# CONFIG_RFKILL_FULL is not set
-# CONFIG_RFKILL_GPIO is not set
-# CONFIG_RFKILL_INPUT is not set
-# CONFIG_RFKILL_LEDS is not set
-# CONFIG_RICHTEK_RTQ6056 is not set
-# CONFIG_RING_BUFFER_BENCHMARK is not set
-# CONFIG_RING_BUFFER_STARTUP_TEST is not set
-# CONFIG_RING_BUFFER_VALIDATE_TIME_DELTAS is not set
-# CONFIG_RISCV_PMU is not set
-# CONFIG_RISCV_PMU_LEGACY is not set
-# CONFIG_RISCV_PMU_SBI is not set
-# CONFIG_RMI4_CORE is not set
-# CONFIG_RMNET is not set
-# CONFIG_ROCKCHIP_ERRATUM_3588001 is not set
-# CONFIG_ROCKCHIP_PHY is not set
-# CONFIG_ROCKER is not set
-# CONFIG_ROHM_BU27008 is not set
-# CONFIG_ROHM_BU27034 is not set
-# CONFIG_ROMFS_FS is not set
-# CONFIG_ROSE is not set
-# CONFIG_RPCSEC_GSS_KRB5 is not set
-# CONFIG_RPCSEC_GSS_KRB5_ENCTYPES_AES_SHA1 is not set
-# CONFIG_RPCSEC_GSS_KRB5_ENCTYPES_AES_SHA2 is not set
-# CONFIG_RPCSEC_GSS_KRB5_ENCTYPES_CAMELLIA is not set
-# CONFIG_RPMSG_QCOM_GLINK_RPM is not set
-# CONFIG_RPMSG_VIRTIO is not set
-# CONFIG_RPMSG_WWAN_CTRL is not set
-# CONFIG_RPR0521 is not set
-# CONFIG_RSEQ is not set
-# CONFIG_RT2X00 is not set
-# CONFIG_RTC_CLASS is not set
-# CONFIG_RTC_DEBUG is not set
-# CONFIG_RTC_DRV_ABB5ZES3 is not set
-# CONFIG_RTC_DRV_ABEOZ9 is not set
-# CONFIG_RTC_DRV_ABX80X is not set
-# CONFIG_RTC_DRV_ARMADA38X is not set
-# CONFIG_RTC_DRV_AU1XXX is not set
-# CONFIG_RTC_DRV_BQ32K is not set
-# CONFIG_RTC_DRV_BQ4802 is not set
-# CONFIG_RTC_DRV_CADENCE is not set
-CONFIG_RTC_DRV_CMOS=y
-# CONFIG_RTC_DRV_DS1286 is not set
-# CONFIG_RTC_DRV_DS1302 is not set
-# CONFIG_RTC_DRV_DS1305 is not set
-# CONFIG_RTC_DRV_DS1307 is not set
-# CONFIG_RTC_DRV_DS1307_CENTURY is not set
-# CONFIG_RTC_DRV_DS1343 is not set
-# CONFIG_RTC_DRV_DS1347 is not set
-# CONFIG_RTC_DRV_DS1374 is not set
-# CONFIG_RTC_DRV_DS1390 is not set
-# CONFIG_RTC_DRV_DS1511 is not set
-# CONFIG_RTC_DRV_DS1553 is not set
-# CONFIG_RTC_DRV_DS1672 is not set
-# CONFIG_RTC_DRV_DS1685_FAMILY is not set
-# CONFIG_RTC_DRV_DS1742 is not set
-# CONFIG_RTC_DRV_DS2404 is not set
-# CONFIG_RTC_DRV_DS3232 is not set
-# CONFIG_RTC_DRV_EM3027 is not set
-# CONFIG_RTC_DRV_EP93XX is not set
-# CONFIG_RTC_DRV_FM3130 is not set
-# CONFIG_RTC_DRV_FTRTC010 is not set
-# CONFIG_RTC_DRV_GENERIC is not set
-# CONFIG_RTC_DRV_GOLDFISH is not set
-# CONFIG_RTC_DRV_HID_SENSOR_TIME is not set
-# CONFIG_RTC_DRV_HYM8563 is not set
-# CONFIG_RTC_DRV_ISL12022 is not set
-# CONFIG_RTC_DRV_ISL12026 is not set
-# CONFIG_RTC_DRV_ISL1208 is not set
-# CONFIG_RTC_DRV_JZ4740 is not set
-# CONFIG_RTC_DRV_M41T80 is not set
-# CONFIG_RTC_DRV_M41T93 is not set
-# CONFIG_RTC_DRV_M41T94 is not set
-# CONFIG_RTC_DRV_M48T35 is not set
-# CONFIG_RTC_DRV_M48T59 is not set
-# CONFIG_RTC_DRV_M48T86 is not set
-# CONFIG_RTC_DRV_MAX6900 is not set
-# CONFIG_RTC_DRV_MAX6902 is not set
-# CONFIG_RTC_DRV_MAX6916 is not set
-# CONFIG_RTC_DRV_MAX77686 is not set
-# CONFIG_RTC_DRV_MCP795 is not set
-# CONFIG_RTC_DRV_MOXART is not set
-# CONFIG_RTC_DRV_MPC5121 is not set
-# CONFIG_RTC_DRV_MSM6242 is not set
-# CONFIG_RTC_DRV_MT2712 is not set
-# CONFIG_RTC_DRV_NCT3018Y is not set
-# CONFIG_RTC_DRV_OMAP is not set
-# CONFIG_RTC_DRV_PCF2123 is not set
-# CONFIG_RTC_DRV_PCF2127 is not set
-# CONFIG_RTC_DRV_PCF85063 is not set
-# CONFIG_RTC_DRV_PCF8523 is not set
-# CONFIG_RTC_DRV_PCF85363 is not set
-# CONFIG_RTC_DRV_PCF8563 is not set
-# CONFIG_RTC_DRV_PCF8583 is not set
-# CONFIG_RTC_DRV_PL030 is not set
-# CONFIG_RTC_DRV_PL031 is not set
-# CONFIG_RTC_DRV_PS3 is not set
-# CONFIG_RTC_DRV_R7301 is not set
-# CONFIG_RTC_DRV_R9701 is not set
-# CONFIG_RTC_DRV_RP5C01 is not set
-# CONFIG_RTC_DRV_RS5C348 is not set
-# CONFIG_RTC_DRV_RS5C372 is not set
-# CONFIG_RTC_DRV_RV3028 is not set
-# CONFIG_RTC_DRV_RV3029C2 is not set
-# CONFIG_RTC_DRV_RV3032 is not set
-# CONFIG_RTC_DRV_RV8803 is not set
-# CONFIG_RTC_DRV_RX4581 is not set
-# CONFIG_RTC_DRV_RX6110 is not set
-# CONFIG_RTC_DRV_RX8010 is not set
-# CONFIG_RTC_DRV_RX8025 is not set
-# CONFIG_RTC_DRV_RX8581 is not set
-# CONFIG_RTC_DRV_S35390A is not set
-# CONFIG_RTC_DRV_SD3078 is not set
-# CONFIG_RTC_DRV_SNVS is not set
-# CONFIG_RTC_DRV_STK17TA8 is not set
-# CONFIG_RTC_DRV_SUN6I is not set
-# CONFIG_RTC_DRV_TEGRA is not set
-# CONFIG_RTC_DRV_TEST is not set
-# CONFIG_RTC_DRV_X1205 is not set
-# CONFIG_RTC_DRV_XGENE is not set
-# CONFIG_RTC_DRV_ZYNQMP is not set
-CONFIG_RTC_HCTOSYS=y
-CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
-CONFIG_RTC_INTF_DEV=y
-# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
-CONFIG_RTC_INTF_PROC=y
-CONFIG_RTC_INTF_SYSFS=y
-CONFIG_RTC_LIB=y
-# CONFIG_RTC_NVMEM is not set
-CONFIG_RTC_SYSTOHC=y
-CONFIG_RTC_SYSTOHC_DEVICE="rtc0"
-# CONFIG_RTL8180 is not set
-# CONFIG_RTL8187 is not set
-# CONFIG_RTL8192E is not set
-# CONFIG_RTL8192U is not set
-# CONFIG_RTL8261N_PHY is not set
-# CONFIG_RTL8306_PHY is not set
-# CONFIG_RTL8366RB_PHY is not set
-# CONFIG_RTL8366S_PHY is not set
-# CONFIG_RTL8366_SMI is not set
-# CONFIG_RTL8366_SMI_DEBUG_FS is not set
-# CONFIG_RTL8367B_PHY is not set
-# CONFIG_RTL8367_PHY is not set
-# CONFIG_RTLLIB is not set
-# CONFIG_RTL_CARDS is not set
-# CONFIG_RTS5208 is not set
-CONFIG_RT_MUTEXES=y
-CONFIG_RUNTIME_TESTING_MENU=y
-# CONFIG_RUST is not set
-# CONFIG_RV is not set
-CONFIG_RXKAD=y
-# CONFIG_RXPERF is not set
-# CONFIG_S2IO is not set
-# CONFIG_SAMPLES is not set
-# CONFIG_SAMSUNG_LAPTOP is not set
-# CONFIG_SATA_ACARD_AHCI is not set
-# CONFIG_SATA_AHCI is not set
-# CONFIG_SATA_AHCI_PLATFORM is not set
-# CONFIG_SATA_DWC is not set
-# CONFIG_SATA_DWC_OLD_DMA is not set
-# CONFIG_SATA_FSL is not set
-# CONFIG_SATA_HIGHBANK is not set
-# CONFIG_SATA_HOST is not set
-# CONFIG_SATA_INIC162X is not set
-CONFIG_SATA_MOBILE_LPM_POLICY=0
-# CONFIG_SATA_MV is not set
-# CONFIG_SATA_NV is not set
-# CONFIG_SATA_PMP is not set
-# CONFIG_SATA_PROMISE is not set
-# CONFIG_SATA_QSTOR is not set
-# CONFIG_SATA_RCAR is not set
-# CONFIG_SATA_SIL is not set
-# CONFIG_SATA_SIL24 is not set
-# CONFIG_SATA_SIS is not set
-# CONFIG_SATA_SVW is not set
-# CONFIG_SATA_SX4 is not set
-# CONFIG_SATA_ULI is not set
-# CONFIG_SATA_VIA is not set
-# CONFIG_SATA_VITESSE is not set
-# CONFIG_SBC_FITPC2_WATCHDOG is not set
-CONFIG_SBITMAP=y
-# CONFIG_SC92031 is not set
-# CONFIG_SCA3000 is not set
-# CONFIG_SCA3300 is not set
-# CONFIG_SCACHE_DEBUGFS is not set
-# CONFIG_SCC is not set
-# CONFIG_SCD30_CORE is not set
-# CONFIG_SCD4X is not set
-# CONFIG_SCF_TORTURE_TEST is not set
-# CONFIG_SCHEDSTATS is not set
-# CONFIG_SCHED_AUTOGROUP is not set
-# CONFIG_SCHED_CLUSTER is not set
-# CONFIG_SCHED_DEBUG is not set
-CONFIG_SCHED_HRTICK=y
-# CONFIG_SCHED_MC is not set
-CONFIG_SCHED_OMIT_FRAME_POINTER=y
-# CONFIG_SCHED_SMT is not set
-CONFIG_SCHED_STACK_END_CHECK=y
-# CONFIG_SCHED_TRACER is not set
-# CONFIG_SCSI is not set
-# CONFIG_SCSI_3W_9XXX is not set
-# CONFIG_SCSI_3W_SAS is not set
-# CONFIG_SCSI_AACRAID is not set
-# CONFIG_SCSI_ACARD is not set
-# CONFIG_SCSI_ADVANSYS is not set
-# CONFIG_SCSI_AHA152X is not set
-# CONFIG_SCSI_AHA1542 is not set
-# CONFIG_SCSI_AIC79XX is not set
-# CONFIG_SCSI_AIC7XXX is not set
-# CONFIG_SCSI_AIC94XX is not set
-# CONFIG_SCSI_AM53C974 is not set
-# CONFIG_SCSI_ARCMSR is not set
-# CONFIG_SCSI_BFA_FC is not set
-# CONFIG_SCSI_BNX2X_FCOE is not set
-# CONFIG_SCSI_BNX2_ISCSI is not set
-# CONFIG_SCSI_BUSLOGIC is not set
-# CONFIG_SCSI_CHELSIO_FCOE is not set
-# CONFIG_SCSI_CONSTANTS is not set
-# CONFIG_SCSI_CXGB3_ISCSI is not set
-# CONFIG_SCSI_CXGB4_ISCSI is not set
-# CONFIG_SCSI_DC395x is not set
-# CONFIG_SCSI_DEBUG is not set
-# CONFIG_SCSI_DH is not set
-CONFIG_SCSI_DMA=y
-# CONFIG_SCSI_DMX3191D is not set
-# CONFIG_SCSI_ESAS2R is not set
-# CONFIG_SCSI_FC_ATTRS is not set
-# CONFIG_SCSI_FDOMAIN_PCI is not set
-# CONFIG_SCSI_GENERIC_NCR5380 is not set
-# CONFIG_SCSI_HISI_SAS is not set
-# CONFIG_SCSI_HPSA is not set
-# CONFIG_SCSI_HPTIOP is not set
-# CONFIG_SCSI_INIA100 is not set
-# CONFIG_SCSI_INITIO is not set
-# CONFIG_SCSI_IPR is not set
-# CONFIG_SCSI_IPS is not set
-# CONFIG_SCSI_ISCI is not set
-# CONFIG_SCSI_ISCSI_ATTRS is not set
-# CONFIG_SCSI_LOGGING is not set
-CONFIG_SCSI_LOWLEVEL=y
-# CONFIG_SCSI_LOWLEVEL_PCMCIA is not set
-# CONFIG_SCSI_LPFC is not set
-CONFIG_SCSI_MOD=y
-# CONFIG_SCSI_MPI3MR is not set
-# CONFIG_SCSI_MPT2SAS is not set
-# CONFIG_SCSI_MPT3SAS is not set
-# CONFIG_SCSI_MVSAS is not set
-# CONFIG_SCSI_MVSAS_DEBUG is not set
-# CONFIG_SCSI_MVUMI is not set
-# CONFIG_SCSI_MYRB is not set
-# CONFIG_SCSI_MYRS is not set
-# CONFIG_SCSI_NETLINK is not set
-# CONFIG_SCSI_NSP32 is not set
-# CONFIG_SCSI_PM8001 is not set
-# CONFIG_SCSI_PMCRAID is not set
-CONFIG_SCSI_PROC_FS=y
-# CONFIG_SCSI_QLA_FC is not set
-# CONFIG_SCSI_QLA_ISCSI is not set
-# CONFIG_SCSI_QLOGIC_1280 is not set
-# CONFIG_SCSI_QLOGIC_FAS is not set
-# CONFIG_SCSI_SAS_ATTRS is not set
-# CONFIG_SCSI_SAS_LIBSAS is not set
-# CONFIG_SCSI_SCAN_ASYNC is not set
-# CONFIG_SCSI_SMARTPQI is not set
-# CONFIG_SCSI_SNIC is not set
-# CONFIG_SCSI_SPI_ATTRS is not set
-# CONFIG_SCSI_SRP_ATTRS is not set
-# CONFIG_SCSI_STEX is not set
-# CONFIG_SCSI_SYM53C8XX_2 is not set
-# CONFIG_SCSI_UFSHCD is not set
-# CONFIG_SCSI_UFSHCD_PCI is not set
-# CONFIG_SCSI_UFSHCD_PLATFORM is not set
-# CONFIG_SCSI_UFS_BSG is not set
-# CONFIG_SCSI_UFS_CDNS_PLATFORM is not set
-# CONFIG_SCSI_UFS_CRYPTO is not set
-# CONFIG_SCSI_UFS_DWC_TC_PLATFORM is not set
-# CONFIG_SCSI_UFS_EXYNOS is not set
-# CONFIG_SCSI_UFS_FAULT_INJECTION is not set
-# CONFIG_SCSI_UFS_HISI is not set
-# CONFIG_SCSI_UFS_HWMON is not set
-# CONFIG_SCSI_UFS_MEDIATEK is not set
-# CONFIG_SCSI_UFS_QCOM is not set
-# CONFIG_SCSI_UFS_RENESAS is not set
-# CONFIG_SCSI_UFS_SPRD is not set
-# CONFIG_SCSI_UFS_TI_J721E is not set
-# CONFIG_SCSI_VIRTIO is not set
-# CONFIG_SCSI_WD719X is not set
-# CONFIG_SC_CAMCC_7180 is not set
-# CONFIG_SC_DISPCC_7280 is not set
-# CONFIG_SC_GCC_7280 is not set
-# CONFIG_SC_GCC_8180X is not set
-# CONFIG_SC_GPUCC_7280 is not set
-# CONFIG_SC_GPUCC_8280XP is not set
-# CONFIG_SC_VIDEOCC_7280 is not set
-# CONFIG_SCx200_ACB is not set
-# CONFIG_SDIO_UART is not set
-# CONFIG_SDM_GPUCC_660 is not set
-# CONFIG_SDM_MMCC_660 is not set
-# CONFIG_SDR_MAX2175 is not set
-# CONFIG_SDR_PLATFORM_DRIVERS is not set
-# CONFIG_SDX_GCC_55 is not set
-# CONFIG_SD_ADC_MODULATOR is not set
-# CONFIG_SECCOMP is not set
-# CONFIG_SECCOMP_CACHE_DEBUG is not set
-# CONFIG_SECRETMEM is not set
-CONFIG_SECTION_MISMATCH_WARN_ONLY=y
-# CONFIG_SECURITY is not set
-# CONFIG_SECURITYFS is not set
-# CONFIG_SECURITY_APPARMOR is not set
-CONFIG_SECURITY_DMESG_RESTRICT=y
-# CONFIG_SECURITY_LANDLOCK is not set
-# CONFIG_SECURITY_LOADPIN is not set
-# CONFIG_SECURITY_LOCKDOWN_LSM is not set
-# CONFIG_SECURITY_NETWORK_XFRM is not set
-# CONFIG_SECURITY_PATH is not set
-# CONFIG_SECURITY_SAFESETID is not set
-# CONFIG_SECURITY_SELINUX_AVC_STATS is not set
-# CONFIG_SECURITY_SELINUX_BOOTPARAM is not set
-# CONFIG_SECURITY_SELINUX_DEBUG is not set
-# CONFIG_SECURITY_SELINUX_DEVELOP is not set
-# CONFIG_SECURITY_SMACK is not set
-# CONFIG_SECURITY_TOMOYO is not set
-# CONFIG_SECURITY_YAMA is not set
-CONFIG_SELECT_MEMORY_MODEL=y
-# CONFIG_SENSEAIR_SUNRISE_CO2 is not set
-# CONFIG_SENSIRION_SGP30 is not set
-# CONFIG_SENSIRION_SGP40 is not set
-# CONFIG_SENSORS_ABITUGURU is not set
-# CONFIG_SENSORS_ABITUGURU3 is not set
-# CONFIG_SENSORS_ACBEL_FSG032 is not set
-# CONFIG_SENSORS_ACPI_POWER is not set
-# CONFIG_SENSORS_AD7314 is not set
-# CONFIG_SENSORS_AD7414 is not set
-# CONFIG_SENSORS_AD7418 is not set
-# CONFIG_SENSORS_ADC128D818 is not set
-# CONFIG_SENSORS_ADCXX is not set
-# CONFIG_SENSORS_ADM1021 is not set
-# CONFIG_SENSORS_ADM1025 is not set
-# CONFIG_SENSORS_ADM1026 is not set
-# CONFIG_SENSORS_ADM1029 is not set
-# CONFIG_SENSORS_ADM1031 is not set
-# CONFIG_SENSORS_ADM1177 is not set
-# CONFIG_SENSORS_ADM1266 is not set
-# CONFIG_SENSORS_ADM1275 is not set
-# CONFIG_SENSORS_ADM9240 is not set
-# CONFIG_SENSORS_ADS7828 is not set
-# CONFIG_SENSORS_ADS7871 is not set
-# CONFIG_SENSORS_ADT7310 is not set
-# CONFIG_SENSORS_ADT7410 is not set
-# CONFIG_SENSORS_ADT7411 is not set
-# CONFIG_SENSORS_ADT7462 is not set
-# CONFIG_SENSORS_ADT7470 is not set
-# CONFIG_SENSORS_ADT7475 is not set
-# CONFIG_SENSORS_AHT10 is not set
-# CONFIG_SENSORS_AMC6821 is not set
-# CONFIG_SENSORS_APDS990X is not set
-# CONFIG_SENSORS_APPLESMC is not set
-# CONFIG_SENSORS_AQUACOMPUTER_D5NEXT is not set
-# CONFIG_SENSORS_AS370 is not set
-# CONFIG_SENSORS_ASB100 is not set
-# CONFIG_SENSORS_ASC7621 is not set
-# CONFIG_SENSORS_ASPEED is not set
-# CONFIG_SENSORS_ATK0110 is not set
-# CONFIG_SENSORS_ATXP1 is not set
-# CONFIG_SENSORS_AXI_FAN_CONTROL is not set
-# CONFIG_SENSORS_BEL_PFE is not set
-# CONFIG_SENSORS_BH1770 is not set
-# CONFIG_SENSORS_BPA_RS600 is not set
-# CONFIG_SENSORS_CORETEMP is not set
-# CONFIG_SENSORS_CORSAIR_CPRO is not set
-# CONFIG_SENSORS_CORSAIR_PSU is not set
-# CONFIG_SENSORS_DELL_SMM is not set
-# CONFIG_SENSORS_DELTA_AHE50DC_FAN is not set
-# CONFIG_SENSORS_DME1737 is not set
-# CONFIG_SENSORS_DPS920AB is not set
-# CONFIG_SENSORS_DRIVETEMP is not set
-# CONFIG_SENSORS_DS1621 is not set
-# CONFIG_SENSORS_DS620 is not set
-# CONFIG_SENSORS_EMC1403 is not set
-# CONFIG_SENSORS_EMC2103 is not set
-# CONFIG_SENSORS_EMC2305 is not set
-# CONFIG_SENSORS_EMC6W201 is not set
-# CONFIG_SENSORS_F71805F is not set
-# CONFIG_SENSORS_F71882FG is not set
-# CONFIG_SENSORS_F75375S is not set
-# CONFIG_SENSORS_FAM15H_POWER is not set
-# CONFIG_SENSORS_FSCHMD is not set
-# CONFIG_SENSORS_FSP_3Y is not set
-# CONFIG_SENSORS_FTSTEUTATES is not set
-# CONFIG_SENSORS_G760A is not set
-# CONFIG_SENSORS_G762 is not set
-# CONFIG_SENSORS_GL518SM is not set
-# CONFIG_SENSORS_GL520SM is not set
-# CONFIG_SENSORS_GPIO_FAN is not set
-# CONFIG_SENSORS_GSC is not set
-# CONFIG_SENSORS_HDAPS is not set
-# CONFIG_SENSORS_HIH6130 is not set
-# CONFIG_SENSORS_HMC5843 is not set
-# CONFIG_SENSORS_HMC5843_I2C is not set
-# CONFIG_SENSORS_HMC5843_SPI is not set
-# CONFIG_SENSORS_HS3001 is not set
-# CONFIG_SENSORS_I5500 is not set
-# CONFIG_SENSORS_I5K_AMB is not set
-# CONFIG_SENSORS_IBM_CFFPS is not set
-# CONFIG_SENSORS_IIO_HWMON is not set
-# CONFIG_SENSORS_INA209 is not set
-# CONFIG_SENSORS_INA238 is not set
-# CONFIG_SENSORS_INA2XX is not set
-# CONFIG_SENSORS_INA3221 is not set
-# CONFIG_SENSORS_INSPUR_IPSPS is not set
-# CONFIG_SENSORS_IR35221 is not set
-# CONFIG_SENSORS_IR36021 is not set
-# CONFIG_SENSORS_IR38064 is not set
-# CONFIG_SENSORS_IRPS5401 is not set
-# CONFIG_SENSORS_ISL29018 is not set
-# CONFIG_SENSORS_ISL29028 is not set
-# CONFIG_SENSORS_ISL68137 is not set
-# CONFIG_SENSORS_IT87 is not set
-# CONFIG_SENSORS_JC42 is not set
-# CONFIG_SENSORS_K10TEMP is not set
-# CONFIG_SENSORS_K8TEMP is not set
-# CONFIG_SENSORS_LINEAGE is not set
-# CONFIG_SENSORS_LIS3LV02D is not set
-# CONFIG_SENSORS_LIS3_I2C is not set
-# CONFIG_SENSORS_LIS3_SPI is not set
-# CONFIG_SENSORS_LM25066 is not set
-# CONFIG_SENSORS_LM63 is not set
-# CONFIG_SENSORS_LM70 is not set
-# CONFIG_SENSORS_LM73 is not set
-# CONFIG_SENSORS_LM75 is not set
-# CONFIG_SENSORS_LM77 is not set
-# CONFIG_SENSORS_LM78 is not set
-# CONFIG_SENSORS_LM80 is not set
-# CONFIG_SENSORS_LM83 is not set
-# CONFIG_SENSORS_LM85 is not set
-# CONFIG_SENSORS_LM87 is not set
-# CONFIG_SENSORS_LM90 is not set
-# CONFIG_SENSORS_LM92 is not set
-# CONFIG_SENSORS_LM93 is not set
-# CONFIG_SENSORS_LM95234 is not set
-# CONFIG_SENSORS_LM95241 is not set
-# CONFIG_SENSORS_LM95245 is not set
-# CONFIG_SENSORS_LT7182S is not set
-# CONFIG_SENSORS_LTC2945 is not set
-# CONFIG_SENSORS_LTC2947_I2C is not set
-# CONFIG_SENSORS_LTC2947_SPI is not set
-# CONFIG_SENSORS_LTC2978 is not set
-# CONFIG_SENSORS_LTC2990 is not set
-# CONFIG_SENSORS_LTC2992 is not set
-# CONFIG_SENSORS_LTC3815 is not set
-# CONFIG_SENSORS_LTC4151 is not set
-# CONFIG_SENSORS_LTC4215 is not set
-# CONFIG_SENSORS_LTC4222 is not set
-# CONFIG_SENSORS_LTC4245 is not set
-# CONFIG_SENSORS_LTC4260 is not set
-# CONFIG_SENSORS_LTC4261 is not set
-# CONFIG_SENSORS_LTQ_CPUTEMP is not set
-# CONFIG_SENSORS_MAX1111 is not set
-# CONFIG_SENSORS_MAX127 is not set
-# CONFIG_SENSORS_MAX15301 is not set
-# CONFIG_SENSORS_MAX16064 is not set
-# CONFIG_SENSORS_MAX16065 is not set
-# CONFIG_SENSORS_MAX1619 is not set
-# CONFIG_SENSORS_MAX16601 is not set
-# CONFIG_SENSORS_MAX1668 is not set
-# CONFIG_SENSORS_MAX197 is not set
-# CONFIG_SENSORS_MAX20730 is not set
-# CONFIG_SENSORS_MAX20751 is not set
-# CONFIG_SENSORS_MAX31722 is not set
-# CONFIG_SENSORS_MAX31730 is not set
-# CONFIG_SENSORS_MAX31760 is not set
-# CONFIG_SENSORS_MAX31785 is not set
-# CONFIG_SENSORS_MAX31790 is not set
-# CONFIG_SENSORS_MAX34440 is not set
-# CONFIG_SENSORS_MAX6620 is not set
-# CONFIG_SENSORS_MAX6621 is not set
-# CONFIG_SENSORS_MAX6639 is not set
-# CONFIG_SENSORS_MAX6642 is not set
-# CONFIG_SENSORS_MAX6650 is not set
-# CONFIG_SENSORS_MAX6697 is not set
-# CONFIG_SENSORS_MAX8688 is not set
-# CONFIG_SENSORS_MC34VR500 is not set
-# CONFIG_SENSORS_MCP3021 is not set
-# CONFIG_SENSORS_MP2888 is not set
-# CONFIG_SENSORS_MP2975 is not set
-# CONFIG_SENSORS_MP5023 is not set
-# CONFIG_SENSORS_MPQ7932 is not set
-# CONFIG_SENSORS_MR75203 is not set
-# CONFIG_SENSORS_NCT6683 is not set
-# CONFIG_SENSORS_NCT6775 is not set
-# CONFIG_SENSORS_NCT6775_I2C is not set
-# CONFIG_SENSORS_NCT7802 is not set
-# CONFIG_SENSORS_NCT7904 is not set
-# CONFIG_SENSORS_NPCM7XX is not set
-# CONFIG_SENSORS_NSA320 is not set
-# CONFIG_SENSORS_NTC_THERMISTOR is not set
-# CONFIG_SENSORS_NZXT_KRAKEN2 is not set
-# CONFIG_SENSORS_NZXT_SMART2 is not set
-# CONFIG_SENSORS_OCC_P8_I2C is not set
-# CONFIG_SENSORS_PC87360 is not set
-# CONFIG_SENSORS_PC87427 is not set
-# CONFIG_SENSORS_PCF8591 is not set
-# CONFIG_SENSORS_PIM4328 is not set
-# CONFIG_SENSORS_PLI1209BC is not set
-# CONFIG_SENSORS_PM6764TR is not set
-# CONFIG_SENSORS_PMBUS is not set
-# CONFIG_SENSORS_POWR1220 is not set
-# CONFIG_SENSORS_PWM_FAN is not set
-# CONFIG_SENSORS_PXE1610 is not set
-# CONFIG_SENSORS_Q54SJ108A2 is not set
-# CONFIG_SENSORS_RM3100_I2C is not set
-# CONFIG_SENSORS_RM3100_SPI is not set
-# CONFIG_SENSORS_SBRMI is not set
-# CONFIG_SENSORS_SBTSI is not set
-# CONFIG_SENSORS_SCH5627 is not set
-# CONFIG_SENSORS_SCH5636 is not set
-# CONFIG_SENSORS_SCH56XX_COMMON is not set
-# CONFIG_SENSORS_SHT15 is not set
-# CONFIG_SENSORS_SHT21 is not set
-# CONFIG_SENSORS_SHT3x is not set
-# CONFIG_SENSORS_SHT4x is not set
-# CONFIG_SENSORS_SHTC1 is not set
-# CONFIG_SENSORS_SIS5595 is not set
-# CONFIG_SENSORS_SMSC47B397 is not set
-# CONFIG_SENSORS_SMSC47M1 is not set
-# CONFIG_SENSORS_SMSC47M192 is not set
-# CONFIG_SENSORS_STPDDC60 is not set
-# CONFIG_SENSORS_STTS751 is not set
-# CONFIG_SENSORS_TC654 is not set
-# CONFIG_SENSORS_TC74 is not set
-# CONFIG_SENSORS_TDA38640 is not set
-# CONFIG_SENSORS_THMC50 is not set
-# CONFIG_SENSORS_TMP102 is not set
-# CONFIG_SENSORS_TMP103 is not set
-# CONFIG_SENSORS_TMP108 is not set
-# CONFIG_SENSORS_TMP401 is not set
-# CONFIG_SENSORS_TMP421 is not set
-# CONFIG_SENSORS_TMP464 is not set
-# CONFIG_SENSORS_TMP513 is not set
-# CONFIG_SENSORS_TPS23861 is not set
-# CONFIG_SENSORS_TPS40422 is not set
-# CONFIG_SENSORS_TPS53679 is not set
-# CONFIG_SENSORS_TPS546D24 is not set
-# CONFIG_SENSORS_TSL2550 is not set
-# CONFIG_SENSORS_TSL2563 is not set
-# CONFIG_SENSORS_UCD9000 is not set
-# CONFIG_SENSORS_UCD9200 is not set
-# CONFIG_SENSORS_VEXPRESS is not set
-# CONFIG_SENSORS_VIA686A is not set
-# CONFIG_SENSORS_VIA_CPUTEMP is not set
-# CONFIG_SENSORS_VT1211 is not set
-# CONFIG_SENSORS_VT8231 is not set
-# CONFIG_SENSORS_W83627EHF is not set
-# CONFIG_SENSORS_W83627HF is not set
-# CONFIG_SENSORS_W83773G is not set
-# CONFIG_SENSORS_W83781D is not set
-# CONFIG_SENSORS_W83791D is not set
-# CONFIG_SENSORS_W83792D is not set
-# CONFIG_SENSORS_W83793 is not set
-# CONFIG_SENSORS_W83795 is not set
-# CONFIG_SENSORS_W83L785TS is not set
-# CONFIG_SENSORS_W83L786NG is not set
-# CONFIG_SENSORS_XDPE122 is not set
-# CONFIG_SENSORS_XDPE152 is not set
-# CONFIG_SENSORS_XGENE is not set
-# CONFIG_SENSORS_ZL6100 is not set
-CONFIG_SERIAL_8250=y
-CONFIG_SERIAL_8250_16550A_VARIANTS=y
-# CONFIG_SERIAL_8250_ACCENT is not set
-# CONFIG_SERIAL_8250_ASPEED_VUART is not set
-# CONFIG_SERIAL_8250_BOCA is not set
-CONFIG_SERIAL_8250_CONSOLE=y
-# CONFIG_SERIAL_8250_CS is not set
-# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set
-# CONFIG_SERIAL_8250_DETECT_IRQ is not set
-CONFIG_SERIAL_8250_DMA=y
-# CONFIG_SERIAL_8250_DW is not set
-# CONFIG_SERIAL_8250_EM is not set
-# CONFIG_SERIAL_8250_EXAR is not set
-# CONFIG_SERIAL_8250_EXAR_ST16C554 is not set
-# CONFIG_SERIAL_8250_EXTENDED is not set
-# CONFIG_SERIAL_8250_FINTEK is not set
-# CONFIG_SERIAL_8250_FOURPORT is not set
-# CONFIG_SERIAL_8250_HUB6 is not set
-# CONFIG_SERIAL_8250_INGENIC is not set
-# CONFIG_SERIAL_8250_LPSS is not set
-# CONFIG_SERIAL_8250_MANY_PORTS is not set
-# CONFIG_SERIAL_8250_MID is not set
-CONFIG_SERIAL_8250_NR_UARTS=2
-# CONFIG_SERIAL_8250_PCI is not set
-# CONFIG_SERIAL_8250_PCI1XXXX is not set
-# CONFIG_SERIAL_8250_PERICOM is not set
-# CONFIG_SERIAL_8250_RSA is not set
-# CONFIG_SERIAL_8250_RT288X is not set
-CONFIG_SERIAL_8250_RUNTIME_UARTS=2
-# CONFIG_SERIAL_ALTERA_JTAGUART is not set
-# CONFIG_SERIAL_ALTERA_UART is not set
-# CONFIG_SERIAL_AMBA_PL010 is not set
-# CONFIG_SERIAL_AMBA_PL011 is not set
-# CONFIG_SERIAL_ARC is not set
-# CONFIG_SERIAL_BCM63XX is not set
-# CONFIG_SERIAL_CONEXANT_DIGICOLOR is not set
-CONFIG_SERIAL_CORE=y
-CONFIG_SERIAL_CORE_CONSOLE=y
-# CONFIG_SERIAL_DEV_BUS is not set
-CONFIG_SERIAL_EARLYCON=y
-# CONFIG_SERIAL_EARLYCON_SEMIHOST is not set
-# CONFIG_SERIAL_FSL_LINFLEXUART is not set
-# CONFIG_SERIAL_FSL_LPUART is not set
-# CONFIG_SERIAL_GRLIB_GAISLER_APBUART is not set
-# CONFIG_SERIAL_JSM is not set
-# CONFIG_SERIAL_MAX3100 is not set
-# CONFIG_SERIAL_MAX310X is not set
-# CONFIG_SERIAL_NONSTANDARD is not set
-# CONFIG_SERIAL_OF_PLATFORM is not set
-# CONFIG_SERIAL_PCH_UART is not set
-# CONFIG_SERIAL_RP2 is not set
-# CONFIG_SERIAL_SC16IS7XX is not set
-# CONFIG_SERIAL_SCCNXP is not set
-# CONFIG_SERIAL_SH_SCI is not set
-# CONFIG_SERIAL_SIFIVE is not set
-# CONFIG_SERIAL_SPRD is not set
-# CONFIG_SERIAL_STM32 is not set
-# CONFIG_SERIAL_ST_ASC is not set
-# CONFIG_SERIAL_TIMBERDALE is not set
-# CONFIG_SERIAL_UARTLITE is not set
-# CONFIG_SERIAL_XILINX_PS_UART is not set
-# CONFIG_SERIO is not set
-# CONFIG_SERIO_ALTERA_PS2 is not set
-# CONFIG_SERIO_AMBAKMI is not set
-# CONFIG_SERIO_APBPS2 is not set
-# CONFIG_SERIO_ARC_PS2 is not set
-# CONFIG_SERIO_CT82C710 is not set
-# CONFIG_SERIO_GPIO_PS2 is not set
-# CONFIG_SERIO_I8042 is not set
-# CONFIG_SERIO_LIBPS2 is not set
-# CONFIG_SERIO_PARKBD is not set
-# CONFIG_SERIO_PCIPS2 is not set
-# CONFIG_SERIO_PS2MULT is not set
-# CONFIG_SERIO_RAW is not set
-# CONFIG_SERIO_SERPORT is not set
-# CONFIG_SERIO_SUN4I_PS2 is not set
-# CONFIG_SERIO_XILINX_XPS_PS2 is not set
-# CONFIG_SFC is not set
-# CONFIG_SFC_FALCON is not set
-# CONFIG_SFC_SIENA is not set
-# CONFIG_SFP is not set
-# CONFIG_SF_PDMA is not set
-# CONFIG_SGETMASK_SYSCALL is not set
-# CONFIG_SGI_IP22 is not set
-# CONFIG_SGI_IP27 is not set
-# CONFIG_SGI_IP28 is not set
-# CONFIG_SGI_IP30 is not set
-# CONFIG_SGI_IP32 is not set
-# CONFIG_SGI_MFD_IOC3 is not set
-# CONFIG_SGI_PARTITION is not set
-# CONFIG_SG_POOL is not set
-# CONFIG_SG_SPLIT is not set
-# CONFIG_SHADOW_CALL_STACK is not set
-CONFIG_SHMEM=y
-# CONFIG_SHRINKER_DEBUG is not set
-# CONFIG_SHUFFLE_PAGE_ALLOCATOR is not set
-# CONFIG_SH_ETH is not set
-# CONFIG_SH_TIMER_CMT is not set
-# CONFIG_SH_TIMER_MTU2 is not set
-# CONFIG_SH_TIMER_TMU is not set
-# CONFIG_SI1133 is not set
-# CONFIG_SI1145 is not set
-# CONFIG_SI7005 is not set
-# CONFIG_SI7020 is not set
-# CONFIG_SIBYTE_BIGSUR is not set
-# CONFIG_SIBYTE_CRHONE is not set
-# CONFIG_SIBYTE_LITTLESUR is not set
-# CONFIG_SIBYTE_RHONE is not set
-# CONFIG_SIBYTE_SENTOSA is not set
-# CONFIG_SIBYTE_SWARM is not set
-CONFIG_SIGNALFD=y
-# CONFIG_SIGNED_PE_FILE_VERIFICATION is not set
-# CONFIG_SIOX is not set
-# CONFIG_SIS190 is not set
-# CONFIG_SIS900 is not set
-# CONFIG_SKGE is not set
-# CONFIG_SKY2 is not set
-# CONFIG_SKY2_DEBUG is not set
-# CONFIG_SLAB_DEPRECATED is not set
-CONFIG_SLAB_FREELIST_HARDENED=y
-CONFIG_SLAB_FREELIST_RANDOM=y
-CONFIG_SLAB_MERGE_DEFAULT=y
-# CONFIG_SLHC is not set
-# CONFIG_SLICOSS is not set
-# CONFIG_SLIMBUS is not set
-# CONFIG_SLIP is not set
-CONFIG_SLUB=y
-CONFIG_SLUB_CPU_PARTIAL=y
-# CONFIG_SLUB_DEBUG is not set
-# CONFIG_SLUB_DEBUG_ON is not set
-# CONFIG_SLUB_STATS is not set
-# CONFIG_SLUB_TINY is not set
-# CONFIG_SMARTJOYPLUS_FF is not set
-# CONFIG_SMB_SERVER is not set
-# CONFIG_SMC9194 is not set
-# CONFIG_SMC91X is not set
-# CONFIG_SMP is not set
-# CONFIG_SMSC911X is not set
-# CONFIG_SMSC9420 is not set
-# CONFIG_SMSC_PHY is not set
-# CONFIG_SMS_SDIO_DRV is not set
-# CONFIG_SMS_USB_DRV is not set
-# CONFIG_SM_CAMCC_8250 is not set
-# CONFIG_SM_FTL is not set
-# CONFIG_SM_GCC_6115 is not set
-# CONFIG_SM_GCC_6125 is not set
-# CONFIG_SM_GCC_6350 is not set
-# CONFIG_SM_GCC_6375 is not set
-# CONFIG_SM_GCC_8350 is not set
-# CONFIG_SND is not set
-# CONFIG_SND_AC97_POWER_SAVE is not set
-# CONFIG_SND_AD1816A is not set
-# CONFIG_SND_AD1848 is not set
-# CONFIG_SND_AD1889 is not set
-# CONFIG_SND_ADLIB is not set
-# CONFIG_SND_ALI5451 is not set
-# CONFIG_SND_ALOOP is not set
-# CONFIG_SND_ALS100 is not set
-# CONFIG_SND_ALS300 is not set
-# CONFIG_SND_ALS4000 is not set
-# CONFIG_SND_AMD_ACP_CONFIG is not set
-# CONFIG_SND_ARM is not set
-# CONFIG_SND_ASIHPI is not set
-# CONFIG_SND_ATIIXP is not set
-# CONFIG_SND_ATIIXP_MODEM is not set
-# CONFIG_SND_ATMEL_AC97C is not set
-# CONFIG_SND_ATMEL_SOC is not set
-# CONFIG_SND_AU8810 is not set
-# CONFIG_SND_AU8820 is not set
-# CONFIG_SND_AU8830 is not set
-# CONFIG_SND_AUDIO_GRAPH_CARD is not set
-# CONFIG_SND_AUDIO_GRAPH_CARD2 is not set
-# CONFIG_SND_AW2 is not set
-# CONFIG_SND_AZT2320 is not set
-# CONFIG_SND_AZT3328 is not set
-# CONFIG_SND_BCD2000 is not set
-# CONFIG_SND_BCM2835 is not set
-# CONFIG_SND_BCM63XX_I2S_WHISTLER is not set
-# CONFIG_SND_BT87X is not set
-# CONFIG_SND_CA0106 is not set
-# CONFIG_SND_CMI8330 is not set
-# CONFIG_SND_CMIPCI is not set
-# CONFIG_SND_CS4231 is not set
-# CONFIG_SND_CS4236 is not set
-# CONFIG_SND_CS4281 is not set
-# CONFIG_SND_CS46XX is not set
-# CONFIG_SND_CS5530 is not set
-# CONFIG_SND_CS5535AUDIO is not set
-# CONFIG_SND_CTL_FAST_LOOKUP is not set
-# CONFIG_SND_CTL_INPUT_VALIDATION is not set
-# CONFIG_SND_CTXFI is not set
-# CONFIG_SND_DARLA20 is not set
-# CONFIG_SND_DARLA24 is not set
-# CONFIG_SND_DEBUG is not set
-# CONFIG_SND_DESIGNWARE_I2S is not set
-CONFIG_SND_DRIVERS=y
-# CONFIG_SND_DUMMY is not set
-# CONFIG_SND_DYNAMIC_MINORS is not set
-# CONFIG_SND_ECHO3G is not set
-# CONFIG_SND_EMU10K1 is not set
-# CONFIG_SND_EMU10K1X is not set
-# CONFIG_SND_EMU10K1_SEQ is not set
-# CONFIG_SND_ENS1370 is not set
-# CONFIG_SND_ENS1371 is not set
-# CONFIG_SND_ES1688 is not set
-# CONFIG_SND_ES18XX is not set
-# CONFIG_SND_ES1938 is not set
-# CONFIG_SND_ES1968 is not set
-# CONFIG_SND_FIREWIRE is not set
-# CONFIG_SND_FM801 is not set
-# CONFIG_SND_GINA20 is not set
-# CONFIG_SND_GINA24 is not set
-# CONFIG_SND_GUSCLASSIC is not set
-# CONFIG_SND_GUSEXTREME is not set
-# CONFIG_SND_GUSMAX is not set
-# CONFIG_SND_HDA_CODEC_CS8409 is not set
-# CONFIG_SND_HDA_INTEL is not set
-# CONFIG_SND_HDA_INTEL_HDMI_SILENT_STREAM is not set
-CONFIG_SND_HDA_POWER_SAVE_DEFAULT=0
-CONFIG_SND_HDA_PREALLOC_SIZE=64
-# CONFIG_SND_HDSP is not set
-# CONFIG_SND_HDSPM is not set
-# CONFIG_SND_HRTIMER is not set
-# CONFIG_SND_HWDEP is not set
-# CONFIG_SND_I2S_HI6210_I2S is not set
-# CONFIG_SND_ICE1712 is not set
-# CONFIG_SND_ICE1724 is not set
-# CONFIG_SND_INDIGO is not set
-# CONFIG_SND_INDIGODJ is not set
-# CONFIG_SND_INDIGODJX is not set
-# CONFIG_SND_INDIGOIO is not set
-# CONFIG_SND_INDIGOIOX is not set
-# CONFIG_SND_INTEL8X0 is not set
-# CONFIG_SND_INTEL8X0M is not set
-# CONFIG_SND_INTERWAVE is not set
-# CONFIG_SND_INTERWAVE_STB is not set
-# CONFIG_SND_ISA is not set
-# CONFIG_SND_JZ4740_SOC_I2S is not set
-# CONFIG_SND_KIRKWOOD_SOC is not set
-# CONFIG_SND_KORG1212 is not set
-# CONFIG_SND_LAYLA20 is not set
-# CONFIG_SND_LAYLA24 is not set
-# CONFIG_SND_LOLA is not set
-# CONFIG_SND_LX6464ES is not set
-# CONFIG_SND_MAESTRO3 is not set
-CONFIG_SND_MAX_CARDS=16
-# CONFIG_SND_MIA is not set
-# CONFIG_SND_MIPS is not set
-# CONFIG_SND_MIRO is not set
-# CONFIG_SND_MIXART is not set
-# CONFIG_SND_MIXER_OSS is not set
-# CONFIG_SND_MONA is not set
-# CONFIG_SND_MPC52xx_SOC_EFIKA is not set
-# CONFIG_SND_MPU401 is not set
-# CONFIG_SND_MTPAV is not set
-# CONFIG_SND_MTS64 is not set
-# CONFIG_SND_MXS_SOC is not set
-# CONFIG_SND_NM256 is not set
-# CONFIG_SND_OPL3SA2 is not set
-# CONFIG_SND_OPL3_LIB_SEQ is not set
-# CONFIG_SND_OPL4_LIB_SEQ is not set
-# CONFIG_SND_OPTI92X_AD1848 is not set
-# CONFIG_SND_OPTI92X_CS4231 is not set
-# CONFIG_SND_OPTI93X is not set
-CONFIG_SND_OSSEMUL=y
-# CONFIG_SND_OXYGEN is not set
-CONFIG_SND_PCI=y
-# CONFIG_SND_PCM is not set
-# CONFIG_SND_PCMCIA is not set
-# CONFIG_SND_PCMTEST is not set
-# CONFIG_SND_PCM_OSS is not set
-CONFIG_SND_PCM_OSS_PLUGINS=y
-# CONFIG_SND_PCM_TIMER is not set
-# CONFIG_SND_PCM_XRUN_DEBUG is not set
-# CONFIG_SND_PCXHR is not set
-# CONFIG_SND_PDAUDIOCF is not set
-# CONFIG_SND_PORTMAN2X4 is not set
-# CONFIG_SND_POWERPC_SOC is not set
-# CONFIG_SND_PPC is not set
-CONFIG_SND_PROC_FS=y
-# CONFIG_SND_RAWMIDI is not set
-# CONFIG_SND_RIPTIDE is not set
-# CONFIG_SND_RME32 is not set
-# CONFIG_SND_RME96 is not set
-# CONFIG_SND_RME9652 is not set
-# CONFIG_SND_SB16 is not set
-# CONFIG_SND_SB8 is not set
-# CONFIG_SND_SBAWE is not set
-# CONFIG_SND_SBAWE_SEQ is not set
-# CONFIG_SND_SE6X is not set
-# CONFIG_SND_SEQUENCER is not set
-# CONFIG_SND_SEQ_UMP is not set
-# CONFIG_SND_SERIAL_GENERIC is not set
-# CONFIG_SND_SERIAL_U16550 is not set
-# CONFIG_SND_SIMPLE_CARD is not set
-# CONFIG_SND_SIS7019 is not set
-# CONFIG_SND_SOC is not set
-# CONFIG_SND_SOC_AC97_CODEC is not set
-# CONFIG_SND_SOC_AD193X_I2C is not set
-# CONFIG_SND_SOC_AD193X_SPI is not set
-# CONFIG_SND_SOC_ADAU1372_I2C is not set
-# CONFIG_SND_SOC_ADAU1372_SPI is not set
-# CONFIG_SND_SOC_ADAU1701 is not set
-# CONFIG_SND_SOC_ADAU1761_I2C is not set
-# CONFIG_SND_SOC_ADAU1761_SPI is not set
-# CONFIG_SND_SOC_ADAU7002 is not set
-# CONFIG_SND_SOC_ADAU7118_HW is not set
-# CONFIG_SND_SOC_ADAU7118_I2C is not set
-# CONFIG_SND_SOC_ADI is not set
-# CONFIG_SND_SOC_AK4104 is not set
-# CONFIG_SND_SOC_AK4118 is not set
-# CONFIG_SND_SOC_AK4375 is not set
-# CONFIG_SND_SOC_AK4458 is not set
-# CONFIG_SND_SOC_AK4554 is not set
-# CONFIG_SND_SOC_AK4613 is not set
-# CONFIG_SND_SOC_AK4642 is not set
-# CONFIG_SND_SOC_AK5386 is not set
-# CONFIG_SND_SOC_AK5558 is not set
-# CONFIG_SND_SOC_ALC5623 is not set
-# CONFIG_SND_SOC_AMD_ACP is not set
-# CONFIG_SND_SOC_AMD_ACP3x is not set
-# CONFIG_SND_SOC_AMD_ACP5x is not set
-# CONFIG_SND_SOC_AMD_RENOIR is not set
-# CONFIG_SND_SOC_AU1XAUDIO is not set
-# CONFIG_SND_SOC_AU1XPSC is not set
-# CONFIG_SND_SOC_AUDIO_IIO_AUX is not set
-# CONFIG_SND_SOC_AW8738 is not set
-# CONFIG_SND_SOC_AW88261 is not set
-# CONFIG_SND_SOC_AW88395 is not set
-# CONFIG_SND_SOC_BD28623 is not set
-# CONFIG_SND_SOC_BT_SCO is not set
-# CONFIG_SND_SOC_CHV3_CODEC is not set
-# CONFIG_SND_SOC_CHV3_I2S is not set
-# CONFIG_SND_SOC_CS35L32 is not set
-# CONFIG_SND_SOC_CS35L33 is not set
-# CONFIG_SND_SOC_CS35L34 is not set
-# CONFIG_SND_SOC_CS35L35 is not set
-# CONFIG_SND_SOC_CS35L36 is not set
-# CONFIG_SND_SOC_CS35L41_I2C is not set
-# CONFIG_SND_SOC_CS35L41_SPI is not set
-# CONFIG_SND_SOC_CS35L45_I2C is not set
-# CONFIG_SND_SOC_CS35L45_SPI is not set
-# CONFIG_SND_SOC_CS35L56_I2C is not set
-# CONFIG_SND_SOC_CS35L56_SPI is not set
-# CONFIG_SND_SOC_CS4234 is not set
-# CONFIG_SND_SOC_CS4265 is not set
-# CONFIG_SND_SOC_CS4270 is not set
-# CONFIG_SND_SOC_CS4271 is not set
-# CONFIG_SND_SOC_CS4271_I2C is not set
-# CONFIG_SND_SOC_CS4271_SPI is not set
-# CONFIG_SND_SOC_CS42L42 is not set
-# CONFIG_SND_SOC_CS42L51_I2C is not set
-# CONFIG_SND_SOC_CS42L52 is not set
-# CONFIG_SND_SOC_CS42L56 is not set
-# CONFIG_SND_SOC_CS42L73 is not set
-# CONFIG_SND_SOC_CS42L83 is not set
-# CONFIG_SND_SOC_CS42XX8_I2C is not set
-# CONFIG_SND_SOC_CS43130 is not set
-# CONFIG_SND_SOC_CS4341 is not set
-# CONFIG_SND_SOC_CS4349 is not set
-# CONFIG_SND_SOC_CS53L30 is not set
-# CONFIG_SND_SOC_CX2072X is not set
-# CONFIG_SND_SOC_DA7213 is not set
-# CONFIG_SND_SOC_DMIC is not set
-# CONFIG_SND_SOC_ES7134 is not set
-# CONFIG_SND_SOC_ES7241 is not set
-# CONFIG_SND_SOC_ES8316 is not set
-# CONFIG_SND_SOC_ES8326 is not set
-# CONFIG_SND_SOC_ES8328 is not set
-# CONFIG_SND_SOC_ES8328_I2C is not set
-# CONFIG_SND_SOC_ES8328_SPI is not set
-# CONFIG_SND_SOC_EUKREA_TLV320 is not set
-# CONFIG_SND_SOC_FSL_ASOC_CARD is not set
-# CONFIG_SND_SOC_FSL_ASRC is not set
-# CONFIG_SND_SOC_FSL_AUD2HTX is not set
-# CONFIG_SND_SOC_FSL_AUDMIX is not set
-# CONFIG_SND_SOC_FSL_ESAI is not set
-# CONFIG_SND_SOC_FSL_MICFIL is not set
-# CONFIG_SND_SOC_FSL_RPMSG is not set
-# CONFIG_SND_SOC_FSL_SAI is not set
-# CONFIG_SND_SOC_FSL_SPDIF is not set
-# CONFIG_SND_SOC_FSL_SSI is not set
-# CONFIG_SND_SOC_FSL_XCVR is not set
-# CONFIG_SND_SOC_GTM601 is not set
-# CONFIG_SND_SOC_HDA is not set
-# CONFIG_SND_SOC_ICS43432 is not set
-# CONFIG_SND_SOC_IDT821034 is not set
-# CONFIG_SND_SOC_IMG is not set
-# CONFIG_SND_SOC_IMX_AUDMIX is not set
-# CONFIG_SND_SOC_IMX_AUDMUX is not set
-# CONFIG_SND_SOC_IMX_CARD is not set
-# CONFIG_SND_SOC_IMX_ES8328 is not set
-# CONFIG_SND_SOC_IMX_HDMI is not set
-# CONFIG_SND_SOC_IMX_RPMSG is not set
-# CONFIG_SND_SOC_IMX_SPDIF is not set
-# CONFIG_SND_SOC_INNO_RK3036 is not set
-# CONFIG_SND_SOC_INTEL_APL is not set
-# CONFIG_SND_SOC_INTEL_BDW_RT5677_MACH is not set
-# CONFIG_SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH is not set
-# CONFIG_SND_SOC_INTEL_BXT_RT298_MACH is not set
-# CONFIG_SND_SOC_INTEL_BYTCR_RT5640_MACH is not set
-# CONFIG_SND_SOC_INTEL_BYTCR_RT5651_MACH is not set
-# CONFIG_SND_SOC_INTEL_BYT_CHT_DA7213_MACH is not set
-# CONFIG_SND_SOC_INTEL_BYT_CHT_ES8316_MACH is not set
-# CONFIG_SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH is not set
-# CONFIG_SND_SOC_INTEL_CATPT is not set
-# CONFIG_SND_SOC_INTEL_CFL is not set
-# CONFIG_SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH is not set
-# CONFIG_SND_SOC_INTEL_CHT_BSW_NAU8824_MACH is not set
-# CONFIG_SND_SOC_INTEL_CHT_BSW_RT5645_MACH is not set
-# CONFIG_SND_SOC_INTEL_CHT_BSW_RT5672_MACH is not set
-# CONFIG_SND_SOC_INTEL_CML_H is not set
-# CONFIG_SND_SOC_INTEL_CML_LP is not set
-# CONFIG_SND_SOC_INTEL_CNL is not set
-# CONFIG_SND_SOC_INTEL_GLK is not set
-# CONFIG_SND_SOC_INTEL_HASWELL is not set
-# CONFIG_SND_SOC_INTEL_KBL is not set
-# CONFIG_SND_SOC_INTEL_KBL_RT5663_MAX98927_MACH is not set
-# CONFIG_SND_SOC_INTEL_KBL_RT5663_RT5514_MAX98927_MACH is not set
-# CONFIG_SND_SOC_INTEL_KEEMBAY is not set
-# CONFIG_SND_SOC_INTEL_SKL is not set
-# CONFIG_SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH is not set
-# CONFIG_SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH is not set
-# CONFIG_SND_SOC_INTEL_SKL_RT286_MACH is not set
-# CONFIG_SND_SOC_INTEL_SKYLAKE is not set
-# CONFIG_SND_SOC_INTEL_SST is not set
-CONFIG_SND_SOC_INTEL_SST_TOPLEVEL=y
-# CONFIG_SND_SOC_INTEL_USER_FRIENDLY_LONG_NAMES is not set
-# CONFIG_SND_SOC_JZ4725B_CODEC is not set
-# CONFIG_SND_SOC_JZ4740_CODEC is not set
-# CONFIG_SND_SOC_JZ4770_CODEC is not set
-# CONFIG_SND_SOC_LOONGSON_CARD is not set
-# CONFIG_SND_SOC_LOONGSON_I2S_PCI is not set
-# CONFIG_SND_SOC_LPASS_RX_MACRO is not set
-# CONFIG_SND_SOC_LPASS_TX_MACRO is not set
-# CONFIG_SND_SOC_LPASS_VA_MACRO is not set
-# CONFIG_SND_SOC_LPASS_WSA_MACRO is not set
-# CONFIG_SND_SOC_MAX9759 is not set
-# CONFIG_SND_SOC_MAX98088 is not set
-# CONFIG_SND_SOC_MAX98090 is not set
-# CONFIG_SND_SOC_MAX98357A is not set
-# CONFIG_SND_SOC_MAX98373 is not set
-# CONFIG_SND_SOC_MAX98373_I2C is not set
-# CONFIG_SND_SOC_MAX98388 is not set
-# CONFIG_SND_SOC_MAX98390 is not set
-# CONFIG_SND_SOC_MAX98396 is not set
-# CONFIG_SND_SOC_MAX98504 is not set
-# CONFIG_SND_SOC_MAX98520 is not set
-# CONFIG_SND_SOC_MAX9860 is not set
-# CONFIG_SND_SOC_MAX9867 is not set
-# CONFIG_SND_SOC_MAX98927 is not set
-# CONFIG_SND_SOC_MEDIATEK is not set
-# CONFIG_SND_SOC_MPC5200_AC97 is not set
-# CONFIG_SND_SOC_MPC5200_I2S is not set
-# CONFIG_SND_SOC_MSM8916_WCD_ANALOG is not set
-# CONFIG_SND_SOC_MSM8916_WCD_DIGITAL is not set
-# CONFIG_SND_SOC_MT2701 is not set
-# CONFIG_SND_SOC_MT6351 is not set
-# CONFIG_SND_SOC_MT6358 is not set
-# CONFIG_SND_SOC_MT6359 is not set
-# CONFIG_SND_SOC_MT6359_ACCDET is not set
-# CONFIG_SND_SOC_MT6660 is not set
-# CONFIG_SND_SOC_MT6797 is not set
-# CONFIG_SND_SOC_MT8173 is not set
-# CONFIG_SND_SOC_MT8183 is not set
-# CONFIG_SND_SOC_MT8186 is not set
-# CONFIG_SND_SOC_MT8188 is not set
-# CONFIG_SND_SOC_MT8192 is not set
-# CONFIG_SND_SOC_MT8195 is not set
-# CONFIG_SND_SOC_MTK_BTCVSD is not set
-# CONFIG_SND_SOC_NAU8315 is not set
-# CONFIG_SND_SOC_NAU8540 is not set
-# CONFIG_SND_SOC_NAU8810 is not set
-# CONFIG_SND_SOC_NAU8821 is not set
-# CONFIG_SND_SOC_NAU8822 is not set
-# CONFIG_SND_SOC_NAU8824 is not set
-# CONFIG_SND_SOC_PCM1681 is not set
-# CONFIG_SND_SOC_PCM1789_I2C is not set
-# CONFIG_SND_SOC_PCM179X_I2C is not set
-# CONFIG_SND_SOC_PCM179X_SPI is not set
-# CONFIG_SND_SOC_PCM186X_I2C is not set
-# CONFIG_SND_SOC_PCM186X_SPI is not set
-# CONFIG_SND_SOC_PCM3060_I2C is not set
-# CONFIG_SND_SOC_PCM3060_SPI is not set
-# CONFIG_SND_SOC_PCM3168A_I2C is not set
-# CONFIG_SND_SOC_PCM3168A_SPI is not set
-# CONFIG_SND_SOC_PCM5102A is not set
-# CONFIG_SND_SOC_PCM512x_I2C is not set
-# CONFIG_SND_SOC_PCM512x_SPI is not set
-# CONFIG_SND_SOC_PEB2466 is not set
-# CONFIG_SND_SOC_QCOM is not set
-# CONFIG_SND_SOC_RK3328 is not set
-# CONFIG_SND_SOC_RK817 is not set
-# CONFIG_SND_SOC_ROCKCHIP is not set
-# CONFIG_SND_SOC_RT5616 is not set
-# CONFIG_SND_SOC_RT5631 is not set
-# CONFIG_SND_SOC_RT5640 is not set
-# CONFIG_SND_SOC_RT5659 is not set
-# CONFIG_SND_SOC_RT5677_SPI is not set
-# CONFIG_SND_SOC_RT9120 is not set
-# CONFIG_SND_SOC_SGTL5000 is not set
-# CONFIG_SND_SOC_SIMPLE_AMPLIFIER is not set
-# CONFIG_SND_SOC_SIMPLE_MUX is not set
-# CONFIG_SND_SOC_SMA1303 is not set
-# CONFIG_SND_SOC_SOF_TOPLEVEL is not set
-# CONFIG_SND_SOC_SPDIF is not set
-# CONFIG_SND_SOC_SRC4XXX_I2C is not set
-# CONFIG_SND_SOC_SSM2305 is not set
-# CONFIG_SND_SOC_SSM2518 is not set
-# CONFIG_SND_SOC_SSM2602_I2C is not set
-# CONFIG_SND_SOC_SSM2602_SPI is not set
-# CONFIG_SND_SOC_SSM3515 is not set
-# CONFIG_SND_SOC_SSM4567 is not set
-# CONFIG_SND_SOC_STA32X is not set
-# CONFIG_SND_SOC_STA350 is not set
-# CONFIG_SND_SOC_STI_SAS is not set
-# CONFIG_SND_SOC_TAS2552 is not set
-# CONFIG_SND_SOC_TAS2562 is not set
-# CONFIG_SND_SOC_TAS2764 is not set
-# CONFIG_SND_SOC_TAS2770 is not set
-# CONFIG_SND_SOC_TAS2780 is not set
-# CONFIG_SND_SOC_TAS2781_I2C is not set
-# CONFIG_SND_SOC_TAS5086 is not set
-# CONFIG_SND_SOC_TAS571X is not set
-# CONFIG_SND_SOC_TAS5720 is not set
-# CONFIG_SND_SOC_TAS5805M is not set
-# CONFIG_SND_SOC_TAS6424 is not set
-# CONFIG_SND_SOC_TDA7419 is not set
-# CONFIG_SND_SOC_TFA9879 is not set
-# CONFIG_SND_SOC_TFA989X is not set
-# CONFIG_SND_SOC_TLV320ADC3XXX is not set
-# CONFIG_SND_SOC_TLV320ADCX140 is not set
-# CONFIG_SND_SOC_TLV320AIC23_I2C is not set
-# CONFIG_SND_SOC_TLV320AIC23_SPI is not set
-# CONFIG_SND_SOC_TLV320AIC31XX is not set
-# CONFIG_SND_SOC_TLV320AIC32X4_I2C is not set
-# CONFIG_SND_SOC_TLV320AIC32X4_SPI is not set
-# CONFIG_SND_SOC_TLV320AIC3X is not set
-# CONFIG_SND_SOC_TLV320AIC3X_I2C is not set
-# CONFIG_SND_SOC_TLV320AIC3X_SPI is not set
-# CONFIG_SND_SOC_TPA6130A2 is not set
-# CONFIG_SND_SOC_TS3A227E is not set
-# CONFIG_SND_SOC_TSCS42XX is not set
-# CONFIG_SND_SOC_TSCS454 is not set
-# CONFIG_SND_SOC_UDA1334 is not set
-# CONFIG_SND_SOC_WM8510 is not set
-# CONFIG_SND_SOC_WM8523 is not set
-# CONFIG_SND_SOC_WM8524 is not set
-# CONFIG_SND_SOC_WM8580 is not set
-# CONFIG_SND_SOC_WM8711 is not set
-# CONFIG_SND_SOC_WM8728 is not set
-# CONFIG_SND_SOC_WM8731 is not set
-# CONFIG_SND_SOC_WM8731_I2C is not set
-# CONFIG_SND_SOC_WM8731_SPI is not set
-# CONFIG_SND_SOC_WM8737 is not set
-# CONFIG_SND_SOC_WM8741 is not set
-# CONFIG_SND_SOC_WM8750 is not set
-# CONFIG_SND_SOC_WM8753 is not set
-# CONFIG_SND_SOC_WM8770 is not set
-# CONFIG_SND_SOC_WM8776 is not set
-# CONFIG_SND_SOC_WM8782 is not set
-# CONFIG_SND_SOC_WM8804_I2C is not set
-# CONFIG_SND_SOC_WM8804_SPI is not set
-# CONFIG_SND_SOC_WM8903 is not set
-# CONFIG_SND_SOC_WM8904 is not set
-# CONFIG_SND_SOC_WM8940 is not set
-# CONFIG_SND_SOC_WM8960 is not set
-# CONFIG_SND_SOC_WM8961 is not set
-# CONFIG_SND_SOC_WM8962 is not set
-# CONFIG_SND_SOC_WM8974 is not set
-# CONFIG_SND_SOC_WM8978 is not set
-# CONFIG_SND_SOC_WM8985 is not set
-# CONFIG_SND_SOC_XILINX_AUDIO_FORMATTER is not set
-# CONFIG_SND_SOC_XILINX_I2S is not set
-# CONFIG_SND_SOC_XILINX_SPDIF is not set
-# CONFIG_SND_SOC_XTFPGA_I2S is not set
-# CONFIG_SND_SOC_ZL38060 is not set
-# CONFIG_SND_SONICVIBES is not set
-# CONFIG_SND_SPI is not set
-# CONFIG_SND_SSCAPE is not set
-# CONFIG_SND_SST_ATOM_HIFI2_PLATFORM_ACPI is not set
-# CONFIG_SND_SST_ATOM_HIFI2_PLATFORM_PCI is not set
-# CONFIG_SND_SUN4I_CODEC is not set
-# CONFIG_SND_SUPPORT_OLD_API is not set
-# CONFIG_SND_TEST_COMPONENT is not set
-# CONFIG_SND_TIMER is not set
-# CONFIG_SND_TRIDENT is not set
-CONFIG_SND_USB=y
-# CONFIG_SND_USB_6FIRE is not set
-# CONFIG_SND_USB_AUDIO is not set
-# CONFIG_SND_USB_AUDIO_MIDI_V2 is not set
-# CONFIG_SND_USB_CAIAQ is not set
-# CONFIG_SND_USB_HIFACE is not set
-# CONFIG_SND_USB_POD is not set
-# CONFIG_SND_USB_PODHD is not set
-# CONFIG_SND_USB_TONEPORT is not set
-# CONFIG_SND_USB_UA101 is not set
-# CONFIG_SND_USB_US122L is not set
-# CONFIG_SND_USB_USX2Y is not set
-# CONFIG_SND_USB_VARIAX is not set
-# CONFIG_SND_VERBOSE_PRINTK is not set
-CONFIG_SND_VERBOSE_PROCFS=y
-# CONFIG_SND_VIA82XX is not set
-# CONFIG_SND_VIA82XX_MODEM is not set
-# CONFIG_SND_VIRTIO is not set
-# CONFIG_SND_VIRTUOSO is not set
-# CONFIG_SND_VX222 is not set
-# CONFIG_SND_VXPOCKET is not set
-# CONFIG_SND_WAVEFRONT is not set
-CONFIG_SND_X86=y
-# CONFIG_SND_XEN_FRONTEND is not set
-# CONFIG_SND_YMFPCI is not set
-# CONFIG_SNI_RM is not set
-# CONFIG_SOCIONEXT_SYNQUACER_PREITS is not set
-# CONFIG_SOCK_CGROUP_DATA is not set
-# CONFIG_SOC_AM33XX is not set
-# CONFIG_SOC_AM43XX is not set
-# CONFIG_SOC_BRCMSTB is not set
-# CONFIG_SOC_DRA7XX is not set
-# CONFIG_SOC_HAS_OMAP2_SDRC is not set
-# CONFIG_SOC_OMAP5 is not set
-# CONFIG_SOC_TI is not set
-# CONFIG_SOFTLOCKUP_DETECTOR is not set
-# CONFIG_SOFT_WATCHDOG is not set
-# CONFIG_SOLARIS_X86_PARTITION is not set
-# CONFIG_SONYPI is not set
-# CONFIG_SONY_LAPTOP is not set
-# CONFIG_SOUND is not set
-# CONFIG_SOUNDWIRE is not set
-# CONFIG_SOUND_OSS_CORE is not set
-# CONFIG_SOUND_OSS_CORE_PRECLAIM is not set
-# CONFIG_SP5100_TCO is not set
-# CONFIG_SPARSEMEM_MANUAL is not set
-# CONFIG_SPARSEMEM_STATIC is not set
-# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
-# CONFIG_SPARSE_IRQ is not set
-# CONFIG_SPEAKUP is not set
-# CONFIG_SPI is not set
-# CONFIG_SPINLOCK_TEST is not set
-# CONFIG_SPI_ALTERA is not set
-# CONFIG_SPI_AMD is not set
-# CONFIG_SPI_AU1550 is not set
-# CONFIG_SPI_AX88796C is not set
-# CONFIG_SPI_AXI_SPI_ENGINE is not set
-# CONFIG_SPI_BCM2835 is not set
-# CONFIG_SPI_BCM63XX_HSSPI is not set
-# CONFIG_SPI_BCMBCA_HSSPI is not set
-# CONFIG_SPI_BCM_QSPI is not set
-# CONFIG_SPI_BITBANG is not set
-# CONFIG_SPI_BUTTERFLY is not set
-# CONFIG_SPI_CADENCE is not set
-# CONFIG_SPI_CADENCE_QUADSPI is not set
-# CONFIG_SPI_CADENCE_XSPI is not set
-# CONFIG_SPI_DEBUG is not set
-# CONFIG_SPI_DESIGNWARE is not set
-# CONFIG_SPI_DW_BT1 is not set
-# CONFIG_SPI_DW_BT1_DIRMAP is not set
-# CONFIG_SPI_DW_DMA is not set
-# CONFIG_SPI_DW_MMIO is not set
-# CONFIG_SPI_DW_PCI is not set
-# CONFIG_SPI_FSL_DSPI is not set
-# CONFIG_SPI_FSL_ESPI is not set
-# CONFIG_SPI_FSL_SPI is not set
-# CONFIG_SPI_GPIO is not set
-# CONFIG_SPI_IMG_SPFI is not set
-# CONFIG_SPI_LANTIQ_SSC is not set
-# CONFIG_SPI_LM70_LLP is not set
-# CONFIG_SPI_LOOPBACK_TEST is not set
-# CONFIG_SPI_MASTER is not set
-# CONFIG_SPI_MEM is not set
-# CONFIG_SPI_MICROCHIP_CORE is not set
-# CONFIG_SPI_MICROCHIP_CORE_QSPI is not set
-# CONFIG_SPI_MPC52xx is not set
-# CONFIG_SPI_MPC52xx_PSC is not set
-# CONFIG_SPI_MUX is not set
-# CONFIG_SPI_MXIC is not set
-# CONFIG_SPI_NXP_FLEXSPI is not set
-# CONFIG_SPI_OCTEON is not set
-# CONFIG_SPI_OC_TINY is not set
-# CONFIG_SPI_ORION is not set
-# CONFIG_SPI_PCI1XXXX is not set
-# CONFIG_SPI_PL022 is not set
-# CONFIG_SPI_PPC4xx is not set
-# CONFIG_SPI_PXA2XX is not set
-# CONFIG_SPI_PXA2XX_PCI is not set
-# CONFIG_SPI_QCOM_QSPI is not set
-# CONFIG_SPI_ROCKCHIP is not set
-# CONFIG_SPI_S3C64XX is not set
-# CONFIG_SPI_SC18IS602 is not set
-# CONFIG_SPI_SIFIVE is not set
-# CONFIG_SPI_SLAVE is not set
-# CONFIG_SPI_SN_F_OSPI is not set
-# CONFIG_SPI_SPIDEV is not set
-# CONFIG_SPI_THUNDERX is not set
-# CONFIG_SPI_TI_QSPI is not set
-# CONFIG_SPI_TLE62X0 is not set
-# CONFIG_SPI_TOPCLIFF_PCH is not set
-# CONFIG_SPI_XCOMM is not set
-# CONFIG_SPI_XILINX is not set
-# CONFIG_SPI_ZYNQMP_GQSPI is not set
-CONFIG_SPLIT_PTLOCK_CPUS=4
-# CONFIG_SPMI is not set
-# CONFIG_SPS30 is not set
-# CONFIG_SPS30_I2C is not set
-# CONFIG_SPS30_SERIAL is not set
-CONFIG_SQUASHFS=y
-# CONFIG_SQUASHFS_4K_DEVBLK_SIZE is not set
-# CONFIG_SQUASHFS_CHOICE_DECOMP_BY_MOUNT is not set
-# CONFIG_SQUASHFS_COMPILE_DECOMP_MULTI is not set
-CONFIG_SQUASHFS_COMPILE_DECOMP_MULTI_PERCPU=y
-# CONFIG_SQUASHFS_COMPILE_DECOMP_SINGLE is not set
-CONFIG_SQUASHFS_DECOMP_MULTI_PERCPU=y
-CONFIG_SQUASHFS_EMBEDDED=y
-# CONFIG_SQUASHFS_FILE_CACHE is not set
-CONFIG_SQUASHFS_FILE_DIRECT=y
-CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3
-# CONFIG_SQUASHFS_LZ4 is not set
-# CONFIG_SQUASHFS_LZO is not set
-# CONFIG_SQUASHFS_XATTR is not set
-CONFIG_SQUASHFS_XZ=y
-# CONFIG_SQUASHFS_ZLIB is not set
-# CONFIG_SQUASHFS_ZSTD is not set
-# CONFIG_SRAM is not set
-# CONFIG_SRF04 is not set
-# CONFIG_SRF08 is not set
-# CONFIG_SSB is not set
-# CONFIG_SSB_DRIVER_GPIO is not set
-# CONFIG_SSB_HOST_SOC is not set
-# CONFIG_SSB_PCMCIAHOST is not set
-CONFIG_SSB_POSSIBLE=y
-# CONFIG_SSB_SDIOHOST is not set
-# CONFIG_SSFDC is not set
-# CONFIG_SSIF_IPMI_BMC is not set
-# CONFIG_STACKPROTECTOR is not set
-# CONFIG_STACKPROTECTOR_PER_TASK is not set
-# CONFIG_STACKPROTECTOR_STRONG is not set
-# CONFIG_STACKTRACE is not set
-# CONFIG_STACKTRACE_BUILD_ID is not set
-CONFIG_STACKTRACE_SUPPORT=y
-# CONFIG_STACK_TRACER is not set
-# CONFIG_STACK_VALIDATION is not set
-CONFIG_STAGING=y
-# CONFIG_STAGING_BOARD is not set
-# CONFIG_STAGING_MEDIA is not set
-CONFIG_STANDALONE=y
-# CONFIG_STATIC_KEYS_SELFTEST is not set
-# CONFIG_STATIC_USERMODEHELPER is not set
-# CONFIG_STE10XP is not set
-# CONFIG_STK3310 is not set
-# CONFIG_STK8312 is not set
-# CONFIG_STK8BA50 is not set
-# CONFIG_STM is not set
-# CONFIG_STMMAC_ETH is not set
-# CONFIG_STMMAC_PCI is not set
-# CONFIG_STMMAC_PLATFORM is not set
-# CONFIG_STMMAC_SELFTESTS is not set
-# CONFIG_STMPE_ADC is not set
-# CONFIG_STM_DUMMY is not set
-# CONFIG_STM_SOURCE_CONSOLE is not set
-CONFIG_STP=y
-# CONFIG_STREAM_PARSER is not set
-# CONFIG_STRICT_DEVMEM is not set
-CONFIG_STRICT_KERNEL_RWX=y
-CONFIG_STRICT_MODULE_RWX=y
-# CONFIG_STRING_SELFTEST is not set
-CONFIG_STRIP_ASM_SYMS=y
-# CONFIG_STX104 is not set
-# CONFIG_ST_UVIS25 is not set
-# CONFIG_SUN4I_GPADC is not set
-# CONFIG_SUN50I_DE2_BUS is not set
-# CONFIG_SUN50I_ERRATUM_UNKNOWN1 is not set
-# CONFIG_SUNDANCE is not set
-# CONFIG_SUNGEM is not set
-# CONFIG_SUNRPC is not set
-# CONFIG_SUNRPC_DEBUG is not set
-# CONFIG_SUNRPC_GSS is not set
-# CONFIG_SUNXI_SRAM is not set
-# CONFIG_SUN_PARTITION is not set
-# CONFIG_SURFACE_PLATFORMS is not set
-# CONFIG_SUSPEND is not set
-# CONFIG_SUSPEND_SKIP_SYNC is not set
-CONFIG_SWAP=y
-# CONFIG_SWCONFIG is not set
-# CONFIG_SWCONFIG_B53 is not set
-# CONFIG_SWCONFIG_B53_MMAP_DRIVER is not set
-# CONFIG_SWCONFIG_B53_SPI_DRIVER is not set
-# CONFIG_SWCONFIG_B53_SRAB_DRIVER is not set
-# CONFIG_SWCONFIG_LEDS is not set
-# CONFIG_SWIOTLB is not set
-# CONFIG_SWIOTLB_DYNAMIC is not set
-# CONFIG_SW_SYNC is not set
-# CONFIG_SX9310 is not set
-# CONFIG_SX9324 is not set
-# CONFIG_SX9360 is not set
-# CONFIG_SX9500 is not set
-# CONFIG_SXGBE_ETH is not set
-CONFIG_SYMBOLIC_ERRNAME=y
-# CONFIG_SYNC_FILE is not set
-# CONFIG_SYNTH_EVENTS is not set
-# CONFIG_SYNTH_EVENT_GEN_TEST is not set
-CONFIG_SYN_COOKIES=y
-# CONFIG_SYSCON_REBOOT_MODE is not set
-CONFIG_SYSCTL=y
-CONFIG_SYSFS=y
-# CONFIG_SYSFS_SYSCALL is not set
-# CONFIG_SYSTEMPORT is not set
-# CONFIG_SYSTEM_BLACKLIST_KEYRING is not set
-# CONFIG_SYSTEM_DATA_VERIFICATION is not set
-# CONFIG_SYSTEM_TRUSTED_KEYRING is not set
-CONFIG_SYSTEM_TRUSTED_KEYS=""
-# CONFIG_SYSV68_PARTITION is not set
-CONFIG_SYSVIPC=y
-CONFIG_SYSVIPC_SYSCTL=y
-# CONFIG_SYSV_FS is not set
-# CONFIG_SYS_HYPERVISOR is not set
-# CONFIG_T5403 is not set
-# CONFIG_TARGET_CORE is not set
-# CONFIG_TASKSTATS is not set
-# CONFIG_TASKS_RCU is not set
-# CONFIG_TASK_XACCT is not set
-# CONFIG_TC35815 is not set
-# CONFIG_TCG_ATMEL is not set
-# CONFIG_TCG_CRB is not set
-# CONFIG_TCG_FTPM_TEE is not set
-# CONFIG_TCG_INFINEON is not set
-# CONFIG_TCG_NSC is not set
-# CONFIG_TCG_TIS is not set
-# CONFIG_TCG_TIS_I2C is not set
-# CONFIG_TCG_TIS_I2C_ATMEL is not set
-# CONFIG_TCG_TIS_I2C_CR50 is not set
-# CONFIG_TCG_TIS_I2C_INFINEON is not set
-# CONFIG_TCG_TIS_I2C_NUVOTON is not set
-# CONFIG_TCG_TIS_SPI is not set
-# CONFIG_TCG_TIS_ST33ZP24_I2C is not set
-# CONFIG_TCG_TIS_ST33ZP24_SPI is not set
-# CONFIG_TCG_TPM is not set
-# CONFIG_TCG_VTPM_PROXY is not set
-# CONFIG_TCG_XEN is not set
-# CONFIG_TCIC is not set
-CONFIG_TCP_CONG_ADVANCED=y
-# CONFIG_TCP_CONG_BBR is not set
-# CONFIG_TCP_CONG_BIC is not set
-# CONFIG_TCP_CONG_CDG is not set
-CONFIG_TCP_CONG_CUBIC=y
-# CONFIG_TCP_CONG_DCTCP is not set
-# CONFIG_TCP_CONG_HSTCP is not set
-# CONFIG_TCP_CONG_HTCP is not set
-# CONFIG_TCP_CONG_HYBLA is not set
-# CONFIG_TCP_CONG_ILLINOIS is not set
-# CONFIG_TCP_CONG_LP is not set
-# CONFIG_TCP_CONG_NV is not set
-# CONFIG_TCP_CONG_SCALABLE is not set
-# CONFIG_TCP_CONG_VEGAS is not set
-# CONFIG_TCP_CONG_VENO is not set
-# CONFIG_TCP_CONG_WESTWOOD is not set
-# CONFIG_TCP_CONG_YEAH is not set
-# CONFIG_TCP_MD5SIG is not set
-# CONFIG_TCS3414 is not set
-# CONFIG_TCS3472 is not set
-# CONFIG_TEE is not set
-# CONFIG_TEGRA_AHB is not set
-# CONFIG_TEGRA_HOST1X is not set
-# CONFIG_TEHUTI is not set
-# CONFIG_TERANETICS_PHY is not set
-# CONFIG_TEST_ASYNC_DRIVER_PROBE is not set
-# CONFIG_TEST_BITMAP is not set
-# CONFIG_TEST_BITOPS is not set
-# CONFIG_TEST_BLACKHOLE_DEV is not set
-# CONFIG_TEST_BPF is not set
-# CONFIG_TEST_CLOCKSOURCE_WATCHDOG is not set
-# CONFIG_TEST_DEBUG_VIRTUAL is not set
-# CONFIG_TEST_DHRY is not set
-# CONFIG_TEST_DIV64 is not set
-# CONFIG_TEST_DYNAMIC_DEBUG is not set
-# CONFIG_TEST_FIRMWARE is not set
-# CONFIG_TEST_FREE_PAGES is not set
-# CONFIG_TEST_HEXDUMP is not set
-# CONFIG_TEST_IDA is not set
-# CONFIG_TEST_KMOD is not set
-# CONFIG_TEST_KSTRTOX is not set
-# CONFIG_TEST_LIST_SORT is not set
-# CONFIG_TEST_LKM is not set
-# CONFIG_TEST_LOCKUP is not set
-# CONFIG_TEST_MAPLE_TREE is not set
-# CONFIG_TEST_MEMCAT_P is not set
-# CONFIG_TEST_MEMINIT is not set
-# CONFIG_TEST_MIN_HEAP is not set
-# CONFIG_TEST_POWER is not set
-# CONFIG_TEST_PRINTF is not set
-# CONFIG_TEST_REF_TRACKER is not set
-# CONFIG_TEST_RHASHTABLE is not set
-# CONFIG_TEST_SCANF is not set
-# CONFIG_TEST_SORT is not set
-# CONFIG_TEST_STATIC_KEYS is not set
-# CONFIG_TEST_STRING_HELPERS is not set
-# CONFIG_TEST_SYSCTL is not set
-# CONFIG_TEST_UBSAN is not set
-# CONFIG_TEST_UDELAY is not set
-# CONFIG_TEST_USER_COPY is not set
-# CONFIG_TEST_UUID is not set
-# CONFIG_TEST_VMALLOC is not set
-# CONFIG_TEST_XARRAY is not set
-CONFIG_TEXTSEARCH=y
-# CONFIG_TEXTSEARCH_BM is not set
-# CONFIG_TEXTSEARCH_FSM is not set
-# CONFIG_TEXTSEARCH_KMP is not set
-# CONFIG_THERMAL is not set
-# CONFIG_THERMAL_DEFAULT_GOV_BANG_BANG is not set
-# CONFIG_THERMAL_DEFAULT_GOV_FAIR_SHARE is not set
-# CONFIG_THERMAL_DEFAULT_GOV_POWER_ALLOCATOR is not set
-# CONFIG_THERMAL_DEFAULT_GOV_USER_SPACE is not set
-# CONFIG_THERMAL_EMULATION is not set
-# CONFIG_THERMAL_GOV_BANG_BANG is not set
-# CONFIG_THERMAL_GOV_FAIR_SHARE is not set
-# CONFIG_THERMAL_GOV_POWER_ALLOCATOR is not set
-# CONFIG_THERMAL_GOV_USER_SPACE is not set
-# CONFIG_THERMAL_HWMON is not set
-# CONFIG_THERMAL_MMIO is not set
-# CONFIG_THERMAL_NETLINK is not set
-# CONFIG_THERMAL_STATISTICS is not set
-# CONFIG_THERMAL_WRITABLE_TRIPS is not set
-# CONFIG_THINKPAD_ACPI is not set
-# CONFIG_THRUSTMASTER_FF is not set
-# CONFIG_THUMB2_KERNEL is not set
-# CONFIG_THUNDER_NIC_BGX is not set
-# CONFIG_THUNDER_NIC_PF is not set
-# CONFIG_THUNDER_NIC_RGX is not set
-# CONFIG_THUNDER_NIC_VF is not set
-# CONFIG_TICK_CPU_ACCOUNTING is not set
-CONFIG_TICK_ONESHOT=y
-# CONFIG_TIFM_CORE is not set
-# CONFIG_TIGON3 is not set
-# CONFIG_TIMB_DMA is not set
-CONFIG_TIMERFD=y
-# CONFIG_TIMERLAT_TRACER is not set
-# CONFIG_TIME_NS is not set
-# CONFIG_TINYDRM_HX8357D is not set
-# CONFIG_TINYDRM_ILI9163 is not set
-# CONFIG_TINYDRM_ILI9225 is not set
-# CONFIG_TINYDRM_ILI9341 is not set
-# CONFIG_TINYDRM_ILI9486 is not set
-# CONFIG_TINYDRM_MI0283QT is not set
-# CONFIG_TINYDRM_REPAPER is not set
-# CONFIG_TINYDRM_ST7586 is not set
-# CONFIG_TINYDRM_ST7735R is not set
-CONFIG_TINY_RCU=y
-# CONFIG_TIPC is not set
-# CONFIG_TI_ADC081C is not set
-# CONFIG_TI_ADC0832 is not set
-# CONFIG_TI_ADC084S021 is not set
-# CONFIG_TI_ADC108S102 is not set
-# CONFIG_TI_ADC12138 is not set
-# CONFIG_TI_ADC128S052 is not set
-# CONFIG_TI_ADC161S626 is not set
-# CONFIG_TI_ADS1015 is not set
-# CONFIG_TI_ADS1100 is not set
-# CONFIG_TI_ADS124S08 is not set
-# CONFIG_TI_ADS131E08 is not set
-# CONFIG_TI_ADS7924 is not set
-# CONFIG_TI_ADS7950 is not set
-# CONFIG_TI_ADS8344 is not set
-# CONFIG_TI_ADS8688 is not set
-# CONFIG_TI_AM335X_ADC is not set
-# CONFIG_TI_CPSW is not set
-# CONFIG_TI_CPSW_PHY_SEL is not set
-# CONFIG_TI_CPTS is not set
-# CONFIG_TI_DAC082S085 is not set
-# CONFIG_TI_DAC5571 is not set
-# CONFIG_TI_DAC7311 is not set
-# CONFIG_TI_DAC7612 is not set
-# CONFIG_TI_DAVINCI_MDIO is not set
-# CONFIG_TI_LMP92064 is not set
-# CONFIG_TI_ST is not set
-# CONFIG_TI_TLC4541 is not set
-# CONFIG_TI_TMAG5273 is not set
-# CONFIG_TI_TSC2046 is not set
-# CONFIG_TLAN is not set
-# CONFIG_TLS is not set
-# CONFIG_TLS_DEVICE is not set
-# CONFIG_TLS_TOE is not set
-# CONFIG_TMD_HERMES is not set
-# CONFIG_TMP006 is not set
-# CONFIG_TMP007 is not set
-# CONFIG_TMP117 is not set
-CONFIG_TMPFS=y
-# CONFIG_TMPFS_INODE64 is not set
-# CONFIG_TMPFS_POSIX_ACL is not set
-# CONFIG_TMPFS_QUOTA is not set
-CONFIG_TMPFS_XATTR=y
-# CONFIG_TOPSTAR_LAPTOP is not set
-# CONFIG_TORTURE_TEST is not set
-# CONFIG_TOSHIBA_HAPS is not set
-# CONFIG_TOUCHSCREEN_88PM860X is not set
-# CONFIG_TOUCHSCREEN_AD7877 is not set
-# CONFIG_TOUCHSCREEN_AD7879 is not set
-# CONFIG_TOUCHSCREEN_AD7879_I2C is not set
-# CONFIG_TOUCHSCREEN_AD7879_SPI is not set
-# CONFIG_TOUCHSCREEN_ADC is not set
-# CONFIG_TOUCHSCREEN_ADS7846 is not set
-# CONFIG_TOUCHSCREEN_AR1021_I2C is not set
-# CONFIG_TOUCHSCREEN_ATMEL_MXT is not set
-# CONFIG_TOUCHSCREEN_ATMEL_MXT_T37 is not set
-# CONFIG_TOUCHSCREEN_AUO_PIXCIR is not set
-# CONFIG_TOUCHSCREEN_BU21013 is not set
-# CONFIG_TOUCHSCREEN_BU21029 is not set
-# CONFIG_TOUCHSCREEN_CHIPONE_ICN8318 is not set
-# CONFIG_TOUCHSCREEN_CHIPONE_ICN8505 is not set
-# CONFIG_TOUCHSCREEN_COLIBRI_VF50 is not set
-# CONFIG_TOUCHSCREEN_CY8CTMA140 is not set
-# CONFIG_TOUCHSCREEN_CY8CTMG110 is not set
-# CONFIG_TOUCHSCREEN_CYTTSP4_CORE is not set
-# CONFIG_TOUCHSCREEN_CYTTSP4_I2C is not set
-# CONFIG_TOUCHSCREEN_CYTTSP4_SPI is not set
-# CONFIG_TOUCHSCREEN_CYTTSP5 is not set
-# CONFIG_TOUCHSCREEN_CYTTSP_CORE is not set
-# CONFIG_TOUCHSCREEN_CYTTSP_I2C is not set
-# CONFIG_TOUCHSCREEN_CYTTSP_SPI is not set
-# CONFIG_TOUCHSCREEN_DA9034 is not set
-# CONFIG_TOUCHSCREEN_DA9052 is not set
-# CONFIG_TOUCHSCREEN_DYNAPRO is not set
-# CONFIG_TOUCHSCREEN_EDT_FT5X06 is not set
-# CONFIG_TOUCHSCREEN_EETI is not set
-# CONFIG_TOUCHSCREEN_EGALAX is not set
-# CONFIG_TOUCHSCREEN_EGALAX_SERIAL is not set
-# CONFIG_TOUCHSCREEN_EKTF2127 is not set
-# CONFIG_TOUCHSCREEN_ELAN is not set
-# CONFIG_TOUCHSCREEN_ELO is not set
-# CONFIG_TOUCHSCREEN_EXC3000 is not set
-# CONFIG_TOUCHSCREEN_FUJITSU is not set
-# CONFIG_TOUCHSCREEN_GOODIX is not set
-# CONFIG_TOUCHSCREEN_GUNZE is not set
-# CONFIG_TOUCHSCREEN_HAMPSHIRE is not set
-# CONFIG_TOUCHSCREEN_HIDEEP is not set
-# CONFIG_TOUCHSCREEN_HIMAX_HX83112B is not set
-# CONFIG_TOUCHSCREEN_HP600 is not set
-# CONFIG_TOUCHSCREEN_HP7XX is not set
-# CONFIG_TOUCHSCREEN_HTCPEN is not set
-# CONFIG_TOUCHSCREEN_HYCON_HY46XX is not set
-# CONFIG_TOUCHSCREEN_HYNITRON_CSTXXX is not set
-# CONFIG_TOUCHSCREEN_ILI210X is not set
-# CONFIG_TOUCHSCREEN_ILITEK is not set
-# CONFIG_TOUCHSCREEN_IMAGIS is not set
-# CONFIG_TOUCHSCREEN_IMX6UL_TSC is not set
-# CONFIG_TOUCHSCREEN_INEXIO is not set
-# CONFIG_TOUCHSCREEN_IPAQ_MICRO is not set
-# CONFIG_TOUCHSCREEN_IPROC is not set
-# CONFIG_TOUCHSCREEN_IQS5XX is not set
-# CONFIG_TOUCHSCREEN_IQS7211 is not set
-# CONFIG_TOUCHSCREEN_LPC32XX is not set
-# CONFIG_TOUCHSCREEN_MAX11801 is not set
-# CONFIG_TOUCHSCREEN_MC13783 is not set
-# CONFIG_TOUCHSCREEN_MCS5000 is not set
-# CONFIG_TOUCHSCREEN_MELFAS_MIP4 is not set
-# CONFIG_TOUCHSCREEN_MIGOR is not set
-# CONFIG_TOUCHSCREEN_MK712 is not set
-# CONFIG_TOUCHSCREEN_MMS114 is not set
-# CONFIG_TOUCHSCREEN_MSG2638 is not set
-# CONFIG_TOUCHSCREEN_MTOUCH is not set
-# CONFIG_TOUCHSCREEN_MX25 is not set
-# CONFIG_TOUCHSCREEN_MXS_LRADC is not set
-# CONFIG_TOUCHSCREEN_NOVATEK_NVT_TS is not set
-# CONFIG_TOUCHSCREEN_PCAP is not set
-# CONFIG_TOUCHSCREEN_PENMOUNT is not set
-# CONFIG_TOUCHSCREEN_PIXCIR is not set
-# CONFIG_TOUCHSCREEN_RASPBERRYPI_FW is not set
-# CONFIG_TOUCHSCREEN_RM_TS is not set
-# CONFIG_TOUCHSCREEN_ROHM_BU21023 is not set
-# CONFIG_TOUCHSCREEN_S6SY761 is not set
-# CONFIG_TOUCHSCREEN_SILEAD is not set
-# CONFIG_TOUCHSCREEN_SIS_I2C is not set
-# CONFIG_TOUCHSCREEN_ST1232 is not set
-# CONFIG_TOUCHSCREEN_STMFTS is not set
-# CONFIG_TOUCHSCREEN_STMPE is not set
-# CONFIG_TOUCHSCREEN_SUN4I is not set
-# CONFIG_TOUCHSCREEN_SUR40 is not set
-# CONFIG_TOUCHSCREEN_SURFACE3_SPI is not set
-# CONFIG_TOUCHSCREEN_SX8654 is not set
-# CONFIG_TOUCHSCREEN_TI_AM335X_TSC is not set
-# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set
-# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
-# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
-# CONFIG_TOUCHSCREEN_TPS6507X is not set
-# CONFIG_TOUCHSCREEN_TS4800 is not set
-# CONFIG_TOUCHSCREEN_TSC2004 is not set
-# CONFIG_TOUCHSCREEN_TSC2005 is not set
-# CONFIG_TOUCHSCREEN_TSC2007 is not set
-# CONFIG_TOUCHSCREEN_TSC2007_IIO is not set
-# CONFIG_TOUCHSCREEN_TSC200X_CORE is not set
-# CONFIG_TOUCHSCREEN_TSC_SERIO is not set
-# CONFIG_TOUCHSCREEN_USB_3M is not set
-# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
-# CONFIG_TOUCHSCREEN_USB_DMC_TSC10 is not set
-# CONFIG_TOUCHSCREEN_USB_E2I is not set
-# CONFIG_TOUCHSCREEN_USB_EASYTOUCH is not set
-# CONFIG_TOUCHSCREEN_USB_EGALAX is not set
-# CONFIG_TOUCHSCREEN_USB_ELO is not set
-# CONFIG_TOUCHSCREEN_USB_ETT_TC45USB is not set
-# CONFIG_TOUCHSCREEN_USB_ETURBO is not set
-# CONFIG_TOUCHSCREEN_USB_GENERAL_TOUCH is not set
-# CONFIG_TOUCHSCREEN_USB_GOTOP is not set
-# CONFIG_TOUCHSCREEN_USB_GUNZE is not set
-# CONFIG_TOUCHSCREEN_USB_IDEALTEK is not set
-# CONFIG_TOUCHSCREEN_USB_IRTOUCH is not set
-# CONFIG_TOUCHSCREEN_USB_ITM is not set
-# CONFIG_TOUCHSCREEN_USB_JASTEC is not set
-# CONFIG_TOUCHSCREEN_USB_NEXIO is not set
-# CONFIG_TOUCHSCREEN_USB_PANJIT is not set
-# CONFIG_TOUCHSCREEN_USB_ZYTRONIC is not set
-# CONFIG_TOUCHSCREEN_WACOM_I2C is not set
-# CONFIG_TOUCHSCREEN_WACOM_W8001 is not set
-# CONFIG_TOUCHSCREEN_WDT87XX_I2C is not set
-# CONFIG_TOUCHSCREEN_WM831X is not set
-# CONFIG_TOUCHSCREEN_WM9705 is not set
-# CONFIG_TOUCHSCREEN_WM9712 is not set
-# CONFIG_TOUCHSCREEN_WM9713 is not set
-# CONFIG_TOUCHSCREEN_WM97XX is not set
-# CONFIG_TOUCHSCREEN_WM97XX_MAINSTONE is not set
-# CONFIG_TOUCHSCREEN_ZET6223 is not set
-# CONFIG_TOUCHSCREEN_ZFORCE is not set
-# CONFIG_TOUCHSCREEN_ZINITIX is not set
-# CONFIG_TPL0102 is not set
-# CONFIG_TPS6105X is not set
-# CONFIG_TPS65010 is not set
-# CONFIG_TPS6507X is not set
-# CONFIG_TRACEPOINT_BENCHMARK is not set
-# CONFIG_TRACER_SNAPSHOT is not set
-# CONFIG_TRACER_SNAPSHOT_PER_CPU_SWAP is not set
-# CONFIG_TRACE_BRANCH_PROFILING is not set
-# CONFIG_TRACE_EVAL_MAP_FILE is not set
-# CONFIG_TRACE_EVENT_INJECT is not set
-CONFIG_TRACE_IRQFLAGS_SUPPORT=y
-# CONFIG_TRACE_MMIO_ACCESS is not set
-CONFIG_TRACING_SUPPORT=y
-CONFIG_TRAD_SIGNALS=y
-# CONFIG_TRANSPARENT_HUGEPAGE is not set
-# CONFIG_TREE_RCU is not set
-# CONFIG_TRIM_UNUSED_KSYMS is not set
-# CONFIG_TRUSTED_FOUNDATIONS is not set
-# CONFIG_TRUSTED_KEYS is not set
-# CONFIG_TRUSTED_KEYS_CAAM is not set
-# CONFIG_TRUSTED_KEYS_TEE is not set
-# CONFIG_TRUSTED_KEYS_TPM is not set
-# CONFIG_TSL2583 is not set
-# CONFIG_TSL2591 is not set
-# CONFIG_TSL2772 is not set
-# CONFIG_TSL4531 is not set
-# CONFIG_TSNEP is not set
-# CONFIG_TSYS01 is not set
-# CONFIG_TSYS02D is not set
-# CONFIG_TTPCI_EEPROM is not set
-CONFIG_TTY=y
-# CONFIG_TTY_PRINTK is not set
-# CONFIG_TUN is not set
-# CONFIG_TUN_VNET_CROSS_LE is not set
-# CONFIG_TWL4030_CORE is not set
-# CONFIG_TWL4030_MADC is not set
-# CONFIG_TWL6030_GPADC is not set
-# CONFIG_TWL6040_CORE is not set
-# CONFIG_TXGBE is not set
-# CONFIG_TYPEC is not set
-# CONFIG_TYPEC_DP_ALTMODE is not set
-# CONFIG_TYPEC_TCPM is not set
-# CONFIG_TYPEC_UCSI is not set
-# CONFIG_TYPHOON is not set
-# CONFIG_UACCE is not set
-# CONFIG_UACCESS_WITH_MEMCPY is not set
-# CONFIG_UBIFS_ATIME_SUPPORT is not set
-# CONFIG_UBIFS_FS_ADVANCED_COMPR is not set
-# CONFIG_UBIFS_FS_AUTHENTICATION is not set
-CONFIG_UBIFS_FS_LZO=y
-# CONFIG_UBIFS_FS_SECURITY is not set
-CONFIG_UBIFS_FS_XATTR=y
-CONFIG_UBIFS_FS_ZLIB=y
-CONFIG_UBIFS_FS_ZSTD=y
-# CONFIG_UBSAN is not set
-CONFIG_UBSAN_ALIGNMENT=y
-CONFIG_UBSAN_BOOL=y
-# CONFIG_UBSAN_DIV_ZERO is not set
-CONFIG_UBSAN_ENUM=y
-CONFIG_UBSAN_SHIFT=y
-# CONFIG_UBSAN_UNREACHABLE is not set
-# CONFIG_UDF_FS is not set
-# CONFIG_UDMABUF is not set
-CONFIG_UEVENT_HELPER=y
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
-# CONFIG_UFS_FS is not set
-# CONFIG_UHID is not set
-CONFIG_UID16=y
-# CONFIG_UIMAGE_FIT_BLK is not set
-# CONFIG_UIO is not set
-# CONFIG_ULTRA is not set
-# CONFIG_ULTRIX_PARTITION is not set
-# CONFIG_UNICODE is not set
-CONFIG_UNIX=y
-CONFIG_UNIX98_PTYS=y
-# CONFIG_UNIXWARE_DISKLABEL is not set
-# CONFIG_UNIX_DIAG is not set
-CONFIG_UNIX_SCM=y
-# CONFIG_UNWINDER_FRAME_POINTER is not set
-# CONFIG_UPROBES is not set
-# CONFIG_UPROBE_EVENTS is not set
-# CONFIG_US5182D is not set
-# CONFIG_USB is not set
-# CONFIG_USB4 is not set
-# CONFIG_USBIP_CORE is not set
-CONFIG_USBIP_VHCI_HC_PORTS=8
-CONFIG_USBIP_VHCI_NR_HCS=1
-# CONFIG_USBIP_VUDC is not set
-# CONFIG_USBPCWATCHDOG is not set
-# CONFIG_USB_ACM is not set
-# CONFIG_USB_ADUTUX is not set
-# CONFIG_USB_AIRSPY is not set
-CONFIG_USB_ALI_M5632=y
-# CONFIG_USB_AMD5536UDC is not set
-CONFIG_USB_AN2720=y
-# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
-# CONFIG_USB_APPLEDISPLAY is not set
-CONFIG_USB_ARCH_HAS_HCD=y
-CONFIG_USB_ARMLINUX=y
-# CONFIG_USB_ATM is not set
-# CONFIG_USB_AUDIO is not set
-CONFIG_USB_AUTOSUSPEND_DELAY=2
-# CONFIG_USB_BDC_UDC is not set
-CONFIG_USB_BELKIN=y
-# CONFIG_USB_C67X00_HCD is not set
-# CONFIG_USB_CATC is not set
-# CONFIG_USB_CDC_COMPOSITE is not set
-# CONFIG_USB_CDNS3 is not set
-# CONFIG_USB_CDNS3_IMX is not set
-# CONFIG_USB_CDNS3_PCI_WRAP is not set
-# CONFIG_USB_CDNSP_PCI is not set
-# CONFIG_USB_CDNS_SUPPORT is not set
-# CONFIG_USB_CHAOSKEY is not set
-# CONFIG_USB_CHIPIDEA is not set
-# CONFIG_USB_CHIPIDEA_GENERIC is not set
-# CONFIG_USB_CHIPIDEA_IMX is not set
-# CONFIG_USB_CHIPIDEA_MSM is not set
-# CONFIG_USB_CHIPIDEA_PCI is not set
-# CONFIG_USB_CHIPIDEA_TEGRA is not set
-# CONFIG_USB_CONFIGFS is not set
-# CONFIG_USB_CONN_GPIO is not set
-# CONFIG_USB_CXACRU is not set
-# CONFIG_USB_CYPRESS_CY7C63 is not set
-# CONFIG_USB_CYTHERM is not set
-CONFIG_USB_DEFAULT_PERSIST=y
-# CONFIG_USB_DSBR is not set
-# CONFIG_USB_DUMMY_HCD is not set
-# CONFIG_USB_DWC2 is not set
-# CONFIG_USB_DWC2_DEBUG is not set
-# CONFIG_USB_DWC2_DUAL_ROLE is not set
-# CONFIG_USB_DWC2_HOST is not set
-# CONFIG_USB_DWC2_PERIPHERAL is not set
-# CONFIG_USB_DWC2_TRACK_MISSED_SOFS is not set
-# CONFIG_USB_DWC3 is not set
-# CONFIG_USB_DWC3_EXYNOS is not set
-# CONFIG_USB_DWC3_HAPS is not set
-# CONFIG_USB_DWC3_KEYSTONE is not set
-# CONFIG_USB_DWC3_OCTEON is not set
-# CONFIG_USB_DWC3_OF_SIMPLE is not set
-# CONFIG_USB_DWC3_PCI is not set
-# CONFIG_USB_DWC3_QCOM is not set
-# CONFIG_USB_DWC3_ULPI is not set
-# CONFIG_USB_DYNAMIC_MINORS is not set
-# CONFIG_USB_EG20T is not set
-# CONFIG_USB_EHCI_FSL is not set
-# CONFIG_USB_EHCI_HCD is not set
-# CONFIG_USB_EHCI_HCD_AT91 is not set
-# CONFIG_USB_EHCI_HCD_OMAP is not set
-# CONFIG_USB_EHCI_HCD_PPC_OF is not set
-# CONFIG_USB_EHCI_MV is not set
-CONFIG_USB_EHCI_ROOT_HUB_TT=y
-CONFIG_USB_EHCI_TT_NEWSCHED=y
-# CONFIG_USB_EHSET_TEST_FIXTURE is not set
-# CONFIG_USB_EMI26 is not set
-# CONFIG_USB_EMI62 is not set
-# CONFIG_USB_EPSON2888 is not set
-# CONFIG_USB_ETH is not set
-# CONFIG_USB_EZUSB_FX2 is not set
-# CONFIG_USB_FEW_INIT_RETRIES is not set
-# CONFIG_USB_FOTG210_HCD is not set
-# CONFIG_USB_FOTG210_UDC is not set
-# CONFIG_USB_FSL_USB2 is not set
-# CONFIG_USB_FUNCTIONFS is not set
-# CONFIG_USB_FUSB300 is not set
-# CONFIG_USB_GADGET is not set
-# CONFIG_USB_GADGETFS is not set
-# CONFIG_USB_GADGET_DEBUG is not set
-# CONFIG_USB_GADGET_DEBUG_FILES is not set
-# CONFIG_USB_GADGET_DEBUG_FS is not set
-CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=2
-CONFIG_USB_GADGET_VBUS_DRAW=2
-# CONFIG_USB_GADGET_XILINX is not set
-# CONFIG_USB_GL860 is not set
-# CONFIG_USB_GOKU is not set
-# CONFIG_USB_GPIO_VBUS is not set
-# CONFIG_USB_GR_UDC is not set
-# CONFIG_USB_GSPCA is not set
-# CONFIG_USB_GSPCA_BENQ is not set
-# CONFIG_USB_GSPCA_CONEX is not set
-# CONFIG_USB_GSPCA_CPIA1 is not set
-# CONFIG_USB_GSPCA_DTCS033 is not set
-# CONFIG_USB_GSPCA_ETOMS is not set
-# CONFIG_USB_GSPCA_FINEPIX is not set
-# CONFIG_USB_GSPCA_JEILINJ is not set
-# CONFIG_USB_GSPCA_JL2005BCD is not set
-# CONFIG_USB_GSPCA_KINECT is not set
-# CONFIG_USB_GSPCA_KONICA is not set
-# CONFIG_USB_GSPCA_MARS is not set
-# CONFIG_USB_GSPCA_MR97310A is not set
-# CONFIG_USB_GSPCA_NW80X is not set
-# CONFIG_USB_GSPCA_OV519 is not set
-# CONFIG_USB_GSPCA_OV534 is not set
-# CONFIG_USB_GSPCA_OV534_9 is not set
-# CONFIG_USB_GSPCA_PAC207 is not set
-# CONFIG_USB_GSPCA_PAC7302 is not set
-# CONFIG_USB_GSPCA_PAC7311 is not set
-# CONFIG_USB_GSPCA_SE401 is not set
-# CONFIG_USB_GSPCA_SN9C2028 is not set
-# CONFIG_USB_GSPCA_SN9C20X is not set
-# CONFIG_USB_GSPCA_SONIXB is not set
-# CONFIG_USB_GSPCA_SONIXJ is not set
-# CONFIG_USB_GSPCA_SPCA1528 is not set
-# CONFIG_USB_GSPCA_SPCA500 is not set
-# CONFIG_USB_GSPCA_SPCA501 is not set
-# CONFIG_USB_GSPCA_SPCA505 is not set
-# CONFIG_USB_GSPCA_SPCA506 is not set
-# CONFIG_USB_GSPCA_SPCA508 is not set
-# CONFIG_USB_GSPCA_SPCA561 is not set
-# CONFIG_USB_GSPCA_SQ905 is not set
-# CONFIG_USB_GSPCA_SQ905C is not set
-# CONFIG_USB_GSPCA_SQ930X is not set
-# CONFIG_USB_GSPCA_STK014 is not set
-# CONFIG_USB_GSPCA_STK1135 is not set
-# CONFIG_USB_GSPCA_STV0680 is not set
-# CONFIG_USB_GSPCA_SUNPLUS is not set
-# CONFIG_USB_GSPCA_T613 is not set
-# CONFIG_USB_GSPCA_TOPRO is not set
-# CONFIG_USB_GSPCA_TOUPTEK is not set
-# CONFIG_USB_GSPCA_TV8532 is not set
-# CONFIG_USB_GSPCA_VC032X is not set
-# CONFIG_USB_GSPCA_VICAM is not set
-# CONFIG_USB_GSPCA_XIRLINK_CIT is not set
-# CONFIG_USB_GSPCA_ZC3XX is not set
-# CONFIG_USB_G_ACM_MS is not set
-# CONFIG_USB_G_DBGP is not set
-# CONFIG_USB_G_HID is not set
-# CONFIG_USB_G_MULTI is not set
-# CONFIG_USB_G_NCM is not set
-# CONFIG_USB_G_NOKIA is not set
-# CONFIG_USB_G_PRINTER is not set
-# CONFIG_USB_G_SERIAL is not set
-# CONFIG_USB_G_WEBCAM is not set
-# CONFIG_USB_HACKRF is not set
-# CONFIG_USB_HCD_TEST_MODE is not set
-# CONFIG_USB_HID is not set
-# CONFIG_USB_HIDDEV is not set
-# CONFIG_USB_HSIC_USB3503 is not set
-# CONFIG_USB_HSIC_USB4604 is not set
-# CONFIG_USB_HSO is not set
-# CONFIG_USB_HUB_USB251XB is not set
-# CONFIG_USB_IDMOUSE is not set
-# CONFIG_USB_IOWARRIOR is not set
-# CONFIG_USB_IPHETH is not set
-# CONFIG_USB_ISIGHTFW is not set
-# CONFIG_USB_ISP116X_HCD is not set
-# CONFIG_USB_ISP1301 is not set
-# CONFIG_USB_ISP1362_HCD is not set
-# CONFIG_USB_ISP1760 is not set
-# CONFIG_USB_ISP1760_HCD is not set
-# CONFIG_USB_KAWETH is not set
-# CONFIG_USB_KBD is not set
-# CONFIG_USB_KC2190 is not set
-# CONFIG_USB_LAN78XX is not set
-# CONFIG_USB_LCD is not set
-# CONFIG_USB_LD is not set
-# CONFIG_USB_LEDS_TRIGGER_USBPORT is not set
-# CONFIG_USB_LED_TRIG is not set
-# CONFIG_USB_LEGOTOWER is not set
-# CONFIG_USB_LGM_PHY is not set
-# CONFIG_USB_LINK_LAYER_TEST is not set
-# CONFIG_USB_M5602 is not set
-# CONFIG_USB_M66592 is not set
-# CONFIG_USB_MASS_STORAGE is not set
-# CONFIG_USB_MAX3420_UDC is not set
-# CONFIG_USB_MAX3421_HCD is not set
-# CONFIG_USB_MDC800 is not set
-# CONFIG_USB_MICROTEK is not set
-# CONFIG_USB_MIDI_GADGET is not set
-# CONFIG_USB_MON is not set
-# CONFIG_USB_MOUSE is not set
-# CONFIG_USB_MSI2500 is not set
-# CONFIG_USB_MTU3 is not set
-# CONFIG_USB_MUSB_GADGET is not set
-# CONFIG_USB_MUSB_HDRC is not set
-# CONFIG_USB_MUSB_HOST is not set
-# CONFIG_USB_MV_U3D is not set
-# CONFIG_USB_MV_UDC is not set
-# CONFIG_USB_MXS_PHY is not set
-# CONFIG_USB_NET2272 is not set
-# CONFIG_USB_NET2280 is not set
-# CONFIG_USB_NET_AQC111 is not set
-# CONFIG_USB_NET_AX88179_178A is not set
-# CONFIG_USB_NET_AX8817X is not set
-# CONFIG_USB_NET_CDCETHER is not set
-# CONFIG_USB_NET_CDC_EEM is not set
-# CONFIG_USB_NET_CDC_MBIM is not set
-# CONFIG_USB_NET_CDC_NCM is not set
-# CONFIG_USB_NET_CDC_SUBSET is not set
-# CONFIG_USB_NET_CH9200 is not set
-# CONFIG_USB_NET_CX82310_ETH is not set
-# CONFIG_USB_NET_DM9601 is not set
-CONFIG_USB_NET_DRIVERS=y
-# CONFIG_USB_NET_GL620A is not set
-# CONFIG_USB_NET_HUAWEI_CDC_NCM is not set
-# CONFIG_USB_NET_INT51X1 is not set
-# CONFIG_USB_NET_KALMIA is not set
-# CONFIG_USB_NET_MCS7830 is not set
-# CONFIG_USB_NET_NET1080 is not set
-# CONFIG_USB_NET_PLUSB is not set
-# CONFIG_USB_NET_QMI_WWAN is not set
-# CONFIG_USB_NET_RNDIS_HOST is not set
-# CONFIG_USB_NET_RNDIS_WLAN is not set
-# CONFIG_USB_NET_SMSC75XX is not set
-# CONFIG_USB_NET_SMSC95XX is not set
-# CONFIG_USB_NET_SR9700 is not set
-# CONFIG_USB_NET_SR9800 is not set
-# CONFIG_USB_NET_ZAURUS is not set
-# CONFIG_USB_OHCI_HCD is not set
-# CONFIG_USB_OHCI_HCD_PCI is not set
-# CONFIG_USB_OHCI_HCD_PPC_OF is not set
-# CONFIG_USB_OHCI_HCD_PPC_OF_BE is not set
-# CONFIG_USB_OHCI_HCD_PPC_OF_LE is not set
-# CONFIG_USB_OHCI_HCD_SSB is not set
-CONFIG_USB_OHCI_LITTLE_ENDIAN=y
-# CONFIG_USB_ONBOARD_HUB is not set
-# CONFIG_USB_OTG is not set
-# CONFIG_USB_OTG_DISABLE_EXTERNAL_HUB is not set
-# CONFIG_USB_OTG_FSM is not set
-# CONFIG_USB_OTG_PRODUCTLIST is not set
-# CONFIG_USB_OXU210HP_HCD is not set
-# CONFIG_USB_PCI is not set
-# CONFIG_USB_PEGASUS is not set
-# CONFIG_USB_PHY is not set
-# CONFIG_USB_PRINTER is not set
-# CONFIG_USB_PWC_INPUT_EVDEV is not set
-# CONFIG_USB_PXA27X is not set
-# CONFIG_USB_QCOM_EUD is not set
-# CONFIG_USB_R8A66597 is not set
-# CONFIG_USB_R8A66597_HCD is not set
-# CONFIG_USB_RAW_GADGET is not set
-# CONFIG_USB_RENESAS_USBHS is not set
-# CONFIG_USB_ROLES_INTEL_XHCI is not set
-# CONFIG_USB_ROLE_SWITCH is not set
-# CONFIG_USB_RTL8150 is not set
-# CONFIG_USB_RTL8152 is not set
-# CONFIG_USB_RTL8153_ECM is not set
-# CONFIG_USB_S2255 is not set
-# CONFIG_USB_SERIAL is not set
-# CONFIG_USB_SERIAL_AIRCABLE is not set
-# CONFIG_USB_SERIAL_ARK3116 is not set
-# CONFIG_USB_SERIAL_BELKIN is not set
-# CONFIG_USB_SERIAL_CH341 is not set
-# CONFIG_USB_SERIAL_CH348 is not set
-# CONFIG_USB_SERIAL_CP210X is not set
-# CONFIG_USB_SERIAL_CYBERJACK is not set
-# CONFIG_USB_SERIAL_CYPRESS_M8 is not set
-# CONFIG_USB_SERIAL_DEBUG is not set
-# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
-# CONFIG_USB_SERIAL_EDGEPORT is not set
-# CONFIG_USB_SERIAL_EDGEPORT_TI is not set
-# CONFIG_USB_SERIAL_EMPEG is not set
-# CONFIG_USB_SERIAL_F81232 is not set
-# CONFIG_USB_SERIAL_F8153X is not set
-# CONFIG_USB_SERIAL_FTDI_SIO is not set
-# CONFIG_USB_SERIAL_GARMIN is not set
-CONFIG_USB_SERIAL_GENERIC=y
-# CONFIG_USB_SERIAL_IPAQ is not set
-# CONFIG_USB_SERIAL_IPW is not set
-# CONFIG_USB_SERIAL_IR is not set
-# CONFIG_USB_SERIAL_IUU is not set
-# CONFIG_USB_SERIAL_KEYSPAN is not set
-# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
-# CONFIG_USB_SERIAL_KLSI is not set
-# CONFIG_USB_SERIAL_KOBIL_SCT is not set
-# CONFIG_USB_SERIAL_MCT_U232 is not set
-# CONFIG_USB_SERIAL_METRO is not set
-# CONFIG_USB_SERIAL_MOS7715_PARPORT is not set
-# CONFIG_USB_SERIAL_MOS7720 is not set
-# CONFIG_USB_SERIAL_MOS7840 is not set
-# CONFIG_USB_SERIAL_MXUPORT is not set
-# CONFIG_USB_SERIAL_NAVMAN is not set
-# CONFIG_USB_SERIAL_OMNINET is not set
-# CONFIG_USB_SERIAL_OPTICON is not set
-# CONFIG_USB_SERIAL_OPTION is not set
-# CONFIG_USB_SERIAL_OTI6858 is not set
-# CONFIG_USB_SERIAL_PL2303 is not set
-# CONFIG_USB_SERIAL_QCAUX is not set
-# CONFIG_USB_SERIAL_QT2 is not set
-# CONFIG_USB_SERIAL_QUALCOMM is not set
-# CONFIG_USB_SERIAL_SAFE is not set
-CONFIG_USB_SERIAL_SAFE_PADDED=y
-# CONFIG_USB_SERIAL_SIERRAWIRELESS is not set
-# CONFIG_USB_SERIAL_SIMPLE is not set
-# CONFIG_USB_SERIAL_SPCP8X5 is not set
-# CONFIG_USB_SERIAL_SSU100 is not set
-# CONFIG_USB_SERIAL_SYMBOL is not set
-# CONFIG_USB_SERIAL_TI is not set
-# CONFIG_USB_SERIAL_UPD78F0730 is not set
-# CONFIG_USB_SERIAL_VISOR is not set
-# CONFIG_USB_SERIAL_WHITEHEAT is not set
-# CONFIG_USB_SERIAL_WISHBONE is not set
-# CONFIG_USB_SERIAL_XR is not set
-# CONFIG_USB_SERIAL_XSENS_MT is not set
-# CONFIG_USB_SEVSEG is not set
-# CONFIG_USB_SIERRA_NET is not set
-# CONFIG_USB_SISUSBVGA is not set
-# CONFIG_USB_SL811_HCD is not set
-# CONFIG_USB_SNP_UDC_PLAT is not set
-# CONFIG_USB_SPEEDTOUCH is not set
-# CONFIG_USB_STORAGE is not set
-# CONFIG_USB_STORAGE_ALAUDA is not set
-# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
-# CONFIG_USB_STORAGE_DATAFAB is not set
-# CONFIG_USB_STORAGE_DEBUG is not set
-# CONFIG_USB_STORAGE_ENE_UB6250 is not set
-# CONFIG_USB_STORAGE_FREECOM is not set
-# CONFIG_USB_STORAGE_ISD200 is not set
-# CONFIG_USB_STORAGE_JUMPSHOT is not set
-# CONFIG_USB_STORAGE_KARMA is not set
-# CONFIG_USB_STORAGE_ONETOUCH is not set
-# CONFIG_USB_STORAGE_REALTEK is not set
-# CONFIG_USB_STORAGE_SDDR09 is not set
-# CONFIG_USB_STORAGE_SDDR55 is not set
-# CONFIG_USB_STORAGE_USBAT is not set
-# CONFIG_USB_STV06XX is not set
-# CONFIG_USB_SUPPORT is not set
-# CONFIG_USB_TEST is not set
-# CONFIG_USB_TMC is not set
-# CONFIG_USB_TRANCEVIBRATOR is not set
-# CONFIG_USB_UAS is not set
-# CONFIG_USB_UEAGLEATM is not set
-# CONFIG_USB_ULPI is not set
-# CONFIG_USB_ULPI_BUS is not set
-# CONFIG_USB_USBNET is not set
-# CONFIG_USB_USS720 is not set
-# CONFIG_USB_VIDEO_CLASS is not set
-CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y
-# CONFIG_USB_VL600 is not set
-# CONFIG_USB_WDM is not set
-# CONFIG_USB_XEN_HCD is not set
-# CONFIG_USB_XHCI_DBGCAP is not set
-# CONFIG_USB_XHCI_HCD is not set
-# CONFIG_USB_XHCI_MVEBU is not set
-# CONFIG_USB_XHCI_PCI_RENESAS is not set
-# CONFIG_USB_XUSBATM is not set
-# CONFIG_USB_YUREX is not set
-# CONFIG_USB_ZD1201 is not set
-# CONFIG_USB_ZERO is not set
-# CONFIG_USELIB is not set
-# CONFIG_USERFAULTFD is not set
-# CONFIG_USERIO is not set
-# CONFIG_USER_DECRYPTED_DATA is not set
-# CONFIG_USER_EVENTS is not set
-# CONFIG_USE_OF is not set
-# CONFIG_UTS_NS is not set
-# CONFIG_U_SERIAL_CONSOLE is not set
-# CONFIG_V4L_MEM2MEM_DRIVERS is not set
-# CONFIG_V4L_PLATFORM_DRIVERS is not set
-# CONFIG_V4L_TEST_DRIVERS is not set
-# CONFIG_VALIDATE_FS_PARSER is not set
-# CONFIG_VBOXGUEST is not set
-# CONFIG_VCAP is not set
-# CONFIG_VCNL3020 is not set
-# CONFIG_VCNL4000 is not set
-# CONFIG_VCNL4035 is not set
-# CONFIG_VCPU_STALL_DETECTOR is not set
-# CONFIG_VDPA is not set
-CONFIG_VDSO=y
-# CONFIG_VEML6030 is not set
-# CONFIG_VEML6070 is not set
-# CONFIG_VETH is not set
-# CONFIG_VEXPRESS_CONFIG is not set
-# CONFIG_VF610_ADC is not set
-# CONFIG_VF610_DAC is not set
-# CONFIG_VFAT_FS is not set
-# CONFIG_VFIO is not set
-# CONFIG_VFIO_FSL_MC is not set
-# CONFIG_VFIO_PLATFORM is not set
-# CONFIG_VGASTATE is not set
-# CONFIG_VGA_ARB is not set
-# CONFIG_VGA_CONSOLE is not set
-# CONFIG_VGA_SWITCHEROO is not set
-# CONFIG_VHOST_CROSS_ENDIAN_LEGACY is not set
-CONFIG_VHOST_MENU=y
-# CONFIG_VHOST_NET is not set
-# CONFIG_VHOST_VSOCK is not set
-# CONFIG_VIA_RHINE is not set
-# CONFIG_VIA_VELOCITY is not set
-# CONFIG_VIDEO_AD5820 is not set
-# CONFIG_VIDEO_ADP1653 is not set
-# CONFIG_VIDEO_ADV7170 is not set
-# CONFIG_VIDEO_ADV7175 is not set
-# CONFIG_VIDEO_ADV7180 is not set
-# CONFIG_VIDEO_ADV7183 is not set
-# CONFIG_VIDEO_ADV7343 is not set
-# CONFIG_VIDEO_ADV7393 is not set
-# CONFIG_VIDEO_ADV748X is not set
-# CONFIG_VIDEO_ADV7511 is not set
-# CONFIG_VIDEO_ADV7604 is not set
-# CONFIG_VIDEO_ADV7842 is not set
-# CONFIG_VIDEO_ADV_DEBUG is not set
-# CONFIG_VIDEO_AK7375 is not set
-# CONFIG_VIDEO_AK881X is not set
-# CONFIG_VIDEO_AM437X_VPFE is not set
-# CONFIG_VIDEO_AR0521 is not set
-# CONFIG_VIDEO_ASPEED is not set
-# CONFIG_VIDEO_ATMEL_ISC is not set
-# CONFIG_VIDEO_ATMEL_ISI is not set
-# CONFIG_VIDEO_AU0828 is not set
-# CONFIG_VIDEO_BCM2835 is not set
-# CONFIG_VIDEO_BT819 is not set
-# CONFIG_VIDEO_BT848 is not set
-# CONFIG_VIDEO_BT856 is not set
-# CONFIG_VIDEO_BT866 is not set
-# CONFIG_VIDEO_CADENCE_CSI2RX is not set
-# CONFIG_VIDEO_CADENCE_CSI2TX is not set
-# CONFIG_VIDEO_CAFE_CCIC is not set
-# CONFIG_VIDEO_CAMERA_SENSOR is not set
-# CONFIG_VIDEO_CCS is not set
-# CONFIG_VIDEO_COBALT is not set
-# CONFIG_VIDEO_CODA is not set
-# CONFIG_VIDEO_CS3308 is not set
-# CONFIG_VIDEO_CS5345 is not set
-# CONFIG_VIDEO_CS53L32A is not set
-# CONFIG_VIDEO_CX231XX is not set
-# CONFIG_VIDEO_CX2341X is not set
-# CONFIG_VIDEO_CX25821 is not set
-# CONFIG_VIDEO_CX25840 is not set
-# CONFIG_VIDEO_CX88 is not set
-# CONFIG_VIDEO_DEV is not set
-# CONFIG_VIDEO_DS90UB913 is not set
-# CONFIG_VIDEO_DS90UB953 is not set
-# CONFIG_VIDEO_DS90UB960 is not set
-# CONFIG_VIDEO_DT3155 is not set
-# CONFIG_VIDEO_DW9714 is not set
-# CONFIG_VIDEO_DW9719 is not set
-# CONFIG_VIDEO_DW9768 is not set
-# CONFIG_VIDEO_DW9807_VCM is not set
-# CONFIG_VIDEO_EM28XX is not set
-# CONFIG_VIDEO_ET8EK8 is not set
-# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set
-# CONFIG_VIDEO_GO7007 is not set
-# CONFIG_VIDEO_GS1662 is not set
-# CONFIG_VIDEO_HDPVR is not set
-# CONFIG_VIDEO_HEXIUM_GEMINI is not set
-# CONFIG_VIDEO_HEXIUM_ORION is not set
-# CONFIG_VIDEO_HI556 is not set
-# CONFIG_VIDEO_HI846 is not set
-# CONFIG_VIDEO_HI847 is not set
-# CONFIG_VIDEO_I2C is not set
-# CONFIG_VIDEO_IMX208 is not set
-# CONFIG_VIDEO_IMX214 is not set
-# CONFIG_VIDEO_IMX219 is not set
-# CONFIG_VIDEO_IMX258 is not set
-# CONFIG_VIDEO_IMX274 is not set
-# CONFIG_VIDEO_IMX290 is not set
-# CONFIG_VIDEO_IMX296 is not set
-# CONFIG_VIDEO_IMX319 is not set
-# CONFIG_VIDEO_IMX334 is not set
-# CONFIG_VIDEO_IMX335 is not set
-# CONFIG_VIDEO_IMX355 is not set
-# CONFIG_VIDEO_IMX412 is not set
-# CONFIG_VIDEO_IMX7_CSI is not set
-# CONFIG_VIDEO_IMX8MQ_MIPI_CSI2 is not set
-# CONFIG_VIDEO_IMX8_ISI is not set
-# CONFIG_VIDEO_IMX8_JPEG is not set
-# CONFIG_VIDEO_IMX_MIPI_CSIS is not set
-# CONFIG_VIDEO_IMX_PXP is not set
-# CONFIG_VIDEO_IR_I2C is not set
-# CONFIG_VIDEO_ISL7998X is not set
-# CONFIG_VIDEO_IVTV is not set
-# CONFIG_VIDEO_KS0127 is not set
-# CONFIG_VIDEO_LM3560 is not set
-# CONFIG_VIDEO_LM3646 is not set
-# CONFIG_VIDEO_M52790 is not set
-# CONFIG_VIDEO_MAX9286 is not set
-# CONFIG_VIDEO_MEM2MEM_DEINTERLACE is not set
-# CONFIG_VIDEO_ML86V7667 is not set
-# CONFIG_VIDEO_MSP3400 is not set
-# CONFIG_VIDEO_MT9M001 is not set
-# CONFIG_VIDEO_MT9M111 is not set
-# CONFIG_VIDEO_MT9P031 is not set
-# CONFIG_VIDEO_MT9T112 is not set
-# CONFIG_VIDEO_MT9V011 is not set
-# CONFIG_VIDEO_MT9V032 is not set
-# CONFIG_VIDEO_MT9V111 is not set
-# CONFIG_VIDEO_MUX is not set
-# CONFIG_VIDEO_MXB is not set
-# CONFIG_VIDEO_OG01A1B is not set
-# CONFIG_VIDEO_OMAP2_VOUT is not set
-# CONFIG_VIDEO_OV02A10 is not set
-# CONFIG_VIDEO_OV08D10 is not set
-# CONFIG_VIDEO_OV13858 is not set
-# CONFIG_VIDEO_OV13B10 is not set
-# CONFIG_VIDEO_OV2640 is not set
-# CONFIG_VIDEO_OV2659 is not set
-# CONFIG_VIDEO_OV2680 is not set
-# CONFIG_VIDEO_OV2685 is not set
-# CONFIG_VIDEO_OV2740 is not set
-# CONFIG_VIDEO_OV5640 is not set
-# CONFIG_VIDEO_OV5645 is not set
-# CONFIG_VIDEO_OV5647 is not set
-# CONFIG_VIDEO_OV5648 is not set
-# CONFIG_VIDEO_OV5670 is not set
-# CONFIG_VIDEO_OV5675 is not set
-# CONFIG_VIDEO_OV5693 is not set
-# CONFIG_VIDEO_OV5695 is not set
-# CONFIG_VIDEO_OV6650 is not set
-# CONFIG_VIDEO_OV7251 is not set
-# CONFIG_VIDEO_OV7640 is not set
-# CONFIG_VIDEO_OV7670 is not set
-# CONFIG_VIDEO_OV772X is not set
-# CONFIG_VIDEO_OV7740 is not set
-# CONFIG_VIDEO_OV8856 is not set
-# CONFIG_VIDEO_OV8865 is not set
-# CONFIG_VIDEO_OV9282 is not set
-# CONFIG_VIDEO_OV9640 is not set
-# CONFIG_VIDEO_OV9650 is not set
-# CONFIG_VIDEO_OV9734 is not set
-# CONFIG_VIDEO_PVRUSB2 is not set
-# CONFIG_VIDEO_RCAR_CSI2 is not set
-# CONFIG_VIDEO_RCAR_ISP is not set
-# CONFIG_VIDEO_RCAR_VIN is not set
-# CONFIG_VIDEO_RDACM20 is not set
-# CONFIG_VIDEO_RDACM21 is not set
-# CONFIG_VIDEO_RJ54N1 is not set
-# CONFIG_VIDEO_ROCKCHIP_ISP1 is not set
-# CONFIG_VIDEO_S5C73M3 is not set
-# CONFIG_VIDEO_S5K5BAF is not set
-# CONFIG_VIDEO_S5K6A3 is not set
-# CONFIG_VIDEO_SAA6588 is not set
-# CONFIG_VIDEO_SAA6752HS is not set
-# CONFIG_VIDEO_SAA7110 is not set
-# CONFIG_VIDEO_SAA711X is not set
-# CONFIG_VIDEO_SAA7127 is not set
-# CONFIG_VIDEO_SAA7134 is not set
-# CONFIG_VIDEO_SAA7164 is not set
-# CONFIG_VIDEO_SAA717X is not set
-# CONFIG_VIDEO_SAA7185 is not set
-# CONFIG_VIDEO_SOLO6X10 is not set
-# CONFIG_VIDEO_SONY_BTF_MPX is not set
-# CONFIG_VIDEO_STK1160 is not set
-# CONFIG_VIDEO_ST_MIPID02 is not set
-# CONFIG_VIDEO_SUN4I_CSI is not set
-# CONFIG_VIDEO_SUN6I_CSI is not set
-# CONFIG_VIDEO_SUN8I_A83T_MIPI_CSI2 is not set
-# CONFIG_VIDEO_TC358743 is not set
-# CONFIG_VIDEO_TC358746 is not set
-# CONFIG_VIDEO_TDA1997X is not set
-# CONFIG_VIDEO_TDA7432 is not set
-# CONFIG_VIDEO_TDA9840 is not set
-# CONFIG_VIDEO_TEA6415C is not set
-# CONFIG_VIDEO_TEA6420 is not set
-# CONFIG_VIDEO_THS7303 is not set
-# CONFIG_VIDEO_THS8200 is not set
-# CONFIG_VIDEO_TLV320AIC23B is not set
-# CONFIG_VIDEO_TVAUDIO is not set
-# CONFIG_VIDEO_TVP514X is not set
-# CONFIG_VIDEO_TVP5150 is not set
-# CONFIG_VIDEO_TVP7002 is not set
-# CONFIG_VIDEO_TW2804 is not set
-# CONFIG_VIDEO_TW5864 is not set
-# CONFIG_VIDEO_TW68 is not set
-# CONFIG_VIDEO_TW9903 is not set
-# CONFIG_VIDEO_TW9906 is not set
-# CONFIG_VIDEO_TW9910 is not set
-# CONFIG_VIDEO_UDA1342 is not set
-# CONFIG_VIDEO_UPD64031A is not set
-# CONFIG_VIDEO_UPD64083 is not set
-# CONFIG_VIDEO_USBTV is not set
-# CONFIG_VIDEO_VP27SMPX is not set
-# CONFIG_VIDEO_VPX3220 is not set
-# CONFIG_VIDEO_WM8739 is not set
-# CONFIG_VIDEO_WM8775 is not set
-# CONFIG_VIDEO_XILINX is not set
-# CONFIG_VIDEO_ZORAN is not set
-# CONFIG_VIRTIO_BALLOON is not set
-# CONFIG_VIRTIO_CONSOLE is not set
-# CONFIG_VIRTIO_FS is not set
-# CONFIG_VIRTIO_INPUT is not set
-CONFIG_VIRTIO_MENU=y
-# CONFIG_VIRTIO_MMIO is not set
-# CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES is not set
-# CONFIG_VIRTIO_PCI is not set
-# CONFIG_VIRTUALIZATION is not set
-# CONFIG_VIRT_CPU_ACCOUNTING_GEN is not set
-# CONFIG_VIRT_DRIVERS is not set
-# CONFIG_VITESSE_PHY is not set
-# CONFIG_VL53L0X_I2C is not set
-# CONFIG_VL6180 is not set
-CONFIG_VLAN_8021Q=y
-# CONFIG_VLAN_8021Q_GVRP is not set
-# CONFIG_VLAN_8021Q_MVRP is not set
-# CONFIG_VMAP_STACK is not set
-# CONFIG_VME_BUS is not set
-# CONFIG_VMLINUX_MAP is not set
-# CONFIG_VMSPLIT_1G is not set
-# CONFIG_VMSPLIT_2G is not set
-# CONFIG_VMSPLIT_2G_OPT is not set
-CONFIG_VMSPLIT_3G=y
-# CONFIG_VMSPLIT_3G_OPT is not set
-# CONFIG_VMWARE_PVSCSI is not set
-# CONFIG_VMWARE_VMCI is not set
-# CONFIG_VMXNET3 is not set
-# CONFIG_VM_EVENT_COUNTERS is not set
-# CONFIG_VORTEX is not set
-# CONFIG_VSOCKETS is not set
-# CONFIG_VSOCKETS_DIAG is not set
-# CONFIG_VT is not set
-# CONFIG_VT6655 is not set
-# CONFIG_VT6656 is not set
-# CONFIG_VXFS_FS is not set
-# CONFIG_VXLAN is not set
-# CONFIG_VZ89X is not set
-# CONFIG_W1 is not set
-# CONFIG_W1_CON is not set
-# CONFIG_W1_MASTER_DS2482 is not set
-# CONFIG_W1_MASTER_DS2490 is not set
-# CONFIG_W1_MASTER_GPIO is not set
-# CONFIG_W1_MASTER_MATROX is not set
-# CONFIG_W1_MASTER_SGI is not set
-# CONFIG_W1_SLAVE_DS2405 is not set
-# CONFIG_W1_SLAVE_DS2406 is not set
-# CONFIG_W1_SLAVE_DS2408 is not set
-# CONFIG_W1_SLAVE_DS2413 is not set
-# CONFIG_W1_SLAVE_DS2423 is not set
-# CONFIG_W1_SLAVE_DS2430 is not set
-# CONFIG_W1_SLAVE_DS2431 is not set
-# CONFIG_W1_SLAVE_DS2433 is not set
-# CONFIG_W1_SLAVE_DS2438 is not set
-# CONFIG_W1_SLAVE_DS250X is not set
-# CONFIG_W1_SLAVE_DS2780 is not set
-# CONFIG_W1_SLAVE_DS2781 is not set
-# CONFIG_W1_SLAVE_DS2805 is not set
-# CONFIG_W1_SLAVE_DS28E04 is not set
-# CONFIG_W1_SLAVE_DS28E17 is not set
-# CONFIG_W1_SLAVE_SMEM is not set
-# CONFIG_W1_SLAVE_THERM is not set
-# CONFIG_W83627HF_WDT is not set
-# CONFIG_W83877F_WDT is not set
-# CONFIG_W83977F_WDT is not set
-# CONFIG_WAN is not set
-# CONFIG_WANXL is not set
-# CONFIG_WARN_ALL_UNSEEDED_RANDOM is not set
-CONFIG_WATCHDOG=y
-# CONFIG_WATCHDOG_CORE is not set
-CONFIG_WATCHDOG_HANDLE_BOOT_ENABLED=y
-# CONFIG_WATCHDOG_HRTIMER_PRETIMEOUT is not set
-# CONFIG_WATCHDOG_NOWAYOUT is not set
-CONFIG_WATCHDOG_OPEN_TIMEOUT=0
-# CONFIG_WATCHDOG_PRETIMEOUT_GOV is not set
-# CONFIG_WATCHDOG_SYSFS is not set
-# CONFIG_WATCH_QUEUE is not set
-# CONFIG_WD80x3 is not set
-# CONFIG_WDAT_WDT is not set
-# CONFIG_WDTPCI is not set
-# CONFIG_WERROR is not set
-# CONFIG_WEXT_CORE is not set
-# CONFIG_WEXT_PRIV is not set
-# CONFIG_WEXT_PROC is not set
-# CONFIG_WEXT_SPY is not set
-# CONFIG_WIREGUARD is not set
-CONFIG_WIRELESS=y
-# CONFIG_WIRELESS_EXT is not set
-# CONFIG_WIZNET_W5100 is not set
-# CONFIG_WIZNET_W5300 is not set
-# CONFIG_WL1251 is not set
-# CONFIG_WL12XX is not set
-# CONFIG_WL18XX is not set
-CONFIG_WLAN=y
-# CONFIG_WLAN_VENDOR_ADMTEK is not set
-# CONFIG_WLAN_VENDOR_ATH is not set
-# CONFIG_WLAN_VENDOR_ATMEL is not set
-# CONFIG_WLAN_VENDOR_BROADCOM is not set
-# CONFIG_WLAN_VENDOR_CISCO is not set
-# CONFIG_WLAN_VENDOR_INTEL is not set
-# CONFIG_WLAN_VENDOR_INTERSIL is not set
-# CONFIG_WLAN_VENDOR_MARVELL is not set
-# CONFIG_WLAN_VENDOR_MEDIATEK is not set
-# CONFIG_WLAN_VENDOR_MICROCHIP is not set
-# CONFIG_WLAN_VENDOR_PURELIFI is not set
-# CONFIG_WLAN_VENDOR_QUANTENNA is not set
-# CONFIG_WLAN_VENDOR_RALINK is not set
-# CONFIG_WLAN_VENDOR_REALTEK is not set
-# CONFIG_WLAN_VENDOR_RSI is not set
-# CONFIG_WLAN_VENDOR_SILABS is not set
-# CONFIG_WLAN_VENDOR_ST is not set
-# CONFIG_WLAN_VENDOR_TI is not set
-# CONFIG_WLAN_VENDOR_ZYDAS is not set
-# CONFIG_WLCORE is not set
-# CONFIG_WPCM450_SOC is not set
-# CONFIG_WQ_CPU_INTENSIVE_REPORT is not set
-CONFIG_WQ_POWER_EFFICIENT_DEFAULT=y
-# CONFIG_WQ_WATCHDOG is not set
-# CONFIG_WWAN is not set
-# CONFIG_WWAN_HWSIM is not set
-# CONFIG_WW_MUTEX_SELFTEST is not set
-# CONFIG_X25 is not set
-# CONFIG_X509_CERTIFICATE_PARSER is not set
-# CONFIG_X86_PKG_TEMP_THERMAL is not set
-# CONFIG_X9250 is not set
-# CONFIG_XDP_SOCKETS is not set
-# CONFIG_XEN is not set
-# CONFIG_XEN_GRANT_DMA_ALLOC is not set
-# CONFIG_XEN_PVCALLS_FRONTEND is not set
-CONFIG_XEN_SCRUB_PAGES_DEFAULT=y
-CONFIG_XFRM=y
-# CONFIG_XFRM_INTERFACE is not set
-# CONFIG_XFRM_IPCOMP is not set
-# CONFIG_XFRM_MIGRATE is not set
-# CONFIG_XFRM_STATISTICS is not set
-# CONFIG_XFRM_SUB_POLICY is not set
-# CONFIG_XFRM_USER is not set
-# CONFIG_XFS_DEBUG is not set
-# CONFIG_XFS_FS is not set
-# CONFIG_XFS_ONLINE_SCRUB is not set
-# CONFIG_XFS_POSIX_ACL is not set
-# CONFIG_XFS_QUOTA is not set
-# CONFIG_XFS_RT is not set
-# CONFIG_XFS_SUPPORT_ASCII_CI is not set
-# CONFIG_XFS_SUPPORT_V4 is not set
-# CONFIG_XFS_WARN is not set
-# CONFIG_XILINX_AXI_EMAC is not set
-# CONFIG_XILINX_DMA is not set
-# CONFIG_XILINX_EMACLITE is not set
-# CONFIG_XILINX_GMII2RGMII is not set
-# CONFIG_XILINX_INTC is not set
-# CONFIG_XILINX_LL_TEMAC is not set
-# CONFIG_XILINX_SDFEC is not set
-# CONFIG_XILINX_VCU is not set
-# CONFIG_XILINX_WATCHDOG is not set
-# CONFIG_XILINX_WINDOW_WATCHDOG is not set
-# CONFIG_XILINX_XADC is not set
-# CONFIG_XILINX_XDMA is not set
-# CONFIG_XILINX_ZYNQMP_DMA is not set
-# CONFIG_XILINX_ZYNQMP_DPDMA is not set
-# CONFIG_XILLYBUS is not set
-# CONFIG_XILLYUSB is not set
-# CONFIG_XIL_AXIS_FIFO is not set
-# CONFIG_XIP_KERNEL is not set
-# CONFIG_XMON is not set
-CONFIG_XZ_DEC=y
-# CONFIG_XZ_DEC_ARM is not set
-# CONFIG_XZ_DEC_ARMTHUMB is not set
-# CONFIG_XZ_DEC_BCJ is not set
-# CONFIG_XZ_DEC_IA64 is not set
-# CONFIG_XZ_DEC_MICROLZMA is not set
-# CONFIG_XZ_DEC_POWERPC is not set
-# CONFIG_XZ_DEC_SPARC is not set
-# CONFIG_XZ_DEC_TEST is not set
-# CONFIG_XZ_DEC_X86 is not set
-# CONFIG_YAM is not set
-# CONFIG_YAMAHA_YAS530 is not set
-# CONFIG_YELLOWFIN is not set
-# CONFIG_YENTA is not set
-# CONFIG_YENTA_O2 is not set
-# CONFIG_YENTA_RICOH is not set
-# CONFIG_YENTA_TI is not set
-# CONFIG_YENTA_TOSHIBA is not set
-# CONFIG_ZBUD is not set
-# CONFIG_ZD1211RW is not set
-# CONFIG_ZD1211RW_DEBUG is not set
-# CONFIG_ZEROPLUS_FF is not set
-# CONFIG_ZERO_CALL_USED_REGS is not set
-# CONFIG_ZIIRAVE_WATCHDOG is not set
-# CONFIG_ZISOFS is not set
-# CONFIG_ZLIB_DEFLATE is not set
-# CONFIG_ZLIB_INFLATE is not set
-CONFIG_ZONE_DMA=y
-# CONFIG_ZOPT2201 is not set
-# CONFIG_ZPA2326 is not set
-# CONFIG_ZPOOL is not set
-# CONFIG_ZRAM is not set
-# CONFIG_ZRAM_DEF_COMP_842 is not set
-# CONFIG_ZRAM_DEF_COMP_LZ4 is not set
-# CONFIG_ZRAM_DEF_COMP_LZ4HC is not set
-# CONFIG_ZRAM_DEF_COMP_LZO is not set
-# CONFIG_ZRAM_DEF_COMP_LZORLE is not set
-# CONFIG_ZRAM_DEF_COMP_ZSTD is not set
-# CONFIG_ZRAM_MEMORY_TRACKING is not set
-# CONFIG_ZRAM_MULTI_COMP is not set
-# CONFIG_ZRAM_TRACK_ENTRY_ACTIME is not set
-# CONFIG_ZSMALLOC is not set
-CONFIG_ZSMALLOC_CHAIN_SIZE=8
-# CONFIG_ZSWAP is not set
+++ /dev/null
-From a7ae4ed0a3951c45d4a59ee575951b64ae4a23fb Mon Sep 17 00:00:00 2001
-Date: Tue, 7 May 2024 12:22:15 +0200
-Subject: [PATCH] kernel: fix tools build breakage on macos with x86
-
----
---- a/tools/scripts/Makefile.include
-+++ b/tools/scripts/Makefile.include
-@@ -72,8 +72,6 @@ $(call allow-override,CXX,$(CROSS_COMPIL
- $(call allow-override,STRIP,$(CROSS_COMPILE)strip)
- endif
-
--CC_NO_CLANG := $(shell $(CC) -dM -E -x c /dev/null | grep -Fq "__clang__"; echo $$?)
--
- ifneq ($(LLVM),)
- HOSTAR ?= $(LLVM_PREFIX)llvm-ar$(LLVM_SUFFIX)
- HOSTCC ?= $(LLVM_PREFIX)clang$(LLVM_SUFFIX)
-@@ -84,6 +82,9 @@ HOSTCC ?= gcc
- HOSTLD ?= ld
- endif
-
-+CC_NO_CLANG := $(shell $(CC) -dM -E -x c /dev/null | grep -Fq "__clang__"; echo $$?)
-+HOSTCC_NO_CLANG := $(shell $(HOSTCC) -dM -E -x c /dev/null | grep -Fq "__clang__"; echo $$?)
-+
- # Some tools require Clang, LLC and/or LLVM utils
- CLANG ?= clang
- LLC ?= llc
-@@ -92,8 +93,9 @@ LLVM_OBJCOPY ?= llvm-objcopy
- LLVM_STRIP ?= llvm-strip
-
- ifeq ($(CC_NO_CLANG), 1)
--EXTRA_WARNINGS += -Wstrict-aliasing=3
--
-+ ifeq ($(HOSTCC_NO_CLANG), 1)
-+ EXTRA_WARNINGS += -Wstrict-aliasing=3
-+ endif
- else ifneq ($(CROSS_COMPILE),)
- # Allow userspace to override CLANG_CROSS_FLAGS to specify their own
- # sysroots and flags or to avoid the GCC call in pure Clang builds.
---- a/tools/include/linux/types.h
-+++ b/tools/include/linux/types.h
-@@ -10,8 +10,12 @@
- #define __SANE_USERSPACE_TYPES__ /* For PPC64, to get LL64 types */
- #endif
-
-+#ifndef __linux__
-+#include <tools/linux_types.h>
-+#else
- #include <asm/types.h>
- #include <asm/posix_types.h>
-+#endif
-
- struct page;
- struct kmem_cache;
-@@ -56,6 +60,7 @@ typedef __s8 s8;
- #define __user
- #endif
- #define __must_check
-+#undef __cold
- #define __cold
-
- typedef __u16 __bitwise __le16;
---- a/tools/lib/subcmd/exec-cmd.c
-+++ b/tools/lib/subcmd/exec-cmd.c
-@@ -12,7 +12,10 @@
- #include "subcmd-config.h"
-
- #define MAX_ARGS 32
-+
-+#ifndef PATH_MAX
- #define PATH_MAX 4096
-+#endif
-
- static const char *argv_exec_path;
- static const char *argv0_path;
---- a/tools/objtool/include/objtool/objtool.h
-+++ b/tools/objtool/include/objtool/objtool.h
-@@ -12,6 +12,7 @@
-
- #include <objtool/elf.h>
-
-+#undef __weak
- #define __weak __attribute__((weak))
-
- struct pv_state {
---- a/tools/include/asm-generic/bitops/fls.h
-+++ b/tools/include/asm-generic/bitops/fls.h
-@@ -2,6 +2,8 @@
- #ifndef _ASM_GENERIC_BITOPS_FLS_H_
- #define _ASM_GENERIC_BITOPS_FLS_H_
-
-+#include <string.h>
-+
- /**
- * fls - find last (most-significant) bit set
- * @x: the word to search
-@@ -10,6 +12,7 @@
- * Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32.
- */
-
-+#define fls __linux_fls
- static __always_inline int fls(unsigned int x)
- {
- int r = 32;
---- a/tools/lib/string.c
-+++ b/tools/lib/string.c
-@@ -96,6 +96,7 @@ int strtobool(const char *s, bool *res)
- * If libc has strlcpy() then that version will override this
- * implementation:
- */
-+#ifndef __APPLE__
- #ifdef __clang__
- #pragma clang diagnostic push
- #pragma clang diagnostic ignored "-Wignored-attributes"
-@@ -114,6 +115,7 @@ size_t __weak strlcpy(char *dest, const
- #ifdef __clang__
- #pragma clang diagnostic pop
- #endif
-+#endif
-
- /**
- * skip_spaces - Removes leading whitespace from @str.
---- a/tools/arch/x86/include/asm/insn.h
-+++ b/tools/arch/x86/include/asm/insn.h
-@@ -7,7 +7,7 @@
- * Copyright (C) IBM Corporation, 2009
- */
-
--#include <asm/byteorder.h>
-+#include <linux/kernel.h>
- /* insn_attr_t is defined in inat.h */
- #include "inat.h" /* __ignore_sync_check__ */
-
---- a/tools/arch/x86/include/asm/orc_types.h
-+++ b/tools/arch/x86/include/asm/orc_types.h
-@@ -46,7 +46,6 @@
- #define ORC_TYPE_REGS_PARTIAL 4
-
- #ifndef __ASSEMBLY__
--#include <asm/byteorder.h>
-
- /*
- * This struct is more or less a vastly simplified version of the DWARF Call
-@@ -59,12 +58,12 @@
- struct orc_entry {
- s16 sp_offset;
- s16 bp_offset;
--#if defined(__LITTLE_ENDIAN_BITFIELD)
-+#if __BYTE_ORDER == __LITTLE_ENDIAN
- unsigned sp_reg:4;
- unsigned bp_reg:4;
- unsigned type:3;
- unsigned signal:1;
--#elif defined(__BIG_ENDIAN_BITFIELD)
-+#elif __BYTE_ORDER == __BIG_ENDIAN
- unsigned bp_reg:4;
- unsigned sp_reg:4;
- unsigned unused:4;
---- a/tools/include/linux/rbtree.h
-+++ b/tools/include/linux/rbtree.h
-@@ -18,7 +18,6 @@
- #define __TOOLS_LINUX_PERF_RBTREE_H
-
- #include <linux/kernel.h>
--#include <linux/stddef.h>
-
- struct rb_node {
- unsigned long __rb_parent_color;
---- a/tools/include/tools/be_byteshift.h
-+++ b/tools/include/tools/be_byteshift.h
-@@ -2,6 +2,10 @@
- #ifndef _TOOLS_BE_BYTESHIFT_H
- #define _TOOLS_BE_BYTESHIFT_H
-
-+#ifndef __linux__
-+#include "linux_types.h"
-+#endif
-+
- #include <stdint.h>
-
- static inline uint16_t __get_unaligned_be16(const uint8_t *p)
---- a/tools/include/tools/le_byteshift.h
-+++ b/tools/include/tools/le_byteshift.h
-@@ -2,6 +2,10 @@
- #ifndef _TOOLS_LE_BYTESHIFT_H
- #define _TOOLS_LE_BYTESHIFT_H
-
-+#ifndef __linux__
-+#include "linux_types.h"
-+#endif
-+
- #include <stdint.h>
-
- static inline uint16_t __get_unaligned_le16(const uint8_t *p)
---- /dev/null
-+++ b/tools/include/tools/linux_types.h
-@@ -0,0 +1,18 @@
-+#ifndef __LINUX_TYPES_H
-+#define __LINUX_TYPES_H
-+
-+#include <stdint.h>
-+
-+typedef int8_t __s8;
-+typedef uint8_t __u8;
-+
-+typedef int16_t __s16;
-+typedef uint16_t __u16;
-+
-+typedef int32_t __s32;
-+typedef uint32_t __u32;
-+
-+typedef int64_t __s64;
-+typedef uint64_t __u64;
-+
-+#endif
---- a/tools/objtool/Makefile
-+++ b/tools/objtool/Makefile
-@@ -39,6 +39,8 @@ OBJTOOL_LDFLAGS := $(LIBELF_LIBS) $(LIBS
- elfshdr := $(shell echo '$(pound)include <libelf.h>' | $(HOSTCC) $(OBJTOOL_CFLAGS) -x c -E - | grep elf_getshdr)
- OBJTOOL_CFLAGS += $(if $(elfshdr),,-DLIBELF_USE_DEPRECATED)
-
-+OBJTOOL_CFLAGS += $(HOST_EXTRACFLAGS)
-+
- # Always want host compilation.
- HOST_OVERRIDES := CC="$(HOSTCC)" LD="$(HOSTLD)" AR="$(HOSTAR)"
-
---- a/tools/objtool/orc_dump.c
-+++ b/tools/objtool/orc_dump.c
-@@ -4,10 +4,10 @@
- */
-
- #include <unistd.h>
--#include <asm/orc_types.h>
- #include <objtool/objtool.h>
- #include <objtool/warn.h>
- #include <objtool/endianness.h>
-+#include <asm/orc_types.h>
-
- static const char *reg_name(unsigned int reg)
- {
---- a/tools/objtool/orc_gen.c
-+++ b/tools/objtool/orc_gen.c
-@@ -7,11 +7,11 @@
- #include <string.h>
-
- #include <linux/objtool_types.h>
--#include <asm/orc_types.h>
-
- #include <objtool/check.h>
- #include <objtool/warn.h>
- #include <objtool/endianness.h>
-+#include <asm/orc_types.h>
-
- static int init_orc_entry(struct orc_entry *orc, struct cfi_state *cfi,
- struct instruction *insn)
---- a/tools/arch/x86/lib/insn.c
-+++ b/tools/arch/x86/lib/insn.c
-@@ -15,7 +15,11 @@
- #include "../include/asm/insn.h" /* __ignore_sync_check__ */
- #include "../include/asm-generic/unaligned.h" /* __ignore_sync_check__ */
-
-+#ifdef __KERNEL__
- #include <linux/errno.h>
-+#else
-+#include <errno.h>
-+#endif
- #include <linux/kconfig.h>
-
- #include "../include/asm/emulate_prefix.h" /* __ignore_sync_check__ */
+++ /dev/null
-From a779a482fb9b9f8fcdf8b2519c789b4b9bb5dd05 Mon Sep 17 00:00:00 2001
-Date: Fri, 7 Jul 2017 16:56:48 +0200
-Subject: build: add a hack for removing non-essential module info
-
----
- include/linux/module.h | 13 ++++++++-----
- include/linux/moduleparam.h | 15 ++++++++++++---
- init/Kconfig | 7 +++++++
- kernel/module.c | 5 ++++-
- scripts/mod/modpost.c | 12 ++++++++++++
- 5 files changed, 43 insertions(+), 9 deletions(-)
-
---- a/include/linux/module.h
-+++ b/include/linux/module.h
-@@ -166,6 +166,7 @@ struct module_kobject *lookup_or_create_
-
- /* Generic info of form tag = "info" */
- #define MODULE_INFO(tag, info) __MODULE_INFO(tag, tag, info)
-+#define MODULE_INFO_STRIP(tag, info) __MODULE_INFO_STRIP(tag, tag, info)
-
- /* For userspace: you can also call me... */
- #define MODULE_ALIAS(_alias) MODULE_INFO(alias, _alias)
-@@ -235,12 +236,12 @@ struct module_kobject *lookup_or_create_
- * Author(s), use "Name <email>" or just "Name", for multiple
- * authors use multiple MODULE_AUTHOR() statements/lines.
- */
--#define MODULE_AUTHOR(_author) MODULE_INFO(author, _author)
-+#define MODULE_AUTHOR(_author) MODULE_INFO_STRIP(author, _author)
-
- /* What your module does. */
--#define MODULE_DESCRIPTION(_description) MODULE_INFO(description, _description)
-+#define MODULE_DESCRIPTION(_description) MODULE_INFO_STRIP(description, _description)
-
--#ifdef MODULE
-+#if defined(MODULE) && !defined(CONFIG_MODULE_STRIPPED)
- /* Creates an alias so file2alias.c can find device table. */
- #define MODULE_DEVICE_TABLE(type, name) \
- extern typeof(name) __mod_##type##__##name##_device_table \
-@@ -267,7 +268,9 @@ extern typeof(name) __mod_##type##__##na
- */
-
- #if defined(MODULE) || !defined(CONFIG_SYSFS)
--#define MODULE_VERSION(_version) MODULE_INFO(version, _version)
-+#define MODULE_VERSION(_version) MODULE_INFO_STRIP(version, _version)
-+#elif defined(CONFIG_MODULE_STRIPPED)
-+#define MODULE_VERSION(_version) __MODULE_INFO_DISABLED(version)
- #else
- #define MODULE_VERSION(_version) \
- MODULE_INFO(version, _version); \
-@@ -290,7 +293,7 @@ extern typeof(name) __mod_##type##__##na
- /* Optional firmware file (or files) needed by the module
- * format is simply firmware file name. Multiple firmware
- * files require multiple MODULE_FIRMWARE() specifiers */
--#define MODULE_FIRMWARE(_firmware) MODULE_INFO(firmware, _firmware)
-+#define MODULE_FIRMWARE(_firmware) MODULE_INFO_STRIP(firmware, _firmware)
-
- #define MODULE_IMPORT_NS(ns) MODULE_INFO(import_ns, __stringify(ns))
-
---- a/include/linux/moduleparam.h
-+++ b/include/linux/moduleparam.h
-@@ -20,6 +20,16 @@
- /* Chosen so that structs with an unsigned long line up. */
- #define MAX_PARAM_PREFIX_LEN (64 - sizeof(unsigned long))
-
-+/* This struct is here for syntactic coherency, it is not used */
-+#define __MODULE_INFO_DISABLED(name) \
-+ struct __UNIQUE_ID(name) {}
-+
-+#ifdef CONFIG_MODULE_STRIPPED
-+#define __MODULE_INFO_STRIP(tag, name, info) __MODULE_INFO_DISABLED(name)
-+#else
-+#define __MODULE_INFO_STRIP(tag, name, info) __MODULE_INFO(tag, name, info)
-+#endif
-+
- #define __MODULE_INFO(tag, name, info) \
- static const char __UNIQUE_ID(name)[] \
- __used __section(".modinfo") __aligned(1) \
-@@ -31,7 +41,7 @@
- /* One for each parameter, describing how to use it. Some files do
- multiple of these per line, so can't just use MODULE_INFO. */
- #define MODULE_PARM_DESC(_parm, desc) \
-- __MODULE_INFO(parm, _parm, #_parm ":" desc)
-+ __MODULE_INFO_STRIP(parm, _parm, #_parm ":" desc)
-
- struct kernel_param;
-
---- a/kernel/module/Kconfig
-+++ b/kernel/module/Kconfig
-@@ -390,4 +390,11 @@ config MODULES_TREE_LOOKUP
- def_bool y
- depends on PERF_EVENTS || TRACING || CFI_CLANG
-
-+config MODULE_STRIPPED
-+ bool "Reduce module size"
-+ depends on MODULES
-+ help
-+ Remove module parameter descriptions, author info, version, aliases,
-+ device tables, etc.
-+
- endif # MODULES
---- a/kernel/module/main.c
-+++ b/kernel/module/main.c
-@@ -999,6 +999,7 @@ size_t modinfo_attrs_count = ARRAY_SIZE(
-
- static const char vermagic[] = VERMAGIC_STRING;
-
-+#if defined(CONFIG_MODVERSIONS) || !defined(CONFIG_MODULE_STRIPPED)
- int try_to_force_load(struct module *mod, const char *reason)
- {
- #ifdef CONFIG_MODULE_FORCE_LOAD
-@@ -1010,6 +1011,7 @@ int try_to_force_load(struct module *mod
- return -ENOEXEC;
- #endif
- }
-+#endif
-
- /* Parse tag=value strings from .modinfo section */
- char *module_next_tag_pair(char *string, unsigned long *secsize)
-@@ -2077,9 +2079,11 @@ static void module_augment_kernel_taints
-
- static int check_modinfo(struct module *mod, struct load_info *info, int flags)
- {
-- const char *modmagic = get_modinfo(info, "vermagic");
- int err;
-
-+#ifndef CONFIG_MODULE_STRIPPED
-+ const char *modmagic = get_modinfo(info, "vermagic");
-+
- if (flags & MODULE_INIT_IGNORE_VERMAGIC)
- modmagic = NULL;
-
-@@ -2093,6 +2097,7 @@ static int check_modinfo(struct module *
- info->name, modmagic, vermagic);
- return -ENOEXEC;
- }
-+#endif
-
- err = check_modinfo_livepatch(mod, info);
- if (err)
---- a/scripts/mod/modpost.c
-+++ b/scripts/mod/modpost.c
-@@ -1666,7 +1666,9 @@ static void read_symbols(const char *mod
- symname = remove_dot(info.strtab + sym->st_name);
-
- handle_symbol(mod, &info, sym, symname);
-+#ifndef CONFIG_MODULE_STRIPPED
- handle_moddevtable(mod, &info, sym, symname);
-+#endif
- }
-
- check_sec_ref(mod, &info);
-@@ -1839,8 +1841,10 @@ static void add_header(struct buffer *b,
- buf_printf(b, "BUILD_SALT;\n");
- buf_printf(b, "BUILD_LTO_INFO;\n");
- buf_printf(b, "\n");
-+#ifndef CONFIG_MODULE_STRIPPED
- buf_printf(b, "MODULE_INFO(vermagic, VERMAGIC_STRING);\n");
- buf_printf(b, "MODULE_INFO(name, KBUILD_MODNAME);\n");
-+#endif
- buf_printf(b, "\n");
- buf_printf(b, "__visible struct module __this_module\n");
- buf_printf(b, "__section(\".gnu.linkonce.this_module\") = {\n");
-@@ -1854,8 +1858,10 @@ static void add_header(struct buffer *b,
- buf_printf(b, "\t.arch = MODULE_ARCH_INIT,\n");
- buf_printf(b, "};\n");
-
-+#ifndef CONFIG_MODULE_STRIPPED
- if (!external_module)
- buf_printf(b, "\nMODULE_INFO(intree, \"Y\");\n");
-+#endif
-
- buf_printf(b,
- "\n"
-@@ -1863,8 +1869,10 @@ static void add_header(struct buffer *b,
- "MODULE_INFO(retpoline, \"Y\");\n"
- "#endif\n");
-
-+#ifndef CONFIG_MODULE_STRIPPED
- if (strstarts(mod->name, "drivers/staging"))
- buf_printf(b, "\nMODULE_INFO(staging, \"Y\");\n");
-+#endif
-
- if (strstarts(mod->name, "tools/testing"))
- buf_printf(b, "\nMODULE_INFO(test, \"Y\");\n");
-@@ -1974,11 +1982,13 @@ static void add_depends(struct buffer *b
-
- static void add_srcversion(struct buffer *b, struct module *mod)
- {
-+#ifndef CONFIG_MODULE_STRIPPED
- if (mod->srcversion[0]) {
- buf_printf(b, "\n");
- buf_printf(b, "MODULE_INFO(srcversion, \"%s\");\n",
- mod->srcversion);
- }
-+#endif
- }
-
- static void write_buf(struct buffer *b, const char *fname)
-@@ -2061,7 +2071,9 @@ static void write_mod_c_file(struct modu
- add_exported_symbols(&buf, mod);
- add_versions(&buf, mod);
- add_depends(&buf, mod);
-+#ifndef CONFIG_MODULE_STRIPPED
- add_moddevtable(&buf, mod);
-+#endif
- add_srcversion(&buf, mod);
-
- ret = snprintf(fname, sizeof(fname), "%s.mod.c", mod->name);
+++ /dev/null
-From 310e8e04a05d9eb43fa9dd7f00143300afcaa37a Mon Sep 17 00:00:00 2001
-Date: Fri, 11 Nov 2022 13:33:44 +0100
-Subject: [PATCH] kconfig: abort configuration on unset symbol
-
-When a target configuration has unset Kconfig symbols, the build will
-fail when OpenWrt is compiled with V=s and stdin is connected to a tty.
-
-In case OpenWrt is compiled without either of these preconditions, the
-build will succeed with the symbols in question being unset.
-
-Modify the kernel configuration in a way it fails on unset symbols
-regardless of the aforementioned preconditions.
-
----
- scripts/kconfig/conf.c | 6 ++++++
- 1 file changed, 6 insertions(+)
-
---- a/scripts/kconfig/conf.c
-+++ b/scripts/kconfig/conf.c
-@@ -338,6 +338,9 @@ static int conf_askvalue(struct symbol *
- }
- /* fall through */
- default:
-+ if (!tty_stdio && getenv("FAIL_ON_UNCONFIGURED")) {
-+ exit(1);
-+ }
- fflush(stdout);
- xfgets(line, sizeof(line), stdin);
- break;
-@@ -520,6 +523,9 @@ static int conf_choice(struct menu *menu
- }
- /* fall through */
- case oldaskconfig:
-+ if (!tty_stdio && getenv("FAIL_ON_UNCONFIGURED")) {
-+ exit(1);
-+ }
- fflush(stdout);
- xfgets(line, sizeof(line), stdin);
- strip(line);
+++ /dev/null
-From db7c30dcd9a0391bf13b62c9f91e144d762ef43a Mon Sep 17 00:00:00 2001
-Date: Fri, 7 Jul 2017 17:00:49 +0200
-Subject: Add an OSX specific patch to make the kernel be compiled
-
-lede-commit: 3fc2a24f0422b2f55f9ed43f116db3111f700526
----
- scripts/kconfig/Makefile | 3 +
- scripts/mod/elf.h | 3007 ++++++++++++++++++++++++++++++++++++++++++++
- scripts/mod/mk_elfconfig.c | 4 +
- scripts/mod/modpost.h | 4 +
- 4 files changed, 3018 insertions(+)
- create mode 100644 scripts/mod/elf.h
-
---- /dev/null
-+++ b/scripts/mod/elf.h
-@@ -0,0 +1,3007 @@
-+/* This file defines standard ELF types, structures, and macros.
-+ Copyright (C) 1995-2012 Free Software Foundation, Inc.
-+ This file is part of the GNU C Library.
-+
-+ The GNU C Library is free software; you can redistribute it and/or
-+ modify it under the terms of the GNU Lesser General Public
-+ License as published by the Free Software Foundation; either
-+ version 2.1 of the License, or (at your option) any later version.
-+
-+ The GNU C Library is distributed in the hope that it will be useful,
-+ but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ Lesser General Public License for more details.
-+
-+ You should have received a copy of the GNU Lesser General Public
-+ License along with the GNU C Library; if not, see
-+ <http://www.gnu.org/licenses/>. */
-+
-+#ifndef _ELF_H
-+#define _ELF_H 1
-+
-+/* Standard ELF types. */
-+
-+#include <stdint.h>
-+
-+/* Type for a 16-bit quantity. */
-+typedef uint16_t Elf32_Half;
-+typedef uint16_t Elf64_Half;
-+
-+/* Types for signed and unsigned 32-bit quantities. */
-+typedef uint32_t Elf32_Word;
-+typedef int32_t Elf32_Sword;
-+typedef uint32_t Elf64_Word;
-+typedef int32_t Elf64_Sword;
-+
-+/* Types for signed and unsigned 64-bit quantities. */
-+typedef uint64_t Elf32_Xword;
-+typedef int64_t Elf32_Sxword;
-+typedef uint64_t Elf64_Xword;
-+typedef int64_t Elf64_Sxword;
-+
-+/* Type of addresses. */
-+typedef uint32_t Elf32_Addr;
-+typedef uint64_t Elf64_Addr;
-+
-+/* Type of file offsets. */
-+typedef uint32_t Elf32_Off;
-+typedef uint64_t Elf64_Off;
-+
-+/* Type for section indices, which are 16-bit quantities. */
-+typedef uint16_t Elf32_Section;
-+typedef uint16_t Elf64_Section;
-+
-+/* Type for version symbol information. */
-+typedef Elf32_Half Elf32_Versym;
-+typedef Elf64_Half Elf64_Versym;
-+
-+
-+/* The ELF file header. This appears at the start of every ELF file. */
-+
-+#define EI_NIDENT (16)
-+
-+typedef struct
-+{
-+ unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */
-+ Elf32_Half e_type; /* Object file type */
-+ Elf32_Half e_machine; /* Architecture */
-+ Elf32_Word e_version; /* Object file version */
-+ Elf32_Addr e_entry; /* Entry point virtual address */
-+ Elf32_Off e_phoff; /* Program header table file offset */
-+ Elf32_Off e_shoff; /* Section header table file offset */
-+ Elf32_Word e_flags; /* Processor-specific flags */
-+ Elf32_Half e_ehsize; /* ELF header size in bytes */
-+ Elf32_Half e_phentsize; /* Program header table entry size */
-+ Elf32_Half e_phnum; /* Program header table entry count */
-+ Elf32_Half e_shentsize; /* Section header table entry size */
-+ Elf32_Half e_shnum; /* Section header table entry count */
-+ Elf32_Half e_shstrndx; /* Section header string table index */
-+} Elf32_Ehdr;
-+
-+typedef struct
-+{
-+ unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */
-+ Elf64_Half e_type; /* Object file type */
-+ Elf64_Half e_machine; /* Architecture */
-+ Elf64_Word e_version; /* Object file version */
-+ Elf64_Addr e_entry; /* Entry point virtual address */
-+ Elf64_Off e_phoff; /* Program header table file offset */
-+ Elf64_Off e_shoff; /* Section header table file offset */
-+ Elf64_Word e_flags; /* Processor-specific flags */
-+ Elf64_Half e_ehsize; /* ELF header size in bytes */
-+ Elf64_Half e_phentsize; /* Program header table entry size */
-+ Elf64_Half e_phnum; /* Program header table entry count */
-+ Elf64_Half e_shentsize; /* Section header table entry size */
-+ Elf64_Half e_shnum; /* Section header table entry count */
-+ Elf64_Half e_shstrndx; /* Section header string table index */
-+} Elf64_Ehdr;
-+
-+/* Fields in the e_ident array. The EI_* macros are indices into the
-+ array. The macros under each EI_* macro are the values the byte
-+ may have. */
-+
-+#define EI_MAG0 0 /* File identification byte 0 index */
-+#define ELFMAG0 0x7f /* Magic number byte 0 */
-+
-+#define EI_MAG1 1 /* File identification byte 1 index */
-+#define ELFMAG1 'E' /* Magic number byte 1 */
-+
-+#define EI_MAG2 2 /* File identification byte 2 index */
-+#define ELFMAG2 'L' /* Magic number byte 2 */
-+
-+#define EI_MAG3 3 /* File identification byte 3 index */
-+#define ELFMAG3 'F' /* Magic number byte 3 */
-+
-+/* Conglomeration of the identification bytes, for easy testing as a word. */
-+#define ELFMAG "\177ELF"
-+#define SELFMAG 4
-+
-+#define EI_CLASS 4 /* File class byte index */
-+#define ELFCLASSNONE 0 /* Invalid class */
-+#define ELFCLASS32 1 /* 32-bit objects */
-+#define ELFCLASS64 2 /* 64-bit objects */
-+#define ELFCLASSNUM 3
-+
-+#define EI_DATA 5 /* Data encoding byte index */
-+#define ELFDATANONE 0 /* Invalid data encoding */
-+#define ELFDATA2LSB 1 /* 2's complement, little endian */
-+#define ELFDATA2MSB 2 /* 2's complement, big endian */
-+#define ELFDATANUM 3
-+
-+#define EI_VERSION 6 /* File version byte index */
-+ /* Value must be EV_CURRENT */
-+
-+#define EI_OSABI 7 /* OS ABI identification */
-+#define ELFOSABI_NONE 0 /* UNIX System V ABI */
-+#define ELFOSABI_SYSV 0 /* Alias. */
-+#define ELFOSABI_HPUX 1 /* HP-UX */
-+#define ELFOSABI_NETBSD 2 /* NetBSD. */
-+#define ELFOSABI_GNU 3 /* Object uses GNU ELF extensions. */
-+#define ELFOSABI_LINUX ELFOSABI_GNU /* Compatibility alias. */
-+#define ELFOSABI_SOLARIS 6 /* Sun Solaris. */
-+#define ELFOSABI_AIX 7 /* IBM AIX. */
-+#define ELFOSABI_IRIX 8 /* SGI Irix. */
-+#define ELFOSABI_FREEBSD 9 /* FreeBSD. */
-+#define ELFOSABI_TRU64 10 /* Compaq TRU64 UNIX. */
-+#define ELFOSABI_MODESTO 11 /* Novell Modesto. */
-+#define ELFOSABI_OPENBSD 12 /* OpenBSD. */
-+#define ELFOSABI_ARM_AEABI 64 /* ARM EABI */
-+#define ELFOSABI_ARM 97 /* ARM */
-+#define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */
-+
-+#define EI_ABIVERSION 8 /* ABI version */
-+
-+#define EI_PAD 9 /* Byte index of padding bytes */
-+
-+/* Legal values for e_type (object file type). */
-+
-+#define ET_NONE 0 /* No file type */
-+#define ET_REL 1 /* Relocatable file */
-+#define ET_EXEC 2 /* Executable file */
-+#define ET_DYN 3 /* Shared object file */
-+#define ET_CORE 4 /* Core file */
-+#define ET_NUM 5 /* Number of defined types */
-+#define ET_LOOS 0xfe00 /* OS-specific range start */
-+#define ET_HIOS 0xfeff /* OS-specific range end */
-+#define ET_LOPROC 0xff00 /* Processor-specific range start */
-+#define ET_HIPROC 0xffff /* Processor-specific range end */
-+
-+/* Legal values for e_machine (architecture). */
-+
-+#define EM_NONE 0 /* No machine */
-+#define EM_M32 1 /* AT&T WE 32100 */
-+#define EM_SPARC 2 /* SUN SPARC */
-+#define EM_386 3 /* Intel 80386 */
-+#define EM_68K 4 /* Motorola m68k family */
-+#define EM_88K 5 /* Motorola m88k family */
-+#define EM_860 7 /* Intel 80860 */
-+#define EM_MIPS 8 /* MIPS R3000 big-endian */
-+#define EM_S370 9 /* IBM System/370 */
-+#define EM_MIPS_RS3_LE 10 /* MIPS R3000 little-endian */
-+
-+#define EM_PARISC 15 /* HPPA */
-+#define EM_VPP500 17 /* Fujitsu VPP500 */
-+#define EM_SPARC32PLUS 18 /* Sun's "v8plus" */
-+#define EM_960 19 /* Intel 80960 */
-+#define EM_PPC 20 /* PowerPC */
-+#define EM_PPC64 21 /* PowerPC 64-bit */
-+#define EM_S390 22 /* IBM S390 */
-+
-+#define EM_V800 36 /* NEC V800 series */
-+#define EM_FR20 37 /* Fujitsu FR20 */
-+#define EM_RH32 38 /* TRW RH-32 */
-+#define EM_RCE 39 /* Motorola RCE */
-+#define EM_ARM 40 /* ARM */
-+#define EM_FAKE_ALPHA 41 /* Digital Alpha */
-+#define EM_SH 42 /* Hitachi SH */
-+#define EM_SPARCV9 43 /* SPARC v9 64-bit */
-+#define EM_TRICORE 44 /* Siemens Tricore */
-+#define EM_ARC 45 /* Argonaut RISC Core */
-+#define EM_H8_300 46 /* Hitachi H8/300 */
-+#define EM_H8_300H 47 /* Hitachi H8/300H */
-+#define EM_H8S 48 /* Hitachi H8S */
-+#define EM_H8_500 49 /* Hitachi H8/500 */
-+#define EM_IA_64 50 /* Intel Merced */
-+#define EM_MIPS_X 51 /* Stanford MIPS-X */
-+#define EM_COLDFIRE 52 /* Motorola Coldfire */
-+#define EM_68HC12 53 /* Motorola M68HC12 */
-+#define EM_MMA 54 /* Fujitsu MMA Multimedia Accelerator*/
-+#define EM_PCP 55 /* Siemens PCP */
-+#define EM_NCPU 56 /* Sony nCPU embeeded RISC */
-+#define EM_NDR1 57 /* Denso NDR1 microprocessor */
-+#define EM_STARCORE 58 /* Motorola Start*Core processor */
-+#define EM_ME16 59 /* Toyota ME16 processor */
-+#define EM_ST100 60 /* STMicroelectronic ST100 processor */
-+#define EM_TINYJ 61 /* Advanced Logic Corp. Tinyj emb.fam*/
-+#define EM_X86_64 62 /* AMD x86-64 architecture */
-+#define EM_PDSP 63 /* Sony DSP Processor */
-+
-+#define EM_FX66 66 /* Siemens FX66 microcontroller */
-+#define EM_ST9PLUS 67 /* STMicroelectronics ST9+ 8/16 mc */
-+#define EM_ST7 68 /* STmicroelectronics ST7 8 bit mc */
-+#define EM_68HC16 69 /* Motorola MC68HC16 microcontroller */
-+#define EM_68HC11 70 /* Motorola MC68HC11 microcontroller */
-+#define EM_68HC08 71 /* Motorola MC68HC08 microcontroller */
-+#define EM_68HC05 72 /* Motorola MC68HC05 microcontroller */
-+#define EM_SVX 73 /* Silicon Graphics SVx */
-+#define EM_ST19 74 /* STMicroelectronics ST19 8 bit mc */
-+#define EM_VAX 75 /* Digital VAX */
-+#define EM_CRIS 76 /* Axis Communications 32-bit embedded processor */
-+#define EM_JAVELIN 77 /* Infineon Technologies 32-bit embedded processor */
-+#define EM_FIREPATH 78 /* Element 14 64-bit DSP Processor */
-+#define EM_ZSP 79 /* LSI Logic 16-bit DSP Processor */
-+#define EM_MMIX 80 /* Donald Knuth's educational 64-bit processor */
-+#define EM_HUANY 81 /* Harvard University machine-independent object files */
-+#define EM_PRISM 82 /* SiTera Prism */
-+#define EM_AVR 83 /* Atmel AVR 8-bit microcontroller */
-+#define EM_FR30 84 /* Fujitsu FR30 */
-+#define EM_D10V 85 /* Mitsubishi D10V */
-+#define EM_D30V 86 /* Mitsubishi D30V */
-+#define EM_V850 87 /* NEC v850 */
-+#define EM_M32R 88 /* Mitsubishi M32R */
-+#define EM_MN10300 89 /* Matsushita MN10300 */
-+#define EM_MN10200 90 /* Matsushita MN10200 */
-+#define EM_PJ 91 /* picoJava */
-+#define EM_OPENRISC 92 /* OpenRISC 32-bit embedded processor */
-+#define EM_ARC_A5 93 /* ARC Cores Tangent-A5 */
-+#define EM_XTENSA 94 /* Tensilica Xtensa Architecture */
-+#define EM_TILEPRO 188 /* Tilera TILEPro */
-+#define EM_TILEGX 191 /* Tilera TILE-Gx */
-+#define EM_NUM 192
-+
-+/* If it is necessary to assign new unofficial EM_* values, please
-+ pick large random numbers (0x8523, 0xa7f2, etc.) to minimize the
-+ chances of collision with official or non-GNU unofficial values. */
-+
-+#define EM_ALPHA 0x9026
-+
-+/* Legal values for e_version (version). */
-+
-+#define EV_NONE 0 /* Invalid ELF version */
-+#define EV_CURRENT 1 /* Current version */
-+#define EV_NUM 2
-+
-+/* Section header. */
-+
-+typedef struct
-+{
-+ Elf32_Word sh_name; /* Section name (string tbl index) */
-+ Elf32_Word sh_type; /* Section type */
-+ Elf32_Word sh_flags; /* Section flags */
-+ Elf32_Addr sh_addr; /* Section virtual addr at execution */
-+ Elf32_Off sh_offset; /* Section file offset */
-+ Elf32_Word sh_size; /* Section size in bytes */
-+ Elf32_Word sh_link; /* Link to another section */
-+ Elf32_Word sh_info; /* Additional section information */
-+ Elf32_Word sh_addralign; /* Section alignment */
-+ Elf32_Word sh_entsize; /* Entry size if section holds table */
-+} Elf32_Shdr;
-+
-+typedef struct
-+{
-+ Elf64_Word sh_name; /* Section name (string tbl index) */
-+ Elf64_Word sh_type; /* Section type */
-+ Elf64_Xword sh_flags; /* Section flags */
-+ Elf64_Addr sh_addr; /* Section virtual addr at execution */
-+ Elf64_Off sh_offset; /* Section file offset */
-+ Elf64_Xword sh_size; /* Section size in bytes */
-+ Elf64_Word sh_link; /* Link to another section */
-+ Elf64_Word sh_info; /* Additional section information */
-+ Elf64_Xword sh_addralign; /* Section alignment */
-+ Elf64_Xword sh_entsize; /* Entry size if section holds table */
-+} Elf64_Shdr;
-+
-+/* Special section indices. */
-+
-+#define SHN_UNDEF 0 /* Undefined section */
-+#define SHN_LORESERVE 0xff00 /* Start of reserved indices */
-+#define SHN_LOPROC 0xff00 /* Start of processor-specific */
-+#define SHN_BEFORE 0xff00 /* Order section before all others
-+ (Solaris). */
-+#define SHN_AFTER 0xff01 /* Order section after all others
-+ (Solaris). */
-+#define SHN_HIPROC 0xff1f /* End of processor-specific */
-+#define SHN_LOOS 0xff20 /* Start of OS-specific */
-+#define SHN_HIOS 0xff3f /* End of OS-specific */
-+#define SHN_ABS 0xfff1 /* Associated symbol is absolute */
-+#define SHN_COMMON 0xfff2 /* Associated symbol is common */
-+#define SHN_XINDEX 0xffff /* Index is in extra table. */
-+#define SHN_HIRESERVE 0xffff /* End of reserved indices */
-+
-+/* Legal values for sh_type (section type). */
-+
-+#define SHT_NULL 0 /* Section header table entry unused */
-+#define SHT_PROGBITS 1 /* Program data */
-+#define SHT_SYMTAB 2 /* Symbol table */
-+#define SHT_STRTAB 3 /* String table */
-+#define SHT_RELA 4 /* Relocation entries with addends */
-+#define SHT_HASH 5 /* Symbol hash table */
-+#define SHT_DYNAMIC 6 /* Dynamic linking information */
-+#define SHT_NOTE 7 /* Notes */
-+#define SHT_NOBITS 8 /* Program space with no data (bss) */
-+#define SHT_REL 9 /* Relocation entries, no addends */
-+#define SHT_SHLIB 10 /* Reserved */
-+#define SHT_DYNSYM 11 /* Dynamic linker symbol table */
-+#define SHT_INIT_ARRAY 14 /* Array of constructors */
-+#define SHT_FINI_ARRAY 15 /* Array of destructors */
-+#define SHT_PREINIT_ARRAY 16 /* Array of pre-constructors */
-+#define SHT_GROUP 17 /* Section group */
-+#define SHT_SYMTAB_SHNDX 18 /* Extended section indeces */
-+#define SHT_NUM 19 /* Number of defined types. */
-+#define SHT_LOOS 0x60000000 /* Start OS-specific. */
-+#define SHT_GNU_ATTRIBUTES 0x6ffffff5 /* Object attributes. */
-+#define SHT_GNU_HASH 0x6ffffff6 /* GNU-style hash table. */
-+#define SHT_GNU_LIBLIST 0x6ffffff7 /* Prelink library list */
-+#define SHT_CHECKSUM 0x6ffffff8 /* Checksum for DSO content. */
-+#define SHT_LOSUNW 0x6ffffffa /* Sun-specific low bound. */
-+#define SHT_SUNW_move 0x6ffffffa
-+#define SHT_SUNW_COMDAT 0x6ffffffb
-+#define SHT_SUNW_syminfo 0x6ffffffc
-+#define SHT_GNU_verdef 0x6ffffffd /* Version definition section. */
-+#define SHT_GNU_verneed 0x6ffffffe /* Version needs section. */
-+#define SHT_GNU_versym 0x6fffffff /* Version symbol table. */
-+#define SHT_HISUNW 0x6fffffff /* Sun-specific high bound. */
-+#define SHT_HIOS 0x6fffffff /* End OS-specific type */
-+#define SHT_LOPROC 0x70000000 /* Start of processor-specific */
-+#define SHT_HIPROC 0x7fffffff /* End of processor-specific */
-+#define SHT_LOUSER 0x80000000 /* Start of application-specific */
-+#define SHT_HIUSER 0x8fffffff /* End of application-specific */
-+
-+/* Legal values for sh_flags (section flags). */
-+
-+#define SHF_WRITE (1 << 0) /* Writable */
-+#define SHF_ALLOC (1 << 1) /* Occupies memory during execution */
-+#define SHF_EXECINSTR (1 << 2) /* Executable */
-+#define SHF_MERGE (1 << 4) /* Might be merged */
-+#define SHF_STRINGS (1 << 5) /* Contains nul-terminated strings */
-+#define SHF_INFO_LINK (1 << 6) /* `sh_info' contains SHT index */
-+#define SHF_LINK_ORDER (1 << 7) /* Preserve order after combining */
-+#define SHF_OS_NONCONFORMING (1 << 8) /* Non-standard OS specific handling
-+ required */
-+#define SHF_GROUP (1 << 9) /* Section is member of a group. */
-+#define SHF_TLS (1 << 10) /* Section hold thread-local data. */
-+#define SHF_MASKOS 0x0ff00000 /* OS-specific. */
-+#define SHF_MASKPROC 0xf0000000 /* Processor-specific */
-+#define SHF_ORDERED (1 << 30) /* Special ordering requirement
-+ (Solaris). */
-+#define SHF_EXCLUDE (1 << 31) /* Section is excluded unless
-+ referenced or allocated (Solaris).*/
-+
-+/* Section group handling. */
-+#define GRP_COMDAT 0x1 /* Mark group as COMDAT. */
-+
-+/* Symbol table entry. */
-+
-+typedef struct
-+{
-+ Elf32_Word st_name; /* Symbol name (string tbl index) */
-+ Elf32_Addr st_value; /* Symbol value */
-+ Elf32_Word st_size; /* Symbol size */
-+ unsigned char st_info; /* Symbol type and binding */
-+ unsigned char st_other; /* Symbol visibility */
-+ Elf32_Section st_shndx; /* Section index */
-+} Elf32_Sym;
-+
-+typedef struct
-+{
-+ Elf64_Word st_name; /* Symbol name (string tbl index) */
-+ unsigned char st_info; /* Symbol type and binding */
-+ unsigned char st_other; /* Symbol visibility */
-+ Elf64_Section st_shndx; /* Section index */
-+ Elf64_Addr st_value; /* Symbol value */
-+ Elf64_Xword st_size; /* Symbol size */
-+} Elf64_Sym;
-+
-+/* The syminfo section if available contains additional information about
-+ every dynamic symbol. */
-+
-+typedef struct
-+{
-+ Elf32_Half si_boundto; /* Direct bindings, symbol bound to */
-+ Elf32_Half si_flags; /* Per symbol flags */
-+} Elf32_Syminfo;
-+
-+typedef struct
-+{
-+ Elf64_Half si_boundto; /* Direct bindings, symbol bound to */
-+ Elf64_Half si_flags; /* Per symbol flags */
-+} Elf64_Syminfo;
-+
-+/* Possible values for si_boundto. */
-+#define SYMINFO_BT_SELF 0xffff /* Symbol bound to self */
-+#define SYMINFO_BT_PARENT 0xfffe /* Symbol bound to parent */
-+#define SYMINFO_BT_LOWRESERVE 0xff00 /* Beginning of reserved entries */
-+
-+/* Possible bitmasks for si_flags. */
-+#define SYMINFO_FLG_DIRECT 0x0001 /* Direct bound symbol */
-+#define SYMINFO_FLG_PASSTHRU 0x0002 /* Pass-thru symbol for translator */
-+#define SYMINFO_FLG_COPY 0x0004 /* Symbol is a copy-reloc */
-+#define SYMINFO_FLG_LAZYLOAD 0x0008 /* Symbol bound to object to be lazy
-+ loaded */
-+/* Syminfo version values. */
-+#define SYMINFO_NONE 0
-+#define SYMINFO_CURRENT 1
-+#define SYMINFO_NUM 2
-+
-+
-+/* How to extract and insert information held in the st_info field. */
-+
-+#define ELF32_ST_BIND(val) (((unsigned char) (val)) >> 4)
-+#define ELF32_ST_TYPE(val) ((val) & 0xf)
-+#define ELF32_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf))
-+
-+/* Both Elf32_Sym and Elf64_Sym use the same one-byte st_info field. */
-+#define ELF64_ST_BIND(val) ELF32_ST_BIND (val)
-+#define ELF64_ST_TYPE(val) ELF32_ST_TYPE (val)
-+#define ELF64_ST_INFO(bind, type) ELF32_ST_INFO ((bind), (type))
-+
-+/* Legal values for ST_BIND subfield of st_info (symbol binding). */
-+
-+#define STB_LOCAL 0 /* Local symbol */
-+#define STB_GLOBAL 1 /* Global symbol */
-+#define STB_WEAK 2 /* Weak symbol */
-+#define STB_NUM 3 /* Number of defined types. */
-+#define STB_LOOS 10 /* Start of OS-specific */
-+#define STB_GNU_UNIQUE 10 /* Unique symbol. */
-+#define STB_HIOS 12 /* End of OS-specific */
-+#define STB_LOPROC 13 /* Start of processor-specific */
-+#define STB_HIPROC 15 /* End of processor-specific */
-+
-+/* Legal values for ST_TYPE subfield of st_info (symbol type). */
-+
-+#define STT_NOTYPE 0 /* Symbol type is unspecified */
-+#define STT_OBJECT 1 /* Symbol is a data object */
-+#define STT_FUNC 2 /* Symbol is a code object */
-+#define STT_SECTION 3 /* Symbol associated with a section */
-+#define STT_FILE 4 /* Symbol's name is file name */
-+#define STT_COMMON 5 /* Symbol is a common data object */
-+#define STT_TLS 6 /* Symbol is thread-local data object*/
-+#define STT_NUM 7 /* Number of defined types. */
-+#define STT_LOOS 10 /* Start of OS-specific */
-+#define STT_GNU_IFUNC 10 /* Symbol is indirect code object */
-+#define STT_HIOS 12 /* End of OS-specific */
-+#define STT_LOPROC 13 /* Start of processor-specific */
-+#define STT_HIPROC 15 /* End of processor-specific */
-+
-+
-+/* Symbol table indices are found in the hash buckets and chain table
-+ of a symbol hash table section. This special index value indicates
-+ the end of a chain, meaning no further symbols are found in that bucket. */
-+
-+#define STN_UNDEF 0 /* End of a chain. */
-+
-+
-+/* How to extract and insert information held in the st_other field. */
-+
-+#define ELF32_ST_VISIBILITY(o) ((o) & 0x03)
-+
-+/* For ELF64 the definitions are the same. */
-+#define ELF64_ST_VISIBILITY(o) ELF32_ST_VISIBILITY (o)
-+
-+/* Symbol visibility specification encoded in the st_other field. */
-+#define STV_DEFAULT 0 /* Default symbol visibility rules */
-+#define STV_INTERNAL 1 /* Processor specific hidden class */
-+#define STV_HIDDEN 2 /* Sym unavailable in other modules */
-+#define STV_PROTECTED 3 /* Not preemptible, not exported */
-+
-+
-+/* Relocation table entry without addend (in section of type SHT_REL). */
-+
-+typedef struct
-+{
-+ Elf32_Addr r_offset; /* Address */
-+ Elf32_Word r_info; /* Relocation type and symbol index */
-+} Elf32_Rel;
-+
-+/* I have seen two different definitions of the Elf64_Rel and
-+ Elf64_Rela structures, so we'll leave them out until Novell (or
-+ whoever) gets their act together. */
-+/* The following, at least, is used on Sparc v9, MIPS, and Alpha. */
-+
-+typedef struct
-+{
-+ Elf64_Addr r_offset; /* Address */
-+ Elf64_Xword r_info; /* Relocation type and symbol index */
-+} Elf64_Rel;
-+
-+/* Relocation table entry with addend (in section of type SHT_RELA). */
-+
-+typedef struct
-+{
-+ Elf32_Addr r_offset; /* Address */
-+ Elf32_Word r_info; /* Relocation type and symbol index */
-+ Elf32_Sword r_addend; /* Addend */
-+} Elf32_Rela;
-+
-+typedef struct
-+{
-+ Elf64_Addr r_offset; /* Address */
-+ Elf64_Xword r_info; /* Relocation type and symbol index */
-+ Elf64_Sxword r_addend; /* Addend */
-+} Elf64_Rela;
-+
-+/* How to extract and insert information held in the r_info field. */
-+
-+#define ELF32_R_SYM(val) ((val) >> 8)
-+#define ELF32_R_TYPE(val) ((val) & 0xff)
-+#define ELF32_R_INFO(sym, type) (((sym) << 8) + ((type) & 0xff))
-+
-+#define ELF64_R_SYM(i) ((i) >> 32)
-+#define ELF64_R_TYPE(i) ((i) & 0xffffffff)
-+#define ELF64_R_INFO(sym,type) ((((Elf64_Xword) (sym)) << 32) + (type))
-+
-+/* Program segment header. */
-+
-+typedef struct
-+{
-+ Elf32_Word p_type; /* Segment type */
-+ Elf32_Off p_offset; /* Segment file offset */
-+ Elf32_Addr p_vaddr; /* Segment virtual address */
-+ Elf32_Addr p_paddr; /* Segment physical address */
-+ Elf32_Word p_filesz; /* Segment size in file */
-+ Elf32_Word p_memsz; /* Segment size in memory */
-+ Elf32_Word p_flags; /* Segment flags */
-+ Elf32_Word p_align; /* Segment alignment */
-+} Elf32_Phdr;
-+
-+typedef struct
-+{
-+ Elf64_Word p_type; /* Segment type */
-+ Elf64_Word p_flags; /* Segment flags */
-+ Elf64_Off p_offset; /* Segment file offset */
-+ Elf64_Addr p_vaddr; /* Segment virtual address */
-+ Elf64_Addr p_paddr; /* Segment physical address */
-+ Elf64_Xword p_filesz; /* Segment size in file */
-+ Elf64_Xword p_memsz; /* Segment size in memory */
-+ Elf64_Xword p_align; /* Segment alignment */
-+} Elf64_Phdr;
-+
-+/* Special value for e_phnum. This indicates that the real number of
-+ program headers is too large to fit into e_phnum. Instead the real
-+ value is in the field sh_info of section 0. */
-+
-+#define PN_XNUM 0xffff
-+
-+/* Legal values for p_type (segment type). */
-+
-+#define PT_NULL 0 /* Program header table entry unused */
-+#define PT_LOAD 1 /* Loadable program segment */
-+#define PT_DYNAMIC 2 /* Dynamic linking information */
-+#define PT_INTERP 3 /* Program interpreter */
-+#define PT_NOTE 4 /* Auxiliary information */
-+#define PT_SHLIB 5 /* Reserved */
-+#define PT_PHDR 6 /* Entry for header table itself */
-+#define PT_TLS 7 /* Thread-local storage segment */
-+#define PT_NUM 8 /* Number of defined types */
-+#define PT_LOOS 0x60000000 /* Start of OS-specific */
-+#define PT_GNU_EH_FRAME 0x6474e550 /* GCC .eh_frame_hdr segment */
-+#define PT_GNU_STACK 0x6474e551 /* Indicates stack executability */
-+#define PT_GNU_RELRO 0x6474e552 /* Read-only after relocation */
-+#define PT_LOSUNW 0x6ffffffa
-+#define PT_SUNWBSS 0x6ffffffa /* Sun Specific segment */
-+#define PT_SUNWSTACK 0x6ffffffb /* Stack segment */
-+#define PT_HISUNW 0x6fffffff
-+#define PT_HIOS 0x6fffffff /* End of OS-specific */
-+#define PT_LOPROC 0x70000000 /* Start of processor-specific */
-+#define PT_HIPROC 0x7fffffff /* End of processor-specific */
-+
-+/* Legal values for p_flags (segment flags). */
-+
-+#define PF_X (1 << 0) /* Segment is executable */
-+#define PF_W (1 << 1) /* Segment is writable */
-+#define PF_R (1 << 2) /* Segment is readable */
-+#define PF_MASKOS 0x0ff00000 /* OS-specific */
-+#define PF_MASKPROC 0xf0000000 /* Processor-specific */
-+
-+/* Legal values for note segment descriptor types for core files. */
-+
-+#define NT_PRSTATUS 1 /* Contains copy of prstatus struct */
-+#define NT_FPREGSET 2 /* Contains copy of fpregset struct */
-+#define NT_PRPSINFO 3 /* Contains copy of prpsinfo struct */
-+#define NT_PRXREG 4 /* Contains copy of prxregset struct */
-+#define NT_TASKSTRUCT 4 /* Contains copy of task structure */
-+#define NT_PLATFORM 5 /* String from sysinfo(SI_PLATFORM) */
-+#define NT_AUXV 6 /* Contains copy of auxv array */
-+#define NT_GWINDOWS 7 /* Contains copy of gwindows struct */
-+#define NT_ASRS 8 /* Contains copy of asrset struct */
-+#define NT_PSTATUS 10 /* Contains copy of pstatus struct */
-+#define NT_PSINFO 13 /* Contains copy of psinfo struct */
-+#define NT_PRCRED 14 /* Contains copy of prcred struct */
-+#define NT_UTSNAME 15 /* Contains copy of utsname struct */
-+#define NT_LWPSTATUS 16 /* Contains copy of lwpstatus struct */
-+#define NT_LWPSINFO 17 /* Contains copy of lwpinfo struct */
-+#define NT_PRFPXREG 20 /* Contains copy of fprxregset struct */
-+#define NT_PRXFPREG 0x46e62b7f /* Contains copy of user_fxsr_struct */
-+#define NT_PPC_VMX 0x100 /* PowerPC Altivec/VMX registers */
-+#define NT_PPC_SPE 0x101 /* PowerPC SPE/EVR registers */
-+#define NT_PPC_VSX 0x102 /* PowerPC VSX registers */
-+#define NT_386_TLS 0x200 /* i386 TLS slots (struct user_desc) */
-+#define NT_386_IOPERM 0x201 /* x86 io permission bitmap (1=deny) */
-+#define NT_X86_XSTATE 0x202 /* x86 extended state using xsave */
-+
-+/* Legal values for the note segment descriptor types for object files. */
-+
-+#define NT_VERSION 1 /* Contains a version string. */
-+
-+
-+/* Dynamic section entry. */
-+
-+typedef struct
-+{
-+ Elf32_Sword d_tag; /* Dynamic entry type */
-+ union
-+ {
-+ Elf32_Word d_val; /* Integer value */
-+ Elf32_Addr d_ptr; /* Address value */
-+ } d_un;
-+} Elf32_Dyn;
-+
-+typedef struct
-+{
-+ Elf64_Sxword d_tag; /* Dynamic entry type */
-+ union
-+ {
-+ Elf64_Xword d_val; /* Integer value */
-+ Elf64_Addr d_ptr; /* Address value */
-+ } d_un;
-+} Elf64_Dyn;
-+
-+/* Legal values for d_tag (dynamic entry type). */
-+
-+#define DT_NULL 0 /* Marks end of dynamic section */
-+#define DT_NEEDED 1 /* Name of needed library */
-+#define DT_PLTRELSZ 2 /* Size in bytes of PLT relocs */
-+#define DT_PLTGOT 3 /* Processor defined value */
-+#define DT_HASH 4 /* Address of symbol hash table */
-+#define DT_STRTAB 5 /* Address of string table */
-+#define DT_SYMTAB 6 /* Address of symbol table */
-+#define DT_RELA 7 /* Address of Rela relocs */
-+#define DT_RELASZ 8 /* Total size of Rela relocs */
-+#define DT_RELAENT 9 /* Size of one Rela reloc */
-+#define DT_STRSZ 10 /* Size of string table */
-+#define DT_SYMENT 11 /* Size of one symbol table entry */
-+#define DT_INIT 12 /* Address of init function */
-+#define DT_FINI 13 /* Address of termination function */
-+#define DT_SONAME 14 /* Name of shared object */
-+#define DT_RPATH 15 /* Library search path (deprecated) */
-+#define DT_SYMBOLIC 16 /* Start symbol search here */
-+#define DT_REL 17 /* Address of Rel relocs */
-+#define DT_RELSZ 18 /* Total size of Rel relocs */
-+#define DT_RELENT 19 /* Size of one Rel reloc */
-+#define DT_PLTREL 20 /* Type of reloc in PLT */
-+#define DT_DEBUG 21 /* For debugging; unspecified */
-+#define DT_TEXTREL 22 /* Reloc might modify .text */
-+#define DT_JMPREL 23 /* Address of PLT relocs */
-+#define DT_BIND_NOW 24 /* Process relocations of object */
-+#define DT_INIT_ARRAY 25 /* Array with addresses of init fct */
-+#define DT_FINI_ARRAY 26 /* Array with addresses of fini fct */
-+#define DT_INIT_ARRAYSZ 27 /* Size in bytes of DT_INIT_ARRAY */
-+#define DT_FINI_ARRAYSZ 28 /* Size in bytes of DT_FINI_ARRAY */
-+#define DT_RUNPATH 29 /* Library search path */
-+#define DT_FLAGS 30 /* Flags for the object being loaded */
-+#define DT_ENCODING 32 /* Start of encoded range */
-+#define DT_PREINIT_ARRAY 32 /* Array with addresses of preinit fct*/
-+#define DT_PREINIT_ARRAYSZ 33 /* size in bytes of DT_PREINIT_ARRAY */
-+#define DT_NUM 34 /* Number used */
-+#define DT_LOOS 0x6000000d /* Start of OS-specific */
-+#define DT_HIOS 0x6ffff000 /* End of OS-specific */
-+#define DT_LOPROC 0x70000000 /* Start of processor-specific */
-+#define DT_HIPROC 0x7fffffff /* End of processor-specific */
-+#define DT_PROCNUM DT_MIPS_NUM /* Most used by any processor */
-+
-+/* DT_* entries which fall between DT_VALRNGHI & DT_VALRNGLO use the
-+ Dyn.d_un.d_val field of the Elf*_Dyn structure. This follows Sun's
-+ approach. */
-+#define DT_VALRNGLO 0x6ffffd00
-+#define DT_GNU_PRELINKED 0x6ffffdf5 /* Prelinking timestamp */
-+#define DT_GNU_CONFLICTSZ 0x6ffffdf6 /* Size of conflict section */
-+#define DT_GNU_LIBLISTSZ 0x6ffffdf7 /* Size of library list */
-+#define DT_CHECKSUM 0x6ffffdf8
-+#define DT_PLTPADSZ 0x6ffffdf9
-+#define DT_MOVEENT 0x6ffffdfa
-+#define DT_MOVESZ 0x6ffffdfb
-+#define DT_FEATURE_1 0x6ffffdfc /* Feature selection (DTF_*). */
-+#define DT_POSFLAG_1 0x6ffffdfd /* Flags for DT_* entries, effecting
-+ the following DT_* entry. */
-+#define DT_SYMINSZ 0x6ffffdfe /* Size of syminfo table (in bytes) */
-+#define DT_SYMINENT 0x6ffffdff /* Entry size of syminfo */
-+#define DT_VALRNGHI 0x6ffffdff
-+#define DT_VALTAGIDX(tag) (DT_VALRNGHI - (tag)) /* Reverse order! */
-+#define DT_VALNUM 12
-+
-+/* DT_* entries which fall between DT_ADDRRNGHI & DT_ADDRRNGLO use the
-+ Dyn.d_un.d_ptr field of the Elf*_Dyn structure.
-+
-+ If any adjustment is made to the ELF object after it has been
-+ built these entries will need to be adjusted. */
-+#define DT_ADDRRNGLO 0x6ffffe00
-+#define DT_GNU_HASH 0x6ffffef5 /* GNU-style hash table. */
-+#define DT_TLSDESC_PLT 0x6ffffef6
-+#define DT_TLSDESC_GOT 0x6ffffef7
-+#define DT_GNU_CONFLICT 0x6ffffef8 /* Start of conflict section */
-+#define DT_GNU_LIBLIST 0x6ffffef9 /* Library list */
-+#define DT_CONFIG 0x6ffffefa /* Configuration information. */
-+#define DT_DEPAUDIT 0x6ffffefb /* Dependency auditing. */
-+#define DT_AUDIT 0x6ffffefc /* Object auditing. */
-+#define DT_PLTPAD 0x6ffffefd /* PLT padding. */
-+#define DT_MOVETAB 0x6ffffefe /* Move table. */
-+#define DT_SYMINFO 0x6ffffeff /* Syminfo table. */
-+#define DT_ADDRRNGHI 0x6ffffeff
-+#define DT_ADDRTAGIDX(tag) (DT_ADDRRNGHI - (tag)) /* Reverse order! */
-+#define DT_ADDRNUM 11
-+
-+/* The versioning entry types. The next are defined as part of the
-+ GNU extension. */
-+#define DT_VERSYM 0x6ffffff0
-+
-+#define DT_RELACOUNT 0x6ffffff9
-+#define DT_RELCOUNT 0x6ffffffa
-+
-+/* These were chosen by Sun. */
-+#define DT_FLAGS_1 0x6ffffffb /* State flags, see DF_1_* below. */
-+#define DT_VERDEF 0x6ffffffc /* Address of version definition
-+ table */
-+#define DT_VERDEFNUM 0x6ffffffd /* Number of version definitions */
-+#define DT_VERNEED 0x6ffffffe /* Address of table with needed
-+ versions */
-+#define DT_VERNEEDNUM 0x6fffffff /* Number of needed versions */
-+#define DT_VERSIONTAGIDX(tag) (DT_VERNEEDNUM - (tag)) /* Reverse order! */
-+#define DT_VERSIONTAGNUM 16
-+
-+/* Sun added these machine-independent extensions in the "processor-specific"
-+ range. Be compatible. */
-+#define DT_AUXILIARY 0x7ffffffd /* Shared object to load before self */
-+#define DT_FILTER 0x7fffffff /* Shared object to get values from */
-+#define DT_EXTRATAGIDX(tag) ((Elf32_Word)-((Elf32_Sword) (tag) <<1>>1)-1)
-+#define DT_EXTRANUM 3
-+
-+/* Values of `d_un.d_val' in the DT_FLAGS entry. */
-+#define DF_ORIGIN 0x00000001 /* Object may use DF_ORIGIN */
-+#define DF_SYMBOLIC 0x00000002 /* Symbol resolutions starts here */
-+#define DF_TEXTREL 0x00000004 /* Object contains text relocations */
-+#define DF_BIND_NOW 0x00000008 /* No lazy binding for this object */
-+#define DF_STATIC_TLS 0x00000010 /* Module uses the static TLS model */
-+
-+/* State flags selectable in the `d_un.d_val' element of the DT_FLAGS_1
-+ entry in the dynamic section. */
-+#define DF_1_NOW 0x00000001 /* Set RTLD_NOW for this object. */
-+#define DF_1_GLOBAL 0x00000002 /* Set RTLD_GLOBAL for this object. */
-+#define DF_1_GROUP 0x00000004 /* Set RTLD_GROUP for this object. */
-+#define DF_1_NODELETE 0x00000008 /* Set RTLD_NODELETE for this object.*/
-+#define DF_1_LOADFLTR 0x00000010 /* Trigger filtee loading at runtime.*/
-+#define DF_1_INITFIRST 0x00000020 /* Set RTLD_INITFIRST for this object*/
-+#define DF_1_NOOPEN 0x00000040 /* Set RTLD_NOOPEN for this object. */
-+#define DF_1_ORIGIN 0x00000080 /* $ORIGIN must be handled. */
-+#define DF_1_DIRECT 0x00000100 /* Direct binding enabled. */
-+#define DF_1_TRANS 0x00000200
-+#define DF_1_INTERPOSE 0x00000400 /* Object is used to interpose. */
-+#define DF_1_NODEFLIB 0x00000800 /* Ignore default lib search path. */
-+#define DF_1_NODUMP 0x00001000 /* Object can't be dldump'ed. */
-+#define DF_1_CONFALT 0x00002000 /* Configuration alternative created.*/
-+#define DF_1_ENDFILTEE 0x00004000 /* Filtee terminates filters search. */
-+#define DF_1_DISPRELDNE 0x00008000 /* Disp reloc applied at build time. */
-+#define DF_1_DISPRELPND 0x00010000 /* Disp reloc applied at run-time. */
-+
-+/* Flags for the feature selection in DT_FEATURE_1. */
-+#define DTF_1_PARINIT 0x00000001
-+#define DTF_1_CONFEXP 0x00000002
-+
-+/* Flags in the DT_POSFLAG_1 entry effecting only the next DT_* entry. */
-+#define DF_P1_LAZYLOAD 0x00000001 /* Lazyload following object. */
-+#define DF_P1_GROUPPERM 0x00000002 /* Symbols from next object are not
-+ generally available. */
-+
-+/* Version definition sections. */
-+
-+typedef struct
-+{
-+ Elf32_Half vd_version; /* Version revision */
-+ Elf32_Half vd_flags; /* Version information */
-+ Elf32_Half vd_ndx; /* Version Index */
-+ Elf32_Half vd_cnt; /* Number of associated aux entries */
-+ Elf32_Word vd_hash; /* Version name hash value */
-+ Elf32_Word vd_aux; /* Offset in bytes to verdaux array */
-+ Elf32_Word vd_next; /* Offset in bytes to next verdef
-+ entry */
-+} Elf32_Verdef;
-+
-+typedef struct
-+{
-+ Elf64_Half vd_version; /* Version revision */
-+ Elf64_Half vd_flags; /* Version information */
-+ Elf64_Half vd_ndx; /* Version Index */
-+ Elf64_Half vd_cnt; /* Number of associated aux entries */
-+ Elf64_Word vd_hash; /* Version name hash value */
-+ Elf64_Word vd_aux; /* Offset in bytes to verdaux array */
-+ Elf64_Word vd_next; /* Offset in bytes to next verdef
-+ entry */
-+} Elf64_Verdef;
-+
-+
-+/* Legal values for vd_version (version revision). */
-+#define VER_DEF_NONE 0 /* No version */
-+#define VER_DEF_CURRENT 1 /* Current version */
-+#define VER_DEF_NUM 2 /* Given version number */
-+
-+/* Legal values for vd_flags (version information flags). */
-+#define VER_FLG_BASE 0x1 /* Version definition of file itself */
-+#define VER_FLG_WEAK 0x2 /* Weak version identifier */
-+
-+/* Versym symbol index values. */
-+#define VER_NDX_LOCAL 0 /* Symbol is local. */
-+#define VER_NDX_GLOBAL 1 /* Symbol is global. */
-+#define VER_NDX_LORESERVE 0xff00 /* Beginning of reserved entries. */
-+#define VER_NDX_ELIMINATE 0xff01 /* Symbol is to be eliminated. */
-+
-+/* Auxialiary version information. */
-+
-+typedef struct
-+{
-+ Elf32_Word vda_name; /* Version or dependency names */
-+ Elf32_Word vda_next; /* Offset in bytes to next verdaux
-+ entry */
-+} Elf32_Verdaux;
-+
-+typedef struct
-+{
-+ Elf64_Word vda_name; /* Version or dependency names */
-+ Elf64_Word vda_next; /* Offset in bytes to next verdaux
-+ entry */
-+} Elf64_Verdaux;
-+
-+
-+/* Version dependency section. */
-+
-+typedef struct
-+{
-+ Elf32_Half vn_version; /* Version of structure */
-+ Elf32_Half vn_cnt; /* Number of associated aux entries */
-+ Elf32_Word vn_file; /* Offset of filename for this
-+ dependency */
-+ Elf32_Word vn_aux; /* Offset in bytes to vernaux array */
-+ Elf32_Word vn_next; /* Offset in bytes to next verneed
-+ entry */
-+} Elf32_Verneed;
-+
-+typedef struct
-+{
-+ Elf64_Half vn_version; /* Version of structure */
-+ Elf64_Half vn_cnt; /* Number of associated aux entries */
-+ Elf64_Word vn_file; /* Offset of filename for this
-+ dependency */
-+ Elf64_Word vn_aux; /* Offset in bytes to vernaux array */
-+ Elf64_Word vn_next; /* Offset in bytes to next verneed
-+ entry */
-+} Elf64_Verneed;
-+
-+
-+/* Legal values for vn_version (version revision). */
-+#define VER_NEED_NONE 0 /* No version */
-+#define VER_NEED_CURRENT 1 /* Current version */
-+#define VER_NEED_NUM 2 /* Given version number */
-+
-+/* Auxiliary needed version information. */
-+
-+typedef struct
-+{
-+ Elf32_Word vna_hash; /* Hash value of dependency name */
-+ Elf32_Half vna_flags; /* Dependency specific information */
-+ Elf32_Half vna_other; /* Unused */
-+ Elf32_Word vna_name; /* Dependency name string offset */
-+ Elf32_Word vna_next; /* Offset in bytes to next vernaux
-+ entry */
-+} Elf32_Vernaux;
-+
-+typedef struct
-+{
-+ Elf64_Word vna_hash; /* Hash value of dependency name */
-+ Elf64_Half vna_flags; /* Dependency specific information */
-+ Elf64_Half vna_other; /* Unused */
-+ Elf64_Word vna_name; /* Dependency name string offset */
-+ Elf64_Word vna_next; /* Offset in bytes to next vernaux
-+ entry */
-+} Elf64_Vernaux;
-+
-+
-+/* Legal values for vna_flags. */
-+#define VER_FLG_WEAK 0x2 /* Weak version identifier */
-+
-+
-+/* Auxiliary vector. */
-+
-+/* This vector is normally only used by the program interpreter. The
-+ usual definition in an ABI supplement uses the name auxv_t. The
-+ vector is not usually defined in a standard <elf.h> file, but it
-+ can't hurt. We rename it to avoid conflicts. The sizes of these
-+ types are an arrangement between the exec server and the program
-+ interpreter, so we don't fully specify them here. */
-+
-+typedef struct
-+{
-+ uint32_t a_type; /* Entry type */
-+ union
-+ {
-+ uint32_t a_val; /* Integer value */
-+ /* We use to have pointer elements added here. We cannot do that,
-+ though, since it does not work when using 32-bit definitions
-+ on 64-bit platforms and vice versa. */
-+ } a_un;
-+} Elf32_auxv_t;
-+
-+typedef struct
-+{
-+ uint64_t a_type; /* Entry type */
-+ union
-+ {
-+ uint64_t a_val; /* Integer value */
-+ /* We use to have pointer elements added here. We cannot do that,
-+ though, since it does not work when using 32-bit definitions
-+ on 64-bit platforms and vice versa. */
-+ } a_un;
-+} Elf64_auxv_t;
-+
-+/* Legal values for a_type (entry type). */
-+
-+#define AT_NULL 0 /* End of vector */
-+#define AT_IGNORE 1 /* Entry should be ignored */
-+#define AT_EXECFD 2 /* File descriptor of program */
-+#define AT_PHDR 3 /* Program headers for program */
-+#define AT_PHENT 4 /* Size of program header entry */
-+#define AT_PHNUM 5 /* Number of program headers */
-+#define AT_PAGESZ 6 /* System page size */
-+#define AT_BASE 7 /* Base address of interpreter */
-+#define AT_FLAGS 8 /* Flags */
-+#define AT_ENTRY 9 /* Entry point of program */
-+#define AT_NOTELF 10 /* Program is not ELF */
-+#define AT_UID 11 /* Real uid */
-+#define AT_EUID 12 /* Effective uid */
-+#define AT_GID 13 /* Real gid */
-+#define AT_EGID 14 /* Effective gid */
-+#define AT_CLKTCK 17 /* Frequency of times() */
-+
-+/* Some more special a_type values describing the hardware. */
-+#define AT_PLATFORM 15 /* String identifying platform. */
-+#define AT_HWCAP 16 /* Machine dependent hints about
-+ processor capabilities. */
-+
-+/* This entry gives some information about the FPU initialization
-+ performed by the kernel. */
-+#define AT_FPUCW 18 /* Used FPU control word. */
-+
-+/* Cache block sizes. */
-+#define AT_DCACHEBSIZE 19 /* Data cache block size. */
-+#define AT_ICACHEBSIZE 20 /* Instruction cache block size. */
-+#define AT_UCACHEBSIZE 21 /* Unified cache block size. */
-+
-+/* A special ignored value for PPC, used by the kernel to control the
-+ interpretation of the AUXV. Must be > 16. */
-+#define AT_IGNOREPPC 22 /* Entry should be ignored. */
-+
-+#define AT_SECURE 23 /* Boolean, was exec setuid-like? */
-+
-+#define AT_BASE_PLATFORM 24 /* String identifying real platforms.*/
-+
-+#define AT_RANDOM 25 /* Address of 16 random bytes. */
-+
-+#define AT_EXECFN 31 /* Filename of executable. */
-+
-+/* Pointer to the global system page used for system calls and other
-+ nice things. */
-+#define AT_SYSINFO 32
-+#define AT_SYSINFO_EHDR 33
-+
-+/* Shapes of the caches. Bits 0-3 contains associativity; bits 4-7 contains
-+ log2 of line size; mask those to get cache size. */
-+#define AT_L1I_CACHESHAPE 34
-+#define AT_L1D_CACHESHAPE 35
-+#define AT_L2_CACHESHAPE 36
-+#define AT_L3_CACHESHAPE 37
-+
-+/* Note section contents. Each entry in the note section begins with
-+ a header of a fixed form. */
-+
-+typedef struct
-+{
-+ Elf32_Word n_namesz; /* Length of the note's name. */
-+ Elf32_Word n_descsz; /* Length of the note's descriptor. */
-+ Elf32_Word n_type; /* Type of the note. */
-+} Elf32_Nhdr;
-+
-+typedef struct
-+{
-+ Elf64_Word n_namesz; /* Length of the note's name. */
-+ Elf64_Word n_descsz; /* Length of the note's descriptor. */
-+ Elf64_Word n_type; /* Type of the note. */
-+} Elf64_Nhdr;
-+
-+/* Known names of notes. */
-+
-+/* Solaris entries in the note section have this name. */
-+#define ELF_NOTE_SOLARIS "SUNW Solaris"
-+
-+/* Note entries for GNU systems have this name. */
-+#define ELF_NOTE_GNU "GNU"
-+
-+
-+/* Defined types of notes for Solaris. */
-+
-+/* Value of descriptor (one word) is desired pagesize for the binary. */
-+#define ELF_NOTE_PAGESIZE_HINT 1
-+
-+
-+/* Defined note types for GNU systems. */
-+
-+/* ABI information. The descriptor consists of words:
-+ word 0: OS descriptor
-+ word 1: major version of the ABI
-+ word 2: minor version of the ABI
-+ word 3: subminor version of the ABI
-+*/
-+#define NT_GNU_ABI_TAG 1
-+#define ELF_NOTE_ABI NT_GNU_ABI_TAG /* Old name. */
-+
-+/* Known OSes. These values can appear in word 0 of an
-+ NT_GNU_ABI_TAG note section entry. */
-+#define ELF_NOTE_OS_LINUX 0
-+#define ELF_NOTE_OS_GNU 1
-+#define ELF_NOTE_OS_SOLARIS2 2
-+#define ELF_NOTE_OS_FREEBSD 3
-+
-+/* Synthetic hwcap information. The descriptor begins with two words:
-+ word 0: number of entries
-+ word 1: bitmask of enabled entries
-+ Then follow variable-length entries, one byte followed by a
-+ '\0'-terminated hwcap name string. The byte gives the bit
-+ number to test if enabled, (1U << bit) & bitmask. */
-+#define NT_GNU_HWCAP 2
-+
-+/* Build ID bits as generated by ld --build-id.
-+ The descriptor consists of any nonzero number of bytes. */
-+#define NT_GNU_BUILD_ID 3
-+
-+/* Version note generated by GNU gold containing a version string. */
-+#define NT_GNU_GOLD_VERSION 4
-+
-+
-+/* Move records. */
-+typedef struct
-+{
-+ Elf32_Xword m_value; /* Symbol value. */
-+ Elf32_Word m_info; /* Size and index. */
-+ Elf32_Word m_poffset; /* Symbol offset. */
-+ Elf32_Half m_repeat; /* Repeat count. */
-+ Elf32_Half m_stride; /* Stride info. */
-+} Elf32_Move;
-+
-+typedef struct
-+{
-+ Elf64_Xword m_value; /* Symbol value. */
-+ Elf64_Xword m_info; /* Size and index. */
-+ Elf64_Xword m_poffset; /* Symbol offset. */
-+ Elf64_Half m_repeat; /* Repeat count. */
-+ Elf64_Half m_stride; /* Stride info. */
-+} Elf64_Move;
-+
-+/* Macro to construct move records. */
-+#define ELF32_M_SYM(info) ((info) >> 8)
-+#define ELF32_M_SIZE(info) ((unsigned char) (info))
-+#define ELF32_M_INFO(sym, size) (((sym) << 8) + (unsigned char) (size))
-+
-+#define ELF64_M_SYM(info) ELF32_M_SYM (info)
-+#define ELF64_M_SIZE(info) ELF32_M_SIZE (info)
-+#define ELF64_M_INFO(sym, size) ELF32_M_INFO (sym, size)
-+
-+
-+/* Motorola 68k specific definitions. */
-+
-+/* Values for Elf32_Ehdr.e_flags. */
-+#define EF_CPU32 0x00810000
-+
-+/* m68k relocs. */
-+
-+#define R_68K_NONE 0 /* No reloc */
-+#define R_68K_32 1 /* Direct 32 bit */
-+#define R_68K_16 2 /* Direct 16 bit */
-+#define R_68K_8 3 /* Direct 8 bit */
-+#define R_68K_PC32 4 /* PC relative 32 bit */
-+#define R_68K_PC16 5 /* PC relative 16 bit */
-+#define R_68K_PC8 6 /* PC relative 8 bit */
-+#define R_68K_GOT32 7 /* 32 bit PC relative GOT entry */
-+#define R_68K_GOT16 8 /* 16 bit PC relative GOT entry */
-+#define R_68K_GOT8 9 /* 8 bit PC relative GOT entry */
-+#define R_68K_GOT32O 10 /* 32 bit GOT offset */
-+#define R_68K_GOT16O 11 /* 16 bit GOT offset */
-+#define R_68K_GOT8O 12 /* 8 bit GOT offset */
-+#define R_68K_PLT32 13 /* 32 bit PC relative PLT address */
-+#define R_68K_PLT16 14 /* 16 bit PC relative PLT address */
-+#define R_68K_PLT8 15 /* 8 bit PC relative PLT address */
-+#define R_68K_PLT32O 16 /* 32 bit PLT offset */
-+#define R_68K_PLT16O 17 /* 16 bit PLT offset */
-+#define R_68K_PLT8O 18 /* 8 bit PLT offset */
-+#define R_68K_COPY 19 /* Copy symbol at runtime */
-+#define R_68K_GLOB_DAT 20 /* Create GOT entry */
-+#define R_68K_JMP_SLOT 21 /* Create PLT entry */
-+#define R_68K_RELATIVE 22 /* Adjust by program base */
-+#define R_68K_TLS_GD32 25 /* 32 bit GOT offset for GD */
-+#define R_68K_TLS_GD16 26 /* 16 bit GOT offset for GD */
-+#define R_68K_TLS_GD8 27 /* 8 bit GOT offset for GD */
-+#define R_68K_TLS_LDM32 28 /* 32 bit GOT offset for LDM */
-+#define R_68K_TLS_LDM16 29 /* 16 bit GOT offset for LDM */
-+#define R_68K_TLS_LDM8 30 /* 8 bit GOT offset for LDM */
-+#define R_68K_TLS_LDO32 31 /* 32 bit module-relative offset */
-+#define R_68K_TLS_LDO16 32 /* 16 bit module-relative offset */
-+#define R_68K_TLS_LDO8 33 /* 8 bit module-relative offset */
-+#define R_68K_TLS_IE32 34 /* 32 bit GOT offset for IE */
-+#define R_68K_TLS_IE16 35 /* 16 bit GOT offset for IE */
-+#define R_68K_TLS_IE8 36 /* 8 bit GOT offset for IE */
-+#define R_68K_TLS_LE32 37 /* 32 bit offset relative to
-+ static TLS block */
-+#define R_68K_TLS_LE16 38 /* 16 bit offset relative to
-+ static TLS block */
-+#define R_68K_TLS_LE8 39 /* 8 bit offset relative to
-+ static TLS block */
-+#define R_68K_TLS_DTPMOD32 40 /* 32 bit module number */
-+#define R_68K_TLS_DTPREL32 41 /* 32 bit module-relative offset */
-+#define R_68K_TLS_TPREL32 42 /* 32 bit TP-relative offset */
-+/* Keep this the last entry. */
-+#define R_68K_NUM 43
-+
-+/* Intel 80386 specific definitions. */
-+
-+/* i386 relocs. */
-+
-+#define R_386_NONE 0 /* No reloc */
-+#define R_386_32 1 /* Direct 32 bit */
-+#define R_386_PC32 2 /* PC relative 32 bit */
-+#define R_386_GOT32 3 /* 32 bit GOT entry */
-+#define R_386_PLT32 4 /* 32 bit PLT address */
-+#define R_386_COPY 5 /* Copy symbol at runtime */
-+#define R_386_GLOB_DAT 6 /* Create GOT entry */
-+#define R_386_JMP_SLOT 7 /* Create PLT entry */
-+#define R_386_RELATIVE 8 /* Adjust by program base */
-+#define R_386_GOTOFF 9 /* 32 bit offset to GOT */
-+#define R_386_GOTPC 10 /* 32 bit PC relative offset to GOT */
-+#define R_386_32PLT 11
-+#define R_386_TLS_TPOFF 14 /* Offset in static TLS block */
-+#define R_386_TLS_IE 15 /* Address of GOT entry for static TLS
-+ block offset */
-+#define R_386_TLS_GOTIE 16 /* GOT entry for static TLS block
-+ offset */
-+#define R_386_TLS_LE 17 /* Offset relative to static TLS
-+ block */
-+#define R_386_TLS_GD 18 /* Direct 32 bit for GNU version of
-+ general dynamic thread local data */
-+#define R_386_TLS_LDM 19 /* Direct 32 bit for GNU version of
-+ local dynamic thread local data
-+ in LE code */
-+#define R_386_16 20
-+#define R_386_PC16 21
-+#define R_386_8 22
-+#define R_386_PC8 23
-+#define R_386_TLS_GD_32 24 /* Direct 32 bit for general dynamic
-+ thread local data */
-+#define R_386_TLS_GD_PUSH 25 /* Tag for pushl in GD TLS code */
-+#define R_386_TLS_GD_CALL 26 /* Relocation for call to
-+ __tls_get_addr() */
-+#define R_386_TLS_GD_POP 27 /* Tag for popl in GD TLS code */
-+#define R_386_TLS_LDM_32 28 /* Direct 32 bit for local dynamic
-+ thread local data in LE code */
-+#define R_386_TLS_LDM_PUSH 29 /* Tag for pushl in LDM TLS code */
-+#define R_386_TLS_LDM_CALL 30 /* Relocation for call to
-+ __tls_get_addr() in LDM code */
-+#define R_386_TLS_LDM_POP 31 /* Tag for popl in LDM TLS code */
-+#define R_386_TLS_LDO_32 32 /* Offset relative to TLS block */
-+#define R_386_TLS_IE_32 33 /* GOT entry for negated static TLS
-+ block offset */
-+#define R_386_TLS_LE_32 34 /* Negated offset relative to static
-+ TLS block */
-+#define R_386_TLS_DTPMOD32 35 /* ID of module containing symbol */
-+#define R_386_TLS_DTPOFF32 36 /* Offset in TLS block */
-+#define R_386_TLS_TPOFF32 37 /* Negated offset in static TLS block */
-+/* 38? */
-+#define R_386_TLS_GOTDESC 39 /* GOT offset for TLS descriptor. */
-+#define R_386_TLS_DESC_CALL 40 /* Marker of call through TLS
-+ descriptor for
-+ relaxation. */
-+#define R_386_TLS_DESC 41 /* TLS descriptor containing
-+ pointer to code and to
-+ argument, returning the TLS
-+ offset for the symbol. */
-+#define R_386_IRELATIVE 42 /* Adjust indirectly by program base */
-+/* Keep this the last entry. */
-+#define R_386_NUM 43
-+
-+/* SUN SPARC specific definitions. */
-+
-+/* Legal values for ST_TYPE subfield of st_info (symbol type). */
-+
-+#define STT_SPARC_REGISTER 13 /* Global register reserved to app. */
-+
-+/* Values for Elf64_Ehdr.e_flags. */
-+
-+#define EF_SPARCV9_MM 3
-+#define EF_SPARCV9_TSO 0
-+#define EF_SPARCV9_PSO 1
-+#define EF_SPARCV9_RMO 2
-+#define EF_SPARC_LEDATA 0x800000 /* little endian data */
-+#define EF_SPARC_EXT_MASK 0xFFFF00
-+#define EF_SPARC_32PLUS 0x000100 /* generic V8+ features */
-+#define EF_SPARC_SUN_US1 0x000200 /* Sun UltraSPARC1 extensions */
-+#define EF_SPARC_HAL_R1 0x000400 /* HAL R1 extensions */
-+#define EF_SPARC_SUN_US3 0x000800 /* Sun UltraSPARCIII extensions */
-+
-+/* SPARC relocs. */
-+
-+#define R_SPARC_NONE 0 /* No reloc */
-+#define R_SPARC_8 1 /* Direct 8 bit */
-+#define R_SPARC_16 2 /* Direct 16 bit */
-+#define R_SPARC_32 3 /* Direct 32 bit */
-+#define R_SPARC_DISP8 4 /* PC relative 8 bit */
-+#define R_SPARC_DISP16 5 /* PC relative 16 bit */
-+#define R_SPARC_DISP32 6 /* PC relative 32 bit */
-+#define R_SPARC_WDISP30 7 /* PC relative 30 bit shifted */
-+#define R_SPARC_WDISP22 8 /* PC relative 22 bit shifted */
-+#define R_SPARC_HI22 9 /* High 22 bit */
-+#define R_SPARC_22 10 /* Direct 22 bit */
-+#define R_SPARC_13 11 /* Direct 13 bit */
-+#define R_SPARC_LO10 12 /* Truncated 10 bit */
-+#define R_SPARC_GOT10 13 /* Truncated 10 bit GOT entry */
-+#define R_SPARC_GOT13 14 /* 13 bit GOT entry */
-+#define R_SPARC_GOT22 15 /* 22 bit GOT entry shifted */
-+#define R_SPARC_PC10 16 /* PC relative 10 bit truncated */
-+#define R_SPARC_PC22 17 /* PC relative 22 bit shifted */
-+#define R_SPARC_WPLT30 18 /* 30 bit PC relative PLT address */
-+#define R_SPARC_COPY 19 /* Copy symbol at runtime */
-+#define R_SPARC_GLOB_DAT 20 /* Create GOT entry */
-+#define R_SPARC_JMP_SLOT 21 /* Create PLT entry */
-+#define R_SPARC_RELATIVE 22 /* Adjust by program base */
-+#define R_SPARC_UA32 23 /* Direct 32 bit unaligned */
-+
-+/* Additional Sparc64 relocs. */
-+
-+#define R_SPARC_PLT32 24 /* Direct 32 bit ref to PLT entry */
-+#define R_SPARC_HIPLT22 25 /* High 22 bit PLT entry */
-+#define R_SPARC_LOPLT10 26 /* Truncated 10 bit PLT entry */
-+#define R_SPARC_PCPLT32 27 /* PC rel 32 bit ref to PLT entry */
-+#define R_SPARC_PCPLT22 28 /* PC rel high 22 bit PLT entry */
-+#define R_SPARC_PCPLT10 29 /* PC rel trunc 10 bit PLT entry */
-+#define R_SPARC_10 30 /* Direct 10 bit */
-+#define R_SPARC_11 31 /* Direct 11 bit */
-+#define R_SPARC_64 32 /* Direct 64 bit */
-+#define R_SPARC_OLO10 33 /* 10bit with secondary 13bit addend */
-+#define R_SPARC_HH22 34 /* Top 22 bits of direct 64 bit */
-+#define R_SPARC_HM10 35 /* High middle 10 bits of ... */
-+#define R_SPARC_LM22 36 /* Low middle 22 bits of ... */
-+#define R_SPARC_PC_HH22 37 /* Top 22 bits of pc rel 64 bit */
-+#define R_SPARC_PC_HM10 38 /* High middle 10 bit of ... */
-+#define R_SPARC_PC_LM22 39 /* Low miggle 22 bits of ... */
-+#define R_SPARC_WDISP16 40 /* PC relative 16 bit shifted */
-+#define R_SPARC_WDISP19 41 /* PC relative 19 bit shifted */
-+#define R_SPARC_GLOB_JMP 42 /* was part of v9 ABI but was removed */
-+#define R_SPARC_7 43 /* Direct 7 bit */
-+#define R_SPARC_5 44 /* Direct 5 bit */
-+#define R_SPARC_6 45 /* Direct 6 bit */
-+#define R_SPARC_DISP64 46 /* PC relative 64 bit */
-+#define R_SPARC_PLT64 47 /* Direct 64 bit ref to PLT entry */
-+#define R_SPARC_HIX22 48 /* High 22 bit complemented */
-+#define R_SPARC_LOX10 49 /* Truncated 11 bit complemented */
-+#define R_SPARC_H44 50 /* Direct high 12 of 44 bit */
-+#define R_SPARC_M44 51 /* Direct mid 22 of 44 bit */
-+#define R_SPARC_L44 52 /* Direct low 10 of 44 bit */
-+#define R_SPARC_REGISTER 53 /* Global register usage */
-+#define R_SPARC_UA64 54 /* Direct 64 bit unaligned */
-+#define R_SPARC_UA16 55 /* Direct 16 bit unaligned */
-+#define R_SPARC_TLS_GD_HI22 56
-+#define R_SPARC_TLS_GD_LO10 57
-+#define R_SPARC_TLS_GD_ADD 58
-+#define R_SPARC_TLS_GD_CALL 59
-+#define R_SPARC_TLS_LDM_HI22 60
-+#define R_SPARC_TLS_LDM_LO10 61
-+#define R_SPARC_TLS_LDM_ADD 62
-+#define R_SPARC_TLS_LDM_CALL 63
-+#define R_SPARC_TLS_LDO_HIX22 64
-+#define R_SPARC_TLS_LDO_LOX10 65
-+#define R_SPARC_TLS_LDO_ADD 66
-+#define R_SPARC_TLS_IE_HI22 67
-+#define R_SPARC_TLS_IE_LO10 68
-+#define R_SPARC_TLS_IE_LD 69
-+#define R_SPARC_TLS_IE_LDX 70
-+#define R_SPARC_TLS_IE_ADD 71
-+#define R_SPARC_TLS_LE_HIX22 72
-+#define R_SPARC_TLS_LE_LOX10 73
-+#define R_SPARC_TLS_DTPMOD32 74
-+#define R_SPARC_TLS_DTPMOD64 75
-+#define R_SPARC_TLS_DTPOFF32 76
-+#define R_SPARC_TLS_DTPOFF64 77
-+#define R_SPARC_TLS_TPOFF32 78
-+#define R_SPARC_TLS_TPOFF64 79
-+#define R_SPARC_GOTDATA_HIX22 80
-+#define R_SPARC_GOTDATA_LOX10 81
-+#define R_SPARC_GOTDATA_OP_HIX22 82
-+#define R_SPARC_GOTDATA_OP_LOX10 83
-+#define R_SPARC_GOTDATA_OP 84
-+#define R_SPARC_H34 85
-+#define R_SPARC_SIZE32 86
-+#define R_SPARC_SIZE64 87
-+#define R_SPARC_WDISP10 88
-+#define R_SPARC_JMP_IREL 248
-+#define R_SPARC_IRELATIVE 249
-+#define R_SPARC_GNU_VTINHERIT 250
-+#define R_SPARC_GNU_VTENTRY 251
-+#define R_SPARC_REV32 252
-+/* Keep this the last entry. */
-+#define R_SPARC_NUM 253
-+
-+/* For Sparc64, legal values for d_tag of Elf64_Dyn. */
-+
-+#define DT_SPARC_REGISTER 0x70000001
-+#define DT_SPARC_NUM 2
-+
-+/* MIPS R3000 specific definitions. */
-+
-+/* Legal values for e_flags field of Elf32_Ehdr. */
-+
-+#define EF_MIPS_NOREORDER 1 /* A .noreorder directive was used */
-+#define EF_MIPS_PIC 2 /* Contains PIC code */
-+#define EF_MIPS_CPIC 4 /* Uses PIC calling sequence */
-+#define EF_MIPS_XGOT 8
-+#define EF_MIPS_64BIT_WHIRL 16
-+#define EF_MIPS_ABI2 32
-+#define EF_MIPS_ABI_ON32 64
-+#define EF_MIPS_ARCH 0xf0000000 /* MIPS architecture level */
-+
-+/* Legal values for MIPS architecture level. */
-+
-+#define EF_MIPS_ARCH_1 0x00000000 /* -mips1 code. */
-+#define EF_MIPS_ARCH_2 0x10000000 /* -mips2 code. */
-+#define EF_MIPS_ARCH_3 0x20000000 /* -mips3 code. */
-+#define EF_MIPS_ARCH_4 0x30000000 /* -mips4 code. */
-+#define EF_MIPS_ARCH_5 0x40000000 /* -mips5 code. */
-+#define EF_MIPS_ARCH_32 0x60000000 /* MIPS32 code. */
-+#define EF_MIPS_ARCH_64 0x70000000 /* MIPS64 code. */
-+
-+/* The following are non-official names and should not be used. */
-+
-+#define E_MIPS_ARCH_1 0x00000000 /* -mips1 code. */
-+#define E_MIPS_ARCH_2 0x10000000 /* -mips2 code. */
-+#define E_MIPS_ARCH_3 0x20000000 /* -mips3 code. */
-+#define E_MIPS_ARCH_4 0x30000000 /* -mips4 code. */
-+#define E_MIPS_ARCH_5 0x40000000 /* -mips5 code. */
-+#define E_MIPS_ARCH_32 0x60000000 /* MIPS32 code. */
-+#define E_MIPS_ARCH_64 0x70000000 /* MIPS64 code. */
-+
-+/* Special section indices. */
-+
-+#define SHN_MIPS_ACOMMON 0xff00 /* Allocated common symbols */
-+#define SHN_MIPS_TEXT 0xff01 /* Allocated test symbols. */
-+#define SHN_MIPS_DATA 0xff02 /* Allocated data symbols. */
-+#define SHN_MIPS_SCOMMON 0xff03 /* Small common symbols */
-+#define SHN_MIPS_SUNDEFINED 0xff04 /* Small undefined symbols */
-+
-+/* Legal values for sh_type field of Elf32_Shdr. */
-+
-+#define SHT_MIPS_LIBLIST 0x70000000 /* Shared objects used in link */
-+#define SHT_MIPS_MSYM 0x70000001
-+#define SHT_MIPS_CONFLICT 0x70000002 /* Conflicting symbols */
-+#define SHT_MIPS_GPTAB 0x70000003 /* Global data area sizes */
-+#define SHT_MIPS_UCODE 0x70000004 /* Reserved for SGI/MIPS compilers */
-+#define SHT_MIPS_DEBUG 0x70000005 /* MIPS ECOFF debugging information*/
-+#define SHT_MIPS_REGINFO 0x70000006 /* Register usage information */
-+#define SHT_MIPS_PACKAGE 0x70000007
-+#define SHT_MIPS_PACKSYM 0x70000008
-+#define SHT_MIPS_RELD 0x70000009
-+#define SHT_MIPS_IFACE 0x7000000b
-+#define SHT_MIPS_CONTENT 0x7000000c
-+#define SHT_MIPS_OPTIONS 0x7000000d /* Miscellaneous options. */
-+#define SHT_MIPS_SHDR 0x70000010
-+#define SHT_MIPS_FDESC 0x70000011
-+#define SHT_MIPS_EXTSYM 0x70000012
-+#define SHT_MIPS_DENSE 0x70000013
-+#define SHT_MIPS_PDESC 0x70000014
-+#define SHT_MIPS_LOCSYM 0x70000015
-+#define SHT_MIPS_AUXSYM 0x70000016
-+#define SHT_MIPS_OPTSYM 0x70000017
-+#define SHT_MIPS_LOCSTR 0x70000018
-+#define SHT_MIPS_LINE 0x70000019
-+#define SHT_MIPS_RFDESC 0x7000001a
-+#define SHT_MIPS_DELTASYM 0x7000001b
-+#define SHT_MIPS_DELTAINST 0x7000001c
-+#define SHT_MIPS_DELTACLASS 0x7000001d
-+#define SHT_MIPS_DWARF 0x7000001e /* DWARF debugging information. */
-+#define SHT_MIPS_DELTADECL 0x7000001f
-+#define SHT_MIPS_SYMBOL_LIB 0x70000020
-+#define SHT_MIPS_EVENTS 0x70000021 /* Event section. */
-+#define SHT_MIPS_TRANSLATE 0x70000022
-+#define SHT_MIPS_PIXIE 0x70000023
-+#define SHT_MIPS_XLATE 0x70000024
-+#define SHT_MIPS_XLATE_DEBUG 0x70000025
-+#define SHT_MIPS_WHIRL 0x70000026
-+#define SHT_MIPS_EH_REGION 0x70000027
-+#define SHT_MIPS_XLATE_OLD 0x70000028
-+#define SHT_MIPS_PDR_EXCEPTION 0x70000029
-+
-+/* Legal values for sh_flags field of Elf32_Shdr. */
-+
-+#define SHF_MIPS_GPREL 0x10000000 /* Must be part of global data area */
-+#define SHF_MIPS_MERGE 0x20000000
-+#define SHF_MIPS_ADDR 0x40000000
-+#define SHF_MIPS_STRINGS 0x80000000
-+#define SHF_MIPS_NOSTRIP 0x08000000
-+#define SHF_MIPS_LOCAL 0x04000000
-+#define SHF_MIPS_NAMES 0x02000000
-+#define SHF_MIPS_NODUPE 0x01000000
-+
-+
-+/* Symbol tables. */
-+
-+/* MIPS specific values for `st_other'. */
-+#define STO_MIPS_DEFAULT 0x0
-+#define STO_MIPS_INTERNAL 0x1
-+#define STO_MIPS_HIDDEN 0x2
-+#define STO_MIPS_PROTECTED 0x3
-+#define STO_MIPS_PLT 0x8
-+#define STO_MIPS_SC_ALIGN_UNUSED 0xff
-+
-+/* MIPS specific values for `st_info'. */
-+#define STB_MIPS_SPLIT_COMMON 13
-+
-+/* Entries found in sections of type SHT_MIPS_GPTAB. */
-+
-+typedef union
-+{
-+ struct
-+ {
-+ Elf32_Word gt_current_g_value; /* -G value used for compilation */
-+ Elf32_Word gt_unused; /* Not used */
-+ } gt_header; /* First entry in section */
-+ struct
-+ {
-+ Elf32_Word gt_g_value; /* If this value were used for -G */
-+ Elf32_Word gt_bytes; /* This many bytes would be used */
-+ } gt_entry; /* Subsequent entries in section */
-+} Elf32_gptab;
-+
-+/* Entry found in sections of type SHT_MIPS_REGINFO. */
-+
-+typedef struct
-+{
-+ Elf32_Word ri_gprmask; /* General registers used */
-+ Elf32_Word ri_cprmask[4]; /* Coprocessor registers used */
-+ Elf32_Sword ri_gp_value; /* $gp register value */
-+} Elf32_RegInfo;
-+
-+/* Entries found in sections of type SHT_MIPS_OPTIONS. */
-+
-+typedef struct
-+{
-+ unsigned char kind; /* Determines interpretation of the
-+ variable part of descriptor. */
-+ unsigned char size; /* Size of descriptor, including header. */
-+ Elf32_Section section; /* Section header index of section affected,
-+ 0 for global options. */
-+ Elf32_Word info; /* Kind-specific information. */
-+} Elf_Options;
-+
-+/* Values for `kind' field in Elf_Options. */
-+
-+#define ODK_NULL 0 /* Undefined. */
-+#define ODK_REGINFO 1 /* Register usage information. */
-+#define ODK_EXCEPTIONS 2 /* Exception processing options. */
-+#define ODK_PAD 3 /* Section padding options. */
-+#define ODK_HWPATCH 4 /* Hardware workarounds performed */
-+#define ODK_FILL 5 /* record the fill value used by the linker. */
-+#define ODK_TAGS 6 /* reserve space for desktop tools to write. */
-+#define ODK_HWAND 7 /* HW workarounds. 'AND' bits when merging. */
-+#define ODK_HWOR 8 /* HW workarounds. 'OR' bits when merging. */
-+
-+/* Values for `info' in Elf_Options for ODK_EXCEPTIONS entries. */
-+
-+#define OEX_FPU_MIN 0x1f /* FPE's which MUST be enabled. */
-+#define OEX_FPU_MAX 0x1f00 /* FPE's which MAY be enabled. */
-+#define OEX_PAGE0 0x10000 /* page zero must be mapped. */
-+#define OEX_SMM 0x20000 /* Force sequential memory mode? */
-+#define OEX_FPDBUG 0x40000 /* Force floating point debug mode? */
-+#define OEX_PRECISEFP OEX_FPDBUG
-+#define OEX_DISMISS 0x80000 /* Dismiss invalid address faults? */
-+
-+#define OEX_FPU_INVAL 0x10
-+#define OEX_FPU_DIV0 0x08
-+#define OEX_FPU_OFLO 0x04
-+#define OEX_FPU_UFLO 0x02
-+#define OEX_FPU_INEX 0x01
-+
-+/* Masks for `info' in Elf_Options for an ODK_HWPATCH entry. */
-+
-+#define OHW_R4KEOP 0x1 /* R4000 end-of-page patch. */
-+#define OHW_R8KPFETCH 0x2 /* may need R8000 prefetch patch. */
-+#define OHW_R5KEOP 0x4 /* R5000 end-of-page patch. */
-+#define OHW_R5KCVTL 0x8 /* R5000 cvt.[ds].l bug. clean=1. */
-+
-+#define OPAD_PREFIX 0x1
-+#define OPAD_POSTFIX 0x2
-+#define OPAD_SYMBOL 0x4
-+
-+/* Entry found in `.options' section. */
-+
-+typedef struct
-+{
-+ Elf32_Word hwp_flags1; /* Extra flags. */
-+ Elf32_Word hwp_flags2; /* Extra flags. */
-+} Elf_Options_Hw;
-+
-+/* Masks for `info' in ElfOptions for ODK_HWAND and ODK_HWOR entries. */
-+
-+#define OHWA0_R4KEOP_CHECKED 0x00000001
-+#define OHWA1_R4KEOP_CLEAN 0x00000002
-+
-+/* MIPS relocs. */
-+
-+#define R_MIPS_NONE 0 /* No reloc */
-+#define R_MIPS_16 1 /* Direct 16 bit */
-+#define R_MIPS_32 2 /* Direct 32 bit */
-+#define R_MIPS_REL32 3 /* PC relative 32 bit */
-+#define R_MIPS_26 4 /* Direct 26 bit shifted */
-+#define R_MIPS_HI16 5 /* High 16 bit */
-+#define R_MIPS_LO16 6 /* Low 16 bit */
-+#define R_MIPS_GPREL16 7 /* GP relative 16 bit */
-+#define R_MIPS_LITERAL 8 /* 16 bit literal entry */
-+#define R_MIPS_GOT16 9 /* 16 bit GOT entry */
-+#define R_MIPS_PC16 10 /* PC relative 16 bit */
-+#define R_MIPS_CALL16 11 /* 16 bit GOT entry for function */
-+#define R_MIPS_GPREL32 12 /* GP relative 32 bit */
-+
-+#define R_MIPS_SHIFT5 16
-+#define R_MIPS_SHIFT6 17
-+#define R_MIPS_64 18
-+#define R_MIPS_GOT_DISP 19
-+#define R_MIPS_GOT_PAGE 20
-+#define R_MIPS_GOT_OFST 21
-+#define R_MIPS_GOT_HI16 22
-+#define R_MIPS_GOT_LO16 23
-+#define R_MIPS_SUB 24
-+#define R_MIPS_INSERT_A 25
-+#define R_MIPS_INSERT_B 26
-+#define R_MIPS_DELETE 27
-+#define R_MIPS_HIGHER 28
-+#define R_MIPS_HIGHEST 29
-+#define R_MIPS_CALL_HI16 30
-+#define R_MIPS_CALL_LO16 31
-+#define R_MIPS_SCN_DISP 32
-+#define R_MIPS_REL16 33
-+#define R_MIPS_ADD_IMMEDIATE 34
-+#define R_MIPS_PJUMP 35
-+#define R_MIPS_RELGOT 36
-+#define R_MIPS_JALR 37
-+#define R_MIPS_TLS_DTPMOD32 38 /* Module number 32 bit */
-+#define R_MIPS_TLS_DTPREL32 39 /* Module-relative offset 32 bit */
-+#define R_MIPS_TLS_DTPMOD64 40 /* Module number 64 bit */
-+#define R_MIPS_TLS_DTPREL64 41 /* Module-relative offset 64 bit */
-+#define R_MIPS_TLS_GD 42 /* 16 bit GOT offset for GD */
-+#define R_MIPS_TLS_LDM 43 /* 16 bit GOT offset for LDM */
-+#define R_MIPS_TLS_DTPREL_HI16 44 /* Module-relative offset, high 16 bits */
-+#define R_MIPS_TLS_DTPREL_LO16 45 /* Module-relative offset, low 16 bits */
-+#define R_MIPS_TLS_GOTTPREL 46 /* 16 bit GOT offset for IE */
-+#define R_MIPS_TLS_TPREL32 47 /* TP-relative offset, 32 bit */
-+#define R_MIPS_TLS_TPREL64 48 /* TP-relative offset, 64 bit */
-+#define R_MIPS_TLS_TPREL_HI16 49 /* TP-relative offset, high 16 bits */
-+#define R_MIPS_TLS_TPREL_LO16 50 /* TP-relative offset, low 16 bits */
-+#define R_MIPS_GLOB_DAT 51
-+#define R_MIPS_COPY 126
-+#define R_MIPS_JUMP_SLOT 127
-+/* Keep this the last entry. */
-+#define R_MIPS_NUM 128
-+
-+/* Legal values for p_type field of Elf32_Phdr. */
-+
-+#define PT_MIPS_REGINFO 0x70000000 /* Register usage information */
-+#define PT_MIPS_RTPROC 0x70000001 /* Runtime procedure table. */
-+#define PT_MIPS_OPTIONS 0x70000002
-+
-+/* Special program header types. */
-+
-+#define PF_MIPS_LOCAL 0x10000000
-+
-+/* Legal values for d_tag field of Elf32_Dyn. */
-+
-+#define DT_MIPS_RLD_VERSION 0x70000001 /* Runtime linker interface version */
-+#define DT_MIPS_TIME_STAMP 0x70000002 /* Timestamp */
-+#define DT_MIPS_ICHECKSUM 0x70000003 /* Checksum */
-+#define DT_MIPS_IVERSION 0x70000004 /* Version string (string tbl index) */
-+#define DT_MIPS_FLAGS 0x70000005 /* Flags */
-+#define DT_MIPS_BASE_ADDRESS 0x70000006 /* Base address */
-+#define DT_MIPS_MSYM 0x70000007
-+#define DT_MIPS_CONFLICT 0x70000008 /* Address of CONFLICT section */
-+#define DT_MIPS_LIBLIST 0x70000009 /* Address of LIBLIST section */
-+#define DT_MIPS_LOCAL_GOTNO 0x7000000a /* Number of local GOT entries */
-+#define DT_MIPS_CONFLICTNO 0x7000000b /* Number of CONFLICT entries */
-+#define DT_MIPS_LIBLISTNO 0x70000010 /* Number of LIBLIST entries */
-+#define DT_MIPS_SYMTABNO 0x70000011 /* Number of DYNSYM entries */
-+#define DT_MIPS_UNREFEXTNO 0x70000012 /* First external DYNSYM */
-+#define DT_MIPS_GOTSYM 0x70000013 /* First GOT entry in DYNSYM */
-+#define DT_MIPS_HIPAGENO 0x70000014 /* Number of GOT page table entries */
-+#define DT_MIPS_RLD_MAP 0x70000016 /* Address of run time loader map. */
-+#define DT_MIPS_DELTA_CLASS 0x70000017 /* Delta C++ class definition. */
-+#define DT_MIPS_DELTA_CLASS_NO 0x70000018 /* Number of entries in
-+ DT_MIPS_DELTA_CLASS. */
-+#define DT_MIPS_DELTA_INSTANCE 0x70000019 /* Delta C++ class instances. */
-+#define DT_MIPS_DELTA_INSTANCE_NO 0x7000001a /* Number of entries in
-+ DT_MIPS_DELTA_INSTANCE. */
-+#define DT_MIPS_DELTA_RELOC 0x7000001b /* Delta relocations. */
-+#define DT_MIPS_DELTA_RELOC_NO 0x7000001c /* Number of entries in
-+ DT_MIPS_DELTA_RELOC. */
-+#define DT_MIPS_DELTA_SYM 0x7000001d /* Delta symbols that Delta
-+ relocations refer to. */
-+#define DT_MIPS_DELTA_SYM_NO 0x7000001e /* Number of entries in
-+ DT_MIPS_DELTA_SYM. */
-+#define DT_MIPS_DELTA_CLASSSYM 0x70000020 /* Delta symbols that hold the
-+ class declaration. */
-+#define DT_MIPS_DELTA_CLASSSYM_NO 0x70000021 /* Number of entries in
-+ DT_MIPS_DELTA_CLASSSYM. */
-+#define DT_MIPS_CXX_FLAGS 0x70000022 /* Flags indicating for C++ flavor. */
-+#define DT_MIPS_PIXIE_INIT 0x70000023
-+#define DT_MIPS_SYMBOL_LIB 0x70000024
-+#define DT_MIPS_LOCALPAGE_GOTIDX 0x70000025
-+#define DT_MIPS_LOCAL_GOTIDX 0x70000026
-+#define DT_MIPS_HIDDEN_GOTIDX 0x70000027
-+#define DT_MIPS_PROTECTED_GOTIDX 0x70000028
-+#define DT_MIPS_OPTIONS 0x70000029 /* Address of .options. */
-+#define DT_MIPS_INTERFACE 0x7000002a /* Address of .interface. */
-+#define DT_MIPS_DYNSTR_ALIGN 0x7000002b
-+#define DT_MIPS_INTERFACE_SIZE 0x7000002c /* Size of the .interface section. */
-+#define DT_MIPS_RLD_TEXT_RESOLVE_ADDR 0x7000002d /* Address of rld_text_rsolve
-+ function stored in GOT. */
-+#define DT_MIPS_PERF_SUFFIX 0x7000002e /* Default suffix of dso to be added
-+ by rld on dlopen() calls. */
-+#define DT_MIPS_COMPACT_SIZE 0x7000002f /* (O32)Size of compact rel section. */
-+#define DT_MIPS_GP_VALUE 0x70000030 /* GP value for aux GOTs. */
-+#define DT_MIPS_AUX_DYNAMIC 0x70000031 /* Address of aux .dynamic. */
-+/* The address of .got.plt in an executable using the new non-PIC ABI. */
-+#define DT_MIPS_PLTGOT 0x70000032
-+/* The base of the PLT in an executable using the new non-PIC ABI if that
-+ PLT is writable. For a non-writable PLT, this is omitted or has a zero
-+ value. */
-+#define DT_MIPS_RWPLT 0x70000034
-+#define DT_MIPS_NUM 0x35
-+
-+/* Legal values for DT_MIPS_FLAGS Elf32_Dyn entry. */
-+
-+#define RHF_NONE 0 /* No flags */
-+#define RHF_QUICKSTART (1 << 0) /* Use quickstart */
-+#define RHF_NOTPOT (1 << 1) /* Hash size not power of 2 */
-+#define RHF_NO_LIBRARY_REPLACEMENT (1 << 2) /* Ignore LD_LIBRARY_PATH */
-+#define RHF_NO_MOVE (1 << 3)
-+#define RHF_SGI_ONLY (1 << 4)
-+#define RHF_GUARANTEE_INIT (1 << 5)
-+#define RHF_DELTA_C_PLUS_PLUS (1 << 6)
-+#define RHF_GUARANTEE_START_INIT (1 << 7)
-+#define RHF_PIXIE (1 << 8)
-+#define RHF_DEFAULT_DELAY_LOAD (1 << 9)
-+#define RHF_REQUICKSTART (1 << 10)
-+#define RHF_REQUICKSTARTED (1 << 11)
-+#define RHF_CORD (1 << 12)
-+#define RHF_NO_UNRES_UNDEF (1 << 13)
-+#define RHF_RLD_ORDER_SAFE (1 << 14)
-+
-+/* Entries found in sections of type SHT_MIPS_LIBLIST. */
-+
-+typedef struct
-+{
-+ Elf32_Word l_name; /* Name (string table index) */
-+ Elf32_Word l_time_stamp; /* Timestamp */
-+ Elf32_Word l_checksum; /* Checksum */
-+ Elf32_Word l_version; /* Interface version */
-+ Elf32_Word l_flags; /* Flags */
-+} Elf32_Lib;
-+
-+typedef struct
-+{
-+ Elf64_Word l_name; /* Name (string table index) */
-+ Elf64_Word l_time_stamp; /* Timestamp */
-+ Elf64_Word l_checksum; /* Checksum */
-+ Elf64_Word l_version; /* Interface version */
-+ Elf64_Word l_flags; /* Flags */
-+} Elf64_Lib;
-+
-+
-+/* Legal values for l_flags. */
-+
-+#define LL_NONE 0
-+#define LL_EXACT_MATCH (1 << 0) /* Require exact match */
-+#define LL_IGNORE_INT_VER (1 << 1) /* Ignore interface version */
-+#define LL_REQUIRE_MINOR (1 << 2)
-+#define LL_EXPORTS (1 << 3)
-+#define LL_DELAY_LOAD (1 << 4)
-+#define LL_DELTA (1 << 5)
-+
-+/* Entries found in sections of type SHT_MIPS_CONFLICT. */
-+
-+typedef Elf32_Addr Elf32_Conflict;
-+
-+
-+/* HPPA specific definitions. */
-+
-+/* Legal values for e_flags field of Elf32_Ehdr. */
-+
-+#define EF_PARISC_TRAPNIL 0x00010000 /* Trap nil pointer dereference. */
-+#define EF_PARISC_EXT 0x00020000 /* Program uses arch. extensions. */
-+#define EF_PARISC_LSB 0x00040000 /* Program expects little endian. */
-+#define EF_PARISC_WIDE 0x00080000 /* Program expects wide mode. */
-+#define EF_PARISC_NO_KABP 0x00100000 /* No kernel assisted branch
-+ prediction. */
-+#define EF_PARISC_LAZYSWAP 0x00400000 /* Allow lazy swapping. */
-+#define EF_PARISC_ARCH 0x0000ffff /* Architecture version. */
-+
-+/* Defined values for `e_flags & EF_PARISC_ARCH' are: */
-+
-+#define EFA_PARISC_1_0 0x020b /* PA-RISC 1.0 big-endian. */
-+#define EFA_PARISC_1_1 0x0210 /* PA-RISC 1.1 big-endian. */
-+#define EFA_PARISC_2_0 0x0214 /* PA-RISC 2.0 big-endian. */
-+
-+/* Additional section indeces. */
-+
-+#define SHN_PARISC_ANSI_COMMON 0xff00 /* Section for tenatively declared
-+ symbols in ANSI C. */
-+#define SHN_PARISC_HUGE_COMMON 0xff01 /* Common blocks in huge model. */
-+
-+/* Legal values for sh_type field of Elf32_Shdr. */
-+
-+#define SHT_PARISC_EXT 0x70000000 /* Contains product specific ext. */
-+#define SHT_PARISC_UNWIND 0x70000001 /* Unwind information. */
-+#define SHT_PARISC_DOC 0x70000002 /* Debug info for optimized code. */
-+
-+/* Legal values for sh_flags field of Elf32_Shdr. */
-+
-+#define SHF_PARISC_SHORT 0x20000000 /* Section with short addressing. */
-+#define SHF_PARISC_HUGE 0x40000000 /* Section far from gp. */
-+#define SHF_PARISC_SBP 0x80000000 /* Static branch prediction code. */
-+
-+/* Legal values for ST_TYPE subfield of st_info (symbol type). */
-+
-+#define STT_PARISC_MILLICODE 13 /* Millicode function entry point. */
-+
-+#define STT_HP_OPAQUE (STT_LOOS + 0x1)
-+#define STT_HP_STUB (STT_LOOS + 0x2)
-+
-+/* HPPA relocs. */
-+
-+#define R_PARISC_NONE 0 /* No reloc. */
-+#define R_PARISC_DIR32 1 /* Direct 32-bit reference. */
-+#define R_PARISC_DIR21L 2 /* Left 21 bits of eff. address. */
-+#define R_PARISC_DIR17R 3 /* Right 17 bits of eff. address. */
-+#define R_PARISC_DIR17F 4 /* 17 bits of eff. address. */
-+#define R_PARISC_DIR14R 6 /* Right 14 bits of eff. address. */
-+#define R_PARISC_PCREL32 9 /* 32-bit rel. address. */
-+#define R_PARISC_PCREL21L 10 /* Left 21 bits of rel. address. */
-+#define R_PARISC_PCREL17R 11 /* Right 17 bits of rel. address. */
-+#define R_PARISC_PCREL17F 12 /* 17 bits of rel. address. */
-+#define R_PARISC_PCREL14R 14 /* Right 14 bits of rel. address. */
-+#define R_PARISC_DPREL21L 18 /* Left 21 bits of rel. address. */
-+#define R_PARISC_DPREL14R 22 /* Right 14 bits of rel. address. */
-+#define R_PARISC_GPREL21L 26 /* GP-relative, left 21 bits. */
-+#define R_PARISC_GPREL14R 30 /* GP-relative, right 14 bits. */
-+#define R_PARISC_LTOFF21L 34 /* LT-relative, left 21 bits. */
-+#define R_PARISC_LTOFF14R 38 /* LT-relative, right 14 bits. */
-+#define R_PARISC_SECREL32 41 /* 32 bits section rel. address. */
-+#define R_PARISC_SEGBASE 48 /* No relocation, set segment base. */
-+#define R_PARISC_SEGREL32 49 /* 32 bits segment rel. address. */
-+#define R_PARISC_PLTOFF21L 50 /* PLT rel. address, left 21 bits. */
-+#define R_PARISC_PLTOFF14R 54 /* PLT rel. address, right 14 bits. */
-+#define R_PARISC_LTOFF_FPTR32 57 /* 32 bits LT-rel. function pointer. */
-+#define R_PARISC_LTOFF_FPTR21L 58 /* LT-rel. fct ptr, left 21 bits. */
-+#define R_PARISC_LTOFF_FPTR14R 62 /* LT-rel. fct ptr, right 14 bits. */
-+#define R_PARISC_FPTR64 64 /* 64 bits function address. */
-+#define R_PARISC_PLABEL32 65 /* 32 bits function address. */
-+#define R_PARISC_PLABEL21L 66 /* Left 21 bits of fdesc address. */
-+#define R_PARISC_PLABEL14R 70 /* Right 14 bits of fdesc address. */
-+#define R_PARISC_PCREL64 72 /* 64 bits PC-rel. address. */
-+#define R_PARISC_PCREL22F 74 /* 22 bits PC-rel. address. */
-+#define R_PARISC_PCREL14WR 75 /* PC-rel. address, right 14 bits. */
-+#define R_PARISC_PCREL14DR 76 /* PC rel. address, right 14 bits. */
-+#define R_PARISC_PCREL16F 77 /* 16 bits PC-rel. address. */
-+#define R_PARISC_PCREL16WF 78 /* 16 bits PC-rel. address. */
-+#define R_PARISC_PCREL16DF 79 /* 16 bits PC-rel. address. */
-+#define R_PARISC_DIR64 80 /* 64 bits of eff. address. */
-+#define R_PARISC_DIR14WR 83 /* 14 bits of eff. address. */
-+#define R_PARISC_DIR14DR 84 /* 14 bits of eff. address. */
-+#define R_PARISC_DIR16F 85 /* 16 bits of eff. address. */
-+#define R_PARISC_DIR16WF 86 /* 16 bits of eff. address. */
-+#define R_PARISC_DIR16DF 87 /* 16 bits of eff. address. */
-+#define R_PARISC_GPREL64 88 /* 64 bits of GP-rel. address. */
-+#define R_PARISC_GPREL14WR 91 /* GP-rel. address, right 14 bits. */
-+#define R_PARISC_GPREL14DR 92 /* GP-rel. address, right 14 bits. */
-+#define R_PARISC_GPREL16F 93 /* 16 bits GP-rel. address. */
-+#define R_PARISC_GPREL16WF 94 /* 16 bits GP-rel. address. */
-+#define R_PARISC_GPREL16DF 95 /* 16 bits GP-rel. address. */
-+#define R_PARISC_LTOFF64 96 /* 64 bits LT-rel. address. */
-+#define R_PARISC_LTOFF14WR 99 /* LT-rel. address, right 14 bits. */
-+#define R_PARISC_LTOFF14DR 100 /* LT-rel. address, right 14 bits. */
-+#define R_PARISC_LTOFF16F 101 /* 16 bits LT-rel. address. */
-+#define R_PARISC_LTOFF16WF 102 /* 16 bits LT-rel. address. */
-+#define R_PARISC_LTOFF16DF 103 /* 16 bits LT-rel. address. */
-+#define R_PARISC_SECREL64 104 /* 64 bits section rel. address. */
-+#define R_PARISC_SEGREL64 112 /* 64 bits segment rel. address. */
-+#define R_PARISC_PLTOFF14WR 115 /* PLT-rel. address, right 14 bits. */
-+#define R_PARISC_PLTOFF14DR 116 /* PLT-rel. address, right 14 bits. */
-+#define R_PARISC_PLTOFF16F 117 /* 16 bits LT-rel. address. */
-+#define R_PARISC_PLTOFF16WF 118 /* 16 bits PLT-rel. address. */
-+#define R_PARISC_PLTOFF16DF 119 /* 16 bits PLT-rel. address. */
-+#define R_PARISC_LTOFF_FPTR64 120 /* 64 bits LT-rel. function ptr. */
-+#define R_PARISC_LTOFF_FPTR14WR 123 /* LT-rel. fct. ptr., right 14 bits. */
-+#define R_PARISC_LTOFF_FPTR14DR 124 /* LT-rel. fct. ptr., right 14 bits. */
-+#define R_PARISC_LTOFF_FPTR16F 125 /* 16 bits LT-rel. function ptr. */
-+#define R_PARISC_LTOFF_FPTR16WF 126 /* 16 bits LT-rel. function ptr. */
-+#define R_PARISC_LTOFF_FPTR16DF 127 /* 16 bits LT-rel. function ptr. */
-+#define R_PARISC_LORESERVE 128
-+#define R_PARISC_COPY 128 /* Copy relocation. */
-+#define R_PARISC_IPLT 129 /* Dynamic reloc, imported PLT */
-+#define R_PARISC_EPLT 130 /* Dynamic reloc, exported PLT */
-+#define R_PARISC_TPREL32 153 /* 32 bits TP-rel. address. */
-+#define R_PARISC_TPREL21L 154 /* TP-rel. address, left 21 bits. */
-+#define R_PARISC_TPREL14R 158 /* TP-rel. address, right 14 bits. */
-+#define R_PARISC_LTOFF_TP21L 162 /* LT-TP-rel. address, left 21 bits. */
-+#define R_PARISC_LTOFF_TP14R 166 /* LT-TP-rel. address, right 14 bits.*/
-+#define R_PARISC_LTOFF_TP14F 167 /* 14 bits LT-TP-rel. address. */
-+#define R_PARISC_TPREL64 216 /* 64 bits TP-rel. address. */
-+#define R_PARISC_TPREL14WR 219 /* TP-rel. address, right 14 bits. */
-+#define R_PARISC_TPREL14DR 220 /* TP-rel. address, right 14 bits. */
-+#define R_PARISC_TPREL16F 221 /* 16 bits TP-rel. address. */
-+#define R_PARISC_TPREL16WF 222 /* 16 bits TP-rel. address. */
-+#define R_PARISC_TPREL16DF 223 /* 16 bits TP-rel. address. */
-+#define R_PARISC_LTOFF_TP64 224 /* 64 bits LT-TP-rel. address. */
-+#define R_PARISC_LTOFF_TP14WR 227 /* LT-TP-rel. address, right 14 bits.*/
-+#define R_PARISC_LTOFF_TP14DR 228 /* LT-TP-rel. address, right 14 bits.*/
-+#define R_PARISC_LTOFF_TP16F 229 /* 16 bits LT-TP-rel. address. */
-+#define R_PARISC_LTOFF_TP16WF 230 /* 16 bits LT-TP-rel. address. */
-+#define R_PARISC_LTOFF_TP16DF 231 /* 16 bits LT-TP-rel. address. */
-+#define R_PARISC_GNU_VTENTRY 232
-+#define R_PARISC_GNU_VTINHERIT 233
-+#define R_PARISC_TLS_GD21L 234 /* GD 21-bit left. */
-+#define R_PARISC_TLS_GD14R 235 /* GD 14-bit right. */
-+#define R_PARISC_TLS_GDCALL 236 /* GD call to __t_g_a. */
-+#define R_PARISC_TLS_LDM21L 237 /* LD module 21-bit left. */
-+#define R_PARISC_TLS_LDM14R 238 /* LD module 14-bit right. */
-+#define R_PARISC_TLS_LDMCALL 239 /* LD module call to __t_g_a. */
-+#define R_PARISC_TLS_LDO21L 240 /* LD offset 21-bit left. */
-+#define R_PARISC_TLS_LDO14R 241 /* LD offset 14-bit right. */
-+#define R_PARISC_TLS_DTPMOD32 242 /* DTP module 32-bit. */
-+#define R_PARISC_TLS_DTPMOD64 243 /* DTP module 64-bit. */
-+#define R_PARISC_TLS_DTPOFF32 244 /* DTP offset 32-bit. */
-+#define R_PARISC_TLS_DTPOFF64 245 /* DTP offset 32-bit. */
-+#define R_PARISC_TLS_LE21L R_PARISC_TPREL21L
-+#define R_PARISC_TLS_LE14R R_PARISC_TPREL14R
-+#define R_PARISC_TLS_IE21L R_PARISC_LTOFF_TP21L
-+#define R_PARISC_TLS_IE14R R_PARISC_LTOFF_TP14R
-+#define R_PARISC_TLS_TPREL32 R_PARISC_TPREL32
-+#define R_PARISC_TLS_TPREL64 R_PARISC_TPREL64
-+#define R_PARISC_HIRESERVE 255
-+
-+/* Legal values for p_type field of Elf32_Phdr/Elf64_Phdr. */
-+
-+#define PT_HP_TLS (PT_LOOS + 0x0)
-+#define PT_HP_CORE_NONE (PT_LOOS + 0x1)
-+#define PT_HP_CORE_VERSION (PT_LOOS + 0x2)
-+#define PT_HP_CORE_KERNEL (PT_LOOS + 0x3)
-+#define PT_HP_CORE_COMM (PT_LOOS + 0x4)
-+#define PT_HP_CORE_PROC (PT_LOOS + 0x5)
-+#define PT_HP_CORE_LOADABLE (PT_LOOS + 0x6)
-+#define PT_HP_CORE_STACK (PT_LOOS + 0x7)
-+#define PT_HP_CORE_SHM (PT_LOOS + 0x8)
-+#define PT_HP_CORE_MMF (PT_LOOS + 0x9)
-+#define PT_HP_PARALLEL (PT_LOOS + 0x10)
-+#define PT_HP_FASTBIND (PT_LOOS + 0x11)
-+#define PT_HP_OPT_ANNOT (PT_LOOS + 0x12)
-+#define PT_HP_HSL_ANNOT (PT_LOOS + 0x13)
-+#define PT_HP_STACK (PT_LOOS + 0x14)
-+
-+#define PT_PARISC_ARCHEXT 0x70000000
-+#define PT_PARISC_UNWIND 0x70000001
-+
-+/* Legal values for p_flags field of Elf32_Phdr/Elf64_Phdr. */
-+
-+#define PF_PARISC_SBP 0x08000000
-+
-+#define PF_HP_PAGE_SIZE 0x00100000
-+#define PF_HP_FAR_SHARED 0x00200000
-+#define PF_HP_NEAR_SHARED 0x00400000
-+#define PF_HP_CODE 0x01000000
-+#define PF_HP_MODIFY 0x02000000
-+#define PF_HP_LAZYSWAP 0x04000000
-+#define PF_HP_SBP 0x08000000
-+
-+
-+/* Alpha specific definitions. */
-+
-+/* Legal values for e_flags field of Elf64_Ehdr. */
-+
-+#define EF_ALPHA_32BIT 1 /* All addresses must be < 2GB. */
-+#define EF_ALPHA_CANRELAX 2 /* Relocations for relaxing exist. */
-+
-+/* Legal values for sh_type field of Elf64_Shdr. */
-+
-+/* These two are primerily concerned with ECOFF debugging info. */
-+#define SHT_ALPHA_DEBUG 0x70000001
-+#define SHT_ALPHA_REGINFO 0x70000002
-+
-+/* Legal values for sh_flags field of Elf64_Shdr. */
-+
-+#define SHF_ALPHA_GPREL 0x10000000
-+
-+/* Legal values for st_other field of Elf64_Sym. */
-+#define STO_ALPHA_NOPV 0x80 /* No PV required. */
-+#define STO_ALPHA_STD_GPLOAD 0x88 /* PV only used for initial ldgp. */
-+
-+/* Alpha relocs. */
-+
-+#define R_ALPHA_NONE 0 /* No reloc */
-+#define R_ALPHA_REFLONG 1 /* Direct 32 bit */
-+#define R_ALPHA_REFQUAD 2 /* Direct 64 bit */
-+#define R_ALPHA_GPREL32 3 /* GP relative 32 bit */
-+#define R_ALPHA_LITERAL 4 /* GP relative 16 bit w/optimization */
-+#define R_ALPHA_LITUSE 5 /* Optimization hint for LITERAL */
-+#define R_ALPHA_GPDISP 6 /* Add displacement to GP */
-+#define R_ALPHA_BRADDR 7 /* PC+4 relative 23 bit shifted */
-+#define R_ALPHA_HINT 8 /* PC+4 relative 16 bit shifted */
-+#define R_ALPHA_SREL16 9 /* PC relative 16 bit */
-+#define R_ALPHA_SREL32 10 /* PC relative 32 bit */
-+#define R_ALPHA_SREL64 11 /* PC relative 64 bit */
-+#define R_ALPHA_GPRELHIGH 17 /* GP relative 32 bit, high 16 bits */
-+#define R_ALPHA_GPRELLOW 18 /* GP relative 32 bit, low 16 bits */
-+#define R_ALPHA_GPREL16 19 /* GP relative 16 bit */
-+#define R_ALPHA_COPY 24 /* Copy symbol at runtime */
-+#define R_ALPHA_GLOB_DAT 25 /* Create GOT entry */
-+#define R_ALPHA_JMP_SLOT 26 /* Create PLT entry */
-+#define R_ALPHA_RELATIVE 27 /* Adjust by program base */
-+#define R_ALPHA_TLS_GD_HI 28
-+#define R_ALPHA_TLSGD 29
-+#define R_ALPHA_TLS_LDM 30
-+#define R_ALPHA_DTPMOD64 31
-+#define R_ALPHA_GOTDTPREL 32
-+#define R_ALPHA_DTPREL64 33
-+#define R_ALPHA_DTPRELHI 34
-+#define R_ALPHA_DTPRELLO 35
-+#define R_ALPHA_DTPREL16 36
-+#define R_ALPHA_GOTTPREL 37
-+#define R_ALPHA_TPREL64 38
-+#define R_ALPHA_TPRELHI 39
-+#define R_ALPHA_TPRELLO 40
-+#define R_ALPHA_TPREL16 41
-+/* Keep this the last entry. */
-+#define R_ALPHA_NUM 46
-+
-+/* Magic values of the LITUSE relocation addend. */
-+#define LITUSE_ALPHA_ADDR 0
-+#define LITUSE_ALPHA_BASE 1
-+#define LITUSE_ALPHA_BYTOFF 2
-+#define LITUSE_ALPHA_JSR 3
-+#define LITUSE_ALPHA_TLS_GD 4
-+#define LITUSE_ALPHA_TLS_LDM 5
-+
-+/* Legal values for d_tag of Elf64_Dyn. */
-+#define DT_ALPHA_PLTRO (DT_LOPROC + 0)
-+#define DT_ALPHA_NUM 1
-+
-+/* PowerPC specific declarations */
-+
-+/* Values for Elf32/64_Ehdr.e_flags. */
-+#define EF_PPC_EMB 0x80000000 /* PowerPC embedded flag */
-+
-+/* Cygnus local bits below */
-+#define EF_PPC_RELOCATABLE 0x00010000 /* PowerPC -mrelocatable flag*/
-+#define EF_PPC_RELOCATABLE_LIB 0x00008000 /* PowerPC -mrelocatable-lib
-+ flag */
-+
-+/* PowerPC relocations defined by the ABIs */
-+#define R_PPC_NONE 0
-+#define R_PPC_ADDR32 1 /* 32bit absolute address */
-+#define R_PPC_ADDR24 2 /* 26bit address, 2 bits ignored. */
-+#define R_PPC_ADDR16 3 /* 16bit absolute address */
-+#define R_PPC_ADDR16_LO 4 /* lower 16bit of absolute address */
-+#define R_PPC_ADDR16_HI 5 /* high 16bit of absolute address */
-+#define R_PPC_ADDR16_HA 6 /* adjusted high 16bit */
-+#define R_PPC_ADDR14 7 /* 16bit address, 2 bits ignored */
-+#define R_PPC_ADDR14_BRTAKEN 8
-+#define R_PPC_ADDR14_BRNTAKEN 9
-+#define R_PPC_REL24 10 /* PC relative 26 bit */
-+#define R_PPC_REL14 11 /* PC relative 16 bit */
-+#define R_PPC_REL14_BRTAKEN 12
-+#define R_PPC_REL14_BRNTAKEN 13
-+#define R_PPC_GOT16 14
-+#define R_PPC_GOT16_LO 15
-+#define R_PPC_GOT16_HI 16
-+#define R_PPC_GOT16_HA 17
-+#define R_PPC_PLTREL24 18
-+#define R_PPC_COPY 19
-+#define R_PPC_GLOB_DAT 20
-+#define R_PPC_JMP_SLOT 21
-+#define R_PPC_RELATIVE 22
-+#define R_PPC_LOCAL24PC 23
-+#define R_PPC_UADDR32 24
-+#define R_PPC_UADDR16 25
-+#define R_PPC_REL32 26
-+#define R_PPC_PLT32 27
-+#define R_PPC_PLTREL32 28
-+#define R_PPC_PLT16_LO 29
-+#define R_PPC_PLT16_HI 30
-+#define R_PPC_PLT16_HA 31
-+#define R_PPC_SDAREL16 32
-+#define R_PPC_SECTOFF 33
-+#define R_PPC_SECTOFF_LO 34
-+#define R_PPC_SECTOFF_HI 35
-+#define R_PPC_SECTOFF_HA 36
-+
-+/* PowerPC relocations defined for the TLS access ABI. */
-+#define R_PPC_TLS 67 /* none (sym+add)@tls */
-+#define R_PPC_DTPMOD32 68 /* word32 (sym+add)@dtpmod */
-+#define R_PPC_TPREL16 69 /* half16* (sym+add)@tprel */
-+#define R_PPC_TPREL16_LO 70 /* half16 (sym+add)@tprel@l */
-+#define R_PPC_TPREL16_HI 71 /* half16 (sym+add)@tprel@h */
-+#define R_PPC_TPREL16_HA 72 /* half16 (sym+add)@tprel@ha */
-+#define R_PPC_TPREL32 73 /* word32 (sym+add)@tprel */
-+#define R_PPC_DTPREL16 74 /* half16* (sym+add)@dtprel */
-+#define R_PPC_DTPREL16_LO 75 /* half16 (sym+add)@dtprel@l */
-+#define R_PPC_DTPREL16_HI 76 /* half16 (sym+add)@dtprel@h */
-+#define R_PPC_DTPREL16_HA 77 /* half16 (sym+add)@dtprel@ha */
-+#define R_PPC_DTPREL32 78 /* word32 (sym+add)@dtprel */
-+#define R_PPC_GOT_TLSGD16 79 /* half16* (sym+add)@got@tlsgd */
-+#define R_PPC_GOT_TLSGD16_LO 80 /* half16 (sym+add)@got@tlsgd@l */
-+#define R_PPC_GOT_TLSGD16_HI 81 /* half16 (sym+add)@got@tlsgd@h */
-+#define R_PPC_GOT_TLSGD16_HA 82 /* half16 (sym+add)@got@tlsgd@ha */
-+#define R_PPC_GOT_TLSLD16 83 /* half16* (sym+add)@got@tlsld */
-+#define R_PPC_GOT_TLSLD16_LO 84 /* half16 (sym+add)@got@tlsld@l */
-+#define R_PPC_GOT_TLSLD16_HI 85 /* half16 (sym+add)@got@tlsld@h */
-+#define R_PPC_GOT_TLSLD16_HA 86 /* half16 (sym+add)@got@tlsld@ha */
-+#define R_PPC_GOT_TPREL16 87 /* half16* (sym+add)@got@tprel */
-+#define R_PPC_GOT_TPREL16_LO 88 /* half16 (sym+add)@got@tprel@l */
-+#define R_PPC_GOT_TPREL16_HI 89 /* half16 (sym+add)@got@tprel@h */
-+#define R_PPC_GOT_TPREL16_HA 90 /* half16 (sym+add)@got@tprel@ha */
-+#define R_PPC_GOT_DTPREL16 91 /* half16* (sym+add)@got@dtprel */
-+#define R_PPC_GOT_DTPREL16_LO 92 /* half16* (sym+add)@got@dtprel@l */
-+#define R_PPC_GOT_DTPREL16_HI 93 /* half16* (sym+add)@got@dtprel@h */
-+#define R_PPC_GOT_DTPREL16_HA 94 /* half16* (sym+add)@got@dtprel@ha */
-+
-+/* The remaining relocs are from the Embedded ELF ABI, and are not
-+ in the SVR4 ELF ABI. */
-+#define R_PPC_EMB_NADDR32 101
-+#define R_PPC_EMB_NADDR16 102
-+#define R_PPC_EMB_NADDR16_LO 103
-+#define R_PPC_EMB_NADDR16_HI 104
-+#define R_PPC_EMB_NADDR16_HA 105
-+#define R_PPC_EMB_SDAI16 106
-+#define R_PPC_EMB_SDA2I16 107
-+#define R_PPC_EMB_SDA2REL 108
-+#define R_PPC_EMB_SDA21 109 /* 16 bit offset in SDA */
-+#define R_PPC_EMB_MRKREF 110
-+#define R_PPC_EMB_RELSEC16 111
-+#define R_PPC_EMB_RELST_LO 112
-+#define R_PPC_EMB_RELST_HI 113
-+#define R_PPC_EMB_RELST_HA 114
-+#define R_PPC_EMB_BIT_FLD 115
-+#define R_PPC_EMB_RELSDA 116 /* 16 bit relative offset in SDA */
-+
-+/* Diab tool relocations. */
-+#define R_PPC_DIAB_SDA21_LO 180 /* like EMB_SDA21, but lower 16 bit */
-+#define R_PPC_DIAB_SDA21_HI 181 /* like EMB_SDA21, but high 16 bit */
-+#define R_PPC_DIAB_SDA21_HA 182 /* like EMB_SDA21, adjusted high 16 */
-+#define R_PPC_DIAB_RELSDA_LO 183 /* like EMB_RELSDA, but lower 16 bit */
-+#define R_PPC_DIAB_RELSDA_HI 184 /* like EMB_RELSDA, but high 16 bit */
-+#define R_PPC_DIAB_RELSDA_HA 185 /* like EMB_RELSDA, adjusted high 16 */
-+
-+/* GNU extension to support local ifunc. */
-+#define R_PPC_IRELATIVE 248
-+
-+/* GNU relocs used in PIC code sequences. */
-+#define R_PPC_REL16 249 /* half16 (sym+add-.) */
-+#define R_PPC_REL16_LO 250 /* half16 (sym+add-.)@l */
-+#define R_PPC_REL16_HI 251 /* half16 (sym+add-.)@h */
-+#define R_PPC_REL16_HA 252 /* half16 (sym+add-.)@ha */
-+
-+/* This is a phony reloc to handle any old fashioned TOC16 references
-+ that may still be in object files. */
-+#define R_PPC_TOC16 255
-+
-+/* PowerPC specific values for the Dyn d_tag field. */
-+#define DT_PPC_GOT (DT_LOPROC + 0)
-+#define DT_PPC_NUM 1
-+
-+/* PowerPC64 relocations defined by the ABIs */
-+#define R_PPC64_NONE R_PPC_NONE
-+#define R_PPC64_ADDR32 R_PPC_ADDR32 /* 32bit absolute address */
-+#define R_PPC64_ADDR24 R_PPC_ADDR24 /* 26bit address, word aligned */
-+#define R_PPC64_ADDR16 R_PPC_ADDR16 /* 16bit absolute address */
-+#define R_PPC64_ADDR16_LO R_PPC_ADDR16_LO /* lower 16bits of address */
-+#define R_PPC64_ADDR16_HI R_PPC_ADDR16_HI /* high 16bits of address. */
-+#define R_PPC64_ADDR16_HA R_PPC_ADDR16_HA /* adjusted high 16bits. */
-+#define R_PPC64_ADDR14 R_PPC_ADDR14 /* 16bit address, word aligned */
-+#define R_PPC64_ADDR14_BRTAKEN R_PPC_ADDR14_BRTAKEN
-+#define R_PPC64_ADDR14_BRNTAKEN R_PPC_ADDR14_BRNTAKEN
-+#define R_PPC64_REL24 R_PPC_REL24 /* PC-rel. 26 bit, word aligned */
-+#define R_PPC64_REL14 R_PPC_REL14 /* PC relative 16 bit */
-+#define R_PPC64_REL14_BRTAKEN R_PPC_REL14_BRTAKEN
-+#define R_PPC64_REL14_BRNTAKEN R_PPC_REL14_BRNTAKEN
-+#define R_PPC64_GOT16 R_PPC_GOT16
-+#define R_PPC64_GOT16_LO R_PPC_GOT16_LO
-+#define R_PPC64_GOT16_HI R_PPC_GOT16_HI
-+#define R_PPC64_GOT16_HA R_PPC_GOT16_HA
-+
-+#define R_PPC64_COPY R_PPC_COPY
-+#define R_PPC64_GLOB_DAT R_PPC_GLOB_DAT
-+#define R_PPC64_JMP_SLOT R_PPC_JMP_SLOT
-+#define R_PPC64_RELATIVE R_PPC_RELATIVE
-+
-+#define R_PPC64_UADDR32 R_PPC_UADDR32
-+#define R_PPC64_UADDR16 R_PPC_UADDR16
-+#define R_PPC64_REL32 R_PPC_REL32
-+#define R_PPC64_PLT32 R_PPC_PLT32
-+#define R_PPC64_PLTREL32 R_PPC_PLTREL32
-+#define R_PPC64_PLT16_LO R_PPC_PLT16_LO
-+#define R_PPC64_PLT16_HI R_PPC_PLT16_HI
-+#define R_PPC64_PLT16_HA R_PPC_PLT16_HA
-+
-+#define R_PPC64_SECTOFF R_PPC_SECTOFF
-+#define R_PPC64_SECTOFF_LO R_PPC_SECTOFF_LO
-+#define R_PPC64_SECTOFF_HI R_PPC_SECTOFF_HI
-+#define R_PPC64_SECTOFF_HA R_PPC_SECTOFF_HA
-+#define R_PPC64_ADDR30 37 /* word30 (S + A - P) >> 2 */
-+#define R_PPC64_ADDR64 38 /* doubleword64 S + A */
-+#define R_PPC64_ADDR16_HIGHER 39 /* half16 #higher(S + A) */
-+#define R_PPC64_ADDR16_HIGHERA 40 /* half16 #highera(S + A) */
-+#define R_PPC64_ADDR16_HIGHEST 41 /* half16 #highest(S + A) */
-+#define R_PPC64_ADDR16_HIGHESTA 42 /* half16 #highesta(S + A) */
-+#define R_PPC64_UADDR64 43 /* doubleword64 S + A */
-+#define R_PPC64_REL64 44 /* doubleword64 S + A - P */
-+#define R_PPC64_PLT64 45 /* doubleword64 L + A */
-+#define R_PPC64_PLTREL64 46 /* doubleword64 L + A - P */
-+#define R_PPC64_TOC16 47 /* half16* S + A - .TOC */
-+#define R_PPC64_TOC16_LO 48 /* half16 #lo(S + A - .TOC.) */
-+#define R_PPC64_TOC16_HI 49 /* half16 #hi(S + A - .TOC.) */
-+#define R_PPC64_TOC16_HA 50 /* half16 #ha(S + A - .TOC.) */
-+#define R_PPC64_TOC 51 /* doubleword64 .TOC */
-+#define R_PPC64_PLTGOT16 52 /* half16* M + A */
-+#define R_PPC64_PLTGOT16_LO 53 /* half16 #lo(M + A) */
-+#define R_PPC64_PLTGOT16_HI 54 /* half16 #hi(M + A) */
-+#define R_PPC64_PLTGOT16_HA 55 /* half16 #ha(M + A) */
-+
-+#define R_PPC64_ADDR16_DS 56 /* half16ds* (S + A) >> 2 */
-+#define R_PPC64_ADDR16_LO_DS 57 /* half16ds #lo(S + A) >> 2 */
-+#define R_PPC64_GOT16_DS 58 /* half16ds* (G + A) >> 2 */
-+#define R_PPC64_GOT16_LO_DS 59 /* half16ds #lo(G + A) >> 2 */
-+#define R_PPC64_PLT16_LO_DS 60 /* half16ds #lo(L + A) >> 2 */
-+#define R_PPC64_SECTOFF_DS 61 /* half16ds* (R + A) >> 2 */
-+#define R_PPC64_SECTOFF_LO_DS 62 /* half16ds #lo(R + A) >> 2 */
-+#define R_PPC64_TOC16_DS 63 /* half16ds* (S + A - .TOC.) >> 2 */
-+#define R_PPC64_TOC16_LO_DS 64 /* half16ds #lo(S + A - .TOC.) >> 2 */
-+#define R_PPC64_PLTGOT16_DS 65 /* half16ds* (M + A) >> 2 */
-+#define R_PPC64_PLTGOT16_LO_DS 66 /* half16ds #lo(M + A) >> 2 */
-+
-+/* PowerPC64 relocations defined for the TLS access ABI. */
-+#define R_PPC64_TLS 67 /* none (sym+add)@tls */
-+#define R_PPC64_DTPMOD64 68 /* doubleword64 (sym+add)@dtpmod */
-+#define R_PPC64_TPREL16 69 /* half16* (sym+add)@tprel */
-+#define R_PPC64_TPREL16_LO 70 /* half16 (sym+add)@tprel@l */
-+#define R_PPC64_TPREL16_HI 71 /* half16 (sym+add)@tprel@h */
-+#define R_PPC64_TPREL16_HA 72 /* half16 (sym+add)@tprel@ha */
-+#define R_PPC64_TPREL64 73 /* doubleword64 (sym+add)@tprel */
-+#define R_PPC64_DTPREL16 74 /* half16* (sym+add)@dtprel */
-+#define R_PPC64_DTPREL16_LO 75 /* half16 (sym+add)@dtprel@l */
-+#define R_PPC64_DTPREL16_HI 76 /* half16 (sym+add)@dtprel@h */
-+#define R_PPC64_DTPREL16_HA 77 /* half16 (sym+add)@dtprel@ha */
-+#define R_PPC64_DTPREL64 78 /* doubleword64 (sym+add)@dtprel */
-+#define R_PPC64_GOT_TLSGD16 79 /* half16* (sym+add)@got@tlsgd */
-+#define R_PPC64_GOT_TLSGD16_LO 80 /* half16 (sym+add)@got@tlsgd@l */
-+#define R_PPC64_GOT_TLSGD16_HI 81 /* half16 (sym+add)@got@tlsgd@h */
-+#define R_PPC64_GOT_TLSGD16_HA 82 /* half16 (sym+add)@got@tlsgd@ha */
-+#define R_PPC64_GOT_TLSLD16 83 /* half16* (sym+add)@got@tlsld */
-+#define R_PPC64_GOT_TLSLD16_LO 84 /* half16 (sym+add)@got@tlsld@l */
-+#define R_PPC64_GOT_TLSLD16_HI 85 /* half16 (sym+add)@got@tlsld@h */
-+#define R_PPC64_GOT_TLSLD16_HA 86 /* half16 (sym+add)@got@tlsld@ha */
-+#define R_PPC64_GOT_TPREL16_DS 87 /* half16ds* (sym+add)@got@tprel */
-+#define R_PPC64_GOT_TPREL16_LO_DS 88 /* half16ds (sym+add)@got@tprel@l */
-+#define R_PPC64_GOT_TPREL16_HI 89 /* half16 (sym+add)@got@tprel@h */
-+#define R_PPC64_GOT_TPREL16_HA 90 /* half16 (sym+add)@got@tprel@ha */
-+#define R_PPC64_GOT_DTPREL16_DS 91 /* half16ds* (sym+add)@got@dtprel */
-+#define R_PPC64_GOT_DTPREL16_LO_DS 92 /* half16ds (sym+add)@got@dtprel@l */
-+#define R_PPC64_GOT_DTPREL16_HI 93 /* half16 (sym+add)@got@dtprel@h */
-+#define R_PPC64_GOT_DTPREL16_HA 94 /* half16 (sym+add)@got@dtprel@ha */
-+#define R_PPC64_TPREL16_DS 95 /* half16ds* (sym+add)@tprel */
-+#define R_PPC64_TPREL16_LO_DS 96 /* half16ds (sym+add)@tprel@l */
-+#define R_PPC64_TPREL16_HIGHER 97 /* half16 (sym+add)@tprel@higher */
-+#define R_PPC64_TPREL16_HIGHERA 98 /* half16 (sym+add)@tprel@highera */
-+#define R_PPC64_TPREL16_HIGHEST 99 /* half16 (sym+add)@tprel@highest */
-+#define R_PPC64_TPREL16_HIGHESTA 100 /* half16 (sym+add)@tprel@highesta */
-+#define R_PPC64_DTPREL16_DS 101 /* half16ds* (sym+add)@dtprel */
-+#define R_PPC64_DTPREL16_LO_DS 102 /* half16ds (sym+add)@dtprel@l */
-+#define R_PPC64_DTPREL16_HIGHER 103 /* half16 (sym+add)@dtprel@higher */
-+#define R_PPC64_DTPREL16_HIGHERA 104 /* half16 (sym+add)@dtprel@highera */
-+#define R_PPC64_DTPREL16_HIGHEST 105 /* half16 (sym+add)@dtprel@highest */
-+#define R_PPC64_DTPREL16_HIGHESTA 106 /* half16 (sym+add)@dtprel@highesta */
-+
-+/* GNU extension to support local ifunc. */
-+#define R_PPC64_JMP_IREL 247
-+#define R_PPC64_IRELATIVE 248
-+#define R_PPC64_REL16 249 /* half16 (sym+add-.) */
-+#define R_PPC64_REL16_LO 250 /* half16 (sym+add-.)@l */
-+#define R_PPC64_REL16_HI 251 /* half16 (sym+add-.)@h */
-+#define R_PPC64_REL16_HA 252 /* half16 (sym+add-.)@ha */
-+
-+/* PowerPC64 specific values for the Dyn d_tag field. */
-+#define DT_PPC64_GLINK (DT_LOPROC + 0)
-+#define DT_PPC64_OPD (DT_LOPROC + 1)
-+#define DT_PPC64_OPDSZ (DT_LOPROC + 2)
-+#define DT_PPC64_NUM 3
-+
-+
-+/* ARM specific declarations */
-+
-+/* Processor specific flags for the ELF header e_flags field. */
-+#define EF_ARM_RELEXEC 0x01
-+#define EF_ARM_HASENTRY 0x02
-+#define EF_ARM_INTERWORK 0x04
-+#define EF_ARM_APCS_26 0x08
-+#define EF_ARM_APCS_FLOAT 0x10
-+#define EF_ARM_PIC 0x20
-+#define EF_ARM_ALIGN8 0x40 /* 8-bit structure alignment is in use */
-+#define EF_ARM_NEW_ABI 0x80
-+#define EF_ARM_OLD_ABI 0x100
-+#define EF_ARM_SOFT_FLOAT 0x200
-+#define EF_ARM_VFP_FLOAT 0x400
-+#define EF_ARM_MAVERICK_FLOAT 0x800
-+
-+
-+/* Other constants defined in the ARM ELF spec. version B-01. */
-+/* NB. These conflict with values defined above. */
-+#define EF_ARM_SYMSARESORTED 0x04
-+#define EF_ARM_DYNSYMSUSESEGIDX 0x08
-+#define EF_ARM_MAPSYMSFIRST 0x10
-+#define EF_ARM_EABIMASK 0XFF000000
-+
-+/* Constants defined in AAELF. */
-+#define EF_ARM_BE8 0x00800000
-+#define EF_ARM_LE8 0x00400000
-+
-+#define EF_ARM_EABI_VERSION(flags) ((flags) & EF_ARM_EABIMASK)
-+#define EF_ARM_EABI_UNKNOWN 0x00000000
-+#define EF_ARM_EABI_VER1 0x01000000
-+#define EF_ARM_EABI_VER2 0x02000000
-+#define EF_ARM_EABI_VER3 0x03000000
-+#define EF_ARM_EABI_VER4 0x04000000
-+#define EF_ARM_EABI_VER5 0x05000000
-+
-+/* Additional symbol types for Thumb. */
-+#define STT_ARM_TFUNC STT_LOPROC /* A Thumb function. */
-+#define STT_ARM_16BIT STT_HIPROC /* A Thumb label. */
-+
-+/* ARM-specific values for sh_flags */
-+#define SHF_ARM_ENTRYSECT 0x10000000 /* Section contains an entry point */
-+#define SHF_ARM_COMDEF 0x80000000 /* Section may be multiply defined
-+ in the input to a link step. */
-+
-+/* ARM-specific program header flags */
-+#define PF_ARM_SB 0x10000000 /* Segment contains the location
-+ addressed by the static base. */
-+#define PF_ARM_PI 0x20000000 /* Position-independent segment. */
-+#define PF_ARM_ABS 0x40000000 /* Absolute segment. */
-+
-+/* Processor specific values for the Phdr p_type field. */
-+#define PT_ARM_EXIDX (PT_LOPROC + 1) /* ARM unwind segment. */
-+
-+/* Processor specific values for the Shdr sh_type field. */
-+#define SHT_ARM_EXIDX (SHT_LOPROC + 1) /* ARM unwind section. */
-+#define SHT_ARM_PREEMPTMAP (SHT_LOPROC + 2) /* Preemption details. */
-+#define SHT_ARM_ATTRIBUTES (SHT_LOPROC + 3) /* ARM attributes section. */
-+
-+
-+/* ARM relocs. */
-+
-+#define R_ARM_NONE 0 /* No reloc */
-+#define R_ARM_PC24 1 /* PC relative 26 bit branch */
-+#define R_ARM_ABS32 2 /* Direct 32 bit */
-+#define R_ARM_REL32 3 /* PC relative 32 bit */
-+#define R_ARM_PC13 4
-+#define R_ARM_ABS16 5 /* Direct 16 bit */
-+#define R_ARM_ABS12 6 /* Direct 12 bit */
-+#define R_ARM_THM_ABS5 7
-+#define R_ARM_ABS8 8 /* Direct 8 bit */
-+#define R_ARM_SBREL32 9
-+#define R_ARM_THM_PC22 10
-+#define R_ARM_THM_PC8 11
-+#define R_ARM_AMP_VCALL9 12
-+#define R_ARM_SWI24 13 /* Obsolete static relocation. */
-+#define R_ARM_TLS_DESC 13 /* Dynamic relocation. */
-+#define R_ARM_THM_SWI8 14
-+#define R_ARM_XPC25 15
-+#define R_ARM_THM_XPC22 16
-+#define R_ARM_TLS_DTPMOD32 17 /* ID of module containing symbol */
-+#define R_ARM_TLS_DTPOFF32 18 /* Offset in TLS block */
-+#define R_ARM_TLS_TPOFF32 19 /* Offset in static TLS block */
-+#define R_ARM_COPY 20 /* Copy symbol at runtime */
-+#define R_ARM_GLOB_DAT 21 /* Create GOT entry */
-+#define R_ARM_JUMP_SLOT 22 /* Create PLT entry */
-+#define R_ARM_RELATIVE 23 /* Adjust by program base */
-+#define R_ARM_GOTOFF 24 /* 32 bit offset to GOT */
-+#define R_ARM_GOTPC 25 /* 32 bit PC relative offset to GOT */
-+#define R_ARM_GOT32 26 /* 32 bit GOT entry */
-+#define R_ARM_PLT32 27 /* 32 bit PLT address */
-+#define R_ARM_ALU_PCREL_7_0 32
-+#define R_ARM_ALU_PCREL_15_8 33
-+#define R_ARM_ALU_PCREL_23_15 34
-+#define R_ARM_LDR_SBREL_11_0 35
-+#define R_ARM_ALU_SBREL_19_12 36
-+#define R_ARM_ALU_SBREL_27_20 37
-+#define R_ARM_TLS_GOTDESC 90
-+#define R_ARM_TLS_CALL 91
-+#define R_ARM_TLS_DESCSEQ 92
-+#define R_ARM_THM_TLS_CALL 93
-+#define R_ARM_GNU_VTENTRY 100
-+#define R_ARM_GNU_VTINHERIT 101
-+#define R_ARM_THM_PC11 102 /* thumb unconditional branch */
-+#define R_ARM_THM_PC9 103 /* thumb conditional branch */
-+#define R_ARM_TLS_GD32 104 /* PC-rel 32 bit for global dynamic
-+ thread local data */
-+#define R_ARM_TLS_LDM32 105 /* PC-rel 32 bit for local dynamic
-+ thread local data */
-+#define R_ARM_TLS_LDO32 106 /* 32 bit offset relative to TLS
-+ block */
-+#define R_ARM_TLS_IE32 107 /* PC-rel 32 bit for GOT entry of
-+ static TLS block offset */
-+#define R_ARM_TLS_LE32 108 /* 32 bit offset relative to static
-+ TLS block */
-+#define R_ARM_THM_TLS_DESCSEQ 129
-+#define R_ARM_IRELATIVE 160
-+#define R_ARM_RXPC25 249
-+#define R_ARM_RSBREL32 250
-+#define R_ARM_THM_RPC22 251
-+#define R_ARM_RREL32 252
-+#define R_ARM_RABS22 253
-+#define R_ARM_RPC24 254
-+#define R_ARM_RBASE 255
-+/* Keep this the last entry. */
-+#define R_ARM_NUM 256
-+
-+/* IA-64 specific declarations. */
-+
-+/* Processor specific flags for the Ehdr e_flags field. */
-+#define EF_IA_64_MASKOS 0x0000000f /* os-specific flags */
-+#define EF_IA_64_ABI64 0x00000010 /* 64-bit ABI */
-+#define EF_IA_64_ARCH 0xff000000 /* arch. version mask */
-+
-+/* Processor specific values for the Phdr p_type field. */
-+#define PT_IA_64_ARCHEXT (PT_LOPROC + 0) /* arch extension bits */
-+#define PT_IA_64_UNWIND (PT_LOPROC + 1) /* ia64 unwind bits */
-+#define PT_IA_64_HP_OPT_ANOT (PT_LOOS + 0x12)
-+#define PT_IA_64_HP_HSL_ANOT (PT_LOOS + 0x13)
-+#define PT_IA_64_HP_STACK (PT_LOOS + 0x14)
-+
-+/* Processor specific flags for the Phdr p_flags field. */
-+#define PF_IA_64_NORECOV 0x80000000 /* spec insns w/o recovery */
-+
-+/* Processor specific values for the Shdr sh_type field. */
-+#define SHT_IA_64_EXT (SHT_LOPROC + 0) /* extension bits */
-+#define SHT_IA_64_UNWIND (SHT_LOPROC + 1) /* unwind bits */
-+
-+/* Processor specific flags for the Shdr sh_flags field. */
-+#define SHF_IA_64_SHORT 0x10000000 /* section near gp */
-+#define SHF_IA_64_NORECOV 0x20000000 /* spec insns w/o recovery */
-+
-+/* Processor specific values for the Dyn d_tag field. */
-+#define DT_IA_64_PLT_RESERVE (DT_LOPROC + 0)
-+#define DT_IA_64_NUM 1
-+
-+/* IA-64 relocations. */
-+#define R_IA64_NONE 0x00 /* none */
-+#define R_IA64_IMM14 0x21 /* symbol + addend, add imm14 */
-+#define R_IA64_IMM22 0x22 /* symbol + addend, add imm22 */
-+#define R_IA64_IMM64 0x23 /* symbol + addend, mov imm64 */
-+#define R_IA64_DIR32MSB 0x24 /* symbol + addend, data4 MSB */
-+#define R_IA64_DIR32LSB 0x25 /* symbol + addend, data4 LSB */
-+#define R_IA64_DIR64MSB 0x26 /* symbol + addend, data8 MSB */
-+#define R_IA64_DIR64LSB 0x27 /* symbol + addend, data8 LSB */
-+#define R_IA64_GPREL22 0x2a /* @gprel(sym + add), add imm22 */
-+#define R_IA64_GPREL64I 0x2b /* @gprel(sym + add), mov imm64 */
-+#define R_IA64_GPREL32MSB 0x2c /* @gprel(sym + add), data4 MSB */
-+#define R_IA64_GPREL32LSB 0x2d /* @gprel(sym + add), data4 LSB */
-+#define R_IA64_GPREL64MSB 0x2e /* @gprel(sym + add), data8 MSB */
-+#define R_IA64_GPREL64LSB 0x2f /* @gprel(sym + add), data8 LSB */
-+#define R_IA64_LTOFF22 0x32 /* @ltoff(sym + add), add imm22 */
-+#define R_IA64_LTOFF64I 0x33 /* @ltoff(sym + add), mov imm64 */
-+#define R_IA64_PLTOFF22 0x3a /* @pltoff(sym + add), add imm22 */
-+#define R_IA64_PLTOFF64I 0x3b /* @pltoff(sym + add), mov imm64 */
-+#define R_IA64_PLTOFF64MSB 0x3e /* @pltoff(sym + add), data8 MSB */
-+#define R_IA64_PLTOFF64LSB 0x3f /* @pltoff(sym + add), data8 LSB */
-+#define R_IA64_FPTR64I 0x43 /* @fptr(sym + add), mov imm64 */
-+#define R_IA64_FPTR32MSB 0x44 /* @fptr(sym + add), data4 MSB */
-+#define R_IA64_FPTR32LSB 0x45 /* @fptr(sym + add), data4 LSB */
-+#define R_IA64_FPTR64MSB 0x46 /* @fptr(sym + add), data8 MSB */
-+#define R_IA64_FPTR64LSB 0x47 /* @fptr(sym + add), data8 LSB */
-+#define R_IA64_PCREL60B 0x48 /* @pcrel(sym + add), brl */
-+#define R_IA64_PCREL21B 0x49 /* @pcrel(sym + add), ptb, call */
-+#define R_IA64_PCREL21M 0x4a /* @pcrel(sym + add), chk.s */
-+#define R_IA64_PCREL21F 0x4b /* @pcrel(sym + add), fchkf */
-+#define R_IA64_PCREL32MSB 0x4c /* @pcrel(sym + add), data4 MSB */
-+#define R_IA64_PCREL32LSB 0x4d /* @pcrel(sym + add), data4 LSB */
-+#define R_IA64_PCREL64MSB 0x4e /* @pcrel(sym + add), data8 MSB */
-+#define R_IA64_PCREL64LSB 0x4f /* @pcrel(sym + add), data8 LSB */
-+#define R_IA64_LTOFF_FPTR22 0x52 /* @ltoff(@fptr(s+a)), imm22 */
-+#define R_IA64_LTOFF_FPTR64I 0x53 /* @ltoff(@fptr(s+a)), imm64 */
-+#define R_IA64_LTOFF_FPTR32MSB 0x54 /* @ltoff(@fptr(s+a)), data4 MSB */
-+#define R_IA64_LTOFF_FPTR32LSB 0x55 /* @ltoff(@fptr(s+a)), data4 LSB */
-+#define R_IA64_LTOFF_FPTR64MSB 0x56 /* @ltoff(@fptr(s+a)), data8 MSB */
-+#define R_IA64_LTOFF_FPTR64LSB 0x57 /* @ltoff(@fptr(s+a)), data8 LSB */
-+#define R_IA64_SEGREL32MSB 0x5c /* @segrel(sym + add), data4 MSB */
-+#define R_IA64_SEGREL32LSB 0x5d /* @segrel(sym + add), data4 LSB */
-+#define R_IA64_SEGREL64MSB 0x5e /* @segrel(sym + add), data8 MSB */
-+#define R_IA64_SEGREL64LSB 0x5f /* @segrel(sym + add), data8 LSB */
-+#define R_IA64_SECREL32MSB 0x64 /* @secrel(sym + add), data4 MSB */
-+#define R_IA64_SECREL32LSB 0x65 /* @secrel(sym + add), data4 LSB */
-+#define R_IA64_SECREL64MSB 0x66 /* @secrel(sym + add), data8 MSB */
-+#define R_IA64_SECREL64LSB 0x67 /* @secrel(sym + add), data8 LSB */
-+#define R_IA64_REL32MSB 0x6c /* data 4 + REL */
-+#define R_IA64_REL32LSB 0x6d /* data 4 + REL */
-+#define R_IA64_REL64MSB 0x6e /* data 8 + REL */
-+#define R_IA64_REL64LSB 0x6f /* data 8 + REL */
-+#define R_IA64_LTV32MSB 0x74 /* symbol + addend, data4 MSB */
-+#define R_IA64_LTV32LSB 0x75 /* symbol + addend, data4 LSB */
-+#define R_IA64_LTV64MSB 0x76 /* symbol + addend, data8 MSB */
-+#define R_IA64_LTV64LSB 0x77 /* symbol + addend, data8 LSB */
-+#define R_IA64_PCREL21BI 0x79 /* @pcrel(sym + add), 21bit inst */
-+#define R_IA64_PCREL22 0x7a /* @pcrel(sym + add), 22bit inst */
-+#define R_IA64_PCREL64I 0x7b /* @pcrel(sym + add), 64bit inst */
-+#define R_IA64_IPLTMSB 0x80 /* dynamic reloc, imported PLT, MSB */
-+#define R_IA64_IPLTLSB 0x81 /* dynamic reloc, imported PLT, LSB */
-+#define R_IA64_COPY 0x84 /* copy relocation */
-+#define R_IA64_SUB 0x85 /* Addend and symbol difference */
-+#define R_IA64_LTOFF22X 0x86 /* LTOFF22, relaxable. */
-+#define R_IA64_LDXMOV 0x87 /* Use of LTOFF22X. */
-+#define R_IA64_TPREL14 0x91 /* @tprel(sym + add), imm14 */
-+#define R_IA64_TPREL22 0x92 /* @tprel(sym + add), imm22 */
-+#define R_IA64_TPREL64I 0x93 /* @tprel(sym + add), imm64 */
-+#define R_IA64_TPREL64MSB 0x96 /* @tprel(sym + add), data8 MSB */
-+#define R_IA64_TPREL64LSB 0x97 /* @tprel(sym + add), data8 LSB */
-+#define R_IA64_LTOFF_TPREL22 0x9a /* @ltoff(@tprel(s+a)), imm2 */
-+#define R_IA64_DTPMOD64MSB 0xa6 /* @dtpmod(sym + add), data8 MSB */
-+#define R_IA64_DTPMOD64LSB 0xa7 /* @dtpmod(sym + add), data8 LSB */
-+#define R_IA64_LTOFF_DTPMOD22 0xaa /* @ltoff(@dtpmod(sym + add)), imm22 */
-+#define R_IA64_DTPREL14 0xb1 /* @dtprel(sym + add), imm14 */
-+#define R_IA64_DTPREL22 0xb2 /* @dtprel(sym + add), imm22 */
-+#define R_IA64_DTPREL64I 0xb3 /* @dtprel(sym + add), imm64 */
-+#define R_IA64_DTPREL32MSB 0xb4 /* @dtprel(sym + add), data4 MSB */
-+#define R_IA64_DTPREL32LSB 0xb5 /* @dtprel(sym + add), data4 LSB */
-+#define R_IA64_DTPREL64MSB 0xb6 /* @dtprel(sym + add), data8 MSB */
-+#define R_IA64_DTPREL64LSB 0xb7 /* @dtprel(sym + add), data8 LSB */
-+#define R_IA64_LTOFF_DTPREL22 0xba /* @ltoff(@dtprel(s+a)), imm22 */
-+
-+/* SH specific declarations */
-+
-+/* Processor specific flags for the ELF header e_flags field. */
-+#define EF_SH_MACH_MASK 0x1f
-+#define EF_SH_UNKNOWN 0x0
-+#define EF_SH1 0x1
-+#define EF_SH2 0x2
-+#define EF_SH3 0x3
-+#define EF_SH_DSP 0x4
-+#define EF_SH3_DSP 0x5
-+#define EF_SH4AL_DSP 0x6
-+#define EF_SH3E 0x8
-+#define EF_SH4 0x9
-+#define EF_SH2E 0xb
-+#define EF_SH4A 0xc
-+#define EF_SH2A 0xd
-+#define EF_SH4_NOFPU 0x10
-+#define EF_SH4A_NOFPU 0x11
-+#define EF_SH4_NOMMU_NOFPU 0x12
-+#define EF_SH2A_NOFPU 0x13
-+#define EF_SH3_NOMMU 0x14
-+#define EF_SH2A_SH4_NOFPU 0x15
-+#define EF_SH2A_SH3_NOFPU 0x16
-+#define EF_SH2A_SH4 0x17
-+#define EF_SH2A_SH3E 0x18
-+
-+/* SH relocs. */
-+#define R_SH_NONE 0
-+#define R_SH_DIR32 1
-+#define R_SH_REL32 2
-+#define R_SH_DIR8WPN 3
-+#define R_SH_IND12W 4
-+#define R_SH_DIR8WPL 5
-+#define R_SH_DIR8WPZ 6
-+#define R_SH_DIR8BP 7
-+#define R_SH_DIR8W 8
-+#define R_SH_DIR8L 9
-+#define R_SH_SWITCH16 25
-+#define R_SH_SWITCH32 26
-+#define R_SH_USES 27
-+#define R_SH_COUNT 28
-+#define R_SH_ALIGN 29
-+#define R_SH_CODE 30
-+#define R_SH_DATA 31
-+#define R_SH_LABEL 32
-+#define R_SH_SWITCH8 33
-+#define R_SH_GNU_VTINHERIT 34
-+#define R_SH_GNU_VTENTRY 35
-+#define R_SH_TLS_GD_32 144
-+#define R_SH_TLS_LD_32 145
-+#define R_SH_TLS_LDO_32 146
-+#define R_SH_TLS_IE_32 147
-+#define R_SH_TLS_LE_32 148
-+#define R_SH_TLS_DTPMOD32 149
-+#define R_SH_TLS_DTPOFF32 150
-+#define R_SH_TLS_TPOFF32 151
-+#define R_SH_GOT32 160
-+#define R_SH_PLT32 161
-+#define R_SH_COPY 162
-+#define R_SH_GLOB_DAT 163
-+#define R_SH_JMP_SLOT 164
-+#define R_SH_RELATIVE 165
-+#define R_SH_GOTOFF 166
-+#define R_SH_GOTPC 167
-+/* Keep this the last entry. */
-+#define R_SH_NUM 256
-+
-+/* S/390 specific definitions. */
-+
-+/* Valid values for the e_flags field. */
-+
-+#define EF_S390_HIGH_GPRS 0x00000001 /* High GPRs kernel facility needed. */
-+
-+/* Additional s390 relocs */
-+
-+#define R_390_NONE 0 /* No reloc. */
-+#define R_390_8 1 /* Direct 8 bit. */
-+#define R_390_12 2 /* Direct 12 bit. */
-+#define R_390_16 3 /* Direct 16 bit. */
-+#define R_390_32 4 /* Direct 32 bit. */
-+#define R_390_PC32 5 /* PC relative 32 bit. */
-+#define R_390_GOT12 6 /* 12 bit GOT offset. */
-+#define R_390_GOT32 7 /* 32 bit GOT offset. */
-+#define R_390_PLT32 8 /* 32 bit PC relative PLT address. */
-+#define R_390_COPY 9 /* Copy symbol at runtime. */
-+#define R_390_GLOB_DAT 10 /* Create GOT entry. */
-+#define R_390_JMP_SLOT 11 /* Create PLT entry. */
-+#define R_390_RELATIVE 12 /* Adjust by program base. */
-+#define R_390_GOTOFF32 13 /* 32 bit offset to GOT. */
-+#define R_390_GOTPC 14 /* 32 bit PC relative offset to GOT. */
-+#define R_390_GOT16 15 /* 16 bit GOT offset. */
-+#define R_390_PC16 16 /* PC relative 16 bit. */
-+#define R_390_PC16DBL 17 /* PC relative 16 bit shifted by 1. */
-+#define R_390_PLT16DBL 18 /* 16 bit PC rel. PLT shifted by 1. */
-+#define R_390_PC32DBL 19 /* PC relative 32 bit shifted by 1. */
-+#define R_390_PLT32DBL 20 /* 32 bit PC rel. PLT shifted by 1. */
-+#define R_390_GOTPCDBL 21 /* 32 bit PC rel. GOT shifted by 1. */
-+#define R_390_64 22 /* Direct 64 bit. */
-+#define R_390_PC64 23 /* PC relative 64 bit. */
-+#define R_390_GOT64 24 /* 64 bit GOT offset. */
-+#define R_390_PLT64 25 /* 64 bit PC relative PLT address. */
-+#define R_390_GOTENT 26 /* 32 bit PC rel. to GOT entry >> 1. */
-+#define R_390_GOTOFF16 27 /* 16 bit offset to GOT. */
-+#define R_390_GOTOFF64 28 /* 64 bit offset to GOT. */
-+#define R_390_GOTPLT12 29 /* 12 bit offset to jump slot. */
-+#define R_390_GOTPLT16 30 /* 16 bit offset to jump slot. */
-+#define R_390_GOTPLT32 31 /* 32 bit offset to jump slot. */
-+#define R_390_GOTPLT64 32 /* 64 bit offset to jump slot. */
-+#define R_390_GOTPLTENT 33 /* 32 bit rel. offset to jump slot. */
-+#define R_390_PLTOFF16 34 /* 16 bit offset from GOT to PLT. */
-+#define R_390_PLTOFF32 35 /* 32 bit offset from GOT to PLT. */
-+#define R_390_PLTOFF64 36 /* 16 bit offset from GOT to PLT. */
-+#define R_390_TLS_LOAD 37 /* Tag for load insn in TLS code. */
-+#define R_390_TLS_GDCALL 38 /* Tag for function call in general
-+ dynamic TLS code. */
-+#define R_390_TLS_LDCALL 39 /* Tag for function call in local
-+ dynamic TLS code. */
-+#define R_390_TLS_GD32 40 /* Direct 32 bit for general dynamic
-+ thread local data. */
-+#define R_390_TLS_GD64 41 /* Direct 64 bit for general dynamic
-+ thread local data. */
-+#define R_390_TLS_GOTIE12 42 /* 12 bit GOT offset for static TLS
-+ block offset. */
-+#define R_390_TLS_GOTIE32 43 /* 32 bit GOT offset for static TLS
-+ block offset. */
-+#define R_390_TLS_GOTIE64 44 /* 64 bit GOT offset for static TLS
-+ block offset. */
-+#define R_390_TLS_LDM32 45 /* Direct 32 bit for local dynamic
-+ thread local data in LE code. */
-+#define R_390_TLS_LDM64 46 /* Direct 64 bit for local dynamic
-+ thread local data in LE code. */
-+#define R_390_TLS_IE32 47 /* 32 bit address of GOT entry for
-+ negated static TLS block offset. */
-+#define R_390_TLS_IE64 48 /* 64 bit address of GOT entry for
-+ negated static TLS block offset. */
-+#define R_390_TLS_IEENT 49 /* 32 bit rel. offset to GOT entry for
-+ negated static TLS block offset. */
-+#define R_390_TLS_LE32 50 /* 32 bit negated offset relative to
-+ static TLS block. */
-+#define R_390_TLS_LE64 51 /* 64 bit negated offset relative to
-+ static TLS block. */
-+#define R_390_TLS_LDO32 52 /* 32 bit offset relative to TLS
-+ block. */
-+#define R_390_TLS_LDO64 53 /* 64 bit offset relative to TLS
-+ block. */
-+#define R_390_TLS_DTPMOD 54 /* ID of module containing symbol. */
-+#define R_390_TLS_DTPOFF 55 /* Offset in TLS block. */
-+#define R_390_TLS_TPOFF 56 /* Negated offset in static TLS
-+ block. */
-+#define R_390_20 57 /* Direct 20 bit. */
-+#define R_390_GOT20 58 /* 20 bit GOT offset. */
-+#define R_390_GOTPLT20 59 /* 20 bit offset to jump slot. */
-+#define R_390_TLS_GOTIE20 60 /* 20 bit GOT offset for static TLS
-+ block offset. */
-+#define R_390_IRELATIVE 61 /* STT_GNU_IFUNC relocation. */
-+/* Keep this the last entry. */
-+#define R_390_NUM 62
-+
-+
-+/* CRIS relocations. */
-+#define R_CRIS_NONE 0
-+#define R_CRIS_8 1
-+#define R_CRIS_16 2
-+#define R_CRIS_32 3
-+#define R_CRIS_8_PCREL 4
-+#define R_CRIS_16_PCREL 5
-+#define R_CRIS_32_PCREL 6
-+#define R_CRIS_GNU_VTINHERIT 7
-+#define R_CRIS_GNU_VTENTRY 8
-+#define R_CRIS_COPY 9
-+#define R_CRIS_GLOB_DAT 10
-+#define R_CRIS_JUMP_SLOT 11
-+#define R_CRIS_RELATIVE 12
-+#define R_CRIS_16_GOT 13
-+#define R_CRIS_32_GOT 14
-+#define R_CRIS_16_GOTPLT 15
-+#define R_CRIS_32_GOTPLT 16
-+#define R_CRIS_32_GOTREL 17
-+#define R_CRIS_32_PLT_GOTREL 18
-+#define R_CRIS_32_PLT_PCREL 19
-+
-+#define R_CRIS_NUM 20
-+
-+
-+/* AMD x86-64 relocations. */
-+#define R_X86_64_NONE 0 /* No reloc */
-+#define R_X86_64_64 1 /* Direct 64 bit */
-+#define R_X86_64_PC32 2 /* PC relative 32 bit signed */
-+#define R_X86_64_GOT32 3 /* 32 bit GOT entry */
-+#define R_X86_64_PLT32 4 /* 32 bit PLT address */
-+#define R_X86_64_COPY 5 /* Copy symbol at runtime */
-+#define R_X86_64_GLOB_DAT 6 /* Create GOT entry */
-+#define R_X86_64_JUMP_SLOT 7 /* Create PLT entry */
-+#define R_X86_64_RELATIVE 8 /* Adjust by program base */
-+#define R_X86_64_GOTPCREL 9 /* 32 bit signed PC relative
-+ offset to GOT */
-+#define R_X86_64_32 10 /* Direct 32 bit zero extended */
-+#define R_X86_64_32S 11 /* Direct 32 bit sign extended */
-+#define R_X86_64_16 12 /* Direct 16 bit zero extended */
-+#define R_X86_64_PC16 13 /* 16 bit sign extended pc relative */
-+#define R_X86_64_8 14 /* Direct 8 bit sign extended */
-+#define R_X86_64_PC8 15 /* 8 bit sign extended pc relative */
-+#define R_X86_64_DTPMOD64 16 /* ID of module containing symbol */
-+#define R_X86_64_DTPOFF64 17 /* Offset in module's TLS block */
-+#define R_X86_64_TPOFF64 18 /* Offset in initial TLS block */
-+#define R_X86_64_TLSGD 19 /* 32 bit signed PC relative offset
-+ to two GOT entries for GD symbol */
-+#define R_X86_64_TLSLD 20 /* 32 bit signed PC relative offset
-+ to two GOT entries for LD symbol */
-+#define R_X86_64_DTPOFF32 21 /* Offset in TLS block */
-+#define R_X86_64_GOTTPOFF 22 /* 32 bit signed PC relative offset
-+ to GOT entry for IE symbol */
-+#define R_X86_64_TPOFF32 23 /* Offset in initial TLS block */
-+#define R_X86_64_PC64 24 /* PC relative 64 bit */
-+#define R_X86_64_GOTOFF64 25 /* 64 bit offset to GOT */
-+#define R_X86_64_GOTPC32 26 /* 32 bit signed pc relative
-+ offset to GOT */
-+#define R_X86_64_GOT64 27 /* 64-bit GOT entry offset */
-+#define R_X86_64_GOTPCREL64 28 /* 64-bit PC relative offset
-+ to GOT entry */
-+#define R_X86_64_GOTPC64 29 /* 64-bit PC relative offset to GOT */
-+#define R_X86_64_GOTPLT64 30 /* like GOT64, says PLT entry needed */
-+#define R_X86_64_PLTOFF64 31 /* 64-bit GOT relative offset
-+ to PLT entry */
-+#define R_X86_64_SIZE32 32 /* Size of symbol plus 32-bit addend */
-+#define R_X86_64_SIZE64 33 /* Size of symbol plus 64-bit addend */
-+#define R_X86_64_GOTPC32_TLSDESC 34 /* GOT offset for TLS descriptor. */
-+#define R_X86_64_TLSDESC_CALL 35 /* Marker for call through TLS
-+ descriptor. */
-+#define R_X86_64_TLSDESC 36 /* TLS descriptor. */
-+#define R_X86_64_IRELATIVE 37 /* Adjust indirectly by program base */
-+#define R_X86_64_RELATIVE64 38 /* 64-bit adjust by program base */
-+
-+#define R_X86_64_NUM 39
-+
-+
-+/* AM33 relocations. */
-+#define R_MN10300_NONE 0 /* No reloc. */
-+#define R_MN10300_32 1 /* Direct 32 bit. */
-+#define R_MN10300_16 2 /* Direct 16 bit. */
-+#define R_MN10300_8 3 /* Direct 8 bit. */
-+#define R_MN10300_PCREL32 4 /* PC-relative 32-bit. */
-+#define R_MN10300_PCREL16 5 /* PC-relative 16-bit signed. */
-+#define R_MN10300_PCREL8 6 /* PC-relative 8-bit signed. */
-+#define R_MN10300_GNU_VTINHERIT 7 /* Ancient C++ vtable garbage... */
-+#define R_MN10300_GNU_VTENTRY 8 /* ... collection annotation. */
-+#define R_MN10300_24 9 /* Direct 24 bit. */
-+#define R_MN10300_GOTPC32 10 /* 32-bit PCrel offset to GOT. */
-+#define R_MN10300_GOTPC16 11 /* 16-bit PCrel offset to GOT. */
-+#define R_MN10300_GOTOFF32 12 /* 32-bit offset from GOT. */
-+#define R_MN10300_GOTOFF24 13 /* 24-bit offset from GOT. */
-+#define R_MN10300_GOTOFF16 14 /* 16-bit offset from GOT. */
-+#define R_MN10300_PLT32 15 /* 32-bit PCrel to PLT entry. */
-+#define R_MN10300_PLT16 16 /* 16-bit PCrel to PLT entry. */
-+#define R_MN10300_GOT32 17 /* 32-bit offset to GOT entry. */
-+#define R_MN10300_GOT24 18 /* 24-bit offset to GOT entry. */
-+#define R_MN10300_GOT16 19 /* 16-bit offset to GOT entry. */
-+#define R_MN10300_COPY 20 /* Copy symbol at runtime. */
-+#define R_MN10300_GLOB_DAT 21 /* Create GOT entry. */
-+#define R_MN10300_JMP_SLOT 22 /* Create PLT entry. */
-+#define R_MN10300_RELATIVE 23 /* Adjust by program base. */
-+
-+#define R_MN10300_NUM 24
-+
-+
-+/* M32R relocs. */
-+#define R_M32R_NONE 0 /* No reloc. */
-+#define R_M32R_16 1 /* Direct 16 bit. */
-+#define R_M32R_32 2 /* Direct 32 bit. */
-+#define R_M32R_24 3 /* Direct 24 bit. */
-+#define R_M32R_10_PCREL 4 /* PC relative 10 bit shifted. */
-+#define R_M32R_18_PCREL 5 /* PC relative 18 bit shifted. */
-+#define R_M32R_26_PCREL 6 /* PC relative 26 bit shifted. */
-+#define R_M32R_HI16_ULO 7 /* High 16 bit with unsigned low. */
-+#define R_M32R_HI16_SLO 8 /* High 16 bit with signed low. */
-+#define R_M32R_LO16 9 /* Low 16 bit. */
-+#define R_M32R_SDA16 10 /* 16 bit offset in SDA. */
-+#define R_M32R_GNU_VTINHERIT 11
-+#define R_M32R_GNU_VTENTRY 12
-+/* M32R relocs use SHT_RELA. */
-+#define R_M32R_16_RELA 33 /* Direct 16 bit. */
-+#define R_M32R_32_RELA 34 /* Direct 32 bit. */
-+#define R_M32R_24_RELA 35 /* Direct 24 bit. */
-+#define R_M32R_10_PCREL_RELA 36 /* PC relative 10 bit shifted. */
-+#define R_M32R_18_PCREL_RELA 37 /* PC relative 18 bit shifted. */
-+#define R_M32R_26_PCREL_RELA 38 /* PC relative 26 bit shifted. */
-+#define R_M32R_HI16_ULO_RELA 39 /* High 16 bit with unsigned low */
-+#define R_M32R_HI16_SLO_RELA 40 /* High 16 bit with signed low */
-+#define R_M32R_LO16_RELA 41 /* Low 16 bit */
-+#define R_M32R_SDA16_RELA 42 /* 16 bit offset in SDA */
-+#define R_M32R_RELA_GNU_VTINHERIT 43
-+#define R_M32R_RELA_GNU_VTENTRY 44
-+#define R_M32R_REL32 45 /* PC relative 32 bit. */
-+
-+#define R_M32R_GOT24 48 /* 24 bit GOT entry */
-+#define R_M32R_26_PLTREL 49 /* 26 bit PC relative to PLT shifted */
-+#define R_M32R_COPY 50 /* Copy symbol at runtime */
-+#define R_M32R_GLOB_DAT 51 /* Create GOT entry */
-+#define R_M32R_JMP_SLOT 52 /* Create PLT entry */
-+#define R_M32R_RELATIVE 53 /* Adjust by program base */
-+#define R_M32R_GOTOFF 54 /* 24 bit offset to GOT */
-+#define R_M32R_GOTPC24 55 /* 24 bit PC relative offset to GOT */
-+#define R_M32R_GOT16_HI_ULO 56 /* High 16 bit GOT entry with unsigned
-+ low */
-+#define R_M32R_GOT16_HI_SLO 57 /* High 16 bit GOT entry with signed
-+ low */
-+#define R_M32R_GOT16_LO 58 /* Low 16 bit GOT entry */
-+#define R_M32R_GOTPC_HI_ULO 59 /* High 16 bit PC relative offset to
-+ GOT with unsigned low */
-+#define R_M32R_GOTPC_HI_SLO 60 /* High 16 bit PC relative offset to
-+ GOT with signed low */
-+#define R_M32R_GOTPC_LO 61 /* Low 16 bit PC relative offset to
-+ GOT */
-+#define R_M32R_GOTOFF_HI_ULO 62 /* High 16 bit offset to GOT
-+ with unsigned low */
-+#define R_M32R_GOTOFF_HI_SLO 63 /* High 16 bit offset to GOT
-+ with signed low */
-+#define R_M32R_GOTOFF_LO 64 /* Low 16 bit offset to GOT */
-+#define R_M32R_NUM 256 /* Keep this the last entry. */
-+
-+
-+/* TILEPro relocations. */
-+#define R_TILEPRO_NONE 0 /* No reloc */
-+#define R_TILEPRO_32 1 /* Direct 32 bit */
-+#define R_TILEPRO_16 2 /* Direct 16 bit */
-+#define R_TILEPRO_8 3 /* Direct 8 bit */
-+#define R_TILEPRO_32_PCREL 4 /* PC relative 32 bit */
-+#define R_TILEPRO_16_PCREL 5 /* PC relative 16 bit */
-+#define R_TILEPRO_8_PCREL 6 /* PC relative 8 bit */
-+#define R_TILEPRO_LO16 7 /* Low 16 bit */
-+#define R_TILEPRO_HI16 8 /* High 16 bit */
-+#define R_TILEPRO_HA16 9 /* High 16 bit, adjusted */
-+#define R_TILEPRO_COPY 10 /* Copy relocation */
-+#define R_TILEPRO_GLOB_DAT 11 /* Create GOT entry */
-+#define R_TILEPRO_JMP_SLOT 12 /* Create PLT entry */
-+#define R_TILEPRO_RELATIVE 13 /* Adjust by program base */
-+#define R_TILEPRO_BROFF_X1 14 /* X1 pipe branch offset */
-+#define R_TILEPRO_JOFFLONG_X1 15 /* X1 pipe jump offset */
-+#define R_TILEPRO_JOFFLONG_X1_PLT 16 /* X1 pipe jump offset to PLT */
-+#define R_TILEPRO_IMM8_X0 17 /* X0 pipe 8-bit */
-+#define R_TILEPRO_IMM8_Y0 18 /* Y0 pipe 8-bit */
-+#define R_TILEPRO_IMM8_X1 19 /* X1 pipe 8-bit */
-+#define R_TILEPRO_IMM8_Y1 20 /* Y1 pipe 8-bit */
-+#define R_TILEPRO_MT_IMM15_X1 21 /* X1 pipe mtspr */
-+#define R_TILEPRO_MF_IMM15_X1 22 /* X1 pipe mfspr */
-+#define R_TILEPRO_IMM16_X0 23 /* X0 pipe 16-bit */
-+#define R_TILEPRO_IMM16_X1 24 /* X1 pipe 16-bit */
-+#define R_TILEPRO_IMM16_X0_LO 25 /* X0 pipe low 16-bit */
-+#define R_TILEPRO_IMM16_X1_LO 26 /* X1 pipe low 16-bit */
-+#define R_TILEPRO_IMM16_X0_HI 27 /* X0 pipe high 16-bit */
-+#define R_TILEPRO_IMM16_X1_HI 28 /* X1 pipe high 16-bit */
-+#define R_TILEPRO_IMM16_X0_HA 29 /* X0 pipe high 16-bit, adjusted */
-+#define R_TILEPRO_IMM16_X1_HA 30 /* X1 pipe high 16-bit, adjusted */
-+#define R_TILEPRO_IMM16_X0_PCREL 31 /* X0 pipe PC relative 16 bit */
-+#define R_TILEPRO_IMM16_X1_PCREL 32 /* X1 pipe PC relative 16 bit */
-+#define R_TILEPRO_IMM16_X0_LO_PCREL 33 /* X0 pipe PC relative low 16 bit */
-+#define R_TILEPRO_IMM16_X1_LO_PCREL 34 /* X1 pipe PC relative low 16 bit */
-+#define R_TILEPRO_IMM16_X0_HI_PCREL 35 /* X0 pipe PC relative high 16 bit */
-+#define R_TILEPRO_IMM16_X1_HI_PCREL 36 /* X1 pipe PC relative high 16 bit */
-+#define R_TILEPRO_IMM16_X0_HA_PCREL 37 /* X0 pipe PC relative ha() 16 bit */
-+#define R_TILEPRO_IMM16_X1_HA_PCREL 38 /* X1 pipe PC relative ha() 16 bit */
-+#define R_TILEPRO_IMM16_X0_GOT 39 /* X0 pipe 16-bit GOT offset */
-+#define R_TILEPRO_IMM16_X1_GOT 40 /* X1 pipe 16-bit GOT offset */
-+#define R_TILEPRO_IMM16_X0_GOT_LO 41 /* X0 pipe low 16-bit GOT offset */
-+#define R_TILEPRO_IMM16_X1_GOT_LO 42 /* X1 pipe low 16-bit GOT offset */
-+#define R_TILEPRO_IMM16_X0_GOT_HI 43 /* X0 pipe high 16-bit GOT offset */
-+#define R_TILEPRO_IMM16_X1_GOT_HI 44 /* X1 pipe high 16-bit GOT offset */
-+#define R_TILEPRO_IMM16_X0_GOT_HA 45 /* X0 pipe ha() 16-bit GOT offset */
-+#define R_TILEPRO_IMM16_X1_GOT_HA 46 /* X1 pipe ha() 16-bit GOT offset */
-+#define R_TILEPRO_MMSTART_X0 47 /* X0 pipe mm "start" */
-+#define R_TILEPRO_MMEND_X0 48 /* X0 pipe mm "end" */
-+#define R_TILEPRO_MMSTART_X1 49 /* X1 pipe mm "start" */
-+#define R_TILEPRO_MMEND_X1 50 /* X1 pipe mm "end" */
-+#define R_TILEPRO_SHAMT_X0 51 /* X0 pipe shift amount */
-+#define R_TILEPRO_SHAMT_X1 52 /* X1 pipe shift amount */
-+#define R_TILEPRO_SHAMT_Y0 53 /* Y0 pipe shift amount */
-+#define R_TILEPRO_SHAMT_Y1 54 /* Y1 pipe shift amount */
-+#define R_TILEPRO_DEST_IMM8_X1 55 /* X1 pipe destination 8-bit */
-+/* Relocs 56-59 are currently not defined. */
-+#define R_TILEPRO_TLS_GD_CALL 60 /* "jal" for TLS GD */
-+#define R_TILEPRO_IMM8_X0_TLS_GD_ADD 61 /* X0 pipe "addi" for TLS GD */
-+#define R_TILEPRO_IMM8_X1_TLS_GD_ADD 62 /* X1 pipe "addi" for TLS GD */
-+#define R_TILEPRO_IMM8_Y0_TLS_GD_ADD 63 /* Y0 pipe "addi" for TLS GD */
-+#define R_TILEPRO_IMM8_Y1_TLS_GD_ADD 64 /* Y1 pipe "addi" for TLS GD */
-+#define R_TILEPRO_TLS_IE_LOAD 65 /* "lw_tls" for TLS IE */
-+#define R_TILEPRO_IMM16_X0_TLS_GD 66 /* X0 pipe 16-bit TLS GD offset */
-+#define R_TILEPRO_IMM16_X1_TLS_GD 67 /* X1 pipe 16-bit TLS GD offset */
-+#define R_TILEPRO_IMM16_X0_TLS_GD_LO 68 /* X0 pipe low 16-bit TLS GD offset */
-+#define R_TILEPRO_IMM16_X1_TLS_GD_LO 69 /* X1 pipe low 16-bit TLS GD offset */
-+#define R_TILEPRO_IMM16_X0_TLS_GD_HI 70 /* X0 pipe high 16-bit TLS GD offset */
-+#define R_TILEPRO_IMM16_X1_TLS_GD_HI 71 /* X1 pipe high 16-bit TLS GD offset */
-+#define R_TILEPRO_IMM16_X0_TLS_GD_HA 72 /* X0 pipe ha() 16-bit TLS GD offset */
-+#define R_TILEPRO_IMM16_X1_TLS_GD_HA 73 /* X1 pipe ha() 16-bit TLS GD offset */
-+#define R_TILEPRO_IMM16_X0_TLS_IE 74 /* X0 pipe 16-bit TLS IE offset */
-+#define R_TILEPRO_IMM16_X1_TLS_IE 75 /* X1 pipe 16-bit TLS IE offset */
-+#define R_TILEPRO_IMM16_X0_TLS_IE_LO 76 /* X0 pipe low 16-bit TLS IE offset */
-+#define R_TILEPRO_IMM16_X1_TLS_IE_LO 77 /* X1 pipe low 16-bit TLS IE offset */
-+#define R_TILEPRO_IMM16_X0_TLS_IE_HI 78 /* X0 pipe high 16-bit TLS IE offset */
-+#define R_TILEPRO_IMM16_X1_TLS_IE_HI 79 /* X1 pipe high 16-bit TLS IE offset */
-+#define R_TILEPRO_IMM16_X0_TLS_IE_HA 80 /* X0 pipe ha() 16-bit TLS IE offset */
-+#define R_TILEPRO_IMM16_X1_TLS_IE_HA 81 /* X1 pipe ha() 16-bit TLS IE offset */
-+#define R_TILEPRO_TLS_DTPMOD32 82 /* ID of module containing symbol */
-+#define R_TILEPRO_TLS_DTPOFF32 83 /* Offset in TLS block */
-+#define R_TILEPRO_TLS_TPOFF32 84 /* Offset in static TLS block */
-+#define R_TILEPRO_IMM16_X0_TLS_LE 85 /* X0 pipe 16-bit TLS LE offset */
-+#define R_TILEPRO_IMM16_X1_TLS_LE 86 /* X1 pipe 16-bit TLS LE offset */
-+#define R_TILEPRO_IMM16_X0_TLS_LE_LO 87 /* X0 pipe low 16-bit TLS LE offset */
-+#define R_TILEPRO_IMM16_X1_TLS_LE_LO 88 /* X1 pipe low 16-bit TLS LE offset */
-+#define R_TILEPRO_IMM16_X0_TLS_LE_HI 89 /* X0 pipe high 16-bit TLS LE offset */
-+#define R_TILEPRO_IMM16_X1_TLS_LE_HI 90 /* X1 pipe high 16-bit TLS LE offset */
-+#define R_TILEPRO_IMM16_X0_TLS_LE_HA 91 /* X0 pipe ha() 16-bit TLS LE offset */
-+#define R_TILEPRO_IMM16_X1_TLS_LE_HA 92 /* X1 pipe ha() 16-bit TLS LE offset */
-+
-+#define R_TILEPRO_GNU_VTINHERIT 128 /* GNU C++ vtable hierarchy */
-+#define R_TILEPRO_GNU_VTENTRY 129 /* GNU C++ vtable member usage */
-+
-+#define R_TILEPRO_NUM 130
-+
-+
-+/* TILE-Gx relocations. */
-+#define R_TILEGX_NONE 0 /* No reloc */
-+#define R_TILEGX_64 1 /* Direct 64 bit */
-+#define R_TILEGX_32 2 /* Direct 32 bit */
-+#define R_TILEGX_16 3 /* Direct 16 bit */
-+#define R_TILEGX_8 4 /* Direct 8 bit */
-+#define R_TILEGX_64_PCREL 5 /* PC relative 64 bit */
-+#define R_TILEGX_32_PCREL 6 /* PC relative 32 bit */
-+#define R_TILEGX_16_PCREL 7 /* PC relative 16 bit */
-+#define R_TILEGX_8_PCREL 8 /* PC relative 8 bit */
-+#define R_TILEGX_HW0 9 /* hword 0 16-bit */
-+#define R_TILEGX_HW1 10 /* hword 1 16-bit */
-+#define R_TILEGX_HW2 11 /* hword 2 16-bit */
-+#define R_TILEGX_HW3 12 /* hword 3 16-bit */
-+#define R_TILEGX_HW0_LAST 13 /* last hword 0 16-bit */
-+#define R_TILEGX_HW1_LAST 14 /* last hword 1 16-bit */
-+#define R_TILEGX_HW2_LAST 15 /* last hword 2 16-bit */
-+#define R_TILEGX_COPY 16 /* Copy relocation */
-+#define R_TILEGX_GLOB_DAT 17 /* Create GOT entry */
-+#define R_TILEGX_JMP_SLOT 18 /* Create PLT entry */
-+#define R_TILEGX_RELATIVE 19 /* Adjust by program base */
-+#define R_TILEGX_BROFF_X1 20 /* X1 pipe branch offset */
-+#define R_TILEGX_JUMPOFF_X1 21 /* X1 pipe jump offset */
-+#define R_TILEGX_JUMPOFF_X1_PLT 22 /* X1 pipe jump offset to PLT */
-+#define R_TILEGX_IMM8_X0 23 /* X0 pipe 8-bit */
-+#define R_TILEGX_IMM8_Y0 24 /* Y0 pipe 8-bit */
-+#define R_TILEGX_IMM8_X1 25 /* X1 pipe 8-bit */
-+#define R_TILEGX_IMM8_Y1 26 /* Y1 pipe 8-bit */
-+#define R_TILEGX_DEST_IMM8_X1 27 /* X1 pipe destination 8-bit */
-+#define R_TILEGX_MT_IMM14_X1 28 /* X1 pipe mtspr */
-+#define R_TILEGX_MF_IMM14_X1 29 /* X1 pipe mfspr */
-+#define R_TILEGX_MMSTART_X0 30 /* X0 pipe mm "start" */
-+#define R_TILEGX_MMEND_X0 31 /* X0 pipe mm "end" */
-+#define R_TILEGX_SHAMT_X0 32 /* X0 pipe shift amount */
-+#define R_TILEGX_SHAMT_X1 33 /* X1 pipe shift amount */
-+#define R_TILEGX_SHAMT_Y0 34 /* Y0 pipe shift amount */
-+#define R_TILEGX_SHAMT_Y1 35 /* Y1 pipe shift amount */
-+#define R_TILEGX_IMM16_X0_HW0 36 /* X0 pipe hword 0 */
-+#define R_TILEGX_IMM16_X1_HW0 37 /* X1 pipe hword 0 */
-+#define R_TILEGX_IMM16_X0_HW1 38 /* X0 pipe hword 1 */
-+#define R_TILEGX_IMM16_X1_HW1 39 /* X1 pipe hword 1 */
-+#define R_TILEGX_IMM16_X0_HW2 40 /* X0 pipe hword 2 */
-+#define R_TILEGX_IMM16_X1_HW2 41 /* X1 pipe hword 2 */
-+#define R_TILEGX_IMM16_X0_HW3 42 /* X0 pipe hword 3 */
-+#define R_TILEGX_IMM16_X1_HW3 43 /* X1 pipe hword 3 */
-+#define R_TILEGX_IMM16_X0_HW0_LAST 44 /* X0 pipe last hword 0 */
-+#define R_TILEGX_IMM16_X1_HW0_LAST 45 /* X1 pipe last hword 0 */
-+#define R_TILEGX_IMM16_X0_HW1_LAST 46 /* X0 pipe last hword 1 */
-+#define R_TILEGX_IMM16_X1_HW1_LAST 47 /* X1 pipe last hword 1 */
-+#define R_TILEGX_IMM16_X0_HW2_LAST 48 /* X0 pipe last hword 2 */
-+#define R_TILEGX_IMM16_X1_HW2_LAST 49 /* X1 pipe last hword 2 */
-+#define R_TILEGX_IMM16_X0_HW0_PCREL 50 /* X0 pipe PC relative hword 0 */
-+#define R_TILEGX_IMM16_X1_HW0_PCREL 51 /* X1 pipe PC relative hword 0 */
-+#define R_TILEGX_IMM16_X0_HW1_PCREL 52 /* X0 pipe PC relative hword 1 */
-+#define R_TILEGX_IMM16_X1_HW1_PCREL 53 /* X1 pipe PC relative hword 1 */
-+#define R_TILEGX_IMM16_X0_HW2_PCREL 54 /* X0 pipe PC relative hword 2 */
-+#define R_TILEGX_IMM16_X1_HW2_PCREL 55 /* X1 pipe PC relative hword 2 */
-+#define R_TILEGX_IMM16_X0_HW3_PCREL 56 /* X0 pipe PC relative hword 3 */
-+#define R_TILEGX_IMM16_X1_HW3_PCREL 57 /* X1 pipe PC relative hword 3 */
-+#define R_TILEGX_IMM16_X0_HW0_LAST_PCREL 58 /* X0 pipe PC-rel last hword 0 */
-+#define R_TILEGX_IMM16_X1_HW0_LAST_PCREL 59 /* X1 pipe PC-rel last hword 0 */
-+#define R_TILEGX_IMM16_X0_HW1_LAST_PCREL 60 /* X0 pipe PC-rel last hword 1 */
-+#define R_TILEGX_IMM16_X1_HW1_LAST_PCREL 61 /* X1 pipe PC-rel last hword 1 */
-+#define R_TILEGX_IMM16_X0_HW2_LAST_PCREL 62 /* X0 pipe PC-rel last hword 2 */
-+#define R_TILEGX_IMM16_X1_HW2_LAST_PCREL 63 /* X1 pipe PC-rel last hword 2 */
-+#define R_TILEGX_IMM16_X0_HW0_GOT 64 /* X0 pipe hword 0 GOT offset */
-+#define R_TILEGX_IMM16_X1_HW0_GOT 65 /* X1 pipe hword 0 GOT offset */
-+/* Relocs 66-71 are currently not defined. */
-+#define R_TILEGX_IMM16_X0_HW0_LAST_GOT 72 /* X0 pipe last hword 0 GOT offset */
-+#define R_TILEGX_IMM16_X1_HW0_LAST_GOT 73 /* X1 pipe last hword 0 GOT offset */
-+#define R_TILEGX_IMM16_X0_HW1_LAST_GOT 74 /* X0 pipe last hword 1 GOT offset */
-+#define R_TILEGX_IMM16_X1_HW1_LAST_GOT 75 /* X1 pipe last hword 1 GOT offset */
-+/* Relocs 76-77 are currently not defined. */
-+#define R_TILEGX_IMM16_X0_HW0_TLS_GD 78 /* X0 pipe hword 0 TLS GD offset */
-+#define R_TILEGX_IMM16_X1_HW0_TLS_GD 79 /* X1 pipe hword 0 TLS GD offset */
-+#define R_TILEGX_IMM16_X0_HW0_TLS_LE 80 /* X0 pipe hword 0 TLS LE offset */
-+#define R_TILEGX_IMM16_X1_HW0_TLS_LE 81 /* X1 pipe hword 0 TLS LE offset */
-+#define R_TILEGX_IMM16_X0_HW0_LAST_TLS_LE 82 /* X0 pipe last hword 0 LE off */
-+#define R_TILEGX_IMM16_X1_HW0_LAST_TLS_LE 83 /* X1 pipe last hword 0 LE off */
-+#define R_TILEGX_IMM16_X0_HW1_LAST_TLS_LE 84 /* X0 pipe last hword 1 LE off */
-+#define R_TILEGX_IMM16_X1_HW1_LAST_TLS_LE 85 /* X1 pipe last hword 1 LE off */
-+#define R_TILEGX_IMM16_X0_HW0_LAST_TLS_GD 86 /* X0 pipe last hword 0 GD off */
-+#define R_TILEGX_IMM16_X1_HW0_LAST_TLS_GD 87 /* X1 pipe last hword 0 GD off */
-+#define R_TILEGX_IMM16_X0_HW1_LAST_TLS_GD 88 /* X0 pipe last hword 1 GD off */
-+#define R_TILEGX_IMM16_X1_HW1_LAST_TLS_GD 89 /* X1 pipe last hword 1 GD off */
-+/* Relocs 90-91 are currently not defined. */
-+#define R_TILEGX_IMM16_X0_HW0_TLS_IE 92 /* X0 pipe hword 0 TLS IE offset */
-+#define R_TILEGX_IMM16_X1_HW0_TLS_IE 93 /* X1 pipe hword 0 TLS IE offset */
-+/* Relocs 94-99 are currently not defined. */
-+#define R_TILEGX_IMM16_X0_HW0_LAST_TLS_IE 100 /* X0 pipe last hword 0 IE off */
-+#define R_TILEGX_IMM16_X1_HW0_LAST_TLS_IE 101 /* X1 pipe last hword 0 IE off */
-+#define R_TILEGX_IMM16_X0_HW1_LAST_TLS_IE 102 /* X0 pipe last hword 1 IE off */
-+#define R_TILEGX_IMM16_X1_HW1_LAST_TLS_IE 103 /* X1 pipe last hword 1 IE off */
-+/* Relocs 104-105 are currently not defined. */
-+#define R_TILEGX_TLS_DTPMOD64 106 /* 64-bit ID of symbol's module */
-+#define R_TILEGX_TLS_DTPOFF64 107 /* 64-bit offset in TLS block */
-+#define R_TILEGX_TLS_TPOFF64 108 /* 64-bit offset in static TLS block */
-+#define R_TILEGX_TLS_DTPMOD32 109 /* 32-bit ID of symbol's module */
-+#define R_TILEGX_TLS_DTPOFF32 110 /* 32-bit offset in TLS block */
-+#define R_TILEGX_TLS_TPOFF32 111 /* 32-bit offset in static TLS block */
-+#define R_TILEGX_TLS_GD_CALL 112 /* "jal" for TLS GD */
-+#define R_TILEGX_IMM8_X0_TLS_GD_ADD 113 /* X0 pipe "addi" for TLS GD */
-+#define R_TILEGX_IMM8_X1_TLS_GD_ADD 114 /* X1 pipe "addi" for TLS GD */
-+#define R_TILEGX_IMM8_Y0_TLS_GD_ADD 115 /* Y0 pipe "addi" for TLS GD */
-+#define R_TILEGX_IMM8_Y1_TLS_GD_ADD 116 /* Y1 pipe "addi" for TLS GD */
-+#define R_TILEGX_TLS_IE_LOAD 117 /* "ld_tls" for TLS IE */
-+#define R_TILEGX_IMM8_X0_TLS_ADD 118 /* X0 pipe "addi" for TLS GD/IE */
-+#define R_TILEGX_IMM8_X1_TLS_ADD 119 /* X1 pipe "addi" for TLS GD/IE */
-+#define R_TILEGX_IMM8_Y0_TLS_ADD 120 /* Y0 pipe "addi" for TLS GD/IE */
-+#define R_TILEGX_IMM8_Y1_TLS_ADD 121 /* Y1 pipe "addi" for TLS GD/IE */
-+
-+#define R_TILEGX_GNU_VTINHERIT 128 /* GNU C++ vtable hierarchy */
-+#define R_TILEGX_GNU_VTENTRY 129 /* GNU C++ vtable member usage */
-+
-+#define R_TILEGX_NUM 130
-+
-+#endif /* elf.h */
---- a/scripts/mod/mk_elfconfig.c
-+++ b/scripts/mod/mk_elfconfig.c
-@@ -2,7 +2,11 @@
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
-+#ifndef __APPLE__
- #include <elf.h>
-+#else
-+#include "elf.h"
-+#endif
-
- int
- main(int argc, char **argv)
---- a/scripts/mod/modpost.h
-+++ b/scripts/mod/modpost.h
-@@ -9,7 +9,11 @@
- #include <sys/mman.h>
- #include <fcntl.h>
- #include <unistd.h>
-+#if !(defined(__APPLE__) || defined(__CYGWIN__))
- #include <elf.h>
-+#else
-+#include "elf.h"
-+#endif
- #include "../../include/linux/module_symbol.h"
-
- #include "list.h"
+++ /dev/null
-From e44fc2af1ddc452b6659d08c16973d65c73b7d0a Mon Sep 17 00:00:00 2001
-Date: Wed, 5 Feb 2020 18:36:43 +0000
-Subject: [PATCH] file2alias: build on macos
-
----
- scripts/mod/file2alias.c | 3 +++
- 1 file changed, 3 insertions(+)
-
---- a/scripts/mod/file2alias.c
-+++ b/scripts/mod/file2alias.c
-@@ -35,6 +35,9 @@ typedef uint32_t __u32;
- typedef uint16_t __u16;
- typedef unsigned char __u8;
-
-+#ifdef __APPLE__
-+#define uuid_t compat_uuid_t
-+#endif
- /* UUID types for backward compatibility, don't use in new code */
- typedef struct {
- __u8 b[16];
+++ /dev/null
-From be9be95ff10e16a5b4ad36f903978d0cc5747024 Mon Sep 17 00:00:00 2001
-Date: Fri, 7 Jul 2017 17:04:08 +0200
-Subject: kernel: fix linux/spi/spidev.h portability issues with musl
-
-Felix will try to get this define included into musl
-
-lede-commit: 795e7cf60de19e7a076a46874fab7bb88b43bbff
----
- include/uapi/linux/spi/spidev.h | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/include/uapi/linux/spi/spidev.h
-+++ b/include/uapi/linux/spi/spidev.h
-@@ -93,7 +93,7 @@ struct spi_ioc_transfer {
-
- /* not all platforms use <asm-generic/ioctl.h> or _IOC_TYPECHECK() ... */
- #define SPI_MSGSIZE(N) \
-- ((((N)*(sizeof (struct spi_ioc_transfer))) < (1 << _IOC_SIZEBITS)) \
-+ ((((N)*(sizeof (struct spi_ioc_transfer))) < (1 << 13)) \
- ? ((N)*(sizeof (struct spi_ioc_transfer))) : 0)
- #define SPI_IOC_MESSAGE(N) _IOW(SPI_IOC_MAGIC, 0, char[SPI_MSGSIZE(N)])
-
+++ /dev/null
-From b3d00b452467f621317953d9e4c6f9ae8dcfd271 Mon Sep 17 00:00:00 2001
-Date: Fri, 7 Jul 2017 17:06:55 +0200
-Subject: use the openwrt lzma options for now
-
-lede-commit: 548de949f392049420a6a1feeef118b30ab8ea8c
----
- lib/decompress.c | 1 +
- scripts/Makefile.lib | 2 +-
- usr/gen_initramfs_list.sh | 10 +++++-----
- 3 files changed, 7 insertions(+), 6 deletions(-)
-
---- a/lib/decompress.c
-+++ b/lib/decompress.c
-@@ -53,6 +53,7 @@ static const struct compress_format comp
- { {0x1f, 0x9e}, "gzip", gunzip },
- { {0x42, 0x5a}, "bzip2", bunzip2 },
- { {0x5d, 0x00}, "lzma", unlzma },
-+ { {0x6d, 0x00}, "lzma-openwrt", unlzma },
- { {0xfd, 0x37}, "xz", unxz },
- { {0x89, 0x4c}, "lzo", unlzo },
- { {0x02, 0x21}, "lz4", unlz4 },
---- a/scripts/Makefile.lib
-+++ b/scripts/Makefile.lib
-@@ -460,10 +460,10 @@ quiet_cmd_bzip2_with_size = BZIP2 $@
- # ---------------------------------------------------------------------------
-
- quiet_cmd_lzma = LZMA $@
-- cmd_lzma = cat $(real-prereqs) | $(LZMA) -9 > $@
-+ cmd_lzma = cat $(real-prereqs) | $(LZMA) e -d20 -lc1 -lp2 -pb2 -eos -si -so > $@
-
- quiet_cmd_lzma_with_size = LZMA $@
-- cmd_lzma_with_size = { cat $(real-prereqs) | $(LZMA) -9; $(size_append); } > $@
-+ cmd_lzma_with_size = { cat $(real-prereqs) | $(LZMA) e -d20 -lc1 -lp2 -pb2 -eos -si -so; $(size_append); } > $@
-
- quiet_cmd_lzo = LZO $@
- cmd_lzo = cat $(real-prereqs) | $(KLZOP) -9 > $@
+++ /dev/null
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-Date: Thu, 20 Nov 2025 20:37:53 +0700
-Subject: [PATCH] kernel: fix build of kmod-udptunnel4 and kmod-udptunnel6
-
-This fixes the following errors:
-```
-make[4]: Entering directory '/home/runner/work/OP/OP/openwrt/build_dir/target-aarch64_cortex-a53_musl/linux-mediatek_filogic/linux-6.12.57'
- MODPOST /home/runner/work/OP/OP/openwrt/build_dir/target-aarch64_cortex-a53_musl/linux-mediatek_filogic/ovpn-dco-0.2.20250801/drivers/net/ovpn-dco/Module.symvers
-ERROR: modpost: "udp_tunnel6_xmit_skb" [/home/runner/work/OP/OP/openwrt/build_dir/target-aarch64_cortex-a53_musl/linux-mediatek_filogic/ovpn-dco-0.2.20250801/drivers/net/ovpn-dco/ovpn-dco-v2.ko] undefined!
-ERROR: modpost: "setup_udp_tunnel_sock" [/home/runner/work/OP/OP/openwrt/build_dir/target-aarch64_cortex-a53_musl/linux-mediatek_filogic/ovpn-dco-0.2.20250801/drivers/net/ovpn-dco/ovpn-dco-v2.ko] undefined!
-ERROR: modpost: "udp_tunnel_xmit_skb" [/home/runner/work/OP/OP/openwrt/build_dir/target-aarch64_cortex-a53_musl/linux-mediatek_filogic/ovpn-dco-0.2.20250801/drivers/net/ovpn-dco/ovpn-dco-v2.ko] undefined!
-make[6]: *** [scripts/Makefile.modpost:145: /home/runner/work/OP/OP/openwrt/build_dir/target-aarch64_cortex-a53_musl/linux-mediatek_filogic/ovpn-dco-0.2.20250801/drivers/net/ovpn-dco/Module.symvers] Error 1
-make[5]: *** [/home/runner/work/OP/OP/openwrt/build_dir/target-aarch64_cortex-a53_musl/linux-mediatek_filogic/linux-6.12.57/Makefile:1897: modpost] Error 2
-make[4]: *** [Makefile:224: __sub-make] Error 2
-```
-
-ref https://github.com/openwrt/openwrt/commit/1d15a96b29dcd0947690951a7c36aead79a27129
-fixes: https://github.com/openwrt/packages/issues/22998
-
----
- net/ipv4/Kconfig | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/net/ipv4/Kconfig
-+++ b/net/ipv4/Kconfig
-@@ -315,7 +315,7 @@ config NET_IPVTI
- on top.
-
- config NET_UDP_TUNNEL
-- tristate
-+ tristate "IP: UDP tunneling support"
- select NET_IP_TUNNEL
- default n
-
+++ /dev/null
-Subject: hack: net: remove bogus netfilter dependencies
-
-lede-commit: 589d2a377dee27d206fc3725325309cf649e4df6
----
- net/netfilter/Kconfig | 2 --
- 1 file changed, 2 deletions(-)
-
---- a/net/netfilter/Kconfig
-+++ b/net/netfilter/Kconfig
-@@ -259,7 +259,6 @@ config NF_CONNTRACK_FTP
-
- config NF_CONNTRACK_H323
- tristate "H.323 protocol support"
-- depends on IPV6 || IPV6=n
- depends on NETFILTER_ADVANCED
- help
- H.323 is a VoIP signalling protocol from ITU-T. As one of the most
-@@ -1120,7 +1119,6 @@ config NETFILTER_XT_TARGET_SECMARK
-
- config NETFILTER_XT_TARGET_TCPMSS
- tristate '"TCPMSS" target support'
-- depends on IPV6 || IPV6=n
- default m if NETFILTER_ADVANCED=n
- help
- This option adds a `TCPMSS' target, which allows you to alter the
+++ /dev/null
-From da3c50704f14132f4adf80d48e9a4cd5d46e54c9 Mon Sep 17 00:00:00 2001
-Date: Fri, 7 Jul 2017 17:09:21 +0200
-Subject: kconfig: owrt specifc dependencies
-
----
- crypto/Kconfig | 10 +++++-----
- drivers/bcma/Kconfig | 1 +
- drivers/ssb/Kconfig | 3 ++-
- lib/Kconfig | 8 ++++----
- net/netfilter/Kconfig | 2 +-
- net/wireless/Kconfig | 17 ++++++++++-------
- sound/core/Kconfig | 4 ++--
- 7 files changed, 25 insertions(+), 20 deletions(-)
-
---- a/crypto/Kconfig
-+++ b/crypto/Kconfig
-@@ -55,7 +55,7 @@ config CRYPTO_FIPS_VERSION
- By default the KERNELRELEASE value is used.
-
- config CRYPTO_ALGAPI
-- tristate
-+ tristate "ALGAPI"
- select CRYPTO_ALGAPI2
- help
- This option provides the API for cryptographic algorithms.
-@@ -64,7 +64,7 @@ config CRYPTO_ALGAPI2
- tristate
-
- config CRYPTO_AEAD
-- tristate
-+ tristate "AEAD"
- select CRYPTO_AEAD2
- select CRYPTO_ALGAPI
-
-@@ -82,7 +82,7 @@ config CRYPTO_SIG2
- select CRYPTO_ALGAPI2
-
- config CRYPTO_SKCIPHER
-- tristate
-+ tristate "SKCIPHER"
- select CRYPTO_SKCIPHER2
- select CRYPTO_ALGAPI
-
-@@ -91,7 +91,7 @@ config CRYPTO_SKCIPHER2
- select CRYPTO_ALGAPI2
-
- config CRYPTO_HASH
-- tristate
-+ tristate "HASH"
- select CRYPTO_HASH2
- select CRYPTO_ALGAPI
-
-@@ -100,7 +100,7 @@ config CRYPTO_HASH2
- select CRYPTO_ALGAPI2
-
- config CRYPTO_RNG
-- tristate
-+ tristate "RNG"
- select CRYPTO_RNG2
- select CRYPTO_ALGAPI
-
---- a/drivers/bcma/Kconfig
-+++ b/drivers/bcma/Kconfig
-@@ -16,6 +16,7 @@ if BCMA
- # Support for Block-I/O. SELECT this from the driver that needs it.
- config BCMA_BLOCKIO
- bool
-+ default y
-
- config BCMA_HOST_PCI_POSSIBLE
- bool
---- a/drivers/ssb/Kconfig
-+++ b/drivers/ssb/Kconfig
-@@ -29,6 +29,7 @@ config SSB_SPROM
- config SSB_BLOCKIO
- bool
- depends on SSB
-+ default y
-
- config SSB_PCIHOST_POSSIBLE
- bool
-@@ -49,7 +50,7 @@ config SSB_PCIHOST
- config SSB_B43_PCI_BRIDGE
- bool
- depends on SSB_PCIHOST
-- default n
-+ default y
-
- config SSB_PCMCIAHOST_POSSIBLE
- bool
---- a/lib/Kconfig
-+++ b/lib/Kconfig
-@@ -460,16 +460,16 @@ config BCH_CONST_T
- # Textsearch support is select'ed if needed
- #
- config TEXTSEARCH
-- bool
-+ bool "Textsearch support"
-
- config TEXTSEARCH_KMP
-- tristate
-+ tristate "Textsearch KMP"
-
- config TEXTSEARCH_BM
-- tristate
-+ tristate "Textsearch BM"
-
- config TEXTSEARCH_FSM
-- tristate
-+ tristate "Textsearch FSM"
-
- config BTREE
- bool
---- a/net/netfilter/Kconfig
-+++ b/net/netfilter/Kconfig
-@@ -22,7 +22,7 @@ config NETFILTER_SKIP_EGRESS
- def_bool NETFILTER_EGRESS && (NET_CLS_ACT || IFB)
-
- config NETFILTER_NETLINK
-- tristate
-+ tristate "Netfilter NFNETLINK interface"
-
- config NETFILTER_FAMILY_BRIDGE
- bool
---- a/sound/core/Kconfig
-+++ b/sound/core/Kconfig
-@@ -17,7 +17,7 @@ config SND_DMAENGINE_PCM
- tristate
-
- config SND_HWDEP
-- tristate
-+ tristate "Sound hardware support"
-
- config SND_SEQ_DEVICE
- tristate
-@@ -40,7 +40,7 @@ config SND_UMP_LEGACY_RAWMIDI
- The device contains 16 substreams corresponding to UMP groups.
-
- config SND_COMPRESS_OFFLOAD
-- tristate
-+ tristate "Compression offloading support"
-
- config SND_JACK
- bool
---- a/net/Kconfig
-+++ b/net/Kconfig
-@@ -467,7 +467,7 @@ config NET_DEVLINK
- default n
-
- config PAGE_POOL
-- bool
-+ bool "Page pool support"
-
- config PAGE_POOL_STATS
- default n
+++ /dev/null
-From dcd966fa7ca63f38cf7147e1184d13d66e2ca340 Mon Sep 17 00:00:00 2001
-Date: Wed, 13 Jul 2022 13:33:30 +0200
-Subject: [PATCH] Kconfig: add tristate for OID and ASNI string
-
----
- init/Kconfig | 2 +-
- lib/Kconfig | 2 +-
- 2 files changed, 2 insertions(+), 2 deletions(-)
-
---- a/init/Kconfig
-+++ b/init/Kconfig
-@@ -2003,7 +2003,7 @@ config PADATA
- bool
-
- config ASN1
-- tristate
-+ tristate "ASN1"
- help
- Build a simple ASN.1 grammar compiler that produces a bytecode output
- that can be interpreted by the ASN.1 stream decoder and used to
---- a/lib/Kconfig
-+++ b/lib/Kconfig
-@@ -641,7 +641,7 @@ config LIBFDT
- bool
-
- config OID_REGISTRY
-- tristate
-+ tristate "OID"
- help
- Enable fast lookup object identifier registry.
-
+++ /dev/null
-From 811d9e2268a62b830cfe93cd8bc929afcb8b198b Mon Sep 17 00:00:00 2001
-Date: Sat, 15 Jul 2017 21:12:38 +0200
-Subject: kernel: move regmap bloat out of the kernel image if it is only being used in modules
-
-lede-commit: 96f39119815028073583e4fca3a9c5fe9141e998
----
- drivers/base/regmap/Kconfig | 15 ++++++++++-----
- drivers/base/regmap/Makefile | 12 ++++++++----
- drivers/base/regmap/regmap.c | 3 +++
- include/linux/regmap.h | 2 +-
- 4 files changed, 22 insertions(+), 10 deletions(-)
-
---- a/drivers/base/regmap/Kconfig
-+++ b/drivers/base/regmap/Kconfig
-@@ -4,8 +4,7 @@
- # subsystems should select the appropriate symbols.
-
- config REGMAP
-- bool
-- default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_W1 || REGMAP_AC97 || REGMAP_MMIO || REGMAP_IRQ || REGMAP_SOUNDWIRE || REGMAP_SOUNDWIRE_MBQ || REGMAP_SCCB || REGMAP_I3C || REGMAP_SPI_AVMM || REGMAP_MDIO || REGMAP_FSI)
-+ tristate
- select IRQ_DOMAIN if REGMAP_IRQ
- select MDIO_BUS if REGMAP_MDIO
- help
-@@ -19,7 +18,7 @@ config REGMAP
-
- config REGMAP_KUNIT
- tristate "KUnit tests for regmap"
-- depends on KUNIT && REGMAP
-+ depends on KUNIT
- default KUNIT_ALL_TESTS
- select REGMAP_RAM
-
-@@ -34,60 +33,76 @@ config REGMAP_BUILD
- normally enabled.
-
- config REGMAP_AC97
-+ select REGMAP
- tristate
-
- config REGMAP_I2C
-+ select REGMAP
- tristate
- depends on I2C
-
- config REGMAP_SLIMBUS
-+ select REGMAP
- tristate
- depends on SLIMBUS
-
- config REGMAP_SPI
-+ select REGMAP
- tristate
- depends on SPI
-
- config REGMAP_SPMI
-+ select REGMAP
- tristate
- depends on SPMI
-
- config REGMAP_W1
-+ select REGMAP
- tristate
- depends on W1
-
- config REGMAP_MDIO
-+ select REGMAP
- tristate
-
- config REGMAP_MMIO
-+ select REGMAP
- tristate
-
- config REGMAP_IRQ
-+ select REGMAP
- bool
-
- config REGMAP_RAM
-+ select REGMAP
- tristate
-
- config REGMAP_SOUNDWIRE
-+ select REGMAP
- tristate
- depends on SOUNDWIRE
-
- config REGMAP_SOUNDWIRE_MBQ
-+ select REGMAP
- tristate
- depends on SOUNDWIRE
-
- config REGMAP_SCCB
-+ select REGMAP
- tristate
- depends on I2C
-
- config REGMAP_I3C
-+ select REGMAP
- tristate
- depends on I3C
-
- config REGMAP_SPI_AVMM
-+ select REGMAP
- tristate
- depends on SPI
-
- config REGMAP_FSI
-+ select REGMAP
- tristate
- depends on FSI
---- a/drivers/base/regmap/Makefile
-+++ b/drivers/base/regmap/Makefile
-@@ -2,9 +2,11 @@
- # For include/trace/define_trace.h to include trace.h
- CFLAGS_regmap.o := -I$(src)
-
--obj-$(CONFIG_REGMAP) += regmap.o regcache.o
--obj-$(CONFIG_REGMAP) += regcache-rbtree.o regcache-flat.o regcache-maple.o
--obj-$(CONFIG_DEBUG_FS) += regmap-debugfs.o
-+regmap-core-objs = regmap.o regcache.o regcache-rbtree.o regcache-flat.o regcache-maple.o
-+ifdef CONFIG_DEBUG_FS
-+regmap-core-objs += regmap-debugfs.o
-+endif
-+obj-$(CONFIG_REGMAP) += regmap-core.o
- obj-$(CONFIG_REGMAP_KUNIT) += regmap-kunit.o
- obj-$(CONFIG_REGMAP_AC97) += regmap-ac97.o
- obj-$(CONFIG_REGMAP_I2C) += regmap-i2c.o
---- a/drivers/base/regmap/regmap.c
-+++ b/drivers/base/regmap/regmap.c
-@@ -9,6 +9,7 @@
- #include <linux/device.h>
- #include <linux/slab.h>
- #include <linux/export.h>
-+#include <linux/module.h>
- #include <linux/mutex.h>
- #include <linux/err.h>
- #include <linux/property.h>
-@@ -3485,3 +3486,5 @@ static int __init regmap_initcall(void)
- return 0;
- }
- postcore_initcall(regmap_initcall);
-+
-+MODULE_LICENSE("GPL");
---- a/include/linux/regmap.h
-+++ b/include/linux/regmap.h
-@@ -197,7 +197,7 @@ struct reg_sequence {
- __ret ?: __tmp; \
- })
-
--#ifdef CONFIG_REGMAP
-+#if IS_REACHABLE(CONFIG_REGMAP)
-
- enum regmap_endian {
- /* Unspecified -> 0 -> Backwards compatible default */
+++ /dev/null
-From fd1799b0bf5efa46dd3e6dfbbf3955564807e508 Mon Sep 17 00:00:00 2001
-Date: Fri, 7 Jul 2017 17:12:51 +0200
-Subject: kernel: prevent cryptomgr from pulling in useless extra dependencies for tests that are not run
-
-Reduces kernel size after LZMA by about 5k on MIPS
-
-lede-commit: 044c316167e076479a344c59905e5b435b84a77f
----
- crypto/Kconfig | 13 ++++++-------
- crypto/algboss.c | 4 ++++
- 2 files changed, 10 insertions(+), 7 deletions(-)
-
---- a/crypto/Kconfig
-+++ b/crypto/Kconfig
-@@ -148,15 +148,15 @@ config CRYPTO_MANAGER
- cbc(aes).
-
- config CRYPTO_MANAGER2
-- def_tristate CRYPTO_MANAGER || (CRYPTO_MANAGER!=n && CRYPTO_ALGAPI=y)
-- select CRYPTO_ACOMP2
-- select CRYPTO_AEAD2
-- select CRYPTO_AKCIPHER2
-- select CRYPTO_SIG2
-- select CRYPTO_HASH2
-- select CRYPTO_KPP2
-- select CRYPTO_RNG2
-- select CRYPTO_SKCIPHER2
-+ def_tristate CRYPTO_MANAGER || (CRYPTO_MANAGER!=n && CRYPTO_ALGAPI=y && !CRYPTO_MANAGER_DISABLE_TESTS)
-+ select CRYPTO_ACOMP2 if !CRYPTO_MANAGER_DISABLE_TESTS
-+ select CRYPTO_AEAD2 if !CRYPTO_MANAGER_DISABLE_TESTS
-+ select CRYPTO_AKCIPHER2 if !CRYPTO_MANAGER_DISABLE_TESTS
-+ select CRYPTO_SIG2 if !CRYPTO_MANAGER_DISABLE_TESTS
-+ select CRYPTO_HASH2 if !CRYPTO_MANAGER_DISABLE_TESTS
-+ select CRYPTO_KPP2 if !CRYPTO_MANAGER_DISABLE_TESTS
-+ select CRYPTO_RNG2 if !CRYPTO_MANAGER_DISABLE_TESTS
-+ select CRYPTO_SKCIPHER2 if !CRYPTO_MANAGER_DISABLE_TESTS
-
- config CRYPTO_USER
- tristate "Userspace cryptographic algorithm configuration"
---- a/crypto/algboss.c
-+++ b/crypto/algboss.c
-@@ -204,6 +204,10 @@ static int cryptomgr_schedule_test(struc
- memcpy(param->alg, alg->cra_name, sizeof(param->alg));
- param->type = alg->cra_flags;
-
-+#ifdef CONFIG_CRYPTO_MANAGER_DISABLE_TESTS
-+ param->type |= CRYPTO_ALG_TESTED;
-+#endif
-+
- thread = kthread_run(cryptomgr_test, param, "cryptomgr_test");
- if (IS_ERR(thread))
- goto err_free_param;
+++ /dev/null
-From 241e5d3f7b0dd3c01f8c7fa83cbc9a3882286d53 Mon Sep 17 00:00:00 2001
-Date: Wed, 13 Jul 2022 13:35:18 +0200
-Subject: [PATCH] lib/crypto: add tristate string for ARC4
-
-This makes it possible to select CONFIG_CRYPTO_LIB_ARC4 directly. We
-need this to be able to compile this into the kernel and make use of it
-from backports.
-
----
- lib/crypto/Kconfig | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/lib/crypto/Kconfig
-+++ b/lib/crypto/Kconfig
-@@ -15,7 +15,7 @@ config CRYPTO_LIB_AESGCM
- select CRYPTO_LIB_UTILS
-
- config CRYPTO_LIB_ARC4
-- tristate
-+ tristate "ARC4 cipher library"
-
- config CRYPTO_LIB_GF128MUL
- tristate
+++ /dev/null
-From 236c1acdfef5958010ac9814a9872e0a46fd78ee Mon Sep 17 00:00:00 2001
-Date: Fri, 7 Jul 2017 17:13:44 +0200
-Subject: rfkill: add fake rfkill support
-
-allow building of modules depending on RFKILL even if RFKILL is not enabled.
-
----
- include/linux/rfkill.h | 2 +-
- net/Makefile | 2 +-
- net/rfkill/Kconfig | 14 +++++++++-----
- net/rfkill/Makefile | 2 +-
- 4 files changed, 12 insertions(+), 8 deletions(-)
-
---- a/include/linux/rfkill.h
-+++ b/include/linux/rfkill.h
-@@ -64,7 +64,7 @@ struct rfkill_ops {
- int (*set_block)(void *data, bool blocked);
- };
-
--#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
-+#if defined(CONFIG_RFKILL_FULL) || defined(CONFIG_RFKILL_FULL_MODULE)
- /**
- * rfkill_alloc - Allocate rfkill structure
- * @name: name of the struct -- the string is not copied internally
---- a/net/Makefile
-+++ b/net/Makefile
-@@ -52,7 +52,7 @@ obj-$(CONFIG_TIPC) += tipc/
- obj-$(CONFIG_NETLABEL) += netlabel/
- obj-$(CONFIG_IUCV) += iucv/
- obj-$(CONFIG_SMC) += smc/
--obj-$(CONFIG_RFKILL) += rfkill/
-+obj-$(CONFIG_RFKILL_FULL) += rfkill/
- obj-$(CONFIG_NET_9P) += 9p/
- obj-$(CONFIG_CAIF) += caif/
- obj-$(CONFIG_DCB) += dcb/
---- a/net/rfkill/Kconfig
-+++ b/net/rfkill/Kconfig
-@@ -2,7 +2,11 @@
- #
- # RF switch subsystem configuration
- #
--menuconfig RFKILL
-+config RFKILL
-+ bool
-+ default y
-+
-+menuconfig RFKILL_FULL
- tristate "RF switch subsystem support"
- help
- Say Y here if you want to have control over RF switches
-@@ -14,19 +18,19 @@ menuconfig RFKILL
- # LED trigger support
- config RFKILL_LEDS
- bool
-- depends on RFKILL
-+ depends on RFKILL_FULL
- depends on LEDS_TRIGGERS = y || RFKILL = LEDS_TRIGGERS
- default y
-
- config RFKILL_INPUT
- bool "RF switch input support" if EXPERT
-- depends on RFKILL
-+ depends on RFKILL_FULL
- depends on INPUT = y || RFKILL = INPUT
- default y if !EXPERT
-
- config RFKILL_GPIO
- tristate "GPIO RFKILL driver"
-- depends on RFKILL
-+ depends on RFKILL_FULL
- depends on GPIOLIB || COMPILE_TEST
- default n
- help
---- a/net/rfkill/Makefile
-+++ b/net/rfkill/Makefile
-@@ -5,5 +5,5 @@
-
- rfkill-y += core.o
- rfkill-$(CONFIG_RFKILL_INPUT) += input.o
--obj-$(CONFIG_RFKILL) += rfkill.o
-+obj-$(CONFIG_RFKILL_FULL) += rfkill.o
- obj-$(CONFIG_RFKILL_GPIO) += rfkill-gpio.o
+++ /dev/null
-Date: Fri, 7 Jun 2013 18:35:22 -0500
-Subject: MIPS: r4k_cache: use more efficient cache blast
-
-Optimize the compiler output for larger cache blast cases that are
-common for DMA-based networking.
-
----
---- a/arch/mips/include/asm/r4kcache.h
-+++ b/arch/mips/include/asm/r4kcache.h
-@@ -286,14 +286,46 @@ static inline void prot##extra##blast_##
- unsigned long end) \
- { \
- unsigned long lsize = cpu_##desc##_line_size(); \
-+ unsigned long lsize_2 = lsize * 2; \
-+ unsigned long lsize_3 = lsize * 3; \
-+ unsigned long lsize_4 = lsize * 4; \
-+ unsigned long lsize_5 = lsize * 5; \
-+ unsigned long lsize_6 = lsize * 6; \
-+ unsigned long lsize_7 = lsize * 7; \
-+ unsigned long lsize_8 = lsize * 8; \
- unsigned long addr = start & ~(lsize - 1); \
-- unsigned long aend = (end - 1) & ~(lsize - 1); \
-+ unsigned long aend = (end + lsize - 1) & ~(lsize - 1); \
-+ int lines = (aend - addr) / lsize; \
- \
-- while (1) { \
-+ while (lines >= 8) { \
-+ prot##cache_op(hitop, addr); \
-+ prot##cache_op(hitop, addr + lsize); \
-+ prot##cache_op(hitop, addr + lsize_2); \
-+ prot##cache_op(hitop, addr + lsize_3); \
-+ prot##cache_op(hitop, addr + lsize_4); \
-+ prot##cache_op(hitop, addr + lsize_5); \
-+ prot##cache_op(hitop, addr + lsize_6); \
-+ prot##cache_op(hitop, addr + lsize_7); \
-+ addr += lsize_8; \
-+ lines -= 8; \
-+ } \
-+ \
-+ if (lines & 0x4) { \
-+ prot##cache_op(hitop, addr); \
-+ prot##cache_op(hitop, addr + lsize); \
-+ prot##cache_op(hitop, addr + lsize_2); \
-+ prot##cache_op(hitop, addr + lsize_3); \
-+ addr += lsize_4; \
-+ } \
-+ \
-+ if (lines & 0x2) { \
-+ prot##cache_op(hitop, addr); \
-+ prot##cache_op(hitop, addr + lsize); \
-+ addr += lsize_2; \
-+ } \
-+ \
-+ if (lines & 0x1) { \
- prot##cache_op(hitop, addr); \
-- if (addr == aend) \
-- break; \
-- addr += lsize; \
- } \
- }
-
+++ /dev/null
-From 0bccc3722bdd88e8ae995e77ef9f7b77ee4cbdee Mon Sep 17 00:00:00 2001
-Date: Wed, 7 Apr 2021 22:45:54 +0100
-Subject: [PATCH 2/2] mtd: blktrans: call add disks after mtd device
-
-Calling device_add_disk while holding mtd_table_mutex leads
-to deadlock in case part_bits!=0 as block partition parsers
-will try to open the newly created disks, trying to acquire
-mutex once again.
-Move device_add_disk to additional function called after
-add partitions of an MTD device have been added and locks
-have been released.
-
----
- drivers/mtd/mtd_blkdevs.c | 33 ++++++++++++++++++++++++++-------
- drivers/mtd/mtdcore.c | 3 +++
- include/linux/mtd/blktrans.h | 1 +
- 3 files changed, 30 insertions(+), 7 deletions(-)
-
---- a/drivers/mtd/mtd_blkdevs.c
-+++ b/drivers/mtd/mtd_blkdevs.c
-@@ -386,19 +386,8 @@ int add_mtd_blktrans_dev(struct mtd_blkt
- if (new->readonly)
- set_disk_ro(gd, 1);
-
-- ret = device_add_disk(&new->mtd->dev, gd, NULL);
-- if (ret)
-- goto out_cleanup_disk;
--
-- if (new->disk_attributes) {
-- ret = sysfs_create_group(&disk_to_dev(gd)->kobj,
-- new->disk_attributes);
-- WARN_ON(ret);
-- }
- return 0;
-
--out_cleanup_disk:
-- put_disk(new->disk);
- out_free_tag_set:
- blk_mq_free_tag_set(new->tag_set);
- out_kfree_tag_set:
-@@ -408,6 +397,35 @@ out_list_del:
- return ret;
- }
-
-+void register_mtd_blktrans_devs(void)
-+{
-+ struct mtd_blktrans_ops *tr;
-+ struct mtd_blktrans_dev *dev, *next;
-+ int ret;
-+
-+ list_for_each_entry(tr, &blktrans_majors, list) {
-+ list_for_each_entry_safe(dev, next, &tr->devs, list) {
-+ if (disk_live(dev->disk))
-+ continue;
-+
-+ ret = device_add_disk(&dev->mtd->dev, dev->disk, NULL);
-+ if (ret)
-+ goto out_cleanup_disk;
-+
-+ if (dev->disk_attributes) {
-+ ret = sysfs_create_group(&disk_to_dev(dev->disk)->kobj,
-+ dev->disk_attributes);
-+ WARN_ON(ret);
-+ }
-+ }
-+ }
-+
-+ return;
-+
-+out_cleanup_disk:
-+ put_disk(dev->disk);
-+}
-+
- int del_mtd_blktrans_dev(struct mtd_blktrans_dev *old)
- {
- unsigned long flags;
---- a/drivers/mtd/mtdcore.c
-+++ b/drivers/mtd/mtdcore.c
-@@ -33,6 +33,7 @@
-
- #include <linux/mtd/mtd.h>
- #include <linux/mtd/partitions.h>
-+#include <linux/mtd/blktrans.h>
-
- #include "mtdcore.h"
-
-@@ -1127,6 +1128,8 @@ int mtd_device_parse_register(struct mtd
- register_reboot_notifier(&mtd->reboot_notifier);
- }
-
-+ register_mtd_blktrans_devs();
-+
- out:
- if (ret) {
- nvmem_unregister(mtd->otp_user_nvmem);
---- a/include/linux/mtd/blktrans.h
-+++ b/include/linux/mtd/blktrans.h
-@@ -76,6 +76,7 @@ extern int deregister_mtd_blktrans(struc
- extern int add_mtd_blktrans_dev(struct mtd_blktrans_dev *dev);
- extern int del_mtd_blktrans_dev(struct mtd_blktrans_dev *dev);
- extern int mtd_blktrans_cease_background(struct mtd_blktrans_dev *dev);
-+extern void register_mtd_blktrans_devs(void);
-
- /**
- * module_mtd_blktrans() - Helper macro for registering a mtd blktrans driver
+++ /dev/null
-Date: Mon, 7 Nov 2022 23:48:24 +0100
-Subject: [PATCH] mtd: support OpenWrt's MTD_ROOTFS_ROOT_DEV
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-This allows setting ROOT_DEV to MTD partition named "rootfs".
-
----
-
---- a/drivers/mtd/mtdcore.c
-+++ b/drivers/mtd/mtdcore.c
-@@ -801,7 +801,8 @@ int add_mtd_device(struct mtd_info *mtd)
-
- mutex_unlock(&mtd_table_mutex);
-
-- if (of_property_read_bool(mtd_get_of_node(mtd), "linux,rootfs")) {
-+ if (of_property_read_bool(mtd_get_of_node(mtd), "linux,rootfs") ||
-+ (IS_ENABLED(CONFIG_MTD_ROOTFS_ROOT_DEV) && !strcmp(mtd->name, "rootfs") && ROOT_DEV == 0)) {
- if (IS_BUILTIN(CONFIG_MTD)) {
- pr_info("mtd: setting mtd%d (%s) as root device\n", mtd->index, mtd->name);
- ROOT_DEV = MKDEV(MTD_BLOCK_MAJOR, mtd->index);
+++ /dev/null
-From 6fa9e3678eb002246df1280322b6a024853950a5 Mon Sep 17 00:00:00 2001
-Date: Mon, 11 Oct 2021 00:53:14 +0200
-Subject: [PATCH] drivers: mtd: parsers: add nvmem support to cmdlinepart
-
-Assuming cmdlinepart is only one level deep partition scheme and that
-static partition are also defined in DTS, we can assign an of_node for
-partition declared from bootargs. cmdlinepart have priority than
-fiexed-partition parser so in this specific case the parser doesn't
-assign an of_node. Fix this by searching a defined of_node using a
-similar fixed_partition parser and if a partition is found with the same
-label, check that it has the same offset and size and return the DT
-of_node to correctly use NVMEM cells.
-
----
- drivers/mtd/parsers/cmdlinepart.c | 71 +++++++++++++++++++++++++++++++
- 1 file changed, 71 insertions(+)
-
---- a/drivers/mtd/parsers/cmdlinepart.c
-+++ b/drivers/mtd/parsers/cmdlinepart.c
-@@ -43,6 +43,7 @@
- #include <linux/mtd/partitions.h>
- #include <linux/module.h>
- #include <linux/err.h>
-+#include <linux/of.h>
-
- /* debug macro */
- #if 0
-@@ -323,6 +324,68 @@ static int mtdpart_setup_real(char *s)
- return 0;
- }
-
-+static int search_fixed_partition(struct mtd_info *master,
-+ struct mtd_partition *target_part,
-+ struct mtd_partition *fixed_part)
-+{
-+ struct device_node *mtd_node;
-+ struct device_node *ofpart_node;
-+ struct device_node *pp;
-+ struct mtd_partition part;
-+ const char *partname;
-+
-+ mtd_node = mtd_get_of_node(master);
-+ if (!mtd_node)
-+ return -EINVAL;
-+
-+ ofpart_node = of_get_child_by_name(mtd_node, "partitions");
-+
-+ for_each_child_of_node(ofpart_node, pp) {
-+ const __be32 *reg;
-+ int len;
-+ int a_cells, s_cells;
-+
-+ reg = of_get_property(pp, "reg", &len);
-+ if (!reg) {
-+ pr_debug("%s: ofpart partition %pOF (%pOF) missing reg property.\n",
-+ master->name, pp,
-+ mtd_node);
-+ continue;
-+ }
-+
-+ a_cells = of_n_addr_cells(pp);
-+ s_cells = of_n_size_cells(pp);
-+ if (len / 4 != a_cells + s_cells) {
-+ pr_debug("%s: ofpart partition %pOF (%pOF) error parsing reg property.\n",
-+ master->name, pp,
-+ mtd_node);
-+ continue;
-+ }
-+
-+ part.offset = of_read_number(reg, a_cells);
-+ part.size = of_read_number(reg + a_cells, s_cells);
-+ part.of_node = pp;
-+
-+ partname = of_get_property(pp, "label", &len);
-+ if (!partname)
-+ partname = of_get_property(pp, "name", &len);
-+ part.name = partname;
-+
-+ if (!strncmp(target_part->name, part.name, len)) {
-+ if (part.offset != target_part->offset)
-+ return -EINVAL;
-+
-+ if (part.size != target_part->size)
-+ return -EINVAL;
-+
-+ memcpy(fixed_part, &part, sizeof(struct mtd_partition));
-+ return 0;
-+ }
-+ }
-+
-+ return -EINVAL;
-+}
-+
- /*
- * Main function to be called from the MTD mapping driver/device to
- * obtain the partitioning information. At this point the command line
-@@ -338,6 +401,7 @@ static int parse_cmdline_partitions(stru
- int i, err;
- struct cmdline_mtd_partition *part;
- const char *mtd_id = master->name;
-+ struct mtd_partition fixed_part;
-
- /* parse command line */
- if (!cmdline_parsed) {
-@@ -382,6 +446,13 @@ static int parse_cmdline_partitions(stru
- sizeof(*part->parts) * (part->num_parts - i));
- i--;
- }
-+
-+ err = search_fixed_partition(master, &part->parts[i], &fixed_part);
-+ if (!err) {
-+ part->parts[i].of_node = fixed_part.of_node;
-+ pr_info("Found partition defined in DT for %s. Assigning OF node to support nvmem.",
-+ part->parts[i].name);
-+ }
- }
-
- *pparts = kmemdup(part->parts, sizeof(*part->parts) * part->num_parts,
+++ /dev/null
-From ac84397efb3b3868c71c10ad7521161773228a17 Mon Sep 17 00:00:00 2001
-Date: Wed, 13 Jul 2022 13:41:44 +0200
-Subject: [PATCH] mtd/nand: add MediaTek NAND bad block managment table
-
----
- drivers/mtd/nand/Kconfig | 4 ++++
- drivers/mtd/nand/Makefile | 1 +
- 2 files changed, 5 insertions(+)
-
---- a/drivers/mtd/nand/Kconfig
-+++ b/drivers/mtd/nand/Kconfig
-@@ -46,6 +46,10 @@ config MTD_NAND_ECC_SW_BCH
- ECC codes. They are used with NAND devices requiring more than 1 bit
- of error correction.
-
-+config MTD_NAND_MTK_BMT
-+ bool "Support MediaTek NAND Bad-block Management Table"
-+ default n
-+
- config MTD_NAND_ECC_MXIC
- bool "Macronix external hardware ECC engine"
- depends on HAS_IOMEM
---- a/drivers/mtd/nand/Makefile
-+++ b/drivers/mtd/nand/Makefile
-@@ -3,6 +3,7 @@
- nandcore-objs := core.o bbt.o
- obj-$(CONFIG_MTD_NAND_CORE) += nandcore.o
- obj-$(CONFIG_MTD_NAND_ECC_MEDIATEK) += ecc-mtk.o
-+obj-$(CONFIG_MTD_NAND_MTK_BMT) += mtk_bmt.o mtk_bmt_v2.o mtk_bmt_bbt.o mtk_bmt_nmbm.o
- ifeq ($(CONFIG_SPI_QPIC_SNAND),y)
- obj-$(CONFIG_SPI_QPIC_SNAND) += qpic_common.o
- else
+++ /dev/null
-Date: Tue, 23 Apr 2024 12:35:21 +0200
-Subject: [PATCH] net: enable fraglist GRO by default
-
-This can significantly improve performance for packet forwarding/bridging
-
----
-
---- a/include/linux/netdev_features.h
-+++ b/include/linux/netdev_features.h
-@@ -243,10 +243,10 @@ static inline int find_next_netdev_featu
- #define NETIF_F_UPPER_DISABLES NETIF_F_LRO
-
- /* changeable features with no special hardware requirements */
--#define NETIF_F_SOFT_FEATURES (NETIF_F_GSO | NETIF_F_GRO)
-+#define NETIF_F_SOFT_FEATURES (NETIF_F_GSO | NETIF_F_GRO | NETIF_F_GRO_FRAGLIST)
-
- /* Changeable features with no special hardware requirements that defaults to off. */
--#define NETIF_F_SOFT_FEATURES_OFF (NETIF_F_GRO_FRAGLIST | NETIF_F_GRO_UDP_FWD)
-+#define NETIF_F_SOFT_FEATURES_OFF (NETIF_F_GRO_UDP_FWD)
-
- #define NETIF_F_VLAN_FEATURES (NETIF_F_HW_VLAN_CTAG_FILTER | \
- NETIF_F_HW_VLAN_CTAG_RX | \
+++ /dev/null
-Date: Fri, 3 Jan 2025 19:29:00 +0100
-Subject: [PATCH] net: page_pool: try to free deferred skbs while waiting for
- pool release
-
-The NAPI defer list can accumulate no longer used skbs, which can be reused
-during alloc. If this happens on a CPU that otherwise does not do any
-rx softirq processing, skbs can be held indefinitely, causing warnings
-on releasing page pools.
-Deal with this by scheduling rx softirq on all CPUs.
-
-Patch by Lorenzo Bianconi
-
----
-
---- a/net/core/page_pool.c
-+++ b/net/core/page_pool.c
-@@ -875,7 +875,8 @@ static void page_pool_release_retry(stru
- {
- struct delayed_work *dwq = to_delayed_work(wq);
- struct page_pool *pool = container_of(dwq, typeof(*pool), release_dw);
-- int inflight;
-+ unsigned long flags;
-+ int cpu, inflight;
-
- inflight = page_pool_release(pool);
- /* In rare cases, a driver bug may cause inflight to go negative.
-@@ -887,6 +888,21 @@ static void page_pool_release_retry(stru
- if (inflight <= 0)
- return;
-
-+ /* Run NET_RX_SOFTIRQ in order to free pending skbs in softnet_data
-+ * defer_list that can stay in the list until we have enough queued
-+ * traffic.
-+ */
-+ local_irq_save(flags);
-+ for_each_online_cpu(cpu) {
-+ struct softnet_data *sd = &per_cpu(softnet_data, cpu);
-+
-+ if (cpu == raw_smp_processor_id())
-+ raise_softirq_irqoff(NET_RX_SOFTIRQ);
-+ else if (!cmpxchg(&sd->defer_ipi_scheduled, 0, 1))
-+ smp_call_function_single_async(cpu, &sd->defer_csd);
-+ }
-+ local_irq_restore(flags);
-+
- /* Periodic warning */
- if (time_after_eq(jiffies, pool->defer_warn)) {
- int sec = (s32)((u32)jiffies - (u32)pool->defer_start) / HZ;
+++ /dev/null
-From eda40b8c8c82e0f2789d6bc8bf63846dce2e8f32 Mon Sep 17 00:00:00 2001
-Date: Sat, 23 Mar 2019 09:29:49 +0000
-Subject: [PATCH] netfilter: connmark: introduce set-dscpmark
-
-set-dscpmark is a method of storing the DSCP of an ip packet into
-conntrack mark. In combination with a suitable tc filter action
-(act_ctinfo) DSCP values are able to be stored in the mark on egress and
-restored on ingress across links that otherwise alter or bleach DSCP.
-
-This is useful for qdiscs such as CAKE which are able to shape according
-to policies based on DSCP.
-
-Ingress classification is traditionally a challenging task since
-iptables rules haven't yet run and tc filter/eBPF programs are pre-NAT
-lookups, hence are unable to see internal IPv4 addresses as used on the
-typical home masquerading gateway.
-
-x_tables CONNMARK set-dscpmark target solves the problem of storing the
-DSCP to the conntrack mark in a way suitable for the new act_ctinfo tc
-action to restore.
-
-The set-dscpmark option accepts 2 parameters, a 32bit 'dscpmask' and a
-32bit 'statemask'. The dscp mask must be 6 contiguous bits and
-represents the area where the DSCP will be stored in the connmark. The
-state mask is a minimum 1 bit length mask that must not overlap with the
-dscpmask. It represents a flag which is set when the DSCP has been
-stored in the conntrack mark. This is useful to implement a 'one shot'
-iptables based classification where the 'complicated' iptables rules are
-only run once to classify the connection on initial (egress) packet and
-subsequent packets are all marked/restored with the same DSCP. A state
-mask of zero disables the setting of a status bit/s.
-
-example syntax with a suitably modified iptables user space application:
-
-iptables -A QOS_MARK_eth0 -t mangle -j CONNMARK --set-dscpmark 0xfc000000/0x01000000
-
-Would store the DSCP in the top 6 bits of the 32bit mark field, and use
-the LSB of the top byte as the 'DSCP has been stored' marker.
-
-|----0xFC----conntrack mark----000000---|
-| Bits 31-26 | bit 25 | bit24 |~~~ Bit 0|
-| DSCP | unused | flag |unused |
-|-----------------------0x01---000000---|
- ^ ^
- | |
- ---| Conditional flag
- | set this when dscp
-|-ip diffserv-| stored in mark
-| 6 bits |
-|-------------|
-
-an identically configured tc action to restore looks like:
-
-tc filter show dev eth0 ingress
-filter parent ffff: protocol all pref 10 u32 chain 0
-filter parent ffff: protocol all pref 10 u32 chain 0 fh 800: ht divisor 1
-filter parent ffff: protocol all pref 10 u32 chain 0 fh 800::800 order 2048 key ht 800 bkt 0 flowid 1: not_in_hw
- match 00000000/00000000 at 0
- action order 1: ctinfo zone 0 pipe
- index 2 ref 1 bind 1 dscp 0xfc000000/0x1000000
-
- action order 2: mirred (Egress Redirect to device ifb4eth0) stolen
- index 1 ref 1 bind 1
-
-|----0xFC----conntrack mark----000000---|
-| Bits 31-26 | bit 25 | bit24 |~~~ Bit 0|
-| DSCP | unused | flag |unused |
-|-----------------------0x01---000000---|
- | |
- | |
- ---| Conditional flag
- v only restore if set
-|-ip diffserv-|
-| 6 bits |
-|-------------|
-
----
- include/uapi/linux/netfilter/xt_connmark.h | 10 ++++
- net/netfilter/xt_connmark.c | 55 ++++++++++++++++++----
- 2 files changed, 57 insertions(+), 8 deletions(-)
-
---- a/include/uapi/linux/netfilter/xt_connmark.h
-+++ b/include/uapi/linux/netfilter/xt_connmark.h
-@@ -15,6 +15,11 @@ enum {
- };
-
- enum {
-+ XT_CONNMARK_VALUE = (1 << 0),
-+ XT_CONNMARK_DSCP = (1 << 1)
-+};
-+
-+enum {
- D_SHIFT_LEFT = 0,
- D_SHIFT_RIGHT,
- };
-@@ -29,6 +34,11 @@ struct xt_connmark_tginfo2 {
- __u8 shift_dir, shift_bits, mode;
- };
-
-+struct xt_connmark_tginfo3 {
-+ __u32 ctmark, ctmask, nfmask;
-+ __u8 shift_dir, shift_bits, mode, func;
-+};
-+
- struct xt_connmark_mtinfo1 {
- __u32 mark, mask;
- __u8 invert;
---- a/net/netfilter/xt_connmark.c
-+++ b/net/netfilter/xt_connmark.c
-@@ -24,13 +24,13 @@ MODULE_ALIAS("ipt_connmark");
- MODULE_ALIAS("ip6t_connmark");
-
- static unsigned int
--connmark_tg_shift(struct sk_buff *skb, const struct xt_connmark_tginfo2 *info)
-+connmark_tg_shift(struct sk_buff *skb, const struct xt_connmark_tginfo3 *info)
- {
- enum ip_conntrack_info ctinfo;
- u_int32_t new_targetmark;
- struct nf_conn *ct;
- u_int32_t newmark;
-- u_int32_t oldmark;
-+ u_int8_t dscp;
-
- ct = nf_ct_get(skb, &ctinfo);
- if (ct == NULL)
-@@ -38,13 +38,24 @@ connmark_tg_shift(struct sk_buff *skb, c
-
- switch (info->mode) {
- case XT_CONNMARK_SET:
-- oldmark = READ_ONCE(ct->mark);
-- newmark = (oldmark & ~info->ctmask) ^ info->ctmark;
-- if (info->shift_dir == D_SHIFT_RIGHT)
-- newmark >>= info->shift_bits;
-- else
-- newmark <<= info->shift_bits;
-+ newmark = READ_ONCE(ct->mark);
-+ if (info->func & XT_CONNMARK_VALUE) {
-+ newmark = (newmark & ~info->ctmask) ^ info->ctmark;
-+ if (info->shift_dir == D_SHIFT_RIGHT)
-+ newmark >>= info->shift_bits;
-+ else
-+ newmark <<= info->shift_bits;
-+ } else if (info->func & XT_CONNMARK_DSCP) {
-+ if (skb->protocol == htons(ETH_P_IP))
-+ dscp = ipv4_get_dsfield(ip_hdr(skb)) >> 2;
-+ else if (skb->protocol == htons(ETH_P_IPV6))
-+ dscp = ipv6_get_dsfield(ipv6_hdr(skb)) >> 2;
-+ else /* protocol doesn't have diffserv */
-+ break;
-
-+ newmark = (newmark & ~info->ctmark) |
-+ (info->ctmask | (dscp << info->shift_bits));
-+ }
- if (READ_ONCE(ct->mark) != newmark) {
- WRITE_ONCE(ct->mark, newmark);
- nf_conntrack_event_cache(IPCT_MARK, ct);
-@@ -83,20 +94,36 @@ static unsigned int
- connmark_tg(struct sk_buff *skb, const struct xt_action_param *par)
- {
- const struct xt_connmark_tginfo1 *info = par->targinfo;
-- const struct xt_connmark_tginfo2 info2 = {
-+ const struct xt_connmark_tginfo3 info3 = {
- .ctmark = info->ctmark,
- .ctmask = info->ctmask,
- .nfmask = info->nfmask,
- .mode = info->mode,
-+ .func = XT_CONNMARK_VALUE
- };
-
-- return connmark_tg_shift(skb, &info2);
-+ return connmark_tg_shift(skb, &info3);
- }
-
- static unsigned int
- connmark_tg_v2(struct sk_buff *skb, const struct xt_action_param *par)
- {
- const struct xt_connmark_tginfo2 *info = par->targinfo;
-+ const struct xt_connmark_tginfo3 info3 = {
-+ .ctmark = info->ctmark,
-+ .ctmask = info->ctmask,
-+ .nfmask = info->nfmask,
-+ .mode = info->mode,
-+ .func = XT_CONNMARK_VALUE
-+ };
-+
-+ return connmark_tg_shift(skb, &info3);
-+}
-+
-+static unsigned int
-+connmark_tg_v3(struct sk_buff *skb, const struct xt_action_param *par)
-+{
-+ const struct xt_connmark_tginfo3 *info = par->targinfo;
-
- return connmark_tg_shift(skb, info);
- }
-@@ -168,6 +195,16 @@ static struct xt_target connmark_tg_reg[
- .destroy = connmark_tg_destroy,
- .me = THIS_MODULE,
- },
-+ {
-+ .name = "CONNMARK",
-+ .revision = 3,
-+ .family = NFPROTO_IPV4,
-+ .checkentry = connmark_tg_check,
-+ .target = connmark_tg_v3,
-+ .targetsize = sizeof(struct xt_connmark_tginfo3),
-+ .destroy = connmark_tg_destroy,
-+ .me = THIS_MODULE,
-+ },
- #if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)
- {
- .name = "CONNMARK",
-@@ -189,6 +226,16 @@ static struct xt_target connmark_tg_reg[
- .destroy = connmark_tg_destroy,
- .me = THIS_MODULE,
- },
-+ {
-+ .name = "CONNMARK",
-+ .revision = 3,
-+ .family = NFPROTO_IPV6,
-+ .checkentry = connmark_tg_check,
-+ .target = connmark_tg_v3,
-+ .targetsize = sizeof(struct xt_connmark_tginfo3),
-+ .destroy = connmark_tg_destroy,
-+ .me = THIS_MODULE,
-+ },
- #endif
- };
-
+++ /dev/null
-Date: Tue, 20 Feb 2018 15:56:02 +0100
-Subject: [PATCH] netfilter: add xt_FLOWOFFLOAD target
-
----
- create mode 100644 net/netfilter/xt_OFFLOAD.c
-
---- a/net/netfilter/Kconfig
-+++ b/net/netfilter/Kconfig
-@@ -729,7 +729,6 @@ config NF_FLOW_TABLE
- tristate "Netfilter flow table module"
- depends on NETFILTER_INGRESS
- depends on NF_CONNTRACK
-- depends on NF_TABLES
- help
- This option adds the flow table core infrastructure.
-
-@@ -1025,6 +1024,15 @@ config NETFILTER_XT_TARGET_NOTRACK
- depends on NETFILTER_ADVANCED
- select NETFILTER_XT_TARGET_CT
-
-+config NETFILTER_XT_TARGET_FLOWOFFLOAD
-+ tristate '"FLOWOFFLOAD" target support'
-+ depends on NF_FLOW_TABLE
-+ depends on NETFILTER_INGRESS
-+ help
-+ This option adds a `FLOWOFFLOAD' target, which uses the nf_flow_offload
-+ module to speed up processing of packets by bypassing the usual
-+ netfilter chains
-+
- config NETFILTER_XT_TARGET_RATEEST
- tristate '"RATEEST" target support'
- depends on NETFILTER_ADVANCED
---- a/net/netfilter/Makefile
-+++ b/net/netfilter/Makefile
-@@ -163,6 +163,7 @@ obj-$(CONFIG_NETFILTER_XT_TARGET_CLASSIF
- obj-$(CONFIG_NETFILTER_XT_TARGET_CONNSECMARK) += xt_CONNSECMARK.o
- obj-$(CONFIG_NETFILTER_XT_TARGET_CT) += xt_CT.o
- obj-$(CONFIG_NETFILTER_XT_TARGET_DSCP) += xt_DSCP.o
-+obj-$(CONFIG_NETFILTER_XT_TARGET_FLOWOFFLOAD) += xt_FLOWOFFLOAD.o
- obj-$(CONFIG_NETFILTER_XT_TARGET_HL) += xt_HL.o
- obj-$(CONFIG_NETFILTER_XT_TARGET_HMARK) += xt_HMARK.o
- obj-$(CONFIG_NETFILTER_XT_TARGET_LED) += xt_LED.o
---- /dev/null
-+++ b/net/netfilter/xt_FLOWOFFLOAD.c
-@@ -0,0 +1,703 @@
-+/*
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
-+ */
-+#include <linux/module.h>
-+#include <linux/init.h>
-+#include <linux/netfilter.h>
-+#include <linux/netfilter/xt_FLOWOFFLOAD.h>
-+#include <linux/if_vlan.h>
-+#include <net/ip.h>
-+#include <net/netfilter/nf_conntrack.h>
-+#include <net/netfilter/nf_conntrack_extend.h>
-+#include <net/netfilter/nf_conntrack_helper.h>
-+#include <net/netfilter/nf_flow_table.h>
-+
-+struct xt_flowoffload_hook {
-+ struct hlist_node list;
-+ struct nf_hook_ops ops;
-+ struct net *net;
-+ bool registered;
-+ bool used;
-+};
-+
-+struct xt_flowoffload_table {
-+ struct nf_flowtable ft;
-+ struct hlist_head hooks;
-+ struct delayed_work work;
-+};
-+
-+struct nf_forward_info {
-+ const struct net_device *indev;
-+ const struct net_device *outdev;
-+ const struct net_device *hw_outdev;
-+ struct id {
-+ __u16 id;
-+ __be16 proto;
-+ } encap[NF_FLOW_TABLE_ENCAP_MAX];
-+ u8 num_encaps;
-+ u8 ingress_vlans;
-+ u8 h_source[ETH_ALEN];
-+ u8 h_dest[ETH_ALEN];
-+ enum flow_offload_xmit_type xmit_type;
-+};
-+
-+static DEFINE_SPINLOCK(hooks_lock);
-+
-+struct xt_flowoffload_table flowtable[2];
-+
-+static unsigned int
-+xt_flowoffload_net_hook(void *priv, struct sk_buff *skb,
-+ const struct nf_hook_state *state)
-+{
-+ struct vlan_ethhdr *veth;
-+ __be16 proto;
-+
-+ switch (skb->protocol) {
-+ case htons(ETH_P_8021Q):
-+ veth = (struct vlan_ethhdr *)skb_mac_header(skb);
-+ proto = veth->h_vlan_encapsulated_proto;
-+ break;
-+ case htons(ETH_P_PPP_SES):
-+ if (!nf_flow_pppoe_proto(skb, &proto))
-+ return NF_ACCEPT;
-+ break;
-+ default:
-+ proto = skb->protocol;
-+ break;
-+ }
-+
-+ switch (proto) {
-+ case htons(ETH_P_IP):
-+ return nf_flow_offload_ip_hook(priv, skb, state);
-+ case htons(ETH_P_IPV6):
-+ return nf_flow_offload_ipv6_hook(priv, skb, state);
-+ }
-+
-+ return NF_ACCEPT;
-+}
-+
-+static int
-+xt_flowoffload_create_hook(struct xt_flowoffload_table *table,
-+ struct net_device *dev)
-+{
-+ struct xt_flowoffload_hook *hook;
-+ struct nf_hook_ops *ops;
-+
-+ hook = kzalloc(sizeof(*hook), GFP_ATOMIC);
-+ if (!hook)
-+ return -ENOMEM;
-+
-+ ops = &hook->ops;
-+ ops->pf = NFPROTO_NETDEV;
-+ ops->hooknum = NF_NETDEV_INGRESS;
-+ ops->priority = 10;
-+ ops->priv = &table->ft;
-+ ops->hook = xt_flowoffload_net_hook;
-+ ops->dev = dev;
-+
-+ hlist_add_head(&hook->list, &table->hooks);
-+ mod_delayed_work(system_power_efficient_wq, &table->work, 0);
-+
-+ return 0;
-+}
-+
-+static struct xt_flowoffload_hook *
-+flow_offload_lookup_hook(struct xt_flowoffload_table *table,
-+ struct net_device *dev)
-+{
-+ struct xt_flowoffload_hook *hook;
-+
-+ hlist_for_each_entry(hook, &table->hooks, list) {
-+ if (hook->ops.dev == dev)
-+ return hook;
-+ }
-+
-+ return NULL;
-+}
-+
-+static void
-+xt_flowoffload_check_device(struct xt_flowoffload_table *table,
-+ struct net_device *dev)
-+{
-+ struct xt_flowoffload_hook *hook;
-+
-+ if (!dev)
-+ return;
-+
-+ spin_lock_bh(&hooks_lock);
-+ hook = flow_offload_lookup_hook(table, dev);
-+ if (hook)
-+ hook->used = true;
-+ else
-+ xt_flowoffload_create_hook(table, dev);
-+ spin_unlock_bh(&hooks_lock);
-+}
-+
-+static void
-+xt_flowoffload_register_hooks(struct xt_flowoffload_table *table)
-+{
-+ struct xt_flowoffload_hook *hook;
-+
-+restart:
-+ hlist_for_each_entry(hook, &table->hooks, list) {
-+ if (hook->registered)
-+ continue;
-+
-+ hook->registered = true;
-+ hook->net = dev_net(hook->ops.dev);
-+ spin_unlock_bh(&hooks_lock);
-+ nf_register_net_hook(hook->net, &hook->ops);
-+ if (table->ft.flags & NF_FLOWTABLE_HW_OFFLOAD)
-+ table->ft.type->setup(&table->ft, hook->ops.dev,
-+ FLOW_BLOCK_BIND);
-+ spin_lock_bh(&hooks_lock);
-+ goto restart;
-+ }
-+
-+}
-+
-+static bool
-+xt_flowoffload_cleanup_hooks(struct xt_flowoffload_table *table)
-+{
-+ struct xt_flowoffload_hook *hook;
-+ bool active = false;
-+
-+restart:
-+ spin_lock_bh(&hooks_lock);
-+ hlist_for_each_entry(hook, &table->hooks, list) {
-+ if (hook->used || !hook->registered) {
-+ active = true;
-+ continue;
-+ }
-+
-+ hlist_del(&hook->list);
-+ spin_unlock_bh(&hooks_lock);
-+ if (table->ft.flags & NF_FLOWTABLE_HW_OFFLOAD)
-+ table->ft.type->setup(&table->ft, hook->ops.dev,
-+ FLOW_BLOCK_UNBIND);
-+ nf_unregister_net_hook(hook->net, &hook->ops);
-+ kfree(hook);
-+ goto restart;
-+ }
-+ spin_unlock_bh(&hooks_lock);
-+
-+ return active;
-+}
-+
-+static void
-+xt_flowoffload_check_hook(struct nf_flowtable *flowtable,
-+ struct flow_offload *flow, void *data)
-+{
-+ struct xt_flowoffload_table *table;
-+ struct flow_offload_tuple *tuple0 = &flow->tuplehash[0].tuple;
-+ struct flow_offload_tuple *tuple1 = &flow->tuplehash[1].tuple;
-+ struct xt_flowoffload_hook *hook;
-+
-+ table = container_of(flowtable, struct xt_flowoffload_table, ft);
-+
-+ spin_lock_bh(&hooks_lock);
-+ hlist_for_each_entry(hook, &table->hooks, list) {
-+ if (hook->ops.dev->ifindex != tuple0->iifidx &&
-+ hook->ops.dev->ifindex != tuple1->iifidx)
-+ continue;
-+
-+ hook->used = true;
-+ }
-+ spin_unlock_bh(&hooks_lock);
-+}
-+
-+static void
-+xt_flowoffload_hook_work(struct work_struct *work)
-+{
-+ struct xt_flowoffload_table *table;
-+ struct xt_flowoffload_hook *hook;
-+ int err;
-+
-+ table = container_of(work, struct xt_flowoffload_table, work.work);
-+
-+ spin_lock_bh(&hooks_lock);
-+ xt_flowoffload_register_hooks(table);
-+ hlist_for_each_entry(hook, &table->hooks, list)
-+ hook->used = false;
-+ spin_unlock_bh(&hooks_lock);
-+
-+ err = nf_flow_table_iterate(&table->ft, xt_flowoffload_check_hook,
-+ NULL);
-+ if (err && err != -EAGAIN)
-+ goto out;
-+
-+ if (!xt_flowoffload_cleanup_hooks(table))
-+ return;
-+
-+out:
-+ queue_delayed_work(system_power_efficient_wq, &table->work, HZ);
-+}
-+
-+static bool
-+xt_flowoffload_skip(struct sk_buff *skb, int family)
-+{
-+ if (skb_sec_path(skb))
-+ return true;
-+
-+ if (family == NFPROTO_IPV4) {
-+ const struct ip_options *opt = &(IPCB(skb)->opt);
-+
-+ if (unlikely(opt->optlen))
-+ return true;
-+ }
-+
-+ return false;
-+}
-+
-+static enum flow_offload_xmit_type nf_xmit_type(struct dst_entry *dst)
-+{
-+ if (dst_xfrm(dst))
-+ return FLOW_OFFLOAD_XMIT_XFRM;
-+
-+ return FLOW_OFFLOAD_XMIT_NEIGH;
-+}
-+
-+static void nf_default_forward_path(struct nf_flow_route *route,
-+ struct dst_entry *dst_cache,
-+ enum ip_conntrack_dir dir,
-+ struct net_device **dev)
-+{
-+ dev[!dir] = dst_cache->dev;
-+ route->tuple[!dir].in.ifindex = dst_cache->dev->ifindex;
-+ route->tuple[dir].dst = dst_cache;
-+ route->tuple[dir].xmit_type = nf_xmit_type(dst_cache);
-+}
-+
-+static bool nf_is_valid_ether_device(const struct net_device *dev)
-+{
-+ if (!dev || (dev->flags & IFF_LOOPBACK) || dev->type != ARPHRD_ETHER ||
-+ dev->addr_len != ETH_ALEN || !is_valid_ether_addr(dev->dev_addr))
-+ return false;
-+
-+ return true;
-+}
-+
-+static void nf_dev_path_info(const struct net_device_path_stack *stack,
-+ struct nf_forward_info *info,
-+ unsigned char *ha)
-+{
-+ const struct net_device_path *path;
-+ int i;
-+
-+ memcpy(info->h_dest, ha, ETH_ALEN);
-+
-+ for (i = 0; i < stack->num_paths; i++) {
-+ path = &stack->path[i];
-+ switch (path->type) {
-+ case DEV_PATH_ETHERNET:
-+ case DEV_PATH_DSA:
-+ case DEV_PATH_VLAN:
-+ case DEV_PATH_PPPOE:
-+ info->indev = path->dev;
-+ if (is_zero_ether_addr(info->h_source))
-+ memcpy(info->h_source, path->dev->dev_addr, ETH_ALEN);
-+
-+ if (path->type == DEV_PATH_ETHERNET)
-+ break;
-+ if (path->type == DEV_PATH_DSA) {
-+ i = stack->num_paths;
-+ break;
-+ }
-+
-+ /* DEV_PATH_VLAN and DEV_PATH_PPPOE */
-+ if (info->num_encaps >= NF_FLOW_TABLE_ENCAP_MAX) {
-+ info->indev = NULL;
-+ break;
-+ }
-+ if (!info->outdev)
-+ info->outdev = path->dev;
-+ info->encap[info->num_encaps].id = path->encap.id;
-+ info->encap[info->num_encaps].proto = path->encap.proto;
-+ info->num_encaps++;
-+ if (path->type == DEV_PATH_PPPOE)
-+ memcpy(info->h_dest, path->encap.h_dest, ETH_ALEN);
-+ break;
-+ case DEV_PATH_BRIDGE:
-+ if (is_zero_ether_addr(info->h_source))
-+ memcpy(info->h_source, path->dev->dev_addr, ETH_ALEN);
-+
-+ switch (path->bridge.vlan_mode) {
-+ case DEV_PATH_BR_VLAN_UNTAG_HW:
-+ info->ingress_vlans |= BIT(info->num_encaps - 1);
-+ break;
-+ case DEV_PATH_BR_VLAN_TAG:
-+ info->encap[info->num_encaps].id = path->bridge.vlan_id;
-+ info->encap[info->num_encaps].proto = path->bridge.vlan_proto;
-+ info->num_encaps++;
-+ break;
-+ case DEV_PATH_BR_VLAN_UNTAG:
-+ info->num_encaps--;
-+ break;
-+ case DEV_PATH_BR_VLAN_KEEP:
-+ break;
-+ }
-+ break;
-+ default:
-+ info->indev = NULL;
-+ break;
-+ }
-+ }
-+ if (!info->outdev)
-+ info->outdev = info->indev;
-+
-+ info->hw_outdev = info->indev;
-+
-+ if (nf_is_valid_ether_device(info->indev))
-+ info->xmit_type = FLOW_OFFLOAD_XMIT_DIRECT;
-+}
-+
-+static int nf_dev_fill_forward_path(const struct nf_flow_route *route,
-+ const struct dst_entry *dst_cache,
-+ const struct nf_conn *ct,
-+ enum ip_conntrack_dir dir, u8 *ha,
-+ struct net_device_path_stack *stack)
-+{
-+ const void *daddr = &ct->tuplehash[!dir].tuple.src.u3;
-+ struct net_device *dev = dst_cache->dev;
-+ struct neighbour *n;
-+ u8 nud_state;
-+
-+ if (!nf_is_valid_ether_device(dev))
-+ goto out;
-+
-+ n = dst_neigh_lookup(dst_cache, daddr);
-+ if (!n)
-+ return -1;
-+
-+ read_lock_bh(&n->lock);
-+ nud_state = n->nud_state;
-+ ether_addr_copy(ha, n->ha);
-+ read_unlock_bh(&n->lock);
-+ neigh_release(n);
-+
-+ if (!(nud_state & NUD_VALID))
-+ return -1;
-+
-+out:
-+ return dev_fill_forward_path(dev, ha, stack);
-+}
-+
-+static void nf_dev_forward_path(struct nf_flow_route *route,
-+ const struct nf_conn *ct,
-+ enum ip_conntrack_dir dir,
-+ struct net_device **devs)
-+{
-+ const struct dst_entry *dst = route->tuple[dir].dst;
-+ struct net_device_path_stack stack;
-+ struct nf_forward_info info = {};
-+ unsigned char ha[ETH_ALEN];
-+ int i;
-+
-+ if (nf_dev_fill_forward_path(route, dst, ct, dir, ha, &stack) >= 0)
-+ nf_dev_path_info(&stack, &info, ha);
-+
-+ devs[!dir] = (struct net_device *)info.indev;
-+ if (!info.indev)
-+ return;
-+
-+ route->tuple[!dir].in.ifindex = info.indev->ifindex;
-+ for (i = 0; i < info.num_encaps; i++) {
-+ route->tuple[!dir].in.encap[i].id = info.encap[i].id;
-+ route->tuple[!dir].in.encap[i].proto = info.encap[i].proto;
-+ }
-+ route->tuple[!dir].in.num_encaps = info.num_encaps;
-+ route->tuple[!dir].in.ingress_vlans = info.ingress_vlans;
-+
-+ if (info.xmit_type == FLOW_OFFLOAD_XMIT_DIRECT) {
-+ memcpy(route->tuple[dir].out.h_source, info.h_source, ETH_ALEN);
-+ memcpy(route->tuple[dir].out.h_dest, info.h_dest, ETH_ALEN);
-+ route->tuple[dir].out.ifindex = info.outdev->ifindex;
-+ route->tuple[dir].out.hw_ifindex = info.hw_outdev->ifindex;
-+ route->tuple[dir].xmit_type = info.xmit_type;
-+ }
-+}
-+
-+static int
-+xt_flowoffload_route(struct sk_buff *skb, const struct nf_conn *ct,
-+ const struct xt_action_param *par,
-+ struct nf_flow_route *route, enum ip_conntrack_dir dir,
-+ struct net_device **devs)
-+{
-+ struct dst_entry *this_dst = skb_dst(skb);
-+ struct dst_entry *other_dst = NULL;
-+ struct flowi fl;
-+
-+ memset(&fl, 0, sizeof(fl));
-+ switch (xt_family(par)) {
-+ case NFPROTO_IPV4:
-+ fl.u.ip4.daddr = ct->tuplehash[dir].tuple.src.u3.ip;
-+ fl.u.ip4.flowi4_oif = xt_in(par)->ifindex;
-+ break;
-+ case NFPROTO_IPV6:
-+ fl.u.ip6.saddr = ct->tuplehash[!dir].tuple.dst.u3.in6;
-+ fl.u.ip6.daddr = ct->tuplehash[dir].tuple.src.u3.in6;
-+ fl.u.ip6.flowi6_oif = xt_in(par)->ifindex;
-+ break;
-+ }
-+
-+ if (!dst_hold_safe(this_dst))
-+ return -ENOENT;
-+
-+ nf_route(xt_net(par), &other_dst, &fl, false, xt_family(par));
-+ if (!other_dst) {
-+ dst_release(this_dst);
-+ return -ENOENT;
-+ }
-+
-+ nf_default_forward_path(route, this_dst, dir, devs);
-+ nf_default_forward_path(route, other_dst, !dir, devs);
-+
-+ if (route->tuple[dir].xmit_type == FLOW_OFFLOAD_XMIT_NEIGH &&
-+ route->tuple[!dir].xmit_type == FLOW_OFFLOAD_XMIT_NEIGH) {
-+ nf_dev_forward_path(route, ct, dir, devs);
-+ nf_dev_forward_path(route, ct, !dir, devs);
-+ }
-+
-+ return 0;
-+}
-+
-+static unsigned int
-+flowoffload_tg(struct sk_buff *skb, const struct xt_action_param *par)
-+{
-+ struct xt_flowoffload_table *table;
-+ const struct xt_flowoffload_target_info *info = par->targinfo;
-+ struct tcphdr _tcph, *tcph = NULL;
-+ enum ip_conntrack_info ctinfo;
-+ enum ip_conntrack_dir dir;
-+ struct nf_flow_route route = {};
-+ struct flow_offload *flow = NULL;
-+ struct net_device *devs[2] = {};
-+ struct nf_conn *ct;
-+ struct net *net;
-+
-+ if (xt_flowoffload_skip(skb, xt_family(par)))
-+ return XT_CONTINUE;
-+
-+ ct = nf_ct_get(skb, &ctinfo);
-+ if (ct == NULL)
-+ return XT_CONTINUE;
-+
-+ switch (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum) {
-+ case IPPROTO_TCP:
-+ if (ct->proto.tcp.state != TCP_CONNTRACK_ESTABLISHED)
-+ return XT_CONTINUE;
-+
-+ tcph = skb_header_pointer(skb, par->thoff,
-+ sizeof(_tcph), &_tcph);
-+ if (unlikely(!tcph || tcph->fin || tcph->rst))
-+ return XT_CONTINUE;
-+ break;
-+ case IPPROTO_UDP:
-+ break;
-+ default:
-+ return XT_CONTINUE;
-+ }
-+
-+ if (nf_ct_ext_exist(ct, NF_CT_EXT_HELPER) ||
-+ ct->status & (IPS_SEQ_ADJUST | IPS_NAT_CLASH))
-+ return XT_CONTINUE;
-+
-+ if (!nf_ct_is_confirmed(ct))
-+ return XT_CONTINUE;
-+
-+ dir = CTINFO2DIR(ctinfo);
-+
-+ devs[dir] = xt_out(par);
-+ devs[!dir] = xt_in(par);
-+
-+ if (!devs[dir] || !devs[!dir])
-+ return XT_CONTINUE;
-+
-+ if (test_and_set_bit(IPS_OFFLOAD_BIT, &ct->status))
-+ return XT_CONTINUE;
-+
-+ if (xt_flowoffload_route(skb, ct, par, &route, dir, devs) < 0)
-+ goto err_flow_route;
-+
-+ flow = flow_offload_alloc(ct);
-+ if (!flow)
-+ goto err_flow_alloc;
-+
-+ flow_offload_route_init(flow, &route);
-+
-+ if (tcph) {
-+ ct->proto.tcp.seen[0].flags |= IP_CT_TCP_FLAG_BE_LIBERAL;
-+ ct->proto.tcp.seen[1].flags |= IP_CT_TCP_FLAG_BE_LIBERAL;
-+ }
-+
-+ table = &flowtable[!!(info->flags & XT_FLOWOFFLOAD_HW)];
-+
-+ net = read_pnet(&table->ft.net);
-+ if (!net)
-+ write_pnet(&table->ft.net, xt_net(par));
-+
-+ __set_bit(NF_FLOW_HW_BIDIRECTIONAL, &flow->flags);
-+ if (flow_offload_add(&table->ft, flow) < 0)
-+ goto err_flow_add;
-+
-+ xt_flowoffload_check_device(table, devs[0]);
-+ xt_flowoffload_check_device(table, devs[1]);
-+
-+ return XT_CONTINUE;
-+
-+err_flow_add:
-+ flow_offload_free(flow);
-+err_flow_alloc:
-+ dst_release(route.tuple[dir].dst);
-+ dst_release(route.tuple[!dir].dst);
-+err_flow_route:
-+ clear_bit(IPS_OFFLOAD_BIT, &ct->status);
-+
-+ return XT_CONTINUE;
-+}
-+
-+static int flowoffload_chk(const struct xt_tgchk_param *par)
-+{
-+ struct xt_flowoffload_target_info *info = par->targinfo;
-+
-+ if (info->flags & ~XT_FLOWOFFLOAD_MASK)
-+ return -EINVAL;
-+
-+ return 0;
-+}
-+
-+static struct xt_target offload_tg_reg __read_mostly = {
-+ .family = NFPROTO_UNSPEC,
-+ .name = "FLOWOFFLOAD",
-+ .revision = 0,
-+ .targetsize = sizeof(struct xt_flowoffload_target_info),
-+ .usersize = sizeof(struct xt_flowoffload_target_info),
-+ .checkentry = flowoffload_chk,
-+ .target = flowoffload_tg,
-+ .me = THIS_MODULE,
-+};
-+
-+static int flow_offload_netdev_event(struct notifier_block *this,
-+ unsigned long event, void *ptr)
-+{
-+ struct xt_flowoffload_hook *hook0, *hook1;
-+ struct net_device *dev = netdev_notifier_info_to_dev(ptr);
-+
-+ if (event != NETDEV_UNREGISTER)
-+ return NOTIFY_DONE;
-+
-+ spin_lock_bh(&hooks_lock);
-+ hook0 = flow_offload_lookup_hook(&flowtable[0], dev);
-+ if (hook0)
-+ hlist_del(&hook0->list);
-+
-+ hook1 = flow_offload_lookup_hook(&flowtable[1], dev);
-+ if (hook1)
-+ hlist_del(&hook1->list);
-+ spin_unlock_bh(&hooks_lock);
-+
-+ if (hook0) {
-+ nf_unregister_net_hook(hook0->net, &hook0->ops);
-+ kfree(hook0);
-+ }
-+
-+ if (hook1) {
-+ nf_unregister_net_hook(hook1->net, &hook1->ops);
-+ kfree(hook1);
-+ }
-+
-+ nf_flow_table_cleanup(dev);
-+
-+ return NOTIFY_DONE;
-+}
-+
-+static struct notifier_block flow_offload_netdev_notifier = {
-+ .notifier_call = flow_offload_netdev_event,
-+};
-+
-+static int nf_flow_rule_route_inet(struct net *net,
-+ struct flow_offload *flow,
-+ enum flow_offload_tuple_dir dir,
-+ struct nf_flow_rule *flow_rule)
-+{
-+ const struct flow_offload_tuple *flow_tuple = &flow->tuplehash[dir].tuple;
-+ int err;
-+
-+ switch (flow_tuple->l3proto) {
-+ case NFPROTO_IPV4:
-+ err = nf_flow_rule_route_ipv4(net, flow, dir, flow_rule);
-+ break;
-+ case NFPROTO_IPV6:
-+ err = nf_flow_rule_route_ipv6(net, flow, dir, flow_rule);
-+ break;
-+ default:
-+ err = -1;
-+ break;
-+ }
-+
-+ return err;
-+}
-+
-+static struct nf_flowtable_type flowtable_inet = {
-+ .family = NFPROTO_INET,
-+ .init = nf_flow_table_init,
-+ .setup = nf_flow_table_offload_setup,
-+ .action = nf_flow_rule_route_inet,
-+ .free = nf_flow_table_free,
-+ .hook = xt_flowoffload_net_hook,
-+ .owner = THIS_MODULE,
-+};
-+
-+static int init_flowtable(struct xt_flowoffload_table *tbl)
-+{
-+ INIT_DELAYED_WORK(&tbl->work, xt_flowoffload_hook_work);
-+ tbl->ft.type = &flowtable_inet;
-+ tbl->ft.flags = NF_FLOWTABLE_COUNTER;
-+
-+ return nf_flow_table_init(&tbl->ft);
-+}
-+
-+static int __init xt_flowoffload_tg_init(void)
-+{
-+ int ret;
-+
-+ register_netdevice_notifier(&flow_offload_netdev_notifier);
-+
-+ ret = init_flowtable(&flowtable[0]);
-+ if (ret)
-+ return ret;
-+
-+ ret = init_flowtable(&flowtable[1]);
-+ if (ret)
-+ goto cleanup;
-+
-+ flowtable[1].ft.flags |= NF_FLOWTABLE_HW_OFFLOAD;
-+
-+ ret = xt_register_target(&offload_tg_reg);
-+ if (ret)
-+ goto cleanup2;
-+
-+ return 0;
-+
-+cleanup2:
-+ nf_flow_table_free(&flowtable[1].ft);
-+cleanup:
-+ nf_flow_table_free(&flowtable[0].ft);
-+ return ret;
-+}
-+
-+static void __exit xt_flowoffload_tg_exit(void)
-+{
-+ xt_unregister_target(&offload_tg_reg);
-+ unregister_netdevice_notifier(&flow_offload_netdev_notifier);
-+ nf_flow_table_free(&flowtable[0].ft);
-+ nf_flow_table_free(&flowtable[1].ft);
-+}
-+
-+MODULE_LICENSE("GPL");
-+module_init(xt_flowoffload_tg_init);
-+module_exit(xt_flowoffload_tg_exit);
---- a/net/netfilter/nf_flow_table_core.c
-+++ b/net/netfilter/nf_flow_table_core.c
-@@ -7,7 +7,6 @@
- #include <linux/netdevice.h>
- #include <net/ip.h>
- #include <net/ip6_route.h>
--#include <net/netfilter/nf_tables.h>
- #include <net/netfilter/nf_flow_table.h>
- #include <net/netfilter/nf_conntrack.h>
- #include <net/netfilter/nf_conntrack_core.h>
-@@ -373,8 +372,7 @@ flow_offload_lookup(struct nf_flowtable
- }
- EXPORT_SYMBOL_GPL(flow_offload_lookup);
-
--static int
--nf_flow_table_iterate(struct nf_flowtable *flow_table,
-+int nf_flow_table_iterate(struct nf_flowtable *flow_table,
- void (*iter)(struct nf_flowtable *flowtable,
- struct flow_offload *flow, void *data),
- void *data)
-@@ -435,6 +433,7 @@ static void nf_flow_offload_gc_step(stru
- nf_flow_offload_stats(flow_table, flow);
- }
- }
-+EXPORT_SYMBOL_GPL(nf_flow_table_iterate);
-
- void nf_flow_table_gc_run(struct nf_flowtable *flow_table)
- {
---- /dev/null
-+++ b/include/uapi/linux/netfilter/xt_FLOWOFFLOAD.h
-@@ -0,0 +1,17 @@
-+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
-+#ifndef _XT_FLOWOFFLOAD_H
-+#define _XT_FLOWOFFLOAD_H
-+
-+#include <linux/types.h>
-+
-+enum {
-+ XT_FLOWOFFLOAD_HW = 1 << 0,
-+
-+ XT_FLOWOFFLOAD_MASK = XT_FLOWOFFLOAD_HW
-+};
-+
-+struct xt_flowoffload_target_info {
-+ __u32 flags;
-+};
-+
-+#endif /* _XT_FLOWOFFLOAD_H */
---- a/include/net/netfilter/nf_flow_table.h
-+++ b/include/net/netfilter/nf_flow_table.h
-@@ -293,6 +293,11 @@ void nf_flow_table_free(struct nf_flowta
-
- void flow_offload_teardown(struct flow_offload *flow);
-
-+int nf_flow_table_iterate(struct nf_flowtable *flow_table,
-+ void (*iter)(struct nf_flowtable *flowtable,
-+ struct flow_offload *flow, void *data),
-+ void *data);
-+
- void nf_flow_snat_port(const struct flow_offload *flow,
- struct sk_buff *skb, unsigned int thoff,
- u8 protocol, enum flow_offload_tuple_dir dir);
+++ /dev/null
-From 6d3bc769657b0ee7c7506dad9911111c4226a7ea Mon Sep 17 00:00:00 2001
-Date: Fri, 7 Jul 2017 17:21:05 +0200
-Subject: mac80211: increase wireless mesh header size
-
-lede-commit 3d4466cfd8f75f717efdb1f96fdde3c70d865fc1
----
- include/linux/netdevice.h | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
---- a/include/linux/netdevice.h
-+++ b/include/linux/netdevice.h
-@@ -157,8 +157,8 @@ static inline bool dev_xmit_complete(int
-
- #if defined(CONFIG_HYPERV_NET)
- # define LL_MAX_HEADER 128
--#elif defined(CONFIG_WLAN) || IS_ENABLED(CONFIG_AX25)
--# if defined(CONFIG_MAC80211_MESH)
-+#elif defined(CONFIG_WLAN) || IS_ENABLED(CONFIG_AX25) || 1
-+# if defined(CONFIG_MAC80211_MESH) || 1
- # define LL_MAX_HEADER 128
- # else
- # define LL_MAX_HEADER 96
+++ /dev/null
-From a6ccb238939b25851474a279b20367fd24a0e816 Mon Sep 17 00:00:00 2001
-Date: Fri, 7 Jul 2017 17:21:53 +0200
-Subject: hack: net: fq_codel: tune defaults for small devices
-
-Assume that x86_64 devices always have a big memory and do not need this
-optimization compared to devices with only 32 MB or 64 MB RAM.
-
----
- net/sched/sch_fq_codel.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/net/sched/sch_fq_codel.c
-+++ b/net/sched/sch_fq_codel.c
-@@ -463,7 +463,11 @@ static int fq_codel_init(struct Qdisc *s
-
- sch->limit = 10*1024;
- q->flows_cnt = 1024;
-+#ifdef CONFIG_X86_64
- q->memory_limit = 32 << 20; /* 32 MBytes */
-+#else
-+ q->memory_limit = 4 << 20; /* 4 MBytes */
-+#endif
- q->drop_batch_size = 64;
- q->quantum = psched_mtu(qdisc_dev(sch));
- INIT_LIST_HEAD(&q->new_flows);
+++ /dev/null
-From 804fbb3f2ec9283f7b778e057a68bfff440a0be6 Mon Sep 17 00:00:00 2001
-Date: Wed, 30 Mar 2022 22:51:55 +0100
-Subject: [PATCH] kernel: ct: size the hashtable more adequately
-
-To set the default size of the connection tracking hash table, a divider of
-16384 becomes inadequate for a router handling lots of connections. Divide by
-2048 instead, making the default size scale better with the available RAM.
-
----
- net/netfilter/nf_conntrack_core.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/net/netfilter/nf_conntrack_core.c
-+++ b/net/netfilter/nf_conntrack_core.c
-@@ -2699,7 +2699,7 @@ int nf_conntrack_init_start(void)
-
- if (!nf_conntrack_htable_size) {
- nf_conntrack_htable_size
-- = (((nr_pages << PAGE_SHIFT) / 16384)
-+ = (((nr_pages << PAGE_SHIFT) / 2048)
- / sizeof(struct hlist_head));
- if (BITS_PER_LONG >= 64 &&
- nr_pages > (4 * (1024 * 1024 * 1024 / PAGE_SIZE)))
+++ /dev/null
-From 36e516290611e613aa92996cb4339561452695b4 Mon Sep 17 00:00:00 2001
-Date: Fri, 7 Jul 2017 17:24:23 +0200
-Subject: net: swconfig: adds openwrt switch layer
-
----
- drivers/net/phy/Kconfig | 83 +++++++++++++++++++++++++++++++++++++++++++++++
- drivers/net/phy/Makefile | 15 +++++++++
- include/uapi/linux/Kbuild | 1 +
- 3 files changed, 99 insertions(+)
-
---- a/drivers/net/phy/Kconfig
-+++ b/drivers/net/phy/Kconfig
-@@ -66,6 +66,80 @@ config SFP
- depends on HWMON || HWMON=n
- select MDIO_I2C
-
-+comment "Switch configuration API + drivers"
-+
-+config SWCONFIG
-+ tristate "Switch configuration API"
-+ help
-+ Switch configuration API using netlink. This allows
-+ you to configure the VLAN features of certain switches.
-+
-+config SWCONFIG_LEDS
-+ bool "Switch LED trigger support"
-+ depends on (SWCONFIG && LEDS_TRIGGERS)
-+
-+config ADM6996_PHY
-+ tristate "Driver for ADM6996 switches"
-+ select SWCONFIG
-+ help
-+ Currently supports the ADM6996FC and ADM6996M switches.
-+ Support for FC is very limited.
-+
-+config AR8216_PHY
-+ tristate "Driver for Atheros AR8216/8327 switches"
-+ select SWCONFIG
-+ select ETHERNET_PACKET_MANGLE
-+
-+config AR8216_PHY_LEDS
-+ bool "Atheros AR8216 switch LED support"
-+ depends on (AR8216_PHY && LEDS_CLASS)
-+
-+source "drivers/net/phy/b53/Kconfig"
-+
-+config IP17XX_PHY
-+ tristate "Driver for IC+ IP17xx switches"
-+ select SWCONFIG
-+
-+config PSB6970_PHY
-+ tristate "Lantiq XWAY Tantos (PSB6970) Ethernet switch"
-+ select SWCONFIG
-+
-+config RTL8306_PHY
-+ tristate "Driver for Realtek RTL8306S switches"
-+ select SWCONFIG
-+
-+config RTL8366_SMI
-+ tristate "Driver for the RTL8366 SMI interface"
-+ depends on GPIOLIB
-+ help
-+ This module implements the SMI interface protocol which is used
-+ by some RTL8366 ethernet switch devices via the generic GPIO API.
-+
-+if RTL8366_SMI
-+
-+config RTL8366_SMI_DEBUG_FS
-+ bool "RTL8366 SMI interface debugfs support"
-+ depends on DEBUG_FS
-+ default n
-+
-+config RTL8366S_PHY
-+ tristate "Driver for the Realtek RTL8366S switch"
-+ select SWCONFIG
-+
-+config RTL8366RB_PHY
-+ tristate "Driver for the Realtek RTL8366RB switch"
-+ select SWCONFIG
-+
-+config RTL8367_PHY
-+ tristate "Driver for the Realtek RTL8367R/M switches"
-+ select SWCONFIG
-+
-+config RTL8367B_PHY
-+ tristate "Driver for the Realtek RTL8367R-VB switch"
-+ select SWCONFIG
-+
-+endif # RTL8366_SMI
-+
- comment "MII PHY device drivers"
-
- config AS21XXX_PHY
---- a/drivers/net/phy/Makefile
-+++ b/drivers/net/phy/Makefile
-@@ -26,6 +26,21 @@ libphy-$(CONFIG_LED_TRIGGER_PHY) += phy_
- obj-$(CONFIG_PHYLINK) += phylink.o
- obj-$(CONFIG_PHYLIB) += libphy.o
-
-+obj-$(CONFIG_SWCONFIG) += swconfig.o
-+obj-$(CONFIG_ADM6996_PHY) += adm6996.o
-+obj-$(CONFIG_AR8216_PHY) += ar8xxx.o
-+ar8xxx-y += ar8216.o
-+ar8xxx-y += ar8327.o
-+obj-$(CONFIG_SWCONFIG_B53) += b53/
-+obj-$(CONFIG_IP17XX_PHY) += ip17xx.o
-+obj-$(CONFIG_PSB6970_PHY) += psb6970.o
-+obj-$(CONFIG_RTL8306_PHY) += rtl8306.o
-+obj-$(CONFIG_RTL8366_SMI) += rtl8366_smi.o
-+obj-$(CONFIG_RTL8366S_PHY) += rtl8366s.o
-+obj-$(CONFIG_RTL8366RB_PHY) += rtl8366rb.o
-+obj-$(CONFIG_RTL8367_PHY) += rtl8367.o
-+obj-$(CONFIG_RTL8367B_PHY) += rtl8367b.o
-+
- obj-$(CONFIG_NETWORK_PHY_TIMESTAMPING) += mii_timestamper.o
-
- obj-$(CONFIG_SFP) += sfp.o
---- a/include/linux/platform_data/b53.h
-+++ b/include/linux/platform_data/b53.h
-@@ -29,6 +29,9 @@ struct b53_platform_data {
- u32 chip_id;
- u16 enabled_ports;
-
-+ /* allow to specify an ethX alias */
-+ const char *alias;
-+
- /* only used by MMAP'd driver */
- unsigned big_endian:1;
- void __iomem *regs;
+++ /dev/null
-From ebd924d773223593142d417c41d4ee6fa16f1805 Mon Sep 17 00:00:00 2001
-Date: Wed, 13 Jul 2022 13:45:56 +0200
-Subject: [PATCH] net/dsa/mv88e6xxx: disable ATU violation
-
----
- drivers/net/dsa/mv88e6xxx/chip.c | 3 +++
- 1 file changed, 3 insertions(+)
-
---- a/drivers/net/dsa/mv88e6xxx/chip.c
-+++ b/drivers/net/dsa/mv88e6xxx/chip.c
-@@ -3446,6 +3446,9 @@ static int mv88e6xxx_setup_port(struct m
- else
- reg = 1 << port;
-
-+ /* Disable ATU member violation interrupt */
-+ reg |= MV88E6XXX_PORT_ASSOC_VECTOR_IGNORE_WRONG;
-+
- err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_ASSOC_VECTOR,
- reg);
- if (err)
+++ /dev/null
-From ffe387740bbe88dd88bbe04d6375902708003d6e Mon Sep 17 00:00:00 2001
-Date: Fri, 7 Jul 2017 17:25:00 +0200
-Subject: net: add packet mangeling
-
-ar8216 switches have a hardware bug, which renders normal 802.1q support
-unusable. Packet mangling is required to fix up the vlan for incoming
-packets.
-
----
- include/linux/netdevice.h | 11 +++++++++++
- include/linux/skbuff.h | 14 ++++----------
- net/Kconfig | 6 ++++++
- net/core/dev.c | 20 +++++++++++++++-----
- net/core/skbuff.c | 17 +++++++++++++++++
- net/ethernet/eth.c | 6 ++++++
- 6 files changed, 59 insertions(+), 15 deletions(-)
-
---- a/include/linux/netdevice.h
-+++ b/include/linux/netdevice.h
-@@ -1758,6 +1758,7 @@ enum netdev_priv_flags {
- IFF_TX_SKB_NO_LINEAR = BIT_ULL(31),
- IFF_CHANGE_PROTO_DOWN = BIT_ULL(32),
- IFF_SEE_ALL_HWTSTAMP_REQUESTS = BIT_ULL(33),
-+ IFF_NO_IP_ALIGN = BIT_ULL(34),
- };
-
- #define IFF_802_1Q_VLAN IFF_802_1Q_VLAN
-@@ -1791,6 +1792,7 @@ enum netdev_priv_flags {
- #define IFF_FAILOVER_SLAVE IFF_FAILOVER_SLAVE
- #define IFF_L3MDEV_RX_HANDLER IFF_L3MDEV_RX_HANDLER
- #define IFF_TX_SKB_NO_LINEAR IFF_TX_SKB_NO_LINEAR
-+#define IFF_NO_IP_ALIGN IFF_NO_IP_ALIGN
-
- /* Specifies the type of the struct net_device::ml_priv pointer */
- enum netdev_ml_priv_type {
-@@ -2183,6 +2185,11 @@ struct net_device {
- const struct tlsdev_ops *tlsdev_ops;
- #endif
-
-+#ifdef CONFIG_ETHERNET_PACKET_MANGLE
-+ void (*eth_mangle_rx)(struct net_device *dev, struct sk_buff *skb);
-+ struct sk_buff *(*eth_mangle_tx)(struct net_device *dev, struct sk_buff *skb);
-+#endif
-+
- const struct header_ops *header_ops;
-
- unsigned char operstate;
-@@ -2256,6 +2263,10 @@ struct net_device {
- struct mctp_dev __rcu *mctp_ptr;
- #endif
-
-+#ifdef CONFIG_ETHERNET_PACKET_MANGLE
-+ void *phy_ptr; /* PHY device specific data */
-+#endif
-+
- /*
- * Cache lines mostly used on receive path (including eth_type_trans())
- */
---- a/include/linux/skbuff.h
-+++ b/include/linux/skbuff.h
-@@ -3121,6 +3121,10 @@ static inline int pskb_trim(struct sk_bu
- return (len < skb->len) ? __pskb_trim(skb, len) : 0;
- }
-
-+extern struct sk_buff *__netdev_alloc_skb_ip_align(struct net_device *dev,
-+ unsigned int length, gfp_t gfp);
-+
-+
- /**
- * pskb_trim_unique - remove end from a paged unique (not cloned) buffer
- * @skb: buffer to alter
-@@ -3286,16 +3290,6 @@ static inline struct sk_buff *dev_alloc_
- }
-
-
--static inline struct sk_buff *__netdev_alloc_skb_ip_align(struct net_device *dev,
-- unsigned int length, gfp_t gfp)
--{
-- struct sk_buff *skb = __netdev_alloc_skb(dev, length + NET_IP_ALIGN, gfp);
--
-- if (NET_IP_ALIGN && skb)
-- skb_reserve(skb, NET_IP_ALIGN);
-- return skb;
--}
--
- static inline struct sk_buff *netdev_alloc_skb_ip_align(struct net_device *dev,
- unsigned int length)
- {
---- a/net/Kconfig
-+++ b/net/Kconfig
-@@ -26,6 +26,12 @@ menuconfig NET
-
- if NET
-
-+config ETHERNET_PACKET_MANGLE
-+ bool
-+ help
-+ This option can be selected by phy drivers that need to mangle
-+ packets going in or out of an ethernet device.
-+
- config WANT_COMPAT_NETLINK_MESSAGES
- bool
- help
---- a/net/core/dev.c
-+++ b/net/core/dev.c
-@@ -3640,6 +3640,11 @@ static int xmit_one(struct sk_buff *skb,
- if (dev_nit_active(dev))
- dev_queue_xmit_nit(skb, dev);
-
-+#ifdef CONFIG_ETHERNET_PACKET_MANGLE
-+ if (dev->eth_mangle_tx && !(skb = dev->eth_mangle_tx(dev, skb)))
-+ return NETDEV_TX_OK;
-+#endif
-+
- len = skb->len;
- trace_net_dev_start_xmit(skb, dev);
- rc = netdev_start_xmit(skb, dev, txq, more);
---- a/net/core/skbuff.c
-+++ b/net/core/skbuff.c
-@@ -62,6 +62,7 @@
- #include <linux/if_vlan.h>
- #include <linux/mpls.h>
- #include <linux/kcov.h>
-+#include <linux/if.h>
-
- #include <net/protocol.h>
- #include <net/dst.h>
-@@ -848,6 +849,22 @@ skb_fail:
- }
- EXPORT_SYMBOL(__napi_alloc_skb);
-
-+struct sk_buff *__netdev_alloc_skb_ip_align(struct net_device *dev,
-+ unsigned int length, gfp_t gfp)
-+{
-+ struct sk_buff *skb = __netdev_alloc_skb(dev, length + NET_IP_ALIGN, gfp);
-+
-+#ifdef CONFIG_ETHERNET_PACKET_MANGLE
-+ if (dev && (dev->priv_flags & IFF_NO_IP_ALIGN))
-+ return skb;
-+#endif
-+
-+ if (NET_IP_ALIGN && skb)
-+ skb_reserve(skb, NET_IP_ALIGN);
-+ return skb;
-+}
-+EXPORT_SYMBOL(__netdev_alloc_skb_ip_align);
-+
- void skb_add_rx_frag(struct sk_buff *skb, int i, struct page *page, int off,
- int size, unsigned int truesize)
- {
---- a/net/ethernet/eth.c
-+++ b/net/ethernet/eth.c
-@@ -159,6 +159,12 @@ __be16 eth_type_trans(struct sk_buff *sk
- const struct ethhdr *eth;
-
- skb->dev = dev;
-+
-+#ifdef CONFIG_ETHERNET_PACKET_MANGLE
-+ if (dev->eth_mangle_rx)
-+ dev->eth_mangle_rx(dev, skb);
-+#endif
-+
- skb_reset_mac_header(skb);
-
- eth = (struct ethhdr *)skb->data;
+++ /dev/null
-From 5f62951fba63a9f9cfff564209426bdea5fcc371 Mon Sep 17 00:00:00 2001
-Date: Tue, 27 Aug 2019 15:16:56 +0300
-Subject: [PATCH] drivers: net: phy: aquantia: enable AQR112 and AQR412
-
-Adds support for AQR112 and AQR412 which is mostly based on existing code
-with the addition of code configuring the protocol on system side.
-This allows changing the system side protocol without having to deploy a
-different firmware on the PHY.
-
----
- drivers/net/phy/aquantia/aquantia_main.c | 88 +++++++++++++++++++++++++++++++++++++++++
- 1 file changed, 88 insertions(+)
-
---- a/drivers/net/phy/aquantia/aquantia_main.c
-+++ b/drivers/net/phy/aquantia/aquantia_main.c
-@@ -96,6 +96,29 @@
- #define AQR107_OP_IN_PROG_SLEEP 1000
- #define AQR107_OP_IN_PROG_TIMEOUT 100000
-
-+/* registers in MDIO_MMD_VEND1 region */
-+#define AQUANTIA_VND1_GLOBAL_SC 0x000
-+#define AQUANTIA_VND1_GLOBAL_SC_LP BIT(0xb)
-+
-+/* global start rate, the protocol associated with this speed is used by default
-+ * on SI.
-+ */
-+#define AQUANTIA_VND1_GSTART_RATE 0x31a
-+#define AQUANTIA_VND1_GSTART_RATE_OFF 0
-+#define AQUANTIA_VND1_GSTART_RATE_100M 1
-+#define AQUANTIA_VND1_GSTART_RATE_1G 2
-+#define AQUANTIA_VND1_GSTART_RATE_10G 3
-+#define AQUANTIA_VND1_GSTART_RATE_2_5G 4
-+#define AQUANTIA_VND1_GSTART_RATE_5G 5
-+
-+/* SYSCFG registers for 100M, 1G, 2.5G, 5G, 10G */
-+#define AQUANTIA_VND1_GSYSCFG_BASE 0x31b
-+#define AQUANTIA_VND1_GSYSCFG_100M 0
-+#define AQUANTIA_VND1_GSYSCFG_1G 1
-+#define AQUANTIA_VND1_GSYSCFG_2_5G 2
-+#define AQUANTIA_VND1_GSYSCFG_5G 3
-+#define AQUANTIA_VND1_GSYSCFG_10G 4
-+
- static int aqr107_get_sset_count(struct phy_device *phydev)
- {
- return AQR107_SGMII_STAT_SZ;
-@@ -202,6 +225,51 @@ static int aqr_config_aneg(struct phy_de
- return genphy_c45_check_and_restart_aneg(phydev, changed);
- }
-
-+static struct {
-+ u16 syscfg;
-+ int cnt;
-+ u16 start_rate;
-+} aquantia_syscfg[PHY_INTERFACE_MODE_MAX] = {
-+ [PHY_INTERFACE_MODE_SGMII] = {0x04b, AQUANTIA_VND1_GSYSCFG_1G,
-+ AQUANTIA_VND1_GSTART_RATE_1G},
-+ [PHY_INTERFACE_MODE_2500BASEX] = {0x144, AQUANTIA_VND1_GSYSCFG_2_5G,
-+ AQUANTIA_VND1_GSTART_RATE_2_5G},
-+ [PHY_INTERFACE_MODE_XGMII] = {0x100, AQUANTIA_VND1_GSYSCFG_10G,
-+ AQUANTIA_VND1_GSTART_RATE_10G},
-+ [PHY_INTERFACE_MODE_USXGMII] = {0x080, AQUANTIA_VND1_GSYSCFG_10G,
-+ AQUANTIA_VND1_GSTART_RATE_10G},
-+};
-+
-+/* Sets up protocol on system side before calling aqr_config_aneg */
-+static int aqr_config_aneg_set_prot(struct phy_device *phydev)
-+{
-+ int if_type = phydev->interface;
-+ int i;
-+
-+ if (!aquantia_syscfg[if_type].cnt)
-+ return 0;
-+
-+ /* set PHY in low power mode so we can configure protocols */
-+ phy_write_mmd(phydev, MDIO_MMD_VEND1, AQUANTIA_VND1_GLOBAL_SC,
-+ AQUANTIA_VND1_GLOBAL_SC_LP);
-+ mdelay(10);
-+
-+ /* set the default rate to enable the SI link */
-+ phy_write_mmd(phydev, MDIO_MMD_VEND1, AQUANTIA_VND1_GSTART_RATE,
-+ aquantia_syscfg[if_type].start_rate);
-+
-+ for (i = 0; i <= aquantia_syscfg[if_type].cnt; i++)
-+ phy_write_mmd(phydev, MDIO_MMD_VEND1,
-+ AQUANTIA_VND1_GSYSCFG_BASE + i,
-+ aquantia_syscfg[if_type].syscfg);
-+
-+ /* wake PHY back up */
-+ phy_write_mmd(phydev, MDIO_MMD_VEND1, AQUANTIA_VND1_GLOBAL_SC, 0);
-+ mdelay(10);
-+
-+ return aqr_config_aneg(phydev);
-+}
-+
- static int aqr_config_intr(struct phy_device *phydev)
- {
- bool en = phydev->interrupts == PHY_INTERRUPT_ENABLED;
-@@ -854,7 +922,7 @@ static struct phy_driver aqr_driver[] =
- PHY_ID_MATCH_MODEL(PHY_ID_AQR112),
- .name = "Aquantia AQR112",
- .probe = aqr107_probe,
-- .config_aneg = aqr_config_aneg,
-+ .config_aneg = aqr_config_aneg_set_prot,
- .config_intr = aqr_config_intr,
- .handle_interrupt = aqr_handle_interrupt,
- .get_tunable = aqr107_get_tunable,
-@@ -877,7 +945,7 @@ static struct phy_driver aqr_driver[] =
- PHY_ID_MATCH_MODEL(PHY_ID_AQR412),
- .name = "Aquantia AQR412",
- .probe = aqr107_probe,
-- .config_aneg = aqr_config_aneg,
-+ .config_aneg = aqr_config_aneg_set_prot,
- .config_intr = aqr_config_intr,
- .handle_interrupt = aqr_handle_interrupt,
- .get_tunable = aqr107_get_tunable,
+++ /dev/null
-From 5f008cb22f60da4e10375f22266c1a4e20b1252e Mon Sep 17 00:00:00 2001
-Date: Fri, 20 Sep 2019 18:22:52 +0300
-Subject: [PATCH] drivers: net: phy: aquantia: fix system side protocol
- misconfiguration
-
-Do not set up protocols for speeds that are not supported by FW. Enabling
-these protocols leads to link issues on system side.
-
----
- drivers/net/phy/aquantia/aquantia_main.c | 8 +++++++-
- 1 file changed, 7 insertions(+), 1 deletion(-)
-
---- a/drivers/net/phy/aquantia/aquantia_main.c
-+++ b/drivers/net/phy/aquantia/aquantia_main.c
-@@ -258,10 +258,16 @@ static int aqr_config_aneg_set_prot(stru
- phy_write_mmd(phydev, MDIO_MMD_VEND1, AQUANTIA_VND1_GSTART_RATE,
- aquantia_syscfg[if_type].start_rate);
-
-- for (i = 0; i <= aquantia_syscfg[if_type].cnt; i++)
-+ for (i = 0; i <= aquantia_syscfg[if_type].cnt; i++) {
-+ u16 reg = phy_read_mmd(phydev, MDIO_MMD_VEND1,
-+ AQUANTIA_VND1_GSYSCFG_BASE + i);
-+ if (!reg)
-+ continue;
-+
- phy_write_mmd(phydev, MDIO_MMD_VEND1,
- AQUANTIA_VND1_GSYSCFG_BASE + i,
- aquantia_syscfg[if_type].syscfg);
-+ }
-
- /* wake PHY back up */
- phy_write_mmd(phydev, MDIO_MMD_VEND1, AQUANTIA_VND1_GLOBAL_SC, 0);
+++ /dev/null
-From 3b92ee7b7899b6beffb2b484c58326e36612a873 Mon Sep 17 00:00:00 2001
-Date: Thu, 23 Dec 2021 14:52:56 +0000
-Subject: [PATCH] net: phy: aquantia: add PHY_ID for AQR112R
-
-As advised by Ian Chang this PHY is used in Puzzle devices.
-
----
- drivers/net/phy/aquantia/aquantia_main.c | 10 ++++++++++
- 1 file changed, 10 insertions(+)
-
---- a/drivers/net/phy/aquantia/aquantia_main.c
-+++ b/drivers/net/phy/aquantia/aquantia_main.c
-@@ -31,6 +31,8 @@
- #define PHY_ID_AQR113C 0x31c31c12
- #define PHY_ID_AQR114C 0x31c31c22
- #define PHY_ID_AQR813 0x31c31cb2
-+#define PHY_ID_AQR112C 0x03a1b790
-+#define PHY_ID_AQR112R 0x31c31d12
-
- #define MDIO_PHYXS_VEND_IF_STATUS 0xe812
- #define MDIO_PHYXS_VEND_IF_STATUS_TYPE_MASK GENMASK(7, 3)
-@@ -1061,6 +1063,30 @@ static struct phy_driver aqr_driver[] =
- .led_hw_control_get = aqr_phy_led_hw_control_get,
- .led_polarity_set = aqr_phy_led_polarity_set,
- },
-+{
-+ PHY_ID_MATCH_MODEL(PHY_ID_AQR112C),
-+ .name = "Aquantia AQR112C",
-+ .probe = aqr107_probe,
-+ .config_aneg = aqr_config_aneg_set_prot,
-+ .config_intr = aqr_config_intr,
-+ .handle_interrupt = aqr_handle_interrupt,
-+ .read_status = aqr107_read_status,
-+ .get_sset_count = aqr107_get_sset_count,
-+ .get_strings = aqr107_get_strings,
-+ .get_stats = aqr107_get_stats,
-+},
-+{
-+ PHY_ID_MATCH_MODEL(PHY_ID_AQR112R),
-+ .name = "Aquantia AQR112R",
-+ .probe = aqr107_probe,
-+ .config_aneg = aqr_config_aneg_set_prot,
-+ .config_intr = aqr_config_intr,
-+ .handle_interrupt = aqr_handle_interrupt,
-+ .read_status = aqr107_read_status,
-+ .get_sset_count = aqr107_get_sset_count,
-+ .get_strings = aqr107_get_strings,
-+ .get_stats = aqr107_get_stats,
-+},
- };
-
- module_phy_driver(aqr_driver);
-@@ -1081,6 +1107,8 @@ static struct mdio_device_id __maybe_unu
- { PHY_ID_MATCH_MODEL(PHY_ID_AQR113C) },
- { PHY_ID_MATCH_MODEL(PHY_ID_AQR114C) },
- { PHY_ID_MATCH_MODEL(PHY_ID_AQR813) },
-+ { PHY_ID_MATCH_MODEL(PHY_ID_AQR112C) },
-+ { PHY_ID_MATCH_MODEL(PHY_ID_AQR112R) },
- { }
- };
-
+++ /dev/null
-From bc51c337a3147c4a02c743489885a6657bc5371c Mon Sep 17 00:00:00 2001
-Date: Wed, 27 Nov 2024 13:36:49 +0800
-Subject: [PATCH] net: ethernet: mtk_eth_soc: add hw dump for forced reset
-
-Without this patch, the ETH driver is unable to dump the registers
-before triggering a forced reset.
-
----
- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 55 +++++++++++++++++++++
- 1 files changed, 55 insertions(+)
-
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -71,6 +71,7 @@ static const struct mtk_reg_map mtk_reg_
- .rx_ptr = 0x1900,
- .rx_cnt_cfg = 0x1904,
- .qcrx_ptr = 0x1908,
-+ .page = 0x19f0,
- .glo_cfg = 0x1a04,
- .rst_idx = 0x1a08,
- .delay_irq = 0x1a0c,
-@@ -137,6 +138,7 @@ static const struct mtk_reg_map mt7986_r
- .rx_ptr = 0x4500,
- .rx_cnt_cfg = 0x4504,
- .qcrx_ptr = 0x4508,
-+ .page = 0x45f0,
- .glo_cfg = 0x4604,
- .rst_idx = 0x4608,
- .delay_irq = 0x460c,
-@@ -188,6 +190,7 @@ static const struct mtk_reg_map mt7988_r
- .rx_ptr = 0x4500,
- .rx_cnt_cfg = 0x4504,
- .qcrx_ptr = 0x4508,
-+ .page = 0x45f0,
- .glo_cfg = 0x4604,
- .rst_idx = 0x4608,
- .delay_irq = 0x460c,
-@@ -3935,6 +3938,56 @@ static void mtk_set_mcr_max_rx(struct mt
- mtk_w32(mac->hw, mcr_new, MTK_MAC_MCR(mac->id));
- }
-
-+static void mtk_hw_dump_reg(struct mtk_eth *eth, char *name, u32 offset, u32 range)
-+{
-+ u32 cur = offset;
-+
-+ pr_info("\n==================== %s ====================\n", name);
-+ while (cur < offset + range) {
-+ pr_info("0x%08x: %08x %08x %08x %08x\n",
-+ cur, mtk_r32(eth, cur), mtk_r32(eth, cur + 0x4),
-+ mtk_r32(eth, cur + 0x8), mtk_r32(eth, cur + 0xc));
-+ cur += 0x10;
-+ }
-+}
-+
-+static void mtk_hw_dump(struct mtk_eth *eth)
-+{
-+ const struct mtk_reg_map *reg_map = eth->soc->reg_map;
-+ u32 id;
-+
-+ mtk_hw_dump_reg(eth, "FE", 0x0, 0x600);
-+ mtk_hw_dump_reg(eth, "FE", 0x1400, 0x300);
-+ mtk_hw_dump_reg(eth, "ADMA", reg_map->pdma.rx_ptr, 0x300);
-+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) {
-+ for (id = 0; id < MTK_QDMA_NUM_QUEUES / 16; id++) {
-+ mtk_w32(eth, id, reg_map->qdma.page);
-+ pr_info("\nQDMA PAGE:%x ", mtk_r32(eth, reg_map->qdma.page));
-+ mtk_hw_dump_reg(eth, "QDMA", reg_map->qdma.qtx_cfg, 0x100);
-+ mtk_w32(eth, 0, reg_map->qdma.page);
-+ }
-+ mtk_hw_dump_reg(eth, "QDMA", reg_map->qdma.rx_ptr, 0x300);
-+ }
-+ if (!MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628)) {
-+ mtk_hw_dump_reg(eth, "WDMA0", reg_map->wdma_base[0], 0x400);
-+ mtk_hw_dump_reg(eth, "WDMA1", reg_map->wdma_base[1], 0x400);
-+ if (mtk_is_netsys_v3_or_greater(eth))
-+ mtk_hw_dump_reg(eth, "WDMA2", reg_map->wdma_base[2], 0x400);
-+ }
-+ mtk_hw_dump_reg(eth, "PPE0", reg_map->ppe_base + 0x200, 0x200);
-+ if (!mtk_is_netsys_v1(eth))
-+ mtk_hw_dump_reg(eth, "PPE1", reg_map->ppe_base + 0x600, 0x200);
-+ if (mtk_is_netsys_v3_or_greater(eth))
-+ mtk_hw_dump_reg(eth, "PPE2", reg_map->ppe_base + 0xE00, 0x200);
-+ mtk_hw_dump_reg(eth, "GMAC", 0x10000, 0x300);
-+ if (mtk_is_netsys_v3_or_greater(eth))
-+ mtk_hw_dump_reg(eth, "GMAC", 0x10300, 0x100);
-+ if (mtk_is_netsys_v3_or_greater(eth)) {
-+ mtk_hw_dump_reg(eth, "XGMAC0", 0x12000, 0x300);
-+ mtk_hw_dump_reg(eth, "XGMAC1", 0x13000, 0x300);
-+ }
-+}
-+
- static void mtk_hw_reset(struct mtk_eth *eth)
- {
- u32 val;
-@@ -4410,6 +4463,8 @@ static void mtk_pending_work(struct work
- rtnl_lock();
- set_bit(MTK_RESETTING, ð->state);
-
-+ mtk_hw_dump(eth);
-+
- mtk_prepare_for_reset(eth);
- mtk_wed_fe_reset();
- /* Run again reset preliminary configuration in order to avoid any
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-@@ -1185,6 +1185,7 @@ struct mtk_reg_map {
- u32 rx_ptr; /* rx base pointer */
- u32 rx_cnt_cfg; /* rx max count configuration */
- u32 qcrx_ptr; /* rx cpu pointer */
-+ u32 page; /* page configuration */
- u32 glo_cfg; /* global configuration */
- u32 rst_idx; /* reset index */
- u32 delay_irq; /* delay interrupt */
+++ /dev/null
---- a/drivers/net/phy/Kconfig
-+++ b/drivers/net/phy/Kconfig
-@@ -403,6 +403,8 @@ config QSEMI_PHY
-
- source "drivers/net/phy/realtek/Kconfig"
-
-+source "drivers/net/phy/rtl8261n/Kconfig"
-+
- config RENESAS_PHY
- tristate "Renesas PHYs"
- help
---- a/drivers/net/phy/Makefile
-+++ b/drivers/net/phy/Makefile
-@@ -100,6 +100,7 @@ obj-$(CONFIG_NXP_TJA11XX_PHY) += nxp-tja
- obj-y += qcom/
- obj-$(CONFIG_QSEMI_PHY) += qsemi.o
- obj-$(CONFIG_REALTEK_PHY) += realtek/
-+obj-y += rtl8261n/
- obj-$(CONFIG_RENESAS_PHY) += uPD60620.o
- obj-$(CONFIG_ROCKCHIP_PHY) += rockchip.o
- obj-$(CONFIG_SMSC_PHY) += smsc.o
+++ /dev/null
-From 880d1311335120f64447ca9d11933872d734e19a Mon Sep 17 00:00:00 2001
-Date: Mon, 27 Mar 2023 18:41:54 +0100
-Subject: [PATCH] generic: pcs-mtk-lynxi: add hack to use 2500Base-X without AN
-
-Using 2500Base-T SFP modules e.g. on the BananaPi R3 requires manually
-disabling auto-negotiation, e.g. using ethtool. While a proper fix
-using SFP quirks is being discussed upstream, bring a work-around to
-restore user experience to what it was before the switch to the
-dedicated SGMII PCS driver.
-
-
---- a/drivers/net/pcs/pcs-mtk-lynxi.c
-+++ b/drivers/net/pcs/pcs-mtk-lynxi.c
-@@ -129,14 +129,23 @@ static void mtk_pcs_lynxi_get_state(stru
- struct phylink_link_state *state)
- {
- struct mtk_pcs_lynxi *mpcs = pcs_to_mtk_pcs_lynxi(pcs);
-- unsigned int bm, adv;
-+ unsigned int bm, bmsr, adv;
-
- /* Read the BMSR and LPA */
- regmap_read(mpcs->regmap, SGMSYS_PCS_CONTROL_1, &bm);
-- regmap_read(mpcs->regmap, SGMSYS_PCS_ADVERTISE, &adv);
-+ bmsr = FIELD_GET(SGMII_BMSR, bm);
-+
-+ if (state->interface == PHY_INTERFACE_MODE_2500BASEX) {
-+ state->link = !!(bmsr & BMSR_LSTATUS);
-+ state->an_complete = !!(bmsr & BMSR_ANEGCOMPLETE);
-+ state->speed = SPEED_2500;
-+ state->duplex = DUPLEX_FULL;
-+
-+ return;
-+ }
-
-- phylink_mii_c22_pcs_decode_state(state, FIELD_GET(SGMII_BMSR, bm),
-- FIELD_GET(SGMII_LPA, adv));
-+ regmap_read(mpcs->regmap, SGMSYS_PCS_ADVERTISE, &adv);
-+ phylink_mii_c22_pcs_decode_state(state, bmsr, FIELD_GET(SGMII_LPA, adv));
- }
-
- static void mtk_sgmii_reset(struct mtk_pcs_lynxi *mpcs)
-@@ -157,7 +166,7 @@ static int mtk_pcs_lynxi_config(struct p
- {
- struct mtk_pcs_lynxi *mpcs = pcs_to_mtk_pcs_lynxi(pcs);
- bool mode_changed = false, changed;
-- unsigned int rgc3, sgm_mode, bmcr;
-+ unsigned int rgc3, sgm_mode, bmcr = 0;
- int advertise, link_timer;
-
- advertise = phylink_mii_c22_pcs_encode_advertisement(interface,
-@@ -180,9 +189,8 @@ static int mtk_pcs_lynxi_config(struct p
- if (neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED) {
- if (interface == PHY_INTERFACE_MODE_SGMII)
- sgm_mode |= SGMII_SPEED_DUPLEX_AN;
-- bmcr = BMCR_ANENABLE;
-- } else {
-- bmcr = 0;
-+ if (interface != PHY_INTERFACE_MODE_2500BASEX)
-+ bmcr = BMCR_ANENABLE;
- }
-
- if (mpcs->interface != interface) {
+++ /dev/null
-From 82985725e071f2a5735052f18e109a32aeac3a0b Mon Sep 17 00:00:00 2001
-Date: Sun, 26 Jul 2020 02:38:31 +0200
-Subject: [PATCH] net: usb: r8152: add LED configuration from OF
-
-This adds the ability to configure the LED configuration register using
-OF. This way, the correct value for board specific LED configuration can
-be determined.
-
----
- drivers/net/usb/r8152.c | 23 +++++++++++++++++++++++
- 1 file changed, 23 insertions(+)
-
---- a/drivers/net/usb/r8152.c
-+++ b/drivers/net/usb/r8152.c
-@@ -11,6 +11,7 @@
- #include <linux/mii.h>
- #include <linux/ethtool.h>
- #include <linux/usb.h>
-+#include <linux/of.h>
- #include <linux/crc32.h>
- #include <linux/if_vlan.h>
- #include <linux/uaccess.h>
-@@ -7045,6 +7046,22 @@ static void rtl_tally_reset(struct r8152
- ocp_write_word(tp, MCU_TYPE_PLA, PLA_RSTTALLY, ocp_data);
- }
-
-+static int r8152_led_configuration(struct r8152 *tp)
-+{
-+ u32 led_data;
-+ int ret;
-+
-+ ret = of_property_read_u32(tp->udev->dev.of_node, "realtek,led-data",
-+ &led_data);
-+
-+ if (ret)
-+ return ret;
-+
-+ ocp_write_word(tp, MCU_TYPE_PLA, PLA_LEDSEL, led_data);
-+
-+ return 0;
-+}
-+
- static void r8152b_init(struct r8152 *tp)
- {
- u32 ocp_data;
-@@ -7086,6 +7103,8 @@ static void r8152b_init(struct r8152 *tp
- ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_USB_CTRL);
- ocp_data &= ~(RX_AGG_DISABLE | RX_ZERO_EN);
- ocp_write_word(tp, MCU_TYPE_USB, USB_USB_CTRL, ocp_data);
-+
-+ r8152_led_configuration(tp);
- }
-
- static void r8153_init(struct r8152 *tp)
-@@ -7226,6 +7245,8 @@ static void r8153_init(struct r8152 *tp)
- tp->coalesce = COALESCE_SLOW;
- break;
- }
-+
-+ r8152_led_configuration(tp);
- }
-
- static void r8153b_init(struct r8152 *tp)
-@@ -7308,6 +7329,8 @@ static void r8153b_init(struct r8152 *tp
- rtl_tally_reset(tp);
-
- tp->coalesce = 15000; /* 15 us */
-+
-+ r8152_led_configuration(tp);
- }
-
- static void r8153c_init(struct r8152 *tp)
+++ /dev/null
-From 3ee05f4aa64fc86af3be5bc176ba5808de9260a7 Mon Sep 17 00:00:00 2001
-Date: Sun, 26 Jul 2020 15:30:33 +0200
-Subject: [PATCH] dt-bindings: net: add RTL8152 binding documentation
-
-Add binding documentation for the Realtek RTL8152 / RTL8153 USB ethernet
-adapters.
-
----
- .../bindings/net/realtek,rtl8152.yaml | 36 +++++++++++++++++++
- 1 file changed, 36 insertions(+)
- create mode 100644 Documentation/devicetree/bindings/net/realtek,rtl8152.yaml
-
---- /dev/null
-+++ b/Documentation/devicetree/bindings/net/realtek,rtl8152.yaml
-@@ -0,0 +1,36 @@
-+# SPDX-License-Identifier: GPL-2.0
-+%YAML 1.2
-+---
-+$id: http://devicetree.org/schemas/net/realtek,rtl8152.yaml#
-+$schema: http://devicetree.org/meta-schemas/core.yaml#
-+
-+title: Realtek RTL8152/RTL8153 series USB ethernet
-+
-+maintainers:
-+
-+properties:
-+ compatible:
-+ oneOf:
-+ - items:
-+ - enum:
-+ - realtek,rtl8152
-+ - realtek,rtl8153
-+
-+ reg:
-+ description: The device number on the USB bus
-+
-+ realtek,led-data:
-+ description: Value to be written to the LED configuration register.
-+
-+required:
-+ - compatible
-+ - reg
-+
-+examples:
-+ - |
-+ usb-eth@2 {
-+ compatible = "realtek,rtl8153";
-+ reg = <2>;
-+ realtek,led-data = <0x87>;
-+ };
-\ No newline at end of file
+++ /dev/null
-From cc225d163b5a4f7a0d1968298bf7927306646a47 Mon Sep 17 00:00:00 2001
-Date: Fri, 28 Apr 2023 01:53:01 +0200
-Subject: [PATCH] net: phy: mediatek-ge: add LED configuration interface
-
-This adds a small hack similar to the one used for ar8xxx switches to
-read a reg:value map for configuring the LED configuration registers.
-
-This allows OpenWrt to write device-specific LED action as well as blink
-configurations. It is unlikely to be accepted upstream, as upstream
-plans on integrating their own framework for handling these LEDs.
-
----
- drivers/net/phy/mediatek/mtk-ge.c | 33 +++++++++++++++++++++++++++++++++
- 1 file changed, 33 insertions(+)
-
---- a/drivers/net/phy/mediatek/mtk-ge.c
-+++ b/drivers/net/phy/mediatek/mtk-ge.c
-@@ -1,4 +1,5 @@
- // SPDX-License-Identifier: GPL-2.0+
-+#include <linux/of.h>
- #include <linux/bitfield.h>
- #include <linux/module.h>
- #include <linux/phy.h>
-@@ -76,6 +77,36 @@ static int mt7530_phy_config_init(struct
- return 0;
- }
-
-+static int mt7530_led_config_of(struct phy_device *phydev)
-+{
-+ struct device_node *np = phydev->mdio.dev.of_node;
-+ const __be32 *paddr;
-+ int len;
-+ int i;
-+
-+ paddr = of_get_property(np, "mediatek,led-config", &len);
-+ if (!paddr)
-+ return 0;
-+
-+ if (len < (2 * sizeof(*paddr)))
-+ return -EINVAL;
-+
-+ len /= sizeof(*paddr);
-+
-+ phydev_warn(phydev, "Configure LED registers (num=%d)\n", len);
-+ for (i = 0; i < len - 1; i += 2) {
-+ u32 reg;
-+ u32 val;
-+
-+ reg = be32_to_cpup(paddr + i);
-+ val = be32_to_cpup(paddr + i + 1);
-+
-+ phy_write_mmd(phydev, MDIO_MMD_VEND2, reg, val);
-+ }
-+
-+ return 0;
-+}
-+
- static int mt7531_phy_config_init(struct phy_device *phydev)
- {
- mtk_gephy_config_init(phydev);
-@@ -96,6 +127,9 @@ static int mt7531_phy_config_init(struct
- FIELD_PREP(MTK_TX_DELAY_PAIR_B_MASK, 0x4) |
- FIELD_PREP(MTK_TX_DELAY_PAIR_D_MASK, 0x4));
-
-+ /* LED Config*/
-+ mt7530_led_config_of(phydev);
-+
- return 0;
- }
-
+++ /dev/null
-From 3cb240533ab787899dc7f17aa7d6c5b4810e2e58 Mon Sep 17 00:00:00 2001
-Date: Fri, 7 Jul 2017 17:26:01 +0200
-Subject: bcm53xx: bgmac: use srab switch driver
-
-use the srab switch driver on these SoCs.
-
----
- drivers/net/ethernet/broadcom/bgmac-bcma.c | 1 +
- drivers/net/ethernet/broadcom/bgmac.c | 24 ++++++++++++++++++++++++
- drivers/net/ethernet/broadcom/bgmac.h | 4 ++++
- 3 files changed, 29 insertions(+)
-
---- a/drivers/net/ethernet/broadcom/bgmac-bcma.c
-+++ b/drivers/net/ethernet/broadcom/bgmac-bcma.c
-@@ -280,6 +280,7 @@ static int bgmac_probe(struct bcma_devic
- bgmac->feature_flags |= BGMAC_FEAT_CLKCTLST;
- bgmac->feature_flags |= BGMAC_FEAT_NO_RESET;
- bgmac->feature_flags |= BGMAC_FEAT_FORCE_SPEED_2500;
-+ bgmac->feature_flags |= BGMAC_FEAT_SRAB;
- break;
- default:
- bgmac->feature_flags |= BGMAC_FEAT_CLKCTLST;
---- a/drivers/net/ethernet/broadcom/bgmac.c
-+++ b/drivers/net/ethernet/broadcom/bgmac.c
-@@ -12,6 +12,7 @@
- #include <linux/bcma/bcma.h>
- #include <linux/etherdevice.h>
- #include <linux/interrupt.h>
-+#include <linux/platform_data/b53.h>
- #include <linux/bcm47xx_nvram.h>
- #include <linux/phy.h>
- #include <linux/phy_fixed.h>
-@@ -1408,6 +1409,17 @@ static const struct ethtool_ops bgmac_et
- .set_link_ksettings = phy_ethtool_set_link_ksettings,
- };
-
-+static struct b53_platform_data bgmac_b53_pdata = {
-+};
-+
-+static struct platform_device bgmac_b53_dev = {
-+ .name = "b53-srab-switch",
-+ .id = -1,
-+ .dev = {
-+ .platform_data = &bgmac_b53_pdata,
-+ },
-+};
-+
- /**************************************************
- * MII
- **************************************************/
-@@ -1546,6 +1558,14 @@ int bgmac_enet_probe(struct bgmac *bgmac
-
- bgmac->in_init = false;
-
-+ if ((bgmac->feature_flags & BGMAC_FEAT_SRAB) && !bgmac_b53_pdata.regs) {
-+ bgmac_b53_pdata.regs = ioremap(0x18007000, 0x1000);
-+
-+ err = platform_device_register(&bgmac_b53_dev);
-+ if (!err)
-+ bgmac->b53_device = &bgmac_b53_dev;
-+ }
-+
- err = register_netdev(bgmac->net_dev);
- if (err) {
- dev_err(bgmac->dev, "Cannot register net device\n");
-@@ -1568,6 +1588,10 @@ EXPORT_SYMBOL_GPL(bgmac_enet_probe);
-
- void bgmac_enet_remove(struct bgmac *bgmac)
- {
-+ if (bgmac->b53_device)
-+ platform_device_unregister(&bgmac_b53_dev);
-+ bgmac->b53_device = NULL;
-+
- unregister_netdev(bgmac->net_dev);
- phy_disconnect(bgmac->net_dev->phydev);
- netif_napi_del(&bgmac->napi);
---- a/drivers/net/ethernet/broadcom/bgmac.h
-+++ b/drivers/net/ethernet/broadcom/bgmac.h
-@@ -387,6 +387,7 @@
- #define BGMAC_FEAT_CC4_IF_SW_TYPE_RGMII BIT(18)
- #define BGMAC_FEAT_CC7_IF_TYPE_RGMII BIT(19)
- #define BGMAC_FEAT_IDM_MASK BIT(20)
-+#define BGMAC_FEAT_SRAB BIT(21)
-
- struct bgmac_slot_info {
- union {
-@@ -494,6 +495,9 @@ struct bgmac {
- void (*cmn_maskset32)(struct bgmac *bgmac, u16 offset, u32 mask,
- u32 set);
- int (*phy_connect)(struct bgmac *bgmac);
-+
-+ /* platform device for associated switch */
-+ struct platform_device *b53_device;
- };
-
- struct bgmac *bgmac_alloc(struct device *dev);
+++ /dev/null
-From f81700b6bb2eda3756247bce472d8eaf6f466f61 Mon Sep 17 00:00:00 2001
-Date: Wed, 13 Jul 2022 13:49:26 +0200
-Subject: [PATCH] net/usb/qmi_wwan: add MeigLink modem support
-
----
- drivers/net/usb/qmi_wwan.c | 1 +
- drivers/usb/serial/option.c | 7 +++++++
- 2 files changed, 8 insertions(+)
-
---- a/drivers/net/usb/qmi_wwan.c
-+++ b/drivers/net/usb/qmi_wwan.c
-@@ -1090,6 +1090,11 @@ static const struct usb_device_id produc
- USB_DEVICE_AND_INTERFACE_INFO(0x03f0, 0x581d, USB_CLASS_VENDOR_SPEC, 1, 7),
- .driver_info = (unsigned long)&qmi_wwan_info,
- },
-+ { /* Meiglink SGM828 */
-+ USB_DEVICE_AND_INTERFACE_INFO(0x2dee, 0x4d49, USB_CLASS_VENDOR_SPEC, 0x10, 0x05),
-+ .driver_info = (unsigned long)&qmi_wwan_info,
-+ },
-+
- {QMI_MATCH_FF_FF_FF(0x2c7c, 0x0122)}, /* Quectel RG650V */
- {QMI_MATCH_FF_FF_FF(0x2c7c, 0x0125)}, /* Quectel EC25, EC20 R2.0 Mini PCIe */
- {QMI_MATCH_FF_FF_FF(0x2c7c, 0x0306)}, /* Quectel EP06/EG06/EM06 */
-@@ -1097,6 +1102,7 @@ static const struct usb_device_id produc
- {QMI_MATCH_FF_FF_FF(0x2c7c, 0x0620)}, /* Quectel EM160R-GL */
- {QMI_MATCH_FF_FF_FF(0x2c7c, 0x0800)}, /* Quectel RM500Q-GL */
- {QMI_MATCH_FF_FF_FF(0x2c7c, 0x0801)}, /* Quectel RM520N */
-+ {QMI_MATCH_FF_FF_FF(0x05c6, 0xf601)}, /* MeigLink SLM750 */
-
- /* 3. Combined interface devices matching on interface number */
- {QMI_FIXED_INTF(0x0408, 0xea42, 4)}, /* Yota / Megafon M100-1 */
---- a/drivers/usb/serial/option.c
-+++ b/drivers/usb/serial/option.c
-@@ -247,6 +247,11 @@ static void option_instat_callback(struc
- #define UBLOX_PRODUCT_R410M 0x90b2
- /* These Yuga products use Qualcomm's vendor ID */
- #define YUGA_PRODUCT_CLM920_NC5 0x9625
-+/* These MeigLink products use Qualcomm's vendor ID */
-+#define MEIGLINK_PRODUCT_SLM750 0xf601
-+
-+#define MEIGLINK_VENDOR_ID 0x2dee
-+#define MEIGLINK_PRODUCT_SLM828 0x4d49
-
- #define QUECTEL_VENDOR_ID 0x2c7c
- /* These Quectel products use Quectel's vendor ID */
-@@ -1156,6 +1161,11 @@ static const struct usb_device_id option
- { USB_DEVICE(QUALCOMM_VENDOR_ID, 0x0023)}, /* ONYX 3G device */
- { USB_DEVICE(QUALCOMM_VENDOR_ID, 0x9000), /* SIMCom SIM5218 */
- .driver_info = NCTRL(0) | NCTRL(1) | NCTRL(2) | NCTRL(3) | RSVD(4) },
-+ /* MeiG */
-+ { USB_DEVICE_AND_INTERFACE_INFO(MEIGLINK_VENDOR_ID, MEIGLINK_PRODUCT_SLM828, USB_CLASS_VENDOR_SPEC, 0x10, 0x01) },
-+ { USB_DEVICE_AND_INTERFACE_INFO(MEIGLINK_VENDOR_ID, MEIGLINK_PRODUCT_SLM828, USB_CLASS_VENDOR_SPEC, 0x10, 0x02) },
-+ { USB_DEVICE_AND_INTERFACE_INFO(MEIGLINK_VENDOR_ID, MEIGLINK_PRODUCT_SLM828, USB_CLASS_VENDOR_SPEC, 0x10, 0x03) },
-+ { USB_DEVICE_AND_INTERFACE_INFO(MEIGLINK_VENDOR_ID, MEIGLINK_PRODUCT_SLM828, USB_CLASS_VENDOR_SPEC, 0x10, 0x04) },
- /* Quectel products using Qualcomm vendor ID */
- { USB_DEVICE(QUALCOMM_VENDOR_ID, QUECTEL_PRODUCT_UC15)},
- { USB_DEVICE(QUALCOMM_VENDOR_ID, QUECTEL_PRODUCT_UC20),
-@@ -1197,6 +1207,11 @@ static const struct usb_device_id option
- .driver_info = ZLP },
- { USB_DEVICE(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_BG96),
- .driver_info = RSVD(4) },
-+ /* Meiglink products using Qualcomm vendor ID */
-+ // Works OK. In case of some issues check macros that are used by Quectel Products
-+ { USB_DEVICE_AND_INTERFACE_INFO(QUALCOMM_VENDOR_ID, MEIGLINK_PRODUCT_SLM750, 0xff, 0xff, 0xff),
-+ .driver_info = NUMEP2 },
-+ { USB_DEVICE_AND_INTERFACE_INFO(QUALCOMM_VENDOR_ID, MEIGLINK_PRODUCT_SLM750, 0xff, 0, 0) },
- { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EP06, 0xff, 0xff, 0xff),
- .driver_info = RSVD(1) | RSVD(2) | RSVD(3) | RSVD(4) | NUMEP2 },
- { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EP06, 0xff, 0, 0) },
+++ /dev/null
-From 9fabf60187f1fa19e6f6bb5441587d485bd534b0 Mon Sep 17 00:00:00 2001
-Date: Tue, 9 Apr 2024 17:06:38 +0100
-Subject: [PATCH] rndis_host: add a bunch of USB IDs
-
-Add a bunch of USB IDs found in various places online to the
-RNDIS USB network driver.
-
----
- drivers/net/usb/rndis_host.c | 40 ++++++++++++++++++++++
- 1 file changed, 40 insertions(+)
-
---- a/drivers/net/usb/rndis_host.c
-+++ b/drivers/net/usb/rndis_host.c
-@@ -630,6 +630,16 @@ static const struct driver_info zte_rndi
- .tx_fixup = rndis_tx_fixup,
- };
-
-+static const struct driver_info asr_rndis_info = {
-+ .description = "Asr RNDIS device",
-+ .flags = FLAG_WWAN | FLAG_POINTTOPOINT | FLAG_FRAMING_RN | FLAG_NO_SETINT | FLAG_NOARP,
-+ .bind = rndis_bind,
-+ .unbind = rndis_unbind,
-+ .status = rndis_status,
-+ .rx_fixup = rndis_rx_fixup,
-+ .tx_fixup = rndis_tx_fixup,
-+};
-+
- /*-------------------------------------------------------------------------*/
-
- static const struct usb_device_id products [] = {
-@@ -666,6 +676,36 @@ static const struct usb_device_id produc
- USB_INTERFACE_INFO(USB_CLASS_WIRELESS_CONTROLLER, 1, 3),
- .driver_info = (unsigned long) &rndis_info,
- }, {
-+ /* Quectel EG060V rndis device */
-+ USB_DEVICE_AND_INTERFACE_INFO(0x2c7c, 0x6004,
-+ USB_CLASS_WIRELESS_CONTROLLER, 1, 3),
-+ .driver_info = (unsigned long) &asr_rndis_info,
-+}, {
-+ /* Quectel EC200A rndis device */
-+ USB_DEVICE_AND_INTERFACE_INFO(0x2c7c, 0x6005,
-+ USB_CLASS_WIRELESS_CONTROLLER, 1, 3),
-+ .driver_info = (unsigned long) &asr_rndis_info,
-+}, {
-+ /* Quectel EC200T rndis device */
-+ USB_DEVICE_AND_INTERFACE_INFO(0x2c7c, 0x6026,
-+ USB_CLASS_WIRELESS_CONTROLLER, 1, 3),
-+ .driver_info = (unsigned long) &asr_rndis_info,
-+}, {
-+ /* Simcom A7906E rndis device */
-+ USB_DEVICE_AND_INTERFACE_INFO(0x1e0e, 0x9011,
-+ USB_CLASS_WIRELESS_CONTROLLER, 1, 3),
-+ .driver_info = (unsigned long) &asr_rndis_info,
-+}, {
-+ /* Meig SLM770A */
-+ USB_DEVICE_AND_INTERFACE_INFO(0x2dee, 0x4d57,
-+ USB_CLASS_WIRELESS_CONTROLLER, 1, 3),
-+ .driver_info = (unsigned long) &asr_rndis_info,
-+}, {
-+ /* Meig SLM828 */
-+ USB_DEVICE_AND_INTERFACE_INFO(0x2dee, 0x4d49,
-+ USB_CLASS_WIRELESS_CONTROLLER, 1, 3),
-+ .driver_info = (unsigned long) &asr_rndis_info,
-+}, {
- /* Novatel Verizon USB730L */
- USB_INTERFACE_INFO(USB_CLASS_MISC, 4, 1),
- .driver_info = (unsigned long) &rndis_info,
+++ /dev/null
-From cc809a441d8f2924f785eb863dfa6aef47a25b0b Mon Sep 17 00:00:00 2001
-Date: Tue, 12 Aug 2014 20:49:27 +0200
-Subject: [PATCH 30/36] GPIO: add named gpio exports
-
---- a/drivers/gpio/gpiolib-of.c
-+++ b/drivers/gpio/gpiolib-of.c
-@@ -21,6 +21,8 @@
-
- #include <linux/gpio/consumer.h>
- #include <linux/gpio/machine.h>
-+#include <linux/init.h>
-+#include <linux/platform_device.h>
-
- #include "gpiolib.h"
- #include "gpiolib-of.h"
-@@ -1138,3 +1140,73 @@ void of_gpiochip_remove(struct gpio_chip
- {
- of_node_put(dev_of_node(&chip->gpiodev->dev));
- }
-+
-+#ifdef CONFIG_GPIO_SYSFS
-+
-+static const struct of_device_id gpio_export_ids[] = {
-+ { .compatible = "gpio-export" },
-+ { /* sentinel */ }
-+};
-+
-+static int of_gpio_export_probe(struct platform_device *pdev)
-+{
-+ struct device_node *np = pdev->dev.of_node;
-+ struct device_node *cnp;
-+ u32 val;
-+ int nb = 0;
-+
-+ for_each_child_of_node(np, cnp) {
-+ const char *name = NULL;
-+ int gpio;
-+ bool dmc;
-+ int max_gpio = 1;
-+ int i;
-+
-+ of_property_read_string(cnp, "gpio-export,name", &name);
-+
-+ if (!name)
-+ max_gpio = of_gpio_named_count(cnp, "gpios");
-+
-+ for (i = 0; i < max_gpio; i++) {
-+ struct gpio_desc *desc;
-+ unsigned flags = 0;
-+ enum of_gpio_flags of_flags;
-+
-+ desc = of_get_named_gpiod_flags(cnp, "gpios", i, &of_flags);
-+ if (IS_ERR(desc))
-+ return PTR_ERR(desc);
-+ gpio = desc_to_gpio(desc);
-+
-+ if (of_flags & OF_GPIO_ACTIVE_LOW)
-+ flags |= GPIOF_ACTIVE_LOW;
-+
-+ if (!of_property_read_u32(cnp, "gpio-export,output", &val))
-+ flags |= val ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW;
-+ else
-+ flags |= GPIOF_IN;
-+
-+ if (devm_gpio_request_one(&pdev->dev, gpio, flags, name ? name : of_node_full_name(np)))
-+ continue;
-+
-+ dmc = of_property_read_bool(cnp, "gpio-export,direction_may_change");
-+ gpio_export_with_name(gpio_to_desc(gpio), dmc, name);
-+ nb++;
-+ }
-+ }
-+
-+ dev_info(&pdev->dev, "%d gpio(s) exported\n", nb);
-+
-+ return 0;
-+}
-+
-+static struct platform_driver gpio_export_driver = {
-+ .driver = {
-+ .name = "gpio-export",
-+ .of_match_table = of_match_ptr(gpio_export_ids),
-+ },
-+ .probe = of_gpio_export_probe,
-+};
-+
-+module_platform_driver(gpio_export_driver);
-+
-+#endif
---- a/include/linux/gpio/consumer.h
-+++ b/include/linux/gpio/consumer.h
-@@ -644,7 +644,10 @@ static inline struct gpio_desc *acpi_get
-
- #if IS_ENABLED(CONFIG_GPIOLIB) && IS_ENABLED(CONFIG_GPIO_SYSFS)
-
-+int __gpiod_export(struct gpio_desc *desc, bool direction_may_change, const char *name);
- int gpiod_export(struct gpio_desc *desc, bool direction_may_change);
-+int gpio_export_with_name(struct gpio_desc *desc, bool direction_may_change,
-+ const char *name);
- int gpiod_export_link(struct device *dev, const char *name,
- struct gpio_desc *desc);
- void gpiod_unexport(struct gpio_desc *desc);
-@@ -653,11 +656,25 @@ void gpiod_unexport(struct gpio_desc *de
-
- #include <asm/errno.h>
-
-+static inline int __gpiod_export(struct gpio_desc *desc,
-+ bool direction_may_change,
-+ const char *name)
-+{
-+ return -ENOSYS;
-+}
-+
- static inline int gpiod_export(struct gpio_desc *desc,
- bool direction_may_change)
- {
- return -ENOSYS;
- }
-+
-+static inline int gpio_export_with_name(struct gpio_desc *desc,
-+ bool direction_may_change,
-+ const char *name)
-+{
-+ return -ENOSYS;
-+}
-
- static inline int gpiod_export_link(struct device *dev, const char *name,
- struct gpio_desc *desc)
---- a/drivers/gpio/gpiolib-sysfs.c
-+++ b/drivers/gpio/gpiolib-sysfs.c
-@@ -558,7 +558,7 @@ static struct class gpio_class = {
- *
- * Returns zero on success, else an error.
- */
--int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
-+int __gpiod_export(struct gpio_desc *desc, bool direction_may_change, const char *name)
- {
- struct gpio_chip *chip;
- struct gpio_device *gdev;
-@@ -620,6 +620,8 @@ int gpiod_export(struct gpio_desc *desc,
- offset = gpio_chip_hwgpio(desc);
- if (chip->names && chip->names[offset])
- ioname = chip->names[offset];
-+ if (name)
-+ ioname = name;
-
- dev = device_create_with_groups(&gpio_class, &gdev->dev,
- MKDEV(0, 0), data, gpio_groups,
-@@ -641,8 +643,21 @@ err_unlock:
- gpiod_dbg(desc, "%s: status %d\n", __func__, status);
- return status;
- }
-+EXPORT_SYMBOL_GPL(__gpiod_export);
-+
-+int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
-+{
-+ return __gpiod_export(desc, direction_may_change, NULL);
-+}
- EXPORT_SYMBOL_GPL(gpiod_export);
-
-+int gpio_export_with_name(struct gpio_desc *desc, bool direction_may_change,
-+ const char *name)
-+{
-+ return __gpiod_export(desc, direction_may_change, name);
-+}
-+EXPORT_SYMBOL_GPL(gpio_export_with_name);
-+
- static int match_export(struct device *dev, const void *desc)
- {
- struct gpiod_data *data = dev_get_drvdata(dev);
+++ /dev/null
-From e4d708702e6c98f2111e33201a264d6788564cb2 Mon Sep 17 00:00:00 2001
-Date: Fri, 12 May 2023 11:08:43 +0200
-Subject: [PATCH] ssb_sprom: add generic kernel support for Broadcom Fallback SPROMs
-
----
- drivers/bcma/Kconfig | 4 ++++
- drivers/bcma/Makefile | 1 +
- drivers/bcma/bcma_private.h | 1 +
- drivers/bcma/main.c | 8 ++++++++
- drivers/bcma/sprom.c | 23 ++++++++++++++---------
- drivers/ssb/Kconfig | 5 +++++
- drivers/ssb/Makefile | 1 +
- drivers/ssb/main.c | 8 ++++++++
- drivers/ssb/sprom.c | 12 +++++++++++-
- drivers/ssb/ssb_private.h | 2 +-
- 10 files changed, 54 insertions(+), 11 deletions(-)
-
---- a/drivers/bcma/Kconfig
-+++ b/drivers/bcma/Kconfig
-@@ -18,6 +18,10 @@ config BCMA_BLOCKIO
- bool
- default y
-
-+config BCMA_FALLBACK_SPROM
-+ bool
-+ default y
-+
- config BCMA_HOST_PCI_POSSIBLE
- bool
- depends on PCI = y
---- a/drivers/bcma/Makefile
-+++ b/drivers/bcma/Makefile
-@@ -11,6 +11,7 @@ bcma-$(CONFIG_BCMA_DRIVER_PCI_HOSTMODE)
- bcma-$(CONFIG_BCMA_DRIVER_MIPS) += driver_mips.o
- bcma-$(CONFIG_BCMA_DRIVER_GMAC_CMN) += driver_gmac_cmn.o
- bcma-$(CONFIG_BCMA_DRIVER_GPIO) += driver_gpio.o
-+bcma-$(CONFIG_BCMA_FALLBACK_SPROM) += fallback-sprom.o
- bcma-$(CONFIG_BCMA_HOST_PCI) += host_pci.o
- bcma-$(CONFIG_BCMA_HOST_SOC) += host_soc.o
- obj-$(CONFIG_BCMA) += bcma.o
---- a/drivers/bcma/bcma_private.h
-+++ b/drivers/bcma/bcma_private.h
-@@ -8,6 +8,7 @@
-
- #include <linux/bcma/bcma.h>
- #include <linux/delay.h>
-+#include "fallback-sprom.h"
-
- #define bcma_err(bus, fmt, ...) \
- dev_err((bus)->dev, "bus%d: " fmt, (bus)->num, ##__VA_ARGS__)
---- a/drivers/bcma/main.c
-+++ b/drivers/bcma/main.c
-@@ -671,6 +671,14 @@ static int __init bcma_modinit(void)
- {
- int err;
-
-+#ifdef CONFIG_BCMA_FALLBACK_SPROM
-+ err = bcma_fbs_register();
-+ if (err) {
-+ pr_err("Fallback SPROM initialization failed\n");
-+ err = 0;
-+ }
-+#endif /* CONFIG_BCMA_FALLBACK_SPROM */
-+
- err = bcma_init_bus_register();
- if (err)
- return err;
---- a/drivers/bcma/sprom.c
-+++ b/drivers/bcma/sprom.c
-@@ -51,21 +51,26 @@ static int bcma_fill_sprom_with_fallback
- {
- int err;
-
-- if (!get_fallback_sprom) {
-+ if (get_fallback_sprom)
-+ err = get_fallback_sprom(bus, out);
-+
-+#ifdef CONFIG_BCMA_FALLBACK_SPROM
-+ if (!get_fallback_sprom || err)
-+ err = bcma_get_fallback_sprom(bus, out);
-+#else
-+ if (!get_fallback_sprom)
- err = -ENOENT;
-- goto fail;
-- }
-+#endif /* CONFIG_BCMA_FALLBACK_SPROM */
-
-- err = get_fallback_sprom(bus, out);
-- if (err)
-- goto fail;
-+ if (err) {
-+ bcma_warn(bus, "Using fallback SPROM failed (err %d)\n", err);
-+ return err;
-+ }
-
- bcma_debug(bus, "Using SPROM revision %d provided by platform.\n",
- bus->sprom.revision);
-+
- return 0;
--fail:
-- bcma_warn(bus, "Using fallback SPROM failed (err %d)\n", err);
-- return err;
- }
-
- /**************************************************
---- a/drivers/ssb/Kconfig
-+++ b/drivers/ssb/Kconfig
-@@ -25,6 +25,11 @@ if SSB
- config SSB_SPROM
- bool
-
-+config SSB_FALLBACK_SPROM
-+ bool
-+ depends on SSB_PCIHOST
-+ default y
-+
- # Support for Block-I/O. SELECT this from the driver that needs it.
- config SSB_BLOCKIO
- bool
---- a/drivers/ssb/Makefile
-+++ b/drivers/ssb/Makefile
-@@ -2,6 +2,7 @@
- # core
- ssb-y += main.o scan.o
- ssb-$(CONFIG_SSB_EMBEDDED) += embedded.o
-+ssb-$(CONFIG_SSB_FALLBACK_SPROM) += fallback-sprom.o
- ssb-$(CONFIG_SSB_SPROM) += sprom.o
-
- # host support
---- a/drivers/ssb/main.c
-+++ b/drivers/ssb/main.c
-@@ -1289,6 +1289,14 @@ static int __init ssb_modinit(void)
- {
- int err;
-
-+#ifdef CONFIG_SSB_FALLBACK_SPROM
-+ err = ssb_fbs_register();
-+ if (err) {
-+ pr_err("Fallback SPROM initialization failed\n");
-+ err = 0;
-+ }
-+#endif /* CONFIG_SSB_FALLBACK_SPROM */
-+
- /* See the comment at the ssb_is_early_boot definition */
- ssb_is_early_boot = 0;
- err = bus_register(&ssb_bustype);
---- a/drivers/ssb/sprom.c
-+++ b/drivers/ssb/sprom.c
-@@ -180,10 +180,20 @@ int ssb_arch_register_fallback_sprom(int
-
- int ssb_fill_sprom_with_fallback(struct ssb_bus *bus, struct ssb_sprom *out)
- {
-+ int err;
-+
-+ if (get_fallback_sprom)
-+ err = get_fallback_sprom(bus, out);
-+
-+#ifdef CONFIG_SSB_FALLBACK_SPROM
-+ if (!get_fallback_sprom || err)
-+ err = ssb_get_fallback_sprom(bus, out);
-+#else
- if (!get_fallback_sprom)
- return -ENOENT;
-+#endif /* CONFIG_SSB_FALLBACK_SPROM */
-
-- return get_fallback_sprom(bus, out);
-+ return err;
- }
-
- /* https://bcm-v4.sipsolutions.net/802.11/IsSpromAvailable */
---- a/drivers/ssb/ssb_private.h
-+++ b/drivers/ssb/ssb_private.h
-@@ -8,7 +8,7 @@
- #include <linux/ssb/ssb.h>
- #include <linux/types.h>
- #include <linux/bcm47xx_wdt.h>
--
-+#include "fallback-sprom.h"
-
- /* pci.c */
- #ifdef CONFIG_SSB_PCIHOST
+++ /dev/null
-From 3b6115d6b57a263bdc8c9b1df273bd4a7955eead Mon Sep 17 00:00:00 2001
-Date: Sat, 8 Jul 2017 08:16:31 +0200
-Subject: debloat: add some debloat patches, strip down procfs and make O_DIRECT support optional, saves ~15K after lzma on MIPS
-
----
- net/Kconfig | 3 +++
- net/core/Makefile | 3 ++-
- net/core/sock.c | 2 ++
- net/ipv4/Kconfig | 1 +
- net/netlink/Kconfig | 1 +
- net/packet/Kconfig | 1 +
- net/unix/Kconfig | 1 +
- 7 files changed, 11 insertions(+), 1 deletion(-)
-
---- a/net/Kconfig
-+++ b/net/Kconfig
-@@ -129,6 +129,9 @@ source "net/mptcp/Kconfig"
-
- endif # if INET
-
-+config SOCK_DIAG
-+ bool
-+
- config NETWORK_SECMARK
- bool "Security Marking"
- help
---- a/net/core/Makefile
-+++ b/net/core/Makefile
-@@ -11,12 +11,13 @@ obj-$(CONFIG_SYSCTL) += sysctl_net_core.
-
- obj-y += dev.o dev_addr_lists.o dst.o netevent.o \
- neighbour.o rtnetlink.o utils.o link_watch.o filter.o \
-- sock_diag.o dev_ioctl.o tso.o sock_reuseport.o \
-+ dev_ioctl.o tso.o sock_reuseport.o \
- fib_notifier.o xdp.o flow_offload.o gro.o \
- netdev-genl.o netdev-genl-gen.o gso.o
-
- obj-$(CONFIG_NETDEV_ADDR_LIST_TEST) += dev_addr_lists_test.o
-
-+obj-$(CONFIG_SOCK_DIAG) += sock_diag.o
- obj-y += net-sysfs.o
- obj-$(CONFIG_PAGE_POOL) += page_pool.o
- obj-$(CONFIG_PROC_FS) += net-procfs.o
---- a/net/core/sock.c
-+++ b/net/core/sock.c
-@@ -118,6 +118,7 @@
- #include <linux/mroute.h>
- #include <linux/mroute6.h>
- #include <linux/icmpv6.h>
-+#include <linux/cookie.h>
-
- #include <linux/uaccess.h>
-
-@@ -150,6 +151,7 @@
-
- static DEFINE_MUTEX(proto_list_mutex);
- static LIST_HEAD(proto_list);
-+DEFINE_COOKIE(sock_cookie);
-
- static void sock_def_write_space_wfree(struct sock *sk);
- static void sock_def_write_space(struct sock *sk);
-@@ -590,6 +592,21 @@ discard_and_relse:
- }
- EXPORT_SYMBOL(__sk_receive_skb);
-
-+u64 __sock_gen_cookie(struct sock *sk)
-+{
-+ u64 res = atomic64_read(&sk->sk_cookie);
-+
-+ if (!res) {
-+ u64 new = gen_cookie_next(&sock_cookie);
-+
-+ atomic64_cmpxchg(&sk->sk_cookie, res, new);
-+
-+ /* Another thread might have changed sk_cookie before us. */
-+ res = atomic64_read(&sk->sk_cookie);
-+ }
-+ return res;
-+}
-+
- INDIRECT_CALLABLE_DECLARE(struct dst_entry *ip6_dst_check(struct dst_entry *,
- u32));
- INDIRECT_CALLABLE_DECLARE(struct dst_entry *ipv4_dst_check(struct dst_entry *,
-@@ -2263,9 +2280,11 @@ static void __sk_free(struct sock *sk)
- if (likely(sk->sk_net_refcnt))
- sock_inuse_add(sock_net(sk), -1);
-
-+#ifdef CONFIG_SOCK_DIAG
- if (unlikely(sk->sk_net_refcnt && sock_diag_has_destroy_listeners(sk)))
- sock_diag_broadcast_destroy(sk);
- else
-+#endif
- sk_destruct(sk);
- }
-
---- a/net/core/sock_diag.c
-+++ b/net/core/sock_diag.c
-@@ -12,7 +12,6 @@
- #include <linux/tcp.h>
- #include <linux/workqueue.h>
- #include <linux/nospec.h>
--#include <linux/cookie.h>
- #include <linux/inet_diag.h>
- #include <linux/sock_diag.h>
-
-@@ -22,23 +21,6 @@ static const struct sock_diag_inet_compa
-
- static struct workqueue_struct *broadcast_wq;
-
--DEFINE_COOKIE(sock_cookie);
--
--u64 __sock_gen_cookie(struct sock *sk)
--{
-- u64 res = atomic64_read(&sk->sk_cookie);
--
-- if (!res) {
-- u64 new = gen_cookie_next(&sock_cookie);
--
-- atomic64_cmpxchg(&sk->sk_cookie, res, new);
--
-- /* Another thread might have changed sk_cookie before us. */
-- res = atomic64_read(&sk->sk_cookie);
-- }
-- return res;
--}
--
- int sock_diag_check_cookie(struct sock *sk, const __u32 *cookie)
- {
- u64 res;
---- a/net/ipv4/Kconfig
-+++ b/net/ipv4/Kconfig
-@@ -423,6 +423,7 @@ config INET_TUNNEL
-
- config INET_DIAG
- tristate "INET: socket monitoring interface"
-+ select SOCK_DIAG
- default y
- help
- Support for INET (TCP, DCCP, etc) socket monitoring interface used by
---- a/net/netlink/Kconfig
-+++ b/net/netlink/Kconfig
-@@ -5,6 +5,7 @@
-
- config NETLINK_DIAG
- tristate "NETLINK: socket monitoring interface"
-+ select SOCK_DIAG
- default n
- help
- Support for NETLINK socket monitoring interface used by the ss tool.
---- a/net/packet/Kconfig
-+++ b/net/packet/Kconfig
-@@ -19,6 +19,7 @@ config PACKET
- config PACKET_DIAG
- tristate "Packet: sockets monitoring interface"
- depends on PACKET
-+ select SOCK_DIAG
- default n
- help
- Support for PF_PACKET sockets monitoring interface used by the ss tool.
---- a/net/unix/Kconfig
-+++ b/net/unix/Kconfig
-@@ -24,6 +24,7 @@ config AF_UNIX_OOB
- config UNIX_DIAG
- tristate "UNIX: socket monitoring interface"
- depends on UNIX
-+ select SOCK_DIAG
- default n
- help
- Support for UNIX socket monitoring interface used by the ss tool.
---- a/net/xdp/Kconfig
-+++ b/net/xdp/Kconfig
-@@ -10,6 +10,7 @@ config XDP_SOCKETS
- config XDP_SOCKETS_DIAG
- tristate "XDP sockets: monitoring interface"
- depends on XDP_SOCKETS
-+ select SOCK_DIAG
- default n
- help
- Support for PF_XDP sockets monitoring interface used by the ss tool.
+++ /dev/null
-From 9e3f1d0805b2d919904dd9a4ff0d956314cc3cba Mon Sep 17 00:00:00 2001
-Date: Sat, 8 Jul 2017 08:20:09 +0200
-Subject: debloat: procfs
-
----
- fs/locks.c | 2 ++
- fs/proc/Kconfig | 5 +++++
- fs/proc/consoles.c | 3 +++
- fs/proc/proc_tty.c | 11 ++++++++++-
- include/net/snmp.h | 18 +++++++++++++++++-
- ipc/msg.c | 3 +++
- ipc/sem.c | 2 ++
- ipc/shm.c | 2 ++
- ipc/util.c | 3 +++
- kernel/exec_domain.c | 2 ++
- kernel/irq/proc.c | 9 +++++++++
- kernel/time/timer_list.c | 2 ++
- mm/vmalloc.c | 2 ++
- mm/vmstat.c | 8 +++++---
- net/8021q/vlanproc.c | 6 ++++++
- net/core/net-procfs.c | 18 ++++++++++++------
- net/core/sock.c | 2 ++
- net/ipv4/fib_trie.c | 18 ++++++++++++------
- net/ipv4/proc.c | 3 +++
- net/ipv4/route.c | 3 +++
- 20 files changed, 105 insertions(+), 17 deletions(-)
-
---- a/fs/locks.c
-+++ b/fs/locks.c
-@@ -2895,6 +2895,8 @@ static const struct seq_operations locks
-
- static int __init proc_locks_init(void)
- {
-+ if (IS_ENABLED(CONFIG_PROC_STRIPPED))
-+ return 0;
- proc_create_seq_private("locks", 0, NULL, &locks_seq_operations,
- sizeof(struct locks_iterator), NULL);
- return 0;
---- a/fs/proc/Kconfig
-+++ b/fs/proc/Kconfig
-@@ -101,6 +101,11 @@ config PROC_CHILDREN
- Say Y if you are running any user-space software which takes benefit from
- this interface. For example, rkt is such a piece of software.
-
-+config PROC_STRIPPED
-+ default n
-+ depends on EXPERT
-+ bool "Strip non-essential /proc functionality to reduce code size"
-+
- config PROC_PID_ARCH_STATUS
- def_bool n
- depends on PROC_FS
---- a/fs/proc/consoles.c
-+++ b/fs/proc/consoles.c
-@@ -107,6 +107,9 @@ static const struct seq_operations conso
-
- static int __init proc_consoles_init(void)
- {
-+ if (IS_ENABLED(CONFIG_PROC_STRIPPED))
-+ return 0;
-+
- proc_create_seq("consoles", 0, NULL, &consoles_op);
- return 0;
- }
---- a/fs/proc/proc_tty.c
-+++ b/fs/proc/proc_tty.c
-@@ -131,7 +131,10 @@ static const struct seq_operations tty_d
- void proc_tty_register_driver(struct tty_driver *driver)
- {
- struct proc_dir_entry *ent;
--
-+
-+ if (IS_ENABLED(CONFIG_PROC_STRIPPED))
-+ return;
-+
- if (!driver->driver_name || driver->proc_entry ||
- !driver->ops->proc_show)
- return;
-@@ -148,6 +151,9 @@ void proc_tty_unregister_driver(struct t
- {
- struct proc_dir_entry *ent;
-
-+ if (IS_ENABLED(CONFIG_PROC_STRIPPED))
-+ return;
-+
- ent = driver->proc_entry;
- if (!ent)
- return;
-@@ -162,6 +168,9 @@ void proc_tty_unregister_driver(struct t
- */
- void __init proc_tty_init(void)
- {
-+ if (IS_ENABLED(CONFIG_PROC_STRIPPED))
-+ return;
-+
- if (!proc_mkdir("tty", NULL))
- return;
- proc_mkdir("tty/ldisc", NULL); /* Preserved: it's userspace visible */
---- a/include/net/snmp.h
-+++ b/include/net/snmp.h
-@@ -124,6 +124,21 @@ struct linux_tls_mib {
- #define DECLARE_SNMP_STAT(type, name) \
- extern __typeof__(type) __percpu *name
-
-+#ifdef CONFIG_PROC_STRIPPED
-+#define __SNMP_STATS_DUMMY(mib) \
-+ do { (void) mib->mibs[0]; } while(0)
-+
-+#define __SNMP_INC_STATS(mib, field) __SNMP_STATS_DUMMY(mib)
-+#define SNMP_INC_STATS_ATOMIC_LONG(mib, field) __SNMP_STATS_DUMMY(mib)
-+#define SNMP_INC_STATS(mib, field) __SNMP_STATS_DUMMY(mib)
-+#define SNMP_DEC_STATS(mib, field) __SNMP_STATS_DUMMY(mib)
-+#define __SNMP_ADD_STATS(mib, field, addend) __SNMP_STATS_DUMMY(mib)
-+#define SNMP_ADD_STATS(mib, field, addend) __SNMP_STATS_DUMMY(mib)
-+#define SNMP_UPD_PO_STATS(mib, basefield, addend) __SNMP_STATS_DUMMY(mib)
-+#define __SNMP_UPD_PO_STATS(mib, basefield, addend) __SNMP_STATS_DUMMY(mib)
-+
-+#else
-+
- #define __SNMP_INC_STATS(mib, field) \
- __this_cpu_inc(mib->mibs[field])
-
-@@ -154,8 +169,9 @@ struct linux_tls_mib {
- __this_cpu_add(ptr[basefield##OCTETS], addend); \
- } while (0)
-
-+#endif
-
--#if BITS_PER_LONG==32
-+#if (BITS_PER_LONG==32) && !defined(CONFIG_PROC_STRIPPED)
-
- #define __SNMP_ADD_STATS64(mib, field, addend) \
- do { \
---- a/ipc/msg.c
-+++ b/ipc/msg.c
-@@ -1370,6 +1370,9 @@ void __init msg_init(void)
- {
- msg_init_ns(&init_ipc_ns);
-
-+ if (IS_ENABLED(CONFIG_PROC_STRIPPED))
-+ return;
-+
- ipc_init_proc_interface("sysvipc/msg",
- " key msqid perms cbytes qnum lspid lrpid uid gid cuid cgid stime rtime ctime\n",
- IPC_MSG_IDS, sysvipc_msg_proc_show);
---- a/ipc/sem.c
-+++ b/ipc/sem.c
-@@ -268,6 +268,8 @@ void sem_exit_ns(struct ipc_namespace *n
- void __init sem_init(void)
- {
- sem_init_ns(&init_ipc_ns);
-+ if (IS_ENABLED(CONFIG_PROC_STRIPPED))
-+ return;
- ipc_init_proc_interface("sysvipc/sem",
- " key semid perms nsems uid gid cuid cgid otime ctime\n",
- IPC_SEM_IDS, sysvipc_sem_proc_show);
---- a/ipc/shm.c
-+++ b/ipc/shm.c
-@@ -154,6 +154,8 @@ pure_initcall(ipc_ns_init);
-
- void __init shm_init(void)
- {
-+ if (IS_ENABLED(CONFIG_PROC_STRIPPED))
-+ return;
- ipc_init_proc_interface("sysvipc/shm",
- #if BITS_PER_LONG <= 32
- " key shmid perms size cpid lpid nattch uid gid cuid cgid atime dtime ctime rss swap\n",
---- a/ipc/util.c
-+++ b/ipc/util.c
-@@ -141,6 +141,9 @@ void __init ipc_init_proc_interface(cons
- struct proc_dir_entry *pde;
- struct ipc_proc_iface *iface;
-
-+ if (IS_ENABLED(CONFIG_PROC_STRIPPED))
-+ return;
-+
- iface = kmalloc(sizeof(*iface), GFP_KERNEL);
- if (!iface)
- return;
---- a/kernel/exec_domain.c
-+++ b/kernel/exec_domain.c
-@@ -29,6 +29,8 @@ static int execdomains_proc_show(struct
-
- static int __init proc_execdomains_init(void)
- {
-+ if (IS_ENABLED(CONFIG_PROC_STRIPPED))
-+ return 0;
- proc_create_single("execdomains", 0, NULL, execdomains_proc_show);
- return 0;
- }
---- a/kernel/irq/proc.c
-+++ b/kernel/irq/proc.c
-@@ -341,6 +341,9 @@ void register_irq_proc(unsigned int irq,
- void __maybe_unused *irqp = (void *)(unsigned long) irq;
- char name [MAX_NAMELEN];
-
-+ if (IS_ENABLED(CONFIG_PROC_STRIPPED) && !IS_ENABLED(CONFIG_SMP))
-+ return;
-+
- if (!root_irq_dir || (desc->irq_data.chip == &no_irq_chip))
- return;
-
-@@ -394,6 +397,9 @@ void unregister_irq_proc(unsigned int ir
- {
- char name [MAX_NAMELEN];
-
-+ if (IS_ENABLED(CONFIG_PROC_STRIPPED) && !IS_ENABLED(CONFIG_SMP))
-+ return;
-+
- if (!root_irq_dir || !desc->dir)
- return;
- #ifdef CONFIG_SMP
-@@ -432,6 +438,9 @@ void init_irq_proc(void)
- unsigned int irq;
- struct irq_desc *desc;
-
-+ if (IS_ENABLED(CONFIG_PROC_STRIPPED) && !IS_ENABLED(CONFIG_SMP))
-+ return;
-+
- /* create /proc/irq */
- root_irq_dir = proc_mkdir("irq", NULL);
- if (!root_irq_dir)
---- a/kernel/time/timer_list.c
-+++ b/kernel/time/timer_list.c
-@@ -350,6 +350,8 @@ static int __init init_timer_list_procfs
- {
- struct proc_dir_entry *pe;
-
-+ if (IS_ENABLED(CONFIG_PROC_STRIPPED))
-+ return 0;
- pe = proc_create_seq_private("timer_list", 0400, NULL, &timer_list_sops,
- sizeof(struct timer_list_iter), NULL);
- if (!pe)
---- a/mm/vmalloc.c
-+++ b/mm/vmalloc.c
-@@ -4458,6 +4458,8 @@ static const struct seq_operations vmall
-
- static int __init proc_vmalloc_init(void)
- {
-+ if (IS_ENABLED(CONFIG_PROC_STRIPPED))
-+ return 0;
- if (IS_ENABLED(CONFIG_NUMA))
- proc_create_seq_private("vmallocinfo", 0400, NULL,
- &vmalloc_op,
---- a/mm/vmstat.c
-+++ b/mm/vmstat.c
-@@ -2137,10 +2137,12 @@ void __init init_mm_internals(void)
- start_shepherd_timer();
- #endif
- #ifdef CONFIG_PROC_FS
-- proc_create_seq("buddyinfo", 0444, NULL, &fragmentation_op);
-- proc_create_seq("pagetypeinfo", 0400, NULL, &pagetypeinfo_op);
-+ if (!IS_ENABLED(CONFIG_PROC_STRIPPED)) {
-+ proc_create_seq("buddyinfo", 0444, NULL, &fragmentation_op);
-+ proc_create_seq("pagetypeinfo", 0400, NULL, &pagetypeinfo_op);
-+ proc_create_seq("zoneinfo", 0444, NULL, &zoneinfo_op);
-+ }
- proc_create_seq("vmstat", 0444, NULL, &vmstat_op);
-- proc_create_seq("zoneinfo", 0444, NULL, &zoneinfo_op);
- #endif
- }
-
---- a/net/8021q/vlanproc.c
-+++ b/net/8021q/vlanproc.c
-@@ -93,6 +93,9 @@ void vlan_proc_cleanup(struct net *net)
- {
- struct vlan_net *vn = net_generic(net, vlan_net_id);
-
-+ if (IS_ENABLED(CONFIG_PROC_STRIPPED))
-+ return;
-+
- if (vn->proc_vlan_conf)
- remove_proc_entry(name_conf, vn->proc_vlan_dir);
-
-@@ -112,6 +115,9 @@ int __net_init vlan_proc_init(struct net
- {
- struct vlan_net *vn = net_generic(net, vlan_net_id);
-
-+ if (IS_ENABLED(CONFIG_PROC_STRIPPED))
-+ return 0;
-+
- vn->proc_vlan_dir = proc_net_mkdir(net, name_root, net->proc_net);
- if (!vn->proc_vlan_dir)
- goto err;
---- a/net/core/net-procfs.c
-+++ b/net/core/net-procfs.c
-@@ -327,10 +327,12 @@ static int __net_init dev_proc_net_init(
- if (!proc_create_net("dev", 0444, net->proc_net, &dev_seq_ops,
- sizeof(struct seq_net_private)))
- goto out;
-- if (!proc_create_seq("softnet_stat", 0444, net->proc_net,
-+ if (!IS_ENABLED(CONFIG_PROC_STRIPPED) &&
-+ !proc_create_seq("softnet_stat", 0444, net->proc_net,
- &softnet_seq_ops))
- goto out_dev;
-- if (!proc_create_net("ptype", 0444, net->proc_net, &ptype_seq_ops,
-+ if (!IS_ENABLED(CONFIG_PROC_STRIPPED) &&
-+ !proc_create_net("ptype", 0444, net->proc_net, &ptype_seq_ops,
- sizeof(struct seq_net_private)))
- goto out_softnet;
-
-@@ -340,9 +342,11 @@ static int __net_init dev_proc_net_init(
- out:
- return rc;
- out_ptype:
-- remove_proc_entry("ptype", net->proc_net);
-+ if (!IS_ENABLED(CONFIG_PROC_STRIPPED))
-+ remove_proc_entry("ptype", net->proc_net);
- out_softnet:
-- remove_proc_entry("softnet_stat", net->proc_net);
-+ if (!IS_ENABLED(CONFIG_PROC_STRIPPED))
-+ remove_proc_entry("softnet_stat", net->proc_net);
- out_dev:
- remove_proc_entry("dev", net->proc_net);
- goto out;
-@@ -352,8 +356,10 @@ static void __net_exit dev_proc_net_exit
- {
- wext_proc_exit(net);
-
-- remove_proc_entry("ptype", net->proc_net);
-- remove_proc_entry("softnet_stat", net->proc_net);
-+ if (!IS_ENABLED(CONFIG_PROC_STRIPPED)) {
-+ remove_proc_entry("ptype", net->proc_net);
-+ remove_proc_entry("softnet_stat", net->proc_net);
-+ }
- remove_proc_entry("dev", net->proc_net);
- }
-
---- a/net/core/sock.c
-+++ b/net/core/sock.c
-@@ -4168,6 +4168,8 @@ static __net_initdata struct pernet_oper
-
- static int __init proto_init(void)
- {
-+ if (IS_ENABLED(CONFIG_PROC_STRIPPED))
-+ return 0;
- return register_pernet_subsys(&proto_net_ops);
- }
-
---- a/net/ipv4/fib_trie.c
-+++ b/net/ipv4/fib_trie.c
-@@ -3015,11 +3015,13 @@ static const struct seq_operations fib_r
-
- int __net_init fib_proc_init(struct net *net)
- {
-- if (!proc_create_net("fib_trie", 0444, net->proc_net, &fib_trie_seq_ops,
-+ if (!IS_ENABLED(CONFIG_PROC_STRIPPED) &&
-+ !proc_create_net("fib_trie", 0444, net->proc_net, &fib_trie_seq_ops,
- sizeof(struct fib_trie_iter)))
- goto out1;
-
-- if (!proc_create_net_single("fib_triestat", 0444, net->proc_net,
-+ if (!IS_ENABLED(CONFIG_PROC_STRIPPED) &&
-+ !proc_create_net_single("fib_triestat", 0444, net->proc_net,
- fib_triestat_seq_show, NULL))
- goto out2;
-
-@@ -3030,17 +3032,21 @@ int __net_init fib_proc_init(struct net
- return 0;
-
- out3:
-- remove_proc_entry("fib_triestat", net->proc_net);
-+ if (!IS_ENABLED(CONFIG_PROC_STRIPPED))
-+ remove_proc_entry("fib_triestat", net->proc_net);
- out2:
-- remove_proc_entry("fib_trie", net->proc_net);
-+ if (!IS_ENABLED(CONFIG_PROC_STRIPPED))
-+ remove_proc_entry("fib_trie", net->proc_net);
- out1:
- return -ENOMEM;
- }
-
- void __net_exit fib_proc_exit(struct net *net)
- {
-- remove_proc_entry("fib_trie", net->proc_net);
-- remove_proc_entry("fib_triestat", net->proc_net);
-+ if (!IS_ENABLED(CONFIG_PROC_STRIPPED)) {
-+ remove_proc_entry("fib_trie", net->proc_net);
-+ remove_proc_entry("fib_triestat", net->proc_net);
-+ }
- remove_proc_entry("route", net->proc_net);
- }
-
---- a/net/ipv4/proc.c
-+++ b/net/ipv4/proc.c
-@@ -557,5 +557,8 @@ static __net_initdata struct pernet_oper
-
- int __init ip_misc_proc_init(void)
- {
-+ if (IS_ENABLED(CONFIG_PROC_STRIPPED))
-+ return 0;
-+
- return register_pernet_subsys(&ip_proc_ops);
- }
---- a/net/ipv4/route.c
-+++ b/net/ipv4/route.c
-@@ -385,6 +385,9 @@ static struct pernet_operations ip_rt_pr
-
- static int __init ip_rt_proc_init(void)
- {
-+ if (IS_ENABLED(CONFIG_PROC_STRIPPED))
-+ return 0;
-+
- return register_pernet_subsys(&ip_rt_proc_ops);
- }
-
---- a/net/ipv4/inet_timewait_sock.c
-+++ b/net/ipv4/inet_timewait_sock.c
-@@ -266,7 +266,7 @@ void __inet_twsk_schedule(struct inet_ti
- */
-
- if (!rearm) {
-- bool kill = timeo <= 4*HZ;
-+ bool __maybe_unused kill = timeo <= 4*HZ;
-
- __NET_INC_STATS(twsk_net(tw), kill ? LINUX_MIB_TIMEWAITKILLED :
- LINUX_MIB_TIMEWAITED);
+++ /dev/null
-From e3692cb2fcd5ba1244512a0f43b8118f65f1c375 Mon Sep 17 00:00:00 2001
-Date: Sat, 8 Jul 2017 08:20:43 +0200
-Subject: debloat: dmabuf
-
----
- drivers/base/Kconfig | 2 +-
- drivers/dma-buf/Makefile | 10 +++++++---
- drivers/dma-buf/dma-buf.c | 4 +++-
- kernel/sched/core.c | 1 +
- 4 files changed, 12 insertions(+), 5 deletions(-)
-
---- a/drivers/base/Kconfig
-+++ b/drivers/base/Kconfig
-@@ -198,7 +198,7 @@ config SOC_BUS
- source "drivers/base/regmap/Kconfig"
-
- config DMA_SHARED_BUFFER
-- bool
-+ tristate
- default n
- select IRQ_WORK
- help
---- a/drivers/dma-buf/heaps/Makefile
-+++ b/drivers/dma-buf/heaps/Makefile
-@@ -1,3 +1,3 @@
- # SPDX-License-Identifier: GPL-2.0
--obj-$(CONFIG_DMABUF_HEAPS_SYSTEM) += system_heap.o
--obj-$(CONFIG_DMABUF_HEAPS_CMA) += cma_heap.o
-+dma-buf-objs-$(CONFIG_DMABUF_HEAPS_SYSTEM) += system_heap.o
-+dma-buf-objs-$(CONFIG_DMABUF_HEAPS_CMA) += cma_heap.o
---- a/drivers/dma-buf/Makefile
-+++ b/drivers/dma-buf/Makefile
-@@ -1,12 +1,14 @@
- # SPDX-License-Identifier: GPL-2.0-only
--obj-y := dma-buf.o dma-fence.o dma-fence-array.o dma-fence-chain.o \
-+obj-$(CONFIG_DMA_SHARED_BUFFER) := dma-shared-buffer.o
-+
-+dma-buf-objs-y := dma-buf.o dma-fence.o dma-fence-array.o dma-fence-chain.o \
- dma-fence-unwrap.o dma-resv.o
--obj-$(CONFIG_DMABUF_HEAPS) += dma-heap.o
--obj-$(CONFIG_DMABUF_HEAPS) += heaps/
--obj-$(CONFIG_SYNC_FILE) += sync_file.o
--obj-$(CONFIG_SW_SYNC) += sw_sync.o sync_debug.o
--obj-$(CONFIG_UDMABUF) += udmabuf.o
--obj-$(CONFIG_DMABUF_SYSFS_STATS) += dma-buf-sysfs-stats.o
-+dma-buf-objs-$(CONFIG_DMABUF_HEAPS) += dma-heap.o
-+obj-$(CONFIG_DMABUF_HEAPS) += heaps/
-+dma-buf-objs-$(CONFIG_SYNC_FILE) += sync_file.o
-+dma-buf-objs-$(CONFIG_SW_SYNC) += sw_sync.o sync_debug.o
-+dma-buf-objs-$(CONFIG_UDMABUF) += udmabuf.o
-+dma-buf-objs-$(CONFIG_DMABUF_SYSFS_STATS) += dma-buf-sysfs-stats.o
-
- dmabuf_selftests-y := \
- selftest.o \
-@@ -15,4 +17,6 @@ dmabuf_selftests-y := \
- st-dma-fence-unwrap.o \
- st-dma-resv.o
-
--obj-$(CONFIG_DMABUF_SELFTESTS) += dmabuf_selftests.o
-+dma-buf-objs-$(CONFIG_DMABUF_SELFTESTS) += dmabuf_selftests.o
-+
-+dma-shared-buffer-objs := $(dma-buf-objs-y)
---- a/drivers/dma-buf/dma-buf.c
-+++ b/drivers/dma-buf/dma-buf.c
-@@ -1731,4 +1731,5 @@ static void __exit dma_buf_deinit(void)
- kern_unmount(dma_buf_mnt);
- dma_buf_uninit_sysfs_statistics();
- }
--__exitcall(dma_buf_deinit);
-+module_exit(dma_buf_deinit);
-+MODULE_LICENSE("GPL");
---- a/kernel/sched/core.c
-+++ b/kernel/sched/core.c
-@@ -4485,6 +4485,7 @@ int wake_up_state(struct task_struct *p,
- {
- return try_to_wake_up(p, state, 0);
- }
-+EXPORT_SYMBOL_GPL(wake_up_state);
-
- /*
- * Perform scheduler related setup for a newly forked process p.
---- a/fs/d_path.c
-+++ b/fs/d_path.c
-@@ -314,6 +314,7 @@ char *dynamic_dname(char *buffer, int bu
- buffer += buflen - sz;
- return memcpy(buffer, temp, sz);
- }
-+EXPORT_SYMBOL_GPL(dynamic_dname);
-
- char *simple_dname(struct dentry *dentry, char *buffer, int buflen)
- {
+++ /dev/null
-From 0d37e6edc09c99e683dd91ca0e83bbc0df8477b3 Mon Sep 17 00:00:00 2001
-Date: Sun, 16 Jul 2017 16:56:10 +0200
-Subject: lib: add uevent_next_seqnum()
-
----
- include/linux/kobject.h | 5 +++++
- lib/kobject_uevent.c | 37 +++++++++++++++++++++++++++++++++++++
- 2 files changed, 42 insertions(+)
-
---- a/lib/kobject_uevent.c
-+++ b/lib/kobject_uevent.c
-@@ -179,6 +179,18 @@ out:
- return r;
- }
-
-+u64 uevent_next_seqnum(void)
-+{
-+ u64 seq;
-+
-+ mutex_lock(&uevent_sock_mutex);
-+ seq = ++uevent_seqnum;
-+ mutex_unlock(&uevent_sock_mutex);
-+
-+ return seq;
-+}
-+EXPORT_SYMBOL_GPL(uevent_next_seqnum);
-+
- /**
- * kobject_synth_uevent - send synthetic uevent with arguments
- *
+++ /dev/null
-From 0d37e6edc09c99e683dd91ca0e83bbc0df8477b3 Mon Sep 17 00:00:00 2001
-Date: Sun, 16 Jul 2017 16:56:10 +0200
-Subject: lib: add broadcast_uevent()
-
----
- include/linux/kobject.h | 5 +++++
- lib/kobject_uevent.c | 37 +++++++++++++++++++++++++++++++++++++
- 2 files changed, 42 insertions(+)
-
---- a/include/linux/kobject.h
-+++ b/include/linux/kobject.h
-@@ -32,6 +32,8 @@
- #define UEVENT_NUM_ENVP 64 /* number of env pointers */
- #define UEVENT_BUFFER_SIZE 2048 /* buffer for the variables */
-
-+struct sk_buff;
-+
- #ifdef CONFIG_UEVENT_HELPER
- /* path to the userspace helper executed on an event */
- extern char uevent_helper[];
-@@ -219,4 +221,7 @@ int kobject_synth_uevent(struct kobject
- __printf(2, 3)
- int add_uevent_var(struct kobj_uevent_env *env, const char *format, ...);
-
-+int broadcast_uevent(struct sk_buff *skb, __u32 pid, __u32 group,
-+ gfp_t allocation);
-+
- #endif /* _KOBJECT_H_ */
---- a/lib/kobject_uevent.c
-+++ b/lib/kobject_uevent.c
-@@ -706,6 +706,43 @@ int add_uevent_var(struct kobj_uevent_en
- EXPORT_SYMBOL_GPL(add_uevent_var);
-
- #if defined(CONFIG_NET)
-+int broadcast_uevent(struct sk_buff *skb, __u32 pid, __u32 group,
-+ gfp_t allocation)
-+{
-+ struct uevent_sock *ue_sk;
-+ int err = 0;
-+
-+ /* send netlink message */
-+ mutex_lock(&uevent_sock_mutex);
-+ list_for_each_entry(ue_sk, &uevent_sock_list, list) {
-+ struct sock *uevent_sock = ue_sk->sk;
-+ struct sk_buff *skb2;
-+
-+ skb2 = skb_clone(skb, allocation);
-+ if (!skb2)
-+ break;
-+
-+ err = netlink_broadcast(uevent_sock, skb2, pid, group,
-+ allocation);
-+ if (err)
-+ break;
-+ }
-+ mutex_unlock(&uevent_sock_mutex);
-+
-+ kfree_skb(skb);
-+ return err;
-+}
-+#else
-+int broadcast_uevent(struct sk_buff *skb, __u32 pid, __u32 group,
-+ gfp_t allocation)
-+{
-+ kfree_skb(skb);
-+ return 0;
-+}
-+#endif
-+EXPORT_SYMBOL_GPL(broadcast_uevent);
-+
-+#if defined(CONFIG_NET)
- static int uevent_net_broadcast(struct sock *usk, struct sk_buff *skb,
- struct netlink_ext_ack *extack)
- {
+++ /dev/null
-From e08bcbbaa52fcc41f02743fd2e62a33255ce52da Mon Sep 17 00:00:00 2001
-Date: Wed, 13 Jul 2022 13:52:28 +0200
-Subject: [PATCH] of/ftd: add device tree cmdline
-
----
- drivers/of/fdt.c | 3 +++
- 1 file changed, 3 insertions(+)
-
---- a/drivers/of/fdt.c
-+++ b/drivers/of/fdt.c
-@@ -1186,6 +1186,9 @@ int __init early_init_dt_scan_chosen(cha
- p = of_get_flat_dt_prop(node, "bootargs", &l);
- if (p != NULL && l > 0)
- strscpy(cmdline, p, min(l, COMMAND_LINE_SIZE));
-+ p = of_get_flat_dt_prop(node, "bootargs-append", &l);
-+ if (p != NULL && l > 0)
-+ strlcat(cmdline, p, min_t(int, strlen(cmdline) + (int)l, COMMAND_LINE_SIZE));
-
- handle_cmdline:
- /*
+++ /dev/null
-Date: Tue, 19 Jul 2022 06:17:48 +0200
-Subject: [PATCH] Revert "Revert "Revert "driver core: Set fw_devlink=on by
- default"""
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-This reverts commit ea718c699055c8566eb64432388a04974c43b2ea.
-
-With of_platform_populate() called for MTD partitions that commit breaks
-probing devices which reference MTD in device tree.
-
----
- drivers/base/core.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/base/core.c
-+++ b/drivers/base/core.c
-@@ -1658,7 +1658,7 @@ static void device_links_purge(struct de
- #define FW_DEVLINK_FLAGS_RPM (FW_DEVLINK_FLAGS_ON | \
- DL_FLAG_PM_RUNTIME)
-
--static u32 fw_devlink_flags = FW_DEVLINK_FLAGS_ON;
-+static u32 fw_devlink_flags = FW_DEVLINK_FLAGS_PERMISSIVE;
- static int __init fw_devlink_setup(char *arg)
- {
- if (!arg)
+++ /dev/null
-LINUX_VERSION-6.6 = .117
-LINUX_KERNEL_HASH-6.6.117 = 643b31079222fdbda70cfdd0b68c514f05a3926104be4762a4685f62818b43d1
+++ /dev/null
-Date: Thu, 22 Oct 2020 22:00:03 +0200
-Subject: [PATCH] compiler.h: only include asm/rwonce.h for kernel code
-
-This header file is not in uapi, which makes any user space code that includes
-linux/compiler.h to fail with the error 'asm/rwonce.h: No such file or directory'
-
-Fixes: e506ea451254 ("compiler.h: Split {READ,WRITE}_ONCE definitions out into rwonce.h")
----
-
---- a/include/linux/compiler.h
-+++ b/include/linux/compiler.h
-@@ -202,6 +202,8 @@ void ftrace_likely_update(struct ftrace_
- __v; \
- })
-
-+#include <asm/rwonce.h>
-+
- #endif /* __KERNEL__ */
-
- /**
-@@ -259,6 +261,4 @@ static inline void *offset_to_ptr(const
- */
- #define prevent_tail_call_optimization() mb()
-
--#include <asm/rwonce.h>
--
- #endif /* __LINUX_COMPILER_H */
+++ /dev/null
-Date: Wed, 18 Apr 2018 10:50:05 +0200
-Subject: [PATCH] MIPS: only process negative stack offsets on stack traces
-
-Fixes endless back traces in cases where the compiler emits a stack
-pointer increase in a branch delay slot (probably for some form of
-function return).
-
-[ 3.475442] BUG: MAX_STACK_TRACE_ENTRIES too low!
-[ 3.480070] turning off the locking correctness validator.
-[ 3.485521] CPU: 0 PID: 1 Comm: swapper/0 Not tainted 4.14.34 #0
-[ 3.491475] Stack : 00000000 00000000 00000000 00000000 80e0fce2 00000034 00000000 00000000
-[ 3.499764] 87c3838c 80696377 8061047c 00000000 00000001 00000001 87c2d850 6534689f
-[ 3.508059] 00000000 00000000 80e10000 00000000 00000000 000000cf 0000000f 00000000
-[ 3.516353] 00000000 806a0000 00076891 00000000 00000000 00000000 ffffffff 00000000
-[ 3.524648] 806c0000 00000004 80e10000 806a0000 00000003 80690000 00000000 80700000
-[ 3.532942] ...
-[ 3.535362] Call Trace:
-[ 3.537818] [<80010a48>] show_stack+0x58/0x100
-[ 3.542207] [<804c2f78>] dump_stack+0xe8/0x170
-[ 3.546613] [<80079f90>] save_trace+0xf0/0x110
-[ 3.551010] [<8007b1ec>] mark_lock+0x33c/0x78c
-[ 3.555413] [<8007bf48>] __lock_acquire+0x2ac/0x1a08
-[ 3.560337] [<8007de60>] lock_acquire+0x64/0x8c
-[ 3.564846] [<804e1570>] _raw_spin_lock_irqsave+0x54/0x78
-[ 3.570186] [<801b618c>] kernfs_notify+0x94/0xac
-[ 3.574770] [<801b7b10>] sysfs_notify+0x74/0xa0
-[ 3.579257] [<801b618c>] kernfs_notify+0x94/0xac
-[ 3.583839] [<801b7b10>] sysfs_notify+0x74/0xa0
-[ 3.588329] [<801b618c>] kernfs_notify+0x94/0xac
-[ 3.592911] [<801b7b10>] sysfs_notify+0x74/0xa0
-[ 3.597401] [<801b618c>] kernfs_notify+0x94/0xac
-[ 3.601983] [<801b7b10>] sysfs_notify+0x74/0xa0
-[ 3.606473] [<801b618c>] kernfs_notify+0x94/0xac
-[ 3.611055] [<801b7b10>] sysfs_notify+0x74/0xa0
-[ 3.615545] [<801b618c>] kernfs_notify+0x94/0xac
-[ 3.620125] [<801b7b10>] sysfs_notify+0x74/0xa0
-[ 3.624619] [<801b618c>] kernfs_notify+0x94/0xac
-[ 3.629197] [<801b7b10>] sysfs_notify+0x74/0xa0
-[ 3.633691] [<801b618c>] kernfs_notify+0x94/0xac
-[ 3.638269] [<801b7b10>] sysfs_notify+0x74/0xa0
-[ 3.642763] [<801b618c>] kernfs_notify+0x94/0xac
-
----
-
---- a/arch/mips/kernel/process.c
-+++ b/arch/mips/kernel/process.c
-@@ -395,6 +395,8 @@ static inline int is_sp_move_ins(union m
-
- if (ip->i_format.opcode == addiu_op ||
- ip->i_format.opcode == daddiu_op) {
-+ if (ip->i_format.simmediate > 0)
-+ return 0;
- *frame_size = -ip->i_format.simmediate;
- return 1;
- }
+++ /dev/null
-From 173019b66dcc9d68ad9333aa744dad1e369b5aa8 Mon Sep 17 00:00:00 2001
-Date: Sun, 9 Jul 2017 00:26:53 +0200
-Subject: [PATCH 34/34] kernel: add compile fix for linux 4.9 on x86
-
----
- Makefile | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
---- a/Makefile
-+++ b/Makefile
-@@ -599,7 +599,7 @@ endif
- # Allows the usage of unstable features in stable compilers.
- export RUSTC_BOOTSTRAP := 1
-
--export ARCH SRCARCH CONFIG_SHELL BASH HOSTCC KBUILD_HOSTCFLAGS CROSS_COMPILE LD CC HOSTPKG_CONFIG
-+export ARCH SRCARCH SUBARCH CONFIG_SHELL BASH HOSTCC KBUILD_HOSTCFLAGS CROSS_COMPILE LD CC HOSTPKG_CONFIG
- export RUSTC RUSTDOC RUSTFMT RUSTC_OR_CLIPPY_QUIET RUSTC_OR_CLIPPY BINDGEN CARGO
- export HOSTRUSTC KBUILD_HOSTRUSTFLAGS
- export CPP AR NM STRIP OBJCOPY OBJDUMP READELF PAHOLE RESOLVE_BTFIDS LEX YACC AWK INSTALLKERNEL
+++ /dev/null
-From bd1b9f66d5134e518419f4c4dacf1884c1616983 Mon Sep 17 00:00:00 2001
-Date: Thu, 28 Apr 2022 11:13:23 +0200
-Subject: [PATCH] watchdog: max63xx_wdt: Add support for specifying WDI logic
- via GPIO
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-On some boards is WDI logic of max6370 chip connected via GPIO.
-So extend max63xx_wdt driver to allow specifying WDI logic via GPIO.
-
----
- drivers/watchdog/max63xx_wdt.c | 24 ++++++++++++++++++++++++
- 1 file changed, 24 insertions(+)
-
---- a/drivers/watchdog/max63xx_wdt.c
-+++ b/drivers/watchdog/max63xx_wdt.c
-@@ -24,6 +24,7 @@
- #include <linux/io.h>
- #include <linux/slab.h>
- #include <linux/property.h>
-+#include <linux/gpio/consumer.h>
-
- #define DEFAULT_HEARTBEAT 60
- #define MAX_HEARTBEAT 60
-@@ -50,6 +51,9 @@ struct max63xx_wdt {
- void __iomem *base;
- spinlock_t lock;
-
-+ /* GPIOs */
-+ struct gpio_desc *gpio_wdi;
-+
- /* WDI and WSET bits write access routines */
- void (*ping)(struct max63xx_wdt *wdt);
- void (*set)(struct max63xx_wdt *wdt, u8 set);
-@@ -155,6 +159,17 @@ static const struct watchdog_info max63x
- .identity = "max63xx Watchdog",
- };
-
-+static void max63xx_gpio_ping(struct max63xx_wdt *wdt)
-+{
-+ spin_lock(&wdt->lock);
-+
-+ gpiod_set_value(wdt->gpio_wdi, 1);
-+ udelay(1);
-+ gpiod_set_value(wdt->gpio_wdi, 0);
-+
-+ spin_unlock(&wdt->lock);
-+}
-+
- static void max63xx_mmap_ping(struct max63xx_wdt *wdt)
- {
- u8 val;
-@@ -222,10 +237,19 @@ static int max63xx_wdt_probe(struct plat
- return -EINVAL;
- }
-
-+ wdt->gpio_wdi = devm_gpiod_get(dev, NULL, GPIOD_FLAGS_BIT_DIR_OUT);
-+ if (IS_ERR(wdt->gpio_wdi) && PTR_ERR(wdt->gpio_wdi) != -ENOENT)
-+ return dev_err_probe(dev, PTR_ERR(wdt->gpio_wdi),
-+ "unable to request gpio: %ld\n",
-+ PTR_ERR(wdt->gpio_wdi));
-+
- err = max63xx_mmap_init(pdev, wdt);
- if (err)
- return err;
-
-+ if (!IS_ERR(wdt->gpio_wdi))
-+ wdt->ping = max63xx_gpio_ping;
-+
- platform_set_drvdata(pdev, &wdt->wdd);
- watchdog_set_drvdata(&wdt->wdd, wdt);
-
+++ /dev/null
-Subject: jffs2: use .rename2 and add RENAME_WHITEOUT support
-
-It is required for renames on overlayfs
-
----
-
---- a/fs/jffs2/dir.c
-+++ b/fs/jffs2/dir.c
-@@ -617,8 +617,8 @@ static int jffs2_rmdir (struct inode *di
- return ret;
- }
-
--static int jffs2_mknod (struct mnt_idmap *idmap, struct inode *dir_i,
-- struct dentry *dentry, umode_t mode, dev_t rdev)
-+static int __jffs2_mknod (struct mnt_idmap *idmap, struct inode *dir_i,
-+ struct dentry *dentry, umode_t mode, dev_t rdev, bool whiteout)
- {
- struct jffs2_inode_info *f, *dir_f;
- struct jffs2_sb_info *c;
-@@ -758,7 +758,11 @@ static int jffs2_mknod (struct mnt_idmap
- mutex_unlock(&dir_f->sem);
- jffs2_complete_reservation(c);
-
-- d_instantiate_new(dentry, inode);
-+ if (!whiteout)
-+ d_instantiate_new(dentry, inode);
-+ else
-+ unlock_new_inode(inode);
-+
- return 0;
-
- fail:
-@@ -766,6 +770,19 @@ static int jffs2_mknod (struct mnt_idmap
- return ret;
- }
-
-+static int jffs2_mknod (struct mnt_idmap *idmap, struct inode *dir_i,
-+ struct dentry *dentry, umode_t mode, dev_t rdev)
-+{
-+ return __jffs2_mknod(idmap, dir_i, dentry, mode, rdev, false);
-+}
-+
-+static int jffs2_whiteout (struct mnt_idmap *idmap, struct inode *old_dir,
-+ struct dentry *old_dentry)
-+{
-+ return __jffs2_mknod(idmap, old_dir, old_dentry, S_IFCHR | WHITEOUT_MODE,
-+ WHITEOUT_DEV, true);
-+}
-+
- static int jffs2_rename (struct mnt_idmap *idmap,
- struct inode *old_dir_i, struct dentry *old_dentry,
- struct inode *new_dir_i, struct dentry *new_dentry,
-@@ -777,7 +794,7 @@ static int jffs2_rename (struct mnt_idma
- uint8_t type;
- uint32_t now;
-
-- if (flags & ~RENAME_NOREPLACE)
-+ if (flags & ~(RENAME_NOREPLACE|RENAME_WHITEOUT))
- return -EINVAL;
-
- /* The VFS will check for us and prevent trying to rename a
-@@ -843,9 +860,14 @@ static int jffs2_rename (struct mnt_idma
- if (d_is_dir(old_dentry) && !victim_f)
- inc_nlink(new_dir_i);
-
-- /* Unlink the original */
-- ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i),
-- old_dentry->d_name.name, old_dentry->d_name.len, NULL, now);
-+ if (flags & RENAME_WHITEOUT)
-+ /* Replace with whiteout */
-+ ret = jffs2_whiteout(idmap, old_dir_i, old_dentry);
-+ else
-+ /* Unlink the original */
-+ ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i),
-+ old_dentry->d_name.name,
-+ old_dentry->d_name.len, NULL, now);
-
- /* We don't touch inode->i_nlink */
-
+++ /dev/null
-Subject: jffs2: add RENAME_EXCHANGE support
-
----
-
---- a/fs/jffs2/dir.c
-+++ b/fs/jffs2/dir.c
-@@ -791,18 +791,31 @@ static int jffs2_rename (struct mnt_idma
- int ret;
- struct jffs2_sb_info *c = JFFS2_SB_INFO(old_dir_i->i_sb);
- struct jffs2_inode_info *victim_f = NULL;
-+ struct inode *fst_inode = d_inode(old_dentry);
-+ struct inode *snd_inode = d_inode(new_dentry);
- uint8_t type;
- uint32_t now;
-
-- if (flags & ~(RENAME_NOREPLACE|RENAME_WHITEOUT))
-+ if (flags & ~(RENAME_NOREPLACE|RENAME_WHITEOUT|RENAME_EXCHANGE))
- return -EINVAL;
-
-+ if ((flags & RENAME_EXCHANGE) && (old_dir_i != new_dir_i)) {
-+ if (S_ISDIR(fst_inode->i_mode) && !S_ISDIR(snd_inode->i_mode)) {
-+ inc_nlink(new_dir_i);
-+ drop_nlink(old_dir_i);
-+ }
-+ else if (!S_ISDIR(fst_inode->i_mode) && S_ISDIR(snd_inode->i_mode)) {
-+ drop_nlink(new_dir_i);
-+ inc_nlink(old_dir_i);
-+ }
-+ }
-+
- /* The VFS will check for us and prevent trying to rename a
- * file over a directory and vice versa, but if it's a directory,
- * the VFS can't check whether the victim is empty. The filesystem
- * needs to do that for itself.
- */
-- if (d_really_is_positive(new_dentry)) {
-+ if (d_really_is_positive(new_dentry) && !(flags & RENAME_EXCHANGE)) {
- victim_f = JFFS2_INODE_INFO(d_inode(new_dentry));
- if (d_is_dir(new_dentry)) {
- struct jffs2_full_dirent *fd;
-@@ -837,7 +850,7 @@ static int jffs2_rename (struct mnt_idma
- if (ret)
- return ret;
-
-- if (victim_f) {
-+ if (victim_f && !(flags & RENAME_EXCHANGE)) {
- /* There was a victim. Kill it off nicely */
- if (d_is_dir(new_dentry))
- clear_nlink(d_inode(new_dentry));
-@@ -863,6 +876,12 @@ static int jffs2_rename (struct mnt_idma
- if (flags & RENAME_WHITEOUT)
- /* Replace with whiteout */
- ret = jffs2_whiteout(idmap, old_dir_i, old_dentry);
-+ else if (flags & RENAME_EXCHANGE)
-+ /* Replace the original */
-+ ret = jffs2_do_link(c, JFFS2_INODE_INFO(old_dir_i),
-+ d_inode(new_dentry)->i_ino, type,
-+ old_dentry->d_name.name, old_dentry->d_name.len,
-+ now);
- else
- /* Unlink the original */
- ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i),
-@@ -895,7 +914,7 @@ static int jffs2_rename (struct mnt_idma
- return ret;
- }
-
-- if (d_is_dir(old_dentry))
-+ if (d_is_dir(old_dentry) && !(flags & RENAME_EXCHANGE))
- drop_nlink(old_dir_i);
-
- old_dir_i->i_mtime = inode_set_ctime_to_ts(old_dir_i, ITIME(now));
+++ /dev/null
-Subject: jffs2: add splice ops
-
-Add splice_read using generic_file_splice_read.
-Add splice_write using iter_file_splice_write
-
----
-
---- a/fs/jffs2/file.c
-+++ b/fs/jffs2/file.c
-@@ -53,6 +53,8 @@ const struct file_operations jffs2_file_
- .open = generic_file_open,
- .read_iter = generic_file_read_iter,
- .write_iter = generic_file_write_iter,
-+ .splice_read = filemap_splice_read,
-+ .splice_write = iter_file_splice_write,
- .unlocked_ioctl=jffs2_ioctl,
- .mmap = generic_file_readonly_mmap,
- .fsync = jffs2_fsync,
+++ /dev/null
-Subject: bridge: allow receiption on disabled port
-
-When an ethernet device is enslaved to a bridge, and the bridge STP
-detects loss of carrier (or operational state down), then normally
-packet receiption is blocked.
-
-This breaks control applications like WPA which maybe expecting to
-receive packets to negotiate to bring link up. The bridge needs to
-block forwarding packets from these disabled ports, but there is no
-hard requirement to not allow local packet delivery.
-
-
---- a/net/bridge/br_input.c
-+++ b/net/bridge/br_input.c
-@@ -245,6 +245,9 @@ static void __br_handle_local_finish(str
- /* note: already called with rcu_read_lock */
- static int br_handle_local_finish(struct net *net, struct sock *sk, struct sk_buff *skb)
- {
-+ struct net_bridge_port *p = br_port_get_rcu(skb->dev);
-+
-+ if (p->state != BR_STATE_DISABLED)
- __br_handle_local_finish(skb);
-
- /* return 1 to signal the okfn() was called so it's ok to use the skb */
-@@ -416,6 +419,17 @@ forward:
- goto defer_stp_filtering;
-
- switch (p->state) {
-+ case BR_STATE_DISABLED:
-+ if (ether_addr_equal(p->br->dev->dev_addr, dest))
-+ skb->pkt_type = PACKET_HOST;
-+
-+ if (NF_HOOK(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING,
-+ dev_net(skb->dev), NULL, skb, skb->dev, NULL,
-+ br_handle_local_finish) == 1) {
-+ return RX_HANDLER_PASS;
-+ }
-+ break;
-+
- case BR_STATE_FORWARDING:
- case BR_STATE_LEARNING:
- defer_stp_filtering:
+++ /dev/null
-Date: Thu, 4 Jan 2024 15:21:21 +0100
-Subject: [PATCH] net: bridge: do not send arp replies if src and target hw
- addr is the same
-
-There are broken devices in the wild that handle duplicate IP address
-detection by sending out ARP requests for the IP that they received from a
-DHCP server and refuse the address if they get a reply.
-When proxyarp is enabled, they would go into a loop of requesting an address
-and then NAKing it again.
-
-Link: https://github.com/openwrt/openwrt/issues/14309
----
-
---- a/net/bridge/br_arp_nd_proxy.c
-+++ b/net/bridge/br_arp_nd_proxy.c
-@@ -204,7 +204,10 @@ void br_do_proxy_suppress_arp(struct sk_
- if ((p && (p->flags & BR_PROXYARP)) ||
- (f->dst && (f->dst->flags & BR_PROXYARP_WIFI)) ||
- br_is_neigh_suppress_enabled(f->dst, vid)) {
-- if (!vid)
-+ replied = true;
-+ if (!memcmp(n->ha, sha, dev->addr_len))
-+ replied = false;
-+ else if (!vid)
- br_arp_send(br, p, skb->dev, sip, tip,
- sha, n->ha, sha, 0, 0);
- else
-@@ -212,7 +215,6 @@ void br_do_proxy_suppress_arp(struct sk_
- sha, n->ha, sha,
- skb->vlan_proto,
- skb_vlan_tag_get(skb));
-- replied = true;
- }
-
- /* If we have replied or as long as we know the
+++ /dev/null
-From 71e5da46e78c1cd24e2feed251a2845327447ad8 Mon Sep 17 00:00:00 2001
-Date: Wed, 21 May 2025 23:27:04 +0200
-Subject: wireguard: global: add __nonstring annotations for unterminated
- strings
-
-When a character array without a terminating NUL character has a static
-initializer, GCC 15's -Wunterminated-string-initialization will only
-warn if the array lacks the "nonstring" attribute[1]. Mark the arrays
-with __nonstring to correctly identify the char array as "not a C string"
-and thereby eliminate the warning:
-
-../drivers/net/wireguard/cookie.c:29:56: warning: initializer-string for array of 'unsigned char' truncates NUL terminator but destination lacks 'nonstring' attribute (9 chars into 8 available) [-Wunterminated-string-initialization]
- 29 | static const u8 mac1_key_label[COOKIE_KEY_LABEL_LEN] = "mac1----";
- | ^~~~~~~~~~
-../drivers/net/wireguard/cookie.c:30:58: warning: initializer-string for array of 'unsigned char' truncates NUL terminator but destination lacks 'nonstring' attribute (9 chars into 8 available) [-Wunterminated-string-initialization]
- 30 | static const u8 cookie_key_label[COOKIE_KEY_LABEL_LEN] = "cookie--";
- | ^~~~~~~~~~
-../drivers/net/wireguard/noise.c:28:38: warning: initializer-string for array of 'unsigned char' truncates NUL terminator but destination lacks 'nonstring' attribute (38 chars into 37 available) [-Wunterminated-string-initialization]
- 28 | static const u8 handshake_name[37] = "Noise_IKpsk2_25519_ChaChaPoly_BLAKE2s";
- | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-../drivers/net/wireguard/noise.c:29:39: warning: initializer-string for array of 'unsigned char' truncates NUL terminator but destination lacks 'nonstring' attribute (35 chars into 34 available) [-Wunterminated-string-initialization]
- | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-The arrays are always used with their fixed size, so use __nonstring.
-
-Link: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117178 [1]
----
- drivers/net/wireguard/cookie.c | 4 ++--
- drivers/net/wireguard/noise.c | 4 ++--
- 2 files changed, 4 insertions(+), 4 deletions(-)
-
---- a/drivers/net/wireguard/cookie.c
-+++ b/drivers/net/wireguard/cookie.c
-@@ -26,8 +26,8 @@ void wg_cookie_checker_init(struct cooki
- }
-
- enum { COOKIE_KEY_LABEL_LEN = 8 };
--static const u8 mac1_key_label[COOKIE_KEY_LABEL_LEN] = "mac1----";
--static const u8 cookie_key_label[COOKIE_KEY_LABEL_LEN] = "cookie--";
-+static const u8 mac1_key_label[COOKIE_KEY_LABEL_LEN] __nonstring = "mac1----";
-+static const u8 cookie_key_label[COOKIE_KEY_LABEL_LEN] __nonstring = "cookie--";
-
- static void precompute_key(u8 key[NOISE_SYMMETRIC_KEY_LEN],
- const u8 pubkey[NOISE_PUBLIC_KEY_LEN],
---- a/drivers/net/wireguard/noise.c
-+++ b/drivers/net/wireguard/noise.c
-@@ -25,8 +25,8 @@
- * <- e, ee, se, psk, {}
- */
-
--static const u8 handshake_name[37] = "Noise_IKpsk2_25519_ChaChaPoly_BLAKE2s";
-+static const u8 handshake_name[37] __nonstring = "Noise_IKpsk2_25519_ChaChaPoly_BLAKE2s";
-+static const u8 identifier_name[34] __nonstring = "WireGuard v1 zx2c4
[email protected]";
- static u8 handshake_init_hash[NOISE_HASH_LEN] __ro_after_init;
- static u8 handshake_init_chaining_key[NOISE_HASH_LEN] __ro_after_init;
- static atomic64_t keypair_counter = ATOMIC64_INIT(0);
+++ /dev/null
-Subject: [PATCH 1/2] rtc: rs5c372: support alarms up to 1 week
-
-The Ricoh R2221x, R2223x, RS5C372, RV5C387A chips can handle 1 week
-alarms.
-
-Read the "wday" alarm register and convert it to a date to support up 1
-week in our driver.
-
----
- drivers/rtc/rtc-rs5c372.c | 48 ++++++++++++++++++++++++++++++++++-----
- 1 file changed, 42 insertions(+), 6 deletions(-)
-
---- a/drivers/rtc/rtc-rs5c372.c
-+++ b/drivers/rtc/rtc-rs5c372.c
-@@ -399,7 +399,9 @@ static int rs5c_read_alarm(struct device
- {
- struct i2c_client *client = to_i2c_client(dev);
- struct rs5c372 *rs5c = i2c_get_clientdata(client);
-- int status;
-+ int status, wday_offs;
-+ struct rtc_time rtc;
-+ unsigned long alarm_secs;
-
- status = rs5c_get_regs(rs5c);
- if (status < 0)
-@@ -409,6 +411,30 @@ static int rs5c_read_alarm(struct device
- t->time.tm_sec = 0;
- t->time.tm_min = bcd2bin(rs5c->regs[RS5C_REG_ALARM_A_MIN] & 0x7f);
- t->time.tm_hour = rs5c_reg2hr(rs5c, rs5c->regs[RS5C_REG_ALARM_A_HOURS]);
-+ t->time.tm_wday = ffs(rs5c->regs[RS5C_REG_ALARM_A_WDAY] & 0x7f) - 1;
-+
-+ /* determine the day, month and year based on alarm wday, taking as a
-+ * reference the current time from the rtc
-+ */
-+ status = rs5c372_rtc_read_time(dev, &rtc);
-+ if (status < 0)
-+ return status;
-+
-+ wday_offs = t->time.tm_wday - rtc.tm_wday;
-+ alarm_secs = mktime64(rtc.tm_year + 1900,
-+ rtc.tm_mon + 1,
-+ rtc.tm_mday + wday_offs,
-+ t->time.tm_hour,
-+ t->time.tm_min,
-+ t->time.tm_sec);
-+
-+ if (wday_offs < 0 || (wday_offs == 0 &&
-+ (t->time.tm_hour < rtc.tm_hour ||
-+ (t->time.tm_hour == rtc.tm_hour &&
-+ t->time.tm_min <= rtc.tm_min))))
-+ alarm_secs += 7 * 86400;
-+
-+ rtc_time64_to_tm(alarm_secs, &t->time);
-
- /* ... and status */
- t->enabled = !!(rs5c->regs[RS5C_REG_CTRL1] & RS5C_CTRL1_AALE);
-@@ -423,12 +449,20 @@ static int rs5c_set_alarm(struct device
- struct rs5c372 *rs5c = i2c_get_clientdata(client);
- int status, addr, i;
- unsigned char buf[3];
-+ struct rtc_time rtc_tm;
-+ unsigned long rtc_secs, alarm_secs;
-
-- /* only handle up to 24 hours in the future, like RTC_ALM_SET */
-- if (t->time.tm_mday != -1
-- || t->time.tm_mon != -1
-- || t->time.tm_year != -1)
-+ /* chip only can handle alarms up to one week in the future*/
-+ status = rs5c372_rtc_read_time(dev, &rtc_tm);
-+ if (status)
-+ return status;
-+ rtc_secs = rtc_tm_to_time64(&rtc_tm);
-+ alarm_secs = rtc_tm_to_time64(&t->time);
-+ if (alarm_secs >= rtc_secs + 7 * 86400) {
-+ dev_err(dev, "%s: alarm maximum is one week in the future (%d)\n",
-+ __func__, status);
- return -EINVAL;
-+ }
-
- /* REVISIT: round up tm_sec */
-
-@@ -449,7 +483,9 @@ static int rs5c_set_alarm(struct device
- /* set alarm */
- buf[0] = bin2bcd(t->time.tm_min);
- buf[1] = rs5c_hr2reg(rs5c, t->time.tm_hour);
-- buf[2] = 0x7f; /* any/all days */
-+ /* each bit is the day of the week, 0x7f means all days */
-+ buf[2] = (t->time.tm_wday >= 0 && t->time.tm_wday < 7) ?
-+ BIT(t->time.tm_wday) : 0x7f;
-
- for (i = 0; i < sizeof(buf); i++) {
- addr = RS5C_ADDR(RS5C_REG_ALARM_A_MIN + i);
+++ /dev/null
-Subject: [PATCH 2/2] rtc: rs5c372: let the alarm to be used as wakeup source
-
-Currently there is no use for the interrupts on the rs5c372 RTC and the
-wakealarm isn't enabled. There are some devices like NASes which use this
-RTC to wake up from the power off state when the INTR pin is activated by
-the alarm clock.
-
-Enable the alarm and let to be used as a wakeup source.
-
-Tested on a Buffalo LS421DE NAS.
-
----
- drivers/rtc/rtc-rs5c372.c | 16 ++++++++++++++++
- 1 file changed, 16 insertions(+)
-
---- a/drivers/rtc/rtc-rs5c372.c
-+++ b/drivers/rtc/rtc-rs5c372.c
-@@ -832,6 +832,7 @@ static int rs5c372_probe(struct i2c_clie
- int err = 0;
- int smbus_mode = 0;
- struct rs5c372 *rs5c372;
-+ bool rs5c372_can_wakeup_device = false;
-
- dev_dbg(&client->dev, "%s\n", __func__);
-
-@@ -868,6 +869,12 @@ static int rs5c372_probe(struct i2c_clie
- rs5c372->type = id->driver_data;
- }
-
-+#ifdef CONFIG_OF
-+ if(of_property_read_bool(client->dev.of_node,
-+ "wakeup-source"))
-+ rs5c372_can_wakeup_device = true;
-+#endif
-+
- /* we read registers 0x0f then 0x00-0x0f; skip the first one */
- rs5c372->regs = &rs5c372->buf[1];
- rs5c372->smbus = smbus_mode;
-@@ -901,6 +908,8 @@ static int rs5c372_probe(struct i2c_clie
- goto exit;
- }
-
-+ rs5c372->has_irq = 1;
-+
- /* if the oscillator lost power and no other software (like
- * the bootloader) set it up, do it here.
- *
-@@ -927,6 +936,10 @@ static int rs5c372_probe(struct i2c_clie
- );
-
- /* REVISIT use client->irq to register alarm irq ... */
-+ if (rs5c372_can_wakeup_device) {
-+ device_init_wakeup(&client->dev, true);
-+ }
-+
- rs5c372->rtc = devm_rtc_device_register(&client->dev,
- rs5c372_driver.driver.name,
- &rs5c372_rtc_ops, THIS_MODULE);
-@@ -940,6 +953,10 @@ static int rs5c372_probe(struct i2c_clie
- if (err)
- goto exit;
-
-+ /* the rs5c372 alarm only supports a minute accuracy */
-+ set_bit(RTC_FEATURE_ALARM_RES_MINUTE, rs5c372->rtc->features);
-+ clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, rs5c372->rtc->features);
-+
- return 0;
-
- exit:
+++ /dev/null
-From cf3d39cfd29ab7bcbd6aa79d4a2f132817969e3d Mon Sep 17 00:00:00 2001
-Date: Tue, 15 Apr 2025 23:16:40 +0200
-Subject: [PATCH] ARM: 9404/1: arm32: fix boot hang with
- HAVE_LD_DEAD_CODE_DATA_ELIMINATION
-
-It was reported that some SoC (mvebu based for example) hang on kernel
-loading. A variant of the feature was present in OpenWrt from long ago
-and adding the additional entry with KEEP, fix the problem.
-
-Fixes: ed0f94102251 ("ARM: 9404/1: arm32: enable HAVE_LD_DEAD_CODE_DATA_ELIMINATION")
----
- arch/arm/include/asm/vmlinux.lds.h | 10 +++++-----
- arch/arm/kernel/vmlinux.lds.S | 4 ++--
- 2 files changed, 7 insertions(+), 7 deletions(-)
-
---- a/arch/arm/include/asm/vmlinux.lds.h
-+++ b/arch/arm/include/asm/vmlinux.lds.h
-@@ -48,7 +48,7 @@
- #define IDMAP_TEXT \
- ALIGN_FUNCTION(); \
- __idmap_text_start = .; \
-- *(.idmap.text) \
-+ KEEP(*(.idmap.text)) \
- __idmap_text_end = .; \
-
- #define ARM_DISCARD \
-@@ -108,12 +108,12 @@
- . = ALIGN(8); \
- .ARM.unwind_idx : { \
- __start_unwind_idx = .; \
-- *(.ARM.exidx*) \
-+ KEEP(*(.ARM.exidx*)) \
- __stop_unwind_idx = .; \
- } \
- .ARM.unwind_tab : { \
- __start_unwind_tab = .; \
-- *(.ARM.extab*) \
-+ KEEP(*(.ARM.extab*)) \
- __stop_unwind_tab = .; \
- }
-
-@@ -125,7 +125,7 @@
- __vectors_lma = .; \
- OVERLAY 0xffff0000 : NOCROSSREFS AT(__vectors_lma) { \
- .vectors { \
-- *(.vectors) \
-+ KEEP(*(.vectors)) \
- } \
- .vectors.bhb.loop8 { \
- *(.vectors.bhb.loop8) \
-@@ -143,7 +143,7 @@
- \
- __stubs_lma = .; \
- .stubs ADDR(.vectors) + 0x1000 : AT(__stubs_lma) { \
-- *(.stubs) \
-+ KEEP(*(.stubs)) \
- } \
- ARM_LMA(__stubs, .stubs); \
- . = __stubs_lma + SIZEOF(.stubs); \
---- a/arch/arm/kernel/vmlinux.lds.S
-+++ b/arch/arm/kernel/vmlinux.lds.S
-@@ -104,13 +104,13 @@ SECTIONS
- }
- .init.tagtable : {
- __tagtable_begin = .;
-- *(.taglist.init)
-+ KEEP(*(.taglist.init))
- __tagtable_end = .;
- }
- #ifdef CONFIG_SMP_ON_UP
- .init.smpalt : {
- __smpalt_begin = .;
-- *(.alt.smp.init)
-+ KEEP(*(.alt.smp.init))
- __smpalt_end = .;
- }
- #endif
+++ /dev/null
-Subject: kernel: add a config option for keeping the kallsyms table uncompressed, saving ~9kb kernel size after lzma on ar71xx
-
-lede-commit: e0e3509b5ce2ccf93d4d67ea907613f5f7ec2eed
----
- init/Kconfig | 11 +++++++++++
- kernel/kallsyms.c | 8 ++++++++
- scripts/kallsyms.c | 12 ++++++++++++
- scripts/link-vmlinux.sh | 4 ++++
- 4 files changed, 35 insertions(+)
-
---- a/init/Kconfig
-+++ b/init/Kconfig
-@@ -1461,6 +1461,17 @@ config SYSCTL_ARCH_UNALIGN_ALLOW
- the unaligned access emulation.
- see arch/parisc/kernel/unaligned.c for reference
-
-+config KALLSYMS_UNCOMPRESSED
-+ bool "Keep kallsyms uncompressed"
-+ depends on KALLSYMS
-+ help
-+ Normally kallsyms contains compressed symbols (using a token table),
-+ reducing the uncompressed kernel image size. Keeping the symbol table
-+ uncompressed significantly improves the size of this part in compressed
-+ kernel images.
-+
-+ Say N unless you need compressed kernel images to be small.
-+
- config HAVE_PCSPKR_PLATFORM
- bool
-
---- a/kernel/kallsyms.c
-+++ b/kernel/kallsyms.c
-@@ -69,6 +69,11 @@ static unsigned int kallsyms_expand_symb
- * For every byte on the compressed symbol data, copy the table
- * entry for that byte.
- */
-+#ifdef CONFIG_KALLSYMS_UNCOMPRESSED
-+ memcpy(result, data + 1, len - 1);
-+ result += len - 1;
-+ len = 0;
-+#endif
- while (len) {
- tptr = &kallsyms_token_table[kallsyms_token_index[*data]];
- data++;
-@@ -101,6 +106,9 @@ tail:
- */
- static char kallsyms_get_symbol_type(unsigned int off)
- {
-+#ifdef CONFIG_KALLSYMS_UNCOMPRESSED
-+ return kallsyms_names[off + 1];
-+#endif
- /*
- * Get just the first code, look it up in the token table,
- * and return the first char from this token.
---- a/scripts/kallsyms.c
-+++ b/scripts/kallsyms.c
-@@ -62,6 +62,7 @@ static struct addr_range percpu_range =
- static struct sym_entry **table;
- static unsigned int table_size, table_cnt;
- static int all_symbols;
-+static int uncompressed;
- static int absolute_percpu;
- static int base_relative;
- static int lto_clang;
-@@ -453,13 +454,15 @@ static void write_src(void)
- }
- printf("\n");
-
-- /*
-- * Now that we wrote out the compressed symbol names, restore the
-- * original names, which are needed in some of the later steps.
-- */
-- for (i = 0; i < table_cnt; i++) {
-- expand_symbol(table[i]->sym, table[i]->len, buf);
-- strcpy((char *)table[i]->sym, buf);
-+ if (!uncompressed) {
-+ /*
-+ * Now that we wrote out the compressed symbol names, restore the
-+ * original names, which are needed in some of the later steps.
-+ */
-+ for (i = 0; i < table_cnt; i++) {
-+ expand_symbol(table[i]->sym, table[i]->len, buf);
-+ strcpy((char *)table[i]->sym, buf);
-+ }
- }
-
- output_label("kallsyms_markers");
-@@ -469,20 +472,22 @@ static void write_src(void)
-
- free(markers);
-
-- output_label("kallsyms_token_table");
-- off = 0;
-- for (i = 0; i < 256; i++) {
-- best_idx[i] = off;
-- expand_symbol(best_table[i], best_table_len[i], buf);
-- printf("\t.asciz\t\"%s\"\n", buf);
-- off += strlen(buf) + 1;
-- }
-- printf("\n");
-+ if (!uncompressed) {
-+ output_label("kallsyms_token_table");
-+ off = 0;
-+ for (i = 0; i < 256; i++) {
-+ best_idx[i] = off;
-+ expand_symbol(best_table[i], best_table_len[i], buf);
-+ printf("\t.asciz\t\"%s\"\n", buf);
-+ off += strlen(buf) + 1;
-+ }
-+ printf("\n");
-
-- output_label("kallsyms_token_index");
-- for (i = 0; i < 256; i++)
-- printf("\t.short\t%d\n", best_idx[i]);
-- printf("\n");
-+ output_label("kallsyms_token_index");
-+ for (i = 0; i < 256; i++)
-+ printf("\t.short\t%d\n", best_idx[i]);
-+ printf("\n");
-+ }
-
- if (!base_relative)
- output_label("kallsyms_addresses");
-@@ -582,6 +587,9 @@ static unsigned char *find_token(unsigne
- {
- int i;
-
-+ if (uncompressed)
-+ return NULL;
-+
- for (i = 0; i < len - 1; i++) {
- if (str[i] == token[0] && str[i+1] == token[1])
- return &str[i];
-@@ -654,6 +662,9 @@ static void optimize_result(void)
- {
- int i, best;
-
-+ if (uncompressed)
-+ return;
-+
- /* using the '\0' symbol last allows compress_symbols to use standard
- * fast string functions */
- for (i = 255; i >= 0; i--) {
-@@ -815,6 +826,7 @@ int main(int argc, char **argv)
- {"absolute-percpu", no_argument, &absolute_percpu, 1},
- {"base-relative", no_argument, &base_relative, 1},
- {"lto-clang", no_argument, <o_clang, 1},
-+ {"uncompressed", no_argument, &uncompressed, 1},
- {},
- };
-
---- a/scripts/link-vmlinux.sh
-+++ b/scripts/link-vmlinux.sh
-@@ -165,6 +165,10 @@ kallsyms()
- kallsymopt="${kallsymopt} --lto-clang"
- fi
-
-+ if is_enabled CONFIG_KALLSYMS_UNCOMPRESSED; then
-+ kallsymopt="${kallsymopt} --uncompressed"
-+ fi
-+
- info KSYMS ${2}
- scripts/kallsyms ${kallsymopt} ${1} > ${2}
- }
+++ /dev/null
-Subject: kernel: when KALLSYMS is disabled, print module address + size for matching backtrace entries
-
-
-lede-commit 53827cdc824556cda910b23ce5030c363b8f1461
----
- lib/vsprintf.c | 15 +++++++++++----
- 1 file changed, 11 insertions(+), 4 deletions(-)
-
---- a/lib/vsprintf.c
-+++ b/lib/vsprintf.c
-@@ -982,8 +982,10 @@ char *symbol_string(char *buf, char *end
- struct printf_spec spec, const char *fmt)
- {
- unsigned long value;
--#ifdef CONFIG_KALLSYMS
- char sym[KSYM_SYMBOL_LEN];
-+#ifndef CONFIG_KALLSYMS
-+ struct module *mod;
-+ int len;
- #endif
-
- if (fmt[1] == 'R')
-@@ -1004,8 +1006,14 @@ char *symbol_string(char *buf, char *end
-
- return string_nocheck(buf, end, sym, spec);
- #else
-- return special_hex_number(buf, end, value, sizeof(void *));
-+ len = snprintf(sym, sizeof(sym), "0x%lx", value);
-+ mod = __module_address(value);
-+ if (mod)
-+ snprintf(sym + len, sizeof(sym) - len, " [%s@%p+0x%x]",
-+ mod->name, mod->mem[MOD_TEXT].base,
-+ mod->mem[MOD_TEXT].size);
- #endif
-+ return string(buf, end, sym, spec);
- }
-
- static const struct printf_spec default_str_spec = {
+++ /dev/null
-Subject: usr: sanitize deps_initramfs list
-
-If any filename in the intramfs dependency
-list contains a colon, that causes a kernel
-build error like this:
-
-/devel/openwrt/build_dir/linux-ar71xx_generic/linux-3.6.6/usr/Makefile:58: *** multiple target patterns. Stop.
-make[5]: *** [usr] Error 2
-
-Fix it by removing such filenames from the
-deps_initramfs list.
-
----
- usr/Makefile | 8 +++++---
- 1 file changed, 5 insertions(+), 3 deletions(-)
-
---- a/usr/Makefile
-+++ b/usr/Makefile
-@@ -56,6 +56,8 @@ hostprogs := gen_init_cpio
- # The dependency list is generated by gen_initramfs.sh -l
- -include $(obj)/.initramfs_data.cpio.d
-
-+deps_initramfs := $(foreach v,$(deps_initramfs),$(if $(findstring :,$(v)),,$(v)))
-+
- # do not try to update files included in initramfs
- $(deps_initramfs): ;
-
+++ /dev/null
-From a22c4c7bbfad3e93e717e16f6faf343259add27a Mon Sep 17 00:00:00 2001
-Date: Fri, 27 Jun 2025 11:09:04 +0100
-Subject: [PATCH v2] kernel/fork: Increase minimum number of allowed threads
-
-A modern Linux system creates much more than 20 threads at bootup.
-When I booted up OpenWrt in qemu the system sometimes failed to boot up
-when it wanted to create the 419th thread. The VM had 128MB RAM and the
-calculation in set_max_threads() calculated that max_threads should be
-set to 419. When the system booted up it tried to notify the user space
-about every device it created because CONFIG_UEVENT_HELPER was set and
-used. I counted 1299 calls to call_usermodehelper_setup(), all of
-them try to create a new thread and call the userspace hotplug script in
-it.
-
-This fixes bootup of Linux on systems with low memory.
-
-I saw the problem with qemu 10.0.2 using these commands:
-qemu-system-aarch64 -machine virt -cpu cortex-a57 -nographic
-
----
- kernel/fork.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/kernel/fork.c
-+++ b/kernel/fork.c
-@@ -115,7 +115,7 @@
- /*
- * Minimum number of threads to boot the kernel
- */
--#define MIN_THREADS 20
-+#define MIN_THREADS 600
-
- /*
- * Maximum number of threads
+++ /dev/null
-From c2deb5ef01a0ef09088832744cbace9e239a6ee0 Mon Sep 17 00:00:00 2001
-Date: Sat, 28 Mar 2020 12:11:50 +0100
-Subject: [PATCH] generic: platform/mikrotik build bits (5.4)
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-This patch adds platform/mikrotik kernel build bits
-
----
- drivers/platform/Kconfig | 2 ++
- drivers/platform/Makefile | 1 +
- 2 files changed, 3 insertions(+)
-
---- a/drivers/platform/Kconfig
-+++ b/drivers/platform/Kconfig
-@@ -14,3 +14,5 @@ source "drivers/platform/olpc/Kconfig"
- source "drivers/platform/surface/Kconfig"
-
- source "drivers/platform/x86/Kconfig"
-+
-+source "drivers/platform/mikrotik/Kconfig"
---- a/drivers/platform/Makefile
-+++ b/drivers/platform/Makefile
-@@ -11,3 +11,4 @@ obj-$(CONFIG_OLPC_EC) += olpc/
- obj-$(CONFIG_GOLDFISH) += goldfish/
- obj-$(CONFIG_CHROME_PLATFORMS) += chrome/
- obj-$(CONFIG_SURFACE_PLATFORMS) += surface/
-+obj-$(CONFIG_MIKROTIK) += mikrotik/
+++ /dev/null
-Subject: mips: expose CONFIG_BOOT_RAW
-
-This exposes the CONFIG_BOOT_RAW symbol in Kconfig. This is needed on
-certain Broadcom chipsets running CFE in order to load the kernel.
-
----
---- a/arch/mips/Kconfig
-+++ b/arch/mips/Kconfig
-@@ -1013,9 +1013,6 @@ config FW_ARC
- config ARCH_MAY_HAVE_PC_FDC
- bool
-
--config BOOT_RAW
-- bool
--
- config CEVT_BCM1480
- bool
-
-@@ -2996,6 +2993,18 @@ choice
- bool "Extend builtin kernel arguments with bootloader arguments"
- endchoice
-
-+config BOOT_RAW
-+ bool "Enable the kernel to be executed from the load address"
-+ default n
-+ help
-+ Allow the kernel to be executed from the load address for
-+ bootloaders which cannot read the ELF format. This places
-+ a jump to start_kernel at the load address.
-+
-+ If unsure, say N.
-+
-+
-+
- endmenu
-
- config LOCKDEP_SUPPORT
+++ /dev/null
-From e6e6ef4275978823ec3a84133fc91f4ffbef5c84 Mon Sep 17 00:00:00 2001
-Date: Mon, 22 Feb 2016 18:09:44 +0000
-Subject: [PATCH] MIPS: Add barriers between dcache & icache flushes
-
-Index-based cache operations may be arbitrarily reordered by out of
-order CPUs. Thus code which writes back the dcache & then invalidates
-the icache using indexed cache ops must include a barrier between
-operating on the 2 caches in order to prevent the scenario in which:
-
- - icache invalidation occurs.
-
- - icache fetch occurs, due to speculation.
-
- - dcache writeback occurs.
-
-If the above were allowed to happen then the icache would contain stale
-data. Forcing the dcache writeback to complete before the icache
-invalidation avoids this.
-
----
- arch/mips/mm/c-r4k.c | 13 +++++++++++--
- 1 file changed, 11 insertions(+), 2 deletions(-)
-
---- a/arch/mips/mm/c-r4k.c
-+++ b/arch/mips/mm/c-r4k.c
-@@ -403,6 +403,7 @@ static inline void local_r4k___flush_cac
-
- default:
- r4k_blast_dcache();
-+ mb(); /* cache instructions may be reordered */
- r4k_blast_icache();
- break;
- }
-@@ -483,8 +484,10 @@ static inline void local_r4k_flush_cache
- if (cpu_has_dc_aliases || (exec && !cpu_has_ic_fills_f_dc))
- r4k_blast_dcache();
- /* If executable, blast stale lines from icache */
-- if (exec)
-+ if (exec) {
-+ mb(); /* cache instructions may be reordered */
- r4k_blast_icache();
-+ }
- }
-
- static void r4k_flush_cache_range(struct vm_area_struct *vma,
-@@ -586,8 +589,13 @@ static inline void local_r4k_flush_cache
- if (cpu_has_dc_aliases || (exec && !cpu_has_ic_fills_f_dc)) {
- vaddr ? r4k_blast_dcache_page(addr) :
- r4k_blast_dcache_user_page(addr);
-- if (exec && !cpu_icache_snoops_remote_store)
-+ if (exec)
-+ mb(); /* cache instructions may be reordered */
-+
-+ if (exec && !cpu_icache_snoops_remote_store) {
- r4k_blast_scache_page(addr);
-+ mb(); /* cache instructions may be reordered */
-+ }
- }
- if (exec) {
- if (vaddr && cpu_has_vtag_icache && mm == current->active_mm) {
-@@ -654,6 +662,7 @@ static inline void __local_r4k_flush_ica
- else
- blast_dcache_range(start, end);
- }
-+ mb(); /* cache instructions may be reordered */
- }
-
- if (type == R4K_INDEX ||
+++ /dev/null
-Subject: mips: use -mno-branch-likely for kernel and userspace
-
-saves ~11k kernel size after lzma and ~12k squashfs size in the
-
-lede-commit: 41a039f46450ffae9483d6216422098669da2900
----
- arch/mips/Makefile | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/arch/mips/Makefile
-+++ b/arch/mips/Makefile
-@@ -94,7 +94,7 @@ all-$(CONFIG_SYS_SUPPORTS_ZBOOT)+= vmlin
- # machines may also. Since BFD is incredibly buggy with respect to
- # crossformat linking we rely on the elf2ecoff tool for format conversion.
- #
--cflags-y += -G 0 -mno-abicalls -fno-pic -pipe
-+cflags-y += -G 0 -mno-abicalls -fno-pic -pipe -mno-branch-likely
- cflags-y += -msoft-float -Wa,-msoft-float
- LDFLAGS_vmlinux += -G 0 -static -n -nostdlib
- KBUILD_AFLAGS_MODULE += -mlong-calls
+++ /dev/null
-Subject: mips: replace -mlong-calls with -mno-long-calls to make function calls faster in kernel modules to achieve this, try to
-
-lede-commit: 3b3d64743ba2a874df9d70cd19e242205b0a788c
----
- arch/mips/Makefile | 5 +
- arch/mips/include/asm/module.h | 5 +
- arch/mips/kernel/module.c | 279 ++++++++++++++++++++++++++++++++++++++++-
- 3 files changed, 284 insertions(+), 5 deletions(-)
-
---- a/arch/mips/Makefile
-+++ b/arch/mips/Makefile
-@@ -97,8 +97,18 @@ all-$(CONFIG_SYS_SUPPORTS_ZBOOT)+= vmlin
- cflags-y += -G 0 -mno-abicalls -fno-pic -pipe -mno-branch-likely
- cflags-y += -msoft-float -Wa,-msoft-float
- LDFLAGS_vmlinux += -G 0 -static -n -nostdlib
-+ifdef CONFIG_64BIT
- KBUILD_AFLAGS_MODULE += -mlong-calls
- KBUILD_CFLAGS_MODULE += -mlong-calls
-+else
-+ ifdef CONFIG_DYNAMIC_FTRACE
-+ KBUILD_AFLAGS_MODULE += -mlong-calls
-+ KBUILD_CFLAGS_MODULE += -mlong-calls
-+ else
-+ KBUILD_AFLAGS_MODULE += -mno-long-calls
-+ KBUILD_CFLAGS_MODULE += -mno-long-calls
-+ endif
-+endif
-
- ifeq ($(CONFIG_RELOCATABLE),y)
- LDFLAGS_vmlinux += --emit-relocs
---- a/arch/mips/include/asm/module.h
-+++ b/arch/mips/include/asm/module.h
-@@ -12,6 +12,11 @@ struct mod_arch_specific {
- const struct exception_table_entry *dbe_start;
- const struct exception_table_entry *dbe_end;
- struct mips_hi16 *r_mips_hi16_list;
-+
-+ void *phys_plt_tbl;
-+ void *virt_plt_tbl;
-+ unsigned int phys_plt_offset;
-+ unsigned int virt_plt_offset;
- };
-
- typedef uint8_t Elf64_Byte; /* Type for a 8-bit quantity. */
---- a/arch/mips/kernel/module.c
-+++ b/arch/mips/kernel/module.c
-@@ -32,23 +32,261 @@ struct mips_hi16 {
- static LIST_HEAD(dbe_list);
- static DEFINE_SPINLOCK(dbe_lock);
-
--#ifdef MODULE_START
-+/*
-+ * Get the potential max trampolines size required of the init and
-+ * non-init sections. Only used if we cannot find enough contiguous
-+ * physically mapped memory to put the module into.
-+ */
-+static unsigned int
-+get_plt_size(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs,
-+ const char *secstrings, unsigned int symindex, bool is_init)
-+{
-+ unsigned long ret = 0;
-+ unsigned int i, j;
-+ Elf_Sym *syms;
-+
-+ /* Everything marked ALLOC (this includes the exported symbols) */
-+ for (i = 1; i < hdr->e_shnum; ++i) {
-+ unsigned int info = sechdrs[i].sh_info;
-+
-+ if (sechdrs[i].sh_type != SHT_REL
-+ && sechdrs[i].sh_type != SHT_RELA)
-+ continue;
-+
-+ /* Not a valid relocation section? */
-+ if (info >= hdr->e_shnum)
-+ continue;
-+
-+ /* Don't bother with non-allocated sections */
-+ if (!(sechdrs[info].sh_flags & SHF_ALLOC))
-+ continue;
-+
-+ /* If it's called *.init*, and we're not init, we're
-+ not interested */
-+ if ((strstr(secstrings + sechdrs[i].sh_name, ".init") != 0)
-+ != is_init)
-+ continue;
-+
-+ syms = (Elf_Sym *) sechdrs[symindex].sh_addr;
-+ if (sechdrs[i].sh_type == SHT_REL) {
-+ Elf_Mips_Rel *rel = (void *) sechdrs[i].sh_addr;
-+ unsigned int size = sechdrs[i].sh_size / sizeof(*rel);
-+
-+ for (j = 0; j < size; ++j) {
-+ Elf_Sym *sym;
-+
-+ if (ELF_MIPS_R_TYPE(rel[j]) != R_MIPS_26)
-+ continue;
-+
-+ sym = syms + ELF_MIPS_R_SYM(rel[j]);
-+ if (!is_init && sym->st_shndx != SHN_UNDEF)
-+ continue;
-+
-+ ret += 4 * sizeof(int);
-+ }
-+ } else {
-+ Elf_Mips_Rela *rela = (void *) sechdrs[i].sh_addr;
-+ unsigned int size = sechdrs[i].sh_size / sizeof(*rela);
-+
-+ for (j = 0; j < size; ++j) {
-+ Elf_Sym *sym;
-+
-+ if (ELF_MIPS_R_TYPE(rela[j]) != R_MIPS_26)
-+ continue;
-+
-+ sym = syms + ELF_MIPS_R_SYM(rela[j]);
-+ if (!is_init && sym->st_shndx != SHN_UNDEF)
-+ continue;
-+
-+ ret += 4 * sizeof(int);
-+ }
-+ }
-+ }
-+
-+ return ret;
-+}
-+
-+#ifndef MODULE_START
-+static void *alloc_phys(unsigned long size)
-+{
-+ unsigned order;
-+ struct page *page;
-+ struct page *p;
-+
-+ size = PAGE_ALIGN(size);
-+ order = get_order(size);
-+
-+ page = alloc_pages(GFP_KERNEL | __GFP_NORETRY | __GFP_NOWARN |
-+ __GFP_THISNODE, order);
-+ if (!page)
-+ return NULL;
-+
-+ split_page(page, order);
-+
-+ /* mark all pages except for the last one */
-+ for (p = page; p + 1 < page + (size >> PAGE_SHIFT); ++p)
-+ set_bit(PG_owner_priv_1, &p->flags);
-+
-+ for (p = page + (size >> PAGE_SHIFT); p < page + (1 << order); ++p)
-+ __free_page(p);
-+
-+ return page_address(page);
-+}
-+#endif
-+
-+static void free_phys(void *ptr)
-+{
-+ struct page *page;
-+ bool free;
-+
-+ page = virt_to_page(ptr);
-+ do {
-+ free = test_and_clear_bit(PG_owner_priv_1, &page->flags);
-+ __free_page(page);
-+ page++;
-+ } while (free);
-+}
-+
-+
- void *module_alloc(unsigned long size)
- {
-+#ifdef MODULE_START
- return __vmalloc_node_range(size, 1, MODULE_START, MODULE_END,
- GFP_KERNEL, PAGE_KERNEL, 0, NUMA_NO_NODE,
- __builtin_return_address(0));
-+#else
-+ void *ptr;
-+
-+ if (size == 0)
-+ return NULL;
-+
-+ ptr = alloc_phys(size);
-+
-+ /* If we failed to allocate physically contiguous memory,
-+ * fall back to regular vmalloc. The module loader code will
-+ * create jump tables to handle long jumps */
-+ if (!ptr)
-+ return vmalloc(size);
-+
-+ return ptr;
-+#endif
- }
-+
-+static inline bool is_phys_addr(void *ptr)
-+{
-+#ifdef CONFIG_64BIT
-+ return (KSEGX((unsigned long)ptr) == CKSEG0);
-+#else
-+ return (KSEGX(ptr) == KSEG0);
- #endif
-+}
-+
-+/* Free memory returned from module_alloc */
-+void module_memfree(void *module_region)
-+{
-+ if (is_phys_addr(module_region))
-+ free_phys(module_region);
-+ else
-+ vfree(module_region);
-+}
-+
-+static void *__module_alloc(int size, bool phys)
-+{
-+ void *ptr;
-+
-+ if (phys)
-+ ptr = kmalloc(size, GFP_KERNEL);
-+ else
-+ ptr = vmalloc(size);
-+ return ptr;
-+}
-+
-+static void __module_free(void *ptr)
-+{
-+ if (is_phys_addr(ptr))
-+ kfree(ptr);
-+ else
-+ vfree(ptr);
-+}
-+
-+int module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs,
-+ char *secstrings, struct module *mod)
-+{
-+ unsigned int symindex = 0;
-+ unsigned int core_size, init_size;
-+ int i;
-+
-+ mod->arch.phys_plt_offset = 0;
-+ mod->arch.virt_plt_offset = 0;
-+ mod->arch.phys_plt_tbl = NULL;
-+ mod->arch.virt_plt_tbl = NULL;
-+
-+ if (IS_ENABLED(CONFIG_64BIT))
-+ return 0;
-+
-+ for (i = 1; i < hdr->e_shnum; i++)
-+ if (sechdrs[i].sh_type == SHT_SYMTAB)
-+ symindex = i;
-+
-+ core_size = get_plt_size(hdr, sechdrs, secstrings, symindex, false);
-+ init_size = get_plt_size(hdr, sechdrs, secstrings, symindex, true);
-+
-+ if ((core_size + init_size) == 0)
-+ return 0;
-+
-+ mod->arch.phys_plt_tbl = __module_alloc(core_size + init_size, 1);
-+ if (!mod->arch.phys_plt_tbl)
-+ return -ENOMEM;
-+
-+ mod->arch.virt_plt_tbl = __module_alloc(core_size + init_size, 0);
-+ if (!mod->arch.virt_plt_tbl) {
-+ __module_free(mod->arch.phys_plt_tbl);
-+ mod->arch.phys_plt_tbl = NULL;
-+ return -ENOMEM;
-+ }
-+
-+ return 0;
-+}
-
- static void apply_r_mips_32(u32 *location, u32 base, Elf_Addr v)
- {
- *location = base + v;
- }
-
-+static Elf_Addr add_plt_entry_to(unsigned *plt_offset,
-+ void *start, Elf_Addr v)
-+{
-+ unsigned *tramp = start + *plt_offset;
-+ *plt_offset += 4 * sizeof(int);
-+
-+ /* adjust carry for addiu */
-+ if (v & 0x00008000)
-+ v += 0x10000;
-+
-+ tramp[0] = 0x3c190000 | (v >> 16); /* lui t9, hi16 */
-+ tramp[1] = 0x27390000 | (v & 0xffff); /* addiu t9, t9, lo16 */
-+ tramp[2] = 0x03200008; /* jr t9 */
-+ tramp[3] = 0x00000000; /* nop */
-+
-+ return (Elf_Addr) tramp;
-+}
-+
-+static Elf_Addr add_plt_entry(struct module *me, void *location, Elf_Addr v)
-+{
-+ if (is_phys_addr(location))
-+ return add_plt_entry_to(&me->arch.phys_plt_offset,
-+ me->arch.phys_plt_tbl, v);
-+ else
-+ return add_plt_entry_to(&me->arch.virt_plt_offset,
-+ me->arch.virt_plt_tbl, v);
-+
-+}
-+
- static int apply_r_mips_26(struct module *me, u32 *location, u32 base,
- Elf_Addr v)
- {
-+ u32 ofs = base & 0x03ffffff;
-+
- if (v % 4) {
- pr_err("module %s: dangerous R_MIPS_26 relocation\n",
- me->name);
-@@ -56,13 +294,17 @@ static int apply_r_mips_26(struct module
- }
-
- if ((v & 0xf0000000) != (((unsigned long)location + 4) & 0xf0000000)) {
-- pr_err("module %s: relocation overflow\n",
-- me->name);
-- return -ENOEXEC;
-+ v = add_plt_entry(me, location, v + (ofs << 2));
-+ if (!v) {
-+ pr_err("module %s: relocation overflow\n",
-+ me->name);
-+ return -ENOEXEC;
-+ }
-+ ofs = 0;
- }
-
- *location = (*location & ~0x03ffffff) |
-- ((base + (v >> 2)) & 0x03ffffff);
-+ ((ofs + (v >> 2)) & 0x03ffffff);
-
- return 0;
- }
-@@ -442,9 +684,36 @@ int module_finalize(const Elf_Ehdr *hdr,
- list_add(&me->arch.dbe_list, &dbe_list);
- spin_unlock_irq(&dbe_lock);
- }
-+
-+ /* Get rid of the fixup trampoline if we're running the module
-+ * from physically mapped address space */
-+ if (me->arch.phys_plt_offset == 0) {
-+ __module_free(me->arch.phys_plt_tbl);
-+ me->arch.phys_plt_tbl = NULL;
-+ }
-+ if (me->arch.virt_plt_offset == 0) {
-+ __module_free(me->arch.virt_plt_tbl);
-+ me->arch.virt_plt_tbl = NULL;
-+ }
-+
- return 0;
- }
-
-+void module_arch_freeing_init(struct module *mod)
-+{
-+ if (mod->state == MODULE_STATE_LIVE)
-+ return;
-+
-+ if (mod->arch.phys_plt_tbl) {
-+ __module_free(mod->arch.phys_plt_tbl);
-+ mod->arch.phys_plt_tbl = NULL;
-+ }
-+ if (mod->arch.virt_plt_tbl) {
-+ __module_free(mod->arch.virt_plt_tbl);
-+ mod->arch.virt_plt_tbl = NULL;
-+ }
-+}
-+
- void module_arch_cleanup(struct module *mod)
- {
- spin_lock_irq(&dbe_lock);
+++ /dev/null
-Subject: kernel: add -mtune=34kc to MIPS CFLAGS when building for mips32r2
-
-This provides a good tradeoff across at least 24Kc-74Kc, while also
-producing smaller code.
-
----
- arch/mips/Makefile | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/arch/mips/Makefile
-+++ b/arch/mips/Makefile
-@@ -163,7 +163,7 @@ cflags-$(CONFIG_CPU_R4300) += -march=r43
- cflags-$(CONFIG_CPU_R4X00) += -march=r4600 -Wa,--trap
- cflags-$(CONFIG_CPU_TX49XX) += -march=r4600 -Wa,--trap
- cflags-$(CONFIG_CPU_MIPS32_R1) += -march=mips32 -Wa,--trap
--cflags-$(CONFIG_CPU_MIPS32_R2) += -march=mips32r2 -Wa,--trap
-+cflags-$(CONFIG_CPU_MIPS32_R2) += -march=mips32r2 -mtune=34kc -Wa,--trap
- cflags-$(CONFIG_CPU_MIPS32_R5) += -march=mips32r5 -Wa,--trap -modd-spreg
- cflags-$(CONFIG_CPU_MIPS32_R6) += -march=mips32r6 -Wa,--trap -modd-spreg
- cflags-$(CONFIG_CPU_MIPS64_R1) += -march=mips64 -Wa,--trap
+++ /dev/null
-Subject: fix errors in unresolved weak symbols on arm
-
-lede-commit: 570699d4838a907c3ef9f2819bf19eb72997b32f
----
- arch/arm/kernel/module.c | 4 ++++
- 1 file changed, 4 insertions(+)
-
---- a/arch/arm/kernel/module.c
-+++ b/arch/arm/kernel/module.c
-@@ -146,6 +146,10 @@ apply_relocate(Elf32_Shdr *sechdrs, cons
- return -ENOEXEC;
- }
-
-+ if ((IS_ERR_VALUE(sym->st_value) || !sym->st_value) &&
-+ ELF_ST_BIND(sym->st_info) == STB_WEAK)
-+ continue;
-+
- loc = dstsec->sh_addr + rel->r_offset;
-
- switch (ELF32_R_TYPE(rel->r_info)) {
+++ /dev/null
-Subject: MIPS: kexec: Accept command line parameters from userspace.
-
----
- arch/mips/kernel/machine_kexec.c | 153 +++++++++++++++++++++++++++++++-----
- arch/mips/kernel/machine_kexec.h | 20 +++++
- arch/mips/kernel/relocate_kernel.S | 21 +++--
- 3 files changed, 167 insertions(+), 27 deletions(-)
- create mode 100644 arch/mips/kernel/machine_kexec.h
-
---- a/arch/mips/kernel/machine_kexec.c
-+++ b/arch/mips/kernel/machine_kexec.c
-@@ -9,14 +9,11 @@
- #include <linux/delay.h>
- #include <linux/libfdt.h>
-
-+#include <asm/bootinfo.h>
- #include <asm/cacheflush.h>
- #include <asm/page.h>
--
--extern const unsigned char relocate_new_kernel[];
--extern const size_t relocate_new_kernel_size;
--
--extern unsigned long kexec_start_address;
--extern unsigned long kexec_indirection_page;
-+#include <linux/uaccess.h>
-+#include "machine_kexec.h"
-
- static unsigned long reboot_code_buffer;
-
-@@ -30,6 +27,101 @@ void (*_crash_smp_send_stop)(void) = NUL
- void (*_machine_kexec_shutdown)(void) = NULL;
- void (*_machine_crash_shutdown)(struct pt_regs *regs) = NULL;
-
-+static void machine_kexec_print_args(void)
-+{
-+ unsigned long argc = (int)kexec_args[0];
-+ int i;
-+
-+ pr_info("kexec_args[0] (argc): %lu\n", argc);
-+ pr_info("kexec_args[1] (argv): %p\n", (void *)kexec_args[1]);
-+ pr_info("kexec_args[2] (env ): %p\n", (void *)kexec_args[2]);
-+ pr_info("kexec_args[3] (desc): %p\n", (void *)kexec_args[3]);
-+
-+ for (i = 0; i < argc; i++) {
-+ pr_info("kexec_argv[%d] = %p, %s\n",
-+ i, kexec_argv[i], kexec_argv[i]);
-+ }
-+}
-+
-+static void machine_kexec_init_argv(struct kimage *image)
-+{
-+ void __user *buf = NULL;
-+ size_t bufsz;
-+ size_t size;
-+ int i;
-+
-+ bufsz = 0;
-+ for (i = 0; i < image->nr_segments; i++) {
-+ struct kexec_segment *seg;
-+
-+ seg = &image->segment[i];
-+ if (seg->bufsz < 6)
-+ continue;
-+
-+ if (strncmp((char *) seg->buf, "kexec ", 6))
-+ continue;
-+
-+ buf = seg->buf;
-+ bufsz = seg->bufsz;
-+ break;
-+ }
-+
-+ if (!buf)
-+ return;
-+
-+ size = KEXEC_COMMAND_LINE_SIZE;
-+ size = min(size, bufsz);
-+ if (size < bufsz)
-+ pr_warn("kexec command line truncated to %zd bytes\n", size);
-+
-+ /* Copy to kernel space */
-+ if (copy_from_user(kexec_argv_buf, buf, size))
-+ pr_warn("kexec command line copy to kernel space failed\n");
-+
-+ kexec_argv_buf[size - 1] = 0;
-+}
-+
-+static void machine_kexec_parse_argv(struct kimage *image)
-+{
-+ char *reboot_code_buffer;
-+ int reloc_delta;
-+ char *ptr;
-+ int argc;
-+ int i;
-+
-+ ptr = kexec_argv_buf;
-+ argc = 0;
-+
-+ /*
-+ * convert command line string to array of parameters
-+ * (as bootloader does).
-+ */
-+ while (ptr && *ptr && (KEXEC_MAX_ARGC > argc)) {
-+ if (*ptr == ' ') {
-+ *ptr++ = '\0';
-+ continue;
-+ }
-+
-+ kexec_argv[argc++] = ptr;
-+ ptr = strchr(ptr, ' ');
-+ }
-+
-+ if (!argc)
-+ return;
-+
-+ kexec_args[0] = argc;
-+ kexec_args[1] = (unsigned long)kexec_argv;
-+ kexec_args[2] = 0;
-+ kexec_args[3] = 0;
-+
-+ reboot_code_buffer = page_address(image->control_code_page);
-+ reloc_delta = reboot_code_buffer - (char *)kexec_relocate_new_kernel;
-+
-+ kexec_args[1] += reloc_delta;
-+ for (i = 0; i < argc; i++)
-+ kexec_argv[i] += reloc_delta;
-+}
-+
- static void kexec_image_info(const struct kimage *kimage)
- {
- unsigned long i;
-@@ -99,6 +191,18 @@ machine_kexec_prepare(struct kimage *kim
- #endif
-
- kexec_image_info(kimage);
-+ /*
-+ * Whenever arguments passed from kexec-tools, Init the arguments as
-+ * the original ones to try avoiding booting failure.
-+ */
-+
-+ kexec_args[0] = fw_arg0;
-+ kexec_args[1] = fw_arg1;
-+ kexec_args[2] = fw_arg2;
-+ kexec_args[3] = fw_arg3;
-+
-+ machine_kexec_init_argv(kimage);
-+ machine_kexec_parse_argv(kimage);
-
- if (_machine_kexec_prepare)
- return _machine_kexec_prepare(kimage);
-@@ -161,7 +265,7 @@ machine_crash_shutdown(struct pt_regs *r
- void kexec_nonboot_cpu_jump(void)
- {
- local_flush_icache_range((unsigned long)relocated_kexec_smp_wait,
-- reboot_code_buffer + relocate_new_kernel_size);
-+ reboot_code_buffer + KEXEC_RELOCATE_NEW_KERNEL_SIZE);
-
- relocated_kexec_smp_wait(NULL);
- }
-@@ -199,7 +303,7 @@ void kexec_reboot(void)
- * machine_kexec() CPU.
- */
- local_flush_icache_range(reboot_code_buffer,
-- reboot_code_buffer + relocate_new_kernel_size);
-+ reboot_code_buffer + KEXEC_RELOCATE_NEW_KERNEL_SIZE);
-
- do_kexec = (void *)reboot_code_buffer;
- do_kexec();
-@@ -212,10 +316,12 @@ machine_kexec(struct kimage *image)
- unsigned long *ptr;
-
- reboot_code_buffer =
-- (unsigned long)page_address(image->control_code_page);
-+ (unsigned long)page_address(image->control_code_page);
-+ pr_info("reboot_code_buffer = %p\n", (void *)reboot_code_buffer);
-
- kexec_start_address =
- (unsigned long) phys_to_virt(image->start);
-+ pr_info("kexec_start_address = %p\n", (void *)kexec_start_address);
-
- if (image->type == KEXEC_TYPE_DEFAULT) {
- kexec_indirection_page =
-@@ -223,9 +329,19 @@ machine_kexec(struct kimage *image)
- } else {
- kexec_indirection_page = (unsigned long)&image->head;
- }
-+ pr_info("kexec_indirection_page = %p\n", (void *)kexec_indirection_page);
-
-- memcpy((void*)reboot_code_buffer, relocate_new_kernel,
-- relocate_new_kernel_size);
-+ pr_info("Where is memcpy: %p\n", memcpy);
-+ pr_info("kexec_relocate_new_kernel = %p, kexec_relocate_new_kernel_end = %p\n",
-+ (void *)kexec_relocate_new_kernel, &kexec_relocate_new_kernel_end);
-+ pr_info("Copy %lu bytes from %p to %p\n", KEXEC_RELOCATE_NEW_KERNEL_SIZE,
-+ (void *)kexec_relocate_new_kernel, (void *)reboot_code_buffer);
-+ memcpy((void*)reboot_code_buffer, kexec_relocate_new_kernel,
-+ KEXEC_RELOCATE_NEW_KERNEL_SIZE);
-+
-+ pr_info("Before _print_args().\n");
-+ machine_kexec_print_args();
-+ pr_info("Before eval loop.\n");
-
- /*
- * The generic kexec code builds a page list with physical
-@@ -256,7 +372,7 @@ machine_kexec(struct kimage *image)
- #ifdef CONFIG_SMP
- /* All secondary cpus now may jump to kexec_wait cycle */
- relocated_kexec_smp_wait = reboot_code_buffer +
-- (void *)(kexec_smp_wait - relocate_new_kernel);
-+ (void *)(kexec_smp_wait - kexec_relocate_new_kernel);
- smp_wmb();
- atomic_set(&kexec_ready_to_reboot, 1);
- #endif
---- /dev/null
-+++ b/arch/mips/kernel/machine_kexec.h
-@@ -0,0 +1,20 @@
-+#ifndef _MACHINE_KEXEC_H
-+#define _MACHINE_KEXEC_H
-+
-+#ifndef __ASSEMBLY__
-+extern const unsigned char kexec_relocate_new_kernel[];
-+extern unsigned long kexec_relocate_new_kernel_end;
-+extern unsigned long kexec_start_address;
-+extern unsigned long kexec_indirection_page;
-+
-+extern char kexec_argv_buf[];
-+extern char *kexec_argv[];
-+
-+#define KEXEC_RELOCATE_NEW_KERNEL_SIZE ((unsigned long)&kexec_relocate_new_kernel_end - (unsigned long)kexec_relocate_new_kernel)
-+#endif /* !__ASSEMBLY__ */
-+
-+#define KEXEC_COMMAND_LINE_SIZE 256
-+#define KEXEC_ARGV_SIZE (KEXEC_COMMAND_LINE_SIZE / 16)
-+#define KEXEC_MAX_ARGC (KEXEC_ARGV_SIZE / sizeof(long))
-+
-+#endif
---- a/arch/mips/kernel/relocate_kernel.S
-+++ b/arch/mips/kernel/relocate_kernel.S
-@@ -10,10 +10,11 @@
- #include <asm/mipsregs.h>
- #include <asm/stackframe.h>
- #include <asm/addrspace.h>
-+#include "machine_kexec.h"
-
- #include <kernel-entry-init.h>
-
--LEAF(relocate_new_kernel)
-+LEAF(kexec_relocate_new_kernel)
- PTR_L a0, arg0
- PTR_L a1, arg1
- PTR_L a2, arg2
-@@ -98,7 +99,7 @@ done:
- #endif
- /* jump to kexec_start_address */
- j s1
-- END(relocate_new_kernel)
-+ END(kexec_relocate_new_kernel)
-
- #ifdef CONFIG_SMP
- /*
-@@ -177,8 +178,15 @@ EXPORT(kexec_indirection_page)
- PTR_WD 0
- .size kexec_indirection_page, PTRSIZE
-
--relocate_new_kernel_end:
-+kexec_argv_buf:
-+ EXPORT(kexec_argv_buf)
-+ .skip KEXEC_COMMAND_LINE_SIZE
-+ .size kexec_argv_buf, KEXEC_COMMAND_LINE_SIZE
-+
-+kexec_argv:
-+ EXPORT(kexec_argv)
-+ .skip KEXEC_ARGV_SIZE
-+ .size kexec_argv, KEXEC_ARGV_SIZE
-
--EXPORT(relocate_new_kernel_size)
-- PTR_WD relocate_new_kernel_end - relocate_new_kernel
-- .size relocate_new_kernel_size, PTRSIZE
-+kexec_relocate_new_kernel_end:
-+ EXPORT(kexec_relocate_new_kernel_end)
+++ /dev/null
-From bb0c3b0175240bf152fd7c644821a0cf9f77c37c Mon Sep 17 00:00:00 2001
-Date: Fri, 15 Mar 2019 18:53:38 +0300
-Subject: [PATCH] arc add OWRTDTB section
-
-This change allows OpenWRT to patch resulting kernel binary with
-external .dtb.
-
-That allows us to re-use exactky the same vmlinux on different boards
-given its ARC core configurations match (at least cache line sizes etc).
-
-""patch-dtb" searches for ASCII "OWRTDTB:" strign and copies external
-.dtb right after it, keeping the string in place.
-
----
- arch/arc/kernel/head.S | 10 ++++++++++
- arch/arc/kernel/setup.c | 4 +++-
- arch/arc/kernel/vmlinux.lds.S | 13 +++++++++++++
- 3 files changed, 26 insertions(+), 1 deletion(-)
-
---- a/arch/arc/kernel/head.S
-+++ b/arch/arc/kernel/head.S
-@@ -88,6 +88,16 @@
- DSP_EARLY_INIT
- .endm
-
-+ ; Here "patch-dtb" will embed external .dtb
-+ ; Note "patch-dtb" searches for ASCII "OWRTDTB:" string
-+ ; and pastes .dtb right after it, hense the string precedes
-+ ; __image_dtb symbol.
-+ .section .owrt, "aw",@progbits
-+ .ascii "OWRTDTB:"
-+ENTRY(__image_dtb)
-+ .fill 0x4000
-+END(__image_dtb)
-+
- .section .init.text, "ax",@progbits
-
- ;----------------------------------------------------------------
---- a/arch/arc/kernel/setup.c
-+++ b/arch/arc/kernel/setup.c
-@@ -450,6 +450,8 @@ static inline bool uboot_arg_invalid(uns
- /* We always pass 0 as magic from U-boot */
- #define UBOOT_MAGIC_VALUE 0
-
-+extern struct boot_param_header __image_dtb;
-+
- void __init handle_uboot_args(void)
- {
- bool use_embedded_dtb = true;
-@@ -488,7 +490,7 @@ void __init handle_uboot_args(void)
- ignore_uboot_args:
-
- if (use_embedded_dtb) {
-- machine_desc = setup_machine_fdt(__dtb_start);
-+ machine_desc = setup_machine_fdt(&__image_dtb);
- if (!machine_desc)
- panic("Embedded DT invalid\n");
- }
---- a/arch/arc/kernel/vmlinux.lds.S
-+++ b/arch/arc/kernel/vmlinux.lds.S
-@@ -27,6 +27,19 @@ SECTIONS
-
- . = CONFIG_LINUX_LINK_BASE;
-
-+ /*
-+ * In OpenWRT we want to patch built binary embedding .dtb of choice.
-+ * This is implemented with "patch-dtb" utility which searches for
-+ * "OWRTDTB:" string in first 16k of image and if it is found
-+ * copies .dtb right after mentioned string.
-+ *
-+ * Note: "OWRTDTB:" won't be overwritten with .dtb, .dtb will follow it.
-+ */
-+ .owrt : {
-+ *(.owrt)
-+ . = ALIGN(PAGE_SIZE);
-+ }
-+
- _int_vec_base_lds = .;
- .vector : {
- *(.vector)
+++ /dev/null
-Subject: arc: enable unaligned access in kernel mode
-
-This enables misaligned access handling even in kernel mode.
-Some wireless drivers (ath9k-htc and mt7601u) use misaligned accesses
-here and there and to cope with that without fixing stuff in the drivers
-we're just gracefully handling it on ARC.
-
----
- arch/arc/kernel/unaligned.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/arch/arc/kernel/unaligned.c
-+++ b/arch/arc/kernel/unaligned.c
-@@ -202,7 +202,7 @@ int misaligned_fixup(unsigned long addre
- char buf[TASK_COMM_LEN];
-
- /* handle user mode only and only if enabled by sysadmin */
-- if (!user_mode(regs) || !unaligned_enabled)
-+ if (!unaligned_enabled)
- return 1;
-
- if (no_unaligned_warning) {
+++ /dev/null
-From 66770a004afe10df11d3902e16eaa0c2c39436bb Mon Sep 17 00:00:00 2001
-Date: Fri, 24 May 2019 17:56:19 +0200
-Subject: [PATCH] powerpc: Enable kernel XZ compression option on PPC_85xx
-
-Enable kernel XZ compression option on PPC_85xx. Tested with
-simpleImage on TP-Link TL-WDR4900 (Freescale P1014 processor).
-
----
- arch/powerpc/Kconfig | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/arch/powerpc/Kconfig
-+++ b/arch/powerpc/Kconfig
-@@ -251,7 +251,7 @@ config PPC
- select HAVE_KERNEL_GZIP
- select HAVE_KERNEL_LZMA if DEFAULT_UIMAGE
- select HAVE_KERNEL_LZO if DEFAULT_UIMAGE
-- select HAVE_KERNEL_XZ if PPC_BOOK3S || 44x
-+ select HAVE_KERNEL_XZ if PPC_BOOK3S || 44x || PPC_85xx
- select HAVE_KPROBES
- select HAVE_KPROBES_ON_FTRACE
- select HAVE_KRETPROBES
+++ /dev/null
-Date: Wed, 13 Mar 2024 20:28:37 +0800
-Subject: [PATCH] mips: kernel: fix detect_memory_region() function
-
-1. Do not use memcmp() on unallocated memory, as the new introduced
- fortify dynamic object size check[1] will report unexpected result.
-2. Use a fixed pattern instead of a random function pointer as the
- magic value.
-3. Flip magic value and double check it.
-4. Enable this feature only for 32-bit CPUs. Currently, only ath79 and
- ralink CPUs are using it.
-
-[1] 439a1bcac648 ("fortify: Use __builtin_dynamic_object_size() when available")
----
- arch/mips/include/asm/bootinfo.h | 2 ++
- arch/mips/kernel/setup.c | 17 ++++++++++++-----
- 2 files changed, 14 insertions(+), 5 deletions(-)
-
---- a/arch/mips/include/asm/bootinfo.h
-+++ b/arch/mips/include/asm/bootinfo.h
-@@ -93,7 +93,9 @@ const char *get_system_type(void);
-
- extern unsigned long mips_machtype;
-
-+#ifndef CONFIG_64BIT
- extern void detect_memory_region(phys_addr_t start, phys_addr_t sz_min, phys_addr_t sz_max);
-+#endif
-
- extern void prom_init(void);
- extern void prom_free_prom_memory(void);
---- a/arch/mips/kernel/setup.c
-+++ b/arch/mips/kernel/setup.c
-@@ -90,21 +90,27 @@ static struct resource bss_resource = {
- unsigned long __kaslr_offset __ro_after_init;
- EXPORT_SYMBOL(__kaslr_offset);
-
--static void *detect_magic __initdata = detect_memory_region;
--
- #ifdef CONFIG_MIPS_AUTO_PFN_OFFSET
- unsigned long ARCH_PFN_OFFSET;
- EXPORT_SYMBOL(ARCH_PFN_OFFSET);
- #endif
-
-+#ifndef CONFIG_64BIT
-+static u32 detect_magic __initdata;
-+#define MIPS_MEM_TEST_PATTERN 0xaa5555aa
-+
- void __init detect_memory_region(phys_addr_t start, phys_addr_t sz_min, phys_addr_t sz_max)
- {
-- void *dm = &detect_magic;
-+ void *dm = (void *)KSEG1ADDR(&detect_magic);
- phys_addr_t size;
-
- for (size = sz_min; size < sz_max; size <<= 1) {
-- if (!memcmp(dm, dm + size, sizeof(detect_magic)))
-- break;
-+ __raw_writel(MIPS_MEM_TEST_PATTERN, dm);
-+ if (__raw_readl(dm) == __raw_readl(dm + size)) {
-+ __raw_writel(~MIPS_MEM_TEST_PATTERN, dm);
-+ if (__raw_readl(dm) == __raw_readl(dm + size))
-+ break;
-+ }
- }
-
- pr_debug("Memory: %lluMB of RAM detected at 0x%llx (min: %lluMB, max: %lluMB)\n",
-@@ -115,6 +121,7 @@ void __init detect_memory_region(phys_ad
-
- memblock_add(start, size);
- }
-+#endif /* CONFIG_64BIT */
-
- /*
- * Manage initrd
+++ /dev/null
-From 39717277d5c87bdb183cf2f258957b44ba99b4df Mon Sep 17 00:00:00 2001
-Date: Wed, 13 Jul 2022 11:47:35 +0200
-Subject: [PATCH] mtd: mtdsplit support
-
----
- drivers/mtd/Kconfig | 19 ++++
- drivers/mtd/Makefile | 2 +
- drivers/mtd/mtdpart.c | 169 ++++++++++++++++++++++++++++-----
- include/linux/mtd/mtd.h | 25 +++++
- include/linux/mtd/partitions.h | 7 ++
- 5 files changed, 197 insertions(+), 25 deletions(-)
-
---- a/drivers/mtd/Kconfig
-+++ b/drivers/mtd/Kconfig
-@@ -12,6 +12,25 @@ menuconfig MTD
-
- if MTD
-
-+menu "OpenWrt specific MTD options"
-+
-+config MTD_ROOTFS_ROOT_DEV
-+ bool "Automatically set 'rootfs' partition to be root filesystem"
-+ default y
-+
-+config MTD_SPLIT_FIRMWARE
-+ bool "Automatically split firmware partition for kernel+rootfs"
-+ default y
-+
-+config MTD_SPLIT_FIRMWARE_NAME
-+ string "Firmware partition name"
-+ depends on MTD_SPLIT_FIRMWARE
-+ default "firmware"
-+
-+source "drivers/mtd/mtdsplit/Kconfig"
-+
-+endmenu
-+
- config MTD_TESTS
- tristate "MTD tests support (DANGEROUS)"
- depends on m
---- a/drivers/mtd/Makefile
-+++ b/drivers/mtd/Makefile
-@@ -9,6 +9,8 @@ mtd-y := mtdcore.o mtdsuper.o mtdconc
-
- obj-y += parsers/
-
-+obj-$(CONFIG_MTD_SPLIT) += mtdsplit/
-+
- # 'Users' - code which presents functionality to userspace.
- obj-$(CONFIG_MTD_BLKDEVS) += mtd_blkdevs.o
- obj-$(CONFIG_MTD_BLOCK) += mtdblock.o
---- a/drivers/mtd/mtdpart.c
-+++ b/drivers/mtd/mtdpart.c
-@@ -15,11 +15,13 @@
- #include <linux/kmod.h>
- #include <linux/mtd/mtd.h>
- #include <linux/mtd/partitions.h>
-+#include <linux/magic.h>
- #include <linux/err.h>
- #include <linux/of.h>
- #include <linux/of_platform.h>
-
- #include "mtdcore.h"
-+#include "mtdsplit/mtdsplit.h"
-
- /*
- * MTD methods which simply translate the effective address and pass through
-@@ -242,6 +244,147 @@ static int mtd_add_partition_attrs(struc
- return ret;
- }
-
-+static DEFINE_SPINLOCK(part_parser_lock);
-+static LIST_HEAD(part_parsers);
-+
-+static struct mtd_part_parser *mtd_part_parser_get(const char *name)
-+{
-+ struct mtd_part_parser *p, *ret = NULL;
-+
-+ spin_lock(&part_parser_lock);
-+
-+ list_for_each_entry(p, &part_parsers, list)
-+ if (!strcmp(p->name, name) && try_module_get(p->owner)) {
-+ ret = p;
-+ break;
-+ }
-+
-+ spin_unlock(&part_parser_lock);
-+
-+ return ret;
-+}
-+
-+static inline void mtd_part_parser_put(const struct mtd_part_parser *p)
-+{
-+ module_put(p->owner);
-+}
-+
-+static struct mtd_part_parser *
-+get_partition_parser_by_type(enum mtd_parser_type type,
-+ struct mtd_part_parser *start)
-+{
-+ struct mtd_part_parser *p, *ret = NULL;
-+
-+ spin_lock(&part_parser_lock);
-+
-+ p = list_prepare_entry(start, &part_parsers, list);
-+ if (start)
-+ mtd_part_parser_put(start);
-+
-+ list_for_each_entry_continue(p, &part_parsers, list) {
-+ if (p->type == type && try_module_get(p->owner)) {
-+ ret = p;
-+ break;
-+ }
-+ }
-+
-+ spin_unlock(&part_parser_lock);
-+
-+ return ret;
-+}
-+
-+static int parse_mtd_partitions_by_type(struct mtd_info *master,
-+ enum mtd_parser_type type,
-+ const struct mtd_partition **pparts,
-+ struct mtd_part_parser_data *data)
-+{
-+ struct mtd_part_parser *prev = NULL;
-+ int ret = 0;
-+
-+ while (1) {
-+ struct mtd_part_parser *parser;
-+
-+ parser = get_partition_parser_by_type(type, prev);
-+ if (!parser)
-+ break;
-+
-+ ret = (*parser->parse_fn)(master, pparts, data);
-+
-+ if (ret > 0) {
-+ mtd_part_parser_put(parser);
-+ printk(KERN_NOTICE
-+ "%d %s partitions found on MTD device %s\n",
-+ ret, parser->name, master->name);
-+ break;
-+ }
-+
-+ prev = parser;
-+ }
-+
-+ return ret;
-+}
-+
-+static int
-+run_parsers_by_type(struct mtd_info *child, enum mtd_parser_type type)
-+{
-+ struct mtd_partition *parts;
-+ int nr_parts;
-+ int i;
-+
-+ nr_parts = parse_mtd_partitions_by_type(child, type, (const struct mtd_partition **)&parts,
-+ NULL);
-+ if (nr_parts <= 0)
-+ return nr_parts;
-+
-+ if (WARN_ON(!parts))
-+ return 0;
-+
-+ for (i = 0; i < nr_parts; i++) {
-+ /* adjust partition offsets */
-+ parts[i].offset += child->part.offset;
-+
-+ mtd_add_partition(child->parent,
-+ parts[i].name,
-+ parts[i].offset,
-+ parts[i].size);
-+ }
-+
-+ kfree(parts);
-+
-+ return nr_parts;
-+}
-+
-+#ifdef CONFIG_MTD_SPLIT_FIRMWARE_NAME
-+#define SPLIT_FIRMWARE_NAME CONFIG_MTD_SPLIT_FIRMWARE_NAME
-+#else
-+#define SPLIT_FIRMWARE_NAME "unused"
-+#endif
-+
-+static void split_firmware(struct mtd_info *master, struct mtd_info *part)
-+{
-+ run_parsers_by_type(part, MTD_PARSER_TYPE_FIRMWARE);
-+}
-+
-+static void mtd_partition_split(struct mtd_info *master, struct mtd_info *part)
-+{
-+ static int rootfs_found = 0;
-+
-+ if (rootfs_found)
-+ return;
-+
-+ if (of_find_property(mtd_get_of_node(part), "linux,rootfs", NULL) ||
-+ !strcmp(part->name, "rootfs")) {
-+ run_parsers_by_type(part, MTD_PARSER_TYPE_ROOTFS);
-+
-+ rootfs_found = 1;
-+ }
-+
-+ if (IS_ENABLED(CONFIG_MTD_SPLIT_FIRMWARE) &&
-+ !strcmp(part->name, SPLIT_FIRMWARE_NAME) &&
-+ !of_find_property(mtd_get_of_node(part), "compatible", NULL))
-+ split_firmware(master, part);
-+}
-+
- int mtd_add_partition(struct mtd_info *parent, const char *name,
- long long offset, long long length)
- {
-@@ -280,6 +423,7 @@ int mtd_add_partition(struct mtd_info *p
- if (ret)
- goto err_remove_part;
-
-+ mtd_partition_split(parent, child);
- mtd_add_partition_attrs(child);
-
- return 0;
-@@ -423,6 +567,7 @@ int add_mtd_partitions(struct mtd_info *
- goto err_del_partitions;
- }
-
-+ mtd_partition_split(master, child);
- mtd_add_partition_attrs(child);
-
- /* Look for subpartitions */
-@@ -439,31 +584,6 @@ err_del_partitions:
- return ret;
- }
-
--static DEFINE_SPINLOCK(part_parser_lock);
--static LIST_HEAD(part_parsers);
--
--static struct mtd_part_parser *mtd_part_parser_get(const char *name)
--{
-- struct mtd_part_parser *p, *ret = NULL;
--
-- spin_lock(&part_parser_lock);
--
-- list_for_each_entry(p, &part_parsers, list)
-- if (!strcmp(p->name, name) && try_module_get(p->owner)) {
-- ret = p;
-- break;
-- }
--
-- spin_unlock(&part_parser_lock);
--
-- return ret;
--}
--
--static inline void mtd_part_parser_put(const struct mtd_part_parser *p)
--{
-- module_put(p->owner);
--}
--
- /*
- * Many partition parsers just expected the core to kfree() all their data in
- * one chunk. Do that by default.
---- a/include/linux/mtd/mtd.h
-+++ b/include/linux/mtd/mtd.h
-@@ -615,6 +615,24 @@ static inline void mtd_align_erase_req(s
- req->len += mtd->erasesize - mod;
- }
-
-+static inline uint64_t mtd_roundup_to_eb(uint64_t sz, struct mtd_info *mtd)
-+{
-+ if (mtd_mod_by_eb(sz, mtd) == 0)
-+ return sz;
-+
-+ /* Round up to next erase block */
-+ return (mtd_div_by_eb(sz, mtd) + 1) * mtd->erasesize;
-+}
-+
-+static inline uint64_t mtd_rounddown_to_eb(uint64_t sz, struct mtd_info *mtd)
-+{
-+ if (mtd_mod_by_eb(sz, mtd) == 0)
-+ return sz;
-+
-+ /* Round down to the start of the current erase block */
-+ return (mtd_div_by_eb(sz, mtd)) * mtd->erasesize;
-+}
-+
- static inline uint32_t mtd_div_by_ws(uint64_t sz, struct mtd_info *mtd)
- {
- if (mtd->writesize_shift)
-@@ -688,6 +706,13 @@ extern struct mtd_info *of_get_mtd_devic
- extern struct mtd_info *get_mtd_device_nm(const char *name);
- extern void put_mtd_device(struct mtd_info *mtd);
-
-+static inline uint64_t mtdpart_get_offset(const struct mtd_info *mtd)
-+{
-+ if (!mtd_is_partition(mtd))
-+ return 0;
-+
-+ return mtd->part.offset;
-+}
-
- struct mtd_notifier {
- void (*add)(struct mtd_info *mtd);
---- a/include/linux/mtd/partitions.h
-+++ b/include/linux/mtd/partitions.h
-@@ -75,6 +75,12 @@ struct mtd_part_parser_data {
- * Functions dealing with the various ways of partitioning the space
- */
-
-+enum mtd_parser_type {
-+ MTD_PARSER_TYPE_DEVICE = 0,
-+ MTD_PARSER_TYPE_ROOTFS,
-+ MTD_PARSER_TYPE_FIRMWARE,
-+};
-+
- struct mtd_part_parser {
- struct list_head list;
- struct module *owner;
-@@ -83,6 +89,7 @@ struct mtd_part_parser {
- int (*parse_fn)(struct mtd_info *, const struct mtd_partition **,
- struct mtd_part_parser_data *);
- void (*cleanup)(const struct mtd_partition *pparts, int nr_parts);
-+ enum mtd_parser_type type;
- };
-
- /* Container for passing around a set of parsed partitions */
+++ /dev/null
-Date: Tue, 31 Oct 2023 15:51:01 +0100
-Subject: [PATCH] mtd: don't register NVMEM devices for partitions with custom
- drivers
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-This fixes issue exposed by upstream commit f4cf4e5db331 ("Revert
-"nvmem: add new config option"").
-
----
- drivers/mtd/mtdcore.c | 23 +++++++++++++++++++++++
- 1 file changed, 23 insertions(+)
-
---- a/drivers/mtd/mtdcore.c
-+++ b/drivers/mtd/mtdcore.c
-@@ -548,6 +548,29 @@ static int mtd_nvmem_add(struct mtd_info
- struct device_node *node = mtd_get_of_node(mtd);
- struct nvmem_config config = {};
-
-+ /*
-+ * Do NOT register NVMEM device for any partition that is meant to be
-+ * handled by a U-Boot env driver. That would result in associating two
-+ * different NVMEM devices with the same OF node.
-+ *
-+ * An example of unwanted behaviour of above (forwardtrace):
-+ * of_get_mac_addr_nvmem()
-+ * of_nvmem_cell_get()
-+ * __nvmem_device_get()
-+ *
-+ * We can't have __nvmem_device_get() return "mtdX" NVMEM device instead
-+ * of U-Boot env NVMEM device. That would result in failing to find
-+ * NVMEM cell.
-+ *
-+ * This issue seems to affect U-Boot env case only and will go away with
-+ * switch to NVMEM layouts.
-+ */
-+ if (of_device_is_compatible(node, "u-boot,env") ||
-+ of_device_is_compatible(node, "u-boot,env-redundant-bool") ||
-+ of_device_is_compatible(node, "u-boot,env-redundant-count") ||
-+ of_device_is_compatible(node, "brcm,env"))
-+ return 0;
-+
- config.id = NVMEM_DEVID_NONE;
- config.dev = &mtd->dev;
- config.name = dev_name(&mtd->dev);
+++ /dev/null
-From acacdac272927ae1d96e0bca51eb82899671eaea Mon Sep 17 00:00:00 2001
-Date: Fri, 25 Dec 2020 18:50:08 +1000
-Subject: [PATCH] mtd: spi-nor: write support for minor aligned partitions
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Do not prevent writing to mtd partitions where a partition boundary sits
-on a minor erasesize boundary.
-This addresses a FIXME that has been present since the start of the
-linux git history:
-/* Doesn't start on a boundary of major erase size */
-/* FIXME: Let it be writable if it is on a boundary of
- * _minor_ erase size though */
-
-Allow a uniform erase region spi-nor device to be configured
-to use the non-uniform erase regions code path for an erase with:
-CONFIG_MTD_SPI_NOR_USE_VARIABLE_ERASE=y
-
-On supporting hardware (SECT_4K: majority of current SPI-NOR device)
-provide the facility for an erase to use the least number
-of SPI-NOR operations, as well as access to 4K erase without
-requiring CONFIG_MTD_SPI_NOR_USE_4K_SECTORS
-
-Introduce erasesize_minor to the mtd struct,
-the smallest erasesize supported by the device
-
-On existing devices, this is useful where write support is wanted
-for data on a 4K partition, such as some u-boot-env partitions,
-or RouterBoot soft_config, while still netting the performance
-benefits of using 64K sectors
-
-Performance:
-time mtd erase firmware
-OpenWrt 5.10 ramips MT7621 w25q128jv 0xfc0000 partition length
-
-Without this patch
-MTD_SPI_NOR_USE_4K_SECTORS=y |n
-real 2m 11.66s |0m 50.86s
-user 0m 0.00s |0m 0.00s
-sys 1m 56.20s |0m 50.80s
-
-With this patch
-MTD_SPI_NOR_USE_VARIABLE_ERASE=n|y |4K_SECTORS=y
-real 0m 51.68s |0m 50.85s |2m 12.89s
-user 0m 0.00s |0m 0.00s |0m 0.01s
-sys 0m 46.94s |0m 50.38s |2m 12.46s
-
-
----
-
-checkpatch does not like the printk(KERN_WARNING
-these should be changed separately beforehand?
-
-Changes v1 -> v2:
-Added mtdcore sysfs for erasesize_minor
-Removed finding minor erasesize for variable erase regions device,
-as untested and no responses regarding it.
-Moved IF_ENABLED for SPINOR variable erase to guard setting
-erasesize_minor in spi-nor/core.c
-Removed setting erasesize to minor where partition boundaries require
-minor erase to be writable
-Simplified minor boundary check by relying on minor being a factor of
-major
-
-Changes RFC -> v1:
-Fix uninitialized variable smatch warning
----
- drivers/mtd/mtdcore.c | 10 ++++++++++
- drivers/mtd/mtdpart.c | 35 +++++++++++++++++++++++++----------
- drivers/mtd/spi-nor/Kconfig | 10 ++++++++++
- drivers/mtd/spi-nor/core.c | 11 +++++++++--
- include/linux/mtd/mtd.h | 2 ++
- 5 files changed, 56 insertions(+), 12 deletions(-)
-
---- a/drivers/mtd/mtdcore.c
-+++ b/drivers/mtd/mtdcore.c
-@@ -198,6 +198,15 @@ static ssize_t mtd_erasesize_show(struct
- }
- MTD_DEVICE_ATTR_RO(erasesize);
-
-+static ssize_t mtd_erasesize_minor_show(struct device *dev,
-+ struct device_attribute *attr, char *buf)
-+{
-+ struct mtd_info *mtd = dev_get_drvdata(dev);
-+
-+ return sysfs_emit(buf, "%lu\n", (unsigned long)mtd->erasesize_minor);
-+}
-+MTD_DEVICE_ATTR_RO(erasesize_minor);
-+
- static ssize_t mtd_writesize_show(struct device *dev,
- struct device_attribute *attr, char *buf)
- {
-@@ -343,6 +352,7 @@ static struct attribute *mtd_attrs[] = {
- &dev_attr_flags.attr,
- &dev_attr_size.attr,
- &dev_attr_erasesize.attr,
-+ &dev_attr_erasesize_minor.attr,
- &dev_attr_writesize.attr,
- &dev_attr_subpagesize.attr,
- &dev_attr_oobsize.attr,
---- a/drivers/mtd/mtdpart.c
-+++ b/drivers/mtd/mtdpart.c
-@@ -47,6 +47,7 @@ static struct mtd_info *allocate_partiti
- struct mtd_info *master = mtd_get_master(parent);
- int wr_alignment = (parent->flags & MTD_NO_ERASE) ?
- master->writesize : master->erasesize;
-+ int wr_alignment_minor = 0;
- u64 parent_size = mtd_is_partition(parent) ?
- parent->part.size : parent->size;
- struct mtd_info *child;
-@@ -171,6 +172,7 @@ static struct mtd_info *allocate_partiti
- } else {
- /* Single erase size */
- child->erasesize = master->erasesize;
-+ child->erasesize_minor = master->erasesize_minor;
- }
-
- /*
-@@ -178,26 +180,39 @@ static struct mtd_info *allocate_partiti
- * exposes several regions with different erasesize. Adjust
- * wr_alignment accordingly.
- */
-- if (!(child->flags & MTD_NO_ERASE))
-+ if (!(child->flags & MTD_NO_ERASE)) {
- wr_alignment = child->erasesize;
-+ wr_alignment_minor = child->erasesize_minor;
-+ }
-
- tmp = mtd_get_master_ofs(child, 0);
- remainder = do_div(tmp, wr_alignment);
- if ((child->flags & MTD_WRITEABLE) && remainder) {
-- /* Doesn't start on a boundary of major erase size */
-- /* FIXME: Let it be writable if it is on a boundary of
-- * _minor_ erase size though */
-- child->flags &= ~MTD_WRITEABLE;
-- printk(KERN_WARNING"mtd: partition \"%s\" doesn't start on an erase/write block boundary -- force read-only\n",
-- part->name);
-+ if (wr_alignment_minor) {
-+ /* rely on minor being a factor of major erasesize */
-+ tmp = remainder;
-+ remainder = do_div(tmp, wr_alignment_minor);
-+ }
-+ if (remainder) {
-+ child->flags &= ~MTD_WRITEABLE;
-+ printk(KERN_WARNING"mtd: partition \"%s\" doesn't start on an erase/write block boundary -- force read-only\n",
-+ part->name);
-+ }
- }
-
- tmp = mtd_get_master_ofs(child, 0) + child->part.size;
- remainder = do_div(tmp, wr_alignment);
- if ((child->flags & MTD_WRITEABLE) && remainder) {
-- child->flags &= ~MTD_WRITEABLE;
-- printk(KERN_WARNING"mtd: partition \"%s\" doesn't end on an erase/write block -- force read-only\n",
-- part->name);
-+ if (wr_alignment_minor) {
-+ tmp = remainder;
-+ remainder = do_div(tmp, wr_alignment_minor);
-+ }
-+
-+ if (remainder) {
-+ child->flags &= ~MTD_WRITEABLE;
-+ printk(KERN_WARNING"mtd: partition \"%s\" doesn't end on an erase/write block -- force read-only\n",
-+ part->name);
-+ }
- }
-
- child->size = child->part.size;
---- a/drivers/mtd/spi-nor/Kconfig
-+++ b/drivers/mtd/spi-nor/Kconfig
-@@ -10,6 +10,16 @@ menuconfig MTD_SPI_NOR
-
- if MTD_SPI_NOR
-
-+config MTD_SPI_NOR_USE_VARIABLE_ERASE
-+ bool "Disable uniform_erase to allow use of all hardware supported erasesizes"
-+ depends on !MTD_SPI_NOR_USE_4K_SECTORS
-+ default n
-+ help
-+ Allow mixed use of all hardware supported erasesizes,
-+ by forcing spi_nor to use the multiple eraseregions code path.
-+ For example: A 68K erase will use one 64K erase, and one 4K erase
-+ on supporting hardware.
-+
- config MTD_SPI_NOR_USE_4K_SECTORS
- bool "Use small 4096 B erase sectors"
- default y
---- a/drivers/mtd/spi-nor/core.c
-+++ b/drivers/mtd/spi-nor/core.c
-@@ -1150,6 +1150,8 @@ static u8 spi_nor_convert_3to4_erase(u8
-
- static bool spi_nor_has_uniform_erase(const struct spi_nor *nor)
- {
-+ if (IS_ENABLED(CONFIG_MTD_SPI_NOR_USE_VARIABLE_ERASE))
-+ return false;
- return !!nor->params->erase_map.uniform_erase_type;
- }
-
-@@ -2582,6 +2584,7 @@ static int spi_nor_select_erase(struct s
- {
- struct spi_nor_erase_map *map = &nor->params->erase_map;
- const struct spi_nor_erase_type *erase = NULL;
-+ const struct spi_nor_erase_type *erase_minor = NULL;
- struct mtd_info *mtd = &nor->mtd;
- u32 wanted_size = nor->info->sector_size;
- int i;
-@@ -2614,8 +2617,9 @@ static int spi_nor_select_erase(struct s
- */
- for (i = SNOR_ERASE_TYPE_MAX - 1; i >= 0; i--) {
- if (map->erase_type[i].size) {
-- erase = &map->erase_type[i];
-- break;
-+ if (!erase)
-+ erase = &map->erase_type[i];
-+ erase_minor = &map->erase_type[i];
- }
- }
-
-@@ -2623,6 +2627,9 @@ static int spi_nor_select_erase(struct s
- return -EINVAL;
-
- mtd->erasesize = erase->size;
-+ if (IS_ENABLED(CONFIG_MTD_SPI_NOR_USE_VARIABLE_ERASE) &&
-+ erase_minor && erase_minor->size < erase->size)
-+ mtd->erasesize_minor = erase_minor->size;
- return 0;
- }
-
---- a/include/linux/mtd/mtd.h
-+++ b/include/linux/mtd/mtd.h
-@@ -245,6 +245,8 @@ struct mtd_info {
- * information below if they desire
- */
- uint32_t erasesize;
-+ /* "Minor" (smallest) erase size supported by the whole device */
-+ uint32_t erasesize_minor;
- /* Minimal writable flash unit size. In case of NOR flash it is 1 (even
- * though individual bits can be cleared), in case of NAND flash it is
- * one NAND page (or half, or one-fourths of it), in case of ECC-ed NOR
+++ /dev/null
-Date: Thu, 01 May 2025 18:19:16 +0200
-Subject: [PATCH next] spi: spi-qpic-snand: validate user/chip specific ECC
- properties
-
-The driver only supports 512 bytes ECC step size and 4 bit ECC strength
-at the moment, however it does not reject unsupported step/strength
-configurations. Due to this, whenever the driver is used with a flash
-chip which needs stronger ECC protection, the following warning is shown
-in the kernel log:
-
- [ 0.574648] spi-nand spi0.0: GigaDevice SPI NAND was found.
- [ 0.635748] spi-nand spi0.0: 256 MiB, block size: 128 KiB, page size: 2048, OOB size: 128
- [ 0.649079] nand: WARNING: (null): the ECC used on your system is too weak compared to the one required by the NAND chip
-
-Although the message indicates that something is wrong, but it often gets
-unnoticed, which can cause serious problems. For example when the user
-writes something into the flash chip despite the warning, the written data
-may won't be readable by the bootloader or by the boot ROM. In the worst
-case, when the attached SPI NAND chip is the boot device, the board may not
-be able to boot anymore.
-
-Also, it is not even possible to create a backup of the flash, because
-reading its content results in bogus data. For example, dumping the first
-page of the flash gives this:
-
- # hexdump -C -n 2048 /dev/mtd0
- 00000000 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f |................|
- *
- 00000040 0f 0f 0f 0f 0f 0f 0f 0d 0f 0f 0f 0f 0f 0f 0f 0f |................|
- 00000050 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f |................|
- *
- 000001c0 0f 0f 0f 0f ff 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f |................|
- 000001d0 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f |................|
- *
- 00000200 0f 0f 0f 0f f5 5b ff ff 0f 0f 0f 0f 0f 0f 0f 0f |.....[..........|
- 00000210 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f |................|
- *
- 000002f0 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 1f 0f 0f |................|
- 00000300 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f |................|
- *
- 000003c0 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f ff 0f 0f 0f |................|
- 000003d0 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f |................|
- *
- 00000400 0f 0f 0f 0f 0f 0f 0f 0f e9 74 c9 06 f5 5b ff ff |.........t...[..|
- 00000410 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f |................|
- *
- 000005d0 0f 0f 0f 0f ff 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f |................|
- 000005e0 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f |................|
- *
- 00000600 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f c6 be 0f c3 |................|
- 00000610 e9 74 c9 06 f5 5b ff ff 0f 0f 0f 0f 0f 0f 0f 0f |.t...[..........|
- 00000620 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f |................|
- *
- 00000770 0f 0f 0f 0f 8f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f |................|
- 00000780 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f |................|
- *
- 00000800
- #
-
-Doing the same by using the downstream kernel results in different output:
-
- # hexdump -C -n 2048 /dev/mtd0
- 00000000 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f |................|
- *
- 00000800
- #
-
-This patch adds some sanity checks to the code to prevent using the driver
-with unsupported ECC step/strength configurations. After the change, probing
-of the driver fails in such cases:
-
- [ 0.655038] spi-nand spi0.0: GigaDevice SPI NAND was found.
- [ 0.659159] spi-nand spi0.0: 256 MiB, block size: 128 KiB, page size: 2048, OOB size: 128
- [ 0.669138] qcom_snand 79b0000.spi: only 4 bits ECC strength is supported
- [ 0.677476] nand: No suitable ECC configuration
- [ 0.689909] spi-nand spi0.0: probe with driver spi-nand failed with error -95
-
-This helps to avoid the aforementioned hassles until support for 8 bit ECC
-strength gets implemented.
-
-Fixes: 7304d1909080 ("spi: spi-qpic: add driver for QCOM SPI NAND flash Interface")
----
-Marked for next because it depends on commit f48d80503504 ("spi: spi-qpic-snand:
-use kmalloc() for OOB buffer allocation").
----
- drivers/spi/spi-qpic-snand.c | 42 +++++++++++++++++++++++++++++++++++++-----
- 1 file changed, 37 insertions(+), 5 deletions(-)
-
-
----
-base-commit: a7f035c2c72496cf7ac34bfaa8c289e0d4c45836
-change-id: 20250501-qpic-snand-validate-ecc-383b3e33e238
-
-Best regards,
-
---- a/drivers/spi/spi-qpic-snand.c
-+++ b/drivers/spi/spi-qpic-snand.c
-@@ -249,9 +249,11 @@ static const struct mtd_ooblayout_ops qc
- static int qcom_spi_ecc_init_ctx_pipelined(struct nand_device *nand)
- {
- struct qcom_nand_controller *snandc = nand_to_qcom_snand(nand);
-+ struct nand_ecc_props *reqs = &nand->ecc.requirements;
-+ struct nand_ecc_props *user = &nand->ecc.user_conf;
- struct nand_ecc_props *conf = &nand->ecc.ctx.conf;
- struct mtd_info *mtd = nanddev_to_mtd(nand);
-- int cwperpage, bad_block_byte;
-+ int cwperpage, bad_block_byte, ret;
- struct qpic_ecc *ecc_cfg;
-
- cwperpage = mtd->writesize / NANDC_STEP_SIZE;
-@@ -260,11 +262,39 @@ static int qcom_spi_ecc_init_ctx_pipelin
- ecc_cfg = kzalloc(sizeof(*ecc_cfg), GFP_KERNEL);
- if (!ecc_cfg)
- return -ENOMEM;
-+
-+ if (user->step_size && user->strength) {
-+ ecc_cfg->step_size = user->step_size;
-+ ecc_cfg->strength = user->strength;
-+ } else if (reqs->step_size && reqs->strength) {
-+ ecc_cfg->step_size = reqs->step_size;
-+ ecc_cfg->strength = reqs->strength;
-+ } else {
-+ /* use defaults */
-+ ecc_cfg->step_size = NANDC_STEP_SIZE;
-+ ecc_cfg->strength = 4;
-+ }
-+
-+ if (ecc_cfg->step_size != NANDC_STEP_SIZE) {
-+ dev_err(snandc->dev,
-+ "only %u bytes ECC step size is supported\n",
-+ NANDC_STEP_SIZE);
-+ ret = -EOPNOTSUPP;
-+ goto err_free_ecc_cfg;
-+ }
-+
-+ if (ecc_cfg->strength != 4) {
-+ dev_err(snandc->dev,
-+ "only 4 bits ECC strength is supported\n");
-+ ret = -EOPNOTSUPP;
-+ goto err_free_ecc_cfg;
-+ }
-+
- snandc->qspi->oob_buf = kmalloc(mtd->writesize + mtd->oobsize,
- GFP_KERNEL);
- if (!snandc->qspi->oob_buf) {
-- kfree(ecc_cfg);
-- return -ENOMEM;
-+ ret = -ENOMEM;
-+ goto err_free_ecc_cfg;
- }
-
- memset(snandc->qspi->oob_buf, 0xff, mtd->writesize + mtd->oobsize);
-@@ -279,8 +309,6 @@ static int qcom_spi_ecc_init_ctx_pipelin
- ecc_cfg->bytes = ecc_cfg->ecc_bytes_hw + ecc_cfg->spare_bytes + ecc_cfg->bbm_size;
-
- ecc_cfg->steps = 4;
-- ecc_cfg->strength = 4;
-- ecc_cfg->step_size = 512;
- ecc_cfg->cw_data = 516;
- ecc_cfg->cw_size = ecc_cfg->cw_data + ecc_cfg->bytes;
- bad_block_byte = mtd->writesize - ecc_cfg->cw_size * (cwperpage - 1) + 1;
-@@ -338,6 +366,10 @@ static int qcom_spi_ecc_init_ctx_pipelin
- ecc_cfg->strength, ecc_cfg->step_size);
-
- return 0;
-+
-+err_free_ecc_cfg:
-+ kfree(ecc_cfg);
-+ return ret;
- }
-
- static void qcom_spi_ecc_cleanup_ctx_pipelined(struct nand_device *nand)
+++ /dev/null
-Date: Fri, 02 May 2025 21:31:16 +0200
-Subject: [PATCH next 1/2] mtd: nand: qpic-common: add defines for ECC_MODE
- values
-
-Add defines for the values of the ECC_MODE field of the NAND_DEV0_ECC_CFG
-register and change both the 'qcom-nandc' and 'spi-qpic-snand' drivers to
-use those instead of magic numbers.
-
-No functional changes. This is in preparation for adding 8 bit ECC strength
-support for the 'spi-qpic-snand' driver.
-
----
- drivers/mtd/nand/raw/qcom_nandc.c | 6 +++---
- drivers/spi/spi-qpic-snand.c | 2 +-
- include/linux/mtd/nand-qpic-common.h | 2 ++
- 3 files changed, 6 insertions(+), 4 deletions(-)
-
---- a/drivers/mtd/nand/raw/qcom_nandc.c
-+++ b/drivers/mtd/nand/raw/qcom_nandc.c
-@@ -1379,7 +1379,7 @@ static int qcom_nand_attach_chip(struct
- struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
- int cwperpage, bad_block_byte, ret;
- bool wide_bus;
-- int ecc_mode = 1;
-+ int ecc_mode = ECC_MODE_8BIT;
-
- /* controller only supports 512 bytes data steps */
- ecc->size = NANDC_STEP_SIZE;
-@@ -1400,7 +1400,7 @@ static int qcom_nand_attach_chip(struct
- if (ecc->strength >= 8) {
- /* 8 bit ECC defaults to BCH ECC on all platforms */
- host->bch_enabled = true;
-- ecc_mode = 1;
-+ ecc_mode = ECC_MODE_8BIT;
-
- if (wide_bus) {
- host->ecc_bytes_hw = 14;
-@@ -1420,7 +1420,7 @@ static int qcom_nand_attach_chip(struct
- if (nandc->props->ecc_modes & ECC_BCH_4BIT) {
- /* BCH */
- host->bch_enabled = true;
-- ecc_mode = 0;
-+ ecc_mode = ECC_MODE_4BIT;
-
- if (wide_bus) {
- host->ecc_bytes_hw = 8;
---- a/drivers/spi/spi-qpic-snand.c
-+++ b/drivers/spi/spi-qpic-snand.c
-@@ -349,7 +349,7 @@ static int qcom_spi_ecc_init_ctx_pipelin
- FIELD_PREP(ECC_SW_RESET, 0) |
- FIELD_PREP(ECC_NUM_DATA_BYTES_MASK, ecc_cfg->cw_data) |
- FIELD_PREP(ECC_FORCE_CLK_OPEN, 1) |
-- FIELD_PREP(ECC_MODE_MASK, 0) |
-+ FIELD_PREP(ECC_MODE_MASK, ECC_MODE_4BIT) |
- FIELD_PREP(ECC_PARITY_SIZE_BYTES_BCH_MASK, ecc_cfg->ecc_bytes_hw);
-
- ecc_cfg->ecc_buf_cfg = 0x203 << NUM_STEPS;
---- a/include/linux/mtd/nand-qpic-common.h
-+++ b/include/linux/mtd/nand-qpic-common.h
-@@ -101,6 +101,8 @@
- #define ECC_SW_RESET BIT(1)
- #define ECC_MODE 4
- #define ECC_MODE_MASK GENMASK(5, 4)
-+#define ECC_MODE_4BIT 0
-+#define ECC_MODE_8BIT 1
- #define ECC_PARITY_SIZE_BYTES_BCH 8
- #define ECC_PARITY_SIZE_BYTES_BCH_MASK GENMASK(12, 8)
- #define ECC_NUM_DATA_BYTES 16
+++ /dev/null
-Date: Fri, 02 May 2025 21:31:17 +0200
-Subject: [PATCH next 2/2] spi: spi-qpic-snand: add support for 8 bits ECC
- strength
-
-Even though the hardware supports 8 bits ECC strength, but that is not
-handled in the driver yet. This change adds the missing bits in order
-to allow using the driver with chips which require 8 bits ECC strength.
-
-No functional changes intended with regard to the existing 4 bits ECC
-strength support.
-
-Tested on an IPQ9574 platform using a GigaDevice GD5F2GM7REYIG chip.
-
----
-mtdtest results:
-
- # dmesg | grep nand
- [ 0.678143] spi-nand spi0.0: GigaDevice SPI NAND was found.
- [ 0.687393] spi-nand spi0.0: 256 MiB, block size: 128 KiB, page size: 2048, OOB size: 128
- # cat /proc/mtd
- dev: size erasesize name
- mtd0: 10000000 00020000 "spi0.0"
- # insmod mtd_test
- # insmod mtd_speedtest dev=0
- [ 63.128425]
- [ 63.128452] =================================================
- [ 63.128979] mtd_speedtest: MTD device: 0
- [ 63.134622] mtd_speedtest: MTD device size 268435456, eraseblock size 131072, page size 2048, count of eraseblocks 2048, pages per eraseblock 64, OOB size 128
- [ 63.139561] mtd_test: scanning for bad eraseblocks
- [ 63.756447] mtd_test: scanned 2048 eraseblocks, 0 are bad
- [ 71.085514] mtd_speedtest: testing eraseblock write speed
- [ 202.745977] mtd_speedtest: eraseblock write speed is 1991 KiB/s
- [ 202.746022] mtd_speedtest: testing eraseblock read speed
- [ 284.104591] mtd_speedtest: eraseblock read speed is 3222 KiB/s
- [ 291.405533] mtd_speedtest: testing page write speed
- [ 422.516341] mtd_speedtest: page write speed is 1999 KiB/s
- [ 422.516384] mtd_speedtest: testing page read speed
- [ 504.144630] mtd_speedtest: page read speed is 3211 KiB/s
- [ 511.476726] mtd_speedtest: testing 2 page write speed
- [ 643.114443] mtd_speedtest: 2 page write speed is 1991 KiB/s
- [ 643.114485] mtd_speedtest: testing 2 page read speed
- [ 724.434752] mtd_speedtest: 2 page read speed is 3223 KiB/s
- [ 724.434796] mtd_speedtest: Testing erase speed
- [ 731.792729] mtd_speedtest: erase speed is 35648 KiB/s
- [ 731.792772] mtd_speedtest: Testing 2x multi-block erase speed
- [ 739.162513] mtd_speedtest: 2x multi-block erase speed is 35589 KiB/s
- [ 739.162558] mtd_speedtest: Testing 4x multi-block erase speed
- [ 746.486241] mtd_speedtest: 4x multi-block erase speed is 35820 KiB/s
- [ 746.486287] mtd_speedtest: Testing 8x multi-block erase speed
- [ 753.789683] mtd_speedtest: 8x multi-block erase speed is 35919 KiB/s
- [ 753.789728] mtd_speedtest: Testing 16x multi-block erase speed
- [ 761.093075] mtd_speedtest: 16x multi-block erase speed is 35920 KiB/s
- [ 761.093120] mtd_speedtest: Testing 32x multi-block erase speed
- [ 768.396145] mtd_speedtest: 32x multi-block erase speed is 35922 KiB/s
- [ 768.396222] mtd_speedtest: Testing 64x multi-block erase speed
- [ 775.699819] mtd_speedtest: 64x multi-block erase speed is 35918 KiB/s
- [ 775.699863] mtd_speedtest: finished
- [ 775.705259] =================================================
- # insmod mtd_readtest dev=0
- [ 919.060671]
- [ 919.060699] =================================================
- [ 919.061226] mtd_readtest: MTD device: 0
- [ 919.066957] mtd_readtest: MTD device size 268435456, eraseblock size 131072, page size 2048, count of eraseblocks 2048, pages per eraseblock 64, OOB size 128
- [ 919.070556] mtd_test: scanning for bad eraseblocks
- [ 919.086016] mtd_test: scanned 2048 eraseblocks, 0 are bad
- [ 919.089465] mtd_readtest: testing page read
- [ 1090.778227] mtd_readtest: finished
- [ 1090.778286] =================================================
- # insmod mtd_pagetest dev=0
- [ 1216.297313]
- [ 1216.297341] =================================================
- [ 1216.297867] mtd_pagetest: MTD device: 0
- [ 1216.303509] mtd_pagetest: MTD device size 268435456, eraseblock size 131072, page size 2048, count of eraseblocks 2048, pages per eraseblock 64, OOB size 128
- [ 1216.307213] mtd_test: scanning for bad eraseblocks
- [ 1216.322680] mtd_test: scanned 2048 eraseblocks, 0 are bad
- [ 1216.326077] mtd_pagetest: erasing whole device
- [ 1223.694968] mtd_pagetest: erased 2048 eraseblocks
- [ 1223.695009] mtd_pagetest: writing whole device
- [ 1223.763930] mtd_pagetest: written up to eraseblock 0
- [ 1240.268942] mtd_pagetest: written up to eraseblock 256
- [ 1256.641498] mtd_pagetest: written up to eraseblock 512
- [ 1273.139048] mtd_pagetest: written up to eraseblock 768
- [ 1289.718929] mtd_pagetest: written up to eraseblock 1024
- [ 1306.244553] mtd_pagetest: written up to eraseblock 1280
- [ 1322.939723] mtd_pagetest: written up to eraseblock 1536
- [ 1339.246937] mtd_pagetest: written up to eraseblock 1792
- [ 1355.613729] mtd_pagetest: written 2048 eraseblocks
- [ 1355.613770] mtd_pagetest: verifying all eraseblocks
- [ 1355.854290] mtd_pagetest: verified up to eraseblock 0
- [ 1416.657733] mtd_pagetest: verified up to eraseblock 256
- [ 1477.384593] mtd_pagetest: verified up to eraseblock 512
- [ 1538.008142] mtd_pagetest: verified up to eraseblock 768
- [ 1599.080797] mtd_pagetest: verified up to eraseblock 1024
- [ 1660.775431] mtd_pagetest: verified up to eraseblock 1280
- [ 1722.177149] mtd_pagetest: verified up to eraseblock 1536
- [ 1783.090166] mtd_pagetest: verified up to eraseblock 1792
- [ 1844.450757] mtd_pagetest: verified 2048 eraseblocks
- [ 1844.450798] mtd_pagetest: crosstest
- [ 1844.455676] mtd_pagetest: reading page at 0x0
- [ 1844.458603] mtd_pagetest: reading page at 0xffff800
- [ 1844.463047] mtd_pagetest: reading page at 0x0
- [ 1844.467790] mtd_pagetest: verifying pages read at 0x0 match
- [ 1844.471636] mtd_pagetest: crosstest ok
- [ 1844.477062] mtd_pagetest: erasecrosstest
- [ 1844.480833] mtd_pagetest: erasing block 0
- [ 1844.488498] mtd_pagetest: writing 1st page of block 0
- [ 1844.489821] mtd_pagetest: reading 1st page of block 0
- [ 1844.494475] mtd_pagetest: verifying 1st page of block 0
- [ 1844.498942] mtd_pagetest: erasing block 0
- [ 1844.507505] mtd_pagetest: writing 1st page of block 0
- [ 1844.509042] mtd_pagetest: erasing block 2047
- [ 1844.516725] mtd_pagetest: reading 1st page of block 0
- [ 1844.518087] mtd_pagetest: verifying 1st page of block 0
- [ 1844.522415] mtd_pagetest: erasecrosstest ok
- [ 1844.527495] mtd_pagetest: erasetest
- [ 1844.531613] mtd_pagetest: erasing block 0
- [ 1844.538671] mtd_pagetest: writing 1st page of block 0
- [ 1844.540249] mtd_pagetest: erasing block 0
- [ 1844.547869] mtd_pagetest: reading 1st page of block 0
- [ 1844.548927] mtd_pagetest: verifying 1st page of block 0 is all 0xff
- [ 1844.553326] mtd_pagetest: erasetest ok
- [ 1844.559440] mtd_pagetest: finished with 0 errors
- [ 1844.563233] =================================================
- # insmod mtd_subpagetest dev=0
- [ 1942.429708]
- [ 1942.429736] =================================================
- [ 1942.430262] mtd_subpagetest: MTD device: 0
- [ 1942.435905] mtd_subpagetest: MTD device size 268435456, eraseblock size 131072, page size 2048, subpage size 2048, count of eraseblocks 2048, pages per eraseblock 64, OOB size 128
- [ 1942.439994] mtd_test: scanning for bad eraseblocks
- [ 1942.457111] mtd_test: scanned 2048 eraseblocks, 0 are bad
- [ 1949.824564] mtd_subpagetest: writing whole device
- [ 1949.826670] mtd_subpagetest: written up to eraseblock 0
- [ 1950.351816] mtd_subpagetest: written up to eraseblock 256
- [ 1950.875797] mtd_subpagetest: written up to eraseblock 512
- [ 1951.399912] mtd_subpagetest: written up to eraseblock 768
- [ 1951.923618] mtd_subpagetest: written up to eraseblock 1024
- [ 1952.447361] mtd_subpagetest: written up to eraseblock 1280
- [ 1952.970834] mtd_subpagetest: written up to eraseblock 1536
- [ 1953.494635] mtd_subpagetest: written up to eraseblock 1792
- [ 1954.016265] mtd_subpagetest: written 2048 eraseblocks
- [ 1954.016294] mtd_subpagetest: verifying all eraseblocks
- [ 1954.021617] mtd_subpagetest: verified up to eraseblock 0
- [ 1954.347458] mtd_subpagetest: verified up to eraseblock 256
- [ 1954.667446] mtd_subpagetest: verified up to eraseblock 512
- [ 1954.987343] mtd_subpagetest: verified up to eraseblock 768
- [ 1955.307385] mtd_subpagetest: verified up to eraseblock 1024
- [ 1955.627462] mtd_subpagetest: verified up to eraseblock 1280
- [ 1955.947277] mtd_subpagetest: verified up to eraseblock 1536
- [ 1956.266834] mtd_subpagetest: verified up to eraseblock 1792
- [ 1956.585581] mtd_subpagetest: verified 2048 eraseblocks
- [ 1963.889308] mtd_subpagetest: verifying all eraseblocks for 0xff
- [ 1963.930487] mtd_subpagetest: verified up to eraseblock 0
- [ 1974.592567] mtd_subpagetest: verified up to eraseblock 256
- [ 1985.180953] mtd_subpagetest: verified up to eraseblock 512
- [ 1995.805397] mtd_subpagetest: verified up to eraseblock 768
- [ 2006.348859] mtd_subpagetest: verified up to eraseblock 1024
- [ 2016.900530] mtd_subpagetest: verified up to eraseblock 1280
- [ 2027.447587] mtd_subpagetest: verified up to eraseblock 1536
- [ 2037.962383] mtd_subpagetest: verified up to eraseblock 1792
- [ 2048.587863] mtd_subpagetest: verified 2048 eraseblocks
- [ 2048.587906] mtd_subpagetest: writing whole device
- [ 2048.648174] mtd_subpagetest: written up to eraseblock 0
- [ 2062.643145] mtd_subpagetest: written up to eraseblock 256
- [ 2076.699015] mtd_subpagetest: written up to eraseblock 512
- [ 2091.004910] mtd_subpagetest: written up to eraseblock 768
- [ 2105.149879] mtd_subpagetest: written up to eraseblock 1024
- [ 2119.470691] mtd_subpagetest: written up to eraseblock 1280
- [ 2133.746861] mtd_subpagetest: written up to eraseblock 1536
- [ 2147.776477] mtd_subpagetest: written up to eraseblock 1792
- [ 2161.947734] mtd_subpagetest: written 2048 eraseblocks
- [ 2161.947776] mtd_subpagetest: verifying all eraseblocks
- [ 2161.986109] mtd_subpagetest: verified up to eraseblock 0
- [ 2170.818316] mtd_subpagetest: verified up to eraseblock 256
- [ 2179.596875] mtd_subpagetest: verified up to eraseblock 512
- [ 2188.405116] mtd_subpagetest: verified up to eraseblock 768
- [ 2197.188588] mtd_subpagetest: verified up to eraseblock 1024
- [ 2206.002204] mtd_subpagetest: verified up to eraseblock 1280
- [ 2214.784815] mtd_subpagetest: verified up to eraseblock 1536
- [ 2223.557141] mtd_subpagetest: verified up to eraseblock 1792
- [ 2232.472832] mtd_subpagetest: verified 2048 eraseblocks
- [ 2239.818213] mtd_subpagetest: verifying all eraseblocks for 0xff
- [ 2239.861404] mtd_subpagetest: verified up to eraseblock 0
- [ 2250.439035] mtd_subpagetest: verified up to eraseblock 256
- [ 2261.176485] mtd_subpagetest: verified up to eraseblock 512
- [ 2271.713183] mtd_subpagetest: verified up to eraseblock 768
- [ 2282.356892] mtd_subpagetest: verified up to eraseblock 1024
- [ 2292.891424] mtd_subpagetest: verified up to eraseblock 1280
- [ 2303.543110] mtd_subpagetest: verified up to eraseblock 1536
- [ 2314.116690] mtd_subpagetest: verified up to eraseblock 1792
- [ 2324.607804] mtd_subpagetest: verified 2048 eraseblocks
- [ 2324.607846] mtd_subpagetest: finished with 0 errors
- [ 2324.611859] =================================================
- # insmod mtd_oobtest dev=0
- [ 2336.159109]
- [ 2336.159138] =================================================
- [ 2336.159664] mtd_oobtest: MTD device: 0
- [ 2336.165308] mtd_oobtest: MTD device size 268435456, eraseblock size 131072, page size 2048, count of eraseblocks 2048, pages per eraseblock 64, OOB size 128
- [ 2336.169043] mtd_test: scanning for bad eraseblocks
- [ 2336.184354] mtd_test: scanned 2048 eraseblocks, 0 are bad
- [ 2336.187716] mtd_oobtest: test 1 of 5
- [ 2343.495966] mtd_oobtest: writing OOBs of whole device
- [ 2343.496073] mtd_oobtest: written up to eraseblock 0
- [ 2343.516803] mtd_oobtest: written up to eraseblock 256
- [ 2343.533527] mtd_oobtest: written up to eraseblock 512
- [ 2343.549945] mtd_oobtest: written up to eraseblock 768
- [ 2343.563666] mtd_oobtest: written up to eraseblock 1024
- [ 2343.575186] mtd_oobtest: written up to eraseblock 1280
- [ 2343.584310] mtd_oobtest: written up to eraseblock 1536
- [ 2343.593011] mtd_oobtest: written up to eraseblock 1792
- [ 2343.600847] mtd_oobtest: written 2048 eraseblocks
- [ 2343.600861] mtd_oobtest: verifying all eraseblocks
- [ 2343.604542] mtd_oobtest: verified up to eraseblock 0
- [ 2343.616606] mtd_oobtest: verified up to eraseblock 256
- [ 2343.623992] mtd_oobtest: verified up to eraseblock 512
- [ 2343.631390] mtd_oobtest: verified up to eraseblock 768
- [ 2343.638788] mtd_oobtest: verified up to eraseblock 1024
- [ 2343.646184] mtd_oobtest: verified up to eraseblock 1280
- [ 2343.653570] mtd_oobtest: verified up to eraseblock 1536
- [ 2343.660970] mtd_oobtest: verified up to eraseblock 1792
- [ 2343.668356] mtd_oobtest: verified 2048 eraseblocks
- [ 2343.668369] mtd_oobtest: test 2 of 5
- [ 2350.985635] mtd_oobtest: writing OOBs of whole device
- [ 2350.985743] mtd_oobtest: written up to eraseblock 0
- [ 2351.006445] mtd_oobtest: written up to eraseblock 256
- [ 2351.023170] mtd_oobtest: written up to eraseblock 512
- [ 2351.039645] mtd_oobtest: written up to eraseblock 768
- [ 2351.053395] mtd_oobtest: written up to eraseblock 1024
- [ 2351.064954] mtd_oobtest: written up to eraseblock 1280
- [ 2351.074144] mtd_oobtest: written up to eraseblock 1536
- [ 2351.082848] mtd_oobtest: written up to eraseblock 1792
- [ 2351.090707] mtd_oobtest: written 2048 eraseblocks
- [ 2351.090721] mtd_oobtest: verifying all eraseblocks
- [ 2351.094373] mtd_oobtest: verified up to eraseblock 0
- [ 2351.099353] mtd_oobtest: verified up to eraseblock 256
- [ 2351.104460] mtd_oobtest: verified up to eraseblock 512
- [ 2351.109437] mtd_oobtest: verified up to eraseblock 768
- [ 2351.114528] mtd_oobtest: verified up to eraseblock 1024
- [ 2351.119683] mtd_oobtest: verified up to eraseblock 1280
- [ 2351.124772] mtd_oobtest: verified up to eraseblock 1536
- [ 2351.129996] mtd_oobtest: verified up to eraseblock 1792
- [ 2351.135187] mtd_oobtest: verified 2048 eraseblocks
- [ 2351.140130] mtd_oobtest: test 3 of 5
- [ 2358.448438] mtd_oobtest: writing OOBs of whole device
- [ 2358.448546] mtd_oobtest: written up to eraseblock 0
- [ 2358.469297] mtd_oobtest: written up to eraseblock 256
- [ 2358.486095] mtd_oobtest: written up to eraseblock 512
- [ 2358.501993] mtd_oobtest: written up to eraseblock 768
- [ 2358.515473] mtd_oobtest: written up to eraseblock 1024
- [ 2358.526708] mtd_oobtest: written up to eraseblock 1280
- [ 2358.535426] mtd_oobtest: written up to eraseblock 1536
- [ 2358.544152] mtd_oobtest: written up to eraseblock 1792
- [ 2358.551732] mtd_oobtest: written 2048 eraseblocks
- [ 2358.551744] mtd_oobtest: verifying all eraseblocks
- [ 2358.555424] mtd_oobtest: verified up to eraseblock 0
- [ 2358.567572] mtd_oobtest: verified up to eraseblock 256
- [ 2358.575045] mtd_oobtest: verified up to eraseblock 512
- [ 2358.582537] mtd_oobtest: verified up to eraseblock 768
- [ 2358.590024] mtd_oobtest: verified up to eraseblock 1024
- [ 2358.597511] mtd_oobtest: verified up to eraseblock 1280
- [ 2358.604984] mtd_oobtest: verified up to eraseblock 1536
- [ 2358.612468] mtd_oobtest: verified up to eraseblock 1792
- [ 2358.619923] mtd_oobtest: verified 2048 eraseblocks
- [ 2358.619936] mtd_oobtest: test 4 of 5
- [ 2365.924669] mtd_oobtest: attempting to start write past end of OOB
- [ 2365.924711] mtd_oobtest: an error is expected...
- [ 2365.929795] mtd_oobtest: error occurred as expected
- [ 2365.934520] mtd_oobtest: attempting to start read past end of OOB
- [ 2365.939150] mtd_oobtest: an error is expected...
- [ 2365.945371] mtd_oobtest: error occurred as expected
- [ 2365.950087] mtd_oobtest: attempting to write past end of device
- [ 2365.954660] mtd_oobtest: an error is expected...
- [ 2365.960623] mtd_oobtest: error occurred as expected
- [ 2365.965422] mtd_oobtest: attempting to read past end of device
- [ 2365.970064] mtd_oobtest: an error is expected...
- [ 2365.975925] mtd_oobtest: error occurred as expected
- [ 2365.984256] mtd_oobtest: attempting to write past end of device
- [ 2365.985300] mtd_oobtest: an error is expected...
- [ 2365.991242] mtd_oobtest: error: wrote past end of device
- [ 2365.996064] mtd_oobtest: attempting to read past end of device
- [ 2366.001389] mtd_oobtest: an error is expected...
- [ 2366.007028] mtd_oobtest: error: read past end of device
- [ 2366.011776] mtd_oobtest: test 5 of 5
- [ 2373.317991] mtd_oobtest: writing OOBs of whole device
- [ 2373.318034] mtd_oobtest: written up to eraseblock 0
- [ 2373.322028] mtd_oobtest: written up to eraseblock 0
- [ 2373.327465] mtd_oobtest: written up to eraseblock 256
- [ 2373.331576] mtd_oobtest: written up to eraseblock 256
- [ 2373.337501] mtd_oobtest: written up to eraseblock 512
- [ 2373.341820] mtd_oobtest: written up to eraseblock 512
- [ 2373.347566] mtd_oobtest: written up to eraseblock 768
- [ 2373.351888] mtd_oobtest: written up to eraseblock 768
- [ 2373.357634] mtd_oobtest: written up to eraseblock 1024
- [ 2373.361957] mtd_oobtest: written up to eraseblock 1024
- [ 2373.367710] mtd_oobtest: written up to eraseblock 1280
- [ 2373.372113] mtd_oobtest: written up to eraseblock 1280
- [ 2373.377841] mtd_oobtest: written up to eraseblock 1536
- [ 2373.382355] mtd_oobtest: written up to eraseblock 1536
- [ 2373.387962] mtd_oobtest: written up to eraseblock 1792
- [ 2373.392597] mtd_oobtest: written up to eraseblock 1792
- [ 2373.398190] mtd_oobtest: written 2047 eraseblocks
- [ 2373.402838] mtd_oobtest: verifying all eraseblocks
- [ 2373.407629] mtd_oobtest: verified up to eraseblock 0
- [ 2373.412483] mtd_oobtest: verified up to eraseblock 256
- [ 2373.417625] mtd_oobtest: verified up to eraseblock 512
- [ 2373.422518] mtd_oobtest: verified up to eraseblock 768
- [ 2373.427650] mtd_oobtest: verified up to eraseblock 1024
- [ 2373.432760] mtd_oobtest: verified up to eraseblock 1280
- [ 2373.437912] mtd_oobtest: verified up to eraseblock 1536
- [ 2373.443091] mtd_oobtest: verified up to eraseblock 1792
- [ 2373.448337] mtd_oobtest: verified 2047 eraseblocks
- [ 2373.453358] mtd_oobtest: finished with 2 errors
- [ 2373.458250] =================================================
-
-Note: the two errors are present even even without this patch when testing
-the driver with a flash chip requiring 4 bits ECC strength.
-
- # insmod mtd_stresstest dev=0
- [ 2383.256453]
- [ 2383.256482] =================================================
- [ 2383.257008] mtd_stresstest: MTD device: 0
- [ 2383.262650] mtd_stresstest: MTD device size 268435456, eraseblock size 131072, page size 2048, count of eraseblocks 2048, pages per eraseblock 64, OOB size 128
- [ 2383.268254] mtd_test: scanning for bad eraseblocks
- [ 2383.281992] mtd_test: scanned 2048 eraseblocks, 0 are bad
- [ 2383.285565] mtd_stresstest: doing operations
- [ 2383.291047] mtd_stresstest: 0 operations done
- [ 2427.841267] mtd_stresstest: 1024 operations done
- [ 2471.142229] mtd_stresstest: 2048 operations done
- [ 2514.405277] mtd_stresstest: 3072 operations done
- [ 2555.451926] mtd_stresstest: 4096 operations done
- [ 2598.107133] mtd_stresstest: 5120 operations done
- [ 2639.936952] mtd_stresstest: 6144 operations done
- [ 2680.724751] mtd_stresstest: 7168 operations done
- [ 2720.344163] mtd_stresstest: 8192 operations done
- [ 2761.645640] mtd_stresstest: 9216 operations done
- [ 2791.760534] mtd_stresstest: finished, 10000 operations done
- [ 2791.760817] =================================================
- #
----
- drivers/spi/spi-qpic-snand.c | 21 ++++++++++++++++-----
- 1 file changed, 16 insertions(+), 5 deletions(-)
-
---- a/drivers/spi/spi-qpic-snand.c
-+++ b/drivers/spi/spi-qpic-snand.c
-@@ -283,9 +283,22 @@ static int qcom_spi_ecc_init_ctx_pipelin
- goto err_free_ecc_cfg;
- }
-
-- if (ecc_cfg->strength != 4) {
-+ switch (ecc_cfg->strength) {
-+ case 4:
-+ ecc_cfg->ecc_mode = ECC_MODE_4BIT;
-+ ecc_cfg->ecc_bytes_hw = 7;
-+ ecc_cfg->spare_bytes = 4;
-+ break;
-+
-+ case 8:
-+ ecc_cfg->ecc_mode = ECC_MODE_8BIT;
-+ ecc_cfg->ecc_bytes_hw = 13;
-+ ecc_cfg->spare_bytes = 2;
-+ break;
-+
-+ default:
- dev_err(snandc->dev,
-- "only 4 bits ECC strength is supported\n");
-+ "only 4 or 8 bits ECC strength is supported\n");
- ret = -EOPNOTSUPP;
- goto err_free_ecc_cfg;
- }
-@@ -302,8 +315,6 @@ static int qcom_spi_ecc_init_ctx_pipelin
- nand->ecc.ctx.priv = ecc_cfg;
- snandc->qspi->mtd = mtd;
-
-- ecc_cfg->ecc_bytes_hw = 7;
-- ecc_cfg->spare_bytes = 4;
- ecc_cfg->bbm_size = 1;
- ecc_cfg->bch_enabled = true;
- ecc_cfg->bytes = ecc_cfg->ecc_bytes_hw + ecc_cfg->spare_bytes + ecc_cfg->bbm_size;
-@@ -349,7 +360,7 @@ static int qcom_spi_ecc_init_ctx_pipelin
- FIELD_PREP(ECC_SW_RESET, 0) |
- FIELD_PREP(ECC_NUM_DATA_BYTES_MASK, ecc_cfg->cw_data) |
- FIELD_PREP(ECC_FORCE_CLK_OPEN, 1) |
-- FIELD_PREP(ECC_MODE_MASK, ECC_MODE_4BIT) |
-+ FIELD_PREP(ECC_MODE_MASK, ecc_cfg->ecc_mode) |
- FIELD_PREP(ECC_PARITY_SIZE_BYTES_BCH_MASK, ecc_cfg->ecc_bytes_hw);
-
- ecc_cfg->ecc_buf_cfg = 0x203 << NUM_STEPS;
+++ /dev/null
-Subject: add patch for including unpartitioned space in the rootfs partition for redboot devices (if applicable)
-
-
-lede-commit: 394918851f84e4d00fa16eb900e7700e95091f00
----
- drivers/mtd/redboot.c | 19 +++++++++++++------
- 1 file changed, 13 insertions(+), 6 deletions(-)
-
---- a/drivers/mtd/parsers/redboot.c
-+++ b/drivers/mtd/parsers/redboot.c
-@@ -278,14 +278,21 @@ nogood:
- #endif
- names += strlen(names) + 1;
-
--#ifdef CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED
- if (fl->next && fl->img->flash_base + fl->img->size + master->erasesize <= fl->next->img->flash_base) {
-- i++;
-- parts[i].offset = parts[i - 1].size + parts[i - 1].offset;
-- parts[i].size = fl->next->img->flash_base - parts[i].offset;
-- parts[i].name = nullname;
-- }
-+ if (!strcmp(parts[i].name, "rootfs")) {
-+ parts[i].size = fl->next->img->flash_base;
-+ parts[i].size &= ~(master->erasesize - 1);
-+ parts[i].size -= parts[i].offset;
-+#ifdef CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED
-+ nrparts--;
-+ } else {
-+ i++;
-+ parts[i].offset = parts[i-1].size + parts[i-1].offset;
-+ parts[i].size = fl->next->img->flash_base - parts[i].offset;
-+ parts[i].name = nullname;
- #endif
-+ }
-+ }
- tmp_fl = fl;
- fl = fl->next;
- kfree(tmp_fl);
+++ /dev/null
-Subject: Add myloader partition table parser
-
-
-lede-commit: d8bf22859b51faa09d22c056fe221a45d2f7a3b8
-[adjust for kernel 5.4, add myloader.c to patch]
-
---- a/drivers/mtd/parsers/Kconfig
-+++ b/drivers/mtd/parsers/Kconfig
-@@ -67,6 +67,22 @@ config MTD_CMDLINE_PARTS
-
- If unsure, say 'N'.
-
-+config MTD_MYLOADER_PARTS
-+ tristate "MyLoader partition parsing"
-+ depends on ADM5120 || ATH79
-+ help
-+ MyLoader is a bootloader which allows the user to define partitions
-+ in flash devices, by putting a table in the second erase block
-+ on the device, similar to a partition table. This table gives the
-+ offsets and lengths of the user defined partitions.
-+
-+ If you need code which can detect and parse these tables, and
-+ register MTD 'partitions' corresponding to each image detected,
-+ enable this option.
-+
-+ You will still need the parsing functions to be called by the driver
-+ for your particular device. It won't happen automatically.
-+
- config MTD_OF_PARTS
- tristate "OpenFirmware (device tree) partitioning parser"
- default y
---- a/drivers/mtd/parsers/Makefile
-+++ b/drivers/mtd/parsers/Makefile
-@@ -4,6 +4,7 @@ obj-$(CONFIG_MTD_BCM47XX_PARTS) += bcm4
- obj-$(CONFIG_MTD_BCM63XX_PARTS) += bcm63xxpart.o
- obj-$(CONFIG_MTD_BRCM_U_BOOT) += brcm_u-boot.o
- obj-$(CONFIG_MTD_CMDLINE_PARTS) += cmdlinepart.o
-+obj-$(CONFIG_MTD_MYLOADER_PARTS) += myloader.o
- obj-$(CONFIG_MTD_OF_PARTS) += ofpart.o
- ofpart-y += ofpart_core.o
- ofpart-$(CONFIG_MTD_OF_PARTS_BCM4908) += ofpart_bcm4908.o
---- /dev/null
-+++ b/drivers/mtd/parsers/myloader.c
-@@ -0,0 +1,181 @@
-+/*
-+ * Parse MyLoader-style flash partition tables and produce a Linux partition
-+ * array to match.
-+ *
-+ *
-+ * This file was based on drivers/mtd/redboot.c
-+ *
-+ * This program is free software; you can redistribute it and/or modify it
-+ * under the terms of the GNU General Public License version 2 as published
-+ * by the Free Software Foundation.
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/version.h>
-+#include <linux/slab.h>
-+#include <linux/init.h>
-+#include <linux/vmalloc.h>
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/partitions.h>
-+#include <linux/byteorder/generic.h>
-+#include <linux/myloader.h>
-+
-+#define BLOCK_LEN_MIN 0x10000
-+#define PART_NAME_LEN 32
-+
-+struct part_data {
-+ struct mylo_partition_table tab;
-+ char names[MYLO_MAX_PARTITIONS][PART_NAME_LEN];
-+};
-+
-+static int myloader_parse_partitions(struct mtd_info *master,
-+ const struct mtd_partition **pparts,
-+ struct mtd_part_parser_data *data)
-+{
-+ struct part_data *buf;
-+ struct mylo_partition_table *tab;
-+ struct mylo_partition *part;
-+ struct mtd_partition *mtd_parts;
-+ struct mtd_partition *mtd_part;
-+ int num_parts;
-+ int ret, i;
-+ size_t retlen;
-+ char *names;
-+ unsigned long offset;
-+ unsigned long blocklen;
-+
-+ buf = vmalloc(sizeof(*buf));
-+ if (!buf) {
-+ return -ENOMEM;
-+ goto out;
-+ }
-+ tab = &buf->tab;
-+
-+ blocklen = master->erasesize;
-+ if (blocklen < BLOCK_LEN_MIN)
-+ blocklen = BLOCK_LEN_MIN;
-+
-+ offset = blocklen;
-+
-+ /* Find the partition table */
-+ for (i = 0; i < 4; i++, offset += blocklen) {
-+ printk(KERN_DEBUG "%s: searching for MyLoader partition table"
-+ " at offset 0x%lx\n", master->name, offset);
-+
-+ ret = mtd_read(master, offset, sizeof(*buf), &retlen,
-+ (void *)buf);
-+ if (ret)
-+ goto out_free_buf;
-+
-+ if (retlen != sizeof(*buf)) {
-+ ret = -EIO;
-+ goto out_free_buf;
-+ }
-+
-+ /* Check for Partition Table magic number */
-+ if (tab->magic == le32_to_cpu(MYLO_MAGIC_PARTITIONS))
-+ break;
-+
-+ }
-+
-+ if (tab->magic != le32_to_cpu(MYLO_MAGIC_PARTITIONS)) {
-+ printk(KERN_DEBUG "%s: no MyLoader partition table found\n",
-+ master->name);
-+ ret = 0;
-+ goto out_free_buf;
-+ }
-+
-+ /* The MyLoader and the Partition Table is always present */
-+ num_parts = 2;
-+
-+ /* Detect number of used partitions */
-+ for (i = 0; i < MYLO_MAX_PARTITIONS; i++) {
-+ part = &tab->partitions[i];
-+
-+ if (le16_to_cpu(part->type) == PARTITION_TYPE_FREE)
-+ continue;
-+
-+ num_parts++;
-+ }
-+
-+ mtd_parts = kzalloc((num_parts * sizeof(*mtd_part) +
-+ num_parts * PART_NAME_LEN), GFP_KERNEL);
-+
-+ if (!mtd_parts) {
-+ ret = -ENOMEM;
-+ goto out_free_buf;
-+ }
-+
-+ mtd_part = mtd_parts;
-+ names = (char *)&mtd_parts[num_parts];
-+
-+ strncpy(names, "myloader", PART_NAME_LEN);
-+ mtd_part->name = names;
-+ mtd_part->offset = 0;
-+ mtd_part->size = offset;
-+ mtd_part->mask_flags = MTD_WRITEABLE;
-+ mtd_part++;
-+ names += PART_NAME_LEN;
-+
-+ strncpy(names, "partition_table", PART_NAME_LEN);
-+ mtd_part->name = names;
-+ mtd_part->offset = offset;
-+ mtd_part->size = blocklen;
-+ mtd_part->mask_flags = MTD_WRITEABLE;
-+ mtd_part++;
-+ names += PART_NAME_LEN;
-+
-+ for (i = 0; i < MYLO_MAX_PARTITIONS; i++) {
-+ part = &tab->partitions[i];
-+
-+ if (le16_to_cpu(part->type) == PARTITION_TYPE_FREE)
-+ continue;
-+
-+ if ((buf->names[i][0]) && (buf->names[i][0] != '\xff'))
-+ strncpy(names, buf->names[i], PART_NAME_LEN);
-+ else
-+ snprintf(names, PART_NAME_LEN, "partition%d", i);
-+
-+ mtd_part->offset = le32_to_cpu(part->addr);
-+ mtd_part->size = le32_to_cpu(part->size);
-+ mtd_part->name = names;
-+ mtd_part++;
-+ names += PART_NAME_LEN;
-+ }
-+
-+ *pparts = mtd_parts;
-+ ret = num_parts;
-+
-+ out_free_buf:
-+ vfree(buf);
-+ out:
-+ return ret;
-+}
-+
-+static struct mtd_part_parser myloader_mtd_parser = {
-+ .owner = THIS_MODULE,
-+ .parse_fn = myloader_parse_partitions,
-+ .name = "MyLoader",
-+};
-+
-+static int __init myloader_mtd_parser_init(void)
-+{
-+ register_mtd_parser(&myloader_mtd_parser);
-+
-+ return 0;
-+}
-+
-+static void __exit myloader_mtd_parser_exit(void)
-+{
-+ deregister_mtd_parser(&myloader_mtd_parser);
-+}
-+
-+module_init(myloader_mtd_parser_init);
-+module_exit(myloader_mtd_parser_exit);
-+
-+MODULE_DESCRIPTION("Parsing code for MyLoader partition tables");
-+MODULE_LICENSE("GPL v2");
+++ /dev/null
-Subject: [PATCH] mtd: bcm47xxpart: check for bad blocks when calculating offsets
-
----
-
---- a/drivers/mtd/parsers/parser_trx.c
-+++ b/drivers/mtd/parsers/parser_trx.c
-@@ -25,6 +25,33 @@ struct trx_header {
- uint32_t offset[3];
- } __packed;
-
-+/*
-+ * Calculate real end offset (address) for a given amount of data. It checks
-+ * all blocks skipping bad ones.
-+ */
-+static size_t parser_trx_real_offset(struct mtd_info *mtd, size_t bytes)
-+{
-+ size_t real_offset = 0;
-+
-+ if (mtd_block_isbad(mtd, real_offset))
-+ pr_warn("Base offset shouldn't be at bad block");
-+
-+ while (bytes >= mtd->erasesize) {
-+ bytes -= mtd->erasesize;
-+ real_offset += mtd->erasesize;
-+ while (mtd_block_isbad(mtd, real_offset)) {
-+ real_offset += mtd->erasesize;
-+
-+ if (real_offset >= mtd->size)
-+ return real_offset - mtd->erasesize;
-+ }
-+ }
-+
-+ real_offset += bytes;
-+
-+ return real_offset;
-+}
-+
- static const char *parser_trx_data_part_name(struct mtd_info *master,
- size_t offset)
- {
-@@ -86,21 +113,21 @@ static int parser_trx_parse(struct mtd_i
- if (trx.offset[2]) {
- part = &parts[curr_part++];
- part->name = "loader";
-- part->offset = trx.offset[i];
-+ part->offset = parser_trx_real_offset(mtd, trx.offset[i]);
- i++;
- }
-
- if (trx.offset[i]) {
- part = &parts[curr_part++];
- part->name = "linux";
-- part->offset = trx.offset[i];
-+ part->offset = parser_trx_real_offset(mtd, trx.offset[i]);
- i++;
- }
-
- if (trx.offset[i]) {
- part = &parts[curr_part++];
-- part->name = parser_trx_data_part_name(mtd, trx.offset[i]);
-- part->offset = trx.offset[i];
-+ part->offset = parser_trx_real_offset(mtd, trx.offset[i]);
-+ part->name = parser_trx_data_part_name(mtd, part->offset);
- i++;
- }
-
+++ /dev/null
-Subject: mtd: bcm47xxpart: detect T_Meter partition
-
-It can be found on many Netgear devices. It consists of many 0x30 blocks
-starting with 4D 54.
-
----
- drivers/mtd/bcm47xxpart.c | 10 ++++++++++
- 1 file changed, 10 insertions(+)
-
---- a/drivers/mtd/parsers/bcm47xxpart.c
-+++ b/drivers/mtd/parsers/bcm47xxpart.c
-@@ -35,6 +35,7 @@
- #define NVRAM_HEADER 0x48534C46 /* FLSH */
- #define POT_MAGIC1 0x54544f50 /* POTT */
- #define POT_MAGIC2 0x504f /* OP */
-+#define T_METER_MAGIC 0x4D540000 /* MT */
- #define ML_MAGIC1 0x39685a42
- #define ML_MAGIC2 0x26594131
- #define TRX_MAGIC 0x30524448
-@@ -178,6 +179,15 @@ static int bcm47xxpart_parse(struct mtd_
- MTD_WRITEABLE);
- continue;
- }
-+
-+ /* T_Meter */
-+ if ((le32_to_cpu(buf[0x000 / 4]) & 0xFFFF0000) == T_METER_MAGIC &&
-+ (le32_to_cpu(buf[0x030 / 4]) & 0xFFFF0000) == T_METER_MAGIC &&
-+ (le32_to_cpu(buf[0x060 / 4]) & 0xFFFF0000) == T_METER_MAGIC) {
-+ bcm47xxpart_add_part(&parts[curr_part++], "T_Meter", offset,
-+ MTD_WRITEABLE);
-+ continue;
-+ }
-
- /* TRX */
- if (buf[0x000 / 4] == TRX_MAGIC) {
+++ /dev/null
-From 4437e01fb6bca63fccdba5d6c44888b0935885c2 Mon Sep 17 00:00:00 2001
-Date: Tue, 24 Mar 2020 11:45:07 +0100
-Subject: [PATCH] generic: routerboot partition build bits (5.4)
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-This patch adds routerbootpart kernel build bits
-
----
- drivers/mtd/parsers/Kconfig | 9 +++++++++
- drivers/mtd/parsers/Makefile | 1 +
- 2 files changed, 10 insertions(+)
-
---- a/drivers/mtd/parsers/Kconfig
-+++ b/drivers/mtd/parsers/Kconfig
-@@ -236,3 +236,12 @@ config MTD_SERCOMM_PARTS
- partition map. This partition table contains real partition
- offsets, which may differ from device to device depending on the
- number and location of bad blocks on NAND.
-+
-+config MTD_ROUTERBOOT_PARTS
-+ tristate "RouterBoot flash partition parser"
-+ depends on MTD && OF
-+ help
-+ MikroTik RouterBoot is implemented as a multi segment system on the
-+ flash, some of which are fixed and some of which are located at
-+ variable offsets. This parser handles both cases via properly
-+ formatted DTS.
---- a/drivers/mtd/parsers/Makefile
-+++ b/drivers/mtd/parsers/Makefile
-@@ -17,3 +17,4 @@ obj-$(CONFIG_MTD_SERCOMM_PARTS) += scpa
- obj-$(CONFIG_MTD_SHARPSL_PARTS) += sharpslpart.o
- obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o
- obj-$(CONFIG_MTD_QCOMSMEM_PARTS) += qcomsmempart.o
-+obj-$(CONFIG_MTD_ROUTERBOOT_PARTS) += routerbootpart.o
+++ /dev/null
-From 3245921a87154bdfbe7a55d743ea62dd559a8fb0 Mon Sep 17 00:00:00 2001
-Date: Thu, 30 May 2024 03:13:09 +0100
-Subject: [PATCH 1/9] dt-bindings: block: add basic bindings for block devices
-
-Add bindings for block devices which are used to allow referencing
-nvmem bits on them.
-
----
- .../bindings/block/block-device.yaml | 22 ++++++++
- .../devicetree/bindings/block/partition.yaml | 51 +++++++++++++++++++
- .../devicetree/bindings/block/partitions.yaml | 20 ++++++++
- 3 files changed, 93 insertions(+)
- create mode 100644 Documentation/devicetree/bindings/block/block-device.yaml
- create mode 100644 Documentation/devicetree/bindings/block/partition.yaml
- create mode 100644 Documentation/devicetree/bindings/block/partitions.yaml
-
---- /dev/null
-+++ b/Documentation/devicetree/bindings/block/block-device.yaml
-@@ -0,0 +1,22 @@
-+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
-+%YAML 1.2
-+---
-+$id: http://devicetree.org/schemas/block/block-device.yaml#
-+$schema: http://devicetree.org/meta-schemas/core.yaml#
-+
-+title: block storage device
-+
-+description: |
-+ This binding is generic and describes a block-oriented storage device.
-+
-+maintainers:
-+
-+properties:
-+ partitions:
-+ $ref: /schemas/block/partitions.yaml
-+
-+ nvmem-layout:
-+ $ref: /schemas/nvmem/layouts/nvmem-layout.yaml#
-+
-+unevaluatedProperties: false
---- /dev/null
-+++ b/Documentation/devicetree/bindings/block/partition.yaml
-@@ -0,0 +1,51 @@
-+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
-+%YAML 1.2
-+---
-+$id: http://devicetree.org/schemas/block/partition.yaml#
-+$schema: http://devicetree.org/meta-schemas/core.yaml#
-+
-+title: Partition on a block device
-+
-+description: |
-+ This binding describes a partition on a block device.
-+ Partitions may be matched by a combination of partition number, name,
-+ and UUID.
-+
-+maintainers:
-+
-+properties:
-+ $nodename:
-+ pattern: '^block-partition-.+$'
-+
-+ partnum:
-+ $ref: /schemas/types.yaml#/definitions/uint32
-+ description:
-+ Matches partition by number if present.
-+
-+ partname:
-+ $ref: /schemas/types.yaml#/definitions/string
-+ description:
-+ Matches partition by PARTNAME if present.
-+
-+ partuuid:
-+ $ref: /schemas/types.yaml#/definitions/string
-+ description:
-+ Matches partition by PARTUUID if present.
-+
-+ nvmem-layout:
-+ $ref: /schemas/nvmem/layouts/nvmem-layout.yaml#
-+ description:
-+ This container may reference an NVMEM layout parser.
-+
-+anyOf:
-+ - required:
-+ - partnum
-+
-+ - required:
-+ - partname
-+
-+ - required:
-+ - partuuid
-+
-+unevaluatedProperties: false
---- /dev/null
-+++ b/Documentation/devicetree/bindings/block/partitions.yaml
-@@ -0,0 +1,20 @@
-+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
-+%YAML 1.2
-+---
-+$id: http://devicetree.org/schemas/block/partitions.yaml#
-+$schema: http://devicetree.org/meta-schemas/core.yaml#
-+
-+title: Partitions on block devices
-+
-+description: |
-+ This binding is generic and describes the content of the partitions container
-+ node.
-+
-+maintainers:
-+
-+patternProperties:
-+ "^block-partition-.+$":
-+ $ref: partition.yaml
-+
-+unevaluatedProperties: false
+++ /dev/null
-From patchwork Tue Jul 30 19:25:59 2024
-Content-Type: text/plain; charset="utf-8"
-MIME-Version: 1.0
-Content-Transfer-Encoding: 7bit
-X-Patchwork-Id: 13747816
-Date: Tue, 30 Jul 2024 20:25:59 +0100
-Subject: [PATCH v5 2/4] block: partitions: populate fwnode
-Message-ID:
- <3051ac090ad3b3e2f5adb6b67c923261ead729a5.1722365899.git.daniel@makrotopia.org>
-Precedence: bulk
-List-Id: <linux-block.vger.kernel.org>
-MIME-Version: 1.0
-Content-Disposition: inline
-
-Assign matching firmware nodes to block partitions in order to allow
-them to be referenced e.g. as NVMEM providers.
-
----
- block/partitions/core.c | 72 +++++++++++++++++++++++++++++++++++++++++
- 1 file changed, 72 insertions(+)
-
---- a/block/partitions/core.c
-+++ b/block/partitions/core.c
-@@ -10,6 +10,8 @@
- #include <linux/ctype.h>
- #include <linux/vmalloc.h>
- #include <linux/raid/detect.h>
-+#include <linux/property.h>
-+
- #include "check.h"
-
- static int (*const check_part[])(struct parsed_partitions *) = {
-@@ -295,6 +297,74 @@ static ssize_t whole_disk_show(struct de
- }
- static const DEVICE_ATTR(whole_disk, 0444, whole_disk_show, NULL);
-
-+static bool part_meta_match(const char *attr, const char *member, size_t length)
-+{
-+ /* check if length of attr exceeds specified maximum length */
-+ if (strnlen(attr, length) == length)
-+ return false;
-+
-+ /* return true if strings match */
-+ return !strncmp(attr, member, length);
-+}
-+
-+static struct fwnode_handle *find_partition_fwnode(struct block_device *bdev)
-+{
-+ struct fwnode_handle *fw_parts, *fw_part;
-+ struct device *ddev = disk_to_dev(bdev->bd_disk);
-+ const char *partname, *uuid;
-+ u32 partno;
-+ bool got_uuid, got_partname, got_partno;
-+
-+ fw_parts = device_get_named_child_node(ddev, "partitions");
-+ if (!fw_parts)
-+ return NULL;
-+
-+ fwnode_for_each_child_node(fw_parts, fw_part) {
-+ got_uuid = false;
-+ got_partname = false;
-+ got_partno = false;
-+ /*
-+ * In case 'uuid' is defined in the partitions firmware node
-+ * require partition meta info being present and the specified
-+ * uuid to match.
-+ */
-+ got_uuid = !fwnode_property_read_string(fw_part, "uuid", &uuid);
-+ if (got_uuid && (!bdev->bd_meta_info ||
-+ !part_meta_match(uuid, bdev->bd_meta_info->uuid,
-+ PARTITION_META_INFO_UUIDLTH)))
-+ continue;
-+
-+ /*
-+ * In case 'partname' is defined in the partitions firmware node
-+ * require partition meta info being present and the specified
-+ * volname to match.
-+ */
-+ got_partname = !fwnode_property_read_string(fw_part, "partname",
-+ &partname);
-+ if (got_partname && (!bdev->bd_meta_info ||
-+ !part_meta_match(partname,
-+ bdev->bd_meta_info->volname,
-+ PARTITION_META_INFO_VOLNAMELTH)))
-+ continue;
-+
-+ /*
-+ * In case 'partno' is defined in the partitions firmware node
-+ * the specified partno needs to match.
-+ */
-+ got_partno = !fwnode_property_read_u32(fw_part, "partno", &partno);
-+ if (got_partno && bdev->bd_partno != partno)
-+ continue;
-+
-+ /* Skip if no matching criteria is present in firmware node */
-+ if (!got_uuid && !got_partname && !got_partno)
-+ continue;
-+
-+ return fw_part;
-+ }
-+
-+ return NULL;
-+}
-+
- /*
- * Must be called either with open_mutex held, before a disk can be opened or
- * after all disk users are gone.
-@@ -377,6 +447,8 @@ static struct block_device *add_partitio
- goto out_put;
- }
-
-+ device_set_node(pdev, find_partition_fwnode(bdev));
-+
- /* delay uevent until 'holders' subdir is created */
- dev_set_uevent_suppress(pdev, 1);
- err = device_add(pdev);
+++ /dev/null
-From patchwork Tue Jul 30 19:26:42 2024
-Content-Type: text/plain; charset="utf-8"
-MIME-Version: 1.0
-Content-Transfer-Encoding: 7bit
-X-Patchwork-Id: 13747817
-Date: Tue, 30 Jul 2024 20:26:42 +0100
-Subject: [PATCH v5 3/4] block: add support for notifications
-Message-ID:
- <ca0022886e8f211a323a716653a1396a3bc91653.1722365899.git.daniel@makrotopia.org>
-Precedence: bulk
-List-Id: <linux-block.vger.kernel.org>
-MIME-Version: 1.0
-Content-Disposition: inline
-
-Add notifier block to notify other subsystems about the addition or
-removal of block devices.
-
----
- block/Kconfig | 6 +++
- block/Makefile | 1 +
- block/blk-notify.c | 87 ++++++++++++++++++++++++++++++++++++++++++
- include/linux/blkdev.h | 11 ++++++
- 4 files changed, 105 insertions(+)
- create mode 100644 block/blk-notify.c
-
---- a/block/Kconfig
-+++ b/block/Kconfig
-@@ -208,6 +208,12 @@ config BLK_INLINE_ENCRYPTION_FALLBACK
- by falling back to the kernel crypto API when inline
- encryption hardware is not present.
-
-+config BLOCK_NOTIFIERS
-+ bool "Enable support for notifications in block layer"
-+ help
-+ Enable this option to provide notifiers for other subsystems
-+ upon addition or removal of block devices.
-+
- source "block/partitions/Kconfig"
-
- config BLK_MQ_PCI
---- a/block/Makefile
-+++ b/block/Makefile
-@@ -40,3 +40,4 @@ obj-$(CONFIG_BLK_INLINE_ENCRYPTION) += b
- blk-crypto-sysfs.o
- obj-$(CONFIG_BLK_INLINE_ENCRYPTION_FALLBACK) += blk-crypto-fallback.o
- obj-$(CONFIG_BLOCK_HOLDER_DEPRECATED) += holder.o
-+obj-$(CONFIG_BLOCK_NOTIFIERS) += blk-notify.o
---- /dev/null
-+++ b/block/blk-notify.c
-@@ -0,0 +1,87 @@
-+// SPDX-License-Identifier: GPL-2.0-or-later
-+/*
-+ * Notifiers for addition and removal of block devices
-+ *
-+ */
-+
-+#include <linux/list.h>
-+#include <linux/mutex.h>
-+#include <linux/notifier.h>
-+
-+#include "blk.h"
-+
-+struct blk_device_list {
-+ struct device *dev;
-+ struct list_head list;
-+};
-+
-+static RAW_NOTIFIER_HEAD(blk_notifier_list);
-+static DEFINE_MUTEX(blk_notifier_lock);
-+static LIST_HEAD(blk_devices);
-+
-+void blk_register_notify(struct notifier_block *nb)
-+{
-+ struct blk_device_list *existing_blkdev;
-+
-+ mutex_lock(&blk_notifier_lock);
-+ raw_notifier_chain_register(&blk_notifier_list, nb);
-+
-+ list_for_each_entry(existing_blkdev, &blk_devices, list)
-+ nb->notifier_call(nb, BLK_DEVICE_ADD, existing_blkdev->dev);
-+
-+ mutex_unlock(&blk_notifier_lock);
-+}
-+EXPORT_SYMBOL_GPL(blk_register_notify);
-+
-+void blk_unregister_notify(struct notifier_block *nb)
-+{
-+ mutex_lock(&blk_notifier_lock);
-+ raw_notifier_chain_unregister(&blk_notifier_list, nb);
-+ mutex_unlock(&blk_notifier_lock);
-+}
-+EXPORT_SYMBOL_GPL(blk_unregister_notify);
-+
-+static int blk_call_notifier_add(struct device *dev)
-+{
-+ struct blk_device_list *new_blkdev;
-+
-+ new_blkdev = kmalloc(sizeof(*new_blkdev), GFP_KERNEL);
-+ if (!new_blkdev)
-+ return -ENOMEM;
-+
-+ new_blkdev->dev = dev;
-+ mutex_lock(&blk_notifier_lock);
-+ list_add_tail(&new_blkdev->list, &blk_devices);
-+ raw_notifier_call_chain(&blk_notifier_list, BLK_DEVICE_ADD, dev);
-+ mutex_unlock(&blk_notifier_lock);
-+ return 0;
-+}
-+
-+static void blk_call_notifier_remove(struct device *dev)
-+{
-+ struct blk_device_list *old_blkdev, *tmp;
-+
-+ mutex_lock(&blk_notifier_lock);
-+ list_for_each_entry_safe(old_blkdev, tmp, &blk_devices, list) {
-+ if (old_blkdev->dev != dev)
-+ continue;
-+
-+ list_del(&old_blkdev->list);
-+ kfree(old_blkdev);
-+ }
-+ raw_notifier_call_chain(&blk_notifier_list, BLK_DEVICE_REMOVE, dev);
-+ mutex_unlock(&blk_notifier_lock);
-+}
-+
-+static struct class_interface blk_notifications_bus_interface __refdata = {
-+ .class = &block_class,
-+ .add_dev = &blk_call_notifier_add,
-+ .remove_dev = &blk_call_notifier_remove,
-+};
-+
-+static int __init blk_notifications_init(void)
-+{
-+ return class_interface_register(&blk_notifications_bus_interface);
-+}
-+device_initcall(blk_notifications_init);
---- a/include/linux/blkdev.h
-+++ b/include/linux/blkdev.h
-@@ -1567,4 +1567,15 @@ struct io_comp_batch {
-
- #define DEFINE_IO_COMP_BATCH(name) struct io_comp_batch name = { }
-
-+
-+#define BLK_DEVICE_ADD 1
-+#define BLK_DEVICE_REMOVE 2
-+#if defined(CONFIG_BLOCK_NOTIFIERS)
-+void blk_register_notify(struct notifier_block *nb);
-+void blk_unregister_notify(struct notifier_block *nb);
-+#else
-+static inline void blk_register_notify(struct notifier_block *nb) { };
-+static inline void blk_unregister_notify(struct notifier_block *nb) { };
-+#endif
-+
- #endif /* _LINUX_BLKDEV_H */
+++ /dev/null
-From patchwork Tue Jul 30 19:27:07 2024
-Content-Type: text/plain; charset="utf-8"
-MIME-Version: 1.0
-Content-Transfer-Encoding: 7bit
-X-Patchwork-Id: 13747818
-Date: Tue, 30 Jul 2024 20:27:07 +0100
-Subject: [PATCH v5 4/4] block: add new genhd flag GENHD_FL_NVMEM
-Message-ID:
- <311ea569c23ce14e2896cd3b069dc494c58c49c2.1722365899.git.daniel@makrotopia.org>
-Precedence: bulk
-List-Id: <linux-block.vger.kernel.org>
-MIME-Version: 1.0
-Content-Disposition: inline
-
-Add new flag to destinguish block devices which may act as an NVMEM
-provider.
-
----
- include/linux/blkdev.h | 2 ++
- 1 file changed, 2 insertions(+)
-
---- a/include/linux/blkdev.h
-+++ b/include/linux/blkdev.h
-@@ -80,11 +80,13 @@ struct partition_meta_info {
- * ``GENHD_FL_NO_PART``: partition support is disabled. The kernel will not
- * scan for partitions from add_disk, and users can't add partitions manually.
- *
-+ * ``GENHD_FL_NVMEM``: the block device should be considered as NVMEM provider.
- */
- enum {
- GENHD_FL_REMOVABLE = 1 << 0,
- GENHD_FL_HIDDEN = 1 << 1,
- GENHD_FL_NO_PART = 1 << 2,
-+ GENHD_FL_NVMEM = 1 << 3,
- };
-
- enum {
+++ /dev/null
-From 9703951cdfe868b130e64d6122420396c2807be8 Mon Sep 17 00:00:00 2001
-Date: Thu, 30 May 2024 03:15:02 +0100
-Subject: [PATCH 5/9] nvmem: implement block NVMEM provider
-
-On embedded devices using an eMMC it is common that one or more partitions
-on the eMMC are used to store MAC addresses and Wi-Fi calibration EEPROM
-data. Allow referencing any block device or partition in Device Tree to
-allow e.g. Ethernet and Wi-Fi drivers accessing them via the NVMEM layer.
-
----
- drivers/nvmem/Kconfig | 11 +++
- drivers/nvmem/Makefile | 2 +
- drivers/nvmem/block.c | 197 +++++++++++++++++++++++++++++++++++++++++
- 3 files changed, 210 insertions(+)
- create mode 100644 drivers/nvmem/block.c
-
---- a/drivers/nvmem/Kconfig
-+++ b/drivers/nvmem/Kconfig
-@@ -40,6 +40,17 @@ config NVMEM_APPLE_EFUSES
- This driver can also be built as a module. If so, the module will
- be called nvmem-apple-efuses.
-
-+config NVMEM_BLOCK
-+ tristate "Block device NVMEM provider"
-+ depends on BLOCK
-+ depends on OF
-+ depends on NVMEM
-+ select BLOCK_NOTIFIERS
-+ help
-+ Allow block devices (or partitions) to act as NVMEM prodivers,
-+ typically used with eMMC to store MAC addresses or Wi-Fi
-+ calibration data on embedded devices.
-+
- config NVMEM_BCM_OCOTP
- tristate "Broadcom On-Chip OTP Controller support"
- depends on ARCH_BCM_IPROC || COMPILE_TEST
---- a/drivers/nvmem/Makefile
-+++ b/drivers/nvmem/Makefile
-@@ -14,6 +14,8 @@ obj-$(CONFIG_NVMEM_APPLE_EFUSES) += nvme
- nvmem-apple-efuses-y := apple-efuses.o
- obj-$(CONFIG_NVMEM_BCM_OCOTP) += nvmem-bcm-ocotp.o
- nvmem-bcm-ocotp-y := bcm-ocotp.o
-+obj-$(CONFIG_NVMEM_BLOCK) += nvmem-block.o
-+nvmem-block-y := block.o
- obj-$(CONFIG_NVMEM_BRCM_NVRAM) += nvmem_brcm_nvram.o
- nvmem_brcm_nvram-y := brcm_nvram.o
- obj-$(CONFIG_NVMEM_IMX_IIM) += nvmem-imx-iim.o
---- /dev/null
-+++ b/drivers/nvmem/block.c
-@@ -0,0 +1,208 @@
-+// SPDX-License-Identifier: GPL-2.0-or-later
-+/*
-+ * block device NVMEM provider
-+ *
-+ *
-+ * Useful on devices using a partition on an eMMC for MAC addresses or
-+ * Wi-Fi calibration EEPROM data.
-+ */
-+
-+#include <linux/blkdev.h>
-+#include <linux/nvmem-provider.h>
-+#include <linux/of.h>
-+#include <linux/pagemap.h>
-+#include <linux/property.h>
-+
-+/* List of all NVMEM devices */
-+static LIST_HEAD(nvmem_devices);
-+static DEFINE_MUTEX(devices_mutex);
-+
-+struct blk_nvmem {
-+ struct nvmem_device *nvmem;
-+ struct block_device *bdev;
-+ struct list_head list;
-+};
-+
-+static int blk_nvmem_reg_read(void *priv, unsigned int from,
-+ void *val, size_t bytes)
-+{
-+ unsigned long offs = from & ~PAGE_MASK, to_read;
-+ pgoff_t f_index = from >> PAGE_SHIFT;
-+ struct address_space *mapping;
-+ struct blk_nvmem *bnv = priv;
-+ size_t bytes_left = bytes;
-+ struct folio *folio;
-+ void *p;
-+ int ret;
-+
-+ if (!bnv->bdev)
-+ return -ENODEV;
-+
-+ if (!bnv->bdev->bd_disk)
-+ return -EINVAL;
-+
-+ if (!bnv->bdev->bd_disk->fops)
-+ return -EIO;
-+
-+ if (!bnv->bdev->bd_disk->fops->open)
-+ return -EIO;
-+
-+ ret = bnv->bdev->bd_disk->fops->open(bnv->bdev->bd_disk, BLK_OPEN_READ);
-+ if (ret)
-+ return ret;
-+
-+ mapping = bnv->bdev->bd_inode->i_mapping;
-+
-+ while (bytes_left) {
-+ folio = read_mapping_folio(mapping, f_index++, NULL);
-+ if (IS_ERR(folio)) {
-+ ret = PTR_ERR(folio);
-+ goto err_release_bdev;
-+ }
-+ to_read = min_t(unsigned long, bytes_left, PAGE_SIZE - offs);
-+ p = folio_address(folio) + offset_in_folio(folio, offs);
-+ memcpy(val, p, to_read);
-+ offs = 0;
-+ bytes_left -= to_read;
-+ val += to_read;
-+ folio_put(folio);
-+ }
-+
-+err_release_bdev:
-+ bnv->bdev->bd_disk->fops->release(bnv->bdev->bd_disk);
-+
-+ return ret;
-+}
-+
-+static int blk_nvmem_register(struct device *dev)
-+{
-+ struct device_node *np = dev_of_node(dev);
-+ struct block_device *bdev = dev_to_bdev(dev);
-+ struct nvmem_config config = {};
-+ struct blk_nvmem *bnv;
-+
-+ /* skip devices which do not have a device tree node */
-+ if (!np)
-+ return 0;
-+
-+ /* skip devices without an nvmem layout defined */
-+ if (!of_get_child_by_name(np, "nvmem-layout"))
-+ return 0;
-+
-+ /*
-+ * skip devices which don't have GENHD_FL_NVMEM set
-+ *
-+ * This flag is used for mtdblock and ubiblock devices because
-+ * both, MTD and UBI already implement their own NVMEM provider.
-+ * To avoid registering multiple NVMEM providers for the same
-+ * device node, don't register the block NVMEM provider for them.
-+ */
-+ if (!(bdev->bd_disk->flags & GENHD_FL_NVMEM))
-+ return 0;
-+
-+ /*
-+ * skip block device too large to be represented as NVMEM devices
-+ * which are using an 'int' as address
-+ */
-+ if (bdev_nr_bytes(bdev) > INT_MAX)
-+ return -EFBIG;
-+
-+ bnv = kzalloc(sizeof(struct blk_nvmem), GFP_KERNEL);
-+ if (!bnv)
-+ return -ENOMEM;
-+
-+ config.id = NVMEM_DEVID_NONE;
-+ config.dev = &bdev->bd_device;
-+ config.name = dev_name(&bdev->bd_device);
-+ config.owner = THIS_MODULE;
-+ config.priv = bnv;
-+ config.reg_read = blk_nvmem_reg_read;
-+ config.size = bdev_nr_bytes(bdev);
-+ config.word_size = 1;
-+ config.stride = 1;
-+ config.read_only = true;
-+ config.root_only = true;
-+ config.ignore_wp = true;
-+ config.of_node = to_of_node(dev->fwnode);
-+
-+ bnv->bdev = bdev;
-+ bnv->nvmem = nvmem_register(&config);
-+ if (IS_ERR(bnv->nvmem)) {
-+ dev_err_probe(&bdev->bd_device, PTR_ERR(bnv->nvmem),
-+ "Failed to register NVMEM device\n");
-+
-+ kfree(bnv);
-+ return PTR_ERR(bnv->nvmem);
-+ }
-+
-+ mutex_lock(&devices_mutex);
-+ list_add_tail(&bnv->list, &nvmem_devices);
-+ mutex_unlock(&devices_mutex);
-+
-+ return 0;
-+}
-+
-+static void blk_nvmem_unregister(struct device *dev)
-+{
-+ struct block_device *bdev = dev_to_bdev(dev);
-+ struct blk_nvmem *bnv_c, *bnv = NULL;
-+
-+ mutex_lock(&devices_mutex);
-+ list_for_each_entry(bnv_c, &nvmem_devices, list) {
-+ if (bnv_c->bdev == bdev) {
-+ bnv = bnv_c;
-+ break;
-+ }
-+ }
-+
-+ if (!bnv) {
-+ mutex_unlock(&devices_mutex);
-+ return;
-+ }
-+
-+ list_del(&bnv->list);
-+ mutex_unlock(&devices_mutex);
-+ nvmem_unregister(bnv->nvmem);
-+ kfree(bnv);
-+}
-+
-+static int blk_nvmem_handler(struct notifier_block *this, unsigned long code, void *obj)
-+{
-+ struct device *dev = (struct device *)obj;
-+
-+ switch (code) {
-+ case BLK_DEVICE_ADD:
-+ return blk_nvmem_register(dev);
-+ case BLK_DEVICE_REMOVE:
-+ blk_nvmem_unregister(dev);
-+ break;
-+ default:
-+ return -EINVAL;
-+ }
-+
-+ return 0;
-+}
-+
-+static struct notifier_block blk_nvmem_notifier = {
-+ .notifier_call = blk_nvmem_handler,
-+};
-+
-+static int __init blk_nvmem_init(void)
-+{
-+ blk_register_notify(&blk_nvmem_notifier);
-+
-+ return 0;
-+}
-+
-+static void __exit blk_nvmem_exit(void)
-+{
-+ blk_unregister_notify(&blk_nvmem_notifier);
-+}
-+
-+module_init(blk_nvmem_init);
-+module_exit(blk_nvmem_exit);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_DESCRIPTION("block device NVMEM provider");
+++ /dev/null
-From f7ec19b34d1b7e934a58ceb102369bbd30b2631d Mon Sep 17 00:00:00 2001
-Date: Thu, 30 May 2024 03:15:11 +0100
-Subject: [PATCH 6/9] dt-bindings: mmc: mmc-card: add block device nodes
-
-Add nodes representing the block devices exposed by an MMC device
-including an example involving nvmem-cells.
-
----
- .../devicetree/bindings/mmc/mmc-card.yaml | 45 +++++++++++++++++++
- 1 file changed, 45 insertions(+)
-
---- a/Documentation/devicetree/bindings/mmc/mmc-card.yaml
-+++ b/Documentation/devicetree/bindings/mmc/mmc-card.yaml
-@@ -26,6 +26,18 @@ properties:
- Use this to indicate that the mmc-card has a broken hpi
- implementation, and that hpi should not be used.
-
-+ block:
-+ $ref: /schemas/block/block-device.yaml#
-+ description:
-+ Represents the block storage provided by an SD card or the
-+ main hardware partition of an eMMC.
-+
-+patternProperties:
-+ '^boot[0-9]+':
-+ $ref: /schemas/block/block-device.yaml#
-+ description:
-+ Represents a boot hardware partition on an eMMC.
-+
- required:
- - compatible
- - reg
-@@ -42,6 +54,39 @@ examples:
- compatible = "mmc-card";
- reg = <0>;
- broken-hpi;
-+
-+ block {
-+ partitions {
-+ cal_data: block-partition-rf {
-+ partnum = <3>;
-+ partname = "rf";
-+
-+ nvmem-layout {
-+ compatible = "fixed-layout";
-+ #address-cells = <1>;
-+ #size-cells = <1>;
-+
-+ eeprom@0 {
-+ reg = <0x0 0x1000>;
-+ };
-+ };
-+ };
-+ };
-+ };
-+
-+ boot1 {
-+ nvmem-layout {
-+ compatible = "fixed-layout";
-+ #address-cells = <1>;
-+ #size-cells = <1>;
-+
-+ macaddr: macaddr@a {
-+ compatible = "mac-base";
-+ reg = <0xa 0x6>;
-+ #nvmem-cell-cells = <1>;
-+ };
-+ };
-+ };
- };
- };
-
+++ /dev/null
-From 043c4f88476cc0f29c9bf82a8a516f58d848e1cd Mon Sep 17 00:00:00 2001
-Date: Thu, 30 May 2024 03:15:25 +0100
-Subject: [PATCH 7/9] mmc: core: set card fwnode_handle
-
-Set fwnode in case it isn't set yet and of_node is present.
-
----
- drivers/mmc/core/bus.c | 2 ++
- 1 file changed, 2 insertions(+)
-
---- a/drivers/mmc/core/bus.c
-+++ b/drivers/mmc/core/bus.c
-@@ -366,6 +366,8 @@ int mmc_add_card(struct mmc_card *card)
-
- mmc_add_card_debugfs(card);
- card->dev.of_node = mmc_of_find_child_device(card->host, 0);
-+ if (card->dev.of_node && !card->dev.fwnode)
-+ card->dev.fwnode = &card->dev.of_node->fwnode;
-
- device_enable_async_suspend(&card->dev);
-
+++ /dev/null
-From ef3e38fec26901b71975d7e810a2df6b8bd54a8e Mon Sep 17 00:00:00 2001
-Date: Thu, 30 May 2024 03:15:36 +0100
-Subject: [PATCH 8/9] mmc: block: set fwnode of disk devices
-
-Set fwnode of disk devices to 'block', 'boot0' and 'boot1' subnodes of
-the mmc-card. This is done in preparation for having the eMMC act as
-NVMEM provider.
-
----
- drivers/mmc/core/block.c | 7 +++++++
- 1 file changed, 7 insertions(+)
-
---- a/drivers/mmc/core/block.c
-+++ b/drivers/mmc/core/block.c
-@@ -2620,6 +2620,10 @@ static struct mmc_blk_data *mmc_blk_allo
- if (area_type == MMC_BLK_DATA_AREA_MAIN)
- dev_set_drvdata(&card->dev, md);
- disk_fwnode = mmc_blk_get_partitions_node(parent, subname);
-+ if (!disk_fwnode)
-+ disk_fwnode = device_get_named_child_node(subname ? md->parent->parent :
-+ md->parent,
-+ subname ? subname : "block");
- ret = add_disk_fwnode(md->parent, md->disk, mmc_disk_attr_groups,
- disk_fwnode);
- if (ret)
+++ /dev/null
-From 7903b50441000365a6fe5badb39735889f562252 Mon Sep 17 00:00:00 2001
-Date: Thu, 30 May 2024 03:15:46 +0100
-Subject: [PATCH 9/9] mmc: block: set GENHD_FL_NVMEM
-
-Set flag to consider MMC block devices as NVMEM providers.
-
----
- drivers/mmc/core/block.c | 1 +
- 1 file changed, 1 insertion(+)
-
---- a/drivers/mmc/core/block.c
-+++ b/drivers/mmc/core/block.c
-@@ -2566,6 +2566,7 @@ static struct mmc_blk_data *mmc_blk_allo
- md->disk->major = MMC_BLOCK_MAJOR;
- md->disk->minors = perdev_minors;
- md->disk->first_minor = devidx * perdev_minors;
-+ md->disk->flags = GENHD_FL_NVMEM;
- md->disk->fops = &mmc_bdops;
- md->disk->private_data = md;
- md->parent = parent;
+++ /dev/null
-Subject: kernel: disable cfi cmdset 0002 erase suspend
-
-on some platforms, erase suspend leads to data corruption and lockups when write
-ops collide with erase ops. this has been observed on the buffalo wzr-hp-g300nh.
-rather than play whack-a-mole with a hard to reproduce issue on a variety of devices,
-simply disable erase suspend, as it will usually not produce any useful gain on
-the small filesystems used on embedded hardware.
-
----
- drivers/mtd/chips/cfi_cmdset_0002.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/mtd/chips/cfi_cmdset_0002.c
-+++ b/drivers/mtd/chips/cfi_cmdset_0002.c
-@@ -906,7 +906,7 @@ static int get_chip(struct map_info *map
- return 0;
-
- case FL_ERASING:
-- if (!cfip || !(cfip->EraseSuspend & (0x1|0x2)) ||
-+ if (1 /* no suspend */ || !cfip || !(cfip->EraseSuspend & (0x1|0x2)) ||
- !(mode == FL_READY || mode == FL_POINT ||
- (mode == FL_WRITING && (cfip->EraseSuspend & 0x2))))
- goto sleep;
+++ /dev/null
-Subject: Issue map read after Write Buffer Load command to ensure chip is ready to receive data.
-
----
- drivers/mtd/chips/cfi_cmdset_0002.c | 1 +
- 1 file changed, 1 insertion(+)
---- a/drivers/mtd/chips/cfi_cmdset_0002.c
-+++ b/drivers/mtd/chips/cfi_cmdset_0002.c
-@@ -2050,6 +2050,7 @@ static int __xipram do_write_buffer(stru
-
- /* Write Buffer Load */
- map_write(map, CMD(0x25), cmd_adr);
-+ (void) map_read(map, cmd_adr);
-
- chip->state = FL_WRITING_TO_BUFFER;
-
+++ /dev/null
-Subject: Disable software protection bits for Macronix flashes.
-
----
- drivers/mtd/spi-nor/spi-nor.c | 1 +
- 1 file changed, 1 insertion(+)
-
---- a/drivers/mtd/spi-nor/macronix.c
-+++ b/drivers/mtd/spi-nor/macronix.c
-@@ -114,6 +114,7 @@ static int macronix_nor_late_init(struct
- {
- if (!nor->params->set_4byte_addr_mode)
- nor->params->set_4byte_addr_mode = spi_nor_set_4byte_addr_mode_en4b_ex4b;
-+ nor->flags |= SNOR_F_HAS_LOCK;
-
- return 0;
- }
+++ /dev/null
-Subject: kernel/mtd: add support for EON EN25Q128
-
----
- drivers/mtd/spi-nor/spi-nor.c | 1 +
- 1 file changed, 1 insertion(+)
-
---- a/drivers/mtd/spi-nor/eon.c
-+++ b/drivers/mtd/spi-nor/eon.c
-@@ -17,6 +17,8 @@ static const struct flash_info eon_nor_p
- { "en25p64", INFO(0x1c2017, 0, 64 * 1024, 128) },
- { "en25q64", INFO(0x1c3017, 0, 64 * 1024, 128)
- NO_SFDP_FLAGS(SECT_4K) },
-+ { "en25q128", INFO(0x1c3018, 0, 64 * 1024, 256)
-+ NO_SFDP_FLAGS(SECT_4K) },
- { "en25q80a", INFO(0x1c3014, 0, 64 * 1024, 16)
- NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ) },
- { "en25qh16", INFO(0x1c7015, 0, 64 * 1024, 32)
+++ /dev/null
-Subject: kernel/mtd: add support for EON EN25QX128A
-
-Add support for EON EN25QX128A with no flags as it does
-support SFDP parsing.
-
----
- drivers/mtd/spi-nor/spi-nor.c | 1 +
- 1 file changed, 1 insertion(+)
-
---- a/drivers/mtd/spi-nor/eon.c
-+++ b/drivers/mtd/spi-nor/eon.c
-@@ -19,6 +19,7 @@ static const struct flash_info eon_nor_p
- NO_SFDP_FLAGS(SECT_4K) },
- { "en25q128", INFO(0x1c3018, 0, 64 * 1024, 256)
- NO_SFDP_FLAGS(SECT_4K) },
-+ { "en25qx128a", INFO(0x1c7118, 0, 64 * 1024, 256) },
- { "en25q80a", INFO(0x1c3014, 0, 64 * 1024, 16)
- NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ) },
- { "en25qh16", INFO(0x1c7015, 0, 64 * 1024, 32)
+++ /dev/null
-From patchwork Thu Feb 6 17:19:41 2020
-Content-Type: text/plain; charset="utf-8"
-MIME-Version: 1.0
-Content-Transfer-Encoding: 7bit
-X-Patchwork-Id: 1234465
-Date: Thu, 6 Feb 2020 19:19:41 +0200
-Subject: [PATCH v2] mtd: spi-nor: Add support for xt25f128b chip
-MIME-Version: 1.0
-Content-Disposition: inline
-List-Subscribe: <http://lists.infradead.org/mailman/listinfo/linux-mtd>,
-Errors-To: linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org
-
-Add XT25F128B made by XTX Technology (Shenzhen) Limited.
-This chip supports dual and quad read and uniform 4K-byte erase.
-Verified on Teltonika RUT955 which comes with XT25F128B in recent
-versions of the device.
-
----
- drivers/mtd/spi-nor/spi-nor.c | 4 ++++
- 1 file changed, 4 insertions(+)
-
---- a/drivers/mtd/spi-nor/Makefile
-+++ b/drivers/mtd/spi-nor/Makefile
-@@ -17,6 +17,7 @@ spi-nor-objs += sst.o
- spi-nor-objs += winbond.o
- spi-nor-objs += xilinx.o
- spi-nor-objs += xmc.o
-+spi-nor-objs += xtx.o
- spi-nor-$(CONFIG_DEBUG_FS) += debugfs.o
- obj-$(CONFIG_MTD_SPI_NOR) += spi-nor.o
-
---- /dev/null
-+++ b/drivers/mtd/spi-nor/xtx.c
-@@ -0,0 +1,17 @@
-+// SPDX-License-Identifier: GPL-2.0
-+#include <linux/mtd/spi-nor.h>
-+
-+#include "core.h"
-+
-+static const struct flash_info xtx_parts[] = {
-+ /* XTX Technology (Shenzhen) Limited */
-+ { "xt25f128b", INFO(0x0B4018, 0, 64 * 1024, 256)
-+ NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ |
-+ SPI_NOR_QUAD_READ) },
-+};
-+
-+const struct spi_nor_manufacturer spi_nor_xtx = {
-+ .name = "xtx",
-+ .parts = xtx_parts,
-+ .nparts = ARRAY_SIZE(xtx_parts),
-+};
---- a/drivers/mtd/spi-nor/core.c
-+++ b/drivers/mtd/spi-nor/core.c
-@@ -2017,6 +2017,7 @@ static const struct spi_nor_manufacturer
- &spi_nor_winbond,
- &spi_nor_xilinx,
- &spi_nor_xmc,
-+ &spi_nor_xtx,
- };
-
- static const struct flash_info spi_nor_generic_flash = {
---- a/drivers/mtd/spi-nor/core.h
-+++ b/drivers/mtd/spi-nor/core.h
-@@ -647,6 +647,7 @@ extern const struct spi_nor_manufacturer
- extern const struct spi_nor_manufacturer spi_nor_winbond;
- extern const struct spi_nor_manufacturer spi_nor_xilinx;
- extern const struct spi_nor_manufacturer spi_nor_xmc;
-+extern const struct spi_nor_manufacturer spi_nor_xtx;
-
- extern const struct attribute_group *spi_nor_sysfs_groups[];
-
+++ /dev/null
-From d68b4aa22e8c625685bfad642dd7337948dc0ad1 Mon Sep 17 00:00:00 2001
-Date: Mon, 6 Jan 2020 13:07:56 +0100
-Subject: [PATCH] mtd: spi-nor: add support for Gigadevice GD25D05
-
----
- drivers/mtd/spi-nor/spi-nor.c | 5 +++++
- 1 file changed, 5 insertions(+)
-
---- a/drivers/mtd/spi-nor/gigadevice.c
-+++ b/drivers/mtd/spi-nor/gigadevice.c
-@@ -34,6 +34,10 @@ static const struct spi_nor_fixups gd25q
- };
-
- static const struct flash_info gigadevice_nor_parts[] = {
-+ { "gd25q05", INFO(0xc84010, 0, 64 * 1024, 1)
-+ FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
-+ NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ |
-+ SPI_NOR_QUAD_READ) },
- { "gd25q16", INFO(0xc84015, 0, 64 * 1024, 32)
- FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
- NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ |
+++ /dev/null
-From f8943df3beb0d3f9754bb35320c3a378727175a8 Mon Sep 17 00:00:00 2001
-Date: Thu, 14 Jul 2022 08:38:07 +0200
-Subject: [PATCH] spi-nor/gigadevic: add gd25q512
-
----
- drivers/mtd/spi-nor/gigadevice.c | 3 +++
- 1 file changed, 3 insertions(+)
-
---- a/drivers/mtd/spi-nor/gigadevice.c
-+++ b/drivers/mtd/spi-nor/gigadevice.c
-@@ -71,6 +71,11 @@ static const struct flash_info gigadevic
- FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | SPI_NOR_TB_SR_BIT6)
- FIXUP_FLAGS(SPI_NOR_4B_OPCODES)
- .fixups = &gd25q256_fixups },
-+ { "gd25q512", INFO(0xc84020, 0, 64 * 1024, 1024)
-+ FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
-+ FIXUP_FLAGS(SPI_NOR_4B_OPCODES)
-+ NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ |
-+ SPI_NOR_QUAD_READ) },
- };
-
- const struct spi_nor_manufacturer spi_nor_gigadevice = {
+++ /dev/null
-From 87363cc0e522de3294ea6ae10fb468d2a8d6fb2f Mon Sep 17 00:00:00 2001
-Date: Wed, 13 Jul 2022 12:17:21 +0200
-Subject: [PATCH] spi-nor/esmt.c: add esmt f25l16pa
-
-This fixes support for Dongwon T&I DW02-412H which uses F25L16PA(2S)
-flash.
-
----
- drivers/mtd/spi-nor/esmt.c | 2 ++
- 1 file changed, 2 insertions(+)
-
---- a/drivers/mtd/spi-nor/esmt.c
-+++ b/drivers/mtd/spi-nor/esmt.c
-@@ -10,6 +10,9 @@
-
- static const struct flash_info esmt_nor_parts[] = {
- /* ESMT */
-+ { "f25l16pa-2s", INFO(0x8c2115, 0, 64 * 1024, 32)
-+ FLAGS(SPI_NOR_HAS_LOCK)
-+ NO_SFDP_FLAGS(SECT_4K) },
- { "f25l32pa", INFO(0x8c2016, 0, 64 * 1024, 64)
- FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE)
- NO_SFDP_FLAGS(SECT_4K) },
+++ /dev/null
-From f6b33d850f7f12555df2fa0e3349b33427bf5890 Mon Sep 17 00:00:00 2001
-Date: Wed, 13 Jul 2022 12:19:01 +0200
-Subject: [PATCH] spi-nor/xmc.c: add xm25qh128c
-
-The XMC XM25QH128C is a 16MB SPI NOR chip. The patch is verified on
-Ruijie RG-EW3200GX PRO.
-Datasheet available at https://www.xmcwh.com/uploads/435/XM25QH128C.pdf
-
----
- drivers/mtd/spi-nor/xmc.c | 2 ++
- 1 file changed, 2 insertions(+)
-
---- a/drivers/mtd/spi-nor/xmc.c
-+++ b/drivers/mtd/spi-nor/xmc.c
-@@ -16,6 +16,9 @@ static const struct flash_info xmc_nor_p
- { "XM25QH128A", INFO(0x207018, 0, 64 * 1024, 256)
- NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ |
- SPI_NOR_QUAD_READ) },
-+ { "XM25QH128C", INFO(0x204018, 0, 64 * 1024, 256)
-+ NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ |
-+ SPI_NOR_QUAD_READ) },
- };
-
- const struct spi_nor_manufacturer spi_nor_xmc = {
+++ /dev/null
-From f32085fc0b87049491b07e198d924d738a1a2834 Mon Sep 17 00:00:00 2001
-Date: Wed, 3 Aug 2022 17:31:03 +0200
-Subject: [PATCH] mtd: spinand: Add support for Etron EM73D044VCx
-
-Airoha is a new ARM platform based on Cortex-A53 which has recently been
-merged into linux-next.
-
-Due to BootROM limitations on this platform, the Cortex-A53 can't run in
-Aarch64 mode and code must be compiled for 32-Bit ARM.
-
-This support is based mostly on those linux-next commits backported
-for kernel 5.15.
-
-Patches:
-1 - platform support = linux-next
-2 - clock driver = linux-next
-3 - gpio driver = linux-next
-4 - linux,usable-memory-range dts support = linux-next
-5 - mtd spinand driver
-6 - spi driver
-7 - pci driver (kconfig only, uses mediatek PCI) = linux-next
-
-Still missing:
-- Ethernet driver
-- Sysupgrade support
-
-A.t.m there exists one subtarget EN7523 with only one evaluation
-board.
-
-The initramfs can be run with the following commands from u-boot:
--
-u-boot> setenv bootfile \
- openwrt-airoha-airoha_en7523-evb-initramfs-kernel.bin
-u-boot> tftpboot
-u-boot> bootm 0x81800000
--
-
-
---- a/drivers/mtd/nand/spi/Makefile
-+++ b/drivers/mtd/nand/spi/Makefile
-@@ -1,4 +1,4 @@
- # SPDX-License-Identifier: GPL-2.0
--spinand-objs := core.o alliancememory.o ato.o esmt.o fmsh.o foresee.o gigadevice.o macronix.o
--spinand-objs += micron.o paragon.o toshiba.o winbond.o xtx.o
-+spinand-objs := core.o alliancememory.o ato.o esmt.o etron.o fmsh.o foresee.o gigadevice.o
-+spinand-objs += macronix.o micron.o paragon.o toshiba.o winbond.o xtx.o
- obj-$(CONFIG_MTD_SPI_NAND) += spinand.o
---- a/drivers/mtd/nand/spi/core.c
-+++ b/drivers/mtd/nand/spi/core.c
-@@ -943,6 +943,7 @@ static const struct spinand_manufacturer
- &alliancememory_spinand_manufacturer,
- &ato_spinand_manufacturer,
- &esmt_c8_spinand_manufacturer,
-+ &etron_spinand_manufacturer,
- &fmsh_spinand_manufacturer,
- &foresee_spinand_manufacturer,
- &gigadevice_spinand_manufacturer,
---- /dev/null
-+++ b/drivers/mtd/nand/spi/etron.c
-@@ -0,0 +1,98 @@
-+// SPDX-License-Identifier: GPL-2.0
-+
-+#include <linux/device.h>
-+#include <linux/kernel.h>
-+#include <linux/mtd/spinand.h>
-+
-+#define SPINAND_MFR_ETRON 0xd5
-+
-+
-+static SPINAND_OP_VARIANTS(read_cache_variants,
-+ SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 1, NULL, 0),
-+ SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
-+ SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
-+ SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
-+ SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
-+ SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
-+
-+static SPINAND_OP_VARIANTS(write_cache_variants,
-+ SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
-+ SPINAND_PROG_LOAD(true, 0, NULL, 0));
-+
-+static SPINAND_OP_VARIANTS(update_cache_variants,
-+ SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
-+ SPINAND_PROG_LOAD(false, 0, NULL, 0));
-+
-+static int etron_ooblayout_ecc(struct mtd_info *mtd, int section,
-+ struct mtd_oob_region *oobregion)
-+{
-+ if (section)
-+ return -ERANGE;
-+
-+ oobregion->offset = 72;
-+ oobregion->length = 56;
-+
-+ return 0;
-+}
-+
-+static int etron_ooblayout_free(struct mtd_info *mtd, int section,
-+ struct mtd_oob_region *oobregion)
-+{
-+ if (section)
-+ return -ERANGE;
-+
-+ oobregion->offset = 1;
-+ oobregion->length = 71;
-+
-+ return 0;
-+}
-+
-+static int etron_ecc_get_status(struct spinand_device *spinand, u8 status)
-+{
-+ switch (status & STATUS_ECC_MASK) {
-+ case STATUS_ECC_NO_BITFLIPS:
-+ return 0;
-+
-+ case STATUS_ECC_HAS_BITFLIPS:
-+ /* Between 1-7 bitflips were corrected */
-+ return 7;
-+
-+ case STATUS_ECC_MASK:
-+ /* Maximum bitflips were corrected */
-+ return 8;
-+
-+ case STATUS_ECC_UNCOR_ERROR:
-+ return -EBADMSG;
-+ }
-+
-+ return -EINVAL;
-+}
-+
-+static const struct mtd_ooblayout_ops etron_ooblayout = {
-+ .ecc = etron_ooblayout_ecc,
-+ .free = etron_ooblayout_free,
-+};
-+
-+static const struct spinand_info etron_spinand_table[] = {
-+ SPINAND_INFO("EM73D044VCx",
-+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x1f),
-+ // bpc, pagesize, oobsize, pagesperblock, bperlun, maxbadplun, ppl, lpt, #t
-+ NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),
-+ NAND_ECCREQ(8, 512),
-+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
-+ &write_cache_variants,
-+ &update_cache_variants),
-+ SPINAND_HAS_QE_BIT,
-+ SPINAND_ECCINFO(&etron_ooblayout, etron_ecc_get_status)),
-+};
-+
-+static const struct spinand_manufacturer_ops etron_spinand_manuf_ops = {
-+};
-+
-+const struct spinand_manufacturer etron_spinand_manufacturer = {
-+ .id = SPINAND_MFR_ETRON,
-+ .name = "Etron",
-+ .chips = etron_spinand_table,
-+ .nchips = ARRAY_SIZE(etron_spinand_table),
-+ .ops = &etron_spinand_manuf_ops,
-+};
---- a/include/linux/mtd/spinand.h
-+++ b/include/linux/mtd/spinand.h
-@@ -263,6 +263,7 @@ struct spinand_manufacturer {
- extern const struct spinand_manufacturer alliancememory_spinand_manufacturer;
- extern const struct spinand_manufacturer ato_spinand_manufacturer;
- extern const struct spinand_manufacturer esmt_c8_spinand_manufacturer;
-+extern const struct spinand_manufacturer etron_spinand_manufacturer;
- extern const struct spinand_manufacturer fmsh_spinand_manufacturer;
- extern const struct spinand_manufacturer foresee_spinand_manufacturer;
- extern const struct spinand_manufacturer gigadevice_spinand_manufacturer;
+++ /dev/null
-Subject: mtd/spi-nor/xmc: add support for XMC XM25QH64C
-
-The XMC XM25QH64C is a 8MB SPI NOR chip. The patch is verified on TL-WPA8631P v3.
-Datasheet available at https://www.xmcwh.com/uploads/442/XM25QH64C.pdf
-
----
- drivers/mtd/spi-nor/xmc.c | 2 ++
- 1 file changed, 2 insertions(+)
-
---- a/drivers/mtd/spi-nor/xmc.c
-+++ b/drivers/mtd/spi-nor/xmc.c
-@@ -13,6 +13,9 @@ static const struct flash_info xmc_nor_p
- { "XM25QH64A", INFO(0x207017, 0, 64 * 1024, 128)
- NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ |
- SPI_NOR_QUAD_READ) },
-+ { "XM25QH64C", INFO(0x204017, 0, 64 * 1024, 128)
-+ NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ |
-+ SPI_NOR_QUAD_READ) },
- { "XM25QH128A", INFO(0x207018, 0, 64 * 1024, 256)
- NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ |
- SPI_NOR_QUAD_READ) },
+++ /dev/null
-Subject: ubi: auto-attach mtd device named "ubi" or "data" on boot
-
----
- drivers/mtd/ubi/build.c | 36 ++++++++++++++++++++++++++++++++++++
- 1 file changed, 36 insertions(+)
-
---- a/drivers/mtd/ubi/build.c
-+++ b/drivers/mtd/ubi/build.c
-@@ -1258,6 +1258,80 @@ static struct mtd_notifier ubi_mtd_notif
- .remove = ubi_notify_remove,
- };
-
-+
-+/*
-+ * This function tries attaching mtd partitions named either "ubi" or "data"
-+ * during boot.
-+ */
-+static void __init ubi_auto_attach(void)
-+{
-+ int err;
-+ struct mtd_info *mtd;
-+ struct device_node *np;
-+ loff_t offset = 0;
-+ size_t len;
-+ char magic[4];
-+
-+ /* try attaching mtd device named "ubi" or "data" */
-+ mtd = open_mtd_device("ubi");
-+ if (IS_ERR(mtd))
-+ mtd = open_mtd_device("data");
-+
-+ if (IS_ERR(mtd))
-+ return;
-+
-+ /* skip "linux,ubi" mtd as it has already been attached */
-+ np = mtd_get_of_node(mtd);
-+ if (of_device_is_compatible(np, "linux,ubi"))
-+ goto cleanup;
-+
-+ /* get the first not bad block */
-+ if (mtd_can_have_bb(mtd))
-+ while (mtd_block_isbad(mtd, offset)) {
-+ offset += mtd->erasesize;
-+
-+ if (offset > mtd->size) {
-+ pr_err("UBI error: Failed to find a non-bad "
-+ "block on mtd%d\n", mtd->index);
-+ goto cleanup;
-+ }
-+ }
-+
-+ /* check if the read from flash was successful */
-+ err = mtd_read(mtd, offset, 4, &len, (void *) magic);
-+ if ((err && !mtd_is_bitflip(err)) || len != 4) {
-+ pr_err("UBI error: unable to read from mtd%d\n", mtd->index);
-+ goto cleanup;
-+ }
-+
-+ /* check for a valid ubi magic */
-+ if (strncmp(magic, "UBI#", 4)) {
-+ pr_err("UBI error: no valid UBI magic found inside mtd%d\n", mtd->index);
-+ goto cleanup;
-+ }
-+
-+ /* don't auto-add media types where UBI doesn't makes sense */
-+ if (mtd->type != MTD_NANDFLASH &&
-+ mtd->type != MTD_NORFLASH &&
-+ mtd->type != MTD_DATAFLASH &&
-+ mtd->type != MTD_MLCNANDFLASH)
-+ goto cleanup;
-+
-+ mutex_lock(&ubi_devices_mutex);
-+ pr_notice("UBI: auto-attach mtd%d\n", mtd->index);
-+ err = ubi_attach_mtd_dev(mtd, UBI_DEV_NUM_AUTO, 0, 0, false);
-+ mutex_unlock(&ubi_devices_mutex);
-+ if (err < 0) {
-+ pr_err("UBI error: cannot attach mtd%d\n", mtd->index);
-+ goto cleanup;
-+ }
-+
-+ return;
-+
-+cleanup:
-+ put_mtd_device(mtd);
-+}
-+
- static int __init ubi_init_attach(void)
- {
- int err, i, k;
-@@ -1308,6 +1382,12 @@ static int __init ubi_init_attach(void)
- }
- }
-
-+ /* auto-attach mtd devices only if built-in to the kernel and no ubi.mtd
-+ * parameter was given */
-+ if (IS_ENABLED(CONFIG_MTD_ROOTFS_ROOT_DEV) &&
-+ !ubi_is_module() && !mtd_devs)
-+ ubi_auto_attach();
-+
- return 0;
-
- out_detach:
+++ /dev/null
-Subject: ubi: auto-create ubiblock device for rootfs
-
----
- drivers/mtd/ubi/block.c | 42 ++++++++++++++++++++++++++++++++++++++++++
- 1 file changed, 42 insertions(+)
-
---- a/drivers/mtd/ubi/block.c
-+++ b/drivers/mtd/ubi/block.c
-@@ -570,10 +570,47 @@ match_volume_desc(struct ubi_volume_info
- return true;
- }
-
-+#define UBIFS_NODE_MAGIC 0x06101831
-+static inline int ubi_vol_is_ubifs(struct ubi_volume_desc *desc)
-+{
-+ int ret;
-+ uint32_t magic_of, magic;
-+ ret = ubi_read(desc, 0, (char *)&magic_of, 0, 4);
-+ if (ret)
-+ return 0;
-+ magic = le32_to_cpu(magic_of);
-+ return magic == UBIFS_NODE_MAGIC;
-+}
-+
-+static void ubiblock_create_auto_rootfs(struct ubi_volume_info *vi)
-+{
-+ int ret, is_ubifs;
-+ struct ubi_volume_desc *desc;
-+
-+ if (strcmp(vi->name, "rootfs") &&
-+ strcmp(vi->name, "fit"))
-+ return;
-+
-+ desc = ubi_open_volume(vi->ubi_num, vi->vol_id, UBI_READONLY);
-+ if (IS_ERR(desc))
-+ return;
-+
-+ is_ubifs = ubi_vol_is_ubifs(desc);
-+ ubi_close_volume(desc);
-+ if (is_ubifs)
-+ return;
-+
-+ ret = ubiblock_create(vi);
-+ if (ret)
-+ pr_err("UBI error: block: can't add '%s' volume, err=%d\n",
-+ vi->name, ret);
-+}
-+
- static void
- ubiblock_create_from_param(struct ubi_volume_info *vi)
- {
- int i, ret = 0;
-+ bool got_param = false;
- struct ubiblock_param *p;
-
- /*
-@@ -586,6 +623,7 @@ ubiblock_create_from_param(struct ubi_vo
- if (!match_volume_desc(vi, p->name, p->ubi_num, p->vol_id))
- continue;
-
-+ got_param = true;
- ret = ubiblock_create(vi);
- if (ret) {
- pr_err(
-@@ -594,6 +632,10 @@ ubiblock_create_from_param(struct ubi_vo
- }
- break;
- }
-+
-+ /* auto-attach "rootfs" volume if existing and non-ubifs */
-+ if (!got_param && IS_ENABLED(CONFIG_MTD_ROOTFS_ROOT_DEV))
-+ ubiblock_create_auto_rootfs(vi);
- }
-
- static int ubiblock_notify(struct notifier_block *nb,
+++ /dev/null
-Subject: try auto-mounting ubi0:rootfs in init/do_mounts.c
-
----
- init/do_mounts.c | 26 +++++++++++++++++++++++++-
- 1 file changed, 25 insertions(+), 1 deletion(-)
-
---- a/init/do_mounts.c
-+++ b/init/do_mounts.c
-@@ -248,7 +248,30 @@ retry:
- out:
- put_page(page);
- }
--
-+
-+#ifdef CONFIG_MTD_ROOTFS_ROOT_DEV
-+static int __init mount_ubi_rootfs(void)
-+{
-+ int flags = MS_SILENT;
-+ int err, tried = 0;
-+
-+ while (tried < 2) {
-+ err = do_mount_root("ubi0:rootfs", "ubifs", flags, \
-+ root_mount_data);
-+ switch (err) {
-+ case -EACCES:
-+ flags |= MS_RDONLY;
-+ tried++;
-+ break;
-+ default:
-+ return err;
-+ }
-+ }
-+
-+ return -EINVAL;
-+}
-+#endif
-+
- #ifdef CONFIG_ROOT_NFS
-
- #define NFSROOT_TIMEOUT_MIN 5
-@@ -385,6 +408,11 @@ static inline void mount_block_root(char
-
- void __init mount_root(char *root_device_name)
- {
-+#ifdef CONFIG_MTD_ROOTFS_ROOT_DEV
-+ if (!mount_ubi_rootfs())
-+ return;
-+#endif
-+
- switch (ROOT_DEV) {
- case Root_NFS:
- mount_nfs_root();
+++ /dev/null
-Subject: ubi: set ROOT_DEV to ubiblock "rootfs" if unset
-
----
- drivers/mtd/ubi/block.c | 10 ++++++++++
- 1 file changed, 10 insertions(+)
-
---- a/drivers/mtd/ubi/block.c
-+++ b/drivers/mtd/ubi/block.c
-@@ -41,6 +41,7 @@
- #include <linux/scatterlist.h>
- #include <linux/idr.h>
- #include <asm/div64.h>
-+#include <linux/root_dev.h>
-
- #include "ubi-media.h"
- #include "ubi.h"
-@@ -428,6 +429,15 @@ int ubiblock_create(struct ubi_volume_in
- dev_info(disk_to_dev(dev->gd), "created from ubi%d:%d(%s)",
- dev->ubi_num, dev->vol_id, vi->name);
- mutex_unlock(&devices_mutex);
-+
-+ if (!strcmp(vi->name, "rootfs") &&
-+ IS_ENABLED(CONFIG_MTD_ROOTFS_ROOT_DEV) &&
-+ ROOT_DEV == 0) {
-+ pr_notice("ubiblock: device ubiblock%d_%d (%s) set to be root filesystem\n",
-+ dev->ubi_num, dev->vol_id, vi->name);
-+ ROOT_DEV = MKDEV(gd->major, gd->first_minor);
-+ }
-+
- return 0;
-
- out_remove_minor:
+++ /dev/null
-Subject: mtd: add EOF marker support to the UBI layer
-
----
- drivers/mtd/ubi/attach.c | 25 ++++++++++++++++++++++---
- drivers/mtd/ubi/ubi.h | 1 +
- 2 files changed, 23 insertions(+), 3 deletions(-)
-
---- a/drivers/mtd/ubi/attach.c
-+++ b/drivers/mtd/ubi/attach.c
-@@ -926,6 +926,13 @@ static bool vol_ignored(int vol_id)
- #endif
- }
-
-+static bool ec_hdr_has_eof(struct ubi_ec_hdr *ech)
-+{
-+ return ech->padding1[0] == 'E' &&
-+ ech->padding1[1] == 'O' &&
-+ ech->padding1[2] == 'F';
-+}
-+
- /**
- * scan_peb - scan and process UBI headers of a PEB.
- * @ubi: UBI device description object
-@@ -958,9 +965,21 @@ static int scan_peb(struct ubi_device *u
- return 0;
- }
-
-- err = ubi_io_read_ec_hdr(ubi, pnum, ech, 0);
-- if (err < 0)
-- return err;
-+ if (!ai->eof_found) {
-+ err = ubi_io_read_ec_hdr(ubi, pnum, ech, 0);
-+ if (err < 0)
-+ return err;
-+
-+ if (ec_hdr_has_eof(ech)) {
-+ pr_notice("UBI: EOF marker found, PEBs from %d will be erased\n",
-+ pnum);
-+ ai->eof_found = true;
-+ }
-+ }
-+
-+ if (ai->eof_found)
-+ err = UBI_IO_FF_BITFLIPS;
-+
- switch (err) {
- case 0:
- break;
---- a/drivers/mtd/ubi/ubi.h
-+++ b/drivers/mtd/ubi/ubi.h
-@@ -780,6 +780,7 @@ struct ubi_attach_info {
- int mean_ec;
- uint64_t ec_sum;
- int ec_count;
-+ bool eof_found;
- struct kmem_cache *aeb_slab_cache;
- struct ubi_ec_hdr *ech;
- struct ubi_vid_io_buf *vidb;
+++ /dev/null
-From 5734c6669fba7ddb5ef491ccff7159d15dba0b59 Mon Sep 17 00:00:00 2001
-Date: Wed, 5 Sep 2018 01:32:51 +0200
-Subject: [PATCH 496/497] dt-bindings: add bindings for mtd-concat devices
-
-Document virtual mtd-concat device bindings.
-
----
- .../devicetree/bindings/mtd/mtd-concat.txt | 36 +++++++++++++++++++
- 1 file changed, 36 insertions(+)
- create mode 100644 Documentation/devicetree/bindings/mtd/mtd-concat.txt
-
---- /dev/null
-+++ b/Documentation/devicetree/bindings/mtd/mtd-concat.txt
-@@ -0,0 +1,36 @@
-+Virtual MTD concat device
-+
-+Requires properties:
-+- devices: list of phandles to mtd nodes that should be concatenated
-+
-+Example:
-+
-+&spi {
-+ flash0: flash@0 {
-+ ...
-+ };
-+ flash1: flash@1 {
-+ ...
-+ };
-+};
-+
-+flash {
-+ compatible = "mtd-concat";
-+
-+ devices = <&flash0 &flash1>;
-+
-+ partitions {
-+ compatible = "fixed-partitions";
-+
-+ partition@0 {
-+ label = "boot";
-+ reg = <0x0000000 0x0040000>;
-+ read-only;
-+ };
-+
-+ partition@40000 {
-+ label = "firmware";
-+ reg = <0x0040000 0x1fc0000>;
-+ };
-+ }
-+}
+++ /dev/null
-From e53f712d8eac71f54399b61038ccf87d2cee99d7 Mon Sep 17 00:00:00 2001
-Date: Sat, 25 Aug 2018 12:35:22 +0200
-Subject: [PATCH 497/497] mtd: mtdconcat: add dt driver for concat devices
-
-Some mtd drivers like physmap variants have support for concatenating
-multiple mtd devices, but there is no generic way to define such a
-concat device from within the device tree.
-
-This is useful for some SoC boards that use multiple flash chips as
-memory banks of a single mtd device, with partitions spanning chip
-borders.
-
-This commit adds a driver for creating virtual mtd-concat devices. They
-must have a compatible = "mtd-concat" line, and define a list of devices
-to concat in the 'devices' property, for example:
-
-flash {
- compatible = "mtd-concat";
-
- devices = <&flash0 &flash1>;
-
- partitions {
- ...
- };
-};
-
-The driver is added to the very end of the mtd Makefile to increase the
-likelyhood of all child devices already being loaded at the time of
-probing, preventing unnecessary deferred probes.
-
----
- drivers/mtd/Kconfig | 2 +
- drivers/mtd/Makefile | 3 +
- drivers/mtd/composite/Kconfig | 12 +++
- drivers/mtd/composite/Makefile | 6 ++
- drivers/mtd/composite/virt_concat.c | 128 ++++++++++++++++++++++++++++
- 5 files changed, 151 insertions(+)
- create mode 100644 drivers/mtd/composite/Kconfig
- create mode 100644 drivers/mtd/composite/Makefile
- create mode 100644 drivers/mtd/composite/virt_concat.c
-
---- a/drivers/mtd/Kconfig
-+++ b/drivers/mtd/Kconfig
-@@ -241,4 +241,6 @@ source "drivers/mtd/ubi/Kconfig"
-
- source "drivers/mtd/hyperbus/Kconfig"
-
-+source "drivers/mtd/composite/Kconfig"
-+
- endif # MTD
---- a/drivers/mtd/Makefile
-+++ b/drivers/mtd/Makefile
-@@ -33,3 +33,6 @@ obj-y += chips/ lpddr/ maps/ devices/ n
- obj-$(CONFIG_MTD_SPI_NOR) += spi-nor/
- obj-$(CONFIG_MTD_UBI) += ubi/
- obj-$(CONFIG_MTD_HYPERBUS) += hyperbus/
-+
-+# Composite drivers must be loaded last
-+obj-y += composite/
---- /dev/null
-+++ b/drivers/mtd/composite/Kconfig
-@@ -0,0 +1,12 @@
-+menu "Composite MTD device drivers"
-+ depends on MTD!=n
-+
-+config MTD_VIRT_CONCAT
-+ tristate "Virtual concat MTD device"
-+ help
-+ This driver allows creation of a virtual MTD concat device, which
-+ concatenates multiple underlying MTD devices to a single device.
-+ This is required by some SoC boards where multiple memory banks are
-+ used as one device with partitions spanning across device boundaries.
-+
-+endmenu
---- /dev/null
-+++ b/drivers/mtd/composite/Makefile
-@@ -0,0 +1,6 @@
-+# SPDX-License-Identifier: GPL-2.0
-+#
-+# linux/drivers/mtd/composite/Makefile
-+#
-+
-+obj-$(CONFIG_MTD_VIRT_CONCAT) += virt_concat.o
---- /dev/null
-+++ b/drivers/mtd/composite/virt_concat.c
-@@ -0,0 +1,128 @@
-+// SPDX-License-Identifier: GPL-2.0+
-+/*
-+ * Virtual concat MTD device driver
-+ *
-+ * Copyright (C) 2018 Bernhard Frauendienst
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/device.h>
-+#include <linux/mtd/concat.h>
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/partitions.h>
-+#include <linux/of.h>
-+#include <linux/of_platform.h>
-+#include <linux/slab.h>
-+
-+/*
-+ * struct of_virt_concat - platform device driver data.
-+ * @cmtd the final mtd_concat device
-+ * @num_devices the number of devices in @devices
-+ * @devices points to an array of devices already loaded
-+ */
-+struct of_virt_concat {
-+ struct mtd_info *cmtd;
-+ int num_devices;
-+ struct mtd_info **devices;
-+};
-+
-+static int virt_concat_remove(struct platform_device *pdev)
-+{
-+ struct of_virt_concat *info;
-+ int i;
-+
-+ info = platform_get_drvdata(pdev);
-+ if (!info)
-+ return 0;
-+
-+ // unset data for when this is called after a probe error
-+ platform_set_drvdata(pdev, NULL);
-+
-+ if (info->cmtd) {
-+ mtd_device_unregister(info->cmtd);
-+ mtd_concat_destroy(info->cmtd);
-+ }
-+
-+ if (info->devices) {
-+ for (i = 0; i < info->num_devices; i++)
-+ put_mtd_device(info->devices[i]);
-+ }
-+
-+ return 0;
-+}
-+
-+static int virt_concat_probe(struct platform_device *pdev)
-+{
-+ struct device_node *node = pdev->dev.of_node;
-+ struct of_phandle_iterator it;
-+ struct of_virt_concat *info;
-+ struct mtd_info *mtd;
-+ int err = 0, count;
-+
-+ count = of_count_phandle_with_args(node, "devices", NULL);
-+ if (count <= 0)
-+ return -EINVAL;
-+
-+ info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
-+ if (!info)
-+ return -ENOMEM;
-+ info->devices = devm_kcalloc(&pdev->dev, count,
-+ sizeof(*(info->devices)), GFP_KERNEL);
-+ if (!info->devices) {
-+ err = -ENOMEM;
-+ goto err_remove;
-+ }
-+
-+ platform_set_drvdata(pdev, info);
-+
-+ of_for_each_phandle(&it, err, node, "devices", NULL, 0) {
-+ mtd = of_get_mtd_device_by_node(it.node);
-+ if (IS_ERR(mtd)) {
-+ of_node_put(it.node);
-+ err = -EPROBE_DEFER;
-+ goto err_remove;
-+ }
-+
-+ info->devices[info->num_devices++] = mtd;
-+ }
-+
-+ info->cmtd = mtd_concat_create(info->devices, info->num_devices,
-+ dev_name(&pdev->dev));
-+ if (!info->cmtd) {
-+ err = -ENXIO;
-+ goto err_remove;
-+ }
-+
-+ info->cmtd->dev.parent = &pdev->dev;
-+ mtd_set_of_node(info->cmtd, node);
-+ mtd_device_register(info->cmtd, NULL, 0);
-+
-+ return 0;
-+
-+err_remove:
-+ virt_concat_remove(pdev);
-+
-+ return err;
-+}
-+
-+static const struct of_device_id virt_concat_of_match[] = {
-+ { .compatible = "mtd-concat", },
-+ { /* sentinel */ }
-+};
-+MODULE_DEVICE_TABLE(of, virt_concat_of_match);
-+
-+static struct platform_driver virt_concat_driver = {
-+ .probe = virt_concat_probe,
-+ .remove = virt_concat_remove,
-+ .driver = {
-+ .name = "virt-mtdconcat",
-+ .of_match_table = virt_concat_of_match,
-+ },
-+};
-+
-+module_platform_driver(virt_concat_driver);
-+
-+MODULE_LICENSE("GPL v2");
-+MODULE_DESCRIPTION("Virtual concat MTD device driver");
+++ /dev/null
-From 8bf2ce6ea4ee840b70f55a27f80e1cd308051b13 Mon Sep 17 00:00:00 2001
-Date: Mon, 27 Dec 2021 00:38:13 +0100
-Subject: [PATCH 1/2] mtd: spi-nor: locking support for MX25L6405D
-
-Macronix MX25L6405D supports locking with four block-protection bits.
-Currently, the driver only sets three bits. If the bootloader does not
-sustain the flash chip in an unlocked state, the flash might be
-non-writeable. Add the corresponding flag to enable locking support with
-four bits in the status register.
-
-Tested on Nanostation M2 XM.
-
-Similar to commit 7ea40b54e83b ("mtd: spi-nor: enable locking support for
-MX25L12805D")
-
----
- drivers/mtd/spi-nor/macronix.c | 3 ++-
- 1 file changed, 2 insertions(+), 1 deletion(-)
-
---- a/drivers/mtd/spi-nor/macronix.c
-+++ b/drivers/mtd/spi-nor/macronix.c
-@@ -48,6 +48,7 @@ static const struct flash_info macronix_
- { "mx25l3255e", INFO(0xc29e16, 0, 64 * 1024, 64)
- NO_SFDP_FLAGS(SECT_4K) },
- { "mx25l6405d", INFO(0xc22017, 0, 64 * 1024, 128)
-+ FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_4BIT_BP)
- NO_SFDP_FLAGS(SECT_4K) },
- { "mx25u2033e", INFO(0xc22532, 0, 64 * 1024, 4)
- NO_SFDP_FLAGS(SECT_4K) },
+++ /dev/null
-From 245224608b5368c10407da07557e546743d3c489 Mon Sep 17 00:00:00 2001
-Date: Mon, 27 Dec 2021 09:33:13 +0100
-Subject: [PATCH 2/2] mtd: spi-nor: disable 16-bit-sr for macronix
-
-Macronix flash chips seem to consist of only one status register.
-These chips will not work with the "16-bit Write Status (01h) Command".
-Disable SNOR_F_HAS_16BIT_SR for all Macronix chips.
-
-Tested with MX25L6405D.
-
-Fixes: 39d1e3340c73 ("mtd: spi-nor: Fix clearing of QE bit on
-lock()/unlock()")
-
----
- drivers/mtd/spi-nor/macronix.c | 1 +
- 1 file changed, 1 insertion(+)
-
---- a/drivers/mtd/spi-nor/macronix.c
-+++ b/drivers/mtd/spi-nor/macronix.c
-@@ -115,6 +115,7 @@ static int macronix_nor_late_init(struct
- {
- if (!nor->params->set_4byte_addr_mode)
- nor->params->set_4byte_addr_mode = spi_nor_set_4byte_addr_mode_en4b_ex4b;
-+ nor->flags &= ~SNOR_F_HAS_16BIT_SR;
- nor->flags |= SNOR_F_HAS_LOCK;
-
- return 0;
+++ /dev/null
-From af7b91bcecce0eae24e90acd35d96ecee73e1407 Mon Sep 17 00:00:00 2001
-Date: Wed, 13 Jul 2022 12:21:15 +0200
-Subject: [PATCH] fs: add cdrom dependency
-
----
- fs/hfs/Kconfig | 1 +
- fs/hfsplus/Kconfig | 1 +
- fs/isofs/Kconfig | 1 +
- fs/udf/Kconfig | 1 +
- 4 files changed, 4 insertions(+)
-
---- a/fs/hfs/Kconfig
-+++ b/fs/hfs/Kconfig
-@@ -2,6 +2,7 @@
- config HFS_FS
- tristate "Apple Macintosh file system support"
- depends on BLOCK
-+ select CDROM
- select BUFFER_HEAD
- select NLS
- select LEGACY_DIRECT_IO
---- a/fs/hfsplus/Kconfig
-+++ b/fs/hfsplus/Kconfig
-@@ -2,6 +2,7 @@
- config HFSPLUS_FS
- tristate "Apple Extended HFS file system support"
- depends on BLOCK
-+ select CDROM
- select BUFFER_HEAD
- select NLS
- select NLS_UTF8
---- a/fs/isofs/Kconfig
-+++ b/fs/isofs/Kconfig
-@@ -1,6 +1,7 @@
- # SPDX-License-Identifier: GPL-2.0-only
- config ISO9660_FS
- tristate "ISO 9660 CDROM file system support"
-+ select CDROM
- select BUFFER_HEAD
- help
- This is the standard file system used on CD-ROMs. It was previously
---- a/fs/udf/Kconfig
-+++ b/fs/udf/Kconfig
-@@ -1,6 +1,7 @@
- # SPDX-License-Identifier: GPL-2.0-only
- config UDF_FS
- tristate "UDF file system support"
-+ select CDROM
- select BUFFER_HEAD
- select CRC_ITU_T
- select NLS
+++ /dev/null
-From 6173a065cb395d4a9528c4e49810af127db68141 Mon Sep 17 00:00:00 2001
-Date: Wed, 16 Nov 2022 12:49:52 +0000
-Subject: [PATCH 1/2] block: add uImage.FIT subimage block driver
-
-Add a small block driver which exposes filesystem sub-images contained
-in U-Boot uImage.FIT images as block devices.
-
-The uImage.FIT image has to be stored directly on a block device or
-partition, MTD device or partition, or UBI volume.
-
-The driver is intended for systems using the U-Boot bootloader and
-uses the root device hint left by the bootloader (or the user) in
-the 'chosen' section of the device-tree.
-
-Example:
-/dts-v1/;
-/ {
- chosen {
- rootdisk = <&mmc0_part3>;
- };
-};
-
----
- MAINTAINERS | 6 +
- drivers/block/Kconfig | 12 +
- drivers/block/Makefile | 2 +
- drivers/block/fitblk.c | 658 ++++++++++++++++++++++++++++++++++++
- drivers/block/open | 4 +
- include/uapi/linux/fitblk.h | 10 +
- 6 files changed, 692 insertions(+)
- create mode 100644 drivers/block/fitblk.c
- create mode 100644 drivers/block/open
- create mode 100644 include/uapi/linux/fitblk.h
-
---- a/MAINTAINERS
-+++ b/MAINTAINERS
-@@ -22018,6 +22018,12 @@ F: Documentation/filesystems/ubifs-authe
- F: Documentation/filesystems/ubifs.rst
- F: fs/ubifs/
-
-+U-BOOT UIMAGE.FIT PARSER
-+S: Maintained
-+F: drivers/block/fitblk.c
-+
- UBLK USERSPACE BLOCK DRIVER
---- a/drivers/block/Kconfig
-+++ b/drivers/block/Kconfig
-@@ -354,6 +354,18 @@ config VIRTIO_BLK
- This is the virtual block driver for virtio. It can be used with
- QEMU based VMMs (like KVM or Xen). Say Y or M.
-
-+config UIMAGE_FIT_BLK
-+ bool "uImage.FIT block driver"
-+ help
-+ This driver allows using filesystems contained in uImage.FIT images
-+ by mapping them as block devices.
-+
-+ It can currently not be built as a module due to libfdt symbols not
-+ being exported.
-+
-+ Say Y if you want to mount filesystems sub-images of a uImage.FIT
-+ stored in a block device partition, mtdblock or ubiblock device.
-+
- config BLK_DEV_RBD
- tristate "Rados block device (RBD)"
- depends on INET && BLOCK
---- a/drivers/block/Makefile
-+++ b/drivers/block/Makefile
-@@ -39,4 +39,6 @@ obj-$(CONFIG_BLK_DEV_NULL_BLK) += null_b
-
- obj-$(CONFIG_BLK_DEV_UBLK) += ublk_drv.o
-
-+obj-$(CONFIG_UIMAGE_FIT_BLK) += fitblk.o
-+
- swim_mod-y := swim.o swim_asm.o
---- /dev/null
-+++ b/drivers/block/fitblk.c
-@@ -0,0 +1,658 @@
-+// SPDX-License-Identifier: GPL-2.0-only
-+/*
-+ * uImage.FIT virtual block device driver.
-+ *
-+ * Copyright (C) 2023 Daniel Golle
-+ * Copyright (C) 2007 Nick Piggin
-+ * Copyright (C) 2007 Novell Inc.
-+ *
-+ * Initially derived from drivers/block/brd.c which is in parts derived from
-+ * drivers/block/rd.c, and drivers/block/loop.c, copyright of their respective
-+ * owners.
-+ *
-+ * uImage.FIT headers extracted from Das U-Boot
-+ * (C) Copyright 2008 Semihalf
-+ * (C) Copyright 2000-2005
-+ */
-+
-+#include <linux/init.h>
-+#include <linux/initrd.h>
-+#include <linux/module.h>
-+#include <linux/moduleparam.h>
-+#include <linux/major.h>
-+#include <linux/blkdev.h>
-+#include <linux/blkpg.h>
-+#include <linux/blk-mq.h>
-+#include <linux/ctype.h>
-+#include <linux/hdreg.h>
-+#include <linux/list.h>
-+#include <linux/mutex.h>
-+#include <linux/of.h>
-+#include <linux/of_device.h>
-+#include <linux/of_fdt.h>
-+#include <linux/pagemap.h>
-+#include <linux/platform_device.h>
-+#include <linux/property.h>
-+#include <linux/refcount.h>
-+#include <linux/task_work.h>
-+#include <linux/types.h>
-+#include <linux/libfdt.h>
-+#include <linux/mtd/mtd.h>
-+#include <linux/root_dev.h>
-+#include <uapi/linux/fitblk.h>
-+
-+#define FIT_DEVICE_PREFIX "fit"
-+
-+/* maximum number of pages used for the uImage.FIT index structure */
-+#define FIT_MAX_PAGES 1024
-+
-+/* minimum free sectors to map as read-write "remainder" volume */
-+#define MIN_FREE_SECT 16
-+
-+/* maximum number of mapped loadables */
-+#define MAX_FIT_LOADABLES 16
-+
-+/* constants for uImage.FIT structrure traversal */
-+#define FIT_IMAGES_PATH "/images"
-+#define FIT_CONFS_PATH "/configurations"
-+
-+/* hash/signature/key node */
-+#define FIT_HASH_NODENAME "hash"
-+#define FIT_ALGO_PROP "algo"
-+#define FIT_VALUE_PROP "value"
-+#define FIT_IGNORE_PROP "uboot-ignore"
-+#define FIT_SIG_NODENAME "signature"
-+#define FIT_KEY_REQUIRED "required"
-+#define FIT_KEY_HINT "key-name-hint"
-+
-+/* cipher node */
-+#define FIT_CIPHER_NODENAME "cipher"
-+#define FIT_ALGO_PROP "algo"
-+
-+/* image node */
-+#define FIT_DATA_PROP "data"
-+#define FIT_DATA_POSITION_PROP "data-position"
-+#define FIT_DATA_OFFSET_PROP "data-offset"
-+#define FIT_DATA_SIZE_PROP "data-size"
-+#define FIT_TIMESTAMP_PROP "timestamp"
-+#define FIT_DESC_PROP "description"
-+#define FIT_ARCH_PROP "arch"
-+#define FIT_TYPE_PROP "type"
-+#define FIT_OS_PROP "os"
-+#define FIT_COMP_PROP "compression"
-+#define FIT_ENTRY_PROP "entry"
-+#define FIT_LOAD_PROP "load"
-+
-+/* configuration node */
-+#define FIT_KERNEL_PROP "kernel"
-+#define FIT_FILESYSTEM_PROP "filesystem"
-+#define FIT_RAMDISK_PROP "ramdisk"
-+#define FIT_FDT_PROP "fdt"
-+#define FIT_LOADABLE_PROP "loadables"
-+#define FIT_DEFAULT_PROP "default"
-+#define FIT_SETUP_PROP "setup"
-+#define FIT_FPGA_PROP "fpga"
-+#define FIT_FIRMWARE_PROP "firmware"
-+#define FIT_STANDALONE_PROP "standalone"
-+
-+/* fitblk driver data */
-+static const char *_fitblk_claim_ptr = "I belong to fitblk";
-+static const char *ubootver;
-+struct device_node *rootdisk;
-+static struct platform_device *pdev;
-+static LIST_HEAD(fitblk_devices);
-+static DEFINE_MUTEX(devices_mutex);
-+refcount_t num_devs;
-+
-+struct fitblk {
-+ struct platform_device *pdev;
-+ struct block_device *lower_bdev;
-+ sector_t start_sect;
-+ struct gendisk *disk;
-+ struct work_struct remove_work;
-+ struct list_head list;
-+ bool dead;
-+};
-+
-+static int fitblk_open(struct gendisk *disk, fmode_t mode)
-+{
-+ struct fitblk *fitblk = disk->private_data;
-+
-+ if (fitblk->dead)
-+ return -ENOENT;
-+
-+ return 0;
-+}
-+
-+static void fitblk_release(struct gendisk *disk)
-+{
-+ return;
-+}
-+
-+static void fitblk_submit_bio(struct bio *orig_bio)
-+{
-+ struct bio *bio = orig_bio;
-+ struct fitblk *fitblk = bio->bi_bdev->bd_disk->private_data;
-+
-+ if (fitblk->dead)
-+ return;
-+
-+ /* mangle bio and re-submit */
-+ while (bio) {
-+ bio->bi_iter.bi_sector += fitblk->start_sect;
-+ bio->bi_bdev = fitblk->lower_bdev;
-+ bio = bio->bi_next;
-+ }
-+ submit_bio(orig_bio);
-+}
-+
-+static void fitblk_remove(struct fitblk *fitblk)
-+{
-+ blk_mark_disk_dead(fitblk->disk);
-+ mutex_lock(&devices_mutex);
-+ fitblk->dead = true;
-+ list_del(&fitblk->list);
-+ mutex_unlock(&devices_mutex);
-+
-+ schedule_work(&fitblk->remove_work);
-+}
-+
-+static int fitblk_ioctl(struct block_device *bdev, fmode_t mode,
-+ unsigned int cmd, unsigned long arg)
-+{
-+ struct fitblk *fitblk = bdev->bd_disk->private_data;
-+
-+ if (!capable(CAP_SYS_ADMIN))
-+ return -EACCES;
-+
-+ if (fitblk->dead)
-+ return -ENOENT;
-+
-+ switch (cmd) {
-+ case FITBLK_RELEASE:
-+ fitblk_remove(fitblk);
-+ break;
-+ default:
-+ return -EINVAL;
-+ }
-+
-+ return 0;
-+}
-+
-+static const struct block_device_operations fitblk_fops = {
-+ .owner = THIS_MODULE,
-+ .ioctl = fitblk_ioctl,
-+ .open = fitblk_open,
-+ .release = fitblk_release,
-+ .submit_bio = fitblk_submit_bio,
-+};
-+
-+static void fitblk_purge(struct work_struct *work)
-+{
-+ struct fitblk *fitblk = container_of(work, struct fitblk, remove_work);
-+
-+ //del_gendisk(fitblk->disk); // causes crash, not doing it doesn't matter
-+ refcount_dec(&num_devs);
-+ platform_device_del(fitblk->pdev);
-+ platform_device_put(fitblk->pdev);
-+
-+ if (refcount_dec_if_one(&num_devs)) {
-+ sysfs_remove_link(&pdev->dev.kobj, "lower_dev");
-+ blkdev_put(fitblk->lower_bdev, &_fitblk_claim_ptr);
-+ }
-+
-+ kfree(fitblk);
-+}
-+
-+static int add_fit_subimage_device(struct block_device *lower_bdev,
-+ unsigned int slot, sector_t start_sect,
-+ sector_t nr_sect, bool readonly)
-+{
-+ struct fitblk *fitblk;
-+ struct gendisk *disk;
-+ int err;
-+
-+ mutex_lock(&devices_mutex);
-+ if (!refcount_inc_not_zero(&num_devs))
-+ return -EBADF;
-+
-+ fitblk = kzalloc(sizeof(struct fitblk), GFP_KERNEL);
-+ if (!fitblk) {
-+ err = -ENOMEM;
-+ goto out_unlock;
-+ }
-+
-+ fitblk->lower_bdev = lower_bdev;
-+ fitblk->start_sect = start_sect;
-+ INIT_WORK(&fitblk->remove_work, fitblk_purge);
-+
-+ disk = blk_alloc_disk(NUMA_NO_NODE);
-+ if (!disk) {
-+ err = -ENOMEM;
-+ goto out_free_fitblk;
-+ }
-+
-+ disk->first_minor = 0;
-+ disk->flags = lower_bdev->bd_disk->flags | GENHD_FL_NO_PART;
-+ disk->fops = &fitblk_fops;
-+ disk->private_data = fitblk;
-+ if (readonly) {
-+ set_disk_ro(disk, 1);
-+ snprintf(disk->disk_name, sizeof(disk->disk_name), FIT_DEVICE_PREFIX "%u", slot);
-+ } else {
-+ strcpy(disk->disk_name, FIT_DEVICE_PREFIX "rw");
-+ }
-+
-+ set_capacity(disk, nr_sect);
-+
-+ disk->queue->queue_flags = lower_bdev->bd_disk->queue->queue_flags;
-+ memcpy(&disk->queue->limits, &lower_bdev->bd_disk->queue->limits,
-+ sizeof(struct queue_limits));
-+
-+ fitblk->disk = disk;
-+ fitblk->pdev = platform_device_alloc(disk->disk_name, PLATFORM_DEVID_NONE);
-+ if (!fitblk->pdev) {
-+ err = -ENOMEM;
-+ goto out_cleanup_disk;
-+ }
-+
-+ fitblk->pdev->dev.parent = &pdev->dev;
-+ err = platform_device_add(fitblk->pdev);
-+ if (err)
-+ goto out_put_pdev;
-+
-+ err = device_add_disk(&fitblk->pdev->dev, disk, NULL);
-+ if (err)
-+ goto out_del_pdev;
-+
-+ if (!ROOT_DEV)
-+ ROOT_DEV = disk->part0->bd_dev;
-+
-+ list_add_tail(&fitblk->list, &fitblk_devices);
-+
-+ mutex_unlock(&devices_mutex);
-+
-+ return 0;
-+
-+out_del_pdev:
-+ platform_device_del(fitblk->pdev);
-+out_put_pdev:
-+ platform_device_put(fitblk->pdev);
-+out_cleanup_disk:
-+ put_disk(disk);
-+out_free_fitblk:
-+ kfree(fitblk);
-+out_unlock:
-+ refcount_dec(&num_devs);
-+ mutex_unlock(&devices_mutex);
-+ return err;
-+}
-+
-+static void fitblk_mark_dead(struct block_device *bdev, bool surprise)
-+{
-+ struct list_head *n, *tmp;
-+ struct fitblk *fitblk;
-+
-+ mutex_lock(&devices_mutex);
-+ list_for_each_safe(n, tmp, &fitblk_devices) {
-+ fitblk = list_entry(n, struct fitblk, list);
-+ if (fitblk->lower_bdev != bdev)
-+ continue;
-+
-+ fitblk->dead = true;
-+ list_del(&fitblk->list);
-+ /* removal needs to be deferred to avoid deadlock */
-+ schedule_work(&fitblk->remove_work);
-+ }
-+ mutex_unlock(&devices_mutex);
-+}
-+
-+static const struct blk_holder_ops fitblk_hops = {
-+ .mark_dead = fitblk_mark_dead,
-+};
-+
-+static int parse_fit_on_dev(struct device *dev)
-+{
-+ struct block_device *bdev;
-+ struct address_space *mapping;
-+ struct folio *folio;
-+ pgoff_t f_index = 0;
-+ size_t bytes_left, bytes_to_copy;
-+ void *pre_fit, *fit, *fit_c;
-+ u64 dsize, dsectors, imgmaxsect = 0;
-+ u32 size, image_pos, image_len;
-+ const __be32 *image_offset_be, *image_len_be, *image_pos_be;
-+ int ret = 0, node, images, config;
-+ const char *image_name, *image_type, *image_description,
-+ *config_default, *config_description, *config_loadables;
-+ u32 image_name_len, image_type_len, image_description_len,
-+ bootconf_len, config_default_len, config_description_len,
-+ config_loadables_len;
-+ sector_t start_sect, nr_sects;
-+ struct device_node *np = NULL;
-+ const char *bootconf_c;
-+ const char *loadable;
-+ char *bootconf = NULL, *bootconf_term;
-+ bool found;
-+ int loadables_rem_len, loadable_len;
-+ u16 loadcnt;
-+ unsigned int slot = 0;
-+
-+ /* Exclusive open the block device to receive holder notifications */
-+ bdev = blkdev_get_by_dev(dev->devt, BLK_OPEN_READ, &_fitblk_claim_ptr, &fitblk_hops);
-+ if (!bdev)
-+ return -ENODEV;
-+
-+ if (IS_ERR(bdev))
-+ return PTR_ERR(bdev);
-+
-+ mapping = bdev->bd_inode->i_mapping;
-+
-+ /* map first page */
-+ folio = read_mapping_folio(mapping, f_index++, NULL);
-+ if (IS_ERR(folio)) {
-+ ret = PTR_ERR(folio);
-+ goto out_blkdev;
-+ }
-+ pre_fit = folio_address(folio) + offset_in_folio(folio, 0);
-+
-+ /* uImage.FIT is based on flattened device tree structure */
-+ if (fdt_check_header(pre_fit)) {
-+ ret = -EINVAL;
-+ folio_put(folio);
-+ goto out_blkdev;
-+ }
-+
-+ size = fdt_totalsize(pre_fit);
-+
-+ if (size > PAGE_SIZE * FIT_MAX_PAGES) {
-+ ret = -EOPNOTSUPP;
-+ folio_put(folio);
-+ goto out_blkdev;
-+ }
-+
-+ /* acquire disk size */
-+ dsectors = bdev_nr_sectors(bdev);
-+ dsize = dsectors << SECTOR_SHIFT;
-+
-+ /* abort if FIT structure is larger than disk or partition size */
-+ if (size >= dsize) {
-+ ret = -EFBIG;
-+ folio_put(folio);
-+ goto out_blkdev;
-+ }
-+
-+ fit = kmalloc(size, GFP_KERNEL);
-+ if (!fit) {
-+ ret = -ENOMEM;
-+ folio_put(folio);
-+ goto out_blkdev;
-+ }
-+
-+ bytes_left = size;
-+ fit_c = fit;
-+ while (bytes_left > 0) {
-+ bytes_to_copy = min_t(size_t, bytes_left,
-+ folio_size(folio) - offset_in_folio(folio, 0));
-+ memcpy(fit_c, pre_fit, bytes_to_copy);
-+ fit_c += bytes_to_copy;
-+ bytes_left -= bytes_to_copy;
-+ if (bytes_left) {
-+ folio_put(folio);
-+ folio = read_mapping_folio(mapping, f_index++, NULL);
-+ if (IS_ERR(folio)) {
-+ ret = PTR_ERR(folio);
-+ goto out_blkdev;
-+ };
-+ pre_fit = folio_address(folio) + offset_in_folio(folio, 0);
-+ }
-+ }
-+ folio_put(folio);
-+
-+ /* set boot config node name U-Boot may have added to the device tree */
-+ np = of_find_node_by_path("/chosen");
-+ if (np) {
-+ bootconf_c = of_get_property(np, "u-boot,bootconf", &bootconf_len);
-+ if (bootconf_c && bootconf_len)
-+ bootconf = kmemdup_nul(bootconf_c, bootconf_len, GFP_KERNEL);
-+ }
-+
-+ if (bootconf) {
-+ bootconf_term = strchr(bootconf, '#');
-+ if (bootconf_term)
-+ *bootconf_term = '\0';
-+ }
-+
-+ /* find configuration path in uImage.FIT */
-+ config = fdt_path_offset(fit, FIT_CONFS_PATH);
-+ if (config < 0) {
-+ pr_err("FIT: Cannot find %s node: %d\n",
-+ FIT_CONFS_PATH, config);
-+ ret = -ENOENT;
-+ goto out_bootconf;
-+ }
-+
-+ /* get default configuration node name */
-+ config_default =
-+ fdt_getprop(fit, config, FIT_DEFAULT_PROP, &config_default_len);
-+
-+ /* make sure we got either default or selected boot config node name */
-+ if (!config_default && !bootconf) {
-+ pr_err("FIT: Cannot find default configuration\n");
-+ ret = -ENOENT;
-+ goto out_bootconf;
-+ }
-+
-+ /* find selected boot config node, fallback on default config node */
-+ node = fdt_subnode_offset(fit, config, bootconf ?: config_default);
-+ if (node < 0) {
-+ pr_err("FIT: Cannot find %s node: %d\n",
-+ bootconf ?: config_default, node);
-+ ret = -ENOENT;
-+ goto out_bootconf;
-+ }
-+
-+ pr_info("FIT: Detected U-Boot %s\n", ubootver);
-+
-+ /* get selected configuration data */
-+ config_description =
-+ fdt_getprop(fit, node, FIT_DESC_PROP, &config_description_len);
-+ config_loadables = fdt_getprop(fit, node, FIT_LOADABLE_PROP,
-+ &config_loadables_len);
-+
-+ pr_info("FIT: %s configuration: \"%.*s\"%s%.*s%s\n",
-+ bootconf ? "Selected" : "Default",
-+ bootconf ? bootconf_len : config_default_len,
-+ bootconf ?: config_default,
-+ config_description ? " (" : "",
-+ config_description ? config_description_len : 0,
-+ config_description ?: "",
-+ config_description ? ")" : "");
-+
-+ if (!config_loadables || !config_loadables_len) {
-+ pr_err("FIT: No loadables configured in \"%s\"\n",
-+ bootconf ?: config_default);
-+ ret = -ENOENT;
-+ goto out_bootconf;
-+ }
-+
-+ /* get images path in uImage.FIT */
-+ images = fdt_path_offset(fit, FIT_IMAGES_PATH);
-+ if (images < 0) {
-+ pr_err("FIT: Cannot find %s node: %d\n", FIT_IMAGES_PATH, images);
-+ ret = -EINVAL;
-+ goto out_bootconf;
-+ }
-+
-+ /* iterate over images in uImage.FIT */
-+ fdt_for_each_subnode(node, fit, images) {
-+ image_name = fdt_get_name(fit, node, &image_name_len);
-+ image_type = fdt_getprop(fit, node, FIT_TYPE_PROP, &image_type_len);
-+ image_offset_be = fdt_getprop(fit, node, FIT_DATA_OFFSET_PROP, NULL);
-+ image_pos_be = fdt_getprop(fit, node, FIT_DATA_POSITION_PROP, NULL);
-+ image_len_be = fdt_getprop(fit, node, FIT_DATA_SIZE_PROP, NULL);
-+
-+ if (!image_name || !image_type || !image_len_be ||
-+ !image_name_len || !image_type_len)
-+ continue;
-+
-+ image_len = be32_to_cpu(*image_len_be);
-+ if (!image_len)
-+ continue;
-+
-+ if (image_offset_be)
-+ image_pos = be32_to_cpu(*image_offset_be) + size;
-+ else if (image_pos_be)
-+ image_pos = be32_to_cpu(*image_pos_be);
-+ else
-+ continue;
-+
-+ image_description = fdt_getprop(fit, node, FIT_DESC_PROP,
-+ &image_description_len);
-+
-+ pr_info("FIT: %16s sub-image 0x%08x..0x%08x \"%.*s\"%s%.*s%s\n",
-+ image_type, image_pos, image_pos + image_len - 1,
-+ image_name_len, image_name, image_description ? " (" : "",
-+ image_description ? image_description_len : 0,
-+ image_description ?: "", image_description ? ") " : "");
-+
-+ /* only 'filesystem' images should be mapped as partitions */
-+ if (strncmp(image_type, FIT_FILESYSTEM_PROP, image_type_len))
-+ continue;
-+
-+ /* check if sub-image is part of configured loadables */
-+ found = false;
-+ loadable = config_loadables;
-+ loadables_rem_len = config_loadables_len;
-+ for (loadcnt = 0; loadables_rem_len > 1 &&
-+ loadcnt < MAX_FIT_LOADABLES; ++loadcnt) {
-+ loadable_len =
-+ strnlen(loadable, loadables_rem_len - 1) + 1;
-+ loadables_rem_len -= loadable_len;
-+ if (!strncmp(image_name, loadable, loadable_len)) {
-+ found = true;
-+ break;
-+ }
-+ loadable += loadable_len;
-+ }
-+ if (!found)
-+ continue;
-+
-+ if (image_pos % (1 << PAGE_SHIFT)) {
-+ dev_err(dev, "FIT: image %.*s start not aligned to page boundaries, skipping\n",
-+ image_name_len, image_name);
-+ continue;
-+ }
-+
-+ if (image_len % (1 << PAGE_SHIFT)) {
-+ dev_err(dev, "FIT: sub-image %.*s end not aligned to page boundaries, skipping\n",
-+ image_name_len, image_name);
-+ continue;
-+ }
-+
-+ start_sect = image_pos >> SECTOR_SHIFT;
-+ nr_sects = image_len >> SECTOR_SHIFT;
-+ imgmaxsect = max_t(sector_t, imgmaxsect, start_sect + nr_sects);
-+
-+ if (start_sect + nr_sects > dsectors) {
-+ dev_err(dev, "FIT: sub-image %.*s disk access beyond EOD\n",
-+ image_name_len, image_name);
-+ continue;
-+ }
-+
-+ if (!slot) {
-+ ret = sysfs_create_link_nowarn(&pdev->dev.kobj, bdev_kobj(bdev), "lower_dev");
-+ if (ret && ret != -EEXIST)
-+ goto out_bootconf;
-+
-+ ret = 0;
-+ }
-+
-+ add_fit_subimage_device(bdev, slot++, start_sect, nr_sects, true);
-+ }
-+
-+ if (!slot)
-+ goto out_bootconf;
-+
-+ dev_info(dev, "mapped %u uImage.FIT filesystem sub-image%s as /dev/fit%s%u%s\n",
-+ slot, (slot > 1)?"s":"", (slot > 1)?"[0...":"", slot - 1,
-+ (slot > 1)?"]":"");
-+
-+ /* in case uImage.FIT is stored in a partition, map the remaining space */
-+ if (!bdev->bd_read_only && bdev_is_partition(bdev) &&
-+ (imgmaxsect + MIN_FREE_SECT) < dsectors) {
-+ add_fit_subimage_device(bdev, slot++, imgmaxsect,
-+ dsectors - imgmaxsect, false);
-+ dev_info(dev, "mapped remaining space as /dev/fitrw\n");
-+ }
-+
-+out_bootconf:
-+ kfree(bootconf);
-+ kfree(fit);
-+out_blkdev:
-+ if (!slot)
-+ blkdev_put(bdev, &_fitblk_claim_ptr);
-+
-+ return ret;
-+}
-+
-+static int fitblk_match_of_node(struct device *dev, const void *np)
-+{
-+ int ret;
-+
-+ ret = device_match_of_node(dev, np);
-+ if (ret)
-+ return ret;
-+
-+ /*
-+ * To match ubiblock and mtdblock devices by their parent ubi
-+ * or mtd device, also consider block device parent
-+ */
-+ if (!dev->parent)
-+ return 0;
-+
-+ return device_match_of_node(dev->parent, np);
-+}
-+
-+static int fitblk_probe(struct platform_device *pdev)
-+{
-+ struct device *dev;
-+
-+ dev = class_find_device(&block_class, NULL, rootdisk, fitblk_match_of_node);
-+ if (!dev)
-+ return -EPROBE_DEFER;
-+
-+ return parse_fit_on_dev(dev);
-+}
-+
-+static struct platform_driver fitblk_driver = {
-+ .probe = fitblk_probe,
-+ .driver = {
-+ .name = "fitblk",
-+ },
-+};
-+
-+static int __init fitblk_init(void)
-+{
-+ /* detect U-Boot firmware */
-+ ubootver = of_get_property(of_chosen, "u-boot,version", NULL);
-+ if (!ubootver)
-+ return 0;
-+
-+ /* parse 'rootdisk' property phandle */
-+ rootdisk = of_parse_phandle(of_chosen, "rootdisk", 0);
-+ if (!rootdisk)
-+ return 0;
-+
-+ if (platform_driver_register(&fitblk_driver))
-+ return -ENODEV;
-+
-+ refcount_set(&num_devs, 1);
-+ pdev = platform_device_register_simple("fitblk", -1, NULL, 0);
-+ if (IS_ERR(pdev))
-+ return PTR_ERR(pdev);
-+
-+ return 0;
-+}
-+device_initcall(fitblk_init);
---- /dev/null
-+++ b/include/uapi/linux/fitblk.h
-@@ -0,0 +1,10 @@
-+/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
-+#ifndef _UAPI_LINUX_FITBLK_H
-+#define _UAPI_LINUX_FITBLK_H
-+
-+/*
-+ * IOCTL commands --- we will commandeer 0x46 ('F')
-+ */
-+#define FITBLK_RELEASE 0x4600
-+
-+#endif /* _UAPI_LINUX_FITBLK_H */
+++ /dev/null
-From 5ede3f8aed9a1a579bf7304142600d1f3500add9 Mon Sep 17 00:00:00 2001
-Date: Mon, 12 Jun 2023 03:58:42 +0100
-Subject: [PATCH 2/2] init: bypass device lookup for /dev/fit* rootfs
-
-Allow 'rootwait' as /dev/fit* can show up late if the underlaying
-device is probed late.
-
----
- init/do_mounts.c | 3 ++-
- 1 file changed, 2 insertions(+), 1 deletion(-)
-
---- a/init/do_mounts.c
-+++ b/init/do_mounts.c
-@@ -463,7 +463,8 @@ static dev_t __init parse_root_device(ch
- int error;
- dev_t dev;
-
-- if (!strncmp(root_device_name, "mtd", 3) ||
-+ if (!strncmp(root_device_name, "fit", 3) ||
-+ !strncmp(root_device_name, "mtd", 3) ||
- !strncmp(root_device_name, "ubi", 3))
- return Root_Generic;
- if (strcmp(root_device_name, "/dev/nfs") == 0)
+++ /dev/null
-Subject: fs: add jffs2/lzma support (not activated by default yet)
-
-lede-commit: c2c88d315fa0e881f8b19da07b62859b915b11b2
----
- fs/jffs2/Kconfig | 9 +
- fs/jffs2/Makefile | 3 +
- fs/jffs2/compr.c | 6 +
- fs/jffs2/compr.h | 10 +-
- fs/jffs2/compr_lzma.c | 128 +++
- fs/jffs2/super.c | 33 +-
- include/linux/lzma.h | 62 ++
- include/linux/lzma/LzFind.h | 115 +++
- include/linux/lzma/LzHash.h | 54 +
- include/linux/lzma/LzmaDec.h | 231 +++++
- include/linux/lzma/LzmaEnc.h | 80 ++
- include/linux/lzma/Types.h | 226 +++++
- include/uapi/linux/jffs2.h | 1 +
- lib/Kconfig | 6 +
- lib/Makefile | 12 +
- lib/lzma/LzFind.c | 761 ++++++++++++++
- lib/lzma/LzmaDec.c | 999 +++++++++++++++++++
- lib/lzma/LzmaEnc.c | 2271 ++++++++++++++++++++++++++++++++++++++++++
- lib/lzma/Makefile | 7 +
- 19 files changed, 5008 insertions(+), 6 deletions(-)
- create mode 100644 fs/jffs2/compr_lzma.c
- create mode 100644 include/linux/lzma.h
- create mode 100644 include/linux/lzma/LzFind.h
- create mode 100644 include/linux/lzma/LzHash.h
- create mode 100644 include/linux/lzma/LzmaDec.h
- create mode 100644 include/linux/lzma/LzmaEnc.h
- create mode 100644 include/linux/lzma/Types.h
- create mode 100644 lib/lzma/LzFind.c
- create mode 100644 lib/lzma/LzmaDec.c
- create mode 100644 lib/lzma/LzmaEnc.c
- create mode 100644 lib/lzma/Makefile
-
---- a/fs/jffs2/Kconfig
-+++ b/fs/jffs2/Kconfig
-@@ -136,6 +136,15 @@ config JFFS2_LZO
- This feature was added in July, 2007. Say 'N' if you need
- compatibility with older bootloaders or kernels.
-
-+config JFFS2_LZMA
-+ bool "JFFS2 LZMA compression support" if JFFS2_COMPRESSION_OPTIONS
-+ select LZMA_COMPRESS
-+ select LZMA_DECOMPRESS
-+ depends on JFFS2_FS
-+ default n
-+ help
-+ JFFS2 wrapper to the LZMA C SDK
-+
- config JFFS2_RTIME
- bool "JFFS2 RTIME compression support" if JFFS2_COMPRESSION_OPTIONS
- depends on JFFS2_FS
---- a/fs/jffs2/Makefile
-+++ b/fs/jffs2/Makefile
-@@ -19,4 +19,7 @@ jffs2-$(CONFIG_JFFS2_RUBIN) += compr_rub
- jffs2-$(CONFIG_JFFS2_RTIME) += compr_rtime.o
- jffs2-$(CONFIG_JFFS2_ZLIB) += compr_zlib.o
- jffs2-$(CONFIG_JFFS2_LZO) += compr_lzo.o
-+jffs2-$(CONFIG_JFFS2_LZMA) += compr_lzma.o
- jffs2-$(CONFIG_JFFS2_SUMMARY) += summary.o
-+
-+CFLAGS_compr_lzma.o += -Iinclude/linux -Ilib/lzma
---- a/fs/jffs2/compr.c
-+++ b/fs/jffs2/compr.c
-@@ -381,6 +381,9 @@ int __init jffs2_compressors_init(void)
- ret = jffs2_lzo_init();
- if (ret)
- goto exit_dynrubin;
-+ ret = jffs2_lzma_init();
-+ if (ret)
-+ goto exit_lzo;
-
-
- /* Setting default compression mode */
-@@ -402,6 +405,8 @@ int __init jffs2_compressors_init(void)
- #endif
- return 0;
-
-+exit_lzo:
-+ jffs2_lzo_exit();
- exit_dynrubin:
- jffs2_dynrubin_exit();
- exit_runinmips:
-@@ -417,6 +422,7 @@ exit:
- int jffs2_compressors_exit(void)
- {
- /* Unregistering compressors */
-+ jffs2_lzma_exit();
- jffs2_lzo_exit();
- jffs2_dynrubin_exit();
- jffs2_rubinmips_exit();
---- a/fs/jffs2/compr.h
-+++ b/fs/jffs2/compr.h
-@@ -29,9 +29,9 @@
- #define JFFS2_DYNRUBIN_PRIORITY 20
- #define JFFS2_LZARI_PRIORITY 30
- #define JFFS2_RTIME_PRIORITY 50
--#define JFFS2_ZLIB_PRIORITY 60
--#define JFFS2_LZO_PRIORITY 80
--
-+#define JFFS2_LZMA_PRIORITY 70
-+#define JFFS2_ZLIB_PRIORITY 80
-+#define JFFS2_LZO_PRIORITY 90
-
- #define JFFS2_RUBINMIPS_DISABLED /* RUBINs will be used only */
- #define JFFS2_DYNRUBIN_DISABLED /* for decompression */
-@@ -115,5 +115,12 @@ extern void jffs2_lzo_exit(void);
- static inline int jffs2_lzo_init(void) { return 0; }
- static inline void jffs2_lzo_exit(void) {}
- #endif
-+#ifdef CONFIG_JFFS2_LZMA
-+extern int jffs2_lzma_init(void);
-+extern void jffs2_lzma_exit(void);
-+#else
-+static inline int jffs2_lzma_init(void) { return 0; }
-+static inline void jffs2_lzma_exit(void) {}
-+#endif
-
- #endif /* __JFFS2_COMPR_H__ */
---- /dev/null
-+++ b/fs/jffs2/compr_lzma.c
-@@ -0,0 +1,128 @@
-+/*
-+ * JFFS2 -- Journalling Flash File System, Version 2.
-+ *
-+ * For licensing information, see the file 'LICENCE' in this directory.
-+ *
-+ * JFFS2 wrapper to the LZMA C SDK
-+ *
-+ */
-+
-+#include <linux/lzma.h>
-+#include "compr.h"
-+
-+#ifdef __KERNEL__
-+ static DEFINE_MUTEX(deflate_mutex);
-+#endif
-+
-+CLzmaEncHandle *p;
-+Byte propsEncoded[LZMA_PROPS_SIZE];
-+SizeT propsSize = sizeof(propsEncoded);
-+
-+STATIC void lzma_free_workspace(void)
-+{
-+ LzmaEnc_Destroy(p, &lzma_alloc, &lzma_alloc);
-+}
-+
-+STATIC int INIT lzma_alloc_workspace(CLzmaEncProps *props)
-+{
-+ if ((p = (CLzmaEncHandle *)LzmaEnc_Create(&lzma_alloc)) == NULL)
-+ {
-+ PRINT_ERROR("Failed to allocate lzma deflate workspace\n");
-+ return -ENOMEM;
-+ }
-+
-+ if (LzmaEnc_SetProps(p, props) != SZ_OK)
-+ {
-+ lzma_free_workspace();
-+ return -1;
-+ }
-+
-+ if (LzmaEnc_WriteProperties(p, propsEncoded, &propsSize) != SZ_OK)
-+ {
-+ lzma_free_workspace();
-+ return -1;
-+ }
-+
-+ return 0;
-+}
-+
-+STATIC int jffs2_lzma_compress(unsigned char *data_in, unsigned char *cpage_out,
-+ uint32_t *sourcelen, uint32_t *dstlen)
-+{
-+ SizeT compress_size = (SizeT)(*dstlen);
-+ int ret;
-+
-+ #ifdef __KERNEL__
-+ mutex_lock(&deflate_mutex);
-+ #endif
-+
-+ ret = LzmaEnc_MemEncode(p, cpage_out, &compress_size, data_in, *sourcelen,
-+ 0, NULL, &lzma_alloc, &lzma_alloc);
-+
-+ #ifdef __KERNEL__
-+ mutex_unlock(&deflate_mutex);
-+ #endif
-+
-+ if (ret != SZ_OK)
-+ return -1;
-+
-+ *dstlen = (uint32_t)compress_size;
-+
-+ return 0;
-+}
-+
-+STATIC int jffs2_lzma_decompress(unsigned char *data_in, unsigned char *cpage_out,
-+ uint32_t srclen, uint32_t destlen)
-+{
-+ int ret;
-+ SizeT dl = (SizeT)destlen;
-+ SizeT sl = (SizeT)srclen;
-+ ELzmaStatus status;
-+
-+ ret = LzmaDecode(cpage_out, &dl, data_in, &sl, propsEncoded,
-+ propsSize, LZMA_FINISH_ANY, &status, &lzma_alloc);
-+
-+ if (ret != SZ_OK || status == LZMA_STATUS_NOT_FINISHED || dl != (SizeT)destlen)
-+ return -1;
-+
-+ return 0;
-+}
-+
-+static struct jffs2_compressor jffs2_lzma_comp = {
-+ .priority = JFFS2_LZMA_PRIORITY,
-+ .name = "lzma",
-+ .compr = JFFS2_COMPR_LZMA,
-+ .compress = &jffs2_lzma_compress,
-+ .decompress = &jffs2_lzma_decompress,
-+ .disabled = 0,
-+};
-+
-+int INIT jffs2_lzma_init(void)
-+{
-+ int ret;
-+ CLzmaEncProps props;
-+ LzmaEncProps_Init(&props);
-+
-+ props.dictSize = LZMA_BEST_DICT(0x2000);
-+ props.level = LZMA_BEST_LEVEL;
-+ props.lc = LZMA_BEST_LC;
-+ props.lp = LZMA_BEST_LP;
-+ props.pb = LZMA_BEST_PB;
-+ props.fb = LZMA_BEST_FB;
-+
-+ ret = lzma_alloc_workspace(&props);
-+ if (ret < 0)
-+ return ret;
-+
-+ ret = jffs2_register_compressor(&jffs2_lzma_comp);
-+ if (ret)
-+ lzma_free_workspace();
-+
-+ return ret;
-+}
-+
-+void jffs2_lzma_exit(void)
-+{
-+ jffs2_unregister_compressor(&jffs2_lzma_comp);
-+ lzma_free_workspace();
-+}
---- a/fs/jffs2/super.c
-+++ b/fs/jffs2/super.c
-@@ -375,14 +375,41 @@ static int __init init_jffs2_fs(void)
- BUILD_BUG_ON(sizeof(struct jffs2_raw_inode) != 68);
- BUILD_BUG_ON(sizeof(struct jffs2_raw_summary) != 32);
-
-- pr_info("version 2.2."
-+ pr_info("version 2.2"
- #ifdef CONFIG_JFFS2_FS_WRITEBUFFER
- " (NAND)"
- #endif
- #ifdef CONFIG_JFFS2_SUMMARY
-- " (SUMMARY) "
-+ " (SUMMARY)"
- #endif
-- " © 2001-2006 Red Hat, Inc.\n");
-+#ifdef CONFIG_JFFS2_ZLIB
-+ " (ZLIB)"
-+#endif
-+#ifdef CONFIG_JFFS2_LZO
-+ " (LZO)"
-+#endif
-+#ifdef CONFIG_JFFS2_LZMA
-+ " (LZMA)"
-+#endif
-+#ifdef CONFIG_JFFS2_RTIME
-+ " (RTIME)"
-+#endif
-+#ifdef CONFIG_JFFS2_RUBIN
-+ " (RUBIN)"
-+#endif
-+#ifdef CONFIG_JFFS2_CMODE_NONE
-+ " (CMODE_NONE)"
-+#endif
-+#ifdef CONFIG_JFFS2_CMODE_PRIORITY
-+ " (CMODE_PRIORITY)"
-+#endif
-+#ifdef CONFIG_JFFS2_CMODE_SIZE
-+ " (CMODE_SIZE)"
-+#endif
-+#ifdef CONFIG_JFFS2_CMODE_FAVOURLZO
-+ " (CMODE_FAVOURLZO)"
-+#endif
-+ " (c) 2001-2006 Red Hat, Inc.\n");
-
- jffs2_inode_cachep = kmem_cache_create("jffs2_i",
- sizeof(struct jffs2_inode_info),
---- /dev/null
-+++ b/include/linux/lzma.h
-@@ -0,0 +1,62 @@
-+#ifndef __LZMA_H__
-+#define __LZMA_H__
-+
-+#ifdef __KERNEL__
-+ #include <linux/kernel.h>
-+ #include <linux/sched.h>
-+ #include <linux/slab.h>
-+ #include <linux/vmalloc.h>
-+ #include <linux/init.h>
-+ #define LZMA_MALLOC vmalloc
-+ #define LZMA_FREE vfree
-+ #define PRINT_ERROR(msg) printk(KERN_WARNING #msg)
-+ #define INIT __init
-+ #define STATIC static
-+#else
-+ #include <stdint.h>
-+ #include <stdlib.h>
-+ #include <stdio.h>
-+ #include <unistd.h>
-+ #include <string.h>
-+ #include <asm/types.h>
-+ #include <errno.h>
-+ #include <linux/jffs2.h>
-+ #ifndef PAGE_SIZE
-+ extern int page_size;
-+ #define PAGE_SIZE page_size
-+ #endif
-+ #define LZMA_MALLOC malloc
-+ #define LZMA_FREE free
-+ #define PRINT_ERROR(msg) fprintf(stderr, msg)
-+ #define INIT
-+ #define STATIC
-+#endif
-+
-+#include "lzma/LzmaDec.h"
-+#include "lzma/LzmaEnc.h"
-+
-+#define LZMA_BEST_LEVEL (9)
-+#define LZMA_BEST_LC (0)
-+#define LZMA_BEST_LP (0)
-+#define LZMA_BEST_PB (0)
-+#define LZMA_BEST_FB (273)
-+
-+#define LZMA_BEST_DICT(n) (((int)((n) / 2)) * 2)
-+
-+static void *p_lzma_malloc(void *p, size_t size)
-+{
-+ if (size == 0)
-+ return NULL;
-+
-+ return LZMA_MALLOC(size);
-+}
-+
-+static void p_lzma_free(void *p, void *address)
-+{
-+ if (address != NULL)
-+ LZMA_FREE(address);
-+}
-+
-+static ISzAlloc lzma_alloc = { .Alloc = p_lzma_malloc, .Free = p_lzma_free };
-+
-+#endif
---- /dev/null
-+++ b/include/linux/lzma/LzFind.h
-@@ -0,0 +1,115 @@
-+/* LzFind.h -- Match finder for LZ algorithms
-+2009-04-22 : Igor Pavlov : Public domain */
-+
-+#ifndef __LZ_FIND_H
-+#define __LZ_FIND_H
-+
-+#include "Types.h"
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+typedef UInt32 CLzRef;
-+
-+typedef struct _CMatchFinder
-+{
-+ Byte *buffer;
-+ UInt32 pos;
-+ UInt32 posLimit;
-+ UInt32 streamPos;
-+ UInt32 lenLimit;
-+
-+ UInt32 cyclicBufferPos;
-+ UInt32 cyclicBufferSize; /* it must be = (historySize + 1) */
-+
-+ UInt32 matchMaxLen;
-+ CLzRef *hash;
-+ CLzRef *son;
-+ UInt32 hashMask;
-+ UInt32 cutValue;
-+
-+ Byte *bufferBase;
-+ ISeqInStream *stream;
-+ int streamEndWasReached;
-+
-+ UInt32 blockSize;
-+ UInt32 keepSizeBefore;
-+ UInt32 keepSizeAfter;
-+
-+ UInt32 numHashBytes;
-+ int directInput;
-+ size_t directInputRem;
-+ int btMode;
-+ int bigHash;
-+ UInt32 historySize;
-+ UInt32 fixedHashSize;
-+ UInt32 hashSizeSum;
-+ UInt32 numSons;
-+ SRes result;
-+ UInt32 crc[256];
-+} CMatchFinder;
-+
-+#define Inline_MatchFinder_GetPointerToCurrentPos(p) ((p)->buffer)
-+#define Inline_MatchFinder_GetIndexByte(p, index) ((p)->buffer[(Int32)(index)])
-+
-+#define Inline_MatchFinder_GetNumAvailableBytes(p) ((p)->streamPos - (p)->pos)
-+
-+int MatchFinder_NeedMove(CMatchFinder *p);
-+Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p);
-+void MatchFinder_MoveBlock(CMatchFinder *p);
-+void MatchFinder_ReadIfRequired(CMatchFinder *p);
-+
-+void MatchFinder_Construct(CMatchFinder *p);
-+
-+/* Conditions:
-+ historySize <= 3 GB
-+ keepAddBufferBefore + matchMaxLen + keepAddBufferAfter < 511MB
-+*/
-+int MatchFinder_Create(CMatchFinder *p, UInt32 historySize,
-+ UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter,
-+ ISzAlloc *alloc);
-+void MatchFinder_Free(CMatchFinder *p, ISzAlloc *alloc);
-+void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems);
-+void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue);
-+
-+UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *buffer, CLzRef *son,
-+ UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 _cutValue,
-+ UInt32 *distances, UInt32 maxLen);
-+
-+/*
-+Conditions:
-+ Mf_GetNumAvailableBytes_Func must be called before each Mf_GetMatchLen_Func.
-+ Mf_GetPointerToCurrentPos_Func's result must be used only before any other function
-+*/
-+
-+typedef void (*Mf_Init_Func)(void *object);
-+typedef Byte (*Mf_GetIndexByte_Func)(void *object, Int32 index);
-+typedef UInt32 (*Mf_GetNumAvailableBytes_Func)(void *object);
-+typedef const Byte * (*Mf_GetPointerToCurrentPos_Func)(void *object);
-+typedef UInt32 (*Mf_GetMatches_Func)(void *object, UInt32 *distances);
-+typedef void (*Mf_Skip_Func)(void *object, UInt32);
-+
-+typedef struct _IMatchFinder
-+{
-+ Mf_Init_Func Init;
-+ Mf_GetIndexByte_Func GetIndexByte;
-+ Mf_GetNumAvailableBytes_Func GetNumAvailableBytes;
-+ Mf_GetPointerToCurrentPos_Func GetPointerToCurrentPos;
-+ Mf_GetMatches_Func GetMatches;
-+ Mf_Skip_Func Skip;
-+} IMatchFinder;
-+
-+void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable);
-+
-+void MatchFinder_Init(CMatchFinder *p);
-+UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances);
-+UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances);
-+void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num);
-+void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num);
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif
---- /dev/null
-+++ b/include/linux/lzma/LzHash.h
-@@ -0,0 +1,54 @@
-+/* LzHash.h -- HASH functions for LZ algorithms
-+2009-02-07 : Igor Pavlov : Public domain */
-+
-+#ifndef __LZ_HASH_H
-+#define __LZ_HASH_H
-+
-+#define kHash2Size (1 << 10)
-+#define kHash3Size (1 << 16)
-+#define kHash4Size (1 << 20)
-+
-+#define kFix3HashSize (kHash2Size)
-+#define kFix4HashSize (kHash2Size + kHash3Size)
-+#define kFix5HashSize (kHash2Size + kHash3Size + kHash4Size)
-+
-+#define HASH2_CALC hashValue = cur[0] | ((UInt32)cur[1] << 8);
-+
-+#define HASH3_CALC { \
-+ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
-+ hash2Value = temp & (kHash2Size - 1); \
-+ hashValue = (temp ^ ((UInt32)cur[2] << 8)) & p->hashMask; }
-+
-+#define HASH4_CALC { \
-+ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
-+ hash2Value = temp & (kHash2Size - 1); \
-+ hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \
-+ hashValue = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)) & p->hashMask; }
-+
-+#define HASH5_CALC { \
-+ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
-+ hash2Value = temp & (kHash2Size - 1); \
-+ hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \
-+ hash4Value = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)); \
-+ hashValue = (hash4Value ^ (p->crc[cur[4]] << 3)) & p->hashMask; \
-+ hash4Value &= (kHash4Size - 1); }
-+
-+/* #define HASH_ZIP_CALC hashValue = ((cur[0] | ((UInt32)cur[1] << 8)) ^ p->crc[cur[2]]) & 0xFFFF; */
-+#define HASH_ZIP_CALC hashValue = ((cur[2] | ((UInt32)cur[0] << 8)) ^ p->crc[cur[1]]) & 0xFFFF;
-+
-+
-+#define MT_HASH2_CALC \
-+ hash2Value = (p->crc[cur[0]] ^ cur[1]) & (kHash2Size - 1);
-+
-+#define MT_HASH3_CALC { \
-+ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
-+ hash2Value = temp & (kHash2Size - 1); \
-+ hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); }
-+
-+#define MT_HASH4_CALC { \
-+ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
-+ hash2Value = temp & (kHash2Size - 1); \
-+ hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \
-+ hash4Value = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)) & (kHash4Size - 1); }
-+
-+#endif
---- /dev/null
-+++ b/include/linux/lzma/LzmaDec.h
-@@ -0,0 +1,231 @@
-+/* LzmaDec.h -- LZMA Decoder
-+2009-02-07 : Igor Pavlov : Public domain */
-+
-+#ifndef __LZMA_DEC_H
-+#define __LZMA_DEC_H
-+
-+#include "Types.h"
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+/* #define _LZMA_PROB32 */
-+/* _LZMA_PROB32 can increase the speed on some CPUs,
-+ but memory usage for CLzmaDec::probs will be doubled in that case */
-+
-+#ifdef _LZMA_PROB32
-+#define CLzmaProb UInt32
-+#else
-+#define CLzmaProb UInt16
-+#endif
-+
-+
-+/* ---------- LZMA Properties ---------- */
-+
-+#define LZMA_PROPS_SIZE 5
-+
-+typedef struct _CLzmaProps
-+{
-+ unsigned lc, lp, pb;
-+ UInt32 dicSize;
-+} CLzmaProps;
-+
-+/* LzmaProps_Decode - decodes properties
-+Returns:
-+ SZ_OK
-+ SZ_ERROR_UNSUPPORTED - Unsupported properties
-+*/
-+
-+SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size);
-+
-+
-+/* ---------- LZMA Decoder state ---------- */
-+
-+/* LZMA_REQUIRED_INPUT_MAX = number of required input bytes for worst case.
-+ Num bits = log2((2^11 / 31) ^ 22) + 26 < 134 + 26 = 160; */
-+
-+#define LZMA_REQUIRED_INPUT_MAX 20
-+
-+typedef struct
-+{
-+ CLzmaProps prop;
-+ CLzmaProb *probs;
-+ Byte *dic;
-+ const Byte *buf;
-+ UInt32 range, code;
-+ SizeT dicPos;
-+ SizeT dicBufSize;
-+ UInt32 processedPos;
-+ UInt32 checkDicSize;
-+ unsigned state;
-+ UInt32 reps[4];
-+ unsigned remainLen;
-+ int needFlush;
-+ int needInitState;
-+ UInt32 numProbs;
-+ unsigned tempBufSize;
-+ Byte tempBuf[LZMA_REQUIRED_INPUT_MAX];
-+} CLzmaDec;
-+
-+#define LzmaDec_Construct(p) { (p)->dic = 0; (p)->probs = 0; }
-+
-+void LzmaDec_Init(CLzmaDec *p);
-+
-+/* There are two types of LZMA streams:
-+ 0) Stream with end mark. That end mark adds about 6 bytes to compressed size.
-+ 1) Stream without end mark. You must know exact uncompressed size to decompress such stream. */
-+
-+typedef enum
-+{
-+ LZMA_FINISH_ANY, /* finish at any point */
-+ LZMA_FINISH_END /* block must be finished at the end */
-+} ELzmaFinishMode;
-+
-+/* ELzmaFinishMode has meaning only if the decoding reaches output limit !!!
-+
-+ You must use LZMA_FINISH_END, when you know that current output buffer
-+ covers last bytes of block. In other cases you must use LZMA_FINISH_ANY.
-+
-+ If LZMA decoder sees end marker before reaching output limit, it returns SZ_OK,
-+ and output value of destLen will be less than output buffer size limit.
-+ You can check status result also.
-+
-+ You can use multiple checks to test data integrity after full decompression:
-+ 1) Check Result and "status" variable.
-+ 2) Check that output(destLen) = uncompressedSize, if you know real uncompressedSize.
-+ 3) Check that output(srcLen) = compressedSize, if you know real compressedSize.
-+ You must use correct finish mode in that case. */
-+
-+typedef enum
-+{
-+ LZMA_STATUS_NOT_SPECIFIED, /* use main error code instead */
-+ LZMA_STATUS_FINISHED_WITH_MARK, /* stream was finished with end mark. */
-+ LZMA_STATUS_NOT_FINISHED, /* stream was not finished */
-+ LZMA_STATUS_NEEDS_MORE_INPUT, /* you must provide more input bytes */
-+ LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK /* there is probability that stream was finished without end mark */
-+} ELzmaStatus;
-+
-+/* ELzmaStatus is used only as output value for function call */
-+
-+
-+/* ---------- Interfaces ---------- */
-+
-+/* There are 3 levels of interfaces:
-+ 1) Dictionary Interface
-+ 2) Buffer Interface
-+ 3) One Call Interface
-+ You can select any of these interfaces, but don't mix functions from different
-+ groups for same object. */
-+
-+
-+/* There are two variants to allocate state for Dictionary Interface:
-+ 1) LzmaDec_Allocate / LzmaDec_Free
-+ 2) LzmaDec_AllocateProbs / LzmaDec_FreeProbs
-+ You can use variant 2, if you set dictionary buffer manually.
-+ For Buffer Interface you must always use variant 1.
-+
-+LzmaDec_Allocate* can return:
-+ SZ_OK
-+ SZ_ERROR_MEM - Memory allocation error
-+ SZ_ERROR_UNSUPPORTED - Unsupported properties
-+*/
-+
-+SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc);
-+void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc);
-+
-+SRes LzmaDec_Allocate(CLzmaDec *state, const Byte *prop, unsigned propsSize, ISzAlloc *alloc);
-+void LzmaDec_Free(CLzmaDec *state, ISzAlloc *alloc);
-+
-+/* ---------- Dictionary Interface ---------- */
-+
-+/* You can use it, if you want to eliminate the overhead for data copying from
-+ dictionary to some other external buffer.
-+ You must work with CLzmaDec variables directly in this interface.
-+
-+ STEPS:
-+ LzmaDec_Constr()
-+ LzmaDec_Allocate()
-+ for (each new stream)
-+ {
-+ LzmaDec_Init()
-+ while (it needs more decompression)
-+ {
-+ LzmaDec_DecodeToDic()
-+ use data from CLzmaDec::dic and update CLzmaDec::dicPos
-+ }
-+ }
-+ LzmaDec_Free()
-+*/
-+
-+/* LzmaDec_DecodeToDic
-+
-+ The decoding to internal dictionary buffer (CLzmaDec::dic).
-+ You must manually update CLzmaDec::dicPos, if it reaches CLzmaDec::dicBufSize !!!
-+
-+finishMode:
-+ It has meaning only if the decoding reaches output limit (dicLimit).
-+ LZMA_FINISH_ANY - Decode just dicLimit bytes.
-+ LZMA_FINISH_END - Stream must be finished after dicLimit.
-+
-+Returns:
-+ SZ_OK
-+ status:
-+ LZMA_STATUS_FINISHED_WITH_MARK
-+ LZMA_STATUS_NOT_FINISHED
-+ LZMA_STATUS_NEEDS_MORE_INPUT
-+ LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK
-+ SZ_ERROR_DATA - Data error
-+*/
-+
-+SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit,
-+ const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status);
-+
-+
-+/* ---------- Buffer Interface ---------- */
-+
-+/* It's zlib-like interface.
-+ See LzmaDec_DecodeToDic description for information about STEPS and return results,
-+ but you must use LzmaDec_DecodeToBuf instead of LzmaDec_DecodeToDic and you don't need
-+ to work with CLzmaDec variables manually.
-+
-+finishMode:
-+ It has meaning only if the decoding reaches output limit (*destLen).
-+ LZMA_FINISH_ANY - Decode just destLen bytes.
-+ LZMA_FINISH_END - Stream must be finished after (*destLen).
-+*/
-+
-+SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen,
-+ const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status);
-+
-+
-+/* ---------- One Call Interface ---------- */
-+
-+/* LzmaDecode
-+
-+finishMode:
-+ It has meaning only if the decoding reaches output limit (*destLen).
-+ LZMA_FINISH_ANY - Decode just destLen bytes.
-+ LZMA_FINISH_END - Stream must be finished after (*destLen).
-+
-+Returns:
-+ SZ_OK
-+ status:
-+ LZMA_STATUS_FINISHED_WITH_MARK
-+ LZMA_STATUS_NOT_FINISHED
-+ LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK
-+ SZ_ERROR_DATA - Data error
-+ SZ_ERROR_MEM - Memory allocation error
-+ SZ_ERROR_UNSUPPORTED - Unsupported properties
-+ SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src).
-+*/
-+
-+SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
-+ const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode,
-+ ELzmaStatus *status, ISzAlloc *alloc);
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif
---- /dev/null
-+++ b/include/linux/lzma/LzmaEnc.h
-@@ -0,0 +1,80 @@
-+/* LzmaEnc.h -- LZMA Encoder
-+2009-02-07 : Igor Pavlov : Public domain */
-+
-+#ifndef __LZMA_ENC_H
-+#define __LZMA_ENC_H
-+
-+#include "Types.h"
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#define LZMA_PROPS_SIZE 5
-+
-+typedef struct _CLzmaEncProps
-+{
-+ int level; /* 0 <= level <= 9 */
-+ UInt32 dictSize; /* (1 << 12) <= dictSize <= (1 << 27) for 32-bit version
-+ (1 << 12) <= dictSize <= (1 << 30) for 64-bit version
-+ default = (1 << 24) */
-+ int lc; /* 0 <= lc <= 8, default = 3 */
-+ int lp; /* 0 <= lp <= 4, default = 0 */
-+ int pb; /* 0 <= pb <= 4, default = 2 */
-+ int algo; /* 0 - fast, 1 - normal, default = 1 */
-+ int fb; /* 5 <= fb <= 273, default = 32 */
-+ int btMode; /* 0 - hashChain Mode, 1 - binTree mode - normal, default = 1 */
-+ int numHashBytes; /* 2, 3 or 4, default = 4 */
-+ UInt32 mc; /* 1 <= mc <= (1 << 30), default = 32 */
-+ unsigned writeEndMark; /* 0 - do not write EOPM, 1 - write EOPM, default = 0 */
-+ int numThreads; /* 1 or 2, default = 2 */
-+} CLzmaEncProps;
-+
-+void LzmaEncProps_Init(CLzmaEncProps *p);
-+void LzmaEncProps_Normalize(CLzmaEncProps *p);
-+UInt32 LzmaEncProps_GetDictSize(const CLzmaEncProps *props2);
-+
-+
-+/* ---------- CLzmaEncHandle Interface ---------- */
-+
-+/* LzmaEnc_* functions can return the following exit codes:
-+Returns:
-+ SZ_OK - OK
-+ SZ_ERROR_MEM - Memory allocation error
-+ SZ_ERROR_PARAM - Incorrect paramater in props
-+ SZ_ERROR_WRITE - Write callback error.
-+ SZ_ERROR_PROGRESS - some break from progress callback
-+ SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version)
-+*/
-+
-+typedef void * CLzmaEncHandle;
-+
-+CLzmaEncHandle LzmaEnc_Create(ISzAlloc *alloc);
-+void LzmaEnc_Destroy(CLzmaEncHandle p, ISzAlloc *alloc, ISzAlloc *allocBig);
-+SRes LzmaEnc_SetProps(CLzmaEncHandle p, const CLzmaEncProps *props);
-+SRes LzmaEnc_WriteProperties(CLzmaEncHandle p, Byte *properties, SizeT *size);
-+SRes LzmaEnc_Encode(CLzmaEncHandle p, ISeqOutStream *outStream, ISeqInStream *inStream,
-+ ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig);
-+SRes LzmaEnc_MemEncode(CLzmaEncHandle p, Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
-+ int writeEndMark, ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig);
-+
-+/* ---------- One Call Interface ---------- */
-+
-+/* LzmaEncode
-+Return code:
-+ SZ_OK - OK
-+ SZ_ERROR_MEM - Memory allocation error
-+ SZ_ERROR_PARAM - Incorrect paramater
-+ SZ_ERROR_OUTPUT_EOF - output buffer overflow
-+ SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version)
-+*/
-+
-+SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
-+ const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark,
-+ ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig);
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif
---- /dev/null
-+++ b/include/linux/lzma/Types.h
-@@ -0,0 +1,226 @@
-+/* Types.h -- Basic types
-+2009-11-23 : Igor Pavlov : Public domain */
-+
-+#ifndef __7Z_TYPES_H
-+#define __7Z_TYPES_H
-+
-+#include <stddef.h>
-+
-+#ifdef _WIN32
-+#include <windows.h>
-+#endif
-+
-+#ifndef EXTERN_C_BEGIN
-+#ifdef __cplusplus
-+#define EXTERN_C_BEGIN extern "C" {
-+#define EXTERN_C_END }
-+#else
-+#define EXTERN_C_BEGIN
-+#define EXTERN_C_END
-+#endif
-+#endif
-+
-+EXTERN_C_BEGIN
-+
-+#define SZ_OK 0
-+
-+#define SZ_ERROR_DATA 1
-+#define SZ_ERROR_MEM 2
-+#define SZ_ERROR_CRC 3
-+#define SZ_ERROR_UNSUPPORTED 4
-+#define SZ_ERROR_PARAM 5
-+#define SZ_ERROR_INPUT_EOF 6
-+#define SZ_ERROR_OUTPUT_EOF 7
-+#define SZ_ERROR_READ 8
-+#define SZ_ERROR_WRITE 9
-+#define SZ_ERROR_PROGRESS 10
-+#define SZ_ERROR_FAIL 11
-+#define SZ_ERROR_THREAD 12
-+
-+#define SZ_ERROR_ARCHIVE 16
-+#define SZ_ERROR_NO_ARCHIVE 17
-+
-+typedef int SRes;
-+
-+#ifdef _WIN32
-+typedef DWORD WRes;
-+#else
-+typedef int WRes;
-+#endif
-+
-+#ifndef RINOK
-+#define RINOK(x) { int __result__ = (x); if (__result__ != 0) return __result__; }
-+#endif
-+
-+typedef unsigned char Byte;
-+typedef short Int16;
-+typedef unsigned short UInt16;
-+
-+#ifdef _LZMA_UINT32_IS_ULONG
-+typedef long Int32;
-+typedef unsigned long UInt32;
-+#else
-+typedef int Int32;
-+typedef unsigned int UInt32;
-+#endif
-+
-+#ifdef _SZ_NO_INT_64
-+
-+/* define _SZ_NO_INT_64, if your compiler doesn't support 64-bit integers.
-+ NOTES: Some code will work incorrectly in that case! */
-+
-+typedef long Int64;
-+typedef unsigned long UInt64;
-+
-+#else
-+
-+#if defined(_MSC_VER) || defined(__BORLANDC__)
-+typedef __int64 Int64;
-+typedef unsigned __int64 UInt64;
-+#else
-+typedef long long int Int64;
-+typedef unsigned long long int UInt64;
-+#endif
-+
-+#endif
-+
-+#ifdef _LZMA_NO_SYSTEM_SIZE_T
-+typedef UInt32 SizeT;
-+#else
-+typedef size_t SizeT;
-+#endif
-+
-+typedef int Bool;
-+#define True 1
-+#define False 0
-+
-+
-+#ifdef _WIN32
-+#define MY_STD_CALL __stdcall
-+#else
-+#define MY_STD_CALL
-+#endif
-+
-+#ifdef _MSC_VER
-+
-+#if _MSC_VER >= 1300
-+#define MY_NO_INLINE __declspec(noinline)
-+#else
-+#define MY_NO_INLINE
-+#endif
-+
-+#define MY_CDECL __cdecl
-+#define MY_FAST_CALL __fastcall
-+
-+#else
-+
-+#define MY_CDECL
-+#define MY_FAST_CALL
-+
-+#endif
-+
-+
-+/* The following interfaces use first parameter as pointer to structure */
-+
-+typedef struct
-+{
-+ SRes (*Read)(void *p, void *buf, size_t *size);
-+ /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream.
-+ (output(*size) < input(*size)) is allowed */
-+} ISeqInStream;
-+
-+/* it can return SZ_ERROR_INPUT_EOF */
-+SRes SeqInStream_Read(ISeqInStream *stream, void *buf, size_t size);
-+SRes SeqInStream_Read2(ISeqInStream *stream, void *buf, size_t size, SRes errorType);
-+SRes SeqInStream_ReadByte(ISeqInStream *stream, Byte *buf);
-+
-+typedef struct
-+{
-+ size_t (*Write)(void *p, const void *buf, size_t size);
-+ /* Returns: result - the number of actually written bytes.
-+ (result < size) means error */
-+} ISeqOutStream;
-+
-+typedef enum
-+{
-+ SZ_SEEK_SET = 0,
-+ SZ_SEEK_CUR = 1,
-+ SZ_SEEK_END = 2
-+} ESzSeek;
-+
-+typedef struct
-+{
-+ SRes (*Read)(void *p, void *buf, size_t *size); /* same as ISeqInStream::Read */
-+ SRes (*Seek)(void *p, Int64 *pos, ESzSeek origin);
-+} ISeekInStream;
-+
-+typedef struct
-+{
-+ SRes (*Look)(void *p, void **buf, size_t *size);
-+ /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream.
-+ (output(*size) > input(*size)) is not allowed
-+ (output(*size) < input(*size)) is allowed */
-+ SRes (*Skip)(void *p, size_t offset);
-+ /* offset must be <= output(*size) of Look */
-+
-+ SRes (*Read)(void *p, void *buf, size_t *size);
-+ /* reads directly (without buffer). It's same as ISeqInStream::Read */
-+ SRes (*Seek)(void *p, Int64 *pos, ESzSeek origin);
-+} ILookInStream;
-+
-+SRes LookInStream_LookRead(ILookInStream *stream, void *buf, size_t *size);
-+SRes LookInStream_SeekTo(ILookInStream *stream, UInt64 offset);
-+
-+/* reads via ILookInStream::Read */
-+SRes LookInStream_Read2(ILookInStream *stream, void *buf, size_t size, SRes errorType);
-+SRes LookInStream_Read(ILookInStream *stream, void *buf, size_t size);
-+
-+#define LookToRead_BUF_SIZE (1 << 14)
-+
-+typedef struct
-+{
-+ ILookInStream s;
-+ ISeekInStream *realStream;
-+ size_t pos;
-+ size_t size;
-+ Byte buf[LookToRead_BUF_SIZE];
-+} CLookToRead;
-+
-+void LookToRead_CreateVTable(CLookToRead *p, int lookahead);
-+void LookToRead_Init(CLookToRead *p);
-+
-+typedef struct
-+{
-+ ISeqInStream s;
-+ ILookInStream *realStream;
-+} CSecToLook;
-+
-+void SecToLook_CreateVTable(CSecToLook *p);
-+
-+typedef struct
-+{
-+ ISeqInStream s;
-+ ILookInStream *realStream;
-+} CSecToRead;
-+
-+void SecToRead_CreateVTable(CSecToRead *p);
-+
-+typedef struct
-+{
-+ SRes (*Progress)(void *p, UInt64 inSize, UInt64 outSize);
-+ /* Returns: result. (result != SZ_OK) means break.
-+ Value (UInt64)(Int64)-1 for size means unknown value. */
-+} ICompressProgress;
-+
-+typedef struct
-+{
-+ void *(*Alloc)(void *p, size_t size);
-+ void (*Free)(void *p, void *address); /* address can be 0 */
-+} ISzAlloc;
-+
-+#define IAlloc_Alloc(p, size) (p)->Alloc((p), size)
-+#define IAlloc_Free(p, a) (p)->Free((p), a)
-+
-+EXTERN_C_END
-+
-+#endif
---- a/include/uapi/linux/jffs2.h
-+++ b/include/uapi/linux/jffs2.h
-@@ -46,6 +46,7 @@
- #define JFFS2_COMPR_DYNRUBIN 0x05
- #define JFFS2_COMPR_ZLIB 0x06
- #define JFFS2_COMPR_LZO 0x07
-+#define JFFS2_COMPR_LZMA 0x08
- /* Compatibility flags. */
- #define JFFS2_COMPAT_MASK 0xc000 /* What do to if an unknown nodetype is found */
- #define JFFS2_NODE_ACCURATE 0x2000
---- a/lib/Kconfig
-+++ b/lib/Kconfig
-@@ -356,6 +356,12 @@ config ZSTD_DECOMPRESS
-
- source "lib/xz/Kconfig"
-
-+config LZMA_COMPRESS
-+ tristate
-+
-+config LZMA_DECOMPRESS
-+ tristate
-+
- #
- # These all provide a common interface (hence the apparent duplication with
- # ZLIB_INFLATE; DECOMPRESS_GZIP is just a wrapper.)
---- a/lib/Makefile
-+++ b/lib/Makefile
-@@ -145,6 +145,16 @@ CFLAGS_kobject.o += -DDEBUG
- CFLAGS_kobject_uevent.o += -DDEBUG
- endif
-
-+ifdef CONFIG_JFFS2_ZLIB
-+ CONFIG_ZLIB_INFLATE:=y
-+ CONFIG_ZLIB_DEFLATE:=y
-+endif
-+
-+ifdef CONFIG_JFFS2_LZMA
-+ CONFIG_LZMA_DECOMPRESS:=y
-+ CONFIG_LZMA_COMPRESS:=y
-+endif
-+
- obj-$(CONFIG_DEBUG_INFO_REDUCED) += debug_info.o
- CFLAGS_debug_info.o += $(call cc-option, -femit-struct-debug-detailed=any)
-
-@@ -205,6 +215,8 @@ obj-$(CONFIG_ZSTD_COMPRESS) += zstd/
- obj-$(CONFIG_ZSTD_DECOMPRESS) += zstd/
- obj-$(CONFIG_XZ_DEC) += xz/
- obj-$(CONFIG_RAID6_PQ) += raid6/
-+obj-$(CONFIG_LZMA_COMPRESS) += lzma/
-+obj-$(CONFIG_LZMA_DECOMPRESS) += lzma/
-
- lib-$(CONFIG_DECOMPRESS_GZIP) += decompress_inflate.o
- lib-$(CONFIG_DECOMPRESS_BZIP2) += decompress_bunzip2.o
---- /dev/null
-+++ b/lib/lzma/LzFind.c
-@@ -0,0 +1,761 @@
-+/* LzFind.c -- Match finder for LZ algorithms
-+2009-04-22 : Igor Pavlov : Public domain */
-+
-+#include <string.h>
-+
-+#include "LzFind.h"
-+#include "LzHash.h"
-+
-+#define kEmptyHashValue 0
-+#define kMaxValForNormalize ((UInt32)0xFFFFFFFF)
-+#define kNormalizeStepMin (1 << 10) /* it must be power of 2 */
-+#define kNormalizeMask (~(kNormalizeStepMin - 1))
-+#define kMaxHistorySize ((UInt32)3 << 30)
-+
-+#define kStartMaxLen 3
-+
-+static void LzInWindow_Free(CMatchFinder *p, ISzAlloc *alloc)
-+{
-+ if (!p->directInput)
-+ {
-+ alloc->Free(alloc, p->bufferBase);
-+ p->bufferBase = 0;
-+ }
-+}
-+
-+/* keepSizeBefore + keepSizeAfter + keepSizeReserv must be < 4G) */
-+
-+static int LzInWindow_Create(CMatchFinder *p, UInt32 keepSizeReserv, ISzAlloc *alloc)
-+{
-+ UInt32 blockSize = p->keepSizeBefore + p->keepSizeAfter + keepSizeReserv;
-+ if (p->directInput)
-+ {
-+ p->blockSize = blockSize;
-+ return 1;
-+ }
-+ if (p->bufferBase == 0 || p->blockSize != blockSize)
-+ {
-+ LzInWindow_Free(p, alloc);
-+ p->blockSize = blockSize;
-+ p->bufferBase = (Byte *)alloc->Alloc(alloc, (size_t)blockSize);
-+ }
-+ return (p->bufferBase != 0);
-+}
-+
-+Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p) { return p->buffer; }
-+Byte MatchFinder_GetIndexByte(CMatchFinder *p, Int32 index) { return p->buffer[index]; }
-+
-+UInt32 MatchFinder_GetNumAvailableBytes(CMatchFinder *p) { return p->streamPos - p->pos; }
-+
-+void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue)
-+{
-+ p->posLimit -= subValue;
-+ p->pos -= subValue;
-+ p->streamPos -= subValue;
-+}
-+
-+static void MatchFinder_ReadBlock(CMatchFinder *p)
-+{
-+ if (p->streamEndWasReached || p->result != SZ_OK)
-+ return;
-+ if (p->directInput)
-+ {
-+ UInt32 curSize = 0xFFFFFFFF - p->streamPos;
-+ if (curSize > p->directInputRem)
-+ curSize = (UInt32)p->directInputRem;
-+ p->directInputRem -= curSize;
-+ p->streamPos += curSize;
-+ if (p->directInputRem == 0)
-+ p->streamEndWasReached = 1;
-+ return;
-+ }
-+ for (;;)
-+ {
-+ Byte *dest = p->buffer + (p->streamPos - p->pos);
-+ size_t size = (p->bufferBase + p->blockSize - dest);
-+ if (size == 0)
-+ return;
-+ p->result = p->stream->Read(p->stream, dest, &size);
-+ if (p->result != SZ_OK)
-+ return;
-+ if (size == 0)
-+ {
-+ p->streamEndWasReached = 1;
-+ return;
-+ }
-+ p->streamPos += (UInt32)size;
-+ if (p->streamPos - p->pos > p->keepSizeAfter)
-+ return;
-+ }
-+}
-+
-+void MatchFinder_MoveBlock(CMatchFinder *p)
-+{
-+ memmove(p->bufferBase,
-+ p->buffer - p->keepSizeBefore,
-+ (size_t)(p->streamPos - p->pos + p->keepSizeBefore));
-+ p->buffer = p->bufferBase + p->keepSizeBefore;
-+}
-+
-+int MatchFinder_NeedMove(CMatchFinder *p)
-+{
-+ if (p->directInput)
-+ return 0;
-+ /* if (p->streamEndWasReached) return 0; */
-+ return ((size_t)(p->bufferBase + p->blockSize - p->buffer) <= p->keepSizeAfter);
-+}
-+
-+void MatchFinder_ReadIfRequired(CMatchFinder *p)
-+{
-+ if (p->streamEndWasReached)
-+ return;
-+ if (p->keepSizeAfter >= p->streamPos - p->pos)
-+ MatchFinder_ReadBlock(p);
-+}
-+
-+static void MatchFinder_CheckAndMoveAndRead(CMatchFinder *p)
-+{
-+ if (MatchFinder_NeedMove(p))
-+ MatchFinder_MoveBlock(p);
-+ MatchFinder_ReadBlock(p);
-+}
-+
-+static void MatchFinder_SetDefaultSettings(CMatchFinder *p)
-+{
-+ p->cutValue = 32;
-+ p->btMode = 1;
-+ p->numHashBytes = 4;
-+ p->bigHash = 0;
-+}
-+
-+#define kCrcPoly 0xEDB88320
-+
-+void MatchFinder_Construct(CMatchFinder *p)
-+{
-+ UInt32 i;
-+ p->bufferBase = 0;
-+ p->directInput = 0;
-+ p->hash = 0;
-+ MatchFinder_SetDefaultSettings(p);
-+
-+ for (i = 0; i < 256; i++)
-+ {
-+ UInt32 r = i;
-+ int j;
-+ for (j = 0; j < 8; j++)
-+ r = (r >> 1) ^ (kCrcPoly & ~((r & 1) - 1));
-+ p->crc[i] = r;
-+ }
-+}
-+
-+static void MatchFinder_FreeThisClassMemory(CMatchFinder *p, ISzAlloc *alloc)
-+{
-+ alloc->Free(alloc, p->hash);
-+ p->hash = 0;
-+}
-+
-+void MatchFinder_Free(CMatchFinder *p, ISzAlloc *alloc)
-+{
-+ MatchFinder_FreeThisClassMemory(p, alloc);
-+ LzInWindow_Free(p, alloc);
-+}
-+
-+static CLzRef* AllocRefs(UInt32 num, ISzAlloc *alloc)
-+{
-+ size_t sizeInBytes = (size_t)num * sizeof(CLzRef);
-+ if (sizeInBytes / sizeof(CLzRef) != num)
-+ return 0;
-+ return (CLzRef *)alloc->Alloc(alloc, sizeInBytes);
-+}
-+
-+int MatchFinder_Create(CMatchFinder *p, UInt32 historySize,
-+ UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter,
-+ ISzAlloc *alloc)
-+{
-+ UInt32 sizeReserv;
-+ if (historySize > kMaxHistorySize)
-+ {
-+ MatchFinder_Free(p, alloc);
-+ return 0;
-+ }
-+ sizeReserv = historySize >> 1;
-+ if (historySize > ((UInt32)2 << 30))
-+ sizeReserv = historySize >> 2;
-+ sizeReserv += (keepAddBufferBefore + matchMaxLen + keepAddBufferAfter) / 2 + (1 << 19);
-+
-+ p->keepSizeBefore = historySize + keepAddBufferBefore + 1;
-+ p->keepSizeAfter = matchMaxLen + keepAddBufferAfter;
-+ /* we need one additional byte, since we use MoveBlock after pos++ and before dictionary using */
-+ if (LzInWindow_Create(p, sizeReserv, alloc))
-+ {
-+ UInt32 newCyclicBufferSize = historySize + 1;
-+ UInt32 hs;
-+ p->matchMaxLen = matchMaxLen;
-+ {
-+ p->fixedHashSize = 0;
-+ if (p->numHashBytes == 2)
-+ hs = (1 << 16) - 1;
-+ else
-+ {
-+ hs = historySize - 1;
-+ hs |= (hs >> 1);
-+ hs |= (hs >> 2);
-+ hs |= (hs >> 4);
-+ hs |= (hs >> 8);
-+ hs >>= 1;
-+ hs |= 0xFFFF; /* don't change it! It's required for Deflate */
-+ if (hs > (1 << 24))
-+ {
-+ if (p->numHashBytes == 3)
-+ hs = (1 << 24) - 1;
-+ else
-+ hs >>= 1;
-+ }
-+ }
-+ p->hashMask = hs;
-+ hs++;
-+ if (p->numHashBytes > 2) p->fixedHashSize += kHash2Size;
-+ if (p->numHashBytes > 3) p->fixedHashSize += kHash3Size;
-+ if (p->numHashBytes > 4) p->fixedHashSize += kHash4Size;
-+ hs += p->fixedHashSize;
-+ }
-+
-+ {
-+ UInt32 prevSize = p->hashSizeSum + p->numSons;
-+ UInt32 newSize;
-+ p->historySize = historySize;
-+ p->hashSizeSum = hs;
-+ p->cyclicBufferSize = newCyclicBufferSize;
-+ p->numSons = (p->btMode ? newCyclicBufferSize * 2 : newCyclicBufferSize);
-+ newSize = p->hashSizeSum + p->numSons;
-+ if (p->hash != 0 && prevSize == newSize)
-+ return 1;
-+ MatchFinder_FreeThisClassMemory(p, alloc);
-+ p->hash = AllocRefs(newSize, alloc);
-+ if (p->hash != 0)
-+ {
-+ p->son = p->hash + p->hashSizeSum;
-+ return 1;
-+ }
-+ }
-+ }
-+ MatchFinder_Free(p, alloc);
-+ return 0;
-+}
-+
-+static void MatchFinder_SetLimits(CMatchFinder *p)
-+{
-+ UInt32 limit = kMaxValForNormalize - p->pos;
-+ UInt32 limit2 = p->cyclicBufferSize - p->cyclicBufferPos;
-+ if (limit2 < limit)
-+ limit = limit2;
-+ limit2 = p->streamPos - p->pos;
-+ if (limit2 <= p->keepSizeAfter)
-+ {
-+ if (limit2 > 0)
-+ limit2 = 1;
-+ }
-+ else
-+ limit2 -= p->keepSizeAfter;
-+ if (limit2 < limit)
-+ limit = limit2;
-+ {
-+ UInt32 lenLimit = p->streamPos - p->pos;
-+ if (lenLimit > p->matchMaxLen)
-+ lenLimit = p->matchMaxLen;
-+ p->lenLimit = lenLimit;
-+ }
-+ p->posLimit = p->pos + limit;
-+}
-+
-+void MatchFinder_Init(CMatchFinder *p)
-+{
-+ UInt32 i;
-+ for (i = 0; i < p->hashSizeSum; i++)
-+ p->hash[i] = kEmptyHashValue;
-+ p->cyclicBufferPos = 0;
-+ p->buffer = p->bufferBase;
-+ p->pos = p->streamPos = p->cyclicBufferSize;
-+ p->result = SZ_OK;
-+ p->streamEndWasReached = 0;
-+ MatchFinder_ReadBlock(p);
-+ MatchFinder_SetLimits(p);
-+}
-+
-+static UInt32 MatchFinder_GetSubValue(CMatchFinder *p)
-+{
-+ return (p->pos - p->historySize - 1) & kNormalizeMask;
-+}
-+
-+void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems)
-+{
-+ UInt32 i;
-+ for (i = 0; i < numItems; i++)
-+ {
-+ UInt32 value = items[i];
-+ if (value <= subValue)
-+ value = kEmptyHashValue;
-+ else
-+ value -= subValue;
-+ items[i] = value;
-+ }
-+}
-+
-+static void MatchFinder_Normalize(CMatchFinder *p)
-+{
-+ UInt32 subValue = MatchFinder_GetSubValue(p);
-+ MatchFinder_Normalize3(subValue, p->hash, p->hashSizeSum + p->numSons);
-+ MatchFinder_ReduceOffsets(p, subValue);
-+}
-+
-+static void MatchFinder_CheckLimits(CMatchFinder *p)
-+{
-+ if (p->pos == kMaxValForNormalize)
-+ MatchFinder_Normalize(p);
-+ if (!p->streamEndWasReached && p->keepSizeAfter == p->streamPos - p->pos)
-+ MatchFinder_CheckAndMoveAndRead(p);
-+ if (p->cyclicBufferPos == p->cyclicBufferSize)
-+ p->cyclicBufferPos = 0;
-+ MatchFinder_SetLimits(p);
-+}
-+
-+static UInt32 * Hc_GetMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son,
-+ UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue,
-+ UInt32 *distances, UInt32 maxLen)
-+{
-+ son[_cyclicBufferPos] = curMatch;
-+ for (;;)
-+ {
-+ UInt32 delta = pos - curMatch;
-+ if (cutValue-- == 0 || delta >= _cyclicBufferSize)
-+ return distances;
-+ {
-+ const Byte *pb = cur - delta;
-+ curMatch = son[_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)];
-+ if (pb[maxLen] == cur[maxLen] && *pb == *cur)
-+ {
-+ UInt32 len = 0;
-+ while (++len != lenLimit)
-+ if (pb[len] != cur[len])
-+ break;
-+ if (maxLen < len)
-+ {
-+ *distances++ = maxLen = len;
-+ *distances++ = delta - 1;
-+ if (len == lenLimit)
-+ return distances;
-+ }
-+ }
-+ }
-+ }
-+}
-+
-+UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son,
-+ UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue,
-+ UInt32 *distances, UInt32 maxLen)
-+{
-+ CLzRef *ptr0 = son + (_cyclicBufferPos << 1) + 1;
-+ CLzRef *ptr1 = son + (_cyclicBufferPos << 1);
-+ UInt32 len0 = 0, len1 = 0;
-+ for (;;)
-+ {
-+ UInt32 delta = pos - curMatch;
-+ if (cutValue-- == 0 || delta >= _cyclicBufferSize)
-+ {
-+ *ptr0 = *ptr1 = kEmptyHashValue;
-+ return distances;
-+ }
-+ {
-+ CLzRef *pair = son + ((_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1);
-+ const Byte *pb = cur - delta;
-+ UInt32 len = (len0 < len1 ? len0 : len1);
-+ if (pb[len] == cur[len])
-+ {
-+ if (++len != lenLimit && pb[len] == cur[len])
-+ while (++len != lenLimit)
-+ if (pb[len] != cur[len])
-+ break;
-+ if (maxLen < len)
-+ {
-+ *distances++ = maxLen = len;
-+ *distances++ = delta - 1;
-+ if (len == lenLimit)
-+ {
-+ *ptr1 = pair[0];
-+ *ptr0 = pair[1];
-+ return distances;
-+ }
-+ }
-+ }
-+ if (pb[len] < cur[len])
-+ {
-+ *ptr1 = curMatch;
-+ ptr1 = pair + 1;
-+ curMatch = *ptr1;
-+ len1 = len;
-+ }
-+ else
-+ {
-+ *ptr0 = curMatch;
-+ ptr0 = pair;
-+ curMatch = *ptr0;
-+ len0 = len;
-+ }
-+ }
-+ }
-+}
-+
-+static void SkipMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son,
-+ UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue)
-+{
-+ CLzRef *ptr0 = son + (_cyclicBufferPos << 1) + 1;
-+ CLzRef *ptr1 = son + (_cyclicBufferPos << 1);
-+ UInt32 len0 = 0, len1 = 0;
-+ for (;;)
-+ {
-+ UInt32 delta = pos - curMatch;
-+ if (cutValue-- == 0 || delta >= _cyclicBufferSize)
-+ {
-+ *ptr0 = *ptr1 = kEmptyHashValue;
-+ return;
-+ }
-+ {
-+ CLzRef *pair = son + ((_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1);
-+ const Byte *pb = cur - delta;
-+ UInt32 len = (len0 < len1 ? len0 : len1);
-+ if (pb[len] == cur[len])
-+ {
-+ while (++len != lenLimit)
-+ if (pb[len] != cur[len])
-+ break;
-+ {
-+ if (len == lenLimit)
-+ {
-+ *ptr1 = pair[0];
-+ *ptr0 = pair[1];
-+ return;
-+ }
-+ }
-+ }
-+ if (pb[len] < cur[len])
-+ {
-+ *ptr1 = curMatch;
-+ ptr1 = pair + 1;
-+ curMatch = *ptr1;
-+ len1 = len;
-+ }
-+ else
-+ {
-+ *ptr0 = curMatch;
-+ ptr0 = pair;
-+ curMatch = *ptr0;
-+ len0 = len;
-+ }
-+ }
-+ }
-+}
-+
-+#define MOVE_POS \
-+ ++p->cyclicBufferPos; \
-+ p->buffer++; \
-+ if (++p->pos == p->posLimit) MatchFinder_CheckLimits(p);
-+
-+#define MOVE_POS_RET MOVE_POS return offset;
-+
-+static void MatchFinder_MovePos(CMatchFinder *p) { MOVE_POS; }
-+
-+#define GET_MATCHES_HEADER2(minLen, ret_op) \
-+ UInt32 lenLimit; UInt32 hashValue; const Byte *cur; UInt32 curMatch; \
-+ lenLimit = p->lenLimit; { if (lenLimit < minLen) { MatchFinder_MovePos(p); ret_op; }} \
-+ cur = p->buffer;
-+
-+#define GET_MATCHES_HEADER(minLen) GET_MATCHES_HEADER2(minLen, return 0)
-+#define SKIP_HEADER(minLen) GET_MATCHES_HEADER2(minLen, continue)
-+
-+#define MF_PARAMS(p) p->pos, p->buffer, p->son, p->cyclicBufferPos, p->cyclicBufferSize, p->cutValue
-+
-+#define GET_MATCHES_FOOTER(offset, maxLen) \
-+ offset = (UInt32)(GetMatchesSpec1(lenLimit, curMatch, MF_PARAMS(p), \
-+ distances + offset, maxLen) - distances); MOVE_POS_RET;
-+
-+#define SKIP_FOOTER \
-+ SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); MOVE_POS;
-+
-+static UInt32 Bt2_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
-+{
-+ UInt32 offset;
-+ GET_MATCHES_HEADER(2)
-+ HASH2_CALC;
-+ curMatch = p->hash[hashValue];
-+ p->hash[hashValue] = p->pos;
-+ offset = 0;
-+ GET_MATCHES_FOOTER(offset, 1)
-+}
-+
-+UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
-+{
-+ UInt32 offset;
-+ GET_MATCHES_HEADER(3)
-+ HASH_ZIP_CALC;
-+ curMatch = p->hash[hashValue];
-+ p->hash[hashValue] = p->pos;
-+ offset = 0;
-+ GET_MATCHES_FOOTER(offset, 2)
-+}
-+
-+static UInt32 Bt3_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
-+{
-+ UInt32 hash2Value, delta2, maxLen, offset;
-+ GET_MATCHES_HEADER(3)
-+
-+ HASH3_CALC;
-+
-+ delta2 = p->pos - p->hash[hash2Value];
-+ curMatch = p->hash[kFix3HashSize + hashValue];
-+
-+ p->hash[hash2Value] =
-+ p->hash[kFix3HashSize + hashValue] = p->pos;
-+
-+
-+ maxLen = 2;
-+ offset = 0;
-+ if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur)
-+ {
-+ for (; maxLen != lenLimit; maxLen++)
-+ if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen])
-+ break;
-+ distances[0] = maxLen;
-+ distances[1] = delta2 - 1;
-+ offset = 2;
-+ if (maxLen == lenLimit)
-+ {
-+ SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p));
-+ MOVE_POS_RET;
-+ }
-+ }
-+ GET_MATCHES_FOOTER(offset, maxLen)
-+}
-+
-+static UInt32 Bt4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
-+{
-+ UInt32 hash2Value, hash3Value, delta2, delta3, maxLen, offset;
-+ GET_MATCHES_HEADER(4)
-+
-+ HASH4_CALC;
-+
-+ delta2 = p->pos - p->hash[ hash2Value];
-+ delta3 = p->pos - p->hash[kFix3HashSize + hash3Value];
-+ curMatch = p->hash[kFix4HashSize + hashValue];
-+
-+ p->hash[ hash2Value] =
-+ p->hash[kFix3HashSize + hash3Value] =
-+ p->hash[kFix4HashSize + hashValue] = p->pos;
-+
-+ maxLen = 1;
-+ offset = 0;
-+ if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur)
-+ {
-+ distances[0] = maxLen = 2;
-+ distances[1] = delta2 - 1;
-+ offset = 2;
-+ }
-+ if (delta2 != delta3 && delta3 < p->cyclicBufferSize && *(cur - delta3) == *cur)
-+ {
-+ maxLen = 3;
-+ distances[offset + 1] = delta3 - 1;
-+ offset += 2;
-+ delta2 = delta3;
-+ }
-+ if (offset != 0)
-+ {
-+ for (; maxLen != lenLimit; maxLen++)
-+ if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen])
-+ break;
-+ distances[offset - 2] = maxLen;
-+ if (maxLen == lenLimit)
-+ {
-+ SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p));
-+ MOVE_POS_RET;
-+ }
-+ }
-+ if (maxLen < 3)
-+ maxLen = 3;
-+ GET_MATCHES_FOOTER(offset, maxLen)
-+}
-+
-+static UInt32 Hc4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
-+{
-+ UInt32 hash2Value, hash3Value, delta2, delta3, maxLen, offset;
-+ GET_MATCHES_HEADER(4)
-+
-+ HASH4_CALC;
-+
-+ delta2 = p->pos - p->hash[ hash2Value];
-+ delta3 = p->pos - p->hash[kFix3HashSize + hash3Value];
-+ curMatch = p->hash[kFix4HashSize + hashValue];
-+
-+ p->hash[ hash2Value] =
-+ p->hash[kFix3HashSize + hash3Value] =
-+ p->hash[kFix4HashSize + hashValue] = p->pos;
-+
-+ maxLen = 1;
-+ offset = 0;
-+ if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur)
-+ {
-+ distances[0] = maxLen = 2;
-+ distances[1] = delta2 - 1;
-+ offset = 2;
-+ }
-+ if (delta2 != delta3 && delta3 < p->cyclicBufferSize && *(cur - delta3) == *cur)
-+ {
-+ maxLen = 3;
-+ distances[offset + 1] = delta3 - 1;
-+ offset += 2;
-+ delta2 = delta3;
-+ }
-+ if (offset != 0)
-+ {
-+ for (; maxLen != lenLimit; maxLen++)
-+ if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen])
-+ break;
-+ distances[offset - 2] = maxLen;
-+ if (maxLen == lenLimit)
-+ {
-+ p->son[p->cyclicBufferPos] = curMatch;
-+ MOVE_POS_RET;
-+ }
-+ }
-+ if (maxLen < 3)
-+ maxLen = 3;
-+ offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p),
-+ distances + offset, maxLen) - (distances));
-+ MOVE_POS_RET
-+}
-+
-+UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
-+{
-+ UInt32 offset;
-+ GET_MATCHES_HEADER(3)
-+ HASH_ZIP_CALC;
-+ curMatch = p->hash[hashValue];
-+ p->hash[hashValue] = p->pos;
-+ offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p),
-+ distances, 2) - (distances));
-+ MOVE_POS_RET
-+}
-+
-+static void Bt2_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
-+{
-+ do
-+ {
-+ SKIP_HEADER(2)
-+ HASH2_CALC;
-+ curMatch = p->hash[hashValue];
-+ p->hash[hashValue] = p->pos;
-+ SKIP_FOOTER
-+ }
-+ while (--num != 0);
-+}
-+
-+void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
-+{
-+ do
-+ {
-+ SKIP_HEADER(3)
-+ HASH_ZIP_CALC;
-+ curMatch = p->hash[hashValue];
-+ p->hash[hashValue] = p->pos;
-+ SKIP_FOOTER
-+ }
-+ while (--num != 0);
-+}
-+
-+static void Bt3_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
-+{
-+ do
-+ {
-+ UInt32 hash2Value;
-+ SKIP_HEADER(3)
-+ HASH3_CALC;
-+ curMatch = p->hash[kFix3HashSize + hashValue];
-+ p->hash[hash2Value] =
-+ p->hash[kFix3HashSize + hashValue] = p->pos;
-+ SKIP_FOOTER
-+ }
-+ while (--num != 0);
-+}
-+
-+static void Bt4_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
-+{
-+ do
-+ {
-+ UInt32 hash2Value, hash3Value;
-+ SKIP_HEADER(4)
-+ HASH4_CALC;
-+ curMatch = p->hash[kFix4HashSize + hashValue];
-+ p->hash[ hash2Value] =
-+ p->hash[kFix3HashSize + hash3Value] = p->pos;
-+ p->hash[kFix4HashSize + hashValue] = p->pos;
-+ SKIP_FOOTER
-+ }
-+ while (--num != 0);
-+}
-+
-+static void Hc4_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
-+{
-+ do
-+ {
-+ UInt32 hash2Value, hash3Value;
-+ SKIP_HEADER(4)
-+ HASH4_CALC;
-+ curMatch = p->hash[kFix4HashSize + hashValue];
-+ p->hash[ hash2Value] =
-+ p->hash[kFix3HashSize + hash3Value] =
-+ p->hash[kFix4HashSize + hashValue] = p->pos;
-+ p->son[p->cyclicBufferPos] = curMatch;
-+ MOVE_POS
-+ }
-+ while (--num != 0);
-+}
-+
-+void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
-+{
-+ do
-+ {
-+ SKIP_HEADER(3)
-+ HASH_ZIP_CALC;
-+ curMatch = p->hash[hashValue];
-+ p->hash[hashValue] = p->pos;
-+ p->son[p->cyclicBufferPos] = curMatch;
-+ MOVE_POS
-+ }
-+ while (--num != 0);
-+}
-+
-+void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable)
-+{
-+ vTable->Init = (Mf_Init_Func)MatchFinder_Init;
-+ vTable->GetIndexByte = (Mf_GetIndexByte_Func)MatchFinder_GetIndexByte;
-+ vTable->GetNumAvailableBytes = (Mf_GetNumAvailableBytes_Func)MatchFinder_GetNumAvailableBytes;
-+ vTable->GetPointerToCurrentPos = (Mf_GetPointerToCurrentPos_Func)MatchFinder_GetPointerToCurrentPos;
-+ if (!p->btMode)
-+ {
-+ vTable->GetMatches = (Mf_GetMatches_Func)Hc4_MatchFinder_GetMatches;
-+ vTable->Skip = (Mf_Skip_Func)Hc4_MatchFinder_Skip;
-+ }
-+ else if (p->numHashBytes == 2)
-+ {
-+ vTable->GetMatches = (Mf_GetMatches_Func)Bt2_MatchFinder_GetMatches;
-+ vTable->Skip = (Mf_Skip_Func)Bt2_MatchFinder_Skip;
-+ }
-+ else if (p->numHashBytes == 3)
-+ {
-+ vTable->GetMatches = (Mf_GetMatches_Func)Bt3_MatchFinder_GetMatches;
-+ vTable->Skip = (Mf_Skip_Func)Bt3_MatchFinder_Skip;
-+ }
-+ else
-+ {
-+ vTable->GetMatches = (Mf_GetMatches_Func)Bt4_MatchFinder_GetMatches;
-+ vTable->Skip = (Mf_Skip_Func)Bt4_MatchFinder_Skip;
-+ }
-+}
---- /dev/null
-+++ b/lib/lzma/LzmaDec.c
-@@ -0,0 +1,999 @@
-+/* LzmaDec.c -- LZMA Decoder
-+2009-09-20 : Igor Pavlov : Public domain */
-+
-+#include "LzmaDec.h"
-+
-+#include <string.h>
-+
-+#define kNumTopBits 24
-+#define kTopValue ((UInt32)1 << kNumTopBits)
-+
-+#define kNumBitModelTotalBits 11
-+#define kBitModelTotal (1 << kNumBitModelTotalBits)
-+#define kNumMoveBits 5
-+
-+#define RC_INIT_SIZE 5
-+
-+#define NORMALIZE if (range < kTopValue) { range <<= 8; code = (code << 8) | (*buf++); }
-+
-+#define IF_BIT_0(p) ttt = *(p); NORMALIZE; bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound)
-+#define UPDATE_0(p) range = bound; *(p) = (CLzmaProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits));
-+#define UPDATE_1(p) range -= bound; code -= bound; *(p) = (CLzmaProb)(ttt - (ttt >> kNumMoveBits));
-+#define GET_BIT2(p, i, A0, A1) IF_BIT_0(p) \
-+ { UPDATE_0(p); i = (i + i); A0; } else \
-+ { UPDATE_1(p); i = (i + i) + 1; A1; }
-+#define GET_BIT(p, i) GET_BIT2(p, i, ; , ;)
-+
-+#define TREE_GET_BIT(probs, i) { GET_BIT((probs + i), i); }
-+#define TREE_DECODE(probs, limit, i) \
-+ { i = 1; do { TREE_GET_BIT(probs, i); } while (i < limit); i -= limit; }
-+
-+/* #define _LZMA_SIZE_OPT */
-+
-+#ifdef _LZMA_SIZE_OPT
-+#define TREE_6_DECODE(probs, i) TREE_DECODE(probs, (1 << 6), i)
-+#else
-+#define TREE_6_DECODE(probs, i) \
-+ { i = 1; \
-+ TREE_GET_BIT(probs, i); \
-+ TREE_GET_BIT(probs, i); \
-+ TREE_GET_BIT(probs, i); \
-+ TREE_GET_BIT(probs, i); \
-+ TREE_GET_BIT(probs, i); \
-+ TREE_GET_BIT(probs, i); \
-+ i -= 0x40; }
-+#endif
-+
-+#define NORMALIZE_CHECK if (range < kTopValue) { if (buf >= bufLimit) return DUMMY_ERROR; range <<= 8; code = (code << 8) | (*buf++); }
-+
-+#define IF_BIT_0_CHECK(p) ttt = *(p); NORMALIZE_CHECK; bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound)
-+#define UPDATE_0_CHECK range = bound;
-+#define UPDATE_1_CHECK range -= bound; code -= bound;
-+#define GET_BIT2_CHECK(p, i, A0, A1) IF_BIT_0_CHECK(p) \
-+ { UPDATE_0_CHECK; i = (i + i); A0; } else \
-+ { UPDATE_1_CHECK; i = (i + i) + 1; A1; }
-+#define GET_BIT_CHECK(p, i) GET_BIT2_CHECK(p, i, ; , ;)
-+#define TREE_DECODE_CHECK(probs, limit, i) \
-+ { i = 1; do { GET_BIT_CHECK(probs + i, i) } while (i < limit); i -= limit; }
-+
-+
-+#define kNumPosBitsMax 4
-+#define kNumPosStatesMax (1 << kNumPosBitsMax)
-+
-+#define kLenNumLowBits 3
-+#define kLenNumLowSymbols (1 << kLenNumLowBits)
-+#define kLenNumMidBits 3
-+#define kLenNumMidSymbols (1 << kLenNumMidBits)
-+#define kLenNumHighBits 8
-+#define kLenNumHighSymbols (1 << kLenNumHighBits)
-+
-+#define LenChoice 0
-+#define LenChoice2 (LenChoice + 1)
-+#define LenLow (LenChoice2 + 1)
-+#define LenMid (LenLow + (kNumPosStatesMax << kLenNumLowBits))
-+#define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits))
-+#define kNumLenProbs (LenHigh + kLenNumHighSymbols)
-+
-+
-+#define kNumStates 12
-+#define kNumLitStates 7
-+
-+#define kStartPosModelIndex 4
-+#define kEndPosModelIndex 14
-+#define kNumFullDistances (1 << (kEndPosModelIndex >> 1))
-+
-+#define kNumPosSlotBits 6
-+#define kNumLenToPosStates 4
-+
-+#define kNumAlignBits 4
-+#define kAlignTableSize (1 << kNumAlignBits)
-+
-+#define kMatchMinLen 2
-+#define kMatchSpecLenStart (kMatchMinLen + kLenNumLowSymbols + kLenNumMidSymbols + kLenNumHighSymbols)
-+
-+#define IsMatch 0
-+#define IsRep (IsMatch + (kNumStates << kNumPosBitsMax))
-+#define IsRepG0 (IsRep + kNumStates)
-+#define IsRepG1 (IsRepG0 + kNumStates)
-+#define IsRepG2 (IsRepG1 + kNumStates)
-+#define IsRep0Long (IsRepG2 + kNumStates)
-+#define PosSlot (IsRep0Long + (kNumStates << kNumPosBitsMax))
-+#define SpecPos (PosSlot + (kNumLenToPosStates << kNumPosSlotBits))
-+#define Align (SpecPos + kNumFullDistances - kEndPosModelIndex)
-+#define LenCoder (Align + kAlignTableSize)
-+#define RepLenCoder (LenCoder + kNumLenProbs)
-+#define Literal (RepLenCoder + kNumLenProbs)
-+
-+#define LZMA_BASE_SIZE 1846
-+#define LZMA_LIT_SIZE 768
-+
-+#define LzmaProps_GetNumProbs(p) ((UInt32)LZMA_BASE_SIZE + (LZMA_LIT_SIZE << ((p)->lc + (p)->lp)))
-+
-+#if Literal != LZMA_BASE_SIZE
-+StopCompilingDueBUG
-+#endif
-+
-+#define LZMA_DIC_MIN (1 << 12)
-+
-+/* First LZMA-symbol is always decoded.
-+And it decodes new LZMA-symbols while (buf < bufLimit), but "buf" is without last normalization
-+Out:
-+ Result:
-+ SZ_OK - OK
-+ SZ_ERROR_DATA - Error
-+ p->remainLen:
-+ < kMatchSpecLenStart : normal remain
-+ = kMatchSpecLenStart : finished
-+ = kMatchSpecLenStart + 1 : Flush marker
-+ = kMatchSpecLenStart + 2 : State Init Marker
-+*/
-+
-+static int MY_FAST_CALL LzmaDec_DecodeReal(CLzmaDec *p, SizeT limit, const Byte *bufLimit)
-+{
-+ CLzmaProb *probs = p->probs;
-+
-+ unsigned state = p->state;
-+ UInt32 rep0 = p->reps[0], rep1 = p->reps[1], rep2 = p->reps[2], rep3 = p->reps[3];
-+ unsigned pbMask = ((unsigned)1 << (p->prop.pb)) - 1;
-+ unsigned lpMask = ((unsigned)1 << (p->prop.lp)) - 1;
-+ unsigned lc = p->prop.lc;
-+
-+ Byte *dic = p->dic;
-+ SizeT dicBufSize = p->dicBufSize;
-+ SizeT dicPos = p->dicPos;
-+
-+ UInt32 processedPos = p->processedPos;
-+ UInt32 checkDicSize = p->checkDicSize;
-+ unsigned len = 0;
-+
-+ const Byte *buf = p->buf;
-+ UInt32 range = p->range;
-+ UInt32 code = p->code;
-+
-+ do
-+ {
-+ CLzmaProb *prob;
-+ UInt32 bound;
-+ unsigned ttt;
-+ unsigned posState = processedPos & pbMask;
-+
-+ prob = probs + IsMatch + (state << kNumPosBitsMax) + posState;
-+ IF_BIT_0(prob)
-+ {
-+ unsigned symbol;
-+ UPDATE_0(prob);
-+ prob = probs + Literal;
-+ if (checkDicSize != 0 || processedPos != 0)
-+ prob += (LZMA_LIT_SIZE * (((processedPos & lpMask) << lc) +
-+ (dic[(dicPos == 0 ? dicBufSize : dicPos) - 1] >> (8 - lc))));
-+
-+ if (state < kNumLitStates)
-+ {
-+ state -= (state < 4) ? state : 3;
-+ symbol = 1;
-+ do { GET_BIT(prob + symbol, symbol) } while (symbol < 0x100);
-+ }
-+ else
-+ {
-+ unsigned matchByte = p->dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)];
-+ unsigned offs = 0x100;
-+ state -= (state < 10) ? 3 : 6;
-+ symbol = 1;
-+ do
-+ {
-+ unsigned bit;
-+ CLzmaProb *probLit;
-+ matchByte <<= 1;
-+ bit = (matchByte & offs);
-+ probLit = prob + offs + bit + symbol;
-+ GET_BIT2(probLit, symbol, offs &= ~bit, offs &= bit)
-+ }
-+ while (symbol < 0x100);
-+ }
-+ dic[dicPos++] = (Byte)symbol;
-+ processedPos++;
-+ continue;
-+ }
-+ else
-+ {
-+ UPDATE_1(prob);
-+ prob = probs + IsRep + state;
-+ IF_BIT_0(prob)
-+ {
-+ UPDATE_0(prob);
-+ state += kNumStates;
-+ prob = probs + LenCoder;
-+ }
-+ else
-+ {
-+ UPDATE_1(prob);
-+ if (checkDicSize == 0 && processedPos == 0)
-+ return SZ_ERROR_DATA;
-+ prob = probs + IsRepG0 + state;
-+ IF_BIT_0(prob)
-+ {
-+ UPDATE_0(prob);
-+ prob = probs + IsRep0Long + (state << kNumPosBitsMax) + posState;
-+ IF_BIT_0(prob)
-+ {
-+ UPDATE_0(prob);
-+ dic[dicPos] = dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)];
-+ dicPos++;
-+ processedPos++;
-+ state = state < kNumLitStates ? 9 : 11;
-+ continue;
-+ }
-+ UPDATE_1(prob);
-+ }
-+ else
-+ {
-+ UInt32 distance;
-+ UPDATE_1(prob);
-+ prob = probs + IsRepG1 + state;
-+ IF_BIT_0(prob)
-+ {
-+ UPDATE_0(prob);
-+ distance = rep1;
-+ }
-+ else
-+ {
-+ UPDATE_1(prob);
-+ prob = probs + IsRepG2 + state;
-+ IF_BIT_0(prob)
-+ {
-+ UPDATE_0(prob);
-+ distance = rep2;
-+ }
-+ else
-+ {
-+ UPDATE_1(prob);
-+ distance = rep3;
-+ rep3 = rep2;
-+ }
-+ rep2 = rep1;
-+ }
-+ rep1 = rep0;
-+ rep0 = distance;
-+ }
-+ state = state < kNumLitStates ? 8 : 11;
-+ prob = probs + RepLenCoder;
-+ }
-+ {
-+ unsigned limit, offset;
-+ CLzmaProb *probLen = prob + LenChoice;
-+ IF_BIT_0(probLen)
-+ {
-+ UPDATE_0(probLen);
-+ probLen = prob + LenLow + (posState << kLenNumLowBits);
-+ offset = 0;
-+ limit = (1 << kLenNumLowBits);
-+ }
-+ else
-+ {
-+ UPDATE_1(probLen);
-+ probLen = prob + LenChoice2;
-+ IF_BIT_0(probLen)
-+ {
-+ UPDATE_0(probLen);
-+ probLen = prob + LenMid + (posState << kLenNumMidBits);
-+ offset = kLenNumLowSymbols;
-+ limit = (1 << kLenNumMidBits);
-+ }
-+ else
-+ {
-+ UPDATE_1(probLen);
-+ probLen = prob + LenHigh;
-+ offset = kLenNumLowSymbols + kLenNumMidSymbols;
-+ limit = (1 << kLenNumHighBits);
-+ }
-+ }
-+ TREE_DECODE(probLen, limit, len);
-+ len += offset;
-+ }
-+
-+ if (state >= kNumStates)
-+ {
-+ UInt32 distance;
-+ prob = probs + PosSlot +
-+ ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << kNumPosSlotBits);
-+ TREE_6_DECODE(prob, distance);
-+ if (distance >= kStartPosModelIndex)
-+ {
-+ unsigned posSlot = (unsigned)distance;
-+ int numDirectBits = (int)(((distance >> 1) - 1));
-+ distance = (2 | (distance & 1));
-+ if (posSlot < kEndPosModelIndex)
-+ {
-+ distance <<= numDirectBits;
-+ prob = probs + SpecPos + distance - posSlot - 1;
-+ {
-+ UInt32 mask = 1;
-+ unsigned i = 1;
-+ do
-+ {
-+ GET_BIT2(prob + i, i, ; , distance |= mask);
-+ mask <<= 1;
-+ }
-+ while (--numDirectBits != 0);
-+ }
-+ }
-+ else
-+ {
-+ numDirectBits -= kNumAlignBits;
-+ do
-+ {
-+ NORMALIZE
-+ range >>= 1;
-+
-+ {
-+ UInt32 t;
-+ code -= range;
-+ t = (0 - ((UInt32)code >> 31)); /* (UInt32)((Int32)code >> 31) */
-+ distance = (distance << 1) + (t + 1);
-+ code += range & t;
-+ }
-+ /*
-+ distance <<= 1;
-+ if (code >= range)
-+ {
-+ code -= range;
-+ distance |= 1;
-+ }
-+ */
-+ }
-+ while (--numDirectBits != 0);
-+ prob = probs + Align;
-+ distance <<= kNumAlignBits;
-+ {
-+ unsigned i = 1;
-+ GET_BIT2(prob + i, i, ; , distance |= 1);
-+ GET_BIT2(prob + i, i, ; , distance |= 2);
-+ GET_BIT2(prob + i, i, ; , distance |= 4);
-+ GET_BIT2(prob + i, i, ; , distance |= 8);
-+ }
-+ if (distance == (UInt32)0xFFFFFFFF)
-+ {
-+ len += kMatchSpecLenStart;
-+ state -= kNumStates;
-+ break;
-+ }
-+ }
-+ }
-+ rep3 = rep2;
-+ rep2 = rep1;
-+ rep1 = rep0;
-+ rep0 = distance + 1;
-+ if (checkDicSize == 0)
-+ {
-+ if (distance >= processedPos)
-+ return SZ_ERROR_DATA;
-+ }
-+ else if (distance >= checkDicSize)
-+ return SZ_ERROR_DATA;
-+ state = (state < kNumStates + kNumLitStates) ? kNumLitStates : kNumLitStates + 3;
-+ }
-+
-+ len += kMatchMinLen;
-+
-+ if (limit == dicPos)
-+ return SZ_ERROR_DATA;
-+ {
-+ SizeT rem = limit - dicPos;
-+ unsigned curLen = ((rem < len) ? (unsigned)rem : len);
-+ SizeT pos = (dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0);
-+
-+ processedPos += curLen;
-+
-+ len -= curLen;
-+ if (pos + curLen <= dicBufSize)
-+ {
-+ Byte *dest = dic + dicPos;
-+ ptrdiff_t src = (ptrdiff_t)pos - (ptrdiff_t)dicPos;
-+ const Byte *lim = dest + curLen;
-+ dicPos += curLen;
-+ do
-+ *(dest) = (Byte)*(dest + src);
-+ while (++dest != lim);
-+ }
-+ else
-+ {
-+ do
-+ {
-+ dic[dicPos++] = dic[pos];
-+ if (++pos == dicBufSize)
-+ pos = 0;
-+ }
-+ while (--curLen != 0);
-+ }
-+ }
-+ }
-+ }
-+ while (dicPos < limit && buf < bufLimit);
-+ NORMALIZE;
-+ p->buf = buf;
-+ p->range = range;
-+ p->code = code;
-+ p->remainLen = len;
-+ p->dicPos = dicPos;
-+ p->processedPos = processedPos;
-+ p->reps[0] = rep0;
-+ p->reps[1] = rep1;
-+ p->reps[2] = rep2;
-+ p->reps[3] = rep3;
-+ p->state = state;
-+
-+ return SZ_OK;
-+}
-+
-+static void MY_FAST_CALL LzmaDec_WriteRem(CLzmaDec *p, SizeT limit)
-+{
-+ if (p->remainLen != 0 && p->remainLen < kMatchSpecLenStart)
-+ {
-+ Byte *dic = p->dic;
-+ SizeT dicPos = p->dicPos;
-+ SizeT dicBufSize = p->dicBufSize;
-+ unsigned len = p->remainLen;
-+ UInt32 rep0 = p->reps[0];
-+ if (limit - dicPos < len)
-+ len = (unsigned)(limit - dicPos);
-+
-+ if (p->checkDicSize == 0 && p->prop.dicSize - p->processedPos <= len)
-+ p->checkDicSize = p->prop.dicSize;
-+
-+ p->processedPos += len;
-+ p->remainLen -= len;
-+ while (len-- != 0)
-+ {
-+ dic[dicPos] = dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)];
-+ dicPos++;
-+ }
-+ p->dicPos = dicPos;
-+ }
-+}
-+
-+static int MY_FAST_CALL LzmaDec_DecodeReal2(CLzmaDec *p, SizeT limit, const Byte *bufLimit)
-+{
-+ do
-+ {
-+ SizeT limit2 = limit;
-+ if (p->checkDicSize == 0)
-+ {
-+ UInt32 rem = p->prop.dicSize - p->processedPos;
-+ if (limit - p->dicPos > rem)
-+ limit2 = p->dicPos + rem;
-+ }
-+ RINOK(LzmaDec_DecodeReal(p, limit2, bufLimit));
-+ if (p->processedPos >= p->prop.dicSize)
-+ p->checkDicSize = p->prop.dicSize;
-+ LzmaDec_WriteRem(p, limit);
-+ }
-+ while (p->dicPos < limit && p->buf < bufLimit && p->remainLen < kMatchSpecLenStart);
-+
-+ if (p->remainLen > kMatchSpecLenStart)
-+ {
-+ p->remainLen = kMatchSpecLenStart;
-+ }
-+ return 0;
-+}
-+
-+typedef enum
-+{
-+ DUMMY_ERROR, /* unexpected end of input stream */
-+ DUMMY_LIT,
-+ DUMMY_MATCH,
-+ DUMMY_REP
-+} ELzmaDummy;
-+
-+static ELzmaDummy LzmaDec_TryDummy(const CLzmaDec *p, const Byte *buf, SizeT inSize)
-+{
-+ UInt32 range = p->range;
-+ UInt32 code = p->code;
-+ const Byte *bufLimit = buf + inSize;
-+ CLzmaProb *probs = p->probs;
-+ unsigned state = p->state;
-+ ELzmaDummy res;
-+
-+ {
-+ CLzmaProb *prob;
-+ UInt32 bound;
-+ unsigned ttt;
-+ unsigned posState = (p->processedPos) & ((1 << p->prop.pb) - 1);
-+
-+ prob = probs + IsMatch + (state << kNumPosBitsMax) + posState;
-+ IF_BIT_0_CHECK(prob)
-+ {
-+ UPDATE_0_CHECK
-+
-+ /* if (bufLimit - buf >= 7) return DUMMY_LIT; */
-+
-+ prob = probs + Literal;
-+ if (p->checkDicSize != 0 || p->processedPos != 0)
-+ prob += (LZMA_LIT_SIZE *
-+ ((((p->processedPos) & ((1 << (p->prop.lp)) - 1)) << p->prop.lc) +
-+ (p->dic[(p->dicPos == 0 ? p->dicBufSize : p->dicPos) - 1] >> (8 - p->prop.lc))));
-+
-+ if (state < kNumLitStates)
-+ {
-+ unsigned symbol = 1;
-+ do { GET_BIT_CHECK(prob + symbol, symbol) } while (symbol < 0x100);
-+ }
-+ else
-+ {
-+ unsigned matchByte = p->dic[p->dicPos - p->reps[0] +
-+ ((p->dicPos < p->reps[0]) ? p->dicBufSize : 0)];
-+ unsigned offs = 0x100;
-+ unsigned symbol = 1;
-+ do
-+ {
-+ unsigned bit;
-+ CLzmaProb *probLit;
-+ matchByte <<= 1;
-+ bit = (matchByte & offs);
-+ probLit = prob + offs + bit + symbol;
-+ GET_BIT2_CHECK(probLit, symbol, offs &= ~bit, offs &= bit)
-+ }
-+ while (symbol < 0x100);
-+ }
-+ res = DUMMY_LIT;
-+ }
-+ else
-+ {
-+ unsigned len;
-+ UPDATE_1_CHECK;
-+
-+ prob = probs + IsRep + state;
-+ IF_BIT_0_CHECK(prob)
-+ {
-+ UPDATE_0_CHECK;
-+ state = 0;
-+ prob = probs + LenCoder;
-+ res = DUMMY_MATCH;
-+ }
-+ else
-+ {
-+ UPDATE_1_CHECK;
-+ res = DUMMY_REP;
-+ prob = probs + IsRepG0 + state;
-+ IF_BIT_0_CHECK(prob)
-+ {
-+ UPDATE_0_CHECK;
-+ prob = probs + IsRep0Long + (state << kNumPosBitsMax) + posState;
-+ IF_BIT_0_CHECK(prob)
-+ {
-+ UPDATE_0_CHECK;
-+ NORMALIZE_CHECK;
-+ return DUMMY_REP;
-+ }
-+ else
-+ {
-+ UPDATE_1_CHECK;
-+ }
-+ }
-+ else
-+ {
-+ UPDATE_1_CHECK;
-+ prob = probs + IsRepG1 + state;
-+ IF_BIT_0_CHECK(prob)
-+ {
-+ UPDATE_0_CHECK;
-+ }
-+ else
-+ {
-+ UPDATE_1_CHECK;
-+ prob = probs + IsRepG2 + state;
-+ IF_BIT_0_CHECK(prob)
-+ {
-+ UPDATE_0_CHECK;
-+ }
-+ else
-+ {
-+ UPDATE_1_CHECK;
-+ }
-+ }
-+ }
-+ state = kNumStates;
-+ prob = probs + RepLenCoder;
-+ }
-+ {
-+ unsigned limit, offset;
-+ CLzmaProb *probLen = prob + LenChoice;
-+ IF_BIT_0_CHECK(probLen)
-+ {
-+ UPDATE_0_CHECK;
-+ probLen = prob + LenLow + (posState << kLenNumLowBits);
-+ offset = 0;
-+ limit = 1 << kLenNumLowBits;
-+ }
-+ else
-+ {
-+ UPDATE_1_CHECK;
-+ probLen = prob + LenChoice2;
-+ IF_BIT_0_CHECK(probLen)
-+ {
-+ UPDATE_0_CHECK;
-+ probLen = prob + LenMid + (posState << kLenNumMidBits);
-+ offset = kLenNumLowSymbols;
-+ limit = 1 << kLenNumMidBits;
-+ }
-+ else
-+ {
-+ UPDATE_1_CHECK;
-+ probLen = prob + LenHigh;
-+ offset = kLenNumLowSymbols + kLenNumMidSymbols;
-+ limit = 1 << kLenNumHighBits;
-+ }
-+ }
-+ TREE_DECODE_CHECK(probLen, limit, len);
-+ len += offset;
-+ }
-+
-+ if (state < 4)
-+ {
-+ unsigned posSlot;
-+ prob = probs + PosSlot +
-+ ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) <<
-+ kNumPosSlotBits);
-+ TREE_DECODE_CHECK(prob, 1 << kNumPosSlotBits, posSlot);
-+ if (posSlot >= kStartPosModelIndex)
-+ {
-+ int numDirectBits = ((posSlot >> 1) - 1);
-+
-+ /* if (bufLimit - buf >= 8) return DUMMY_MATCH; */
-+
-+ if (posSlot < kEndPosModelIndex)
-+ {
-+ prob = probs + SpecPos + ((2 | (posSlot & 1)) << numDirectBits) - posSlot - 1;
-+ }
-+ else
-+ {
-+ numDirectBits -= kNumAlignBits;
-+ do
-+ {
-+ NORMALIZE_CHECK
-+ range >>= 1;
-+ code -= range & (((code - range) >> 31) - 1);
-+ /* if (code >= range) code -= range; */
-+ }
-+ while (--numDirectBits != 0);
-+ prob = probs + Align;
-+ numDirectBits = kNumAlignBits;
-+ }
-+ {
-+ unsigned i = 1;
-+ do
-+ {
-+ GET_BIT_CHECK(prob + i, i);
-+ }
-+ while (--numDirectBits != 0);
-+ }
-+ }
-+ }
-+ }
-+ }
-+ NORMALIZE_CHECK;
-+ return res;
-+}
-+
-+
-+static void LzmaDec_InitRc(CLzmaDec *p, const Byte *data)
-+{
-+ p->code = ((UInt32)data[1] << 24) | ((UInt32)data[2] << 16) | ((UInt32)data[3] << 8) | ((UInt32)data[4]);
-+ p->range = 0xFFFFFFFF;
-+ p->needFlush = 0;
-+}
-+
-+void LzmaDec_InitDicAndState(CLzmaDec *p, Bool initDic, Bool initState)
-+{
-+ p->needFlush = 1;
-+ p->remainLen = 0;
-+ p->tempBufSize = 0;
-+
-+ if (initDic)
-+ {
-+ p->processedPos = 0;
-+ p->checkDicSize = 0;
-+ p->needInitState = 1;
-+ }
-+ if (initState)
-+ p->needInitState = 1;
-+}
-+
-+void LzmaDec_Init(CLzmaDec *p)
-+{
-+ p->dicPos = 0;
-+ LzmaDec_InitDicAndState(p, True, True);
-+}
-+
-+static void LzmaDec_InitStateReal(CLzmaDec *p)
-+{
-+ UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (p->prop.lc + p->prop.lp));
-+ UInt32 i;
-+ CLzmaProb *probs = p->probs;
-+ for (i = 0; i < numProbs; i++)
-+ probs[i] = kBitModelTotal >> 1;
-+ p->reps[0] = p->reps[1] = p->reps[2] = p->reps[3] = 1;
-+ p->state = 0;
-+ p->needInitState = 0;
-+}
-+
-+SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, const Byte *src, SizeT *srcLen,
-+ ELzmaFinishMode finishMode, ELzmaStatus *status)
-+{
-+ SizeT inSize = *srcLen;
-+ (*srcLen) = 0;
-+ LzmaDec_WriteRem(p, dicLimit);
-+
-+ *status = LZMA_STATUS_NOT_SPECIFIED;
-+
-+ while (p->remainLen != kMatchSpecLenStart)
-+ {
-+ int checkEndMarkNow;
-+
-+ if (p->needFlush != 0)
-+ {
-+ for (; inSize > 0 && p->tempBufSize < RC_INIT_SIZE; (*srcLen)++, inSize--)
-+ p->tempBuf[p->tempBufSize++] = *src++;
-+ if (p->tempBufSize < RC_INIT_SIZE)
-+ {
-+ *status = LZMA_STATUS_NEEDS_MORE_INPUT;
-+ return SZ_OK;
-+ }
-+ if (p->tempBuf[0] != 0)
-+ return SZ_ERROR_DATA;
-+
-+ LzmaDec_InitRc(p, p->tempBuf);
-+ p->tempBufSize = 0;
-+ }
-+
-+ checkEndMarkNow = 0;
-+ if (p->dicPos >= dicLimit)
-+ {
-+ if (p->remainLen == 0 && p->code == 0)
-+ {
-+ *status = LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK;
-+ return SZ_OK;
-+ }
-+ if (finishMode == LZMA_FINISH_ANY)
-+ {
-+ *status = LZMA_STATUS_NOT_FINISHED;
-+ return SZ_OK;
-+ }
-+ if (p->remainLen != 0)
-+ {
-+ *status = LZMA_STATUS_NOT_FINISHED;
-+ return SZ_ERROR_DATA;
-+ }
-+ checkEndMarkNow = 1;
-+ }
-+
-+ if (p->needInitState)
-+ LzmaDec_InitStateReal(p);
-+
-+ if (p->tempBufSize == 0)
-+ {
-+ SizeT processed;
-+ const Byte *bufLimit;
-+ if (inSize < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow)
-+ {
-+ int dummyRes = LzmaDec_TryDummy(p, src, inSize);
-+ if (dummyRes == DUMMY_ERROR)
-+ {
-+ memcpy(p->tempBuf, src, inSize);
-+ p->tempBufSize = (unsigned)inSize;
-+ (*srcLen) += inSize;
-+ *status = LZMA_STATUS_NEEDS_MORE_INPUT;
-+ return SZ_OK;
-+ }
-+ if (checkEndMarkNow && dummyRes != DUMMY_MATCH)
-+ {
-+ *status = LZMA_STATUS_NOT_FINISHED;
-+ return SZ_ERROR_DATA;
-+ }
-+ bufLimit = src;
-+ }
-+ else
-+ bufLimit = src + inSize - LZMA_REQUIRED_INPUT_MAX;
-+ p->buf = src;
-+ if (LzmaDec_DecodeReal2(p, dicLimit, bufLimit) != 0)
-+ return SZ_ERROR_DATA;
-+ processed = (SizeT)(p->buf - src);
-+ (*srcLen) += processed;
-+ src += processed;
-+ inSize -= processed;
-+ }
-+ else
-+ {
-+ unsigned rem = p->tempBufSize, lookAhead = 0;
-+ while (rem < LZMA_REQUIRED_INPUT_MAX && lookAhead < inSize)
-+ p->tempBuf[rem++] = src[lookAhead++];
-+ p->tempBufSize = rem;
-+ if (rem < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow)
-+ {
-+ int dummyRes = LzmaDec_TryDummy(p, p->tempBuf, rem);
-+ if (dummyRes == DUMMY_ERROR)
-+ {
-+ (*srcLen) += lookAhead;
-+ *status = LZMA_STATUS_NEEDS_MORE_INPUT;
-+ return SZ_OK;
-+ }
-+ if (checkEndMarkNow && dummyRes != DUMMY_MATCH)
-+ {
-+ *status = LZMA_STATUS_NOT_FINISHED;
-+ return SZ_ERROR_DATA;
-+ }
-+ }
-+ p->buf = p->tempBuf;
-+ if (LzmaDec_DecodeReal2(p, dicLimit, p->buf) != 0)
-+ return SZ_ERROR_DATA;
-+ lookAhead -= (rem - (unsigned)(p->buf - p->tempBuf));
-+ (*srcLen) += lookAhead;
-+ src += lookAhead;
-+ inSize -= lookAhead;
-+ p->tempBufSize = 0;
-+ }
-+ }
-+ if (p->code == 0)
-+ *status = LZMA_STATUS_FINISHED_WITH_MARK;
-+ return (p->code == 0) ? SZ_OK : SZ_ERROR_DATA;
-+}
-+
-+SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status)
-+{
-+ SizeT outSize = *destLen;
-+ SizeT inSize = *srcLen;
-+ *srcLen = *destLen = 0;
-+ for (;;)
-+ {
-+ SizeT inSizeCur = inSize, outSizeCur, dicPos;
-+ ELzmaFinishMode curFinishMode;
-+ SRes res;
-+ if (p->dicPos == p->dicBufSize)
-+ p->dicPos = 0;
-+ dicPos = p->dicPos;
-+ if (outSize > p->dicBufSize - dicPos)
-+ {
-+ outSizeCur = p->dicBufSize;
-+ curFinishMode = LZMA_FINISH_ANY;
-+ }
-+ else
-+ {
-+ outSizeCur = dicPos + outSize;
-+ curFinishMode = finishMode;
-+ }
-+
-+ res = LzmaDec_DecodeToDic(p, outSizeCur, src, &inSizeCur, curFinishMode, status);
-+ src += inSizeCur;
-+ inSize -= inSizeCur;
-+ *srcLen += inSizeCur;
-+ outSizeCur = p->dicPos - dicPos;
-+ memcpy(dest, p->dic + dicPos, outSizeCur);
-+ dest += outSizeCur;
-+ outSize -= outSizeCur;
-+ *destLen += outSizeCur;
-+ if (res != 0)
-+ return res;
-+ if (outSizeCur == 0 || outSize == 0)
-+ return SZ_OK;
-+ }
-+}
-+
-+void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc)
-+{
-+ alloc->Free(alloc, p->probs);
-+ p->probs = 0;
-+}
-+
-+static void LzmaDec_FreeDict(CLzmaDec *p, ISzAlloc *alloc)
-+{
-+ alloc->Free(alloc, p->dic);
-+ p->dic = 0;
-+}
-+
-+void LzmaDec_Free(CLzmaDec *p, ISzAlloc *alloc)
-+{
-+ LzmaDec_FreeProbs(p, alloc);
-+ LzmaDec_FreeDict(p, alloc);
-+}
-+
-+SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size)
-+{
-+ UInt32 dicSize;
-+ Byte d;
-+
-+ if (size < LZMA_PROPS_SIZE)
-+ return SZ_ERROR_UNSUPPORTED;
-+ else
-+ dicSize = data[1] | ((UInt32)data[2] << 8) | ((UInt32)data[3] << 16) | ((UInt32)data[4] << 24);
-+
-+ if (dicSize < LZMA_DIC_MIN)
-+ dicSize = LZMA_DIC_MIN;
-+ p->dicSize = dicSize;
-+
-+ d = data[0];
-+ if (d >= (9 * 5 * 5))
-+ return SZ_ERROR_UNSUPPORTED;
-+
-+ p->lc = d % 9;
-+ d /= 9;
-+ p->pb = d / 5;
-+ p->lp = d % 5;
-+
-+ return SZ_OK;
-+}
-+
-+static SRes LzmaDec_AllocateProbs2(CLzmaDec *p, const CLzmaProps *propNew, ISzAlloc *alloc)
-+{
-+ UInt32 numProbs = LzmaProps_GetNumProbs(propNew);
-+ if (p->probs == 0 || numProbs != p->numProbs)
-+ {
-+ LzmaDec_FreeProbs(p, alloc);
-+ p->probs = (CLzmaProb *)alloc->Alloc(alloc, numProbs * sizeof(CLzmaProb));
-+ p->numProbs = numProbs;
-+ if (p->probs == 0)
-+ return SZ_ERROR_MEM;
-+ }
-+ return SZ_OK;
-+}
-+
-+SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc)
-+{
-+ CLzmaProps propNew;
-+ RINOK(LzmaProps_Decode(&propNew, props, propsSize));
-+ RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc));
-+ p->prop = propNew;
-+ return SZ_OK;
-+}
-+
-+SRes LzmaDec_Allocate(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc)
-+{
-+ CLzmaProps propNew;
-+ SizeT dicBufSize;
-+ RINOK(LzmaProps_Decode(&propNew, props, propsSize));
-+ RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc));
-+ dicBufSize = propNew.dicSize;
-+ if (p->dic == 0 || dicBufSize != p->dicBufSize)
-+ {
-+ LzmaDec_FreeDict(p, alloc);
-+ p->dic = (Byte *)alloc->Alloc(alloc, dicBufSize);
-+ if (p->dic == 0)
-+ {
-+ LzmaDec_FreeProbs(p, alloc);
-+ return SZ_ERROR_MEM;
-+ }
-+ }
-+ p->dicBufSize = dicBufSize;
-+ p->prop = propNew;
-+ return SZ_OK;
-+}
-+
-+SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
-+ const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode,
-+ ELzmaStatus *status, ISzAlloc *alloc)
-+{
-+ CLzmaDec p;
-+ SRes res;
-+ SizeT inSize = *srcLen;
-+ SizeT outSize = *destLen;
-+ *srcLen = *destLen = 0;
-+ if (inSize < RC_INIT_SIZE)
-+ return SZ_ERROR_INPUT_EOF;
-+
-+ LzmaDec_Construct(&p);
-+ res = LzmaDec_AllocateProbs(&p, propData, propSize, alloc);
-+ if (res != 0)
-+ return res;
-+ p.dic = dest;
-+ p.dicBufSize = outSize;
-+
-+ LzmaDec_Init(&p);
-+
-+ *srcLen = inSize;
-+ res = LzmaDec_DecodeToDic(&p, outSize, src, srcLen, finishMode, status);
-+
-+ if (res == SZ_OK && *status == LZMA_STATUS_NEEDS_MORE_INPUT)
-+ res = SZ_ERROR_INPUT_EOF;
-+
-+ (*destLen) = p.dicPos;
-+ LzmaDec_FreeProbs(&p, alloc);
-+ return res;
-+}
---- /dev/null
-+++ b/lib/lzma/LzmaEnc.c
-@@ -0,0 +1,2271 @@
-+/* LzmaEnc.c -- LZMA Encoder
-+2009-11-24 : Igor Pavlov : Public domain */
-+
-+#include <string.h>
-+
-+/* #define SHOW_STAT */
-+/* #define SHOW_STAT2 */
-+
-+#if defined(SHOW_STAT) || defined(SHOW_STAT2)
-+#include <stdio.h>
-+#endif
-+
-+#include "LzmaEnc.h"
-+
-+/* disable MT */
-+#define _7ZIP_ST
-+
-+#include "LzFind.h"
-+#ifndef _7ZIP_ST
-+#include "LzFindMt.h"
-+#endif
-+
-+#ifdef SHOW_STAT
-+static int ttt = 0;
-+#endif
-+
-+#define kBlockSizeMax ((1 << LZMA_NUM_BLOCK_SIZE_BITS) - 1)
-+
-+#define kBlockSize (9 << 10)
-+#define kUnpackBlockSize (1 << 18)
-+#define kMatchArraySize (1 << 21)
-+#define kMatchRecordMaxSize ((LZMA_MATCH_LEN_MAX * 2 + 3) * LZMA_MATCH_LEN_MAX)
-+
-+#define kNumMaxDirectBits (31)
-+
-+#define kNumTopBits 24
-+#define kTopValue ((UInt32)1 << kNumTopBits)
-+
-+#define kNumBitModelTotalBits 11
-+#define kBitModelTotal (1 << kNumBitModelTotalBits)
-+#define kNumMoveBits 5
-+#define kProbInitValue (kBitModelTotal >> 1)
-+
-+#define kNumMoveReducingBits 4
-+#define kNumBitPriceShiftBits 4
-+#define kBitPrice (1 << kNumBitPriceShiftBits)
-+
-+void LzmaEncProps_Init(CLzmaEncProps *p)
-+{
-+ p->level = 5;
-+ p->dictSize = p->mc = 0;
-+ p->lc = p->lp = p->pb = p->algo = p->fb = p->btMode = p->numHashBytes = p->numThreads = -1;
-+ p->writeEndMark = 0;
-+}
-+
-+void LzmaEncProps_Normalize(CLzmaEncProps *p)
-+{
-+ int level = p->level;
-+ if (level < 0) level = 5;
-+ p->level = level;
-+ if (p->dictSize == 0) p->dictSize = (level <= 5 ? (1 << (level * 2 + 14)) : (level == 6 ? (1 << 25) : (1 << 26)));
-+ if (p->lc < 0) p->lc = 3;
-+ if (p->lp < 0) p->lp = 0;
-+ if (p->pb < 0) p->pb = 2;
-+ if (p->algo < 0) p->algo = (level < 5 ? 0 : 1);
-+ if (p->fb < 0) p->fb = (level < 7 ? 32 : 64);
-+ if (p->btMode < 0) p->btMode = (p->algo == 0 ? 0 : 1);
-+ if (p->numHashBytes < 0) p->numHashBytes = 4;
-+ if (p->mc == 0) p->mc = (16 + (p->fb >> 1)) >> (p->btMode ? 0 : 1);
-+ if (p->numThreads < 0)
-+ p->numThreads =
-+ #ifndef _7ZIP_ST
-+ ((p->btMode && p->algo) ? 2 : 1);
-+ #else
-+ 1;
-+ #endif
-+}
-+
-+UInt32 LzmaEncProps_GetDictSize(const CLzmaEncProps *props2)
-+{
-+ CLzmaEncProps props = *props2;
-+ LzmaEncProps_Normalize(&props);
-+ return props.dictSize;
-+}
-+
-+/* #define LZMA_LOG_BSR */
-+/* Define it for Intel's CPU */
-+
-+
-+#ifdef LZMA_LOG_BSR
-+
-+#define kDicLogSizeMaxCompress 30
-+
-+#define BSR2_RET(pos, res) { unsigned long i; _BitScanReverse(&i, (pos)); res = (i + i) + ((pos >> (i - 1)) & 1); }
-+
-+UInt32 GetPosSlot1(UInt32 pos)
-+{
-+ UInt32 res;
-+ BSR2_RET(pos, res);
-+ return res;
-+}
-+#define GetPosSlot2(pos, res) { BSR2_RET(pos, res); }
-+#define GetPosSlot(pos, res) { if (pos < 2) res = pos; else BSR2_RET(pos, res); }
-+
-+#else
-+
-+#define kNumLogBits (9 + (int)sizeof(size_t) / 2)
-+#define kDicLogSizeMaxCompress ((kNumLogBits - 1) * 2 + 7)
-+
-+void LzmaEnc_FastPosInit(Byte *g_FastPos)
-+{
-+ int c = 2, slotFast;
-+ g_FastPos[0] = 0;
-+ g_FastPos[1] = 1;
-+
-+ for (slotFast = 2; slotFast < kNumLogBits * 2; slotFast++)
-+ {
-+ UInt32 k = (1 << ((slotFast >> 1) - 1));
-+ UInt32 j;
-+ for (j = 0; j < k; j++, c++)
-+ g_FastPos[c] = (Byte)slotFast;
-+ }
-+}
-+
-+#define BSR2_RET(pos, res) { UInt32 i = 6 + ((kNumLogBits - 1) & \
-+ (0 - (((((UInt32)1 << (kNumLogBits + 6)) - 1) - pos) >> 31))); \
-+ res = p->g_FastPos[pos >> i] + (i * 2); }
-+/*
-+#define BSR2_RET(pos, res) { res = (pos < (1 << (kNumLogBits + 6))) ? \
-+ p->g_FastPos[pos >> 6] + 12 : \
-+ p->g_FastPos[pos >> (6 + kNumLogBits - 1)] + (6 + (kNumLogBits - 1)) * 2; }
-+*/
-+
-+#define GetPosSlot1(pos) p->g_FastPos[pos]
-+#define GetPosSlot2(pos, res) { BSR2_RET(pos, res); }
-+#define GetPosSlot(pos, res) { if (pos < kNumFullDistances) res = p->g_FastPos[pos]; else BSR2_RET(pos, res); }
-+
-+#endif
-+
-+
-+#define LZMA_NUM_REPS 4
-+
-+typedef unsigned CState;
-+
-+typedef struct
-+{
-+ UInt32 price;
-+
-+ CState state;
-+ int prev1IsChar;
-+ int prev2;
-+
-+ UInt32 posPrev2;
-+ UInt32 backPrev2;
-+
-+ UInt32 posPrev;
-+ UInt32 backPrev;
-+ UInt32 backs[LZMA_NUM_REPS];
-+} COptimal;
-+
-+#define kNumOpts (1 << 12)
-+
-+#define kNumLenToPosStates 4
-+#define kNumPosSlotBits 6
-+#define kDicLogSizeMin 0
-+#define kDicLogSizeMax 32
-+#define kDistTableSizeMax (kDicLogSizeMax * 2)
-+
-+
-+#define kNumAlignBits 4
-+#define kAlignTableSize (1 << kNumAlignBits)
-+#define kAlignMask (kAlignTableSize - 1)
-+
-+#define kStartPosModelIndex 4
-+#define kEndPosModelIndex 14
-+#define kNumPosModels (kEndPosModelIndex - kStartPosModelIndex)
-+
-+#define kNumFullDistances (1 << (kEndPosModelIndex >> 1))
-+
-+#ifdef _LZMA_PROB32
-+#define CLzmaProb UInt32
-+#else
-+#define CLzmaProb UInt16
-+#endif
-+
-+#define LZMA_PB_MAX 4
-+#define LZMA_LC_MAX 8
-+#define LZMA_LP_MAX 4
-+
-+#define LZMA_NUM_PB_STATES_MAX (1 << LZMA_PB_MAX)
-+
-+
-+#define kLenNumLowBits 3
-+#define kLenNumLowSymbols (1 << kLenNumLowBits)
-+#define kLenNumMidBits 3
-+#define kLenNumMidSymbols (1 << kLenNumMidBits)
-+#define kLenNumHighBits 8
-+#define kLenNumHighSymbols (1 << kLenNumHighBits)
-+
-+#define kLenNumSymbolsTotal (kLenNumLowSymbols + kLenNumMidSymbols + kLenNumHighSymbols)
-+
-+#define LZMA_MATCH_LEN_MIN 2
-+#define LZMA_MATCH_LEN_MAX (LZMA_MATCH_LEN_MIN + kLenNumSymbolsTotal - 1)
-+
-+#define kNumStates 12
-+
-+typedef struct
-+{
-+ CLzmaProb choice;
-+ CLzmaProb choice2;
-+ CLzmaProb low[LZMA_NUM_PB_STATES_MAX << kLenNumLowBits];
-+ CLzmaProb mid[LZMA_NUM_PB_STATES_MAX << kLenNumMidBits];
-+ CLzmaProb high[kLenNumHighSymbols];
-+} CLenEnc;
-+
-+typedef struct
-+{
-+ CLenEnc p;
-+ UInt32 prices[LZMA_NUM_PB_STATES_MAX][kLenNumSymbolsTotal];
-+ UInt32 tableSize;
-+ UInt32 counters[LZMA_NUM_PB_STATES_MAX];
-+} CLenPriceEnc;
-+
-+typedef struct
-+{
-+ UInt32 range;
-+ Byte cache;
-+ UInt64 low;
-+ UInt64 cacheSize;
-+ Byte *buf;
-+ Byte *bufLim;
-+ Byte *bufBase;
-+ ISeqOutStream *outStream;
-+ UInt64 processed;
-+ SRes res;
-+} CRangeEnc;
-+
-+typedef struct
-+{
-+ CLzmaProb *litProbs;
-+
-+ CLzmaProb isMatch[kNumStates][LZMA_NUM_PB_STATES_MAX];
-+ CLzmaProb isRep[kNumStates];
-+ CLzmaProb isRepG0[kNumStates];
-+ CLzmaProb isRepG1[kNumStates];
-+ CLzmaProb isRepG2[kNumStates];
-+ CLzmaProb isRep0Long[kNumStates][LZMA_NUM_PB_STATES_MAX];
-+
-+ CLzmaProb posSlotEncoder[kNumLenToPosStates][1 << kNumPosSlotBits];
-+ CLzmaProb posEncoders[kNumFullDistances - kEndPosModelIndex];
-+ CLzmaProb posAlignEncoder[1 << kNumAlignBits];
-+
-+ CLenPriceEnc lenEnc;
-+ CLenPriceEnc repLenEnc;
-+
-+ UInt32 reps[LZMA_NUM_REPS];
-+ UInt32 state;
-+} CSaveState;
-+
-+typedef struct
-+{
-+ IMatchFinder matchFinder;
-+ void *matchFinderObj;
-+
-+ #ifndef _7ZIP_ST
-+ Bool mtMode;
-+ CMatchFinderMt matchFinderMt;
-+ #endif
-+
-+ CMatchFinder matchFinderBase;
-+
-+ #ifndef _7ZIP_ST
-+ Byte pad[128];
-+ #endif
-+
-+ UInt32 optimumEndIndex;
-+ UInt32 optimumCurrentIndex;
-+
-+ UInt32 longestMatchLength;
-+ UInt32 numPairs;
-+ UInt32 numAvail;
-+ COptimal opt[kNumOpts];
-+
-+ #ifndef LZMA_LOG_BSR
-+ Byte g_FastPos[1 << kNumLogBits];
-+ #endif
-+
-+ UInt32 ProbPrices[kBitModelTotal >> kNumMoveReducingBits];
-+ UInt32 matches[LZMA_MATCH_LEN_MAX * 2 + 2 + 1];
-+ UInt32 numFastBytes;
-+ UInt32 additionalOffset;
-+ UInt32 reps[LZMA_NUM_REPS];
-+ UInt32 state;
-+
-+ UInt32 posSlotPrices[kNumLenToPosStates][kDistTableSizeMax];
-+ UInt32 distancesPrices[kNumLenToPosStates][kNumFullDistances];
-+ UInt32 alignPrices[kAlignTableSize];
-+ UInt32 alignPriceCount;
-+
-+ UInt32 distTableSize;
-+
-+ unsigned lc, lp, pb;
-+ unsigned lpMask, pbMask;
-+
-+ CLzmaProb *litProbs;
-+
-+ CLzmaProb isMatch[kNumStates][LZMA_NUM_PB_STATES_MAX];
-+ CLzmaProb isRep[kNumStates];
-+ CLzmaProb isRepG0[kNumStates];
-+ CLzmaProb isRepG1[kNumStates];
-+ CLzmaProb isRepG2[kNumStates];
-+ CLzmaProb isRep0Long[kNumStates][LZMA_NUM_PB_STATES_MAX];
-+
-+ CLzmaProb posSlotEncoder[kNumLenToPosStates][1 << kNumPosSlotBits];
-+ CLzmaProb posEncoders[kNumFullDistances - kEndPosModelIndex];
-+ CLzmaProb posAlignEncoder[1 << kNumAlignBits];
-+
-+ CLenPriceEnc lenEnc;
-+ CLenPriceEnc repLenEnc;
-+
-+ unsigned lclp;
-+
-+ Bool fastMode;
-+
-+ CRangeEnc rc;
-+
-+ Bool writeEndMark;
-+ UInt64 nowPos64;
-+ UInt32 matchPriceCount;
-+ Bool finished;
-+ Bool multiThread;
-+
-+ SRes result;
-+ UInt32 dictSize;
-+ UInt32 matchFinderCycles;
-+
-+ int needInit;
-+
-+ CSaveState saveState;
-+} CLzmaEnc;
-+
-+void LzmaEnc_SaveState(CLzmaEncHandle pp)
-+{
-+ CLzmaEnc *p = (CLzmaEnc *)pp;
-+ CSaveState *dest = &p->saveState;
-+ int i;
-+ dest->lenEnc = p->lenEnc;
-+ dest->repLenEnc = p->repLenEnc;
-+ dest->state = p->state;
-+
-+ for (i = 0; i < kNumStates; i++)
-+ {
-+ memcpy(dest->isMatch[i], p->isMatch[i], sizeof(p->isMatch[i]));
-+ memcpy(dest->isRep0Long[i], p->isRep0Long[i], sizeof(p->isRep0Long[i]));
-+ }
-+ for (i = 0; i < kNumLenToPosStates; i++)
-+ memcpy(dest->posSlotEncoder[i], p->posSlotEncoder[i], sizeof(p->posSlotEncoder[i]));
-+ memcpy(dest->isRep, p->isRep, sizeof(p->isRep));
-+ memcpy(dest->isRepG0, p->isRepG0, sizeof(p->isRepG0));
-+ memcpy(dest->isRepG1, p->isRepG1, sizeof(p->isRepG1));
-+ memcpy(dest->isRepG2, p->isRepG2, sizeof(p->isRepG2));
-+ memcpy(dest->posEncoders, p->posEncoders, sizeof(p->posEncoders));
-+ memcpy(dest->posAlignEncoder, p->posAlignEncoder, sizeof(p->posAlignEncoder));
-+ memcpy(dest->reps, p->reps, sizeof(p->reps));
-+ memcpy(dest->litProbs, p->litProbs, (0x300 << p->lclp) * sizeof(CLzmaProb));
-+}
-+
-+void LzmaEnc_RestoreState(CLzmaEncHandle pp)
-+{
-+ CLzmaEnc *dest = (CLzmaEnc *)pp;
-+ const CSaveState *p = &dest->saveState;
-+ int i;
-+ dest->lenEnc = p->lenEnc;
-+ dest->repLenEnc = p->repLenEnc;
-+ dest->state = p->state;
-+
-+ for (i = 0; i < kNumStates; i++)
-+ {
-+ memcpy(dest->isMatch[i], p->isMatch[i], sizeof(p->isMatch[i]));
-+ memcpy(dest->isRep0Long[i], p->isRep0Long[i], sizeof(p->isRep0Long[i]));
-+ }
-+ for (i = 0; i < kNumLenToPosStates; i++)
-+ memcpy(dest->posSlotEncoder[i], p->posSlotEncoder[i], sizeof(p->posSlotEncoder[i]));
-+ memcpy(dest->isRep, p->isRep, sizeof(p->isRep));
-+ memcpy(dest->isRepG0, p->isRepG0, sizeof(p->isRepG0));
-+ memcpy(dest->isRepG1, p->isRepG1, sizeof(p->isRepG1));
-+ memcpy(dest->isRepG2, p->isRepG2, sizeof(p->isRepG2));
-+ memcpy(dest->posEncoders, p->posEncoders, sizeof(p->posEncoders));
-+ memcpy(dest->posAlignEncoder, p->posAlignEncoder, sizeof(p->posAlignEncoder));
-+ memcpy(dest->reps, p->reps, sizeof(p->reps));
-+ memcpy(dest->litProbs, p->litProbs, (0x300 << dest->lclp) * sizeof(CLzmaProb));
-+}
-+
-+SRes LzmaEnc_SetProps(CLzmaEncHandle pp, const CLzmaEncProps *props2)
-+{
-+ CLzmaEnc *p = (CLzmaEnc *)pp;
-+ CLzmaEncProps props = *props2;
-+ LzmaEncProps_Normalize(&props);
-+
-+ if (props.lc > LZMA_LC_MAX || props.lp > LZMA_LP_MAX || props.pb > LZMA_PB_MAX ||
-+ props.dictSize > (1 << kDicLogSizeMaxCompress) || props.dictSize > (1 << 30))
-+ return SZ_ERROR_PARAM;
-+ p->dictSize = props.dictSize;
-+ p->matchFinderCycles = props.mc;
-+ {
-+ unsigned fb = props.fb;
-+ if (fb < 5)
-+ fb = 5;
-+ if (fb > LZMA_MATCH_LEN_MAX)
-+ fb = LZMA_MATCH_LEN_MAX;
-+ p->numFastBytes = fb;
-+ }
-+ p->lc = props.lc;
-+ p->lp = props.lp;
-+ p->pb = props.pb;
-+ p->fastMode = (props.algo == 0);
-+ p->matchFinderBase.btMode = props.btMode;
-+ {
-+ UInt32 numHashBytes = 4;
-+ if (props.btMode)
-+ {
-+ if (props.numHashBytes < 2)
-+ numHashBytes = 2;
-+ else if (props.numHashBytes < 4)
-+ numHashBytes = props.numHashBytes;
-+ }
-+ p->matchFinderBase.numHashBytes = numHashBytes;
-+ }
-+
-+ p->matchFinderBase.cutValue = props.mc;
-+
-+ p->writeEndMark = props.writeEndMark;
-+
-+ #ifndef _7ZIP_ST
-+ /*
-+ if (newMultiThread != _multiThread)
-+ {
-+ ReleaseMatchFinder();
-+ _multiThread = newMultiThread;
-+ }
-+ */
-+ p->multiThread = (props.numThreads > 1);
-+ #endif
-+
-+ return SZ_OK;
-+}
-+
-+static const int kLiteralNextStates[kNumStates] = {0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 4, 5};
-+static const int kMatchNextStates[kNumStates] = {7, 7, 7, 7, 7, 7, 7, 10, 10, 10, 10, 10};
-+static const int kRepNextStates[kNumStates] = {8, 8, 8, 8, 8, 8, 8, 11, 11, 11, 11, 11};
-+static const int kShortRepNextStates[kNumStates]= {9, 9, 9, 9, 9, 9, 9, 11, 11, 11, 11, 11};
-+
-+#define IsCharState(s) ((s) < 7)
-+
-+#define GetLenToPosState(len) (((len) < kNumLenToPosStates + 1) ? (len) - 2 : kNumLenToPosStates - 1)
-+
-+#define kInfinityPrice (1 << 30)
-+
-+static void RangeEnc_Construct(CRangeEnc *p)
-+{
-+ p->outStream = 0;
-+ p->bufBase = 0;
-+}
-+
-+#define RangeEnc_GetProcessed(p) ((p)->processed + ((p)->buf - (p)->bufBase) + (p)->cacheSize)
-+
-+#define RC_BUF_SIZE (1 << 16)
-+static int RangeEnc_Alloc(CRangeEnc *p, ISzAlloc *alloc)
-+{
-+ if (p->bufBase == 0)
-+ {
-+ p->bufBase = (Byte *)alloc->Alloc(alloc, RC_BUF_SIZE);
-+ if (p->bufBase == 0)
-+ return 0;
-+ p->bufLim = p->bufBase + RC_BUF_SIZE;
-+ }
-+ return 1;
-+}
-+
-+static void RangeEnc_Free(CRangeEnc *p, ISzAlloc *alloc)
-+{
-+ alloc->Free(alloc, p->bufBase);
-+ p->bufBase = 0;
-+}
-+
-+static void RangeEnc_Init(CRangeEnc *p)
-+{
-+ /* Stream.Init(); */
-+ p->low = 0;
-+ p->range = 0xFFFFFFFF;
-+ p->cacheSize = 1;
-+ p->cache = 0;
-+
-+ p->buf = p->bufBase;
-+
-+ p->processed = 0;
-+ p->res = SZ_OK;
-+}
-+
-+static void RangeEnc_FlushStream(CRangeEnc *p)
-+{
-+ size_t num;
-+ if (p->res != SZ_OK)
-+ return;
-+ num = p->buf - p->bufBase;
-+ if (num != p->outStream->Write(p->outStream, p->bufBase, num))
-+ p->res = SZ_ERROR_WRITE;
-+ p->processed += num;
-+ p->buf = p->bufBase;
-+}
-+
-+static void MY_FAST_CALL RangeEnc_ShiftLow(CRangeEnc *p)
-+{
-+ if ((UInt32)p->low < (UInt32)0xFF000000 || (int)(p->low >> 32) != 0)
-+ {
-+ Byte temp = p->cache;
-+ do
-+ {
-+ Byte *buf = p->buf;
-+ *buf++ = (Byte)(temp + (Byte)(p->low >> 32));
-+ p->buf = buf;
-+ if (buf == p->bufLim)
-+ RangeEnc_FlushStream(p);
-+ temp = 0xFF;
-+ }
-+ while (--p->cacheSize != 0);
-+ p->cache = (Byte)((UInt32)p->low >> 24);
-+ }
-+ p->cacheSize++;
-+ p->low = (UInt32)p->low << 8;
-+}
-+
-+static void RangeEnc_FlushData(CRangeEnc *p)
-+{
-+ int i;
-+ for (i = 0; i < 5; i++)
-+ RangeEnc_ShiftLow(p);
-+}
-+
-+static void RangeEnc_EncodeDirectBits(CRangeEnc *p, UInt32 value, int numBits)
-+{
-+ do
-+ {
-+ p->range >>= 1;
-+ p->low += p->range & (0 - ((value >> --numBits) & 1));
-+ if (p->range < kTopValue)
-+ {
-+ p->range <<= 8;
-+ RangeEnc_ShiftLow(p);
-+ }
-+ }
-+ while (numBits != 0);
-+}
-+
-+static void RangeEnc_EncodeBit(CRangeEnc *p, CLzmaProb *prob, UInt32 symbol)
-+{
-+ UInt32 ttt = *prob;
-+ UInt32 newBound = (p->range >> kNumBitModelTotalBits) * ttt;
-+ if (symbol == 0)
-+ {
-+ p->range = newBound;
-+ ttt += (kBitModelTotal - ttt) >> kNumMoveBits;
-+ }
-+ else
-+ {
-+ p->low += newBound;
-+ p->range -= newBound;
-+ ttt -= ttt >> kNumMoveBits;
-+ }
-+ *prob = (CLzmaProb)ttt;
-+ if (p->range < kTopValue)
-+ {
-+ p->range <<= 8;
-+ RangeEnc_ShiftLow(p);
-+ }
-+}
-+
-+static void LitEnc_Encode(CRangeEnc *p, CLzmaProb *probs, UInt32 symbol)
-+{
-+ symbol |= 0x100;
-+ do
-+ {
-+ RangeEnc_EncodeBit(p, probs + (symbol >> 8), (symbol >> 7) & 1);
-+ symbol <<= 1;
-+ }
-+ while (symbol < 0x10000);
-+}
-+
-+static void LitEnc_EncodeMatched(CRangeEnc *p, CLzmaProb *probs, UInt32 symbol, UInt32 matchByte)
-+{
-+ UInt32 offs = 0x100;
-+ symbol |= 0x100;
-+ do
-+ {
-+ matchByte <<= 1;
-+ RangeEnc_EncodeBit(p, probs + (offs + (matchByte & offs) + (symbol >> 8)), (symbol >> 7) & 1);
-+ symbol <<= 1;
-+ offs &= ~(matchByte ^ symbol);
-+ }
-+ while (symbol < 0x10000);
-+}
-+
-+void LzmaEnc_InitPriceTables(UInt32 *ProbPrices)
-+{
-+ UInt32 i;
-+ for (i = (1 << kNumMoveReducingBits) / 2; i < kBitModelTotal; i += (1 << kNumMoveReducingBits))
-+ {
-+ const int kCyclesBits = kNumBitPriceShiftBits;
-+ UInt32 w = i;
-+ UInt32 bitCount = 0;
-+ int j;
-+ for (j = 0; j < kCyclesBits; j++)
-+ {
-+ w = w * w;
-+ bitCount <<= 1;
-+ while (w >= ((UInt32)1 << 16))
-+ {
-+ w >>= 1;
-+ bitCount++;
-+ }
-+ }
-+ ProbPrices[i >> kNumMoveReducingBits] = ((kNumBitModelTotalBits << kCyclesBits) - 15 - bitCount);
-+ }
-+}
-+
-+
-+#define GET_PRICE(prob, symbol) \
-+ p->ProbPrices[((prob) ^ (((-(int)(symbol))) & (kBitModelTotal - 1))) >> kNumMoveReducingBits];
-+
-+#define GET_PRICEa(prob, symbol) \
-+ ProbPrices[((prob) ^ ((-((int)(symbol))) & (kBitModelTotal - 1))) >> kNumMoveReducingBits];
-+
-+#define GET_PRICE_0(prob) p->ProbPrices[(prob) >> kNumMoveReducingBits]
-+#define GET_PRICE_1(prob) p->ProbPrices[((prob) ^ (kBitModelTotal - 1)) >> kNumMoveReducingBits]
-+
-+#define GET_PRICE_0a(prob) ProbPrices[(prob) >> kNumMoveReducingBits]
-+#define GET_PRICE_1a(prob) ProbPrices[((prob) ^ (kBitModelTotal - 1)) >> kNumMoveReducingBits]
-+
-+static UInt32 LitEnc_GetPrice(const CLzmaProb *probs, UInt32 symbol, UInt32 *ProbPrices)
-+{
-+ UInt32 price = 0;
-+ symbol |= 0x100;
-+ do
-+ {
-+ price += GET_PRICEa(probs[symbol >> 8], (symbol >> 7) & 1);
-+ symbol <<= 1;
-+ }
-+ while (symbol < 0x10000);
-+ return price;
-+}
-+
-+static UInt32 LitEnc_GetPriceMatched(const CLzmaProb *probs, UInt32 symbol, UInt32 matchByte, UInt32 *ProbPrices)
-+{
-+ UInt32 price = 0;
-+ UInt32 offs = 0x100;
-+ symbol |= 0x100;
-+ do
-+ {
-+ matchByte <<= 1;
-+ price += GET_PRICEa(probs[offs + (matchByte & offs) + (symbol >> 8)], (symbol >> 7) & 1);
-+ symbol <<= 1;
-+ offs &= ~(matchByte ^ symbol);
-+ }
-+ while (symbol < 0x10000);
-+ return price;
-+}
-+
-+
-+static void RcTree_Encode(CRangeEnc *rc, CLzmaProb *probs, int numBitLevels, UInt32 symbol)
-+{
-+ UInt32 m = 1;
-+ int i;
-+ for (i = numBitLevels; i != 0;)
-+ {
-+ UInt32 bit;
-+ i--;
-+ bit = (symbol >> i) & 1;
-+ RangeEnc_EncodeBit(rc, probs + m, bit);
-+ m = (m << 1) | bit;
-+ }
-+}
-+
-+static void RcTree_ReverseEncode(CRangeEnc *rc, CLzmaProb *probs, int numBitLevels, UInt32 symbol)
-+{
-+ UInt32 m = 1;
-+ int i;
-+ for (i = 0; i < numBitLevels; i++)
-+ {
-+ UInt32 bit = symbol & 1;
-+ RangeEnc_EncodeBit(rc, probs + m, bit);
-+ m = (m << 1) | bit;
-+ symbol >>= 1;
-+ }
-+}
-+
-+static UInt32 RcTree_GetPrice(const CLzmaProb *probs, int numBitLevels, UInt32 symbol, UInt32 *ProbPrices)
-+{
-+ UInt32 price = 0;
-+ symbol |= (1 << numBitLevels);
-+ while (symbol != 1)
-+ {
-+ price += GET_PRICEa(probs[symbol >> 1], symbol & 1);
-+ symbol >>= 1;
-+ }
-+ return price;
-+}
-+
-+static UInt32 RcTree_ReverseGetPrice(const CLzmaProb *probs, int numBitLevels, UInt32 symbol, UInt32 *ProbPrices)
-+{
-+ UInt32 price = 0;
-+ UInt32 m = 1;
-+ int i;
-+ for (i = numBitLevels; i != 0; i--)
-+ {
-+ UInt32 bit = symbol & 1;
-+ symbol >>= 1;
-+ price += GET_PRICEa(probs[m], bit);
-+ m = (m << 1) | bit;
-+ }
-+ return price;
-+}
-+
-+
-+static void LenEnc_Init(CLenEnc *p)
-+{
-+ unsigned i;
-+ p->choice = p->choice2 = kProbInitValue;
-+ for (i = 0; i < (LZMA_NUM_PB_STATES_MAX << kLenNumLowBits); i++)
-+ p->low[i] = kProbInitValue;
-+ for (i = 0; i < (LZMA_NUM_PB_STATES_MAX << kLenNumMidBits); i++)
-+ p->mid[i] = kProbInitValue;
-+ for (i = 0; i < kLenNumHighSymbols; i++)
-+ p->high[i] = kProbInitValue;
-+}
-+
-+static void LenEnc_Encode(CLenEnc *p, CRangeEnc *rc, UInt32 symbol, UInt32 posState)
-+{
-+ if (symbol < kLenNumLowSymbols)
-+ {
-+ RangeEnc_EncodeBit(rc, &p->choice, 0);
-+ RcTree_Encode(rc, p->low + (posState << kLenNumLowBits), kLenNumLowBits, symbol);
-+ }
-+ else
-+ {
-+ RangeEnc_EncodeBit(rc, &p->choice, 1);
-+ if (symbol < kLenNumLowSymbols + kLenNumMidSymbols)
-+ {
-+ RangeEnc_EncodeBit(rc, &p->choice2, 0);
-+ RcTree_Encode(rc, p->mid + (posState << kLenNumMidBits), kLenNumMidBits, symbol - kLenNumLowSymbols);
-+ }
-+ else
-+ {
-+ RangeEnc_EncodeBit(rc, &p->choice2, 1);
-+ RcTree_Encode(rc, p->high, kLenNumHighBits, symbol - kLenNumLowSymbols - kLenNumMidSymbols);
-+ }
-+ }
-+}
-+
-+static void LenEnc_SetPrices(CLenEnc *p, UInt32 posState, UInt32 numSymbols, UInt32 *prices, UInt32 *ProbPrices)
-+{
-+ UInt32 a0 = GET_PRICE_0a(p->choice);
-+ UInt32 a1 = GET_PRICE_1a(p->choice);
-+ UInt32 b0 = a1 + GET_PRICE_0a(p->choice2);
-+ UInt32 b1 = a1 + GET_PRICE_1a(p->choice2);
-+ UInt32 i = 0;
-+ for (i = 0; i < kLenNumLowSymbols; i++)
-+ {
-+ if (i >= numSymbols)
-+ return;
-+ prices[i] = a0 + RcTree_GetPrice(p->low + (posState << kLenNumLowBits), kLenNumLowBits, i, ProbPrices);
-+ }
-+ for (; i < kLenNumLowSymbols + kLenNumMidSymbols; i++)
-+ {
-+ if (i >= numSymbols)
-+ return;
-+ prices[i] = b0 + RcTree_GetPrice(p->mid + (posState << kLenNumMidBits), kLenNumMidBits, i - kLenNumLowSymbols, ProbPrices);
-+ }
-+ for (; i < numSymbols; i++)
-+ prices[i] = b1 + RcTree_GetPrice(p->high, kLenNumHighBits, i - kLenNumLowSymbols - kLenNumMidSymbols, ProbPrices);
-+}
-+
-+static void MY_FAST_CALL LenPriceEnc_UpdateTable(CLenPriceEnc *p, UInt32 posState, UInt32 *ProbPrices)
-+{
-+ LenEnc_SetPrices(&p->p, posState, p->tableSize, p->prices[posState], ProbPrices);
-+ p->counters[posState] = p->tableSize;
-+}
-+
-+static void LenPriceEnc_UpdateTables(CLenPriceEnc *p, UInt32 numPosStates, UInt32 *ProbPrices)
-+{
-+ UInt32 posState;
-+ for (posState = 0; posState < numPosStates; posState++)
-+ LenPriceEnc_UpdateTable(p, posState, ProbPrices);
-+}
-+
-+static void LenEnc_Encode2(CLenPriceEnc *p, CRangeEnc *rc, UInt32 symbol, UInt32 posState, Bool updatePrice, UInt32 *ProbPrices)
-+{
-+ LenEnc_Encode(&p->p, rc, symbol, posState);
-+ if (updatePrice)
-+ if (--p->counters[posState] == 0)
-+ LenPriceEnc_UpdateTable(p, posState, ProbPrices);
-+}
-+
-+
-+
-+
-+static void MovePos(CLzmaEnc *p, UInt32 num)
-+{
-+ #ifdef SHOW_STAT
-+ ttt += num;
-+ printf("\n MovePos %d", num);
-+ #endif
-+ if (num != 0)
-+ {
-+ p->additionalOffset += num;
-+ p->matchFinder.Skip(p->matchFinderObj, num);
-+ }
-+}
-+
-+static UInt32 ReadMatchDistances(CLzmaEnc *p, UInt32 *numDistancePairsRes)
-+{
-+ UInt32 lenRes = 0, numPairs;
-+ p->numAvail = p->matchFinder.GetNumAvailableBytes(p->matchFinderObj);
-+ numPairs = p->matchFinder.GetMatches(p->matchFinderObj, p->matches);
-+ #ifdef SHOW_STAT
-+ printf("\n i = %d numPairs = %d ", ttt, numPairs / 2);
-+ ttt++;
-+ {
-+ UInt32 i;
-+ for (i = 0; i < numPairs; i += 2)
-+ printf("%2d %6d | ", p->matches[i], p->matches[i + 1]);
-+ }
-+ #endif
-+ if (numPairs > 0)
-+ {
-+ lenRes = p->matches[numPairs - 2];
-+ if (lenRes == p->numFastBytes)
-+ {
-+ const Byte *pby = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1;
-+ UInt32 distance = p->matches[numPairs - 1] + 1;
-+ UInt32 numAvail = p->numAvail;
-+ if (numAvail > LZMA_MATCH_LEN_MAX)
-+ numAvail = LZMA_MATCH_LEN_MAX;
-+ {
-+ const Byte *pby2 = pby - distance;
-+ for (; lenRes < numAvail && pby[lenRes] == pby2[lenRes]; lenRes++);
-+ }
-+ }
-+ }
-+ p->additionalOffset++;
-+ *numDistancePairsRes = numPairs;
-+ return lenRes;
-+}
-+
-+
-+#define MakeAsChar(p) (p)->backPrev = (UInt32)(-1); (p)->prev1IsChar = False;
-+#define MakeAsShortRep(p) (p)->backPrev = 0; (p)->prev1IsChar = False;
-+#define IsShortRep(p) ((p)->backPrev == 0)
-+
-+static UInt32 GetRepLen1Price(CLzmaEnc *p, UInt32 state, UInt32 posState)
-+{
-+ return
-+ GET_PRICE_0(p->isRepG0[state]) +
-+ GET_PRICE_0(p->isRep0Long[state][posState]);
-+}
-+
-+static UInt32 GetPureRepPrice(CLzmaEnc *p, UInt32 repIndex, UInt32 state, UInt32 posState)
-+{
-+ UInt32 price;
-+ if (repIndex == 0)
-+ {
-+ price = GET_PRICE_0(p->isRepG0[state]);
-+ price += GET_PRICE_1(p->isRep0Long[state][posState]);
-+ }
-+ else
-+ {
-+ price = GET_PRICE_1(p->isRepG0[state]);
-+ if (repIndex == 1)
-+ price += GET_PRICE_0(p->isRepG1[state]);
-+ else
-+ {
-+ price += GET_PRICE_1(p->isRepG1[state]);
-+ price += GET_PRICE(p->isRepG2[state], repIndex - 2);
-+ }
-+ }
-+ return price;
-+}
-+
-+static UInt32 GetRepPrice(CLzmaEnc *p, UInt32 repIndex, UInt32 len, UInt32 state, UInt32 posState)
-+{
-+ return p->repLenEnc.prices[posState][len - LZMA_MATCH_LEN_MIN] +
-+ GetPureRepPrice(p, repIndex, state, posState);
-+}
-+
-+static UInt32 Backward(CLzmaEnc *p, UInt32 *backRes, UInt32 cur)
-+{
-+ UInt32 posMem = p->opt[cur].posPrev;
-+ UInt32 backMem = p->opt[cur].backPrev;
-+ p->optimumEndIndex = cur;
-+ do
-+ {
-+ if (p->opt[cur].prev1IsChar)
-+ {
-+ MakeAsChar(&p->opt[posMem])
-+ p->opt[posMem].posPrev = posMem - 1;
-+ if (p->opt[cur].prev2)
-+ {
-+ p->opt[posMem - 1].prev1IsChar = False;
-+ p->opt[posMem - 1].posPrev = p->opt[cur].posPrev2;
-+ p->opt[posMem - 1].backPrev = p->opt[cur].backPrev2;
-+ }
-+ }
-+ {
-+ UInt32 posPrev = posMem;
-+ UInt32 backCur = backMem;
-+
-+ backMem = p->opt[posPrev].backPrev;
-+ posMem = p->opt[posPrev].posPrev;
-+
-+ p->opt[posPrev].backPrev = backCur;
-+ p->opt[posPrev].posPrev = cur;
-+ cur = posPrev;
-+ }
-+ }
-+ while (cur != 0);
-+ *backRes = p->opt[0].backPrev;
-+ p->optimumCurrentIndex = p->opt[0].posPrev;
-+ return p->optimumCurrentIndex;
-+}
-+
-+#define LIT_PROBS(pos, prevByte) (p->litProbs + ((((pos) & p->lpMask) << p->lc) + ((prevByte) >> (8 - p->lc))) * 0x300)
-+
-+static UInt32 GetOptimum(CLzmaEnc *p, UInt32 position, UInt32 *backRes)
-+{
-+ UInt32 numAvail, mainLen, numPairs, repMaxIndex, i, posState, lenEnd, len, cur;
-+ UInt32 matchPrice, repMatchPrice, normalMatchPrice;
-+ UInt32 reps[LZMA_NUM_REPS], repLens[LZMA_NUM_REPS];
-+ UInt32 *matches;
-+ const Byte *data;
-+ Byte curByte, matchByte;
-+ if (p->optimumEndIndex != p->optimumCurrentIndex)
-+ {
-+ const COptimal *opt = &p->opt[p->optimumCurrentIndex];
-+ UInt32 lenRes = opt->posPrev - p->optimumCurrentIndex;
-+ *backRes = opt->backPrev;
-+ p->optimumCurrentIndex = opt->posPrev;
-+ return lenRes;
-+ }
-+ p->optimumCurrentIndex = p->optimumEndIndex = 0;
-+
-+ if (p->additionalOffset == 0)
-+ mainLen = ReadMatchDistances(p, &numPairs);
-+ else
-+ {
-+ mainLen = p->longestMatchLength;
-+ numPairs = p->numPairs;
-+ }
-+
-+ numAvail = p->numAvail;
-+ if (numAvail < 2)
-+ {
-+ *backRes = (UInt32)(-1);
-+ return 1;
-+ }
-+ if (numAvail > LZMA_MATCH_LEN_MAX)
-+ numAvail = LZMA_MATCH_LEN_MAX;
-+
-+ data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1;
-+ repMaxIndex = 0;
-+ for (i = 0; i < LZMA_NUM_REPS; i++)
-+ {
-+ UInt32 lenTest;
-+ const Byte *data2;
-+ reps[i] = p->reps[i];
-+ data2 = data - (reps[i] + 1);
-+ if (data[0] != data2[0] || data[1] != data2[1])
-+ {
-+ repLens[i] = 0;
-+ continue;
-+ }
-+ for (lenTest = 2; lenTest < numAvail && data[lenTest] == data2[lenTest]; lenTest++);
-+ repLens[i] = lenTest;
-+ if (lenTest > repLens[repMaxIndex])
-+ repMaxIndex = i;
-+ }
-+ if (repLens[repMaxIndex] >= p->numFastBytes)
-+ {
-+ UInt32 lenRes;
-+ *backRes = repMaxIndex;
-+ lenRes = repLens[repMaxIndex];
-+ MovePos(p, lenRes - 1);
-+ return lenRes;
-+ }
-+
-+ matches = p->matches;
-+ if (mainLen >= p->numFastBytes)
-+ {
-+ *backRes = matches[numPairs - 1] + LZMA_NUM_REPS;
-+ MovePos(p, mainLen - 1);
-+ return mainLen;
-+ }
-+ curByte = *data;
-+ matchByte = *(data - (reps[0] + 1));
-+
-+ if (mainLen < 2 && curByte != matchByte && repLens[repMaxIndex] < 2)
-+ {
-+ *backRes = (UInt32)-1;
-+ return 1;
-+ }
-+
-+ p->opt[0].state = (CState)p->state;
-+
-+ posState = (position & p->pbMask);
-+
-+ {
-+ const CLzmaProb *probs = LIT_PROBS(position, *(data - 1));
-+ p->opt[1].price = GET_PRICE_0(p->isMatch[p->state][posState]) +
-+ (!IsCharState(p->state) ?
-+ LitEnc_GetPriceMatched(probs, curByte, matchByte, p->ProbPrices) :
-+ LitEnc_GetPrice(probs, curByte, p->ProbPrices));
-+ }
-+
-+ MakeAsChar(&p->opt[1]);
-+
-+ matchPrice = GET_PRICE_1(p->isMatch[p->state][posState]);
-+ repMatchPrice = matchPrice + GET_PRICE_1(p->isRep[p->state]);
-+
-+ if (matchByte == curByte)
-+ {
-+ UInt32 shortRepPrice = repMatchPrice + GetRepLen1Price(p, p->state, posState);
-+ if (shortRepPrice < p->opt[1].price)
-+ {
-+ p->opt[1].price = shortRepPrice;
-+ MakeAsShortRep(&p->opt[1]);
-+ }
-+ }
-+ lenEnd = ((mainLen >= repLens[repMaxIndex]) ? mainLen : repLens[repMaxIndex]);
-+
-+ if (lenEnd < 2)
-+ {
-+ *backRes = p->opt[1].backPrev;
-+ return 1;
-+ }
-+
-+ p->opt[1].posPrev = 0;
-+ for (i = 0; i < LZMA_NUM_REPS; i++)
-+ p->opt[0].backs[i] = reps[i];
-+
-+ len = lenEnd;
-+ do
-+ p->opt[len--].price = kInfinityPrice;
-+ while (len >= 2);
-+
-+ for (i = 0; i < LZMA_NUM_REPS; i++)
-+ {
-+ UInt32 repLen = repLens[i];
-+ UInt32 price;
-+ if (repLen < 2)
-+ continue;
-+ price = repMatchPrice + GetPureRepPrice(p, i, p->state, posState);
-+ do
-+ {
-+ UInt32 curAndLenPrice = price + p->repLenEnc.prices[posState][repLen - 2];
-+ COptimal *opt = &p->opt[repLen];
-+ if (curAndLenPrice < opt->price)
-+ {
-+ opt->price = curAndLenPrice;
-+ opt->posPrev = 0;
-+ opt->backPrev = i;
-+ opt->prev1IsChar = False;
-+ }
-+ }
-+ while (--repLen >= 2);
-+ }
-+
-+ normalMatchPrice = matchPrice + GET_PRICE_0(p->isRep[p->state]);
-+
-+ len = ((repLens[0] >= 2) ? repLens[0] + 1 : 2);
-+ if (len <= mainLen)
-+ {
-+ UInt32 offs = 0;
-+ while (len > matches[offs])
-+ offs += 2;
-+ for (; ; len++)
-+ {
-+ COptimal *opt;
-+ UInt32 distance = matches[offs + 1];
-+
-+ UInt32 curAndLenPrice = normalMatchPrice + p->lenEnc.prices[posState][len - LZMA_MATCH_LEN_MIN];
-+ UInt32 lenToPosState = GetLenToPosState(len);
-+ if (distance < kNumFullDistances)
-+ curAndLenPrice += p->distancesPrices[lenToPosState][distance];
-+ else
-+ {
-+ UInt32 slot;
-+ GetPosSlot2(distance, slot);
-+ curAndLenPrice += p->alignPrices[distance & kAlignMask] + p->posSlotPrices[lenToPosState][slot];
-+ }
-+ opt = &p->opt[len];
-+ if (curAndLenPrice < opt->price)
-+ {
-+ opt->price = curAndLenPrice;
-+ opt->posPrev = 0;
-+ opt->backPrev = distance + LZMA_NUM_REPS;
-+ opt->prev1IsChar = False;
-+ }
-+ if (len == matches[offs])
-+ {
-+ offs += 2;
-+ if (offs == numPairs)
-+ break;
-+ }
-+ }
-+ }
-+
-+ cur = 0;
-+
-+ #ifdef SHOW_STAT2
-+ if (position >= 0)
-+ {
-+ unsigned i;
-+ printf("\n pos = %4X", position);
-+ for (i = cur; i <= lenEnd; i++)
-+ printf("\nprice[%4X] = %d", position - cur + i, p->opt[i].price);
-+ }
-+ #endif
-+
-+ for (;;)
-+ {
-+ UInt32 numAvailFull, newLen, numPairs, posPrev, state, posState, startLen;
-+ UInt32 curPrice, curAnd1Price, matchPrice, repMatchPrice;
-+ Bool nextIsChar;
-+ Byte curByte, matchByte;
-+ const Byte *data;
-+ COptimal *curOpt;
-+ COptimal *nextOpt;
-+
-+ cur++;
-+ if (cur == lenEnd)
-+ return Backward(p, backRes, cur);
-+
-+ newLen = ReadMatchDistances(p, &numPairs);
-+ if (newLen >= p->numFastBytes)
-+ {
-+ p->numPairs = numPairs;
-+ p->longestMatchLength = newLen;
-+ return Backward(p, backRes, cur);
-+ }
-+ position++;
-+ curOpt = &p->opt[cur];
-+ posPrev = curOpt->posPrev;
-+ if (curOpt->prev1IsChar)
-+ {
-+ posPrev--;
-+ if (curOpt->prev2)
-+ {
-+ state = p->opt[curOpt->posPrev2].state;
-+ if (curOpt->backPrev2 < LZMA_NUM_REPS)
-+ state = kRepNextStates[state];
-+ else
-+ state = kMatchNextStates[state];
-+ }
-+ else
-+ state = p->opt[posPrev].state;
-+ state = kLiteralNextStates[state];
-+ }
-+ else
-+ state = p->opt[posPrev].state;
-+ if (posPrev == cur - 1)
-+ {
-+ if (IsShortRep(curOpt))
-+ state = kShortRepNextStates[state];
-+ else
-+ state = kLiteralNextStates[state];
-+ }
-+ else
-+ {
-+ UInt32 pos;
-+ const COptimal *prevOpt;
-+ if (curOpt->prev1IsChar && curOpt->prev2)
-+ {
-+ posPrev = curOpt->posPrev2;
-+ pos = curOpt->backPrev2;
-+ state = kRepNextStates[state];
-+ }
-+ else
-+ {
-+ pos = curOpt->backPrev;
-+ if (pos < LZMA_NUM_REPS)
-+ state = kRepNextStates[state];
-+ else
-+ state = kMatchNextStates[state];
-+ }
-+ prevOpt = &p->opt[posPrev];
-+ if (pos < LZMA_NUM_REPS)
-+ {
-+ UInt32 i;
-+ reps[0] = prevOpt->backs[pos];
-+ for (i = 1; i <= pos; i++)
-+ reps[i] = prevOpt->backs[i - 1];
-+ for (; i < LZMA_NUM_REPS; i++)
-+ reps[i] = prevOpt->backs[i];
-+ }
-+ else
-+ {
-+ UInt32 i;
-+ reps[0] = (pos - LZMA_NUM_REPS);
-+ for (i = 1; i < LZMA_NUM_REPS; i++)
-+ reps[i] = prevOpt->backs[i - 1];
-+ }
-+ }
-+ curOpt->state = (CState)state;
-+
-+ curOpt->backs[0] = reps[0];
-+ curOpt->backs[1] = reps[1];
-+ curOpt->backs[2] = reps[2];
-+ curOpt->backs[3] = reps[3];
-+
-+ curPrice = curOpt->price;
-+ nextIsChar = False;
-+ data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1;
-+ curByte = *data;
-+ matchByte = *(data - (reps[0] + 1));
-+
-+ posState = (position & p->pbMask);
-+
-+ curAnd1Price = curPrice + GET_PRICE_0(p->isMatch[state][posState]);
-+ {
-+ const CLzmaProb *probs = LIT_PROBS(position, *(data - 1));
-+ curAnd1Price +=
-+ (!IsCharState(state) ?
-+ LitEnc_GetPriceMatched(probs, curByte, matchByte, p->ProbPrices) :
-+ LitEnc_GetPrice(probs, curByte, p->ProbPrices));
-+ }
-+
-+ nextOpt = &p->opt[cur + 1];
-+
-+ if (curAnd1Price < nextOpt->price)
-+ {
-+ nextOpt->price = curAnd1Price;
-+ nextOpt->posPrev = cur;
-+ MakeAsChar(nextOpt);
-+ nextIsChar = True;
-+ }
-+
-+ matchPrice = curPrice + GET_PRICE_1(p->isMatch[state][posState]);
-+ repMatchPrice = matchPrice + GET_PRICE_1(p->isRep[state]);
-+
-+ if (matchByte == curByte && !(nextOpt->posPrev < cur && nextOpt->backPrev == 0))
-+ {
-+ UInt32 shortRepPrice = repMatchPrice + GetRepLen1Price(p, state, posState);
-+ if (shortRepPrice <= nextOpt->price)
-+ {
-+ nextOpt->price = shortRepPrice;
-+ nextOpt->posPrev = cur;
-+ MakeAsShortRep(nextOpt);
-+ nextIsChar = True;
-+ }
-+ }
-+ numAvailFull = p->numAvail;
-+ {
-+ UInt32 temp = kNumOpts - 1 - cur;
-+ if (temp < numAvailFull)
-+ numAvailFull = temp;
-+ }
-+
-+ if (numAvailFull < 2)
-+ continue;
-+ numAvail = (numAvailFull <= p->numFastBytes ? numAvailFull : p->numFastBytes);
-+
-+ if (!nextIsChar && matchByte != curByte) /* speed optimization */
-+ {
-+ /* try Literal + rep0 */
-+ UInt32 temp;
-+ UInt32 lenTest2;
-+ const Byte *data2 = data - (reps[0] + 1);
-+ UInt32 limit = p->numFastBytes + 1;
-+ if (limit > numAvailFull)
-+ limit = numAvailFull;
-+
-+ for (temp = 1; temp < limit && data[temp] == data2[temp]; temp++);
-+ lenTest2 = temp - 1;
-+ if (lenTest2 >= 2)
-+ {
-+ UInt32 state2 = kLiteralNextStates[state];
-+ UInt32 posStateNext = (position + 1) & p->pbMask;
-+ UInt32 nextRepMatchPrice = curAnd1Price +
-+ GET_PRICE_1(p->isMatch[state2][posStateNext]) +
-+ GET_PRICE_1(p->isRep[state2]);
-+ /* for (; lenTest2 >= 2; lenTest2--) */
-+ {
-+ UInt32 curAndLenPrice;
-+ COptimal *opt;
-+ UInt32 offset = cur + 1 + lenTest2;
-+ while (lenEnd < offset)
-+ p->opt[++lenEnd].price = kInfinityPrice;
-+ curAndLenPrice = nextRepMatchPrice + GetRepPrice(p, 0, lenTest2, state2, posStateNext);
-+ opt = &p->opt[offset];
-+ if (curAndLenPrice < opt->price)
-+ {
-+ opt->price = curAndLenPrice;
-+ opt->posPrev = cur + 1;
-+ opt->backPrev = 0;
-+ opt->prev1IsChar = True;
-+ opt->prev2 = False;
-+ }
-+ }
-+ }
-+ }
-+
-+ startLen = 2; /* speed optimization */
-+ {
-+ UInt32 repIndex;
-+ for (repIndex = 0; repIndex < LZMA_NUM_REPS; repIndex++)
-+ {
-+ UInt32 lenTest;
-+ UInt32 lenTestTemp;
-+ UInt32 price;
-+ const Byte *data2 = data - (reps[repIndex] + 1);
-+ if (data[0] != data2[0] || data[1] != data2[1])
-+ continue;
-+ for (lenTest = 2; lenTest < numAvail && data[lenTest] == data2[lenTest]; lenTest++);
-+ while (lenEnd < cur + lenTest)
-+ p->opt[++lenEnd].price = kInfinityPrice;
-+ lenTestTemp = lenTest;
-+ price = repMatchPrice + GetPureRepPrice(p, repIndex, state, posState);
-+ do
-+ {
-+ UInt32 curAndLenPrice = price + p->repLenEnc.prices[posState][lenTest - 2];
-+ COptimal *opt = &p->opt[cur + lenTest];
-+ if (curAndLenPrice < opt->price)
-+ {
-+ opt->price = curAndLenPrice;
-+ opt->posPrev = cur;
-+ opt->backPrev = repIndex;
-+ opt->prev1IsChar = False;
-+ }
-+ }
-+ while (--lenTest >= 2);
-+ lenTest = lenTestTemp;
-+
-+ if (repIndex == 0)
-+ startLen = lenTest + 1;
-+
-+ /* if (_maxMode) */
-+ {
-+ UInt32 lenTest2 = lenTest + 1;
-+ UInt32 limit = lenTest2 + p->numFastBytes;
-+ UInt32 nextRepMatchPrice;
-+ if (limit > numAvailFull)
-+ limit = numAvailFull;
-+ for (; lenTest2 < limit && data[lenTest2] == data2[lenTest2]; lenTest2++);
-+ lenTest2 -= lenTest + 1;
-+ if (lenTest2 >= 2)
-+ {
-+ UInt32 state2 = kRepNextStates[state];
-+ UInt32 posStateNext = (position + lenTest) & p->pbMask;
-+ UInt32 curAndLenCharPrice =
-+ price + p->repLenEnc.prices[posState][lenTest - 2] +
-+ GET_PRICE_0(p->isMatch[state2][posStateNext]) +
-+ LitEnc_GetPriceMatched(LIT_PROBS(position + lenTest, data[lenTest - 1]),
-+ data[lenTest], data2[lenTest], p->ProbPrices);
-+ state2 = kLiteralNextStates[state2];
-+ posStateNext = (position + lenTest + 1) & p->pbMask;
-+ nextRepMatchPrice = curAndLenCharPrice +
-+ GET_PRICE_1(p->isMatch[state2][posStateNext]) +
-+ GET_PRICE_1(p->isRep[state2]);
-+
-+ /* for (; lenTest2 >= 2; lenTest2--) */
-+ {
-+ UInt32 curAndLenPrice;
-+ COptimal *opt;
-+ UInt32 offset = cur + lenTest + 1 + lenTest2;
-+ while (lenEnd < offset)
-+ p->opt[++lenEnd].price = kInfinityPrice;
-+ curAndLenPrice = nextRepMatchPrice + GetRepPrice(p, 0, lenTest2, state2, posStateNext);
-+ opt = &p->opt[offset];
-+ if (curAndLenPrice < opt->price)
-+ {
-+ opt->price = curAndLenPrice;
-+ opt->posPrev = cur + lenTest + 1;
-+ opt->backPrev = 0;
-+ opt->prev1IsChar = True;
-+ opt->prev2 = True;
-+ opt->posPrev2 = cur;
-+ opt->backPrev2 = repIndex;
-+ }
-+ }
-+ }
-+ }
-+ }
-+ }
-+ /* for (UInt32 lenTest = 2; lenTest <= newLen; lenTest++) */
-+ if (newLen > numAvail)
-+ {
-+ newLen = numAvail;
-+ for (numPairs = 0; newLen > matches[numPairs]; numPairs += 2);
-+ matches[numPairs] = newLen;
-+ numPairs += 2;
-+ }
-+ if (newLen >= startLen)
-+ {
-+ UInt32 normalMatchPrice = matchPrice + GET_PRICE_0(p->isRep[state]);
-+ UInt32 offs, curBack, posSlot;
-+ UInt32 lenTest;
-+ while (lenEnd < cur + newLen)
-+ p->opt[++lenEnd].price = kInfinityPrice;
-+
-+ offs = 0;
-+ while (startLen > matches[offs])
-+ offs += 2;
-+ curBack = matches[offs + 1];
-+ GetPosSlot2(curBack, posSlot);
-+ for (lenTest = /*2*/ startLen; ; lenTest++)
-+ {
-+ UInt32 curAndLenPrice = normalMatchPrice + p->lenEnc.prices[posState][lenTest - LZMA_MATCH_LEN_MIN];
-+ UInt32 lenToPosState = GetLenToPosState(lenTest);
-+ COptimal *opt;
-+ if (curBack < kNumFullDistances)
-+ curAndLenPrice += p->distancesPrices[lenToPosState][curBack];
-+ else
-+ curAndLenPrice += p->posSlotPrices[lenToPosState][posSlot] + p->alignPrices[curBack & kAlignMask];
-+
-+ opt = &p->opt[cur + lenTest];
-+ if (curAndLenPrice < opt->price)
-+ {
-+ opt->price = curAndLenPrice;
-+ opt->posPrev = cur;
-+ opt->backPrev = curBack + LZMA_NUM_REPS;
-+ opt->prev1IsChar = False;
-+ }
-+
-+ if (/*_maxMode && */lenTest == matches[offs])
-+ {
-+ /* Try Match + Literal + Rep0 */
-+ const Byte *data2 = data - (curBack + 1);
-+ UInt32 lenTest2 = lenTest + 1;
-+ UInt32 limit = lenTest2 + p->numFastBytes;
-+ UInt32 nextRepMatchPrice;
-+ if (limit > numAvailFull)
-+ limit = numAvailFull;
-+ for (; lenTest2 < limit && data[lenTest2] == data2[lenTest2]; lenTest2++);
-+ lenTest2 -= lenTest + 1;
-+ if (lenTest2 >= 2)
-+ {
-+ UInt32 state2 = kMatchNextStates[state];
-+ UInt32 posStateNext = (position + lenTest) & p->pbMask;
-+ UInt32 curAndLenCharPrice = curAndLenPrice +
-+ GET_PRICE_0(p->isMatch[state2][posStateNext]) +
-+ LitEnc_GetPriceMatched(LIT_PROBS(position + lenTest, data[lenTest - 1]),
-+ data[lenTest], data2[lenTest], p->ProbPrices);
-+ state2 = kLiteralNextStates[state2];
-+ posStateNext = (posStateNext + 1) & p->pbMask;
-+ nextRepMatchPrice = curAndLenCharPrice +
-+ GET_PRICE_1(p->isMatch[state2][posStateNext]) +
-+ GET_PRICE_1(p->isRep[state2]);
-+
-+ /* for (; lenTest2 >= 2; lenTest2--) */
-+ {
-+ UInt32 offset = cur + lenTest + 1 + lenTest2;
-+ UInt32 curAndLenPrice;
-+ COptimal *opt;
-+ while (lenEnd < offset)
-+ p->opt[++lenEnd].price = kInfinityPrice;
-+ curAndLenPrice = nextRepMatchPrice + GetRepPrice(p, 0, lenTest2, state2, posStateNext);
-+ opt = &p->opt[offset];
-+ if (curAndLenPrice < opt->price)
-+ {
-+ opt->price = curAndLenPrice;
-+ opt->posPrev = cur + lenTest + 1;
-+ opt->backPrev = 0;
-+ opt->prev1IsChar = True;
-+ opt->prev2 = True;
-+ opt->posPrev2 = cur;
-+ opt->backPrev2 = curBack + LZMA_NUM_REPS;
-+ }
-+ }
-+ }
-+ offs += 2;
-+ if (offs == numPairs)
-+ break;
-+ curBack = matches[offs + 1];
-+ if (curBack >= kNumFullDistances)
-+ GetPosSlot2(curBack, posSlot);
-+ }
-+ }
-+ }
-+ }
-+}
-+
-+#define ChangePair(smallDist, bigDist) (((bigDist) >> 7) > (smallDist))
-+
-+static UInt32 GetOptimumFast(CLzmaEnc *p, UInt32 *backRes)
-+{
-+ UInt32 numAvail, mainLen, mainDist, numPairs, repIndex, repLen, i;
-+ const Byte *data;
-+ const UInt32 *matches;
-+
-+ if (p->additionalOffset == 0)
-+ mainLen = ReadMatchDistances(p, &numPairs);
-+ else
-+ {
-+ mainLen = p->longestMatchLength;
-+ numPairs = p->numPairs;
-+ }
-+
-+ numAvail = p->numAvail;
-+ *backRes = (UInt32)-1;
-+ if (numAvail < 2)
-+ return 1;
-+ if (numAvail > LZMA_MATCH_LEN_MAX)
-+ numAvail = LZMA_MATCH_LEN_MAX;
-+ data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1;
-+
-+ repLen = repIndex = 0;
-+ for (i = 0; i < LZMA_NUM_REPS; i++)
-+ {
-+ UInt32 len;
-+ const Byte *data2 = data - (p->reps[i] + 1);
-+ if (data[0] != data2[0] || data[1] != data2[1])
-+ continue;
-+ for (len = 2; len < numAvail && data[len] == data2[len]; len++);
-+ if (len >= p->numFastBytes)
-+ {
-+ *backRes = i;
-+ MovePos(p, len - 1);
-+ return len;
-+ }
-+ if (len > repLen)
-+ {
-+ repIndex = i;
-+ repLen = len;
-+ }
-+ }
-+
-+ matches = p->matches;
-+ if (mainLen >= p->numFastBytes)
-+ {
-+ *backRes = matches[numPairs - 1] + LZMA_NUM_REPS;
-+ MovePos(p, mainLen - 1);
-+ return mainLen;
-+ }
-+
-+ mainDist = 0; /* for GCC */
-+ if (mainLen >= 2)
-+ {
-+ mainDist = matches[numPairs - 1];
-+ while (numPairs > 2 && mainLen == matches[numPairs - 4] + 1)
-+ {
-+ if (!ChangePair(matches[numPairs - 3], mainDist))
-+ break;
-+ numPairs -= 2;
-+ mainLen = matches[numPairs - 2];
-+ mainDist = matches[numPairs - 1];
-+ }
-+ if (mainLen == 2 && mainDist >= 0x80)
-+ mainLen = 1;
-+ }
-+
-+ if (repLen >= 2 && (
-+ (repLen + 1 >= mainLen) ||
-+ (repLen + 2 >= mainLen && mainDist >= (1 << 9)) ||
-+ (repLen + 3 >= mainLen && mainDist >= (1 << 15))))
-+ {
-+ *backRes = repIndex;
-+ MovePos(p, repLen - 1);
-+ return repLen;
-+ }
-+
-+ if (mainLen < 2 || numAvail <= 2)
-+ return 1;
-+
-+ p->longestMatchLength = ReadMatchDistances(p, &p->numPairs);
-+ if (p->longestMatchLength >= 2)
-+ {
-+ UInt32 newDistance = matches[p->numPairs - 1];
-+ if ((p->longestMatchLength >= mainLen && newDistance < mainDist) ||
-+ (p->longestMatchLength == mainLen + 1 && !ChangePair(mainDist, newDistance)) ||
-+ (p->longestMatchLength > mainLen + 1) ||
-+ (p->longestMatchLength + 1 >= mainLen && mainLen >= 3 && ChangePair(newDistance, mainDist)))
-+ return 1;
-+ }
-+
-+ data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1;
-+ for (i = 0; i < LZMA_NUM_REPS; i++)
-+ {
-+ UInt32 len, limit;
-+ const Byte *data2 = data - (p->reps[i] + 1);
-+ if (data[0] != data2[0] || data[1] != data2[1])
-+ continue;
-+ limit = mainLen - 1;
-+ for (len = 2; len < limit && data[len] == data2[len]; len++);
-+ if (len >= limit)
-+ return 1;
-+ }
-+ *backRes = mainDist + LZMA_NUM_REPS;
-+ MovePos(p, mainLen - 2);
-+ return mainLen;
-+}
-+
-+static void WriteEndMarker(CLzmaEnc *p, UInt32 posState)
-+{
-+ UInt32 len;
-+ RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][posState], 1);
-+ RangeEnc_EncodeBit(&p->rc, &p->isRep[p->state], 0);
-+ p->state = kMatchNextStates[p->state];
-+ len = LZMA_MATCH_LEN_MIN;
-+ LenEnc_Encode2(&p->lenEnc, &p->rc, len - LZMA_MATCH_LEN_MIN, posState, !p->fastMode, p->ProbPrices);
-+ RcTree_Encode(&p->rc, p->posSlotEncoder[GetLenToPosState(len)], kNumPosSlotBits, (1 << kNumPosSlotBits) - 1);
-+ RangeEnc_EncodeDirectBits(&p->rc, (((UInt32)1 << 30) - 1) >> kNumAlignBits, 30 - kNumAlignBits);
-+ RcTree_ReverseEncode(&p->rc, p->posAlignEncoder, kNumAlignBits, kAlignMask);
-+}
-+
-+static SRes CheckErrors(CLzmaEnc *p)
-+{
-+ if (p->result != SZ_OK)
-+ return p->result;
-+ if (p->rc.res != SZ_OK)
-+ p->result = SZ_ERROR_WRITE;
-+ if (p->matchFinderBase.result != SZ_OK)
-+ p->result = SZ_ERROR_READ;
-+ if (p->result != SZ_OK)
-+ p->finished = True;
-+ return p->result;
-+}
-+
-+static SRes Flush(CLzmaEnc *p, UInt32 nowPos)
-+{
-+ /* ReleaseMFStream(); */
-+ p->finished = True;
-+ if (p->writeEndMark)
-+ WriteEndMarker(p, nowPos & p->pbMask);
-+ RangeEnc_FlushData(&p->rc);
-+ RangeEnc_FlushStream(&p->rc);
-+ return CheckErrors(p);
-+}
-+
-+static void FillAlignPrices(CLzmaEnc *p)
-+{
-+ UInt32 i;
-+ for (i = 0; i < kAlignTableSize; i++)
-+ p->alignPrices[i] = RcTree_ReverseGetPrice(p->posAlignEncoder, kNumAlignBits, i, p->ProbPrices);
-+ p->alignPriceCount = 0;
-+}
-+
-+static void FillDistancesPrices(CLzmaEnc *p)
-+{
-+ UInt32 tempPrices[kNumFullDistances];
-+ UInt32 i, lenToPosState;
-+ for (i = kStartPosModelIndex; i < kNumFullDistances; i++)
-+ {
-+ UInt32 posSlot = GetPosSlot1(i);
-+ UInt32 footerBits = ((posSlot >> 1) - 1);
-+ UInt32 base = ((2 | (posSlot & 1)) << footerBits);
-+ tempPrices[i] = RcTree_ReverseGetPrice(p->posEncoders + base - posSlot - 1, footerBits, i - base, p->ProbPrices);
-+ }
-+
-+ for (lenToPosState = 0; lenToPosState < kNumLenToPosStates; lenToPosState++)
-+ {
-+ UInt32 posSlot;
-+ const CLzmaProb *encoder = p->posSlotEncoder[lenToPosState];
-+ UInt32 *posSlotPrices = p->posSlotPrices[lenToPosState];
-+ for (posSlot = 0; posSlot < p->distTableSize; posSlot++)
-+ posSlotPrices[posSlot] = RcTree_GetPrice(encoder, kNumPosSlotBits, posSlot, p->ProbPrices);
-+ for (posSlot = kEndPosModelIndex; posSlot < p->distTableSize; posSlot++)
-+ posSlotPrices[posSlot] += ((((posSlot >> 1) - 1) - kNumAlignBits) << kNumBitPriceShiftBits);
-+
-+ {
-+ UInt32 *distancesPrices = p->distancesPrices[lenToPosState];
-+ UInt32 i;
-+ for (i = 0; i < kStartPosModelIndex; i++)
-+ distancesPrices[i] = posSlotPrices[i];
-+ for (; i < kNumFullDistances; i++)
-+ distancesPrices[i] = posSlotPrices[GetPosSlot1(i)] + tempPrices[i];
-+ }
-+ }
-+ p->matchPriceCount = 0;
-+}
-+
-+void LzmaEnc_Construct(CLzmaEnc *p)
-+{
-+ RangeEnc_Construct(&p->rc);
-+ MatchFinder_Construct(&p->matchFinderBase);
-+ #ifndef _7ZIP_ST
-+ MatchFinderMt_Construct(&p->matchFinderMt);
-+ p->matchFinderMt.MatchFinder = &p->matchFinderBase;
-+ #endif
-+
-+ {
-+ CLzmaEncProps props;
-+ LzmaEncProps_Init(&props);
-+ LzmaEnc_SetProps(p, &props);
-+ }
-+
-+ #ifndef LZMA_LOG_BSR
-+ LzmaEnc_FastPosInit(p->g_FastPos);
-+ #endif
-+
-+ LzmaEnc_InitPriceTables(p->ProbPrices);
-+ p->litProbs = 0;
-+ p->saveState.litProbs = 0;
-+}
-+
-+CLzmaEncHandle LzmaEnc_Create(ISzAlloc *alloc)
-+{
-+ void *p;
-+ p = alloc->Alloc(alloc, sizeof(CLzmaEnc));
-+ if (p != 0)
-+ LzmaEnc_Construct((CLzmaEnc *)p);
-+ return p;
-+}
-+
-+void LzmaEnc_FreeLits(CLzmaEnc *p, ISzAlloc *alloc)
-+{
-+ alloc->Free(alloc, p->litProbs);
-+ alloc->Free(alloc, p->saveState.litProbs);
-+ p->litProbs = 0;
-+ p->saveState.litProbs = 0;
-+}
-+
-+void LzmaEnc_Destruct(CLzmaEnc *p, ISzAlloc *alloc, ISzAlloc *allocBig)
-+{
-+ #ifndef _7ZIP_ST
-+ MatchFinderMt_Destruct(&p->matchFinderMt, allocBig);
-+ #endif
-+ MatchFinder_Free(&p->matchFinderBase, allocBig);
-+ LzmaEnc_FreeLits(p, alloc);
-+ RangeEnc_Free(&p->rc, alloc);
-+}
-+
-+void LzmaEnc_Destroy(CLzmaEncHandle p, ISzAlloc *alloc, ISzAlloc *allocBig)
-+{
-+ LzmaEnc_Destruct((CLzmaEnc *)p, alloc, allocBig);
-+ alloc->Free(alloc, p);
-+}
-+
-+static SRes LzmaEnc_CodeOneBlock(CLzmaEnc *p, Bool useLimits, UInt32 maxPackSize, UInt32 maxUnpackSize)
-+{
-+ UInt32 nowPos32, startPos32;
-+ if (p->needInit)
-+ {
-+ p->matchFinder.Init(p->matchFinderObj);
-+ p->needInit = 0;
-+ }
-+
-+ if (p->finished)
-+ return p->result;
-+ RINOK(CheckErrors(p));
-+
-+ nowPos32 = (UInt32)p->nowPos64;
-+ startPos32 = nowPos32;
-+
-+ if (p->nowPos64 == 0)
-+ {
-+ UInt32 numPairs;
-+ Byte curByte;
-+ if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) == 0)
-+ return Flush(p, nowPos32);
-+ ReadMatchDistances(p, &numPairs);
-+ RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][0], 0);
-+ p->state = kLiteralNextStates[p->state];
-+ curByte = p->matchFinder.GetIndexByte(p->matchFinderObj, 0 - p->additionalOffset);
-+ LitEnc_Encode(&p->rc, p->litProbs, curByte);
-+ p->additionalOffset--;
-+ nowPos32++;
-+ }
-+
-+ if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) != 0)
-+ for (;;)
-+ {
-+ UInt32 pos, len, posState;
-+
-+ if (p->fastMode)
-+ len = GetOptimumFast(p, &pos);
-+ else
-+ len = GetOptimum(p, nowPos32, &pos);
-+
-+ #ifdef SHOW_STAT2
-+ printf("\n pos = %4X, len = %d pos = %d", nowPos32, len, pos);
-+ #endif
-+
-+ posState = nowPos32 & p->pbMask;
-+ if (len == 1 && pos == (UInt32)-1)
-+ {
-+ Byte curByte;
-+ CLzmaProb *probs;
-+ const Byte *data;
-+
-+ RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][posState], 0);
-+ data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset;
-+ curByte = *data;
-+ probs = LIT_PROBS(nowPos32, *(data - 1));
-+ if (IsCharState(p->state))
-+ LitEnc_Encode(&p->rc, probs, curByte);
-+ else
-+ LitEnc_EncodeMatched(&p->rc, probs, curByte, *(data - p->reps[0] - 1));
-+ p->state = kLiteralNextStates[p->state];
-+ }
-+ else
-+ {
-+ RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][posState], 1);
-+ if (pos < LZMA_NUM_REPS)
-+ {
-+ RangeEnc_EncodeBit(&p->rc, &p->isRep[p->state], 1);
-+ if (pos == 0)
-+ {
-+ RangeEnc_EncodeBit(&p->rc, &p->isRepG0[p->state], 0);
-+ RangeEnc_EncodeBit(&p->rc, &p->isRep0Long[p->state][posState], ((len == 1) ? 0 : 1));
-+ }
-+ else
-+ {
-+ UInt32 distance = p->reps[pos];
-+ RangeEnc_EncodeBit(&p->rc, &p->isRepG0[p->state], 1);
-+ if (pos == 1)
-+ RangeEnc_EncodeBit(&p->rc, &p->isRepG1[p->state], 0);
-+ else
-+ {
-+ RangeEnc_EncodeBit(&p->rc, &p->isRepG1[p->state], 1);
-+ RangeEnc_EncodeBit(&p->rc, &p->isRepG2[p->state], pos - 2);
-+ if (pos == 3)
-+ p->reps[3] = p->reps[2];
-+ p->reps[2] = p->reps[1];
-+ }
-+ p->reps[1] = p->reps[0];
-+ p->reps[0] = distance;
-+ }
-+ if (len == 1)
-+ p->state = kShortRepNextStates[p->state];
-+ else
-+ {
-+ LenEnc_Encode2(&p->repLenEnc, &p->rc, len - LZMA_MATCH_LEN_MIN, posState, !p->fastMode, p->ProbPrices);
-+ p->state = kRepNextStates[p->state];
-+ }
-+ }
-+ else
-+ {
-+ UInt32 posSlot;
-+ RangeEnc_EncodeBit(&p->rc, &p->isRep[p->state], 0);
-+ p->state = kMatchNextStates[p->state];
-+ LenEnc_Encode2(&p->lenEnc, &p->rc, len - LZMA_MATCH_LEN_MIN, posState, !p->fastMode, p->ProbPrices);
-+ pos -= LZMA_NUM_REPS;
-+ GetPosSlot(pos, posSlot);
-+ RcTree_Encode(&p->rc, p->posSlotEncoder[GetLenToPosState(len)], kNumPosSlotBits, posSlot);
-+
-+ if (posSlot >= kStartPosModelIndex)
-+ {
-+ UInt32 footerBits = ((posSlot >> 1) - 1);
-+ UInt32 base = ((2 | (posSlot & 1)) << footerBits);
-+ UInt32 posReduced = pos - base;
-+
-+ if (posSlot < kEndPosModelIndex)
-+ RcTree_ReverseEncode(&p->rc, p->posEncoders + base - posSlot - 1, footerBits, posReduced);
-+ else
-+ {
-+ RangeEnc_EncodeDirectBits(&p->rc, posReduced >> kNumAlignBits, footerBits - kNumAlignBits);
-+ RcTree_ReverseEncode(&p->rc, p->posAlignEncoder, kNumAlignBits, posReduced & kAlignMask);
-+ p->alignPriceCount++;
-+ }
-+ }
-+ p->reps[3] = p->reps[2];
-+ p->reps[2] = p->reps[1];
-+ p->reps[1] = p->reps[0];
-+ p->reps[0] = pos;
-+ p->matchPriceCount++;
-+ }
-+ }
-+ p->additionalOffset -= len;
-+ nowPos32 += len;
-+ if (p->additionalOffset == 0)
-+ {
-+ UInt32 processed;
-+ if (!p->fastMode)
-+ {
-+ if (p->matchPriceCount >= (1 << 7))
-+ FillDistancesPrices(p);
-+ if (p->alignPriceCount >= kAlignTableSize)
-+ FillAlignPrices(p);
-+ }
-+ if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) == 0)
-+ break;
-+ processed = nowPos32 - startPos32;
-+ if (useLimits)
-+ {
-+ if (processed + kNumOpts + 300 >= maxUnpackSize ||
-+ RangeEnc_GetProcessed(&p->rc) + kNumOpts * 2 >= maxPackSize)
-+ break;
-+ }
-+ else if (processed >= (1 << 15))
-+ {
-+ p->nowPos64 += nowPos32 - startPos32;
-+ return CheckErrors(p);
-+ }
-+ }
-+ }
-+ p->nowPos64 += nowPos32 - startPos32;
-+ return Flush(p, nowPos32);
-+}
-+
-+#define kBigHashDicLimit ((UInt32)1 << 24)
-+
-+static SRes LzmaEnc_Alloc(CLzmaEnc *p, UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig)
-+{
-+ UInt32 beforeSize = kNumOpts;
-+ Bool btMode;
-+ if (!RangeEnc_Alloc(&p->rc, alloc))
-+ return SZ_ERROR_MEM;
-+ btMode = (p->matchFinderBase.btMode != 0);
-+ #ifndef _7ZIP_ST
-+ p->mtMode = (p->multiThread && !p->fastMode && btMode);
-+ #endif
-+
-+ {
-+ unsigned lclp = p->lc + p->lp;
-+ if (p->litProbs == 0 || p->saveState.litProbs == 0 || p->lclp != lclp)
-+ {
-+ LzmaEnc_FreeLits(p, alloc);
-+ p->litProbs = (CLzmaProb *)alloc->Alloc(alloc, (0x300 << lclp) * sizeof(CLzmaProb));
-+ p->saveState.litProbs = (CLzmaProb *)alloc->Alloc(alloc, (0x300 << lclp) * sizeof(CLzmaProb));
-+ if (p->litProbs == 0 || p->saveState.litProbs == 0)
-+ {
-+ LzmaEnc_FreeLits(p, alloc);
-+ return SZ_ERROR_MEM;
-+ }
-+ p->lclp = lclp;
-+ }
-+ }
-+
-+ p->matchFinderBase.bigHash = (p->dictSize > kBigHashDicLimit);
-+
-+ if (beforeSize + p->dictSize < keepWindowSize)
-+ beforeSize = keepWindowSize - p->dictSize;
-+
-+ #ifndef _7ZIP_ST
-+ if (p->mtMode)
-+ {
-+ RINOK(MatchFinderMt_Create(&p->matchFinderMt, p->dictSize, beforeSize, p->numFastBytes, LZMA_MATCH_LEN_MAX, allocBig));
-+ p->matchFinderObj = &p->matchFinderMt;
-+ MatchFinderMt_CreateVTable(&p->matchFinderMt, &p->matchFinder);
-+ }
-+ else
-+ #endif
-+ {
-+ if (!MatchFinder_Create(&p->matchFinderBase, p->dictSize, beforeSize, p->numFastBytes, LZMA_MATCH_LEN_MAX, allocBig))
-+ return SZ_ERROR_MEM;
-+ p->matchFinderObj = &p->matchFinderBase;
-+ MatchFinder_CreateVTable(&p->matchFinderBase, &p->matchFinder);
-+ }
-+ return SZ_OK;
-+}
-+
-+void LzmaEnc_Init(CLzmaEnc *p)
-+{
-+ UInt32 i;
-+ p->state = 0;
-+ for (i = 0 ; i < LZMA_NUM_REPS; i++)
-+ p->reps[i] = 0;
-+
-+ RangeEnc_Init(&p->rc);
-+
-+
-+ for (i = 0; i < kNumStates; i++)
-+ {
-+ UInt32 j;
-+ for (j = 0; j < LZMA_NUM_PB_STATES_MAX; j++)
-+ {
-+ p->isMatch[i][j] = kProbInitValue;
-+ p->isRep0Long[i][j] = kProbInitValue;
-+ }
-+ p->isRep[i] = kProbInitValue;
-+ p->isRepG0[i] = kProbInitValue;
-+ p->isRepG1[i] = kProbInitValue;
-+ p->isRepG2[i] = kProbInitValue;
-+ }
-+
-+ {
-+ UInt32 num = 0x300 << (p->lp + p->lc);
-+ for (i = 0; i < num; i++)
-+ p->litProbs[i] = kProbInitValue;
-+ }
-+
-+ {
-+ for (i = 0; i < kNumLenToPosStates; i++)
-+ {
-+ CLzmaProb *probs = p->posSlotEncoder[i];
-+ UInt32 j;
-+ for (j = 0; j < (1 << kNumPosSlotBits); j++)
-+ probs[j] = kProbInitValue;
-+ }
-+ }
-+ {
-+ for (i = 0; i < kNumFullDistances - kEndPosModelIndex; i++)
-+ p->posEncoders[i] = kProbInitValue;
-+ }
-+
-+ LenEnc_Init(&p->lenEnc.p);
-+ LenEnc_Init(&p->repLenEnc.p);
-+
-+ for (i = 0; i < (1 << kNumAlignBits); i++)
-+ p->posAlignEncoder[i] = kProbInitValue;
-+
-+ p->optimumEndIndex = 0;
-+ p->optimumCurrentIndex = 0;
-+ p->additionalOffset = 0;
-+
-+ p->pbMask = (1 << p->pb) - 1;
-+ p->lpMask = (1 << p->lp) - 1;
-+}
-+
-+void LzmaEnc_InitPrices(CLzmaEnc *p)
-+{
-+ if (!p->fastMode)
-+ {
-+ FillDistancesPrices(p);
-+ FillAlignPrices(p);
-+ }
-+
-+ p->lenEnc.tableSize =
-+ p->repLenEnc.tableSize =
-+ p->numFastBytes + 1 - LZMA_MATCH_LEN_MIN;
-+ LenPriceEnc_UpdateTables(&p->lenEnc, 1 << p->pb, p->ProbPrices);
-+ LenPriceEnc_UpdateTables(&p->repLenEnc, 1 << p->pb, p->ProbPrices);
-+}
-+
-+static SRes LzmaEnc_AllocAndInit(CLzmaEnc *p, UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig)
-+{
-+ UInt32 i;
-+ for (i = 0; i < (UInt32)kDicLogSizeMaxCompress; i++)
-+ if (p->dictSize <= ((UInt32)1 << i))
-+ break;
-+ p->distTableSize = i * 2;
-+
-+ p->finished = False;
-+ p->result = SZ_OK;
-+ RINOK(LzmaEnc_Alloc(p, keepWindowSize, alloc, allocBig));
-+ LzmaEnc_Init(p);
-+ LzmaEnc_InitPrices(p);
-+ p->nowPos64 = 0;
-+ return SZ_OK;
-+}
-+
-+static SRes LzmaEnc_Prepare(CLzmaEncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream,
-+ ISzAlloc *alloc, ISzAlloc *allocBig)
-+{
-+ CLzmaEnc *p = (CLzmaEnc *)pp;
-+ p->matchFinderBase.stream = inStream;
-+ p->needInit = 1;
-+ p->rc.outStream = outStream;
-+ return LzmaEnc_AllocAndInit(p, 0, alloc, allocBig);
-+}
-+
-+SRes LzmaEnc_PrepareForLzma2(CLzmaEncHandle pp,
-+ ISeqInStream *inStream, UInt32 keepWindowSize,
-+ ISzAlloc *alloc, ISzAlloc *allocBig)
-+{
-+ CLzmaEnc *p = (CLzmaEnc *)pp;
-+ p->matchFinderBase.stream = inStream;
-+ p->needInit = 1;
-+ return LzmaEnc_AllocAndInit(p, keepWindowSize, alloc, allocBig);
-+}
-+
-+static void LzmaEnc_SetInputBuf(CLzmaEnc *p, const Byte *src, SizeT srcLen)
-+{
-+ p->matchFinderBase.directInput = 1;
-+ p->matchFinderBase.bufferBase = (Byte *)src;
-+ p->matchFinderBase.directInputRem = srcLen;
-+}
-+
-+SRes LzmaEnc_MemPrepare(CLzmaEncHandle pp, const Byte *src, SizeT srcLen,
-+ UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig)
-+{
-+ CLzmaEnc *p = (CLzmaEnc *)pp;
-+ LzmaEnc_SetInputBuf(p, src, srcLen);
-+ p->needInit = 1;
-+
-+ return LzmaEnc_AllocAndInit(p, keepWindowSize, alloc, allocBig);
-+}
-+
-+void LzmaEnc_Finish(CLzmaEncHandle pp)
-+{
-+ #ifndef _7ZIP_ST
-+ CLzmaEnc *p = (CLzmaEnc *)pp;
-+ if (p->mtMode)
-+ MatchFinderMt_ReleaseStream(&p->matchFinderMt);
-+ #else
-+ pp = pp;
-+ #endif
-+}
-+
-+typedef struct
-+{
-+ ISeqOutStream funcTable;
-+ Byte *data;
-+ SizeT rem;
-+ Bool overflow;
-+} CSeqOutStreamBuf;
-+
-+static size_t MyWrite(void *pp, const void *data, size_t size)
-+{
-+ CSeqOutStreamBuf *p = (CSeqOutStreamBuf *)pp;
-+ if (p->rem < size)
-+ {
-+ size = p->rem;
-+ p->overflow = True;
-+ }
-+ memcpy(p->data, data, size);
-+ p->rem -= size;
-+ p->data += size;
-+ return size;
-+}
-+
-+
-+UInt32 LzmaEnc_GetNumAvailableBytes(CLzmaEncHandle pp)
-+{
-+ const CLzmaEnc *p = (CLzmaEnc *)pp;
-+ return p->matchFinder.GetNumAvailableBytes(p->matchFinderObj);
-+}
-+
-+const Byte *LzmaEnc_GetCurBuf(CLzmaEncHandle pp)
-+{
-+ const CLzmaEnc *p = (CLzmaEnc *)pp;
-+ return p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset;
-+}
-+
-+SRes LzmaEnc_CodeOneMemBlock(CLzmaEncHandle pp, Bool reInit,
-+ Byte *dest, size_t *destLen, UInt32 desiredPackSize, UInt32 *unpackSize)
-+{
-+ CLzmaEnc *p = (CLzmaEnc *)pp;
-+ UInt64 nowPos64;
-+ SRes res;
-+ CSeqOutStreamBuf outStream;
-+
-+ outStream.funcTable.Write = MyWrite;
-+ outStream.data = dest;
-+ outStream.rem = *destLen;
-+ outStream.overflow = False;
-+
-+ p->writeEndMark = False;
-+ p->finished = False;
-+ p->result = SZ_OK;
-+
-+ if (reInit)
-+ LzmaEnc_Init(p);
-+ LzmaEnc_InitPrices(p);
-+ nowPos64 = p->nowPos64;
-+ RangeEnc_Init(&p->rc);
-+ p->rc.outStream = &outStream.funcTable;
-+
-+ res = LzmaEnc_CodeOneBlock(p, True, desiredPackSize, *unpackSize);
-+
-+ *unpackSize = (UInt32)(p->nowPos64 - nowPos64);
-+ *destLen -= outStream.rem;
-+ if (outStream.overflow)
-+ return SZ_ERROR_OUTPUT_EOF;
-+
-+ return res;
-+}
-+
-+static SRes LzmaEnc_Encode2(CLzmaEnc *p, ICompressProgress *progress)
-+{
-+ SRes res = SZ_OK;
-+
-+ #ifndef _7ZIP_ST
-+ Byte allocaDummy[0x300];
-+ int i = 0;
-+ for (i = 0; i < 16; i++)
-+ allocaDummy[i] = (Byte)i;
-+ #endif
-+
-+ for (;;)
-+ {
-+ res = LzmaEnc_CodeOneBlock(p, False, 0, 0);
-+ if (res != SZ_OK || p->finished != 0)
-+ break;
-+ if (progress != 0)
-+ {
-+ res = progress->Progress(progress, p->nowPos64, RangeEnc_GetProcessed(&p->rc));
-+ if (res != SZ_OK)
-+ {
-+ res = SZ_ERROR_PROGRESS;
-+ break;
-+ }
-+ }
-+ }
-+ LzmaEnc_Finish(p);
-+ return res;
-+}
-+
-+SRes LzmaEnc_Encode(CLzmaEncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream, ICompressProgress *progress,
-+ ISzAlloc *alloc, ISzAlloc *allocBig)
-+{
-+ RINOK(LzmaEnc_Prepare(pp, outStream, inStream, alloc, allocBig));
-+ return LzmaEnc_Encode2((CLzmaEnc *)pp, progress);
-+}
-+
-+SRes LzmaEnc_WriteProperties(CLzmaEncHandle pp, Byte *props, SizeT *size)
-+{
-+ CLzmaEnc *p = (CLzmaEnc *)pp;
-+ int i;
-+ UInt32 dictSize = p->dictSize;
-+ if (*size < LZMA_PROPS_SIZE)
-+ return SZ_ERROR_PARAM;
-+ *size = LZMA_PROPS_SIZE;
-+ props[0] = (Byte)((p->pb * 5 + p->lp) * 9 + p->lc);
-+
-+ for (i = 11; i <= 30; i++)
-+ {
-+ if (dictSize <= ((UInt32)2 << i))
-+ {
-+ dictSize = (2 << i);
-+ break;
-+ }
-+ if (dictSize <= ((UInt32)3 << i))
-+ {
-+ dictSize = (3 << i);
-+ break;
-+ }
-+ }
-+
-+ for (i = 0; i < 4; i++)
-+ props[1 + i] = (Byte)(dictSize >> (8 * i));
-+ return SZ_OK;
-+}
-+
-+SRes LzmaEnc_MemEncode(CLzmaEncHandle pp, Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
-+ int writeEndMark, ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig)
-+{
-+ SRes res;
-+ CLzmaEnc *p = (CLzmaEnc *)pp;
-+
-+ CSeqOutStreamBuf outStream;
-+
-+ LzmaEnc_SetInputBuf(p, src, srcLen);
-+
-+ outStream.funcTable.Write = MyWrite;
-+ outStream.data = dest;
-+ outStream.rem = *destLen;
-+ outStream.overflow = False;
-+
-+ p->writeEndMark = writeEndMark;
-+
-+ p->rc.outStream = &outStream.funcTable;
-+ res = LzmaEnc_MemPrepare(pp, src, srcLen, 0, alloc, allocBig);
-+ if (res == SZ_OK)
-+ res = LzmaEnc_Encode2(p, progress);
-+
-+ *destLen -= outStream.rem;
-+ if (outStream.overflow)
-+ return SZ_ERROR_OUTPUT_EOF;
-+ return res;
-+}
-+
-+SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
-+ const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark,
-+ ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig)
-+{
-+ CLzmaEnc *p = (CLzmaEnc *)LzmaEnc_Create(alloc);
-+ SRes res;
-+ if (p == 0)
-+ return SZ_ERROR_MEM;
-+
-+ res = LzmaEnc_SetProps(p, props);
-+ if (res == SZ_OK)
-+ {
-+ res = LzmaEnc_WriteProperties(p, propsEncoded, propsSize);
-+ if (res == SZ_OK)
-+ res = LzmaEnc_MemEncode(p, dest, destLen, src, srcLen,
-+ writeEndMark, progress, alloc, allocBig);
-+ }
-+
-+ LzmaEnc_Destroy(p, alloc, allocBig);
-+ return res;
-+}
---- /dev/null
-+++ b/lib/lzma/Makefile
-@@ -0,0 +1,7 @@
-+lzma_compress-objs := LzFind.o LzmaEnc.o
-+lzma_decompress-objs := LzmaDec.o
-+
-+obj-$(CONFIG_LZMA_COMPRESS) += lzma_compress.o
-+obj-$(CONFIG_LZMA_DECOMPRESS) += lzma_decompress.o
-+
-+EXTRA_CFLAGS += -Iinclude/linux -Iinclude/linux/lzma -include types.h
+++ /dev/null
-Subject: fs: jffs2: EOF marker
-
----
- fs/jffs2/build.c | 10 ++++++++++
- fs/jffs2/scan.c | 21 +++++++++++++++++++--
- 2 files changed, 29 insertions(+), 2 deletions(-)
-
---- a/fs/jffs2/build.c
-+++ b/fs/jffs2/build.c
-@@ -117,6 +117,16 @@ static int jffs2_build_filesystem(struct
- dbg_fsbuild("scanned flash completely\n");
- jffs2_dbg_dump_block_lists_nolock(c);
-
-+ if (c->flags & (1 << 7)) {
-+ printk("%s(): unlocking the mtd device... ", __func__);
-+ mtd_unlock(c->mtd, 0, c->mtd->size);
-+ printk("done.\n");
-+
-+ printk("%s(): erasing all blocks after the end marker... ", __func__);
-+ jffs2_erase_pending_blocks(c, -1);
-+ printk("done.\n");
-+ }
-+
- dbg_fsbuild("pass 1 starting\n");
- c->flags |= JFFS2_SB_FLAG_BUILDING;
- /* Now scan the directory tree, increasing nlink according to every dirent found. */
---- a/fs/jffs2/scan.c
-+++ b/fs/jffs2/scan.c
-@@ -148,8 +148,14 @@ int jffs2_scan_medium(struct jffs2_sb_in
- /* reset summary info for next eraseblock scan */
- jffs2_sum_reset_collected(s);
-
-- ret = jffs2_scan_eraseblock(c, jeb, buf_size?flashbuf:(flashbuf+jeb->offset),
-- buf_size, s);
-+ if (c->flags & (1 << 7)) {
-+ if (mtd_block_isbad(c->mtd, jeb->offset))
-+ ret = BLK_STATE_BADBLOCK;
-+ else
-+ ret = BLK_STATE_ALLFF;
-+ } else
-+ ret = jffs2_scan_eraseblock(c, jeb, buf_size?flashbuf:(flashbuf+jeb->offset),
-+ buf_size, s);
-
- if (ret < 0)
- goto out;
-@@ -569,6 +575,17 @@ full_scan:
- return err;
- }
-
-+ if ((buf[0] == 0xde) &&
-+ (buf[1] == 0xad) &&
-+ (buf[2] == 0xc0) &&
-+ (buf[3] == 0xde)) {
-+ /* end of filesystem. erase everything after this point */
-+ printk("%s(): End of filesystem marker found at 0x%x\n", __func__, jeb->offset);
-+ c->flags |= (1 << 7);
-+
-+ return BLK_STATE_ALLFF;
-+ }
-+
- /* We temporarily use 'ofs' as a pointer into the buffer/jeb */
- ofs = 0;
- max_ofs = EMPTY_SCAN_SIZE(c->sector_size);
+++ /dev/null
-Subject: netfilter: add support for flushing conntrack via /proc
-
-lede-commit 8193bbe59a74d34d6a26d4a8cb857b1952905314
----
- net/netfilter/nf_conntrack_standalone.c | 59 ++++++++++++++++++++++++++++++++-
- 1 file changed, 58 insertions(+), 1 deletion(-)
-
---- a/net/netfilter/nf_conntrack_standalone.c
-+++ b/net/netfilter/nf_conntrack_standalone.c
-@@ -9,6 +9,7 @@
- #include <linux/percpu.h>
- #include <linux/netdevice.h>
- #include <linux/security.h>
-+#include <linux/inet.h>
- #include <net/net_namespace.h>
- #ifdef CONFIG_SYSCTL
- #include <linux/sysctl.h>
-@@ -458,6 +459,58 @@ static int ct_cpu_seq_show(struct seq_fi
- return 0;
- }
-
-+struct kill_request {
-+ u16 family;
-+ union nf_inet_addr addr;
-+};
-+
-+static int kill_matching(struct nf_conn *i, void *data)
-+{
-+ struct kill_request *kr = data;
-+ struct nf_conntrack_tuple *t1 = &i->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
-+ struct nf_conntrack_tuple *t2 = &i->tuplehash[IP_CT_DIR_REPLY].tuple;
-+
-+ if (!kr->family)
-+ return 1;
-+
-+ if (t1->src.l3num != kr->family)
-+ return 0;
-+
-+ return (nf_inet_addr_cmp(&kr->addr, &t1->src.u3) ||
-+ nf_inet_addr_cmp(&kr->addr, &t1->dst.u3) ||
-+ nf_inet_addr_cmp(&kr->addr, &t2->src.u3) ||
-+ nf_inet_addr_cmp(&kr->addr, &t2->dst.u3));
-+}
-+
-+static int ct_file_write(struct file *file, char *buf, size_t count)
-+{
-+ struct seq_file *seq = file->private_data;
-+ struct nf_ct_iter_data iter_data;
-+ struct kill_request kr = { };
-+
-+ if (count == 0)
-+ return 0;
-+
-+ if (count >= INET6_ADDRSTRLEN)
-+ count = INET6_ADDRSTRLEN - 1;
-+
-+ if (strnchr(buf, count, ':')) {
-+ kr.family = AF_INET6;
-+ if (!in6_pton(buf, count, (void *)&kr.addr, '\n', NULL))
-+ return -EINVAL;
-+ } else if (strnchr(buf, count, '.')) {
-+ kr.family = AF_INET;
-+ if (!in4_pton(buf, count, (void *)&kr.addr, '\n', NULL))
-+ return -EINVAL;
-+ }
-+
-+ iter_data.net = seq_file_net(seq);
-+ iter_data.data = &kr;
-+ nf_ct_iterate_cleanup_net(kill_matching, &iter_data);
-+
-+ return 0;
-+}
-+
- static const struct seq_operations ct_cpu_seq_ops = {
- .start = ct_cpu_seq_start,
- .next = ct_cpu_seq_next,
-@@ -471,8 +524,9 @@ static int nf_conntrack_standalone_init_
- kuid_t root_uid;
- kgid_t root_gid;
-
-- pde = proc_create_net("nf_conntrack", 0440, net->proc_net, &ct_seq_ops,
-- sizeof(struct ct_iter_state));
-+ pde = proc_create_net_data_write("nf_conntrack", 0440, net->proc_net,
-+ &ct_seq_ops, &ct_file_write,
-+ sizeof(struct ct_iter_state), NULL);
- if (!pde)
- goto out_nf_conntrack;
-
+++ /dev/null
-Subject: kernel: add a new version of my netfilter speedup patches for linux 2.6.39 and 3.0
-
----
- include/uapi/linux/netfilter_ipv4/ip_tables.h | 1 +
- net/ipv4/netfilter/ip_tables.c | 37 +++++++++++++++++++++++++++
- 2 files changed, 38 insertions(+)
-
---- a/include/uapi/linux/netfilter_ipv4/ip_tables.h
-+++ b/include/uapi/linux/netfilter_ipv4/ip_tables.h
-@@ -89,6 +89,7 @@ struct ipt_ip {
- #define IPT_F_FRAG 0x01 /* Set if rule is a fragment rule */
- #define IPT_F_GOTO 0x02 /* Set if jump is a goto */
- #define IPT_F_MASK 0x03 /* All possible flag bits mask. */
-+#define IPT_F_NO_DEF_MATCH 0x80 /* Internal: no default match rules present */
-
- /* Values for "inv" field in struct ipt_ip. */
- #define IPT_INV_VIA_IN 0x01 /* Invert the sense of IN IFACE. */
---- a/net/ipv4/netfilter/ip_tables.c
-+++ b/net/ipv4/netfilter/ip_tables.c
-@@ -48,6 +48,9 @@ ip_packet_match(const struct iphdr *ip,
- {
- unsigned long ret;
-
-+ if (ipinfo->flags & IPT_F_NO_DEF_MATCH)
-+ return true;
-+
- if (NF_INVF(ipinfo, IPT_INV_SRCIP,
- (ip->saddr & ipinfo->smsk.s_addr) != ipinfo->src.s_addr) ||
- NF_INVF(ipinfo, IPT_INV_DSTIP,
-@@ -78,6 +81,29 @@ ip_packet_match(const struct iphdr *ip,
- return true;
- }
-
-+static void
-+ip_checkdefault(struct ipt_ip *ip)
-+{
-+ static const char iface_mask[IFNAMSIZ] = {};
-+
-+ if (ip->invflags || ip->flags & IPT_F_FRAG)
-+ return;
-+
-+ if (memcmp(ip->iniface_mask, iface_mask, IFNAMSIZ) != 0)
-+ return;
-+
-+ if (memcmp(ip->outiface_mask, iface_mask, IFNAMSIZ) != 0)
-+ return;
-+
-+ if (ip->smsk.s_addr || ip->dmsk.s_addr)
-+ return;
-+
-+ if (ip->proto)
-+ return;
-+
-+ ip->flags |= IPT_F_NO_DEF_MATCH;
-+}
-+
- static bool
- ip_checkentry(const struct ipt_ip *ip)
- {
-@@ -523,6 +549,8 @@ find_check_entry(struct ipt_entry *e, st
- struct xt_mtchk_param mtpar;
- struct xt_entry_match *ematch;
-
-+ ip_checkdefault(&e->ip);
-+
- if (!xt_percpu_counter_alloc(alloc_state, &e->counters))
- return -ENOMEM;
-
-@@ -817,6 +845,7 @@ copy_entries_to_user(unsigned int total_
- const struct xt_table_info *private = table->private;
- int ret = 0;
- const void *loc_cpu_entry;
-+ u8 flags;
-
- counters = alloc_counters(table);
- if (IS_ERR(counters))
-@@ -844,6 +873,14 @@ copy_entries_to_user(unsigned int total_
- goto free_counters;
- }
-
-+ flags = e->ip.flags & IPT_F_MASK;
-+ if (copy_to_user(userptr + off
-+ + offsetof(struct ipt_entry, ip.flags),
-+ &flags, sizeof(flags)) != 0) {
-+ ret = -EFAULT;
-+ goto free_counters;
-+ }
-+
- for (i = sizeof(struct ipt_entry);
- i < e->target_offset;
- i += m->u.match_size) {
-@@ -1225,12 +1262,15 @@ compat_copy_entry_to_user(struct ipt_ent
- compat_uint_t origsize;
- const struct xt_entry_match *ematch;
- int ret = 0;
-+ u8 flags = e->ip.flags & IPT_F_MASK;
-
- origsize = *size;
- ce = *dstptr;
- if (copy_to_user(ce, e, sizeof(struct ipt_entry)) != 0 ||
- copy_to_user(&ce->counters, &counters[i],
-- sizeof(counters[i])) != 0)
-+ sizeof(counters[i])) != 0 ||
-+ copy_to_user(&ce->ip.flags, &flags,
-+ sizeof(flags)) != 0)
- return -EFAULT;
-
- *dstptr += sizeof(struct compat_ipt_entry);
+++ /dev/null
-Subject: netfilter: match bypass default table
-
----
- net/ipv4/netfilter/ip_tables.c | 79 +++++++++++++++++++++++++++++++-----------
- 1 file changed, 58 insertions(+), 21 deletions(-)
-
---- a/net/ipv4/netfilter/ip_tables.c
-+++ b/net/ipv4/netfilter/ip_tables.c
-@@ -244,6 +244,33 @@ struct ipt_entry *ipt_next_entry(const s
- return (void *)entry + entry->next_offset;
- }
-
-+static bool
-+ipt_handle_default_rule(struct ipt_entry *e, unsigned int *verdict)
-+{
-+ struct xt_entry_target *t;
-+ struct xt_standard_target *st;
-+
-+ if (e->target_offset != sizeof(struct ipt_entry))
-+ return false;
-+
-+ if (!(e->ip.flags & IPT_F_NO_DEF_MATCH))
-+ return false;
-+
-+ t = ipt_get_target(e);
-+ if (t->u.kernel.target->target)
-+ return false;
-+
-+ st = (struct xt_standard_target *) t;
-+ if (st->verdict == XT_RETURN)
-+ return false;
-+
-+ if (st->verdict >= 0)
-+ return false;
-+
-+ *verdict = (unsigned)(-st->verdict) - 1;
-+ return true;
-+}
-+
- /* Returns one of the generic firewall policies, like NF_ACCEPT. */
- unsigned int
- ipt_do_table(void *priv,
-@@ -265,27 +292,28 @@ ipt_do_table(void *priv,
- unsigned int addend;
-
- /* Initialization */
-+ WARN_ON(!(table->valid_hooks & (1 << hook)));
-+ local_bh_disable();
-+ private = READ_ONCE(table->private); /* Address dependency. */
-+ cpu = smp_processor_id();
-+ table_base = private->entries;
-+
-+ e = get_entry(table_base, private->hook_entry[hook]);
-+ if (ipt_handle_default_rule(e, &verdict)) {
-+ struct xt_counters *counter;
-+
-+ counter = xt_get_this_cpu_counter(&e->counters);
-+ ADD_COUNTER(*counter, skb->len, 1);
-+ local_bh_enable();
-+ return verdict;
-+ }
-+
- stackidx = 0;
- ip = ip_hdr(skb);
- indev = state->in ? state->in->name : nulldevname;
- outdev = state->out ? state->out->name : nulldevname;
-- /* We handle fragments by dealing with the first fragment as
-- * if it was a normal packet. All other fragments are treated
-- * normally, except that they will NEVER match rules that ask
-- * things we don't know, ie. tcp syn flag or ports). If the
-- * rule is also a fragment-specific rule, non-fragments won't
-- * match it. */
-- acpar.fragoff = ntohs(ip->frag_off) & IP_OFFSET;
-- acpar.thoff = ip_hdrlen(skb);
-- acpar.hotdrop = false;
-- acpar.state = state;
-
-- WARN_ON(!(table->valid_hooks & (1 << hook)));
-- local_bh_disable();
- addend = xt_write_recseq_begin();
-- private = READ_ONCE(table->private); /* Address dependency. */
-- cpu = smp_processor_id();
-- table_base = private->entries;
- jumpstack = (struct ipt_entry **)private->jumpstack[cpu];
-
- /* Switch to alternate jumpstack if we're being invoked via TEE.
-@@ -298,7 +326,16 @@ ipt_do_table(void *priv,
- if (static_key_false(&xt_tee_enabled))
- jumpstack += private->stacksize * __this_cpu_read(nf_skb_duplicated);
-
-- e = get_entry(table_base, private->hook_entry[hook]);
-+ /* We handle fragments by dealing with the first fragment as
-+ * if it was a normal packet. All other fragments are treated
-+ * normally, except that they will NEVER match rules that ask
-+ * things we don't know, ie. tcp syn flag or ports). If the
-+ * rule is also a fragment-specific rule, non-fragments won't
-+ * match it. */
-+ acpar.fragoff = ntohs(ip->frag_off) & IP_OFFSET;
-+ acpar.thoff = ip_hdrlen(skb);
-+ acpar.hotdrop = false;
-+ acpar.state = state;
-
- do {
- const struct xt_entry_target *t;
+++ /dev/null
-Subject: netfilter: reduce match memory access
-
----
- net/ipv4/netfilter/ip_tables.c | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
---- a/net/ipv4/netfilter/ip_tables.c
-+++ b/net/ipv4/netfilter/ip_tables.c
-@@ -51,9 +51,9 @@ ip_packet_match(const struct iphdr *ip,
- if (ipinfo->flags & IPT_F_NO_DEF_MATCH)
- return true;
-
-- if (NF_INVF(ipinfo, IPT_INV_SRCIP,
-+ if (NF_INVF(ipinfo, IPT_INV_SRCIP, ipinfo->smsk.s_addr &&
- (ip->saddr & ipinfo->smsk.s_addr) != ipinfo->src.s_addr) ||
-- NF_INVF(ipinfo, IPT_INV_DSTIP,
-+ NF_INVF(ipinfo, IPT_INV_DSTIP, ipinfo->dmsk.s_addr &&
- (ip->daddr & ipinfo->dmsk.s_addr) != ipinfo->dst.s_addr))
- return false;
-
+++ /dev/null
-Subject: net: add an optimization for dealing with raw sockets
-
-lede-commit: 4898039703d7315f0f3431c860123338ec3be0f6
----
- include/uapi/linux/if_packet.h | 3 +++
- net/packet/af_packet.c | 34 +++++++++++++++++++++++++++-------
- net/packet/internal.h | 1 +
- 3 files changed, 31 insertions(+), 7 deletions(-)
-
---- a/include/uapi/linux/if_packet.h
-+++ b/include/uapi/linux/if_packet.h
-@@ -33,6 +33,8 @@ struct sockaddr_ll {
- #define PACKET_KERNEL 7 /* To kernel space */
- /* Unused, PACKET_FASTROUTE and PACKET_LOOPBACK are invisible to user space */
- #define PACKET_FASTROUTE 6 /* Fastrouted frame */
-+#define PACKET_MASK_ANY 0xffffffff /* mask for packet type bits */
-+
-
- /* Packet socket options */
-
-@@ -60,6 +62,7 @@ struct sockaddr_ll {
- #define PACKET_FANOUT_DATA 22
- #define PACKET_IGNORE_OUTGOING 23
- #define PACKET_VNET_HDR_SZ 24
-+#define PACKET_RECV_TYPE 25
-
- #define PACKET_FANOUT_HASH 0
- #define PACKET_FANOUT_LB 1
---- a/net/packet/af_packet.c
-+++ b/net/packet/af_packet.c
-@@ -1911,6 +1911,7 @@ static int packet_rcv_spkt(struct sk_buf
- {
- struct sock *sk;
- struct sockaddr_pkt *spkt;
-+ struct packet_sock *po;
-
- /*
- * When we registered the protocol we saved the socket in the data
-@@ -1918,6 +1919,7 @@ static int packet_rcv_spkt(struct sk_buf
- */
-
- sk = pt->af_packet_priv;
-+ po = pkt_sk(sk);
-
- /*
- * Yank back the headers [hope the device set this
-@@ -1930,7 +1932,7 @@ static int packet_rcv_spkt(struct sk_buf
- * so that this procedure is noop.
- */
-
-- if (skb->pkt_type == PACKET_LOOPBACK)
-+ if (!(po->pkt_type & (1 << skb->pkt_type)))
- goto out;
-
- if (!net_eq(dev_net(dev), sock_net(sk)))
-@@ -2176,12 +2178,12 @@ static int packet_rcv(struct sk_buff *sk
- unsigned int snaplen, res;
- bool is_drop_n_account = false;
-
-- if (skb->pkt_type == PACKET_LOOPBACK)
-- goto drop;
--
- sk = pt->af_packet_priv;
- po = pkt_sk(sk);
-
-+ if (!(po->pkt_type & (1 << skb->pkt_type)))
-+ goto drop;
-+
- if (!net_eq(dev_net(dev), sock_net(sk)))
- goto drop;
-
-@@ -2308,12 +2310,12 @@ static int tpacket_rcv(struct sk_buff *s
- BUILD_BUG_ON(TPACKET_ALIGN(sizeof(*h.h2)) != 32);
- BUILD_BUG_ON(TPACKET_ALIGN(sizeof(*h.h3)) != 48);
-
-- if (skb->pkt_type == PACKET_LOOPBACK)
-- goto drop;
--
- sk = pt->af_packet_priv;
- po = pkt_sk(sk);
-
-+ if (!(po->pkt_type & (1 << skb->pkt_type)))
-+ goto drop;
-+
- if (!net_eq(dev_net(dev), sock_net(sk)))
- goto drop;
-
-@@ -3436,6 +3438,7 @@ static int packet_create(struct net *net
- mutex_init(&po->pg_vec_lock);
- po->rollover = NULL;
- po->prot_hook.func = packet_rcv;
-+ po->pkt_type = PACKET_MASK_ANY & ~(1 << PACKET_LOOPBACK);
-
- if (sock->type == SOCK_PACKET)
- po->prot_hook.func = packet_rcv_spkt;
-@@ -4103,6 +4106,16 @@ packet_setsockopt(struct socket *sock, i
- packet_sock_flag_set(po, PACKET_SOCK_QDISC_BYPASS, val);
- return 0;
- }
-+ case PACKET_RECV_TYPE:
-+ {
-+ unsigned int val;
-+ if (optlen != sizeof(val))
-+ return -EINVAL;
-+ if (copy_from_sockptr(&val, optval, sizeof(val)))
-+ return -EFAULT;
-+ po->pkt_type = val & ~BIT(PACKET_LOOPBACK);
-+ return 0;
-+ }
- default:
- return -ENOPROTOOPT;
- }
-@@ -4162,6 +4175,13 @@ static int packet_getsockopt(struct sock
- case PACKET_VNET_HDR_SZ:
- val = READ_ONCE(po->vnet_hdr_sz);
- break;
-+ case PACKET_RECV_TYPE:
-+ if (len > sizeof(unsigned int))
-+ len = sizeof(unsigned int);
-+ val = po->pkt_type;
-+
-+ data = &val;
-+ break;
- case PACKET_VERSION:
- val = po->tp_version;
- break;
---- a/net/packet/internal.h
-+++ b/net/packet/internal.h
-@@ -131,6 +131,7 @@ struct packet_sock {
- struct net_device __rcu *cached_dev;
- struct packet_type prot_hook ____cacheline_aligned_in_smp;
- atomic_t tp_drops ____cacheline_aligned_in_smp;
-+ unsigned int pkt_type;
- };
-
- #define pkt_sk(ptr) container_of_const(ptr, struct packet_sock, sk)
+++ /dev/null
-Date: Thu, 22 Aug 2024 18:02:17 +0200
-Subject: [PATCH] net: bridge: fix switchdev host mdb entry updates
-
-When a mdb entry is removed, the bridge switchdev code can issue a
-switchdev_port_obj_del call for a port that was not offloaded.
-
-This leads to an imbalance in switchdev_port_obj_add/del calls, since
-br_switchdev_mdb_replay has not been called for the port before.
-
-This can lead to potential multicast forwarding issues and messages such as:
-mt7915e 0000:01:00.0 wl1-ap0: Failed to del Host Multicast Database entry
- (object id=3) with error: -ENOENT (-2).
-
-Fix this issue by checking the port offload status when iterating over
-lower devs.
-
----
-
---- a/net/bridge/br_switchdev.c
-+++ b/net/bridge/br_switchdev.c
-@@ -571,10 +571,18 @@ static void br_switchdev_host_mdb(struct
- struct net_bridge_mdb_entry *mp, int type)
- {
- struct net_device *lower_dev;
-+ struct net_bridge_port *port;
- struct list_head *iter;
-
-- netdev_for_each_lower_dev(dev, lower_dev, iter)
-+ rcu_read_lock();
-+ netdev_for_each_lower_dev(dev, lower_dev, iter) {
-+ port = br_port_get_rcu(lower_dev);
-+ if (!port || !port->offload_count)
-+ continue;
-+
- br_switchdev_host_mdb_one(dev, lower_dev, mp, type);
-+ }
-+ rcu_read_unlock();
- }
-
- static int
+++ /dev/null
-Date: Sun, 20 Oct 2024 18:20:14 +0200
-Subject: [PATCH] net: bridge: switchdev: Don't drop packets between ports with
- no hwdom
-
-nbp_switchdev_allowed_egress uses hwdom to determine whether or not a
-packet has already been forwarded to a hardware domain. For
-net_bridge_ports that aren't set up to use forward offloading, hwdom is
-set to 0. When both ingress and egress port have no hwdom,
-'cb->src_hwdom != p->hwdom' indicates that the packet is already known in
-the target domain - which it isn't - and the packet is wrongly dropped.
-
-The error was found on a bridge containing a wifi device and a VLAN
-tagging device (e.g. eth0.12). With VLAN filtering, this shouldn't happen.
-
-This patch adds a check for p->hwdom != 0 before comparing hardware
-domains to restore forwarding between ports with hwdom = 0.
-
-fwd_hwdoms are only set for ports with offloading enabled, which also
-implies a valid hwdom, so the check '!test_bit(p->hwdom, &cb->fwd_hwdoms)'
-doesn't fail in this way (yet - fingers crossed..) and it is left in place.
-
----
-
---- a/net/bridge/br_switchdev.c
-+++ b/net/bridge/br_switchdev.c
-@@ -70,7 +70,7 @@ bool nbp_switchdev_allowed_egress(const
- struct br_input_skb_cb *cb = BR_INPUT_SKB_CB(skb);
-
- return !test_bit(p->hwdom, &cb->fwd_hwdoms) &&
-- (!skb->offload_fwd_mark || cb->src_hwdom != p->hwdom);
-+ (!skb->offload_fwd_mark || !p->hwdom || cb->src_hwdom != p->hwdom);
- }
-
- /* Flags that can be offloaded to hardware */
+++ /dev/null
-Date: Tue, 15 Jul 2025 12:37:45 +0200
-Subject: [PATCH] net: pppoe: implement GRO support
-
-Only handles packets where the pppoe header length field matches the exact
-packet length. Significantly improves rx throughput.
-
-When running NAT traffic through a MediaTek MT7621 devices from a host
-behind PPPoE to a host directly connected via ethernet, the TCP throughput
-that the device is able to handle improves from ~130 Mbit/s to ~630 Mbit/s,
-using fraglist GRO.
-
----
-
---- a/drivers/net/ppp/pppoe.c
-+++ b/drivers/net/ppp/pppoe.c
-@@ -77,6 +77,7 @@
- #include <net/net_namespace.h>
- #include <net/netns/generic.h>
- #include <net/sock.h>
-+#include <net/gro.h>
-
- #include <linux/uaccess.h>
-
-@@ -435,7 +436,7 @@ static int pppoe_rcv(struct sk_buff *skb
- if (skb->len < len)
- goto drop;
-
-- if (pskb_trim_rcsum(skb, len))
-+ if (!skb_is_gso(skb) && pskb_trim_rcsum(skb, len))
- goto drop;
-
- ph = pppoe_hdr(skb);
-@@ -1173,6 +1174,161 @@ static struct pernet_operations pppoe_ne
- .size = sizeof(struct pppoe_net),
- };
-
-+static u16
-+compare_pppoe_header(struct pppoe_hdr *phdr, struct pppoe_hdr *phdr2)
-+{
-+ return (__force __u16)((phdr->sid ^ phdr2->sid) |
-+ (phdr->tag[0].tag_type ^ phdr2->tag[0].tag_type));
-+}
-+
-+static __be16 pppoe_hdr_proto(struct pppoe_hdr *phdr)
-+{
-+ switch (phdr->tag[0].tag_type) {
-+ case cpu_to_be16(PPP_IP):
-+ return cpu_to_be16(ETH_P_IP);
-+ case cpu_to_be16(PPP_IPV6):
-+ return cpu_to_be16(ETH_P_IPV6);
-+ default:
-+ return 0;
-+ }
-+
-+}
-+
-+static struct sk_buff *pppoe_gro_receive(struct list_head *head,
-+ struct sk_buff *skb)
-+{
-+ const struct packet_offload *ptype;
-+ unsigned int hlen, off_pppoe;
-+ struct sk_buff *pp = NULL;
-+ struct pppoe_hdr *phdr;
-+ struct sk_buff *p;
-+ int flush = 1;
-+ __be16 type;
-+
-+ off_pppoe = skb_gro_offset(skb);
-+ hlen = off_pppoe + sizeof(*phdr);
-+ phdr = skb_gro_header(skb, hlen + 2, off_pppoe);
-+ if (unlikely(!phdr))
-+ goto out;
-+
-+ /* ignore packets with padding or invalid length */
-+ if (skb_gro_len(skb) != be16_to_cpu(phdr->length) + hlen)
-+ goto out;
-+
-+ type = pppoe_hdr_proto(phdr);
-+ if (!type)
-+ goto out;
-+
-+ ptype = gro_find_receive_by_type(type);
-+ if (!ptype)
-+ goto out;
-+
-+ flush = 0;
-+
-+ list_for_each_entry(p, head, list) {
-+ struct pppoe_hdr *phdr2;
-+
-+ if (!NAPI_GRO_CB(p)->same_flow)
-+ continue;
-+
-+ phdr2 = (struct pppoe_hdr *)(p->data + off_pppoe);
-+ if (compare_pppoe_header(phdr, phdr2))
-+ NAPI_GRO_CB(p)->same_flow = 0;
-+ }
-+
-+ skb_gro_pull(skb, sizeof(*phdr) + 2);
-+ skb_gro_postpull_rcsum(skb, phdr, sizeof(*phdr) + 2);
-+
-+ pp = indirect_call_gro_receive_inet(ptype->callbacks.gro_receive,
-+ ipv6_gro_receive, inet_gro_receive,
-+ head, skb);
-+
-+out:
-+ skb_gro_flush_final(skb, pp, flush);
-+
-+ return pp;
-+}
-+
-+static int pppoe_gro_complete(struct sk_buff *skb, int nhoff)
-+{
-+ struct pppoe_hdr *phdr = (struct pppoe_hdr *)(skb->data + nhoff);
-+ __be16 type = pppoe_hdr_proto(phdr);
-+ struct packet_offload *ptype;
-+ int len, err;
-+
-+ ptype = gro_find_complete_by_type(type);
-+ if (!ptype)
-+ return -ENOENT;
-+
-+ err = INDIRECT_CALL_INET(ptype->callbacks.gro_complete,
-+ ipv6_gro_complete, inet_gro_complete,
-+ skb, nhoff + sizeof(*phdr) + 2);
-+ if (err)
-+ return err;
-+
-+ len = skb->len - (nhoff + sizeof(*phdr));
-+ phdr->length = cpu_to_be16(len);
-+
-+ return 0;
-+}
-+
-+static struct sk_buff *pppoe_gso_segment(struct sk_buff *skb,
-+ netdev_features_t features)
-+{
-+ unsigned int pppoe_hlen = sizeof(struct pppoe_hdr) + 2;
-+ struct sk_buff *segs = ERR_PTR(-EINVAL);
-+ u16 mac_offset = skb->mac_header;
-+ struct packet_offload *ptype;
-+ u16 mac_len = skb->mac_len;
-+ struct pppoe_hdr *phdr;
-+ __be16 orig_type, type;
-+ int len, nhoff;
-+
-+ skb_reset_network_header(skb);
-+ nhoff = skb_network_header(skb) - skb_mac_header(skb);
-+
-+ if (unlikely(!pskb_may_pull(skb, pppoe_hlen)))
-+ goto out;
-+
-+ phdr = (struct pppoe_hdr *)skb_network_header(skb);
-+ type = pppoe_hdr_proto(phdr);
-+ ptype = gro_find_complete_by_type(type);
-+ if (!ptype)
-+ goto out;
-+
-+ orig_type = skb->protocol;
-+ __skb_pull(skb, pppoe_hlen);
-+ segs = ptype->callbacks.gso_segment(skb, features);
-+ if (IS_ERR_OR_NULL(segs)) {
-+ skb_gso_error_unwind(skb, orig_type, pppoe_hlen, mac_offset,
-+ mac_len);
-+ goto out;
-+ }
-+
-+ skb = segs;
-+ do {
-+ phdr = (struct pppoe_hdr *)(skb_mac_header(skb) + nhoff);
-+ len = skb->len - (nhoff + sizeof(*phdr));
-+ phdr->length = cpu_to_be16(len);
-+ skb->network_header = (u8 *)phdr - skb->head;
-+ skb->protocol = orig_type;
-+ skb_reset_mac_len(skb);
-+ } while ((skb = skb->next));
-+
-+out:
-+ return segs;
-+}
-+
-+static struct packet_offload pppoe_packet_offload __read_mostly = {
-+ .type = cpu_to_be16(ETH_P_PPP_SES),
-+ .priority = 20,
-+ .callbacks = {
-+ .gro_receive = pppoe_gro_receive,
-+ .gro_complete = pppoe_gro_complete,
-+ .gso_segment = pppoe_gso_segment,
-+ },
-+};
-+
- static int __init pppoe_init(void)
- {
- int err;
-@@ -1189,6 +1345,7 @@ static int __init pppoe_init(void)
- if (err)
- goto out_unregister_pppoe_proto;
-
-+ dev_add_offload(&pppoe_packet_offload);
- dev_add_pack(&pppoes_ptype);
- dev_add_pack(&pppoed_ptype);
- register_netdevice_notifier(&pppoe_notifier);
-@@ -1208,6 +1365,7 @@ static void __exit pppoe_exit(void)
- unregister_netdevice_notifier(&pppoe_notifier);
- dev_remove_pack(&pppoed_ptype);
- dev_remove_pack(&pppoes_ptype);
-+ dev_remove_offload(&pppoe_packet_offload);
- unregister_pppox_proto(PX_PROTO_OE);
- proto_unregister(&pppoe_sk_proto);
- unregister_pernet_device(&pppoe_net_ops);
---- a/net/ipv4/af_inet.c
-+++ b/net/ipv4/af_inet.c
-@@ -1587,6 +1587,7 @@ out:
-
- return pp;
- }
-+EXPORT_INDIRECT_CALLABLE(inet_gro_receive);
-
- static struct sk_buff *ipip_gro_receive(struct list_head *head,
- struct sk_buff *skb)
-@@ -1672,6 +1673,7 @@ int inet_gro_complete(struct sk_buff *sk
- out:
- return err;
- }
-+EXPORT_INDIRECT_CALLABLE(inet_gro_complete);
-
- static int ipip_gro_complete(struct sk_buff *skb, int nhoff)
- {
---- a/net/ipv6/ip6_offload.c
-+++ b/net/ipv6/ip6_offload.c
-@@ -321,6 +321,7 @@ out:
-
- return pp;
- }
-+EXPORT_INDIRECT_CALLABLE(ipv6_gro_receive);
-
- static struct sk_buff *sit_ip6ip6_gro_receive(struct list_head *head,
- struct sk_buff *skb)
-@@ -403,6 +404,7 @@ INDIRECT_CALLABLE_SCOPE int ipv6_gro_com
- out:
- return err;
- }
-+EXPORT_INDIRECT_CALLABLE(ipv6_gro_complete);
-
- static int sit_gro_complete(struct sk_buff *skb, int nhoff)
- {
+++ /dev/null
-Subject: kernel: add a few patches for avoiding unnecessary skb reallocations - significantly improves ethernet<->wireless performance
-
-lede-commit: 6f89cffc9add6939d44a6b54cf9a5e77849aa7fd
----
- include/linux/skbuff.h | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/include/linux/skbuff.h
-+++ b/include/linux/skbuff.h
-@@ -3088,7 +3088,7 @@ static inline int pskb_network_may_pull(
- * NET_IP_ALIGN(2) + ethernet_header(14) + IP_header(20/40) + ports(8)
- */
- #ifndef NET_SKB_PAD
--#define NET_SKB_PAD max(32, L1_CACHE_BYTES)
-+#define NET_SKB_PAD max(64, L1_CACHE_BYTES)
- #endif
-
- int ___pskb_trim(struct sk_buff *skb, unsigned int len);
+++ /dev/null
-Subject: Add support for MAP-E FMRs (mesh mode)
-
-MAP-E FMRs (draft-ietf-softwire-map-10) are rules for IPv4-communication
-between MAP CEs (mesh mode) without the need to forward such data to a
-border relay. This is similar to how 6rd works but for IPv4 over IPv6.
-
----
- include/net/ip6_tunnel.h | 13 ++
- include/uapi/linux/if_tunnel.h | 13 ++
- net/ipv6/ip6_tunnel.c | 276 +++++++++++++++++++++++++++++++++++++++--
- 3 files changed, 291 insertions(+), 11 deletions(-)
-
---- a/include/net/ip6_tunnel.h
-+++ b/include/net/ip6_tunnel.h
-@@ -18,6 +18,18 @@
- /* determine capability on a per-packet basis */
- #define IP6_TNL_F_CAP_PER_PACKET 0x40000
-
-+/* IPv6 tunnel FMR */
-+struct __ip6_tnl_fmr {
-+ struct __ip6_tnl_fmr *next; /* next fmr in list */
-+ struct in6_addr ip6_prefix;
-+ struct in_addr ip4_prefix;
-+
-+ __u8 ip6_prefix_len;
-+ __u8 ip4_prefix_len;
-+ __u8 ea_len;
-+ __u8 offset;
-+};
-+
- struct __ip6_tnl_parm {
- char name[IFNAMSIZ]; /* name of tunnel device */
- int link; /* ifindex of underlying L2 interface */
-@@ -29,6 +41,7 @@ struct __ip6_tnl_parm {
- __u32 flags; /* tunnel flags */
- struct in6_addr laddr; /* local tunnel end-point address */
- struct in6_addr raddr; /* remote tunnel end-point address */
-+ struct __ip6_tnl_fmr *fmrs; /* FMRs */
-
- __be16 i_flags;
- __be16 o_flags;
---- a/include/uapi/linux/if_tunnel.h
-+++ b/include/uapi/linux/if_tunnel.h
-@@ -77,10 +77,23 @@ enum {
- IFLA_IPTUN_ENCAP_DPORT,
- IFLA_IPTUN_COLLECT_METADATA,
- IFLA_IPTUN_FWMARK,
-+ IFLA_IPTUN_FMRS,
- __IFLA_IPTUN_MAX,
- };
- #define IFLA_IPTUN_MAX (__IFLA_IPTUN_MAX - 1)
-
-+enum {
-+ IFLA_IPTUN_FMR_UNSPEC,
-+ IFLA_IPTUN_FMR_IP6_PREFIX,
-+ IFLA_IPTUN_FMR_IP4_PREFIX,
-+ IFLA_IPTUN_FMR_IP6_PREFIX_LEN,
-+ IFLA_IPTUN_FMR_IP4_PREFIX_LEN,
-+ IFLA_IPTUN_FMR_EA_LEN,
-+ IFLA_IPTUN_FMR_OFFSET,
-+ __IFLA_IPTUN_FMR_MAX,
-+};
-+#define IFLA_IPTUN_FMR_MAX (__IFLA_IPTUN_FMR_MAX - 1)
-+
- enum tunnel_encap_types {
- TUNNEL_ENCAP_NONE,
- TUNNEL_ENCAP_FOU,
---- a/net/ipv6/ip6_tunnel.c
-+++ b/net/ipv6/ip6_tunnel.c
-@@ -11,6 +11,9 @@
- * linux/net/ipv6/sit.c and linux/net/ipv4/ipip.c
- *
- * RFC 2473
-+ *
-+ * Changes:
- */
-
- #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-@@ -67,9 +70,9 @@ static bool log_ecn_error = true;
- module_param(log_ecn_error, bool, 0644);
- MODULE_PARM_DESC(log_ecn_error, "Log packets received with corrupted ECN");
-
--static u32 HASH(const struct in6_addr *addr1, const struct in6_addr *addr2)
-+static u32 HASH(const struct in6_addr *addr)
- {
-- u32 hash = ipv6_addr_hash(addr1) ^ ipv6_addr_hash(addr2);
-+ u32 hash = ipv6_addr_hash(addr);
-
- return hash_32(hash, IP6_TUNNEL_HASH_SIZE_SHIFT);
- }
-@@ -114,17 +117,33 @@ static struct ip6_tnl *
- ip6_tnl_lookup(struct net *net, int link,
- const struct in6_addr *remote, const struct in6_addr *local)
- {
-- unsigned int hash = HASH(remote, local);
-+ unsigned int hash = HASH(local);
- struct ip6_tnl *t, *cand = NULL;
- struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id);
- struct in6_addr any;
-
- for_each_ip6_tunnel_rcu(ip6n->tnls_r_l[hash]) {
- if (!ipv6_addr_equal(local, &t->parms.laddr) ||
-- !ipv6_addr_equal(remote, &t->parms.raddr) ||
- !(t->dev->flags & IFF_UP))
- continue;
-
-+ if (!ipv6_addr_equal(remote, &t->parms.raddr)) {
-+ struct __ip6_tnl_fmr *fmr;
-+ bool found = false;
-+
-+ for (fmr = t->parms.fmrs; fmr; fmr = fmr->next) {
-+ if (!ipv6_prefix_equal(remote, &fmr->ip6_prefix,
-+ fmr->ip6_prefix_len))
-+ continue;
-+
-+ found = true;
-+ break;
-+ }
-+
-+ if (!found)
-+ continue;
-+ }
-+
- if (link == t->parms.link)
- return t;
- else
-@@ -132,7 +151,7 @@ ip6_tnl_lookup(struct net *net, int link
- }
-
- memset(&any, 0, sizeof(any));
-- hash = HASH(&any, local);
-+ hash = HASH(local);
- for_each_ip6_tunnel_rcu(ip6n->tnls_r_l[hash]) {
- if (!ipv6_addr_equal(local, &t->parms.laddr) ||
- !ipv6_addr_any(&t->parms.raddr) ||
-@@ -145,7 +164,7 @@ ip6_tnl_lookup(struct net *net, int link
- cand = t;
- }
-
-- hash = HASH(remote, &any);
-+ hash = HASH(&any);
- for_each_ip6_tunnel_rcu(ip6n->tnls_r_l[hash]) {
- if (!ipv6_addr_equal(remote, &t->parms.raddr) ||
- !ipv6_addr_any(&t->parms.laddr) ||
-@@ -194,7 +213,7 @@ ip6_tnl_bucket(struct ip6_tnl_net *ip6n,
-
- if (!ipv6_addr_any(remote) || !ipv6_addr_any(local)) {
- prio = 1;
-- h = HASH(remote, local);
-+ h = HASH(local);
- }
- return &ip6n->tnls[prio][h];
- }
-@@ -376,6 +395,12 @@ ip6_tnl_dev_uninit(struct net_device *de
- struct net *net = t->net;
- struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id);
-
-+ while (t->parms.fmrs) {
-+ struct __ip6_tnl_fmr *next = t->parms.fmrs->next;
-+ kfree(t->parms.fmrs);
-+ t->parms.fmrs = next;
-+ }
-+
- if (dev == ip6n->fb_tnl_dev)
- RCU_INIT_POINTER(ip6n->tnls_wc[0], NULL);
- else
-@@ -788,6 +813,107 @@ int ip6_tnl_rcv_ctl(struct ip6_tnl *t,
- }
- EXPORT_SYMBOL_GPL(ip6_tnl_rcv_ctl);
-
-+/**
-+ * ip4ip6_fmr_calc - calculate target / source IPv6-address based on FMR
-+ * @dest: destination IPv6 address buffer
-+ * @skb: received socket buffer
-+ * @fmr: MAP FMR
-+ * @xmit: Calculate for xmit or rcv
-+ **/
-+static void ip4ip6_fmr_calc(struct in6_addr *dest,
-+ const struct iphdr *iph, const uint8_t *end,
-+ const struct __ip6_tnl_fmr *fmr, bool xmit)
-+{
-+ int psidlen = fmr->ea_len - (32 - fmr->ip4_prefix_len);
-+ u8 *portp = NULL;
-+ bool use_dest_addr;
-+ const struct iphdr *dsth = iph;
-+
-+ if ((u8*)dsth >= end)
-+ return;
-+
-+ /* find significant IP header */
-+ if (iph->protocol == IPPROTO_ICMP) {
-+ struct icmphdr *ih = (struct icmphdr*)(((u8*)dsth) + dsth->ihl * 4);
-+ if (ih && ((u8*)&ih[1]) <= end && (
-+ ih->type == ICMP_DEST_UNREACH ||
-+ ih->type == ICMP_SOURCE_QUENCH ||
-+ ih->type == ICMP_TIME_EXCEEDED ||
-+ ih->type == ICMP_PARAMETERPROB ||
-+ ih->type == ICMP_REDIRECT))
-+ dsth = (const struct iphdr*)&ih[1];
-+ }
-+
-+ /* in xmit-path use dest port by default and source port only if
-+ this is an ICMP reply to something else; vice versa in rcv-path */
-+ use_dest_addr = (xmit && dsth == iph) || (!xmit && dsth != iph);
-+
-+ /* get dst port */
-+ if (((u8*)&dsth[1]) <= end && (
-+ dsth->protocol == IPPROTO_UDP ||
-+ dsth->protocol == IPPROTO_TCP ||
-+ dsth->protocol == IPPROTO_SCTP ||
-+ dsth->protocol == IPPROTO_DCCP)) {
-+ /* for UDP, TCP, SCTP and DCCP source and dest port
-+ follow IPv4 header directly */
-+ portp = ((u8*)dsth) + dsth->ihl * 4;
-+
-+ if (use_dest_addr)
-+ portp += sizeof(u16);
-+ } else if (iph->protocol == IPPROTO_ICMP) {
-+ struct icmphdr *ih = (struct icmphdr*)(((u8*)dsth) + dsth->ihl * 4);
-+
-+ /* use icmp identifier as port */
-+ if (((u8*)&ih) <= end && (
-+ (use_dest_addr && (
-+ ih->type == ICMP_ECHOREPLY ||
-+ ih->type == ICMP_TIMESTAMPREPLY ||
-+ ih->type == ICMP_INFO_REPLY ||
-+ ih->type == ICMP_ADDRESSREPLY)) ||
-+ (!use_dest_addr && (
-+ ih->type == ICMP_ECHO ||
-+ ih->type == ICMP_TIMESTAMP ||
-+ ih->type == ICMP_INFO_REQUEST ||
-+ ih->type == ICMP_ADDRESS)
-+ )))
-+ portp = (u8*)&ih->un.echo.id;
-+ }
-+
-+ if ((portp && &portp[2] <= end) || psidlen == 0) {
-+ int frombyte = fmr->ip6_prefix_len / 8;
-+ int fromrem = fmr->ip6_prefix_len % 8;
-+ int bytes = sizeof(struct in6_addr) - frombyte;
-+ const u32 *addr = (use_dest_addr) ? &iph->daddr : &iph->saddr;
-+ u64 eabits = ((u64)ntohl(*addr)) << (32 + fmr->ip4_prefix_len);
-+ u64 t = 0;
-+
-+ /* extract PSID from port and add it to eabits */
-+ u16 psidbits = 0;
-+ if (psidlen > 0) {
-+ psidbits = ((u16)portp[0]) << 8 | ((u16)portp[1]);
-+ psidbits >>= 16 - psidlen - fmr->offset;
-+ psidbits = (u16)(psidbits << (16 - psidlen));
-+ eabits |= ((u64)psidbits) << (48 - (fmr->ea_len - psidlen));
-+ }
-+
-+ /* rewrite destination address */
-+ *dest = fmr->ip6_prefix;
-+ memcpy(&dest->s6_addr[10], addr, sizeof(*addr));
-+ dest->s6_addr16[7] = htons(psidbits >> (16 - psidlen));
-+
-+ if (bytes > sizeof(u64))
-+ bytes = sizeof(u64);
-+
-+ /* insert eabits */
-+ memcpy(&t, &dest->s6_addr[frombyte], bytes);
-+ t = be64_to_cpu(t) & ~(((((u64)1) << fmr->ea_len) - 1)
-+ << (64 - fmr->ea_len - fromrem));
-+ t = cpu_to_be64(t | (eabits >> fromrem));
-+ memcpy(&dest->s6_addr[frombyte], &t, bytes);
-+ }
-+}
-+
-+
- static int __ip6_tnl_rcv(struct ip6_tnl *tunnel, struct sk_buff *skb,
- const struct tnl_ptk_info *tpi,
- struct metadata_dst *tun_dst,
-@@ -855,6 +981,27 @@ static int __ip6_tnl_rcv(struct ip6_tnl
-
- memset(skb->cb, 0, sizeof(struct inet6_skb_parm));
-
-+ if (tpi->proto == htons(ETH_P_IP) && tunnel->parms.fmrs &&
-+ !ipv6_addr_equal(&ipv6h->saddr, &tunnel->parms.raddr)) {
-+ /* Packet didn't come from BR, so lookup FMR */
-+ struct __ip6_tnl_fmr *fmr;
-+ struct in6_addr expected = tunnel->parms.raddr;
-+ for (fmr = tunnel->parms.fmrs; fmr; fmr = fmr->next)
-+ if (ipv6_prefix_equal(&ipv6h->saddr,
-+ &fmr->ip6_prefix, fmr->ip6_prefix_len))
-+ break;
-+
-+ /* Check that IPv6 matches IPv4 source to prevent spoofing */
-+ if (fmr)
-+ ip4ip6_fmr_calc(&expected, ip_hdr(skb),
-+ skb_tail_pointer(skb), fmr, false);
-+
-+ if (!ipv6_addr_equal(&ipv6h->saddr, &expected)) {
-+ rcu_read_unlock();
-+ goto drop;
-+ }
-+ }
-+
- __skb_tunnel_rx(skb, tunnel->dev, tunnel->net);
-
- err = dscp_ecn_decapsulate(tunnel, ipv6h, skb);
-@@ -1002,6 +1149,7 @@ static void init_tel_txopt(struct ipv6_t
- opt->ops.opt_nflen = 8;
- }
-
-+
- /**
- * ip6_tnl_addr_conflict - compare packet addresses to tunnel's own
- * @t: the outgoing tunnel device
-@@ -1291,6 +1439,7 @@ ipxip6_tnl_xmit(struct sk_buff *skb, str
- u8 protocol)
- {
- struct ip6_tnl *t = netdev_priv(dev);
-+ struct __ip6_tnl_fmr *fmr;
- struct ipv6hdr *ipv6h;
- const struct iphdr *iph;
- int encap_limit = -1;
-@@ -1390,6 +1539,18 @@ ipxip6_tnl_xmit(struct sk_buff *skb, str
- fl6.flowi6_uid = sock_net_uid(dev_net(dev), NULL);
- dsfield = INET_ECN_encapsulate(dsfield, orig_dsfield);
-
-+ /* try to find matching FMR */
-+ for (fmr = t->parms.fmrs; fmr; fmr = fmr->next) {
-+ unsigned mshift = 32 - fmr->ip4_prefix_len;
-+ if (ntohl(fmr->ip4_prefix.s_addr) >> mshift ==
-+ ntohl(ip_hdr(skb)->daddr) >> mshift)
-+ break;
-+ }
-+
-+ /* change dstaddr according to FMR */
-+ if (fmr)
-+ ip4ip6_fmr_calc(&fl6.daddr, ip_hdr(skb), skb_tail_pointer(skb), fmr, true);
-+
- if (iptunnel_handle_offloads(skb, SKB_GSO_IPXIP6))
- return -1;
-
-@@ -1543,6 +1704,14 @@ ip6_tnl_change(struct ip6_tnl *t, const
- t->parms.link = p->link;
- t->parms.proto = p->proto;
- t->parms.fwmark = p->fwmark;
-+
-+ while (t->parms.fmrs) {
-+ struct __ip6_tnl_fmr *next = t->parms.fmrs->next;
-+ kfree(t->parms.fmrs);
-+ t->parms.fmrs = next;
-+ }
-+ t->parms.fmrs = p->fmrs;
-+
- dst_cache_reset(&t->dst_cache);
- ip6_tnl_link_config(t);
- }
-@@ -1577,6 +1746,7 @@ ip6_tnl_parm_from_user(struct __ip6_tnl_
- p->flowinfo = u->flowinfo;
- p->link = u->link;
- p->proto = u->proto;
-+ p->fmrs = NULL;
- memcpy(p->name, u->name, sizeof(u->name));
- }
-
-@@ -1965,6 +2135,15 @@ static int ip6_tnl_validate(struct nlatt
- return 0;
- }
-
-+static const struct nla_policy ip6_tnl_fmr_policy[IFLA_IPTUN_FMR_MAX + 1] = {
-+ [IFLA_IPTUN_FMR_IP6_PREFIX] = { .len = sizeof(struct in6_addr) },
-+ [IFLA_IPTUN_FMR_IP4_PREFIX] = { .len = sizeof(struct in_addr) },
-+ [IFLA_IPTUN_FMR_IP6_PREFIX_LEN] = { .type = NLA_U8 },
-+ [IFLA_IPTUN_FMR_IP4_PREFIX_LEN] = { .type = NLA_U8 },
-+ [IFLA_IPTUN_FMR_EA_LEN] = { .type = NLA_U8 },
-+ [IFLA_IPTUN_FMR_OFFSET] = { .type = NLA_U8 }
-+};
-+
- static void ip6_tnl_netlink_parms(struct nlattr *data[],
- struct __ip6_tnl_parm *parms)
- {
-@@ -2002,6 +2181,46 @@ static void ip6_tnl_netlink_parms(struct
-
- if (data[IFLA_IPTUN_FWMARK])
- parms->fwmark = nla_get_u32(data[IFLA_IPTUN_FWMARK]);
-+
-+ if (data[IFLA_IPTUN_FMRS]) {
-+ unsigned rem;
-+ struct nlattr *fmr;
-+ nla_for_each_nested(fmr, data[IFLA_IPTUN_FMRS], rem) {
-+ struct nlattr *fmrd[IFLA_IPTUN_FMR_MAX + 1], *c;
-+ struct __ip6_tnl_fmr *nfmr;
-+
-+ nla_parse_nested(fmrd, IFLA_IPTUN_FMR_MAX,
-+ fmr, ip6_tnl_fmr_policy, NULL);
-+
-+ if (!(nfmr = kzalloc(sizeof(*nfmr), GFP_KERNEL)))
-+ continue;
-+
-+ nfmr->offset = 6;
-+
-+ if ((c = fmrd[IFLA_IPTUN_FMR_IP6_PREFIX]))
-+ nla_memcpy(&nfmr->ip6_prefix, fmrd[IFLA_IPTUN_FMR_IP6_PREFIX],
-+ sizeof(nfmr->ip6_prefix));
-+
-+ if ((c = fmrd[IFLA_IPTUN_FMR_IP4_PREFIX]))
-+ nla_memcpy(&nfmr->ip4_prefix, fmrd[IFLA_IPTUN_FMR_IP4_PREFIX],
-+ sizeof(nfmr->ip4_prefix));
-+
-+ if ((c = fmrd[IFLA_IPTUN_FMR_IP6_PREFIX_LEN]))
-+ nfmr->ip6_prefix_len = nla_get_u8(c);
-+
-+ if ((c = fmrd[IFLA_IPTUN_FMR_IP4_PREFIX_LEN]))
-+ nfmr->ip4_prefix_len = nla_get_u8(c);
-+
-+ if ((c = fmrd[IFLA_IPTUN_FMR_EA_LEN]))
-+ nfmr->ea_len = nla_get_u8(c);
-+
-+ if ((c = fmrd[IFLA_IPTUN_FMR_OFFSET]))
-+ nfmr->offset = nla_get_u8(c);
-+
-+ nfmr->next = parms->fmrs;
-+ parms->fmrs = nfmr;
-+ }
-+ }
- }
-
- static int ip6_tnl_newlink(struct net *src_net, struct net_device *dev,
-@@ -2085,6 +2304,12 @@ static void ip6_tnl_dellink(struct net_d
-
- static size_t ip6_tnl_get_size(const struct net_device *dev)
- {
-+ const struct ip6_tnl *t = netdev_priv(dev);
-+ struct __ip6_tnl_fmr *c;
-+ int fmrs = 0;
-+ for (c = t->parms.fmrs; c; c = c->next)
-+ ++fmrs;
-+
- return
- /* IFLA_IPTUN_LINK */
- nla_total_size(4) +
-@@ -2114,6 +2339,24 @@ static size_t ip6_tnl_get_size(const str
- nla_total_size(0) +
- /* IFLA_IPTUN_FWMARK */
- nla_total_size(4) +
-+ /* IFLA_IPTUN_FMRS */
-+ nla_total_size(0) +
-+ (
-+ /* nest */
-+ nla_total_size(0) +
-+ /* IFLA_IPTUN_FMR_IP6_PREFIX */
-+ nla_total_size(sizeof(struct in6_addr)) +
-+ /* IFLA_IPTUN_FMR_IP4_PREFIX */
-+ nla_total_size(sizeof(struct in_addr)) +
-+ /* IFLA_IPTUN_FMR_EA_LEN */
-+ nla_total_size(1) +
-+ /* IFLA_IPTUN_FMR_IP6_PREFIX_LEN */
-+ nla_total_size(1) +
-+ /* IFLA_IPTUN_FMR_IP4_PREFIX_LEN */
-+ nla_total_size(1) +
-+ /* IFLA_IPTUN_FMR_OFFSET */
-+ nla_total_size(1)
-+ ) * fmrs +
- 0;
- }
-
-@@ -2121,6 +2364,9 @@ static int ip6_tnl_fill_info(struct sk_b
- {
- struct ip6_tnl *tunnel = netdev_priv(dev);
- struct __ip6_tnl_parm *parm = &tunnel->parms;
-+ struct __ip6_tnl_fmr *c;
-+ int fmrcnt = 0;
-+ struct nlattr *fmrs;
-
- if (nla_put_u32(skb, IFLA_IPTUN_LINK, parm->link) ||
- nla_put_in6_addr(skb, IFLA_IPTUN_LOCAL, &parm->laddr) ||
-@@ -2130,9 +2376,27 @@ static int ip6_tnl_fill_info(struct sk_b
- nla_put_be32(skb, IFLA_IPTUN_FLOWINFO, parm->flowinfo) ||
- nla_put_u32(skb, IFLA_IPTUN_FLAGS, parm->flags) ||
- nla_put_u8(skb, IFLA_IPTUN_PROTO, parm->proto) ||
-- nla_put_u32(skb, IFLA_IPTUN_FWMARK, parm->fwmark))
-+ nla_put_u32(skb, IFLA_IPTUN_FWMARK, parm->fwmark) ||
-+ !(fmrs = nla_nest_start(skb, IFLA_IPTUN_FMRS)))
- goto nla_put_failure;
-
-+ for (c = parm->fmrs; c; c = c->next) {
-+ struct nlattr *fmr = nla_nest_start(skb, ++fmrcnt);
-+ if (!fmr ||
-+ nla_put(skb, IFLA_IPTUN_FMR_IP6_PREFIX,
-+ sizeof(c->ip6_prefix), &c->ip6_prefix) ||
-+ nla_put(skb, IFLA_IPTUN_FMR_IP4_PREFIX,
-+ sizeof(c->ip4_prefix), &c->ip4_prefix) ||
-+ nla_put_u8(skb, IFLA_IPTUN_FMR_IP6_PREFIX_LEN, c->ip6_prefix_len) ||
-+ nla_put_u8(skb, IFLA_IPTUN_FMR_IP4_PREFIX_LEN, c->ip4_prefix_len) ||
-+ nla_put_u8(skb, IFLA_IPTUN_FMR_EA_LEN, c->ea_len) ||
-+ nla_put_u8(skb, IFLA_IPTUN_FMR_OFFSET, c->offset))
-+ goto nla_put_failure;
-+
-+ nla_nest_end(skb, fmr);
-+ }
-+ nla_nest_end(skb, fmrs);
-+
- if (nla_put_u16(skb, IFLA_IPTUN_ENCAP_TYPE, tunnel->encap.type) ||
- nla_put_be16(skb, IFLA_IPTUN_ENCAP_SPORT, tunnel->encap.sport) ||
- nla_put_be16(skb, IFLA_IPTUN_ENCAP_DPORT, tunnel->encap.dport) ||
-@@ -2172,6 +2436,7 @@ static const struct nla_policy ip6_tnl_p
- [IFLA_IPTUN_ENCAP_DPORT] = { .type = NLA_U16 },
- [IFLA_IPTUN_COLLECT_METADATA] = { .type = NLA_FLAG },
- [IFLA_IPTUN_FWMARK] = { .type = NLA_U32 },
-+ [IFLA_IPTUN_FMRS] = { .type = NLA_NESTED },
- };
-
- static struct rtnl_link_ops ip6_link_ops __read_mostly = {
+++ /dev/null
-Subject: ipv6: allow rejecting with "source address failed policy"
-
-RFC6204 L-14 requires rejecting traffic from invalid addresses with
-ICMPv6 Destination Unreachable, Code 5 (Source address failed ingress/
-egress policy) on the LAN side, so add an appropriate rule for that.
-
----
- include/net/netns/ipv6.h | 1 +
- include/uapi/linux/fib_rules.h | 4 +++
- include/uapi/linux/rtnetlink.h | 1 +
- net/ipv4/fib_semantics.c | 4 +++
- net/ipv4/fib_trie.c | 1 +
- net/ipv4/ipmr.c | 1 +
- net/ipv6/fib6_rules.c | 4 +++
- net/ipv6/ip6mr.c | 2 ++
- net/ipv6/route.c | 58 +++++++++++++++++++++++++++++++++++++++++-
- 9 files changed, 75 insertions(+), 1 deletion(-)
-
---- a/include/net/netns/ipv6.h
-+++ b/include/net/netns/ipv6.h
-@@ -86,6 +86,7 @@ struct netns_ipv6 {
- unsigned int fib6_routes_require_src;
- #endif
- struct rt6_info *ip6_prohibit_entry;
-+ struct rt6_info *ip6_policy_failed_entry;
- struct rt6_info *ip6_blk_hole_entry;
- struct fib6_table *fib6_local_tbl;
- struct fib_rules_ops *fib6_rules_ops;
---- a/include/uapi/linux/fib_rules.h
-+++ b/include/uapi/linux/fib_rules.h
-@@ -82,6 +82,10 @@ enum {
- FR_ACT_BLACKHOLE, /* Drop without notification */
- FR_ACT_UNREACHABLE, /* Drop with ENETUNREACH */
- FR_ACT_PROHIBIT, /* Drop with EACCES */
-+ FR_ACT_RES9,
-+ FR_ACT_RES10,
-+ FR_ACT_RES11,
-+ FR_ACT_POLICY_FAILED, /* Drop with EACCES */
- __FR_ACT_MAX,
- };
-
---- a/include/uapi/linux/rtnetlink.h
-+++ b/include/uapi/linux/rtnetlink.h
-@@ -265,6 +265,7 @@ enum {
- RTN_THROW, /* Not in this table */
- RTN_NAT, /* Translate this address */
- RTN_XRESOLVE, /* Use external resolver */
-+ RTN_POLICY_FAILED, /* Failed ingress/egress policy */
- __RTN_MAX
- };
-
---- a/net/ipv4/fib_semantics.c
-+++ b/net/ipv4/fib_semantics.c
-@@ -145,6 +145,10 @@ const struct fib_prop fib_props[RTN_MAX
- .error = -EINVAL,
- .scope = RT_SCOPE_NOWHERE,
- },
-+ [RTN_POLICY_FAILED] = {
-+ .error = -EACCES,
-+ .scope = RT_SCOPE_UNIVERSE,
-+ },
- };
-
- static void rt_fibinfo_free(struct rtable __rcu **rtp)
---- a/net/ipv4/fib_trie.c
-+++ b/net/ipv4/fib_trie.c
-@@ -2762,6 +2762,7 @@ static const char *const rtn_type_names[
- [RTN_THROW] = "THROW",
- [RTN_NAT] = "NAT",
- [RTN_XRESOLVE] = "XRESOLVE",
-+ [RTN_POLICY_FAILED] = "POLICY_FAILED",
- };
-
- static inline const char *rtn_type(char *buf, size_t len, unsigned int t)
---- a/net/ipv4/ipmr.c
-+++ b/net/ipv4/ipmr.c
-@@ -190,6 +190,7 @@ static int ipmr_rule_action(struct fib_r
- case FR_ACT_UNREACHABLE:
- return -ENETUNREACH;
- case FR_ACT_PROHIBIT:
-+ case FR_ACT_POLICY_FAILED:
- return -EACCES;
- case FR_ACT_BLACKHOLE:
- default:
---- a/net/ipv6/fib6_rules.c
-+++ b/net/ipv6/fib6_rules.c
-@@ -221,6 +221,10 @@ static int __fib6_rule_action(struct fib
- err = -EACCES;
- rt = net->ipv6.ip6_prohibit_entry;
- goto discard_pkt;
-+ case FR_ACT_POLICY_FAILED:
-+ err = -EACCES;
-+ rt = net->ipv6.ip6_policy_failed_entry;
-+ goto discard_pkt;
- }
-
- tb_id = fib_rule_get_table(rule, arg);
---- a/net/ipv6/ip6mr.c
-+++ b/net/ipv6/ip6mr.c
-@@ -180,6 +180,8 @@ static int ip6mr_rule_action(struct fib_
- return -ENETUNREACH;
- case FR_ACT_PROHIBIT:
- return -EACCES;
-+ case FR_ACT_POLICY_FAILED:
-+ return -EACCES;
- case FR_ACT_BLACKHOLE:
- default:
- return -EINVAL;
---- a/net/ipv6/route.c
-+++ b/net/ipv6/route.c
-@@ -98,6 +98,8 @@ static int ip6_pkt_discard(struct sk_bu
- static int ip6_pkt_discard_out(struct net *net, struct sock *sk, struct sk_buff *skb);
- static int ip6_pkt_prohibit(struct sk_buff *skb);
- static int ip6_pkt_prohibit_out(struct net *net, struct sock *sk, struct sk_buff *skb);
-+static int ip6_pkt_policy_failed(struct sk_buff *skb);
-+static int ip6_pkt_policy_failed_out(struct net *net, struct sock *sk, struct sk_buff *skb);
- static void ip6_link_failure(struct sk_buff *skb);
- static void ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk,
- struct sk_buff *skb, u32 mtu,
-@@ -318,6 +320,18 @@ static const struct rt6_info ip6_prohibi
- .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP),
- };
-
-+static const struct rt6_info ip6_policy_failed_entry_template = {
-+ .dst = {
-+ .__rcuref = RCUREF_INIT(1),
-+ .__use = 1,
-+ .obsolete = DST_OBSOLETE_FORCE_CHK,
-+ .error = -EACCES,
-+ .input = ip6_pkt_policy_failed,
-+ .output = ip6_pkt_policy_failed_out,
-+ },
-+ .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP),
-+};
-+
- static const struct rt6_info ip6_blk_hole_entry_template = {
- .dst = {
- .__rcuref = RCUREF_INIT(1),
-@@ -1077,6 +1091,7 @@ static const int fib6_prop[RTN_MAX + 1]
- [RTN_BLACKHOLE] = -EINVAL,
- [RTN_UNREACHABLE] = -EHOSTUNREACH,
- [RTN_PROHIBIT] = -EACCES,
-+ [RTN_POLICY_FAILED] = -EACCES,
- [RTN_THROW] = -EAGAIN,
- [RTN_NAT] = -EINVAL,
- [RTN_XRESOLVE] = -EINVAL,
-@@ -1112,6 +1127,10 @@ static void ip6_rt_init_dst_reject(struc
- rt->dst.output = ip6_pkt_prohibit_out;
- rt->dst.input = ip6_pkt_prohibit;
- break;
-+ case RTN_POLICY_FAILED:
-+ rt->dst.output = ip6_pkt_policy_failed_out;
-+ rt->dst.input = ip6_pkt_policy_failed;
-+ break;
- case RTN_THROW:
- case RTN_UNREACHABLE:
- default:
-@@ -4588,6 +4607,17 @@ static int ip6_pkt_prohibit_out(struct n
- return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_OUTNOROUTES);
- }
-
-+static int ip6_pkt_policy_failed(struct sk_buff *skb)
-+{
-+ return ip6_pkt_drop(skb, ICMPV6_POLICY_FAIL, IPSTATS_MIB_INNOROUTES);
-+}
-+
-+static int ip6_pkt_policy_failed_out(struct net *net, struct sock *sk, struct sk_buff *skb)
-+{
-+ skb->dev = skb_dst(skb)->dev;
-+ return ip6_pkt_drop(skb, ICMPV6_POLICY_FAIL, IPSTATS_MIB_OUTNOROUTES);
-+}
-+
- /*
- * Allocate a dst for local (unicast / anycast) address.
- */
-@@ -5079,7 +5109,8 @@ static int rtm_to_fib6_config(struct sk_
- if (rtm->rtm_type == RTN_UNREACHABLE ||
- rtm->rtm_type == RTN_BLACKHOLE ||
- rtm->rtm_type == RTN_PROHIBIT ||
-- rtm->rtm_type == RTN_THROW)
-+ rtm->rtm_type == RTN_THROW ||
-+ rtm->rtm_type == RTN_POLICY_FAILED)
- cfg->fc_flags |= RTF_REJECT;
-
- if (rtm->rtm_type == RTN_LOCAL)
-@@ -6349,6 +6380,8 @@ static int ip6_route_dev_notify(struct n
- #ifdef CONFIG_IPV6_MULTIPLE_TABLES
- net->ipv6.ip6_prohibit_entry->dst.dev = dev;
- net->ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(dev);
-+ net->ipv6.ip6_policy_failed_entry->dst.dev = dev;
-+ net->ipv6.ip6_policy_failed_entry->rt6i_idev = in6_dev_get(dev);
- net->ipv6.ip6_blk_hole_entry->dst.dev = dev;
- net->ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(dev);
- #endif
-@@ -6360,6 +6393,7 @@ static int ip6_route_dev_notify(struct n
- in6_dev_put_clear(&net->ipv6.ip6_null_entry->rt6i_idev);
- #ifdef CONFIG_IPV6_MULTIPLE_TABLES
- in6_dev_put_clear(&net->ipv6.ip6_prohibit_entry->rt6i_idev);
-+ in6_dev_put_clear(&net->ipv6.ip6_policy_failed_entry->rt6i_idev);
- in6_dev_put_clear(&net->ipv6.ip6_blk_hole_entry->rt6i_idev);
- #endif
- }
-@@ -6560,6 +6594,8 @@ static int __net_init ip6_route_net_init
-
- #ifdef CONFIG_IPV6_MULTIPLE_TABLES
- net->ipv6.fib6_has_custom_rules = false;
-+
-+
- net->ipv6.ip6_prohibit_entry = kmemdup(&ip6_prohibit_entry_template,
- sizeof(*net->ipv6.ip6_prohibit_entry),
- GFP_KERNEL);
-@@ -6570,11 +6606,21 @@ static int __net_init ip6_route_net_init
- ip6_template_metrics, true);
- INIT_LIST_HEAD(&net->ipv6.ip6_prohibit_entry->dst.rt_uncached);
-
-+ net->ipv6.ip6_policy_failed_entry =
-+ kmemdup(&ip6_policy_failed_entry_template,
-+ sizeof(*net->ipv6.ip6_policy_failed_entry), GFP_KERNEL);
-+ if (!net->ipv6.ip6_policy_failed_entry)
-+ goto out_ip6_prohibit_entry;
-+ net->ipv6.ip6_policy_failed_entry->dst.ops = &net->ipv6.ip6_dst_ops;
-+ dst_init_metrics(&net->ipv6.ip6_policy_failed_entry->dst,
-+ ip6_template_metrics, true);
-+ INIT_LIST_HEAD(&net->ipv6.ip6_policy_failed_entry->dst.rt_uncached);
-+
- net->ipv6.ip6_blk_hole_entry = kmemdup(&ip6_blk_hole_entry_template,
- sizeof(*net->ipv6.ip6_blk_hole_entry),
- GFP_KERNEL);
- if (!net->ipv6.ip6_blk_hole_entry)
-- goto out_ip6_prohibit_entry;
-+ goto out_ip6_policy_failed_entry;
- net->ipv6.ip6_blk_hole_entry->dst.ops = &net->ipv6.ip6_dst_ops;
- dst_init_metrics(&net->ipv6.ip6_blk_hole_entry->dst,
- ip6_template_metrics, true);
-@@ -6601,6 +6647,8 @@ out:
- return ret;
-
- #ifdef CONFIG_IPV6_MULTIPLE_TABLES
-+out_ip6_policy_failed_entry:
-+ kfree(net->ipv6.ip6_policy_failed_entry);
- out_ip6_prohibit_entry:
- kfree(net->ipv6.ip6_prohibit_entry);
- out_ip6_null_entry:
-@@ -6620,6 +6668,7 @@ static void __net_exit ip6_route_net_exi
- kfree(net->ipv6.ip6_null_entry);
- #ifdef CONFIG_IPV6_MULTIPLE_TABLES
- kfree(net->ipv6.ip6_prohibit_entry);
-+ kfree(net->ipv6.ip6_policy_failed_entry);
- kfree(net->ipv6.ip6_blk_hole_entry);
- #endif
- dst_entries_destroy(&net->ipv6.ip6_dst_ops);
-@@ -6703,6 +6752,9 @@ void __init ip6_route_init_special_entri
- init_net.ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
- init_net.ipv6.ip6_blk_hole_entry->dst.dev = init_net.loopback_dev;
- init_net.ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
-+ init_net.ipv6.ip6_policy_failed_entry->dst.dev = init_net.loopback_dev;
-+ init_net.ipv6.ip6_policy_failed_entry->rt6i_idev =
-+ in6_dev_get(init_net.loopback_dev);
- #endif
- }
-
+++ /dev/null
-Subject: net: provide defines for _POLICY_FAILED until all code is updated
-
-Upstream introduced ICMPV6_POLICY_FAIL for code 5 of destination
-unreachable, conflicting with our name.
-
-Add appropriate defines to allow our code to build with the new
-name until we have updated our local patches for older kernels
-and userspace packages.
-
----
- include/uapi/linux/fib_rules.h | 2 ++
- include/uapi/linux/icmpv6.h | 2 ++
- include/uapi/linux/rtnetlink.h | 2 ++
- 3 files changed, 6 insertions(+)
-
---- a/include/uapi/linux/fib_rules.h
-+++ b/include/uapi/linux/fib_rules.h
-@@ -89,6 +89,8 @@ enum {
- __FR_ACT_MAX,
- };
-
-+#define FR_ACT_FAILED_POLICY FR_ACT_POLICY_FAILED
-+
- #define FR_ACT_MAX (__FR_ACT_MAX - 1)
-
- #endif
---- a/include/uapi/linux/icmpv6.h
-+++ b/include/uapi/linux/icmpv6.h
-@@ -126,6 +126,8 @@ struct icmp6hdr {
- #define ICMPV6_POLICY_FAIL 5
- #define ICMPV6_REJECT_ROUTE 6
-
-+#define ICMPV6_FAILED_POLICY ICMPV6_POLICY_FAIL
-+
- /*
- * Codes for Time Exceeded
- */
---- a/include/uapi/linux/rtnetlink.h
-+++ b/include/uapi/linux/rtnetlink.h
-@@ -269,6 +269,8 @@ enum {
- __RTN_MAX
- };
-
-+#define RTN_FAILED_POLICY RTN_POLICY_FAILED
-+
- #define RTN_MAX (__RTN_MAX - 1)
-
-
+++ /dev/null
-Date: Thu, 15 Aug 2024 21:15:13 +0200
-Subject: [PATCH] net: remove NETIF_F_GSO_FRAGLIST from NETIF_F_GSO_SOFTWARE
-
-Several drivers set NETIF_F_GSO_SOFTWARE, but mangle fraglist GRO packets
-in a way that they can't be properly segmented anymore.
-In order to properly deal with this, remove fraglist GSO from
-NETIF_F_GSO_SOFTWARE and switch to NETIF_F_GSO_SOFTWARE_ALL (which includes
-fraglist GSO) in places where it's safe to add.
-
----
-
---- a/drivers/net/dummy.c
-+++ b/drivers/net/dummy.c
-@@ -118,7 +118,7 @@ static void dummy_setup(struct net_devic
- dev->flags &= ~IFF_MULTICAST;
- dev->priv_flags |= IFF_LIVE_ADDR_CHANGE | IFF_NO_QUEUE;
- dev->features |= NETIF_F_SG | NETIF_F_FRAGLIST;
-- dev->features |= NETIF_F_GSO_SOFTWARE;
-+ dev->features |= NETIF_F_GSO_SOFTWARE_ALL;
- dev->features |= NETIF_F_HW_CSUM | NETIF_F_HIGHDMA | NETIF_F_LLTX;
- dev->features |= NETIF_F_GSO_ENCAP_ALL;
- dev->hw_features |= dev->features;
---- a/drivers/net/loopback.c
-+++ b/drivers/net/loopback.c
-@@ -176,7 +176,7 @@ static void gen_lo_setup(struct net_devi
- dev->flags = IFF_LOOPBACK;
- dev->priv_flags |= IFF_LIVE_ADDR_CHANGE | IFF_NO_QUEUE;
- netif_keep_dst(dev);
-- dev->hw_features = NETIF_F_GSO_SOFTWARE;
-+ dev->hw_features = NETIF_F_GSO_SOFTWARE_ALL;
- dev->features = NETIF_F_SG | NETIF_F_FRAGLIST
- | NETIF_F_GSO_SOFTWARE
- | NETIF_F_HW_CSUM
---- a/drivers/net/macvlan.c
-+++ b/drivers/net/macvlan.c
-@@ -896,7 +896,7 @@ static int macvlan_hwtstamp_set(struct n
- static struct lock_class_key macvlan_netdev_addr_lock_key;
-
- #define ALWAYS_ON_OFFLOADS \
-- (NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_GSO_SOFTWARE | \
-+ (NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_GSO_SOFTWARE_ALL | \
- NETIF_F_GSO_ROBUST | NETIF_F_GSO_ENCAP_ALL)
-
- #define ALWAYS_ON_FEATURES (ALWAYS_ON_OFFLOADS | NETIF_F_LLTX)
---- a/include/linux/netdev_features.h
-+++ b/include/linux/netdev_features.h
-@@ -219,13 +219,14 @@ static inline int find_next_netdev_featu
-
- /* List of features with software fallbacks. */
- #define NETIF_F_GSO_SOFTWARE (NETIF_F_ALL_TSO | NETIF_F_GSO_SCTP | \
-- NETIF_F_GSO_UDP_L4 | NETIF_F_GSO_FRAGLIST)
-+ NETIF_F_GSO_UDP_L4)
-+#define NETIF_F_GSO_SOFTWARE_ALL (NETIF_F_GSO_SOFTWARE | NETIF_F_GSO_FRAGLIST)
-
- /*
- * If one device supports one of these features, then enable them
- * for all in netdev_increment_features.
- */
--#define NETIF_F_ONE_FOR_ALL (NETIF_F_GSO_SOFTWARE | NETIF_F_GSO_ROBUST | \
-+#define NETIF_F_ONE_FOR_ALL (NETIF_F_GSO_SOFTWARE_ALL | NETIF_F_GSO_ROBUST | \
- NETIF_F_SG | NETIF_F_HIGHDMA | \
- NETIF_F_FRAGLIST | NETIF_F_VLAN_CHALLENGED)
-
---- a/net/8021q/vlan.h
-+++ b/net/8021q/vlan.h
-@@ -109,7 +109,7 @@ static inline netdev_features_t vlan_tnl
- netdev_features_t ret;
-
- ret = real_dev->hw_enc_features &
-- (NETIF_F_CSUM_MASK | NETIF_F_GSO_SOFTWARE |
-+ (NETIF_F_CSUM_MASK | NETIF_F_GSO_SOFTWARE_ALL |
- NETIF_F_GSO_ENCAP_ALL);
-
- if ((ret & NETIF_F_GSO_ENCAP_ALL) && (ret & NETIF_F_CSUM_MASK))
---- a/net/8021q/vlan_dev.c
-+++ b/net/8021q/vlan_dev.c
-@@ -560,7 +560,7 @@ static int vlan_dev_init(struct net_devi
- dev->state |= (1 << __LINK_STATE_NOCARRIER);
-
- dev->hw_features = NETIF_F_HW_CSUM | NETIF_F_SG |
-- NETIF_F_FRAGLIST | NETIF_F_GSO_SOFTWARE |
-+ NETIF_F_FRAGLIST | NETIF_F_GSO_SOFTWARE_ALL |
- NETIF_F_GSO_ENCAP_ALL |
- NETIF_F_HIGHDMA | NETIF_F_SCTP_CRC |
- NETIF_F_ALL_FCOE;
-@@ -653,7 +653,7 @@ static netdev_features_t vlan_dev_fix_fe
- if (lower_features & (NETIF_F_IP_CSUM|NETIF_F_IPV6_CSUM))
- lower_features |= NETIF_F_HW_CSUM;
- features = netdev_intersect_features(features, lower_features);
-- features |= old_features & (NETIF_F_SOFT_FEATURES | NETIF_F_GSO_SOFTWARE);
-+ features |= old_features & (NETIF_F_SOFT_FEATURES | NETIF_F_GSO_SOFTWARE_ALL);
- features |= NETIF_F_LLTX;
-
- return features;
---- a/net/core/sock.c
-+++ b/net/core/sock.c
-@@ -2466,7 +2466,7 @@ void sk_setup_caps(struct sock *sk, stru
- if (sk_is_tcp(sk))
- sk->sk_route_caps |= NETIF_F_GSO;
- if (sk->sk_route_caps & NETIF_F_GSO)
-- sk->sk_route_caps |= NETIF_F_GSO_SOFTWARE;
-+ sk->sk_route_caps |= NETIF_F_GSO_SOFTWARE_ALL;
- if (unlikely(sk->sk_gso_disabled))
- sk->sk_route_caps &= ~NETIF_F_GSO_MASK;
- if (sk_can_gso(sk)) {
---- a/net/mac80211/ieee80211_i.h
-+++ b/net/mac80211/ieee80211_i.h
-@@ -2005,7 +2005,7 @@ void ieee80211_color_collision_detection
- /* interface handling */
- #define MAC80211_SUPPORTED_FEATURES_TX (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | \
- NETIF_F_HW_CSUM | NETIF_F_SG | \
-- NETIF_F_HIGHDMA | NETIF_F_GSO_SOFTWARE | \
-+ NETIF_F_HIGHDMA | NETIF_F_GSO_SOFTWARE_ALL | \
- NETIF_F_HW_TC)
- #define MAC80211_SUPPORTED_FEATURES_RX (NETIF_F_RXCSUM)
- #define MAC80211_SUPPORTED_FEATURES (MAC80211_SUPPORTED_FEATURES_TX | \
---- a/net/openvswitch/vport-internal_dev.c
-+++ b/net/openvswitch/vport-internal_dev.c
-@@ -110,7 +110,7 @@ static void do_setup(struct net_device *
-
- netdev->features = NETIF_F_LLTX | NETIF_F_SG | NETIF_F_FRAGLIST |
- NETIF_F_HIGHDMA | NETIF_F_HW_CSUM |
-- NETIF_F_GSO_SOFTWARE | NETIF_F_GSO_ENCAP_ALL;
-+ NETIF_F_GSO_SOFTWARE_ALL | NETIF_F_GSO_ENCAP_ALL;
-
- netdev->vlan_features = netdev->features;
- netdev->hw_enc_features = netdev->features;
+++ /dev/null
-From 8585756342caa6d27008d1ad0c18023e4211a40a Mon Sep 17 00:00:00 2001
-Date: Wed, 13 Jul 2022 12:22:48 +0200
-Subject: [PATCH] of/of_net: write back netdev MAC-address to device-tree
-
-The label-mac logic relies on the mac-address property of a netdev
-devices of-node. However, the mac address can also be stored as a
-different property or read from e.g. an mtd device.
-
-Create this node when reading a mac-address from OF if it does not
-already exist and copy the mac-address used for the device to this
-property. This way, the MAC address can be accessed using procfs.
-
----
- net/core/of_net.c | 22 ++++++++++++++++++++++
- 1 file changed, 22 insertions(+)
-
---- a/net/core/of_net.c
-+++ b/net/core/of_net.c
-@@ -97,6 +97,27 @@ int of_get_mac_address_nvmem(struct devi
- }
- EXPORT_SYMBOL(of_get_mac_address_nvmem);
-
-+static int of_add_mac_address(struct device_node *np, u8* addr)
-+{
-+ struct property *prop;
-+
-+ prop = kzalloc(sizeof(*prop), GFP_KERNEL);
-+ if (!prop)
-+ return -ENOMEM;
-+
-+ prop->name = "mac-address";
-+ prop->length = ETH_ALEN;
-+ prop->value = kmemdup(addr, ETH_ALEN, GFP_KERNEL);
-+ if (!prop->value || of_update_property(np, prop))
-+ goto free;
-+
-+ return 0;
-+free:
-+ kfree(prop->value);
-+ kfree(prop);
-+ return -ENOMEM;
-+}
-+
- /**
- * of_get_mac_address()
- * @np: Caller's Device Node
-@@ -132,17 +153,23 @@ int of_get_mac_address(struct device_nod
-
- ret = of_get_mac_addr(np, "mac-address", addr);
- if (!ret)
-- return 0;
-+ goto found;
-
- ret = of_get_mac_addr(np, "local-mac-address", addr);
- if (!ret)
-- return 0;
-+ goto found;
-
- ret = of_get_mac_addr(np, "address", addr);
- if (!ret)
-- return 0;
-+ goto found;
-
-- return of_get_mac_address_nvmem(np, addr);
-+ ret = of_get_mac_address_nvmem(np, addr);
-+ if (ret)
-+ return ret;
-+
-+found:
-+ ret = of_add_mac_address(np, addr);
-+ return ret;
- }
- EXPORT_SYMBOL(of_get_mac_address);
-
+++ /dev/null
-From 4498f0aa561092bc656bfabe7c4bdae41bc4a5b4 Mon Sep 17 00:00:00 2001
-Date: Tue, 7 May 2024 11:24:50 +0200
-Subject: [PATCH] net: add missing check for TCP fraglist GRO
-
-It turns out that the existing checks do not guarantee that the skb can be
-pulled up to the GRO offset. When using the usb r8152 network driver with
-GRO fraglist, the BUG() in __skb_pull is often triggered.
-Fix the crash by adding the missing check.
-
-Fixes: 8d95dc474f85 ("net: add code for TCP fraglist GRO")
----
- net/ipv4/tcp_offload.c | 1 +
- 1 file changed, 1 insertion(+)
-
---- a/net/ipv4/tcp_offload.c
-+++ b/net/ipv4/tcp_offload.c
-@@ -367,6 +367,7 @@ struct sk_buff *tcp_gro_receive(struct l
- flush |= (__force int)(flags ^ tcp_flag_word(th2));
- flush |= skb->ip_summed != p->ip_summed;
- flush |= skb->csum_level != p->csum_level;
-+ flush |= !pskb_may_pull(skb, skb_gro_offset(skb));
- flush |= NAPI_GRO_CB(p)->count >= 64;
-
- if (flush || skb_gro_receive_list(p, skb))
+++ /dev/null
-Date: Thu, 25 Jan 2018 12:58:55 +0100
-Subject: [PATCH] netfilter: nft_flow_offload: handle netdevice events from
- nf_flow_table
-
-Move the code that deals with device events to the core.
-
----
-
---- a/net/netfilter/nf_flow_table_core.c
-+++ b/net/netfilter/nf_flow_table_core.c
-@@ -658,6 +658,23 @@ static struct pernet_operations nf_flow_
- .exit_batch = nf_flow_table_pernet_exit,
- };
-
-+static int nf_flow_table_netdev_event(struct notifier_block *this,
-+ unsigned long event, void *ptr)
-+{
-+ struct net_device *dev = netdev_notifier_info_to_dev(ptr);
-+
-+ if (event != NETDEV_DOWN)
-+ return NOTIFY_DONE;
-+
-+ nf_flow_table_cleanup(dev);
-+
-+ return NOTIFY_DONE;
-+}
-+
-+static struct notifier_block flow_offload_netdev_notifier = {
-+ .notifier_call = nf_flow_table_netdev_event,
-+};
-+
- static int __init nf_flow_table_module_init(void)
- {
- int ret;
-@@ -670,8 +687,14 @@ static int __init nf_flow_table_module_i
- if (ret)
- goto out_offload;
-
-+ ret = register_netdevice_notifier(&flow_offload_netdev_notifier);
-+ if (ret)
-+ goto out_offload_init;
-+
- return 0;
-
-+out_offload_init:
-+ nf_flow_table_offload_exit();
- out_offload:
- unregister_pernet_subsys(&nf_flow_table_net_ops);
- return ret;
-@@ -679,6 +702,7 @@ out_offload:
-
- static void __exit nf_flow_table_module_exit(void)
- {
-+ unregister_netdevice_notifier(&flow_offload_netdev_notifier);
- nf_flow_table_offload_exit();
- unregister_pernet_subsys(&nf_flow_table_net_ops);
- }
---- a/net/netfilter/nft_flow_offload.c
-+++ b/net/netfilter/nft_flow_offload.c
-@@ -486,47 +486,14 @@ static struct nft_expr_type nft_flow_off
- .owner = THIS_MODULE,
- };
-
--static int flow_offload_netdev_event(struct notifier_block *this,
-- unsigned long event, void *ptr)
--{
-- struct net_device *dev = netdev_notifier_info_to_dev(ptr);
--
-- if (event != NETDEV_DOWN)
-- return NOTIFY_DONE;
--
-- nf_flow_table_cleanup(dev);
--
-- return NOTIFY_DONE;
--}
--
--static struct notifier_block flow_offload_netdev_notifier = {
-- .notifier_call = flow_offload_netdev_event,
--};
--
- static int __init nft_flow_offload_module_init(void)
- {
-- int err;
--
-- err = register_netdevice_notifier(&flow_offload_netdev_notifier);
-- if (err)
-- goto err;
--
-- err = nft_register_expr(&nft_flow_offload_type);
-- if (err < 0)
-- goto register_expr;
--
-- return 0;
--
--register_expr:
-- unregister_netdevice_notifier(&flow_offload_netdev_notifier);
--err:
-- return err;
-+ return nft_register_expr(&nft_flow_offload_type);
- }
-
- static void __exit nft_flow_offload_module_exit(void)
- {
- nft_unregister_expr(&nft_flow_offload_type);
-- unregister_netdevice_notifier(&flow_offload_netdev_notifier);
- }
-
- module_init(nft_flow_offload_module_init);
+++ /dev/null
-Date: Thu, 31 Aug 2023 21:48:38 +0200
-Subject: [PATCH] netfilter: nf_tables: ignore -EOPNOTSUPP on flowtable device
- offload setup
-
-On many embedded devices, it is common to configure flowtable offloading for
-a mix of different devices, some of which have hardware offload support and
-some of which don't.
-The current code limits the ability of user space to properly set up such a
-configuration by only allowing adding devices with hardware offload support to
-a offload-enabled flowtable.
-Given that offload-enabled flowtables also imply fallback to pure software
-offloading, this limitation makes little sense.
-Fix it by not bailing out when the offload setup returns -EOPNOTSUPP
-
----
-
---- a/net/netfilter/nf_tables_api.c
-+++ b/net/netfilter/nf_tables_api.c
-@@ -8463,7 +8463,7 @@ static int nft_register_flowtable_net_ho
- err = flowtable->data.type->setup(&flowtable->data,
- hook->ops.dev,
- FLOW_BLOCK_BIND);
-- if (err < 0)
-+ if (err < 0 && err != -EOPNOTSUPP)
- goto err_unregister_net_hooks;
-
- err = nf_register_net_hook(net, &hook->ops);
+++ /dev/null
-Date: Mon, 21 Mar 2022 20:39:59 +0100
-Subject: [PATCH] net: ethernet: mtk_eth_soc: enable threaded NAPI
-
-This can improve performance under load by ensuring that NAPI processing is
-not pinned on CPU 0.
-
----
-
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -5141,6 +5141,8 @@ static int mtk_probe(struct platform_dev
- * for NAPI to work
- */
- init_dummy_netdev(ð->dummy_dev);
-+ eth->dummy_dev.threaded = 1;
-+ strcpy(eth->dummy_dev.name, "mtk_eth");
- netif_napi_add(ð->dummy_dev, ð->tx_napi, mtk_napi_tx);
- netif_napi_add(ð->dummy_dev, ð->rx_napi, mtk_napi_rx);
-
+++ /dev/null
-Subject: generic: add detach callback to struct phy_driver
-
-lede-commit: fe61fc2d7d0b3fb348b502f68f98243b3ddf5867
-
----
- drivers/net/phy/phy_device.c | 3 +++
- include/linux/phy.h | 6 ++++++
- 2 files changed, 9 insertions(+)
-
---- a/drivers/net/phy/phy_device.c
-+++ b/drivers/net/phy/phy_device.c
-@@ -1934,6 +1934,9 @@ void phy_detach(struct phy_device *phyde
- phydev->devlink = NULL;
- }
-
-+ if (phydev->drv && phydev->drv->detach)
-+ phydev->drv->detach(phydev);
-+
- if (phydev->sysfs_links) {
- if (dev)
- sysfs_remove_link(&dev->dev.kobj, "phydev");
---- a/include/linux/phy.h
-+++ b/include/linux/phy.h
-@@ -1008,6 +1008,12 @@ struct phy_driver {
- /** @handle_interrupt: Override default interrupt handling */
- irqreturn_t (*handle_interrupt)(struct phy_device *phydev);
-
-+ /*
-+ * Called before an ethernet device is detached
-+ * from the PHY.
-+ */
-+ void (*detach)(struct phy_device *phydev);
-+
- /** @remove: Clears up any memory if needed */
- void (*remove)(struct phy_device *phydev);
-
+++ /dev/null
-Date: Fri, 6 May 2022 21:38:42 +0200
-Subject: [PATCH] net: dsa: tag_mtk: add padding for tx packets
-
-Padding for transmitted packets needs to account for the special tag.
-With not enough padding, garbage bytes are inserted by the switch at the
-end of small packets.
-
-Fixes: 5cd8985a1909 ("net-next: dsa: add Mediatek tag RX/TX handler")
----
-
---- a/net/dsa/tag_mtk.c
-+++ b/net/dsa/tag_mtk.c
-@@ -29,6 +29,13 @@ static struct sk_buff *mtk_tag_xmit(stru
-
- skb_set_queue_mapping(skb, dp->index);
-
-+ /* The Ethernet switch we are interfaced with needs packets to be at
-+ * least 64 bytes (including FCS) otherwise their padding might be
-+ * corrupted. With tags enabled, we need to make sure that packets are
-+ * at least 68 bytes (including FCS and tag).
-+ */
-+ eth_skb_pad(skb);
-+
- /* Build the special tag after the MAC Source Address. If VLAN header
- * is present, it's required that VLAN header and special tag is
- * being combined. Only in this way we can allow the switch can parse
+++ /dev/null
-From 4e432e530db0056450fbc4a3cee793f16adc39a7 Mon Sep 17 00:00:00 2001
-Date: Tue, 8 Oct 2024 23:58:41 +0100
-Subject: [PATCH] net: phy: populate host_interfaces when attaching PHY
-
-Use bitmask of interfaces supported by the MAC for the PHY to choose
-from if the declared interface mode is among those using a single pair
-of SerDes lanes.
-This will allow 2500Base-T PHYs to switch to SGMII on most hosts, which
-results in half-duplex being supported in case the MAC supports them.
-Without this change, 2500Base-T PHYs will always operate in 2500Base-X
-mode with rate-matching, which is not only wasteful in terms of energy
-consumption, but also limits the supported interface modes to
-full-duplex only.
-
----
- drivers/net/phy/phylink.c | 21 ++++++++++++++++++++-
- 1 file changed, 20 insertions(+), 1 deletion(-)
-
---- a/drivers/net/phy/phylink.c
-+++ b/drivers/net/phy/phylink.c
-@@ -2261,7 +2261,7 @@ int phylink_fwnode_phy_connect(struct ph
- {
- struct fwnode_handle *phy_fwnode;
- struct phy_device *phy_dev;
-- int ret;
-+ int i, ret;
-
- /* Fixed links and 802.3z are handled without needing a PHY */
- if (pl->cfg_link_an_mode == MLO_AN_FIXED ||
-@@ -2288,6 +2288,25 @@ int phylink_fwnode_phy_connect(struct ph
- pl->link_config.interface = pl->link_interface;
- }
-
-+ /* Assume single-lane SerDes interface modes share the same
-+ * lanes and allow the PHY to switch to slower also supported modes
-+ */
-+ for (i = ARRAY_SIZE(phylink_sfp_interface_preference) - 1; i >= 0; i--) {
-+ /* skip unsupported modes */
-+ if (!test_bit(phylink_sfp_interface_preference[i], pl->config->supported_interfaces))
-+ continue;
-+
-+ __set_bit(phylink_sfp_interface_preference[i], phy_dev->host_interfaces);
-+
-+ /* skip all faster modes */
-+ if (phylink_sfp_interface_preference[i] == pl->link_interface)
-+ break;
-+ }
-+
-+ if (test_bit(pl->link_interface, phylink_sfp_interfaces))
-+ phy_interface_and(phy_dev->host_interfaces, phylink_sfp_interfaces,
-+ pl->config->supported_interfaces);
-+
- ret = phy_attach_direct(pl->netdev, phy_dev, flags,
- pl->link_interface);
- phy_device_free(phy_dev);
+++ /dev/null
-Date: Fri, 27 Aug 2021 12:22:32 +0200
-Subject: [PATCH] bridge: add knob for filtering rx/tx BPDU packets on a port
-
-Some devices (e.g. wireless APs) can't have devices behind them be part of
-a bridge topology with redundant links, due to address limitations.
-Additionally, broadcast traffic on these devices is somewhat expensive, due to
-the low data rate and wakeups of clients in powersave mode.
-This knob can be used to ensure that BPDU packets are never sent or forwarded
-to/from these devices
-
----
-
---- a/include/linux/if_bridge.h
-+++ b/include/linux/if_bridge.h
-@@ -61,6 +61,7 @@ struct br_ip_list {
- #define BR_PORT_LOCKED BIT(21)
- #define BR_PORT_MAB BIT(22)
- #define BR_NEIGH_VLAN_SUPPRESS BIT(23)
-+#define BR_BPDU_FILTER BIT(24)
-
- #define BR_DEFAULT_AGEING_TIME (300 * HZ)
-
---- a/net/bridge/br_forward.c
-+++ b/net/bridge/br_forward.c
-@@ -202,6 +202,7 @@ void br_flood(struct net_bridge *br, str
- enum br_pkt_type pkt_type, bool local_rcv, bool local_orig,
- u16 vid)
- {
-+ const unsigned char *dest = eth_hdr(skb)->h_dest;
- struct net_bridge_port *prev = NULL;
- struct net_bridge_port *p;
-
-@@ -219,6 +220,10 @@ void br_flood(struct net_bridge *br, str
- case BR_PKT_MULTICAST:
- if (!(p->flags & BR_MCAST_FLOOD) && skb->dev != br->dev)
- continue;
-+ if ((p->flags & BR_BPDU_FILTER) &&
-+ unlikely(is_link_local_ether_addr(dest) &&
-+ dest[5] == 0))
-+ continue;
- break;
- case BR_PKT_BROADCAST:
- if (!(p->flags & BR_BCAST_FLOOD) && skb->dev != br->dev)
---- a/net/bridge/br_input.c
-+++ b/net/bridge/br_input.c
-@@ -368,6 +368,8 @@ static rx_handler_result_t br_handle_fra
- fwd_mask |= p->group_fwd_mask;
- switch (dest[5]) {
- case 0x00: /* Bridge Group Address */
-+ if (p->flags & BR_BPDU_FILTER)
-+ goto drop;
- /* If STP is turned off,
- then must forward to keep loop detection */
- if (p->br->stp_enabled == BR_NO_STP ||
---- a/net/bridge/br_sysfs_if.c
-+++ b/net/bridge/br_sysfs_if.c
-@@ -240,6 +240,7 @@ BRPORT_ATTR_FLAG(multicast_flood, BR_MCA
- BRPORT_ATTR_FLAG(broadcast_flood, BR_BCAST_FLOOD);
- BRPORT_ATTR_FLAG(neigh_suppress, BR_NEIGH_SUPPRESS);
- BRPORT_ATTR_FLAG(isolated, BR_ISOLATED);
-+BRPORT_ATTR_FLAG(bpdu_filter, BR_BPDU_FILTER);
-
- #ifdef CONFIG_BRIDGE_IGMP_SNOOPING
- static ssize_t show_multicast_router(struct net_bridge_port *p, char *buf)
-@@ -292,6 +293,7 @@ static const struct brport_attribute *br
- &brport_attr_group_fwd_mask,
- &brport_attr_neigh_suppress,
- &brport_attr_isolated,
-+ &brport_attr_bpdu_filter,
- &brport_attr_backup_port,
- NULL
- };
---- a/net/bridge/br_stp_bpdu.c
-+++ b/net/bridge/br_stp_bpdu.c
-@@ -80,7 +80,8 @@ void br_send_config_bpdu(struct net_brid
- {
- unsigned char buf[35];
-
-- if (p->br->stp_enabled != BR_KERNEL_STP)
-+ if (p->br->stp_enabled != BR_KERNEL_STP ||
-+ (p->flags & BR_BPDU_FILTER))
- return;
-
- buf[0] = 0;
-@@ -127,7 +128,8 @@ void br_send_tcn_bpdu(struct net_bridge_
- {
- unsigned char buf[4];
-
-- if (p->br->stp_enabled != BR_KERNEL_STP)
-+ if (p->br->stp_enabled != BR_KERNEL_STP ||
-+ (p->flags & BR_BPDU_FILTER))
- return;
-
- buf[0] = 0;
-@@ -172,6 +174,9 @@ void br_stp_rcv(const struct stp_proto *
- if (!(br->dev->flags & IFF_UP))
- goto out;
-
-+ if (p->flags & BR_BPDU_FILTER)
-+ goto out;
-+
- if (p->state == BR_STATE_DISABLED)
- goto out;
-
---- a/include/uapi/linux/if_link.h
-+++ b/include/uapi/linux/if_link.h
-@@ -571,6 +571,7 @@ enum {
- IFLA_BRPORT_MCAST_MAX_GROUPS,
- IFLA_BRPORT_NEIGH_VLAN_SUPPRESS,
- IFLA_BRPORT_BACKUP_NHID,
-+ IFLA_BRPORT_BPDU_FILTER,
- __IFLA_BRPORT_MAX
- };
- #define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1)
---- a/net/bridge/br_netlink.c
-+++ b/net/bridge/br_netlink.c
-@@ -190,6 +190,7 @@ static inline size_t br_port_info_size(v
- + nla_total_size(1) /* IFLA_BRPORT_LOCKED */
- + nla_total_size(1) /* IFLA_BRPORT_MAB */
- + nla_total_size(1) /* IFLA_BRPORT_NEIGH_VLAN_SUPPRESS */
-+ + nla_total_size(1) /* IFLA_BRPORT_BPDU_FILTER */
- + nla_total_size(sizeof(struct ifla_bridge_id)) /* IFLA_BRPORT_ROOT_ID */
- + nla_total_size(sizeof(struct ifla_bridge_id)) /* IFLA_BRPORT_BRIDGE_ID */
- + nla_total_size(sizeof(u16)) /* IFLA_BRPORT_DESIGNATED_PORT */
-@@ -282,7 +283,8 @@ static int br_port_fill_attrs(struct sk_
- nla_put_u8(skb, IFLA_BRPORT_LOCKED, !!(p->flags & BR_PORT_LOCKED)) ||
- nla_put_u8(skb, IFLA_BRPORT_MAB, !!(p->flags & BR_PORT_MAB)) ||
- nla_put_u8(skb, IFLA_BRPORT_NEIGH_VLAN_SUPPRESS,
-- !!(p->flags & BR_NEIGH_VLAN_SUPPRESS)))
-+ !!(p->flags & BR_NEIGH_VLAN_SUPPRESS)) ||
-+ nla_put_u8(skb, IFLA_BRPORT_BPDU_FILTER, !!(p->flags & BR_BPDU_FILTER)))
- return -EMSGSIZE;
-
- timerval = br_timer_value(&p->message_age_timer);
-@@ -902,6 +904,7 @@ static const struct nla_policy br_port_p
- [IFLA_BRPORT_MCAST_MAX_GROUPS] = { .type = NLA_U32 },
- [IFLA_BRPORT_NEIGH_VLAN_SUPPRESS] = NLA_POLICY_MAX(NLA_U8, 1),
- [IFLA_BRPORT_BACKUP_NHID] = { .type = NLA_U32 },
-+ [IFLA_BRPORT_BPDU_FILTER] = { .type = NLA_U8 },
- };
-
- /* Change the state of the port and notify spanning tree */
-@@ -970,6 +973,7 @@ static int br_setport(struct net_bridge_
- br_set_port_flag(p, tb, IFLA_BRPORT_MAB, BR_PORT_MAB);
- br_set_port_flag(p, tb, IFLA_BRPORT_NEIGH_VLAN_SUPPRESS,
- BR_NEIGH_VLAN_SUPPRESS);
-+ br_set_port_flag(p, tb, IFLA_BRPORT_BPDU_FILTER, BR_BPDU_FILTER);
-
- if ((p->flags & BR_PORT_MAB) &&
- (!(p->flags & BR_PORT_LOCKED) || !(p->flags & BR_LEARNING))) {
---- a/net/core/rtnetlink.c
-+++ b/net/core/rtnetlink.c
-@@ -61,7 +61,7 @@
- #include "dev.h"
-
- #define RTNL_MAX_TYPE 50
--#define RTNL_SLAVE_MAX_TYPE 44
-+#define RTNL_SLAVE_MAX_TYPE 45
-
- struct rtnl_link {
- rtnl_doit_func doit;
-@@ -4978,7 +4978,9 @@ int ndo_dflt_bridge_getlink(struct sk_bu
- brport_nla_put_flag(skb, flags, mask,
- IFLA_BRPORT_MCAST_FLOOD, BR_MCAST_FLOOD) ||
- brport_nla_put_flag(skb, flags, mask,
-- IFLA_BRPORT_BCAST_FLOOD, BR_BCAST_FLOOD)) {
-+ IFLA_BRPORT_BCAST_FLOOD, BR_BCAST_FLOOD) ||
-+ brport_nla_put_flag(skb, flags, mask,
-+ IFLA_BRPORT_BPDU_FILTER, BR_BPDU_FILTER)) {
- nla_nest_cancel(skb, protinfo);
- goto nla_put_failure;
- }
+++ /dev/null
-From 3b4329230db8750bea7a56ef07f07cbbf5fc6c5a Mon Sep 17 00:00:00 2001
-Date: Tue, 4 Jul 2023 22:50:12 +0200
-Subject: [PATCH 19/20] net: dsa: qca8k: implement lag_fdb_add/del ops
-
-Implement lag_fdb_add/del ops to correctly support using LAG interface.
-Qca8k switch supports declaring fdb entry for link aggregation by simply
-setting the DES_PORT bits to all the LAG member.
-
----
- drivers/net/dsa/qca/qca8k-8xxx.c | 2 ++
- drivers/net/dsa/qca/qca8k-common.c | 48 ++++++++++++++++++++++++++++++
- drivers/net/dsa/qca/qca8k.h | 6 ++++
- 3 files changed, 56 insertions(+)
-
---- a/drivers/net/dsa/qca/qca8k-8xxx.c
-+++ b/drivers/net/dsa/qca/qca8k-8xxx.c
-@@ -2012,6 +2012,8 @@ static const struct dsa_switch_ops qca8k
- .port_fdb_add = qca8k_port_fdb_add,
- .port_fdb_del = qca8k_port_fdb_del,
- .port_fdb_dump = qca8k_port_fdb_dump,
-+ .lag_fdb_add = qca8k_lag_fdb_add,
-+ .lag_fdb_del = qca8k_lag_fdb_del,
- .port_mdb_add = qca8k_port_mdb_add,
- .port_mdb_del = qca8k_port_mdb_del,
- .port_mirror_add = qca8k_port_mirror_add,
---- a/drivers/net/dsa/qca/qca8k-common.c
-+++ b/drivers/net/dsa/qca/qca8k-common.c
-@@ -1235,6 +1235,42 @@ int qca8k_port_lag_leave(struct dsa_swit
- return qca8k_lag_refresh_portmap(ds, port, lag, true);
- }
-
-+int qca8k_lag_fdb_add(struct dsa_switch *ds, struct dsa_lag lag,
-+ const unsigned char *addr, u16 vid,
-+ struct dsa_db db)
-+{
-+ struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv;
-+ struct dsa_port *dp;
-+ u16 port_mask = 0;
-+
-+ /* Set the vid to the port vlan id if no vid is set */
-+ if (!vid)
-+ vid = QCA8K_PORT_VID_DEF;
-+
-+ dsa_lag_foreach_port(dp, ds->dst, &lag)
-+ port_mask |= BIT(dp->index);
-+
-+ return qca8k_port_fdb_insert(priv, addr, port_mask, vid);
-+}
-+
-+int qca8k_lag_fdb_del(struct dsa_switch *ds, struct dsa_lag lag,
-+ const unsigned char *addr, u16 vid,
-+ struct dsa_db db)
-+{
-+ struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv;
-+ struct dsa_port *dp;
-+ u16 port_mask = 0;
-+
-+ /* Set the vid to the port vlan id if no vid is set */
-+ if (!vid)
-+ vid = QCA8K_PORT_VID_DEF;
-+
-+ dsa_lag_foreach_port(dp, ds->dst, &lag)
-+ port_mask |= BIT(dp->index);
-+
-+ return qca8k_fdb_del(priv, addr, port_mask, vid);
-+}
-+
- int qca8k_read_switch_id(struct qca8k_priv *priv)
- {
- u32 val;
---- a/drivers/net/dsa/qca/qca8k.h
-+++ b/drivers/net/dsa/qca/qca8k.h
-@@ -591,5 +591,11 @@ int qca8k_port_lag_join(struct dsa_switc
- struct netlink_ext_ack *extack);
- int qca8k_port_lag_leave(struct dsa_switch *ds, int port,
- struct dsa_lag lag);
-+int qca8k_lag_fdb_add(struct dsa_switch *ds, struct dsa_lag lag,
-+ const unsigned char *addr, u16 vid,
-+ struct dsa_db db);
-+int qca8k_lag_fdb_del(struct dsa_switch *ds, struct dsa_lag lag,
-+ const unsigned char *addr, u16 vid,
-+ struct dsa_db db);
-
- #endif /* __QCA8K_H */
+++ /dev/null
-From b954d61d9ecfa64450fc178586719dc2a95b92a7 Mon Sep 17 00:00:00 2001
-Date: Tue, 20 Jun 2023 21:48:24 +0200
-Subject: [PATCH 3/4] net: dsa: qca8k: enable flooding to both CPU port
-
-To permit a multi-CPU setup, flood all unknown frames to all CPU ports.
-Each CPU port should have correct LOOKUP MEMBER configuration to
-prevent receiving duplicate packets from user ports.
-
----
- drivers/net/dsa/qca/qca8k-8xxx.c | 13 +++++--------
- 1 file changed, 5 insertions(+), 8 deletions(-)
-
---- a/drivers/net/dsa/qca/qca8k-8xxx.c
-+++ b/drivers/net/dsa/qca/qca8k-8xxx.c
-@@ -1901,15 +1901,12 @@ qca8k_setup(struct dsa_switch *ds)
- }
- }
-
-- /* Forward all unknown frames to CPU port for Linux processing
-- * Notice that in multi-cpu config only one port should be set
-- * for igmp, unknown, multicast and broadcast packet
-- */
-+ /* Forward all unknown frames to CPU port for Linux processing */
- ret = qca8k_write(priv, QCA8K_REG_GLOBAL_FW_CTRL1,
-- FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_IGMP_DP_MASK, BIT(cpu_port)) |
-- FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_BC_DP_MASK, BIT(cpu_port)) |
-- FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_MC_DP_MASK, BIT(cpu_port)) |
-- FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_UC_DP_MASK, BIT(cpu_port)));
-+ FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_IGMP_DP_MASK, dsa_cpu_ports(ds)) |
-+ FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_BC_DP_MASK, dsa_cpu_ports(ds)) |
-+ FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_MC_DP_MASK, dsa_cpu_ports(ds)) |
-+ FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_UC_DP_MASK, dsa_cpu_ports(ds)));
- if (ret)
- return ret;
-
+++ /dev/null
-From b2d6ebf2f92f8695c83fa6979f4ab579c588df76 Mon Sep 17 00:00:00 2001
-Date: Tue, 20 Jun 2023 07:57:38 +0200
-Subject: [PATCH 4/4] net: dsa: qca8k: add support for port_change_master
-
-Add support for port_change_master to permit assigning an alternative
-CPU port if the switch have both CPU port connected or create a LAG on
-both CPU port and assign the LAG as DSA master.
-
-On port change master request, we check if the master is a LAG.
-With LAG we compose the cpu_port_mask with the CPU port in the LAG, if
-master is a simple dsa_port, we derive the index.
-
-Finally we apply the new cpu_port_mask to the LOOKUP MEMBER to permit
-the port to receive packet by the new CPU port setup for the port and we
-refresh the CPU ports LOOKUP MEMBER configuration to reflect the new
-user port state.
-
-port_lag_join/leave is updated to refresh the user ports if we detect
-that the LAG is a DSA master and we have user port using it as a master.
-
----
- drivers/net/dsa/qca/qca8k-8xxx.c | 116 ++++++++++++++++++++++++++++++-
- 1 file changed, 114 insertions(+), 2 deletions(-)
-
---- a/drivers/net/dsa/qca/qca8k-8xxx.c
-+++ b/drivers/net/dsa/qca/qca8k-8xxx.c
-@@ -1738,6 +1738,117 @@ qca8k_get_tag_protocol(struct dsa_switch
- return DSA_TAG_PROTO_QCA;
- }
-
-+static int qca8k_port_change_master(struct dsa_switch *ds, int port,
-+ struct net_device *master,
-+ struct netlink_ext_ack *extack)
-+{
-+ struct dsa_switch_tree *dst = ds->dst;
-+ struct qca8k_priv *priv = ds->priv;
-+ u8 cpu_port_mask = 0;
-+ struct dsa_port *dp;
-+ u32 val;
-+ int ret;
-+
-+ /* With LAG of CPU port, compose the mask for port LOOKUP MEMBER */
-+ if (netif_is_lag_master(master)) {
-+ struct dsa_lag *lag;
-+ int id;
-+
-+ id = dsa_lag_id(dst, master);
-+ lag = dsa_lag_by_id(dst, id);
-+
-+ dsa_lag_foreach_port(dp, dst, lag)
-+ if (dsa_port_is_cpu(dp))
-+ cpu_port_mask |= BIT(dp->index);
-+ } else {
-+ dp = master->dsa_ptr;
-+ cpu_port_mask |= BIT(dp->index);
-+ }
-+
-+ /* Connect port to new cpu port */
-+ ret = regmap_read(priv->regmap, QCA8K_PORT_LOOKUP_CTRL(port), &val);
-+ if (ret)
-+ return ret;
-+
-+ /* Reset connected CPU port in port LOOKUP MEMBER */
-+ val &= ~dsa_cpu_ports(ds);
-+ /* Assign the new CPU port in port LOOKUP MEMBER */
-+ val |= cpu_port_mask;
-+
-+ ret = regmap_update_bits(priv->regmap, QCA8K_PORT_LOOKUP_CTRL(port),
-+ QCA8K_PORT_LOOKUP_MEMBER,
-+ val);
-+ if (ret)
-+ return ret;
-+
-+ /* Refresh CPU port LOOKUP MEMBER with new port */
-+ dsa_tree_for_each_cpu_port(dp, ds->dst) {
-+ u32 reg = QCA8K_PORT_LOOKUP_CTRL(dp->index);
-+
-+ /* If CPU port in mask assign port, else remove port */
-+ if (BIT(dp->index) & cpu_port_mask)
-+ ret = regmap_set_bits(priv->regmap, reg, BIT(port));
-+ else
-+ ret = regmap_clear_bits(priv->regmap, reg, BIT(port));
-+
-+ if (ret)
-+ return ret;
-+ }
-+
-+ return 0;
-+}
-+
-+static int qca8k_port_lag_refresh_user_ports(struct dsa_switch *ds,
-+ struct dsa_lag lag)
-+{
-+ struct net_device *lag_dev = lag.dev;
-+ struct dsa_port *dp;
-+ int ret;
-+
-+ /* Ignore if LAG is not a DSA master */
-+ if (!netif_is_lag_master(lag_dev))
-+ return 0;
-+
-+ dsa_switch_for_each_user_port(dp, ds) {
-+ /* Skip if assigned master is not the LAG */
-+ if (dsa_port_to_master(dp) != lag_dev)
-+ continue;
-+
-+ ret = qca8k_port_change_master(ds, dp->index,
-+ lag_dev, NULL);
-+ if (ret)
-+ return ret;
-+ }
-+
-+ return 0;
-+}
-+
-+static int qca8xxx_port_lag_join(struct dsa_switch *ds, int port,
-+ struct dsa_lag lag,
-+ struct netdev_lag_upper_info *info,
-+ struct netlink_ext_ack *extack)
-+{
-+ int ret;
-+
-+ ret = qca8k_port_lag_join(ds, port, lag, info, extack);
-+ if (ret)
-+ return ret;
-+
-+ return qca8k_port_lag_refresh_user_ports(ds, lag);
-+}
-+
-+static int qca8xxx_port_lag_leave(struct dsa_switch *ds, int port,
-+ struct dsa_lag lag)
-+{
-+ int ret;
-+
-+ ret = qca8k_port_lag_leave(ds, port, lag);
-+ if (ret)
-+ return ret;
-+
-+ return qca8k_port_lag_refresh_user_ports(ds, lag);
-+}
-+
- static void
- qca8k_master_change(struct dsa_switch *ds, const struct net_device *master,
- bool operational)
-@@ -2024,8 +2135,9 @@ static const struct dsa_switch_ops qca8k
- .phylink_mac_link_down = qca8k_phylink_mac_link_down,
- .phylink_mac_link_up = qca8k_phylink_mac_link_up,
- .get_phy_flags = qca8k_get_phy_flags,
-- .port_lag_join = qca8k_port_lag_join,
-- .port_lag_leave = qca8k_port_lag_leave,
-+ .port_lag_join = qca8xxx_port_lag_join,
-+ .port_lag_leave = qca8xxx_port_lag_leave,
-+ .port_change_master = qca8k_port_change_master,
- .master_state_change = qca8k_master_change,
- .connect_tag_protocol = qca8k_connect_tag_protocol,
- };
+++ /dev/null
-From 0f6599167c126ce32c85d4f8a1f3d1775a268572 Mon Sep 17 00:00:00 2001
-Date: Fri, 6 Oct 2023 12:44:00 +0200
-Subject: [PATCH] net: dsa: qca8k: enable assisted learning on CPU port
-
-Enable assisted learning on CPU port.
-
-It has been verified that there is a problem in packet roaming
-from one BSS to another in the same security settings from one
-physical R7800 to another physical R7800 where they are in the
-same L2 broadcast domain backhauled/linked together via one
-of the ethernet ports.
-DHCP will fail to complete and traffic cannot flow for around 300
-seconds.
-
----
- drivers/net/dsa/qca/qca8k-8xxx.c | 14 +++++++++-----
- 1 file changed, 9 insertions(+), 5 deletions(-)
-
---- a/drivers/net/dsa/qca/qca8k-8xxx.c
-+++ b/drivers/net/dsa/qca/qca8k-8xxx.c
-@@ -2010,6 +2010,12 @@ qca8k_setup(struct dsa_switch *ds)
- dev_err(priv->dev, "failed enabling QCA header mode on port %d", dp->index);
- return ret;
- }
-+
-+ /* Disable learning by default on all ports */
-+ ret = regmap_clear_bits(priv->regmap, QCA8K_PORT_LOOKUP_CTRL(dp->index),
-+ QCA8K_PORT_LOOKUP_LEARN);
-+ if (ret)
-+ return ret;
- }
-
- /* Forward all unknown frames to CPU port for Linux processing */
-@@ -2039,11 +2045,6 @@ qca8k_setup(struct dsa_switch *ds)
- if (ret)
- return ret;
-
-- ret = regmap_clear_bits(priv->regmap, QCA8K_PORT_LOOKUP_CTRL(port),
-- QCA8K_PORT_LOOKUP_LEARN);
-- if (ret)
-- return ret;
--
- /* For port based vlans to work we need to set the
- * default egress vid
- */
-@@ -2095,6 +2096,9 @@ qca8k_setup(struct dsa_switch *ds)
- /* Set max number of LAGs supported */
- ds->num_lag_ids = QCA8K_NUM_LAGS;
-
-+ /* HW learn on CPU port is limited and require manual setting */
-+ ds->assisted_learning_on_cpu_port = true;
-+
- return 0;
- }
-
+++ /dev/null
-From 85cd45580f5e3b26068cccb7d6173f200e754dc0 Mon Sep 17 00:00:00 2001
-Date: Sun, 2 Apr 2023 23:56:16 +0100
-Subject: [PATCH 1/2] net: phy: realtek: use genphy_soft_reset for 2.5G PHYs
-
-Some vendor bootloaders do weird things with those PHYs which result in
-link modes being reported wrongly. Start from a clean sheet by resetting
-the PHY.
-
----
- drivers/net/phy/realtek/realtek_main.c | 6 ++++++
- 1 file changed, 6 insertions(+)
-
---- a/drivers/net/phy/realtek/realtek_main.c
-+++ b/drivers/net/phy/realtek/realtek_main.c
-@@ -1913,6 +1913,7 @@ static struct phy_driver realtek_drvs[]
- }, {
- .name = "RTL8226 2.5Gbps PHY",
- .match_phy_device = rtl8226_match_phy_device,
-+ .soft_reset = genphy_soft_reset,
- .get_features = rtl822x_get_features,
- .config_aneg = rtl822x_config_aneg,
- .read_status = rtl822x_read_status,
-@@ -1923,6 +1924,7 @@ static struct phy_driver realtek_drvs[]
- }, {
- .match_phy_device = rtl8221b_match_phy_device,
- .name = "RTL8226B_RTL8221B 2.5Gbps PHY",
-+ .soft_reset = genphy_soft_reset,
- .get_features = rtl822x_get_features,
- .config_aneg = rtl822x_config_aneg,
- .config_init = rtl822xb_config_init,
-@@ -1935,6 +1937,7 @@ static struct phy_driver realtek_drvs[]
- }, {
- PHY_ID_MATCH_EXACT(0x001cc838),
- .name = "RTL8226-CG 2.5Gbps PHY",
-+ .soft_reset = genphy_soft_reset,
- .get_features = rtl822x_get_features,
- .config_aneg = rtl822x_config_aneg,
- .read_status = rtl822x_read_status,
-@@ -1945,6 +1948,7 @@ static struct phy_driver realtek_drvs[]
- }, {
- PHY_ID_MATCH_EXACT(0x001cc848),
- .name = "RTL8226B-CG_RTL8221B-CG 2.5Gbps PHY",
-+ .soft_reset = genphy_soft_reset,
- .get_features = rtl822x_get_features,
- .config_aneg = rtl822x_config_aneg,
- .config_init = rtl822xb_config_init,
-@@ -1957,6 +1961,7 @@ static struct phy_driver realtek_drvs[]
- }, {
- .match_phy_device = rtl8221b_vb_cg_c22_match_phy_device,
- .name = "RTL8221B-VB-CG 2.5Gbps PHY (C22)",
-+ .soft_reset = genphy_soft_reset,
- .probe = rtl822x_probe,
- .get_features = rtl822x_get_features,
- .config_aneg = rtl822x_config_aneg,
-@@ -1972,6 +1977,7 @@ static struct phy_driver realtek_drvs[]
- .name = "RTL8221B-VB-CG 2.5Gbps PHY (C45)",
- .config_intr = rtl8221b_config_intr,
- .handle_interrupt = rtl8221b_handle_interrupt,
-+ .soft_reset = genphy_soft_reset,
- .probe = rtl822x_probe,
- .config_init = rtl822xb_config_init,
- .get_rate_matching = rtl822xb_get_rate_matching,
-@@ -1983,6 +1989,7 @@ static struct phy_driver realtek_drvs[]
- }, {
- .match_phy_device = rtl8221b_vm_cg_c22_match_phy_device,
- .name = "RTL8221B-VM-CG 2.5Gbps PHY (C22)",
-+ .soft_reset = genphy_soft_reset,
- .probe = rtl822x_probe,
- .get_features = rtl822x_get_features,
- .config_aneg = rtl822x_config_aneg,
-@@ -1998,6 +2005,7 @@ static struct phy_driver realtek_drvs[]
- .name = "RTL8221B-VM-CG 2.5Gbps PHY (C45)",
- .config_intr = rtl8221b_config_intr,
- .handle_interrupt = rtl8221b_handle_interrupt,
-+ .soft_reset = genphy_soft_reset,
- .probe = rtl822x_probe,
- .config_init = rtl822xb_config_init,
- .get_rate_matching = rtl822xb_get_rate_matching,
+++ /dev/null
-From d54ef6aea00e7a6ace439baade6ad0aa38ee4b04 Mon Sep 17 00:00:00 2001
-Date: Mon, 3 Apr 2023 01:21:57 +0300
-Subject: [PATCH 287/326] net: phy: realtek: disable SGMII in-band AN for 2.5G
- PHYs
-
-MAC drivers don't use SGMII in-band autonegotiation unless told to do so
-in device tree using 'managed = "in-band-status"'. When using MDIO to
-access a PHY, in-band-status is unneeded as we have link-status via
-MDIO. Switch off SGMII in-band autonegotiation using magic values.
-
----
- drivers/net/phy/realtek/realtek_main.c | 27 +++++++++++++++++++++++++--
- 1 file changed, 25 insertions(+), 2 deletions(-)
-
---- a/drivers/net/phy/realtek/realtek_main.c
-+++ b/drivers/net/phy/realtek/realtek_main.c
-@@ -1092,8 +1092,8 @@ static int rtl822x_probe(struct phy_devi
- static int rtl822xb_config_init(struct phy_device *phydev)
- {
- bool has_2500, has_sgmii;
-+ int ret, val;
- u16 mode;
-- int ret;
-
- has_2500 = test_bit(PHY_INTERFACE_MODE_2500BASEX,
- phydev->host_interfaces) ||
-@@ -1143,7 +1143,29 @@ static int rtl822xb_config_init(struct p
- if (ret < 0)
- return ret;
-
-- return phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x6f11, 0x8020);
-+ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x6f11, 0x8020);
-+ if (ret < 0)
-+ return ret;
-+
-+ /* Disable SGMII AN */
-+ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x7588, 0x2);
-+ if (ret < 0)
-+ return ret;
-+
-+ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x7589, 0x71d0);
-+ if (ret < 0)
-+ return ret;
-+
-+ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x7587, 0x3);
-+ if (ret < 0)
-+ return ret;
-+
-+ ret = phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND1, 0x7587,
-+ val, !(val & BIT(0)), 500, 100000, false);
-+ if (ret < 0)
-+ return ret;
-+
-+ return 0;
- }
-
- static int rtl822xb_get_rate_matching(struct phy_device *phydev,
+++ /dev/null
-From 4dd2cc9b91ecb25f278a2c55e07e6455e9000e6b Mon Sep 17 00:00:00 2001
-Date: Sat, 22 Apr 2023 01:21:14 +0100
-Subject: [PATCH] net: phy: realtek: make sure paged read is protected by mutex
-
-As we cannot rely on phy_read_paged function before the PHY is
-identified, the paged read in rtlgen_supports_2_5gbps needs to be open
-coded as it is being called by the match_phy_device function, ie. before
-.read_page and .write_page have been populated.
-
-Make sure it is also protected by the MDIO bus mutex and use
-rtl821x_write_page instead of 3 individually locked MDIO bus operations.
-
----
- drivers/net/phy/realtek/realtek_main.c | 8 +++++---
- 1 file changed, 5 insertions(+), 3 deletions(-)
-
---- a/drivers/net/phy/realtek/realtek_main.c
-+++ b/drivers/net/phy/realtek/realtek_main.c
-@@ -1532,9 +1532,11 @@ static bool rtlgen_supports_2_5gbps(stru
- {
- int val;
-
-- phy_write(phydev, RTL821x_PAGE_SELECT, 0xa61);
-- val = phy_read(phydev, 0x13);
-- phy_write(phydev, RTL821x_PAGE_SELECT, 0);
-+ mutex_lock(&phydev->mdio.bus->mdio_lock);
-+ rtl821x_write_page(phydev, 0xa61);
-+ val = __phy_read(phydev, 0x13);
-+ rtl821x_write_page(phydev, 0);
-+ mutex_unlock(&phydev->mdio.bus->mdio_lock);
-
- return val >= 0 && val & MDIO_PMA_SPEED_2_5G;
- }
+++ /dev/null
-From 9155098547fb1172d4fa536f3f6bc9d42f59d08c Mon Sep 17 00:00:00 2001
-Date: Sat, 22 Apr 2023 03:26:01 +0100
-Subject: [PATCH] net: phy: realtek: setup ALDPS on RTL822x
-
-Setup Link Down Power Saving Mode according the DTS property
-just like for RTL821x 1GE PHYs.
-
----
- drivers/net/phy/realtek/realtek_main.c | 11 +++++++++++
- 1 file changed, 11 insertions(+)
-
---- a/drivers/net/phy/realtek/realtek_main.c
-+++ b/drivers/net/phy/realtek/realtek_main.c
-@@ -156,6 +156,10 @@
-
- #define RTL8224_SRAM_RTCT_LEN(pair) (0x8028 + (pair) * 4)
-
-+#define RTL8221B_PHYCR1 0xa430
-+#define RTL8221B_PHYCR1_ALDPS_EN BIT(2)
-+#define RTL8221B_PHYCR1_ALDPS_XTAL_OFF_EN BIT(12)
-+
- #define RTL8366RB_POWER_SAVE 0x15
- #define RTL8366RB_POWER_SAVE_ON BIT(12)
-
-@@ -1147,6 +1151,15 @@ static int rtl822xb_config_init(struct p
- if (ret < 0)
- return ret;
-
-+ if (of_property_read_bool(phydev->mdio.dev.of_node, "realtek,aldps-enable"))
-+ ret = phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, RTL8221B_PHYCR1,
-+ RTL8221B_PHYCR1_ALDPS_EN | RTL8221B_PHYCR1_ALDPS_XTAL_OFF_EN);
-+ else
-+ ret = phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, RTL8221B_PHYCR1,
-+ RTL8221B_PHYCR1_ALDPS_EN | RTL8221B_PHYCR1_ALDPS_XTAL_OFF_EN);
-+ if (ret < 0)
-+ return ret;
-+
- /* Disable SGMII AN */
- ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x7588, 0x2);
- if (ret < 0)
+++ /dev/null
-From 0de82310d2b32e78ff79d42c08b1122a6ede3778 Mon Sep 17 00:00:00 2001
-Date: Sun, 30 Apr 2023 00:15:41 +0100
-Subject: [PATCH] net: phy: realtek: detect early version of RTL8221B
-
-Early versions (?) of the RTL8221B PHY cannot be identified in a regular
-Clause-45 bus scan as the PHY doesn't report the implemented MMDs
-correctly but returns 0 instead.
-Implement custom identify function using the PKGID instead of iterating
-over the implemented MMDs.
-
-[forward-port by @namiltd]
---- a/drivers/net/phy/realtek/realtek_main.c
-+++ b/drivers/net/phy/realtek/realtek_main.c
-@@ -1589,10 +1589,32 @@ static int rtl8226_match_phy_device(stru
- static int rtlgen_is_c45_match(struct phy_device *phydev, unsigned int id,
- bool is_c45)
- {
-- if (phydev->is_c45)
-- return is_c45 && (id == phydev->c45_ids.device_ids[1]);
-- else
-+ if (phydev->is_c45) {
-+ u32 rid;
-+
-+ if (!is_c45)
-+ return 0;
-+
-+ rid = phydev->c45_ids.device_ids[1];
-+ if ((rid == 0xffffffff) && phydev->mdio.bus->read_c45) {
-+ int val;
-+
-+ val = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PKGID1);
-+ if (val < 0)
-+ return 0;
-+
-+ rid = val << 16;
-+ val = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PKGID2);
-+ if (val < 0)
-+ return 0;
-+
-+ rid |= val;
-+ }
-+
-+ return (id == rid);
-+ } else {
- return !is_c45 && (id == phydev->phy_id);
-+ }
- }
-
- static int rtl8221b_match_phy_device(struct phy_device *phydev,
+++ /dev/null
-From 1addfb042a9d27788a0fb2c2935045b56fd8560e Mon Sep 17 00:00:00 2001
-Date: Thu, 23 Jan 2025 03:25:29 +0000
-Subject: [PATCH] net: phy: realtek: mark existing MMDs as present
-
-When using Clause-45 mode to access RealTek RTL8221B 2.5G PHYs some
-versions of the PHY fail to report the MMDs present on the PHY.
-Mark MMDs PMAPMD, PCS and AN which are always existing according to
-the datasheet as present to fix that.
-
----
- drivers/net/phy/realtek/realtek_main.c | 3 +++
- 1 file changed, 3 insertions(+)
-
---- a/drivers/net/phy/realtek/realtek_main.c
-+++ b/drivers/net/phy/realtek/realtek_main.c
-@@ -1301,6 +1301,9 @@ static int rtl822x_c45_get_features(stru
- linkmode_set_bit(ETHTOOL_LINK_MODE_TP_BIT,
- phydev->supported);
-
-+ phydev->c45_ids.mmds_present |= MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS |
-+ MDIO_DEVS_AN;
-+
- return genphy_c45_pma_read_abilities(phydev);
- }
-
+++ /dev/null
-Date: Thu, 30 Jan 2025 05:33:12 +0000
-Subject: [PATCH] net: phy: realtek: work around broken SerDes
-
-For still unknown reasons the SerDes init sequence may sometimes
-time out because a self-clearing bit never clears, indicating the
-PHY has entered an unrecoverable error state.
-
-Work-around the issue by triggering a hardware reset and retry the
-setup sequence while warning the user that this has happened.
-This is really more of a work-around than a fix, and should be
-replaced by a better actual fix in future (hopefully).
-
----
---- a/drivers/net/phy/realtek/realtek_main.c
-+++ b/drivers/net/phy/realtek/realtek_main.c
-@@ -1181,6 +1181,22 @@ static int rtl822xb_config_init(struct p
- return 0;
- }
-
-+static int rtl822xb_config_init_war(struct phy_device *phydev)
-+{
-+ int ret;
-+
-+ ret = rtl822xb_config_init(phydev);
-+
-+ if (ret == -ETIMEDOUT) {
-+ phydev_warn(phydev, "SerDes setup timed out, retrying\n");
-+ phy_device_reset(phydev, 1);
-+ phy_device_reset(phydev, 0);
-+ ret = rtl822xb_config_init(phydev);
-+ }
-+
-+ return ret;
-+}
-+
- static int rtl822xb_get_rate_matching(struct phy_device *phydev,
- phy_interface_t iface)
- {
-@@ -2041,7 +2057,7 @@ static struct phy_driver realtek_drvs[]
- .handle_interrupt = rtl8221b_handle_interrupt,
- .soft_reset = genphy_soft_reset,
- .probe = rtl822x_probe,
-- .config_init = rtl822xb_config_init,
-+ .config_init = rtl822xb_config_init_war,
- .get_rate_matching = rtl822xb_get_rate_matching,
- .get_features = rtl822x_c45_get_features,
- .config_aneg = rtl822x_c45_config_aneg,
-@@ -2069,7 +2085,7 @@ static struct phy_driver realtek_drvs[]
- .handle_interrupt = rtl8221b_handle_interrupt,
- .soft_reset = genphy_soft_reset,
- .probe = rtl822x_probe,
-- .config_init = rtl822xb_config_init,
-+ .config_init = rtl822xb_config_init_war,
- .get_rate_matching = rtl822xb_get_rate_matching,
- .get_features = rtl822x_c45_get_features,
- .config_aneg = rtl822x_c45_config_aneg,
+++ /dev/null
-Date: Thu, 30 Jan 2025 05:38:31 +0000
-Subject: [PATCH] net: phy: realtek: disable MDIO broadcast
-
-RealTek's PHYs by default also listen on MDIO address 0 which is defined
-as broadcast address. This can lead to problems if there is an actual PHY
-(such as MT7981 built-in PHY) present at this address, as accessing that
-PHY may then confuse the RealTek PHY.
-
-Disabled listening on the MDIO broadcast address to avoid such problems.
-
----
---- a/drivers/net/phy/realtek/realtek_main.c
-+++ b/drivers/net/phy/realtek/realtek_main.c
-@@ -1107,6 +1107,11 @@ static int rtl822xb_config_init(struct p
- phydev->host_interfaces) ||
- phydev->interface == PHY_INTERFACE_MODE_SGMII;
-
-+ /* disable listening on MDIO broadcast address (0) */
-+ ret = phy_clear_bits_mmd(phydev, MDIO_MMD_VEND2, 0xa430, BIT(13));
-+ if (ret < 0)
-+ return ret;
-+
- /* fill in possible interfaces */
- __assign_bit(PHY_INTERFACE_MODE_2500BASEX, phydev->possible_interfaces,
- has_2500);
+++ /dev/null
-From 686c603f67ae87bf21a61b5e4b1564443f41c3ee Mon Sep 17 00:00:00 2001
-Date: Thu, 20 Oct 2022 03:34:43 +0200
-Subject: [PATCH] net: permit ieee80211_ptr even with no CFG82111 support
-
-Introduce a new flag CONFIG_CFG80211_HEADERS to compile in ieee80211_ptr
-even if CFG80211 support is not compiled in. This is needed for the
-backports project and for any downstream wireless driver that loads in
-the kernel dynamically.
-
----
- include/linux/netdevice.h | 2 +-
- net/batman-adv/hard-interface.c | 2 +-
- net/wireless/Kconfig | 4 ++++
- 3 files changed, 6 insertions(+), 2 deletions(-)
-
---- a/include/linux/netdevice.h
-+++ b/include/linux/netdevice.h
-@@ -2243,7 +2243,7 @@ struct net_device {
- #if IS_ENABLED(CONFIG_AX25)
- struct ax25_dev __rcu *ax25_ptr;
- #endif
--#if IS_ENABLED(CONFIG_CFG80211)
-+#if IS_ENABLED(CONFIG_CFG80211_HEADERS)
- struct wireless_dev *ieee80211_ptr;
- #endif
- #if IS_ENABLED(CONFIG_IEEE802154) || IS_ENABLED(CONFIG_6LOWPAN)
---- a/net/batman-adv/hard-interface.c
-+++ b/net/batman-adv/hard-interface.c
-@@ -309,7 +309,7 @@ static bool batadv_is_cfg80211_netdev(st
- if (!net_device)
- return false;
-
--#if IS_ENABLED(CONFIG_CFG80211)
-+#if IS_ENABLED(CONFIG_CFG80211_HEADERS)
- /* cfg80211 drivers have to set ieee80211_ptr */
- if (net_device->ieee80211_ptr)
- return true;
---- a/net/wireless/Kconfig
-+++ b/net/wireless/Kconfig
-@@ -26,6 +26,7 @@ config CFG80211
- # using a different algorithm, though right now they shouldn't
- # (this is here rather than below to allow it to be a module)
- select CRYPTO_SHA256 if CFG80211_USE_KERNEL_REGDB_KEYS
-+ select CFG80211_HEADERS
- help
- cfg80211 is the Linux wireless LAN (802.11) configuration API.
- Enable this if you have a wireless device.
-@@ -36,6 +37,9 @@ config CFG80211
-
- When built as a module it will be called cfg80211.
-
-+config CFG80211_HEADERS
-+ bool "cfg80211 - headers support"
-+
- if CFG80211
-
- config NL80211_TESTMODE
+++ /dev/null
-Date: Thu, 27 Oct 2022 23:39:52 +0200
-Subject: [PATCH] net: ethernet: mtk_eth_soc: compile out netsys v2 code
- on mt7621
-
-Avoid some branches in the hot path on low-end devices with limited CPU power,
-and reduce code size
-
----
-
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-@@ -1357,6 +1357,22 @@ struct mtk_mac {
- /* the struct describing the SoC. these are declared in the soc_xyz.c files */
- extern const struct of_device_id of_mtk_match[];
-
-+#ifdef CONFIG_SOC_MT7621
-+static inline bool mtk_is_netsys_v1(struct mtk_eth *eth)
-+{
-+ return true;
-+}
-+
-+static inline bool mtk_is_netsys_v2_or_greater(struct mtk_eth *eth)
-+{
-+ return false;
-+}
-+
-+static inline bool mtk_is_netsys_v3_or_greater(struct mtk_eth *eth)
-+{
-+ return false;
-+}
-+#else
- static inline bool mtk_is_netsys_v1(struct mtk_eth *eth)
- {
- return eth->soc->version == 1;
-@@ -1371,6 +1387,7 @@ static inline bool mtk_is_netsys_v3_or_g
- {
- return eth->soc->version > 2;
- }
-+#endif
-
- static inline struct mtk_foe_entry *
- mtk_foe_get_entry(struct mtk_ppe *ppe, u16 hash)
+++ /dev/null
-Date: Thu, 3 Nov 2022 12:38:49 +0100
-Subject: [PATCH] net: ethernet: mtk_eth_soc: work around issue with sending
- small fragments
-
-When lots of frames are sent with a number of very small fragments, an
-internal FIFO can overflow, causing the DMA engine to lock up lock up and
-transmit attempts time out.
-
-Fix this on MT7986 by increasing the reserved FIFO space.
-Fix this on older chips by detecting the presence of small fragments and use
-skb_gso_segment + skb_linearize to deal with them.
-
----
-
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -26,6 +26,7 @@
- #include <linux/bitfield.h>
- #include <net/dsa.h>
- #include <net/dst_metadata.h>
-+#include <net/gso.h>
- #include <net/page_pool/helpers.h>
-
- #include "mtk_eth_soc.h"
-@@ -1606,12 +1607,28 @@ static void mtk_wake_queue(struct mtk_et
- }
- }
-
-+static bool mtk_skb_has_small_frag(struct sk_buff *skb)
-+{
-+ int min_size = 16;
-+ int i;
-+
-+ if (skb_headlen(skb) < min_size)
-+ return true;
-+
-+ for (i = 0; i < skb_shinfo(skb)->nr_frags; i++)
-+ if (skb_frag_size(&skb_shinfo(skb)->frags[i]) < min_size)
-+ return true;
-+
-+ return false;
-+}
-+
- static netdev_tx_t mtk_start_xmit(struct sk_buff *skb, struct net_device *dev)
- {
- struct mtk_mac *mac = netdev_priv(dev);
- struct mtk_eth *eth = mac->hw;
- struct mtk_tx_ring *ring = ð->tx_ring;
- struct net_device_stats *stats = &dev->stats;
-+ struct sk_buff *segs, *next;
- bool gso = false;
- int tx_num;
-
-@@ -1640,6 +1657,18 @@ static netdev_tx_t mtk_start_xmit(struct
- return NETDEV_TX_BUSY;
- }
-
-+ if (mtk_is_netsys_v1(eth) &&
-+ skb_is_gso(skb) && mtk_skb_has_small_frag(skb)) {
-+ segs = skb_gso_segment(skb, dev->features & ~NETIF_F_ALL_TSO);
-+ if (IS_ERR(segs))
-+ goto drop;
-+
-+ if (segs) {
-+ consume_skb(skb);
-+ skb = segs;
-+ }
-+ }
-+
- /* TSO: fill MSS info in tcp checksum field */
- if (skb_is_gso(skb)) {
- if (skb_cow_head(skb, 0)) {
-@@ -1655,8 +1684,14 @@ static netdev_tx_t mtk_start_xmit(struct
- }
- }
-
-- if (mtk_tx_map(skb, dev, tx_num, ring, gso) < 0)
-- goto drop;
-+ skb_list_walk_safe(skb, skb, next) {
-+ if ((mtk_is_netsys_v1(eth) &&
-+ mtk_skb_has_small_frag(skb) && skb_linearize(skb)) ||
-+ mtk_tx_map(skb, dev, tx_num, ring, gso) < 0) {
-+ stats->tx_dropped++;
-+ dev_kfree_skb_any(skb);
-+ }
-+ }
-
- if (unlikely(atomic_read(&ring->free_count) <= ring->thresh))
- netif_tx_stop_all_queues(dev);
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-@@ -278,7 +278,7 @@
- #define MTK_CHK_DDONE_EN BIT(28)
- #define MTK_DMAD_WR_WDONE BIT(26)
- #define MTK_WCOMP_EN BIT(24)
--#define MTK_RESV_BUF (0x40 << 16)
-+#define MTK_RESV_BUF (0x80 << 16)
- #define MTK_MUTLI_CNT (0x4 << 12)
- #define MTK_LEAKY_BUCKET_EN BIT(11)
-
+++ /dev/null
-Date: Tue, 15 Oct 2024 12:52:56 +0200
-Subject: [PATCH] net: ethernet: mtk_eth_soc: optimize dma ring address/index
- calculation
-
-Since DMA descriptor sizes are all power of 2, we can avoid costly integer
-division in favor or simple shifts.
-
----
-
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -43,6 +43,11 @@ MODULE_PARM_DESC(msg_level, "Message lev
- offsetof(struct mtk_hw_stats, xdp_stats.x) / \
- sizeof(u64) }
-
-+#define RX_DESC_OFS(eth, i) \
-+ ((i) << (eth)->soc->rx.desc_shift)
-+#define TX_DESC_OFS(eth, i) \
-+ ((i) << (eth)->soc->tx.desc_shift)
-+
- static const struct mtk_reg_map mtk_reg_map = {
- .tx_irq_mask = 0x1a1c,
- .tx_irq_status = 0x1a18,
-@@ -1159,14 +1164,14 @@ static int mtk_init_fq_dma(struct mtk_et
- eth->scratch_ring = eth->sram_base;
- else
- eth->scratch_ring = dma_alloc_coherent(eth->dma_dev,
-- cnt * soc->tx.desc_size,
-+ TX_DESC_OFS(eth, cnt),
- ð->phy_scratch_ring,
- GFP_KERNEL);
-
- if (unlikely(!eth->scratch_ring))
- return -ENOMEM;
-
-- phy_ring_tail = eth->phy_scratch_ring + soc->tx.desc_size * (cnt - 1);
-+ phy_ring_tail = eth->phy_scratch_ring + TX_DESC_OFS(eth, cnt - 1);
-
- for (j = 0; j < DIV_ROUND_UP(soc->tx.fq_dma_size, MTK_FQ_DMA_LENGTH); j++) {
- len = min_t(int, cnt - j * MTK_FQ_DMA_LENGTH, MTK_FQ_DMA_LENGTH);
-@@ -1185,11 +1190,11 @@ static int mtk_init_fq_dma(struct mtk_et
- for (i = 0; i < len; i++) {
- struct mtk_tx_dma_v2 *txd;
-
-- txd = eth->scratch_ring + (j * MTK_FQ_DMA_LENGTH + i) * soc->tx.desc_size;
-+ txd = eth->scratch_ring + TX_DESC_OFS(eth, j * MTK_FQ_DMA_LENGTH + i);
- txd->txd1 = dma_addr + i * MTK_QDMA_PAGE_SIZE;
- if (j * MTK_FQ_DMA_LENGTH + i < cnt)
- txd->txd2 = eth->phy_scratch_ring +
-- (j * MTK_FQ_DMA_LENGTH + i + 1) * soc->tx.desc_size;
-+ TX_DESC_OFS(eth, j * MTK_FQ_DMA_LENGTH + i + 1);
-
- txd->txd3 = TX_DMA_PLEN0(MTK_QDMA_PAGE_SIZE);
- if (MTK_HAS_CAPS(soc->caps, MTK_36BIT_DMA))
-@@ -1219,9 +1224,9 @@ static void *mtk_qdma_phys_to_virt(struc
- }
-
- static struct mtk_tx_buf *mtk_desc_to_tx_buf(struct mtk_tx_ring *ring,
-- void *txd, u32 txd_size)
-+ void *txd, u32 txd_shift)
- {
-- int idx = (txd - ring->dma) / txd_size;
-+ int idx = (txd - ring->dma) >> txd_shift;
-
- return &ring->buf[idx];
- }
-@@ -1232,9 +1237,9 @@ static struct mtk_tx_dma *qdma_to_pdma(s
- return ring->dma_pdma - (struct mtk_tx_dma *)ring->dma + dma;
- }
-
--static int txd_to_idx(struct mtk_tx_ring *ring, void *dma, u32 txd_size)
-+static int txd_to_idx(struct mtk_tx_ring *ring, void *dma, u32 txd_shift)
- {
-- return (dma - ring->dma) / txd_size;
-+ return (dma - ring->dma) >> txd_shift;
- }
-
- static void mtk_tx_unmap(struct mtk_eth *eth, struct mtk_tx_buf *tx_buf,
-@@ -1442,7 +1447,7 @@ static int mtk_tx_map(struct sk_buff *sk
- if (itxd == ring->last_free)
- return -ENOMEM;
-
-- itx_buf = mtk_desc_to_tx_buf(ring, itxd, soc->tx.desc_size);
-+ itx_buf = mtk_desc_to_tx_buf(ring, itxd, soc->tx.desc_shift);
- memset(itx_buf, 0, sizeof(*itx_buf));
-
- txd_info.addr = dma_map_single(eth->dma_dev, skb->data, txd_info.size,
-@@ -1496,7 +1501,7 @@ static int mtk_tx_map(struct sk_buff *sk
- mtk_tx_set_dma_desc(dev, txd, &txd_info);
-
- tx_buf = mtk_desc_to_tx_buf(ring, txd,
-- soc->tx.desc_size);
-+ soc->tx.desc_shift);
- if (new_desc)
- memset(tx_buf, 0, sizeof(*tx_buf));
- tx_buf->data = (void *)MTK_DMA_DUMMY_DESC;
-@@ -1539,7 +1544,7 @@ static int mtk_tx_map(struct sk_buff *sk
- } else {
- int next_idx;
-
-- next_idx = NEXT_DESP_IDX(txd_to_idx(ring, txd, soc->tx.desc_size),
-+ next_idx = NEXT_DESP_IDX(txd_to_idx(ring, txd, soc->tx.desc_shift),
- ring->dma_size);
- mtk_w32(eth, next_idx, MT7628_TX_CTX_IDX0);
- }
-@@ -1548,7 +1553,7 @@ static int mtk_tx_map(struct sk_buff *sk
-
- err_dma:
- do {
-- tx_buf = mtk_desc_to_tx_buf(ring, itxd, soc->tx.desc_size);
-+ tx_buf = mtk_desc_to_tx_buf(ring, itxd, soc->tx.desc_shift);
-
- /* unmap dma */
- mtk_tx_unmap(eth, tx_buf, NULL, false);
-@@ -1722,7 +1727,7 @@ static struct mtk_rx_ring *mtk_get_rx_ri
-
- ring = ð->rx_ring[i];
- idx = NEXT_DESP_IDX(ring->calc_idx, ring->dma_size);
-- rxd = ring->dma + idx * eth->soc->rx.desc_size;
-+ rxd = ring->dma + RX_DESC_OFS(eth, idx);
- if (rxd->rxd2 & RX_DMA_DONE) {
- ring->calc_idx_update = true;
- return ring;
-@@ -1890,7 +1895,7 @@ static int mtk_xdp_submit_frame(struct m
- }
- htxd = txd;
-
-- tx_buf = mtk_desc_to_tx_buf(ring, txd, soc->tx.desc_size);
-+ tx_buf = mtk_desc_to_tx_buf(ring, txd, soc->tx.desc_shift);
- memset(tx_buf, 0, sizeof(*tx_buf));
- htx_buf = tx_buf;
-
-@@ -1909,7 +1914,7 @@ static int mtk_xdp_submit_frame(struct m
- goto unmap;
-
- tx_buf = mtk_desc_to_tx_buf(ring, txd,
-- soc->tx.desc_size);
-+ soc->tx.desc_shift);
- memset(tx_buf, 0, sizeof(*tx_buf));
- n_desc++;
- }
-@@ -1947,7 +1952,7 @@ static int mtk_xdp_submit_frame(struct m
- } else {
- int idx;
-
-- idx = txd_to_idx(ring, txd, soc->tx.desc_size);
-+ idx = txd_to_idx(ring, txd, soc->tx.desc_shift);
- mtk_w32(eth, NEXT_DESP_IDX(idx, ring->dma_size),
- MT7628_TX_CTX_IDX0);
- }
-@@ -1958,7 +1963,7 @@ static int mtk_xdp_submit_frame(struct m
-
- unmap:
- while (htxd != txd) {
-- tx_buf = mtk_desc_to_tx_buf(ring, htxd, soc->tx.desc_size);
-+ tx_buf = mtk_desc_to_tx_buf(ring, htxd, soc->tx.desc_shift);
- mtk_tx_unmap(eth, tx_buf, NULL, false);
-
- htxd->txd3 = TX_DMA_LS0 | TX_DMA_OWNER_CPU;
-@@ -2090,7 +2095,7 @@ static int mtk_poll_rx(struct napi_struc
- goto rx_done;
-
- idx = NEXT_DESP_IDX(ring->calc_idx, ring->dma_size);
-- rxd = ring->dma + idx * eth->soc->rx.desc_size;
-+ rxd = ring->dma + RX_DESC_OFS(eth, idx);
- data = ring->data[idx];
-
- if (!mtk_rx_get_desc(eth, &trxd, rxd))
-@@ -2354,7 +2359,7 @@ static int mtk_poll_tx_qdma(struct mtk_e
- break;
-
- tx_buf = mtk_desc_to_tx_buf(ring, desc,
-- eth->soc->tx.desc_size);
-+ eth->soc->tx.desc_shift);
- if (!tx_buf->data)
- break;
-
-@@ -2405,7 +2410,7 @@ static int mtk_poll_tx_pdma(struct mtk_e
- }
- mtk_tx_unmap(eth, tx_buf, &bq, true);
-
-- desc = ring->dma + cpu * eth->soc->tx.desc_size;
-+ desc = ring->dma + TX_DESC_OFS(eth, cpu);
- ring->last_free = desc;
- atomic_inc(&ring->free_count);
-
-@@ -2523,7 +2528,7 @@ static int mtk_tx_alloc(struct mtk_eth *
- {
- const struct mtk_soc_data *soc = eth->soc;
- struct mtk_tx_ring *ring = ð->tx_ring;
-- int i, sz = soc->tx.desc_size;
-+ int i, sz = TX_DESC_OFS(eth, 1);
- struct mtk_tx_dma_v2 *txd;
- int ring_size;
- u32 ofs, val;
-@@ -2570,7 +2575,7 @@ static int mtk_tx_alloc(struct mtk_eth *
- * descriptors in ring->dma_pdma.
- */
- if (!MTK_HAS_CAPS(soc->caps, MTK_QDMA)) {
-- ring->dma_pdma = dma_alloc_coherent(eth->dma_dev, ring_size * sz,
-+ ring->dma_pdma = dma_alloc_coherent(eth->dma_dev, TX_DESC_OFS(eth, ring_size),
- &ring->phys_pdma, GFP_KERNEL);
- if (!ring->dma_pdma)
- goto no_tx_mem;
-@@ -2585,7 +2590,7 @@ static int mtk_tx_alloc(struct mtk_eth *
- atomic_set(&ring->free_count, ring_size - 2);
- ring->next_free = ring->dma;
- ring->last_free = (void *)txd;
-- ring->last_free_ptr = (u32)(ring->phys + ((ring_size - 1) * sz));
-+ ring->last_free_ptr = (u32)(ring->phys + TX_DESC_OFS(eth, ring_size - 1));
- ring->thresh = MAX_SKB_FRAGS;
-
- /* make sure that all changes to the dma ring are flushed before we
-@@ -2597,7 +2602,7 @@ static int mtk_tx_alloc(struct mtk_eth *
- mtk_w32(eth, ring->phys, soc->reg_map->qdma.ctx_ptr);
- mtk_w32(eth, ring->phys, soc->reg_map->qdma.dtx_ptr);
- mtk_w32(eth,
-- ring->phys + ((ring_size - 1) * sz),
-+ ring->phys + TX_DESC_OFS(eth, ring_size - 1),
- soc->reg_map->qdma.crx_ptr);
- mtk_w32(eth, ring->last_free_ptr, soc->reg_map->qdma.drx_ptr);
-
-@@ -2646,14 +2651,14 @@ static void mtk_tx_clean(struct mtk_eth
- }
- if (!MTK_HAS_CAPS(soc->caps, MTK_SRAM) && ring->dma) {
- dma_free_coherent(eth->dma_dev,
-- ring->dma_size * soc->tx.desc_size,
-+ TX_DESC_OFS(eth, ring->dma_size),
- ring->dma, ring->phys);
- ring->dma = NULL;
- }
-
- if (ring->dma_pdma) {
- dma_free_coherent(eth->dma_dev,
-- ring->dma_size * soc->tx.desc_size,
-+ TX_DESC_OFS(eth, ring->dma_size),
- ring->dma_pdma, ring->phys_pdma);
- ring->dma_pdma = NULL;
- }
-@@ -2709,15 +2714,13 @@ static int mtk_rx_alloc(struct mtk_eth *
- if (!MTK_HAS_CAPS(eth->soc->caps, MTK_SRAM) ||
- rx_flag != MTK_RX_FLAGS_NORMAL) {
- ring->dma = dma_alloc_coherent(eth->dma_dev,
-- rx_dma_size * eth->soc->rx.desc_size,
-+ RX_DESC_OFS(eth, rx_dma_size),
- &ring->phys, GFP_KERNEL);
- } else {
- struct mtk_tx_ring *tx_ring = ð->tx_ring;
-
-- ring->dma = tx_ring->dma + tx_ring_size *
-- eth->soc->tx.desc_size * (ring_no + 1);
-- ring->phys = tx_ring->phys + tx_ring_size *
-- eth->soc->tx.desc_size * (ring_no + 1);
-+ ring->dma = tx_ring->dma + TX_DESC_OFS(eth, tx_ring_size * (ring_no + 1));
-+ ring->phys = tx_ring->phys + TX_DESC_OFS(eth, tx_ring_size * (ring_no + 1));
- }
-
- if (!ring->dma)
-@@ -2728,7 +2731,7 @@ static int mtk_rx_alloc(struct mtk_eth *
- dma_addr_t dma_addr;
- void *data;
-
-- rxd = ring->dma + i * eth->soc->rx.desc_size;
-+ rxd = ring->dma + RX_DESC_OFS(eth, i);
- if (ring->page_pool) {
- data = mtk_page_pool_get_buff(ring->page_pool,
- &dma_addr, GFP_KERNEL);
-@@ -2819,7 +2822,7 @@ static void mtk_rx_clean(struct mtk_eth
- if (!ring->data[i])
- continue;
-
-- rxd = ring->dma + i * eth->soc->rx.desc_size;
-+ rxd = ring->dma + RX_DESC_OFS(eth, i);
- if (!rxd->rxd1)
- continue;
-
-@@ -2836,7 +2839,7 @@ static void mtk_rx_clean(struct mtk_eth
-
- if (!in_sram && ring->dma) {
- dma_free_coherent(eth->dma_dev,
-- ring->dma_size * eth->soc->rx.desc_size,
-+ RX_DESC_OFS(eth, ring->dma_size),
- ring->dma, ring->phys);
- ring->dma = NULL;
- }
-@@ -3207,7 +3210,7 @@ static void mtk_dma_free(struct mtk_eth
-
- if (!MTK_HAS_CAPS(soc->caps, MTK_SRAM) && eth->scratch_ring) {
- dma_free_coherent(eth->dma_dev,
-- MTK_QDMA_RING_SIZE * soc->tx.desc_size,
-+ TX_DESC_OFS(eth, MTK_QDMA_RING_SIZE),
- eth->scratch_ring, eth->phy_scratch_ring);
- eth->scratch_ring = NULL;
- eth->phy_scratch_ring = 0;
-@@ -5228,6 +5231,9 @@ static int mtk_remove(struct platform_de
- return 0;
- }
-
-+#define DESC_SIZE(struct_name) \
-+ .desc_shift = const_ilog2(sizeof(struct_name))
-+
- static const struct mtk_soc_data mt2701_data = {
- .reg_map = &mtk_reg_map,
- .caps = MT7623_CAPS | MTK_HWLRO,
-@@ -5236,14 +5242,14 @@ static const struct mtk_soc_data mt2701_
- .required_pctl = true,
- .version = 1,
- .tx = {
-- .desc_size = sizeof(struct mtk_tx_dma),
-+ DESC_SIZE(struct mtk_tx_dma),
- .dma_max_len = MTK_TX_DMA_BUF_LEN,
- .dma_len_offset = 16,
- .dma_size = MTK_DMA_SIZE(2K),
- .fq_dma_size = MTK_DMA_SIZE(2K),
- },
- .rx = {
-- .desc_size = sizeof(struct mtk_rx_dma),
-+ DESC_SIZE(struct mtk_rx_dma),
- .irq_done_mask = MTK_RX_DONE_INT,
- .dma_l4_valid = RX_DMA_L4_VALID,
- .dma_size = MTK_DMA_SIZE(2K),
-@@ -5264,14 +5270,14 @@ static const struct mtk_soc_data mt7621_
- .hash_offset = 2,
- .foe_entry_size = MTK_FOE_ENTRY_V1_SIZE,
- .tx = {
-- .desc_size = sizeof(struct mtk_tx_dma),
-+ DESC_SIZE(struct mtk_tx_dma),
- .dma_max_len = MTK_TX_DMA_BUF_LEN,
- .dma_len_offset = 16,
- .dma_size = MTK_DMA_SIZE(2K),
- .fq_dma_size = MTK_DMA_SIZE(2K),
- },
- .rx = {
-- .desc_size = sizeof(struct mtk_rx_dma),
-+ DESC_SIZE(struct mtk_rx_dma),
- .irq_done_mask = MTK_RX_DONE_INT,
- .dma_l4_valid = RX_DMA_L4_VALID,
- .dma_size = MTK_DMA_SIZE(2K),
-@@ -5294,14 +5300,14 @@ static const struct mtk_soc_data mt7622_
- .has_accounting = true,
- .foe_entry_size = MTK_FOE_ENTRY_V1_SIZE,
- .tx = {
-- .desc_size = sizeof(struct mtk_tx_dma),
-+ DESC_SIZE(struct mtk_tx_dma),
- .dma_max_len = MTK_TX_DMA_BUF_LEN,
- .dma_len_offset = 16,
- .dma_size = MTK_DMA_SIZE(2K),
- .fq_dma_size = MTK_DMA_SIZE(2K),
- },
- .rx = {
-- .desc_size = sizeof(struct mtk_rx_dma),
-+ DESC_SIZE(struct mtk_rx_dma),
- .irq_done_mask = MTK_RX_DONE_INT,
- .dma_l4_valid = RX_DMA_L4_VALID,
- .dma_size = MTK_DMA_SIZE(2K),
-@@ -5323,14 +5329,14 @@ static const struct mtk_soc_data mt7623_
- .foe_entry_size = MTK_FOE_ENTRY_V1_SIZE,
- .disable_pll_modes = true,
- .tx = {
-- .desc_size = sizeof(struct mtk_tx_dma),
-+ DESC_SIZE(struct mtk_tx_dma),
- .dma_max_len = MTK_TX_DMA_BUF_LEN,
- .dma_len_offset = 16,
- .dma_size = MTK_DMA_SIZE(2K),
- .fq_dma_size = MTK_DMA_SIZE(2K),
- },
- .rx = {
-- .desc_size = sizeof(struct mtk_rx_dma),
-+ DESC_SIZE(struct mtk_rx_dma),
- .irq_done_mask = MTK_RX_DONE_INT,
- .dma_l4_valid = RX_DMA_L4_VALID,
- .dma_size = MTK_DMA_SIZE(2K),
-@@ -5349,14 +5355,14 @@ static const struct mtk_soc_data mt7629_
- .has_accounting = true,
- .version = 1,
- .tx = {
-- .desc_size = sizeof(struct mtk_tx_dma),
-+ DESC_SIZE(struct mtk_tx_dma),
- .dma_max_len = MTK_TX_DMA_BUF_LEN,
- .dma_len_offset = 16,
- .dma_size = MTK_DMA_SIZE(2K),
- .fq_dma_size = MTK_DMA_SIZE(2K),
- },
- .rx = {
-- .desc_size = sizeof(struct mtk_rx_dma),
-+ DESC_SIZE(struct mtk_rx_dma),
- .irq_done_mask = MTK_RX_DONE_INT,
- .dma_l4_valid = RX_DMA_L4_VALID,
- .dma_size = MTK_DMA_SIZE(2K),
-@@ -5379,14 +5385,14 @@ static const struct mtk_soc_data mt7981_
- .has_accounting = true,
- .foe_entry_size = MTK_FOE_ENTRY_V2_SIZE,
- .tx = {
-- .desc_size = sizeof(struct mtk_tx_dma_v2),
-+ DESC_SIZE(struct mtk_tx_dma_v2),
- .dma_max_len = MTK_TX_DMA_BUF_LEN_V2,
- .dma_len_offset = 8,
- .dma_size = MTK_DMA_SIZE(2K),
- .fq_dma_size = MTK_DMA_SIZE(2K),
- },
- .rx = {
-- .desc_size = sizeof(struct mtk_rx_dma),
-+ DESC_SIZE(struct mtk_rx_dma),
- .irq_done_mask = MTK_RX_DONE_INT,
- .dma_l4_valid = RX_DMA_L4_VALID_V2,
- .dma_max_len = MTK_TX_DMA_BUF_LEN,
-@@ -5409,14 +5415,14 @@ static const struct mtk_soc_data mt7986_
- .has_accounting = true,
- .foe_entry_size = MTK_FOE_ENTRY_V2_SIZE,
- .tx = {
-- .desc_size = sizeof(struct mtk_tx_dma_v2),
-+ DESC_SIZE(struct mtk_tx_dma_v2),
- .dma_max_len = MTK_TX_DMA_BUF_LEN_V2,
- .dma_len_offset = 8,
- .dma_size = MTK_DMA_SIZE(2K),
- .fq_dma_size = MTK_DMA_SIZE(2K),
- },
- .rx = {
-- .desc_size = sizeof(struct mtk_rx_dma),
-+ DESC_SIZE(struct mtk_rx_dma),
- .irq_done_mask = MTK_RX_DONE_INT,
- .dma_l4_valid = RX_DMA_L4_VALID_V2,
- .dma_max_len = MTK_TX_DMA_BUF_LEN,
-@@ -5439,14 +5445,14 @@ static const struct mtk_soc_data mt7988_
- .has_accounting = true,
- .foe_entry_size = MTK_FOE_ENTRY_V3_SIZE,
- .tx = {
-- .desc_size = sizeof(struct mtk_tx_dma_v2),
-+ DESC_SIZE(struct mtk_tx_dma_v2),
- .dma_max_len = MTK_TX_DMA_BUF_LEN_V2,
- .dma_len_offset = 8,
- .dma_size = MTK_DMA_SIZE(2K),
- .fq_dma_size = MTK_DMA_SIZE(4K),
- },
- .rx = {
-- .desc_size = sizeof(struct mtk_rx_dma_v2),
-+ DESC_SIZE(struct mtk_rx_dma_v2),
- .irq_done_mask = MTK_RX_DONE_INT_V2,
- .dma_l4_valid = RX_DMA_L4_VALID_V2,
- .dma_max_len = MTK_TX_DMA_BUF_LEN_V2,
-@@ -5463,13 +5469,13 @@ static const struct mtk_soc_data rt5350_
- .required_pctl = false,
- .version = 1,
- .tx = {
-- .desc_size = sizeof(struct mtk_tx_dma),
-+ DESC_SIZE(struct mtk_tx_dma),
- .dma_max_len = MTK_TX_DMA_BUF_LEN,
- .dma_len_offset = 16,
- .dma_size = MTK_DMA_SIZE(2K),
- },
- .rx = {
-- .desc_size = sizeof(struct mtk_rx_dma),
-+ DESC_SIZE(struct mtk_rx_dma),
- .irq_done_mask = MTK_RX_DONE_INT,
- .dma_l4_valid = RX_DMA_L4_VALID_PDMA,
- .dma_max_len = MTK_TX_DMA_BUF_LEN,
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-@@ -1174,7 +1174,7 @@ struct mtk_reg_map {
- * @foe_entry_size Foe table entry size.
- * @has_accounting Bool indicating support for accounting of
- * offloaded flows.
-- * @desc_size Tx/Rx DMA descriptor size.
-+ * @desc_shift Tx/Rx DMA descriptor size (in power-of-2).
- * @irq_done_mask Rx irq done register mask.
- * @dma_l4_valid Rx DMA valid register mask.
- * @dma_max_len Max DMA tx/rx buffer length.
-@@ -1195,14 +1195,14 @@ struct mtk_soc_data {
- bool has_accounting;
- bool disable_pll_modes;
- struct {
-- u32 desc_size;
-+ u32 desc_shift;
- u32 dma_max_len;
- u32 dma_len_offset;
- u32 dma_size;
- u32 fq_dma_size;
- } tx;
- struct {
-- u32 desc_size;
-+ u32 desc_shift;
- u32 irq_done_mask;
- u32 dma_l4_valid;
- u32 dma_max_len;
+++ /dev/null
-Date: Mon, 14 Jul 2025 10:52:59 +0200
-Subject: [PATCH] net: ethernet: mtk_eth_soc: shrink struct mtk_tx_buf
-
-There is no need to track the difference between dma_map_page
-and dma_map_single, since they're unmapped in exactly the same way.
-Also reorder fields in order to avoid padding.
-
----
-
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -1245,32 +1245,19 @@ static int txd_to_idx(struct mtk_tx_ring
- static void mtk_tx_unmap(struct mtk_eth *eth, struct mtk_tx_buf *tx_buf,
- struct xdp_frame_bulk *bq, bool napi)
- {
-- if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) {
-- if (tx_buf->flags & MTK_TX_FLAGS_SINGLE0) {
-- dma_unmap_single(eth->dma_dev,
-- dma_unmap_addr(tx_buf, dma_addr0),
-- dma_unmap_len(tx_buf, dma_len0),
-- DMA_TO_DEVICE);
-- } else if (tx_buf->flags & MTK_TX_FLAGS_PAGE0) {
-- dma_unmap_page(eth->dma_dev,
-- dma_unmap_addr(tx_buf, dma_addr0),
-- dma_unmap_len(tx_buf, dma_len0),
-- DMA_TO_DEVICE);
-- }
-- } else {
-- if (dma_unmap_len(tx_buf, dma_len0)) {
-- dma_unmap_page(eth->dma_dev,
-- dma_unmap_addr(tx_buf, dma_addr0),
-- dma_unmap_len(tx_buf, dma_len0),
-- DMA_TO_DEVICE);
-- }
-+ if (dma_unmap_len(tx_buf, dma_len0)) {
-+ dma_unmap_page(eth->dma_dev,
-+ dma_unmap_addr(tx_buf, dma_addr0),
-+ dma_unmap_len(tx_buf, dma_len0),
-+ DMA_TO_DEVICE);
-+ }
-
-- if (dma_unmap_len(tx_buf, dma_len1)) {
-- dma_unmap_page(eth->dma_dev,
-- dma_unmap_addr(tx_buf, dma_addr1),
-- dma_unmap_len(tx_buf, dma_len1),
-- DMA_TO_DEVICE);
-- }
-+ if (!MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA) &&
-+ dma_unmap_len(tx_buf, dma_len1)) {
-+ dma_unmap_page(eth->dma_dev,
-+ dma_unmap_addr(tx_buf, dma_addr1),
-+ dma_unmap_len(tx_buf, dma_len1),
-+ DMA_TO_DEVICE);
- }
-
- if (tx_buf->data && tx_buf->data != (void *)MTK_DMA_DUMMY_DESC) {
-@@ -1292,7 +1279,6 @@ static void mtk_tx_unmap(struct mtk_eth
- xdp_return_frame(xdpf);
- }
- }
-- tx_buf->flags = 0;
- tx_buf->data = NULL;
- }
-
-@@ -1457,7 +1443,6 @@ static int mtk_tx_map(struct sk_buff *sk
-
- mtk_tx_set_dma_desc(dev, itxd, &txd_info);
-
-- itx_buf->flags |= MTK_TX_FLAGS_SINGLE0;
- itx_buf->mac_id = mac->id;
- setup_tx_buf(eth, itx_buf, itxd_pdma, txd_info.addr, txd_info.size,
- k++);
-@@ -1505,7 +1490,6 @@ static int mtk_tx_map(struct sk_buff *sk
- if (new_desc)
- memset(tx_buf, 0, sizeof(*tx_buf));
- tx_buf->data = (void *)MTK_DMA_DUMMY_DESC;
-- tx_buf->flags |= MTK_TX_FLAGS_PAGE0;
- tx_buf->mac_id = mac->id;
-
- setup_tx_buf(eth, tx_buf, txd_pdma, txd_info.addr,
-@@ -1838,8 +1822,6 @@ static int mtk_xdp_frame_map(struct mtk_
- txd_info->size, DMA_TO_DEVICE);
- if (unlikely(dma_mapping_error(eth->dma_dev, txd_info->addr)))
- return -ENOMEM;
--
-- tx_buf->flags |= MTK_TX_FLAGS_SINGLE0;
- } else {
- struct page *page = virt_to_head_page(data);
-
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-@@ -701,14 +701,6 @@ struct mtk_hw_stats {
- struct u64_stats_sync syncp;
- };
-
--enum mtk_tx_flags {
-- /* PDMA descriptor can point at 1-2 segments. This enum allows us to
-- * track how memory was allocated so that it can be freed properly.
-- */
-- MTK_TX_FLAGS_SINGLE0 = 0x01,
-- MTK_TX_FLAGS_PAGE0 = 0x02,
--};
--
- /* This enum allows us to identify how the clock is defined on the array of the
- * clock in the order
- */
-@@ -895,13 +887,12 @@ enum mtk_tx_buf_type {
- */
- struct mtk_tx_buf {
- enum mtk_tx_buf_type type;
-+ u16 mac_id;
- void *data;
-
-- u16 mac_id;
-- u16 flags;
- DEFINE_DMA_UNMAP_ADDR(dma_addr0);
-- DEFINE_DMA_UNMAP_LEN(dma_len0);
- DEFINE_DMA_UNMAP_ADDR(dma_addr1);
-+ DEFINE_DMA_UNMAP_LEN(dma_len0);
- DEFINE_DMA_UNMAP_LEN(dma_len1);
- };
-
+++ /dev/null
-Date: Mon, 14 Jul 2025 10:41:27 +0200
-Subject: [PATCH] net: ethernet: mtk_eth_soc: add support for sending
- fraglist GSO packets
-
-When primarily forwarding traffic, TCP fraglist GRO can be noticeably more
-efficient than regular TCP GRO. In order to avoid the overhead of
-unnecessary segmentation on ethernet tx, add support for sending fraglist
-GRO packets.
-
----
-
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -1403,29 +1403,70 @@ static void mtk_tx_set_dma_desc(struct n
- mtk_tx_set_dma_desc_v1(dev, txd, info);
- }
-
-+struct mtk_tx_map_state {
-+ struct mtk_tx_dma *txd, *txd_pdma;
-+ struct mtk_tx_buf *tx_buf;
-+ int nbuf;
-+ int ndesc;
-+};
-+
-+static int
-+mtk_tx_map_info(struct mtk_eth *eth, struct mtk_tx_ring *ring,
-+ struct net_device *dev, struct mtk_tx_map_state *state,
-+ struct mtk_tx_dma_desc_info *txd_info)
-+{
-+ const struct mtk_soc_data *soc = eth->soc;
-+ struct mtk_tx_dma *txd_pdma = state->txd_pdma;
-+ struct mtk_tx_buf *tx_buf = state->tx_buf;
-+ struct mtk_tx_dma *txd = state->txd;
-+ struct mtk_mac *mac = netdev_priv(dev);
-+
-+ if (state->nbuf &&
-+ (MTK_HAS_CAPS(soc->caps, MTK_QDMA) || (state->nbuf & 1) == 0)) {
-+ txd = state->txd = mtk_qdma_phys_to_virt(ring, txd->txd2);
-+ txd_pdma = state->txd_pdma = qdma_to_pdma(ring, txd);
-+ if (state->txd == ring->last_free)
-+ return -1;
-+
-+ tx_buf = mtk_desc_to_tx_buf(ring, state->txd,
-+ soc->tx.desc_shift);
-+ state->tx_buf = tx_buf;
-+ memset(tx_buf, 0, sizeof(*tx_buf));
-+ state->ndesc++;
-+ }
-+
-+ mtk_tx_set_dma_desc(dev, txd, txd_info);
-+ tx_buf->data = (void *)MTK_DMA_DUMMY_DESC;
-+ tx_buf->mac_id = mac->id;
-+
-+ setup_tx_buf(eth, tx_buf, txd_pdma, txd_info->addr,
-+ txd_info->size, state->nbuf++);
-+ return 0;
-+}
-+
- static int mtk_tx_map(struct sk_buff *skb, struct net_device *dev,
- int tx_num, struct mtk_tx_ring *ring, bool gso)
- {
- struct mtk_tx_dma_desc_info txd_info = {
-- .size = skb_headlen(skb),
- .gso = gso,
-- .csum = skb->ip_summed == CHECKSUM_PARTIAL,
-+ .csum = skb->ip_summed == CHECKSUM_PARTIAL || gso,
- .vlan = skb_vlan_tag_present(skb),
-- .qid = skb_get_queue_mapping(skb),
- .vlan_tci = skb_vlan_tag_get(skb),
- .first = true,
-- .last = !skb_is_nonlinear(skb),
-+ };
-+ struct mtk_tx_map_state state = {
-+ .ndesc = 1,
- };
- struct netdev_queue *txq;
- struct mtk_mac *mac = netdev_priv(dev);
- struct mtk_eth *eth = mac->hw;
- const struct mtk_soc_data *soc = eth->soc;
-- struct mtk_tx_dma *itxd, *txd;
-- struct mtk_tx_dma *itxd_pdma, *txd_pdma;
-- struct mtk_tx_buf *itx_buf, *tx_buf;
-- int i, n_desc = 1;
-+ struct mtk_tx_dma *itxd, *itxd_pdma;
-+ struct mtk_tx_buf *itx_buf;
-+ struct sk_buff *cur_skb, *next_skb;
- int queue = skb_get_queue_mapping(skb);
-- int k = 0;
-+ unsigned int offset = 0;
-+ int i, frag_size;
-
- txq = netdev_get_tx_queue(dev, queue);
- itxd = ring->next_free;
-@@ -1436,86 +1477,81 @@ static int mtk_tx_map(struct sk_buff *sk
- itx_buf = mtk_desc_to_tx_buf(ring, itxd, soc->tx.desc_shift);
- memset(itx_buf, 0, sizeof(*itx_buf));
-
-- txd_info.addr = dma_map_single(eth->dma_dev, skb->data, txd_info.size,
-- DMA_TO_DEVICE);
-- if (unlikely(dma_mapping_error(eth->dma_dev, txd_info.addr)))
-- return -ENOMEM;
--
-- mtk_tx_set_dma_desc(dev, itxd, &txd_info);
--
-- itx_buf->mac_id = mac->id;
-- setup_tx_buf(eth, itx_buf, itxd_pdma, txd_info.addr, txd_info.size,
-- k++);
--
-- /* TX SG offload */
-- txd = itxd;
-- txd_pdma = qdma_to_pdma(ring, txd);
--
-- for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
-- skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
-- unsigned int offset = 0;
-- int frag_size = skb_frag_size(frag);
--
-+ cur_skb = skb;
-+ next_skb = skb_shinfo(skb)->frag_list;
-+ state.txd = itxd;
-+ state.txd_pdma = itxd_pdma;
-+ state.tx_buf = itx_buf;
-+
-+next:
-+ txd_info.qid = queue;
-+ frag_size = skb_headlen(cur_skb);
-+
-+ while (frag_size) {
-+ txd_info.size = min_t(unsigned int, frag_size,
-+ soc->tx.dma_max_len);
-+ txd_info.addr = dma_map_single(eth->dma_dev, cur_skb->data + offset,
-+ txd_info.size, DMA_TO_DEVICE);
-+ if (unlikely(dma_mapping_error(eth->dma_dev, txd_info.addr)))
-+ goto err_dma;
-+
-+ frag_size -= txd_info.size;
-+ offset += txd_info.size;
-+ txd_info.last = !skb_is_nonlinear(cur_skb) && !next_skb &&
-+ !frag_size;
-+ if (mtk_tx_map_info(eth, ring, dev, &state, &txd_info) < 0)
-+ goto err_dma;
-+
-+ txd_info.first = false;
-+ }
-+
-+ for (i = 0; i < skb_shinfo(cur_skb)->nr_frags; i++) {
-+ skb_frag_t *frag = &skb_shinfo(cur_skb)->frags[i];
-+
-+ frag_size = skb_frag_size(frag);
-+ memset(&txd_info, 0, sizeof(struct mtk_tx_dma_desc_info));
-+ txd_info.qid = queue;
-+ offset = 0;
- while (frag_size) {
-- bool new_desc = true;
--
-- if (MTK_HAS_CAPS(soc->caps, MTK_QDMA) ||
-- (i & 0x1)) {
-- txd = mtk_qdma_phys_to_virt(ring, txd->txd2);
-- txd_pdma = qdma_to_pdma(ring, txd);
-- if (txd == ring->last_free)
-- goto err_dma;
--
-- n_desc++;
-- } else {
-- new_desc = false;
-- }
--
-- memset(&txd_info, 0, sizeof(struct mtk_tx_dma_desc_info));
- txd_info.size = min_t(unsigned int, frag_size,
- soc->tx.dma_max_len);
-- txd_info.qid = queue;
-- txd_info.last = i == skb_shinfo(skb)->nr_frags - 1 &&
-- !(frag_size - txd_info.size);
-- txd_info.addr = skb_frag_dma_map(eth->dma_dev, frag,
-- offset, txd_info.size,
-- DMA_TO_DEVICE);
-+ txd_info.addr = skb_frag_dma_map(eth->dma_dev, frag, offset,
-+ txd_info.size, DMA_TO_DEVICE);
- if (unlikely(dma_mapping_error(eth->dma_dev, txd_info.addr)))
- goto err_dma;
-
-- mtk_tx_set_dma_desc(dev, txd, &txd_info);
--
-- tx_buf = mtk_desc_to_tx_buf(ring, txd,
-- soc->tx.desc_shift);
-- if (new_desc)
-- memset(tx_buf, 0, sizeof(*tx_buf));
-- tx_buf->data = (void *)MTK_DMA_DUMMY_DESC;
-- tx_buf->mac_id = mac->id;
--
-- setup_tx_buf(eth, tx_buf, txd_pdma, txd_info.addr,
-- txd_info.size, k++);
--
- frag_size -= txd_info.size;
- offset += txd_info.size;
-+ txd_info.last = i == skb_shinfo(cur_skb)->nr_frags - 1 &&
-+ !frag_size && !next_skb;
-+ if (mtk_tx_map_info(eth, ring, dev, &state, &txd_info) < 0)
-+ goto err_dma;
- }
- }
-
-+ if (next_skb) {
-+ cur_skb = next_skb;
-+ next_skb = cur_skb->next;
-+ memset(&txd_info, 0, sizeof(txd_info));
-+ goto next;
-+ }
-+
- /* store skb to cleanup */
- itx_buf->type = MTK_TYPE_SKB;
- itx_buf->data = skb;
-
- if (!MTK_HAS_CAPS(soc->caps, MTK_QDMA)) {
-- if (k & 0x1)
-- txd_pdma->txd2 |= TX_DMA_LS0;
-+ if (state.nbuf & 0x1)
-+ state.txd_pdma->txd2 |= TX_DMA_LS0;
- else
-- txd_pdma->txd2 |= TX_DMA_LS1;
-+ state.txd_pdma->txd2 |= TX_DMA_LS1;
- }
-
- netdev_tx_sent_queue(txq, skb->len);
- skb_tx_timestamp(skb);
-
-- ring->next_free = mtk_qdma_phys_to_virt(ring, txd->txd2);
-- atomic_sub(n_desc, &ring->free_count);
-+ ring->next_free = mtk_qdma_phys_to_virt(ring, state.txd->txd2);
-+ atomic_sub(state.ndesc, &ring->free_count);
-
- /* make sure that all changes to the dma ring are flushed before we
- * continue
-@@ -1524,11 +1560,11 @@ static int mtk_tx_map(struct sk_buff *sk
-
- if (MTK_HAS_CAPS(soc->caps, MTK_QDMA)) {
- if (netif_xmit_stopped(txq) || !netdev_xmit_more())
-- mtk_w32(eth, txd->txd2, soc->reg_map->qdma.ctx_ptr);
-+ mtk_w32(eth, state.txd->txd2, soc->reg_map->qdma.ctx_ptr);
- } else {
- int next_idx;
-
-- next_idx = NEXT_DESP_IDX(txd_to_idx(ring, txd, soc->tx.desc_shift),
-+ next_idx = NEXT_DESP_IDX(txd_to_idx(ring, state.txd, soc->tx.desc_shift),
- ring->dma_size);
- mtk_w32(eth, next_idx, MT7628_TX_CTX_IDX0);
- }
-@@ -1537,10 +1573,10 @@ static int mtk_tx_map(struct sk_buff *sk
-
- err_dma:
- do {
-- tx_buf = mtk_desc_to_tx_buf(ring, itxd, soc->tx.desc_shift);
-+ itx_buf = mtk_desc_to_tx_buf(ring, itxd, soc->tx.desc_shift);
-
- /* unmap dma */
-- mtk_tx_unmap(eth, tx_buf, NULL, false);
-+ mtk_tx_unmap(eth, itx_buf, NULL, false);
-
- itxd->txd3 = TX_DMA_LS0 | TX_DMA_OWNER_CPU;
- if (!MTK_HAS_CAPS(soc->caps, MTK_QDMA))
-@@ -1548,7 +1584,7 @@ err_dma:
-
- itxd = mtk_qdma_phys_to_virt(ring, itxd->txd2);
- itxd_pdma = qdma_to_pdma(ring, itxd);
-- } while (itxd != txd);
-+ } while (itxd != state.txd);
-
- return -ENOMEM;
- }
-@@ -1568,6 +1604,9 @@ static int mtk_cal_txd_req(struct mtk_et
- nfrags += skb_shinfo(skb)->nr_frags;
- }
-
-+ for (skb = skb_shinfo(skb)->frag_list; skb; skb = skb->next)
-+ nfrags += mtk_cal_txd_req(eth, skb);
-+
- return nfrags;
- }
-
-@@ -1608,6 +1647,10 @@ static bool mtk_skb_has_small_frag(struc
- if (skb_frag_size(&skb_shinfo(skb)->frags[i]) < min_size)
- return true;
-
-+ for (skb = skb_shinfo(skb)->frag_list; skb; skb = skb->next)
-+ if (mtk_skb_has_small_frag(skb))
-+ return true;
-+
- return false;
- }
-
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-@@ -51,6 +51,8 @@
- NETIF_F_HW_VLAN_CTAG_TX | \
- NETIF_F_SG | NETIF_F_TSO | \
- NETIF_F_TSO6 | \
-+ NETIF_F_FRAGLIST | \
-+ NETIF_F_GSO_FRAGLIST | \
- NETIF_F_IPV6_CSUM |\
- NETIF_F_HW_TC)
- #define MTK_HW_FEATURES_MT7628 (NETIF_F_SG | NETIF_F_RXCSUM)
+++ /dev/null
-Date: Mon, 20 May 2024 14:29:58 +0200
-Subject: [PATCH] net: ethernet: mtk_eth_soc: use napi_build_skb()
-
-The napi_build_skb() can reuse the skb in skb cache per CPU or
-can allocate skbs in bulk, which helps improve the performance.
-
----
-
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -2188,7 +2188,7 @@ static int mtk_poll_rx(struct napi_struc
- if (ret != XDP_PASS)
- goto skip_rx;
-
-- skb = build_skb(data, PAGE_SIZE);
-+ skb = napi_build_skb(data, PAGE_SIZE);
- if (unlikely(!skb)) {
- page_pool_put_full_page(ring->page_pool,
- page, true);
-@@ -2226,7 +2226,7 @@ static int mtk_poll_rx(struct napi_struc
- dma_unmap_single(eth->dma_dev, ((u64)trxd.rxd1 | addr64),
- ring->buf_size, DMA_FROM_DEVICE);
-
-- skb = build_skb(data, ring->frag_size);
-+ skb = napi_build_skb(data, ring->frag_size);
- if (unlikely(!skb)) {
- netdev->stats.rx_dropped++;
- skb_free_frag(data);
+++ /dev/null
-Date: Mon, 16 Sep 2024 19:29:03 -0700
-Subject: [PATCH] net: ethernet: mediatek: increase QDMA RESV_BUF size
-
-Increase QDMA RESV_BUF from 2K to 3K for netsys v2 to match Mediatek SDK[1].
-This helps reduce the possibility of Ethernet transmit timeouts.
-
-[1]: https://git01.mediatek.com/plugins/gitiles/openwrt/feeds/mtk-openwrt-feeds/+/19d8456c3051e5f6dabf42fa770916a2126ea4bf
-
----
- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 6 ++++--
- drivers/net/ethernet/mediatek/mtk_eth_soc.h | 1 +
- 2 files changed, 5 insertions(+), 2 deletions(-)
-
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-@@ -282,6 +282,7 @@
- #define MTK_WCOMP_EN BIT(24)
- #define MTK_RESV_BUF (0x80 << 16)
- #define MTK_MUTLI_CNT (0x4 << 12)
-+#define MTK_RESV_BUF_MASK (0xff << 16)
- #define MTK_LEAKY_BUCKET_EN BIT(11)
-
- /* QDMA Flow Control Register */
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -3359,12 +3359,14 @@ static int mtk_start_dma(struct mtk_eth
- MTK_TX_BT_32DWORDS | MTK_NDP_CO_PRO |
- MTK_RX_2B_OFFSET | MTK_TX_WB_DDONE;
-
-- if (mtk_is_netsys_v2_or_greater(eth))
-+ if (mtk_is_netsys_v2_or_greater(eth)) {
-+ val &= ~MTK_RESV_BUF_MASK;
- val |= MTK_MUTLI_CNT | MTK_RESV_BUF |
- MTK_WCOMP_EN | MTK_DMAD_WR_WDONE |
- MTK_CHK_DDONE_EN;
-- else
-+ } else {
- val |= MTK_RX_BT_32DWORDS;
-+ }
- mtk_w32(eth, val, reg_map->qdma.glo_cfg);
-
- mtk_w32(eth,
+++ /dev/null
-Date: Thu, 23 Mar 2023 10:24:11 +0100
-Subject: [PATCH] net: ethernet: mtk_eth_soc: improve keeping track of
- offloaded flows
-
-Unify tracking of L2 and L3 flows. Use the generic list field in struct
-mtk_foe_entry for tracking L2 subflows. Preparation for improving
-flow accounting support.
-
----
- drivers/net/ethernet/mediatek/mtk_ppe.c | 162 ++++++++++++------------
- drivers/net/ethernet/mediatek/mtk_ppe.h | 15 +--
- 2 files changed, 86 insertions(+), 91 deletions(-)
-
---- a/drivers/net/ethernet/mediatek/mtk_ppe.c
-+++ b/drivers/net/ethernet/mediatek/mtk_ppe.c
-@@ -479,42 +479,43 @@ int mtk_foe_entry_set_queue(struct mtk_e
- return 0;
- }
-
-+static int
-+mtk_flow_entry_match_len(struct mtk_eth *eth, struct mtk_foe_entry *entry)
-+{
-+ int type = mtk_get_ib1_pkt_type(eth, entry->ib1);
-+
-+ if (type > MTK_PPE_PKT_TYPE_IPV4_DSLITE)
-+ return offsetof(struct mtk_foe_entry, ipv6._rsv);
-+ else
-+ return offsetof(struct mtk_foe_entry, ipv4.ib2);
-+}
-+
- static bool
- mtk_flow_entry_match(struct mtk_eth *eth, struct mtk_flow_entry *entry,
-- struct mtk_foe_entry *data)
-+ struct mtk_foe_entry *data, int len)
- {
-- int type, len;
--
- if ((data->ib1 ^ entry->data.ib1) & MTK_FOE_IB1_UDP)
- return false;
-
-- type = mtk_get_ib1_pkt_type(eth, entry->data.ib1);
-- if (type > MTK_PPE_PKT_TYPE_IPV4_DSLITE)
-- len = offsetof(struct mtk_foe_entry, ipv6._rsv);
-- else
-- len = offsetof(struct mtk_foe_entry, ipv4.ib2);
--
- return !memcmp(&entry->data.data, &data->data, len - 4);
- }
-
- static void
--__mtk_foe_entry_clear(struct mtk_ppe *ppe, struct mtk_flow_entry *entry)
-+__mtk_foe_entry_clear(struct mtk_ppe *ppe, struct mtk_flow_entry *entry,
-+ bool set_state)
- {
-- struct hlist_head *head;
- struct hlist_node *tmp;
-
- if (entry->type == MTK_FLOW_TYPE_L2) {
- rhashtable_remove_fast(&ppe->l2_flows, &entry->l2_node,
- mtk_flow_l2_ht_params);
-
-- head = &entry->l2_flows;
-- hlist_for_each_entry_safe(entry, tmp, head, l2_data.list)
-- __mtk_foe_entry_clear(ppe, entry);
-+ hlist_for_each_entry_safe(entry, tmp, &entry->l2_flows, l2_list)
-+ __mtk_foe_entry_clear(ppe, entry, set_state);
- return;
- }
-
-- hlist_del_init(&entry->list);
-- if (entry->hash != 0xffff) {
-+ if (entry->hash != 0xffff && set_state) {
- struct mtk_foe_entry *hwe = mtk_foe_get_entry(ppe, entry->hash);
-
- hwe->ib1 &= ~MTK_FOE_IB1_STATE;
-@@ -535,7 +536,8 @@ __mtk_foe_entry_clear(struct mtk_ppe *pp
- if (entry->type != MTK_FLOW_TYPE_L2_SUBFLOW)
- return;
-
-- hlist_del_init(&entry->l2_data.list);
-+ hlist_del_init(&entry->l2_list);
-+ hlist_del_init(&entry->list);
- kfree(entry);
- }
-
-@@ -551,66 +553,55 @@ static int __mtk_foe_entry_idle_time(str
- return now - timestamp;
- }
-
-+static bool
-+mtk_flow_entry_update(struct mtk_ppe *ppe, struct mtk_flow_entry *entry)
-+{
-+ struct mtk_foe_entry foe = {};
-+ struct mtk_foe_entry *hwe;
-+ u16 hash = entry->hash;
-+ int len;
-+
-+ if (hash == 0xffff)
-+ return false;
-+
-+ hwe = mtk_foe_get_entry(ppe, hash);
-+ len = mtk_flow_entry_match_len(ppe->eth, &entry->data);
-+ memcpy(&foe, hwe, len);
-+
-+ if (!mtk_flow_entry_match(ppe->eth, entry, &foe, len) ||
-+ FIELD_GET(MTK_FOE_IB1_STATE, foe.ib1) != MTK_FOE_STATE_BIND)
-+ return false;
-+
-+ entry->data.ib1 = foe.ib1;
-+
-+ return true;
-+}
-+
- static void
- mtk_flow_entry_update_l2(struct mtk_ppe *ppe, struct mtk_flow_entry *entry)
- {
- u32 ib1_ts_mask = mtk_get_ib1_ts_mask(ppe->eth);
- struct mtk_flow_entry *cur;
-- struct mtk_foe_entry *hwe;
- struct hlist_node *tmp;
- int idle;
-
- idle = __mtk_foe_entry_idle_time(ppe, entry->data.ib1);
-- hlist_for_each_entry_safe(cur, tmp, &entry->l2_flows, l2_data.list) {
-+ hlist_for_each_entry_safe(cur, tmp, &entry->l2_flows, l2_list) {
- int cur_idle;
-- u32 ib1;
--
-- hwe = mtk_foe_get_entry(ppe, cur->hash);
-- ib1 = READ_ONCE(hwe->ib1);
-
-- if (FIELD_GET(MTK_FOE_IB1_STATE, ib1) != MTK_FOE_STATE_BIND) {
-- cur->hash = 0xffff;
-- __mtk_foe_entry_clear(ppe, cur);
-+ if (!mtk_flow_entry_update(ppe, cur)) {
-+ __mtk_foe_entry_clear(ppe, entry, false);
- continue;
- }
-
-- cur_idle = __mtk_foe_entry_idle_time(ppe, ib1);
-+ cur_idle = __mtk_foe_entry_idle_time(ppe, cur->data.ib1);
- if (cur_idle >= idle)
- continue;
-
- idle = cur_idle;
- entry->data.ib1 &= ~ib1_ts_mask;
-- entry->data.ib1 |= hwe->ib1 & ib1_ts_mask;
-- }
--}
--
--static void
--mtk_flow_entry_update(struct mtk_ppe *ppe, struct mtk_flow_entry *entry)
--{
-- struct mtk_foe_entry foe = {};
-- struct mtk_foe_entry *hwe;
--
-- spin_lock_bh(&ppe_lock);
--
-- if (entry->type == MTK_FLOW_TYPE_L2) {
-- mtk_flow_entry_update_l2(ppe, entry);
-- goto out;
-+ entry->data.ib1 |= cur->data.ib1 & ib1_ts_mask;
- }
--
-- if (entry->hash == 0xffff)
-- goto out;
--
-- hwe = mtk_foe_get_entry(ppe, entry->hash);
-- memcpy(&foe, hwe, ppe->eth->soc->foe_entry_size);
-- if (!mtk_flow_entry_match(ppe->eth, entry, &foe)) {
-- entry->hash = 0xffff;
-- goto out;
-- }
--
-- entry->data.ib1 = foe.ib1;
--
--out:
-- spin_unlock_bh(&ppe_lock);
- }
-
- static void
-@@ -653,7 +644,8 @@ __mtk_foe_entry_commit(struct mtk_ppe *p
- void mtk_foe_entry_clear(struct mtk_ppe *ppe, struct mtk_flow_entry *entry)
- {
- spin_lock_bh(&ppe_lock);
-- __mtk_foe_entry_clear(ppe, entry);
-+ __mtk_foe_entry_clear(ppe, entry, true);
-+ hlist_del_init(&entry->list);
- spin_unlock_bh(&ppe_lock);
- }
-
-@@ -700,8 +692,8 @@ mtk_foe_entry_commit_subflow(struct mtk_
- {
- const struct mtk_soc_data *soc = ppe->eth->soc;
- struct mtk_flow_entry *flow_info;
-- struct mtk_foe_entry foe = {}, *hwe;
- struct mtk_foe_mac_info *l2;
-+ struct mtk_foe_entry *hwe;
- u32 ib1_mask = mtk_get_ib1_pkt_type_mask(ppe->eth) | MTK_FOE_IB1_UDP;
- int type;
-
-@@ -709,30 +701,30 @@ mtk_foe_entry_commit_subflow(struct mtk_
- if (!flow_info)
- return;
-
-- flow_info->l2_data.base_flow = entry;
- flow_info->type = MTK_FLOW_TYPE_L2_SUBFLOW;
- flow_info->hash = hash;
- hlist_add_head(&flow_info->list,
- &ppe->foe_flow[hash / soc->hash_offset]);
-- hlist_add_head(&flow_info->l2_data.list, &entry->l2_flows);
-+ hlist_add_head(&flow_info->l2_list, &entry->l2_flows);
-
- hwe = mtk_foe_get_entry(ppe, hash);
-- memcpy(&foe, hwe, soc->foe_entry_size);
-- foe.ib1 &= ib1_mask;
-- foe.ib1 |= entry->data.ib1 & ~ib1_mask;
-+ memcpy(&flow_info->data, hwe, soc->foe_entry_size);
-+ flow_info->data.ib1 &= ib1_mask;
-+ flow_info->data.ib1 |= entry->data.ib1 & ~ib1_mask;
-
-- l2 = mtk_foe_entry_l2(ppe->eth, &foe);
-+ l2 = mtk_foe_entry_l2(ppe->eth, &flow_info->data);
- memcpy(l2, &entry->data.bridge.l2, sizeof(*l2));
-
-- type = mtk_get_ib1_pkt_type(ppe->eth, foe.ib1);
-+ type = mtk_get_ib1_pkt_type(ppe->eth, flow_info->data.ib1);
- if (type == MTK_PPE_PKT_TYPE_IPV4_HNAPT)
-- memcpy(&foe.ipv4.new, &foe.ipv4.orig, sizeof(foe.ipv4.new));
-+ memcpy(&flow_info->data.ipv4.new, &flow_info->data.ipv4.orig,
-+ sizeof(flow_info->data.ipv4.new));
- else if (type >= MTK_PPE_PKT_TYPE_IPV6_ROUTE_3T && l2->etype == ETH_P_IP)
- l2->etype = ETH_P_IPV6;
-
-- *mtk_foe_entry_ib2(ppe->eth, &foe) = entry->data.bridge.ib2;
-+ *mtk_foe_entry_ib2(ppe->eth, &flow_info->data) = entry->data.bridge.ib2;
-
-- __mtk_foe_entry_commit(ppe, &foe, hash);
-+ __mtk_foe_entry_commit(ppe, &flow_info->data, hash);
- }
-
- void __mtk_ppe_check_skb(struct mtk_ppe *ppe, struct sk_buff *skb, u16 hash)
-@@ -742,9 +734,11 @@ void __mtk_ppe_check_skb(struct mtk_ppe
- struct mtk_foe_entry *hwe = mtk_foe_get_entry(ppe, hash);
- struct mtk_flow_entry *entry;
- struct mtk_foe_bridge key = {};
-+ struct mtk_foe_entry foe = {};
- struct hlist_node *n;
- struct ethhdr *eh;
- bool found = false;
-+ int entry_len;
- u8 *tag;
-
- spin_lock_bh(&ppe_lock);
-@@ -752,20 +746,14 @@ void __mtk_ppe_check_skb(struct mtk_ppe
- if (FIELD_GET(MTK_FOE_IB1_STATE, hwe->ib1) == MTK_FOE_STATE_BIND)
- goto out;
-
-- hlist_for_each_entry_safe(entry, n, head, list) {
-- if (entry->type == MTK_FLOW_TYPE_L2_SUBFLOW) {
-- if (unlikely(FIELD_GET(MTK_FOE_IB1_STATE, hwe->ib1) ==
-- MTK_FOE_STATE_BIND))
-- continue;
--
-- entry->hash = 0xffff;
-- __mtk_foe_entry_clear(ppe, entry);
-- continue;
-- }
-+ entry_len = mtk_flow_entry_match_len(ppe->eth, hwe);
-+ memcpy(&foe, hwe, entry_len);
-
-- if (found || !mtk_flow_entry_match(ppe->eth, entry, hwe)) {
-+ hlist_for_each_entry_safe(entry, n, head, list) {
-+ if (found ||
-+ !mtk_flow_entry_match(ppe->eth, entry, &foe, entry_len)) {
- if (entry->hash != 0xffff)
-- entry->hash = 0xffff;
-+ __mtk_foe_entry_clear(ppe, entry, false);
- continue;
- }
-
-@@ -816,9 +804,17 @@ out:
-
- int mtk_foe_entry_idle_time(struct mtk_ppe *ppe, struct mtk_flow_entry *entry)
- {
-- mtk_flow_entry_update(ppe, entry);
-+ int idle;
-+
-+ spin_lock_bh(&ppe_lock);
-+ if (entry->type == MTK_FLOW_TYPE_L2)
-+ mtk_flow_entry_update_l2(ppe, entry);
-+ else
-+ mtk_flow_entry_update(ppe, entry);
-+ idle = __mtk_foe_entry_idle_time(ppe, entry->data.ib1);
-+ spin_unlock_bh(&ppe_lock);
-
-- return __mtk_foe_entry_idle_time(ppe, entry->data.ib1);
-+ return idle;
- }
-
- int mtk_ppe_prepare_reset(struct mtk_ppe *ppe)
---- a/drivers/net/ethernet/mediatek/mtk_ppe.h
-+++ b/drivers/net/ethernet/mediatek/mtk_ppe.h
-@@ -286,7 +286,12 @@ enum {
-
- struct mtk_flow_entry {
- union {
-- struct hlist_node list;
-+ /* regular flows + L2 subflows */
-+ struct {
-+ struct hlist_node list;
-+ struct hlist_node l2_list;
-+ };
-+ /* L2 flows */
- struct {
- struct rhash_head l2_node;
- struct hlist_head l2_flows;
-@@ -296,13 +301,7 @@ struct mtk_flow_entry {
- s8 wed_index;
- u8 ppe_index;
- u16 hash;
-- union {
-- struct mtk_foe_entry data;
-- struct {
-- struct mtk_flow_entry *base_flow;
-- struct hlist_node list;
-- } l2_data;
-- };
-+ struct mtk_foe_entry data;
- struct rhash_head node;
- unsigned long cookie;
- };
+++ /dev/null
-Date: Thu, 23 Mar 2023 11:05:22 +0100
-Subject: [PATCH] net: ethernet: mediatek: fix ppe flow accounting for L2
- flows
-
-For L2 flows, the packet/byte counters should report the sum of the
-counters of their subflows, both current and expired.
-In order to make this work, change the way that accounting data is tracked.
-Reset counters when a flow enters bind. Once it expires (or enters unbind),
-store the last counter value in struct mtk_flow_entry.
-
----
-
---- a/drivers/net/ethernet/mediatek/mtk_ppe.c
-+++ b/drivers/net/ethernet/mediatek/mtk_ppe.c
-@@ -80,9 +80,9 @@ static int mtk_ppe_mib_wait_busy(struct
- int ret;
- u32 val;
-
-- ret = readl_poll_timeout(ppe->base + MTK_PPE_MIB_SER_CR, val,
-- !(val & MTK_PPE_MIB_SER_CR_ST),
-- 20, MTK_PPE_WAIT_TIMEOUT_US);
-+ ret = readl_poll_timeout_atomic(ppe->base + MTK_PPE_MIB_SER_CR, val,
-+ !(val & MTK_PPE_MIB_SER_CR_ST),
-+ 20, MTK_PPE_WAIT_TIMEOUT_US);
-
- if (ret)
- dev_err(ppe->dev, "MIB table busy");
-@@ -90,17 +90,31 @@ static int mtk_ppe_mib_wait_busy(struct
- return ret;
- }
-
--static int mtk_mib_entry_read(struct mtk_ppe *ppe, u16 index, u64 *bytes, u64 *packets)
-+static inline struct mtk_foe_accounting *
-+mtk_ppe_acct_data(struct mtk_ppe *ppe, u16 index)
-+{
-+ if (!ppe->acct_table)
-+ return NULL;
-+
-+ return ppe->acct_table + index * sizeof(struct mtk_foe_accounting);
-+}
-+
-+struct mtk_foe_accounting *mtk_ppe_mib_entry_read(struct mtk_ppe *ppe, u16 index)
- {
- u32 val, cnt_r0, cnt_r1, cnt_r2;
-+ struct mtk_foe_accounting *acct;
- int ret;
-
- val = FIELD_PREP(MTK_PPE_MIB_SER_CR_ADDR, index) | MTK_PPE_MIB_SER_CR_ST;
- ppe_w32(ppe, MTK_PPE_MIB_SER_CR, val);
-
-+ acct = mtk_ppe_acct_data(ppe, index);
-+ if (!acct)
-+ return NULL;
-+
- ret = mtk_ppe_mib_wait_busy(ppe);
- if (ret)
-- return ret;
-+ return acct;
-
- cnt_r0 = readl(ppe->base + MTK_PPE_MIB_SER_R0);
- cnt_r1 = readl(ppe->base + MTK_PPE_MIB_SER_R1);
-@@ -109,19 +123,19 @@ static int mtk_mib_entry_read(struct mtk
- if (mtk_is_netsys_v3_or_greater(ppe->eth)) {
- /* 64 bit for each counter */
- u32 cnt_r3 = readl(ppe->base + MTK_PPE_MIB_SER_R3);
-- *bytes = ((u64)cnt_r1 << 32) | cnt_r0;
-- *packets = ((u64)cnt_r3 << 32) | cnt_r2;
-+ acct->bytes += ((u64)cnt_r1 << 32) | cnt_r0;
-+ acct->packets += ((u64)cnt_r3 << 32) | cnt_r2;
- } else {
- /* 48 bit byte counter, 40 bit packet counter */
- u32 byte_cnt_low = FIELD_GET(MTK_PPE_MIB_SER_R0_BYTE_CNT_LOW, cnt_r0);
- u32 byte_cnt_high = FIELD_GET(MTK_PPE_MIB_SER_R1_BYTE_CNT_HIGH, cnt_r1);
- u32 pkt_cnt_low = FIELD_GET(MTK_PPE_MIB_SER_R1_PKT_CNT_LOW, cnt_r1);
- u32 pkt_cnt_high = FIELD_GET(MTK_PPE_MIB_SER_R2_PKT_CNT_HIGH, cnt_r2);
-- *bytes = ((u64)byte_cnt_high << 32) | byte_cnt_low;
-- *packets = ((u64)pkt_cnt_high << 16) | pkt_cnt_low;
-+ acct->bytes += ((u64)byte_cnt_high << 32) | byte_cnt_low;
-+ acct->packets += ((u64)pkt_cnt_high << 16) | pkt_cnt_low;
- }
-
-- return 0;
-+ return acct;
- }
-
- static void mtk_ppe_cache_clear(struct mtk_ppe *ppe)
-@@ -522,14 +536,6 @@ __mtk_foe_entry_clear(struct mtk_ppe *pp
- hwe->ib1 |= FIELD_PREP(MTK_FOE_IB1_STATE, MTK_FOE_STATE_INVALID);
- dma_wmb();
- mtk_ppe_cache_clear(ppe);
--
-- if (ppe->accounting) {
-- struct mtk_foe_accounting *acct;
--
-- acct = ppe->acct_table + entry->hash * sizeof(*acct);
-- acct->packets = 0;
-- acct->bytes = 0;
-- }
- }
- entry->hash = 0xffff;
-
-@@ -554,11 +560,14 @@ static int __mtk_foe_entry_idle_time(str
- }
-
- static bool
--mtk_flow_entry_update(struct mtk_ppe *ppe, struct mtk_flow_entry *entry)
-+mtk_flow_entry_update(struct mtk_ppe *ppe, struct mtk_flow_entry *entry,
-+ u64 *packets, u64 *bytes)
- {
-+ struct mtk_foe_accounting *acct;
- struct mtk_foe_entry foe = {};
- struct mtk_foe_entry *hwe;
- u16 hash = entry->hash;
-+ bool ret = false;
- int len;
-
- if (hash == 0xffff)
-@@ -569,18 +578,35 @@ mtk_flow_entry_update(struct mtk_ppe *pp
- memcpy(&foe, hwe, len);
-
- if (!mtk_flow_entry_match(ppe->eth, entry, &foe, len) ||
-- FIELD_GET(MTK_FOE_IB1_STATE, foe.ib1) != MTK_FOE_STATE_BIND)
-- return false;
-+ FIELD_GET(MTK_FOE_IB1_STATE, foe.ib1) != MTK_FOE_STATE_BIND) {
-+ acct = mtk_ppe_acct_data(ppe, hash);
-+ if (acct) {
-+ entry->prev_packets += acct->packets;
-+ entry->prev_bytes += acct->bytes;
-+ }
-+
-+ goto out;
-+ }
-
- entry->data.ib1 = foe.ib1;
-+ acct = mtk_ppe_mib_entry_read(ppe, hash);
-+ ret = true;
-+
-+out:
-+ if (acct) {
-+ *packets += acct->packets;
-+ *bytes += acct->bytes;
-+ }
-
-- return true;
-+ return ret;
- }
-
- static void
- mtk_flow_entry_update_l2(struct mtk_ppe *ppe, struct mtk_flow_entry *entry)
- {
- u32 ib1_ts_mask = mtk_get_ib1_ts_mask(ppe->eth);
-+ u64 *packets = &entry->packets;
-+ u64 *bytes = &entry->bytes;
- struct mtk_flow_entry *cur;
- struct hlist_node *tmp;
- int idle;
-@@ -589,7 +615,9 @@ mtk_flow_entry_update_l2(struct mtk_ppe
- hlist_for_each_entry_safe(cur, tmp, &entry->l2_flows, l2_list) {
- int cur_idle;
-
-- if (!mtk_flow_entry_update(ppe, cur)) {
-+ if (!mtk_flow_entry_update(ppe, cur, packets, bytes)) {
-+ entry->prev_packets += cur->prev_packets;
-+ entry->prev_bytes += cur->prev_bytes;
- __mtk_foe_entry_clear(ppe, entry, false);
- continue;
- }
-@@ -604,10 +632,29 @@ mtk_flow_entry_update_l2(struct mtk_ppe
- }
- }
-
-+void mtk_foe_entry_get_stats(struct mtk_ppe *ppe, struct mtk_flow_entry *entry,
-+ int *idle)
-+{
-+ entry->packets = entry->prev_packets;
-+ entry->bytes = entry->prev_bytes;
-+
-+ spin_lock_bh(&ppe_lock);
-+
-+ if (entry->type == MTK_FLOW_TYPE_L2)
-+ mtk_flow_entry_update_l2(ppe, entry);
-+ else
-+ mtk_flow_entry_update(ppe, entry, &entry->packets, &entry->bytes);
-+
-+ *idle = __mtk_foe_entry_idle_time(ppe, entry->data.ib1);
-+
-+ spin_unlock_bh(&ppe_lock);
-+}
-+
- static void
- __mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_foe_entry *entry,
- u16 hash)
- {
-+ struct mtk_foe_accounting *acct;
- struct mtk_eth *eth = ppe->eth;
- u16 timestamp = mtk_eth_timestamp(eth);
- struct mtk_foe_entry *hwe;
-@@ -638,6 +685,12 @@ __mtk_foe_entry_commit(struct mtk_ppe *p
-
- dma_wmb();
-
-+ acct = mtk_ppe_mib_entry_read(ppe, hash);
-+ if (acct) {
-+ acct->packets = 0;
-+ acct->bytes = 0;
-+ }
-+
- mtk_ppe_cache_clear(ppe);
- }
-
-@@ -802,21 +855,6 @@ out:
- spin_unlock_bh(&ppe_lock);
- }
-
--int mtk_foe_entry_idle_time(struct mtk_ppe *ppe, struct mtk_flow_entry *entry)
--{
-- int idle;
--
-- spin_lock_bh(&ppe_lock);
-- if (entry->type == MTK_FLOW_TYPE_L2)
-- mtk_flow_entry_update_l2(ppe, entry);
-- else
-- mtk_flow_entry_update(ppe, entry);
-- idle = __mtk_foe_entry_idle_time(ppe, entry->data.ib1);
-- spin_unlock_bh(&ppe_lock);
--
-- return idle;
--}
--
- int mtk_ppe_prepare_reset(struct mtk_ppe *ppe)
- {
- if (!ppe)
-@@ -844,32 +882,6 @@ int mtk_ppe_prepare_reset(struct mtk_ppe
- return mtk_ppe_wait_busy(ppe);
- }
-
--struct mtk_foe_accounting *mtk_foe_entry_get_mib(struct mtk_ppe *ppe, u32 index,
-- struct mtk_foe_accounting *diff)
--{
-- struct mtk_foe_accounting *acct;
-- int size = sizeof(struct mtk_foe_accounting);
-- u64 bytes, packets;
--
-- if (!ppe->accounting)
-- return NULL;
--
-- if (mtk_mib_entry_read(ppe, index, &bytes, &packets))
-- return NULL;
--
-- acct = ppe->acct_table + index * size;
--
-- acct->bytes += bytes;
-- acct->packets += packets;
--
-- if (diff) {
-- diff->bytes = bytes;
-- diff->packets = packets;
-- }
--
-- return acct;
--}
--
- struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base, int index)
- {
- bool accounting = eth->soc->has_accounting;
---- a/drivers/net/ethernet/mediatek/mtk_ppe.h
-+++ b/drivers/net/ethernet/mediatek/mtk_ppe.h
-@@ -304,6 +304,8 @@ struct mtk_flow_entry {
- struct mtk_foe_entry data;
- struct rhash_head node;
- unsigned long cookie;
-+ u64 prev_packets, prev_bytes;
-+ u64 packets, bytes;
- };
-
- struct mtk_mib_entry {
-@@ -348,6 +350,7 @@ void mtk_ppe_deinit(struct mtk_eth *eth)
- void mtk_ppe_start(struct mtk_ppe *ppe);
- int mtk_ppe_stop(struct mtk_ppe *ppe);
- int mtk_ppe_prepare_reset(struct mtk_ppe *ppe);
-+struct mtk_foe_accounting *mtk_ppe_mib_entry_read(struct mtk_ppe *ppe, u16 index);
-
- void __mtk_ppe_check_skb(struct mtk_ppe *ppe, struct sk_buff *skb, u16 hash);
-
-@@ -397,9 +400,8 @@ int mtk_foe_entry_set_queue(struct mtk_e
- unsigned int queue);
- int mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_flow_entry *entry);
- void mtk_foe_entry_clear(struct mtk_ppe *ppe, struct mtk_flow_entry *entry);
--int mtk_foe_entry_idle_time(struct mtk_ppe *ppe, struct mtk_flow_entry *entry);
- int mtk_ppe_debugfs_init(struct mtk_ppe *ppe, int index);
--struct mtk_foe_accounting *mtk_foe_entry_get_mib(struct mtk_ppe *ppe, u32 index,
-- struct mtk_foe_accounting *diff);
-+void mtk_foe_entry_get_stats(struct mtk_ppe *ppe, struct mtk_flow_entry *entry,
-+ int *idle);
-
- #endif
---- a/drivers/net/ethernet/mediatek/mtk_ppe_debugfs.c
-+++ b/drivers/net/ethernet/mediatek/mtk_ppe_debugfs.c
-@@ -96,7 +96,7 @@ mtk_ppe_debugfs_foe_show(struct seq_file
- if (bind && state != MTK_FOE_STATE_BIND)
- continue;
-
-- acct = mtk_foe_entry_get_mib(ppe, i, NULL);
-+ acct = mtk_ppe_mib_entry_read(ppe, i);
-
- type = mtk_get_ib1_pkt_type(ppe->eth, entry->ib1);
- seq_printf(m, "%05x %s %7s", i,
---- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
-+++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
-@@ -518,24 +518,21 @@ static int
- mtk_flow_offload_stats(struct mtk_eth *eth, struct flow_cls_offload *f)
- {
- struct mtk_flow_entry *entry;
-- struct mtk_foe_accounting diff;
-- u32 idle;
-+ u64 packets, bytes;
-+ int idle;
-
- entry = rhashtable_lookup(ð->flow_table, &f->cookie,
- mtk_flow_ht_params);
- if (!entry)
- return -ENOENT;
-
-- idle = mtk_foe_entry_idle_time(eth->ppe[entry->ppe_index], entry);
-+ packets = entry->packets;
-+ bytes = entry->bytes;
-+ mtk_foe_entry_get_stats(eth->ppe[entry->ppe_index], entry, &idle);
-+ f->stats.pkts += entry->packets - packets;
-+ f->stats.bytes += entry->bytes - bytes;
- f->stats.lastused = jiffies - idle * HZ;
-
-- if (entry->hash != 0xFFFF &&
-- mtk_foe_entry_get_mib(eth->ppe[entry->ppe_index], entry->hash,
-- &diff)) {
-- f->stats.pkts += diff.packets;
-- f->stats.bytes += diff.bytes;
-- }
--
- return 0;
- }
-
+++ /dev/null
-Date: Fri, 12 Sep 2025 14:18:14 +0200
-Subject: [PATCH] net: ethernet: mtk_eth_soc: zero initialize PPE flow table
-
-Avoid picking up flows from last boot or other invalid data
-
----
-
---- a/drivers/net/ethernet/mediatek/mtk_ppe.c
-+++ b/drivers/net/ethernet/mediatek/mtk_ppe.c
-@@ -914,6 +914,7 @@ struct mtk_ppe *mtk_ppe_init(struct mtk_
- if (!foe)
- goto err_free_l2_flows;
-
-+ memset(foe, 0, MTK_PPE_ENTRIES * soc->foe_entry_size);
- ppe->foe_table = foe;
-
- foe_flow_size = (MTK_PPE_ENTRIES / soc->hash_offset) *
-@@ -928,6 +929,7 @@ struct mtk_ppe *mtk_ppe_init(struct mtk_
- if (!mib)
- return NULL;
-
-+ memset(mib, 0, MTK_PPE_ENTRIES * sizeof(*mib));
- ppe->mib_table = mib;
-
- acct = devm_kzalloc(dev, MTK_PPE_ENTRIES * sizeof(*acct),
+++ /dev/null
-From d5e337e7aecc2e1cc9e96768062610adb95f8f72 Mon Sep 17 00:00:00 2001
-Date: Tue, 12 Dec 2023 03:51:14 +0000
-Subject: [PATCH] net: ethernet: mtk_eth_soc: add paths and SerDes modes for
- MT7988
-
-MT7988 comes with a built-in 2.5G PHY as well as SerDes lanes to
-connect external PHYs or transceivers in USXGMII, 10GBase-R, 5GBase-R,
-2500Base-X, 1000Base-X and Cisco SGMII interface modes.
-
-Implement support for configuring for the new paths to SerDes interfaces
-and the internal 2.5G PHY.
-
-Add USXGMII PCS driver for 10GBase-R, 5GBase-R and USXGMII mode, and
-setup the new PHYA on MT7988 to access the also still existing old
-LynxI PCS for 1000Base-X, 2500Base-X and Cisco SGMII PCS interface
-modes.
-
----
- drivers/net/ethernet/mediatek/mtk_eth_path.c | 122 +++++++-
- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 292 +++++++++++++++++--
- drivers/net/ethernet/mediatek/mtk_eth_soc.h | 107 ++++++-
- 3 files changed, 470 insertions(+), 51 deletions(-)
-
---- a/drivers/net/ethernet/mediatek/mtk_eth_path.c
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_path.c
-@@ -31,10 +31,20 @@ static const char *mtk_eth_path_name(u64
- return "gmac2_rgmii";
- case MTK_ETH_PATH_GMAC2_SGMII:
- return "gmac2_sgmii";
-+ case MTK_ETH_PATH_GMAC2_2P5GPHY:
-+ return "gmac2_2p5gphy";
- case MTK_ETH_PATH_GMAC2_GEPHY:
- return "gmac2_gephy";
-+ case MTK_ETH_PATH_GMAC3_SGMII:
-+ return "gmac3_sgmii";
- case MTK_ETH_PATH_GDM1_ESW:
- return "gdm1_esw";
-+ case MTK_ETH_PATH_GMAC1_USXGMII:
-+ return "gmac1_usxgmii";
-+ case MTK_ETH_PATH_GMAC2_USXGMII:
-+ return "gmac2_usxgmii";
-+ case MTK_ETH_PATH_GMAC3_USXGMII:
-+ return "gmac3_usxgmii";
- default:
- return "unknown path";
- }
-@@ -127,6 +137,27 @@ static int set_mux_u3_gmac2_to_qphy(stru
- return 0;
- }
-
-+static int set_mux_gmac2_to_2p5gphy(struct mtk_eth *eth, u64 path)
-+{
-+ int ret;
-+
-+ if (path == MTK_ETH_PATH_GMAC2_2P5GPHY) {
-+ ret = regmap_clear_bits(eth->ethsys, ETHSYS_SYSCFG0, SYSCFG0_SGMII_GMAC2_V2);
-+ if (ret)
-+ return ret;
-+
-+ /* Setup mux to 2p5g PHY */
-+ ret = regmap_clear_bits(eth->infra, TOP_MISC_NETSYS_PCS_MUX, MUX_G2_USXGMII_SEL);
-+ if (ret)
-+ return ret;
-+
-+ dev_dbg(eth->dev, "path %s in %s updated\n",
-+ mtk_eth_path_name(path), __func__);
-+ }
-+
-+ return 0;
-+}
-+
- static int set_mux_gmac1_gmac2_to_sgmii_rgmii(struct mtk_eth *eth, u64 path)
- {
- unsigned int val = 0;
-@@ -165,7 +196,48 @@ static int set_mux_gmac1_gmac2_to_sgmii_
- return 0;
- }
-
--static int set_mux_gmac12_to_gephy_sgmii(struct mtk_eth *eth, u64 path)
-+static int set_mux_gmac123_to_usxgmii(struct mtk_eth *eth, u64 path)
-+{
-+ unsigned int val = 0;
-+ bool updated = true;
-+ int mac_id = 0;
-+
-+ /* Disable SYSCFG1 SGMII */
-+ regmap_read(eth->ethsys, ETHSYS_SYSCFG0, &val);
-+
-+ switch (path) {
-+ case MTK_ETH_PATH_GMAC1_USXGMII:
-+ val &= ~(u32)SYSCFG0_SGMII_GMAC1_V2;
-+ mac_id = MTK_GMAC1_ID;
-+ break;
-+ case MTK_ETH_PATH_GMAC2_USXGMII:
-+ val &= ~(u32)SYSCFG0_SGMII_GMAC2_V2;
-+ mac_id = MTK_GMAC2_ID;
-+ break;
-+ case MTK_ETH_PATH_GMAC3_USXGMII:
-+ val &= ~(u32)SYSCFG0_SGMII_GMAC3_V2;
-+ mac_id = MTK_GMAC3_ID;
-+ break;
-+ default:
-+ updated = false;
-+ };
-+
-+ if (updated) {
-+ regmap_update_bits(eth->ethsys, ETHSYS_SYSCFG0,
-+ SYSCFG0_SGMII_MASK, val);
-+
-+ if (mac_id == MTK_GMAC2_ID)
-+ regmap_set_bits(eth->infra, TOP_MISC_NETSYS_PCS_MUX,
-+ MUX_G2_USXGMII_SEL);
-+ }
-+
-+ dev_dbg(eth->dev, "path %s in %s updated = %d\n",
-+ mtk_eth_path_name(path), __func__, updated);
-+
-+ return 0;
-+}
-+
-+static int set_mux_gmac123_to_gephy_sgmii(struct mtk_eth *eth, u64 path)
- {
- unsigned int val = 0;
- bool updated = true;
-@@ -182,6 +254,9 @@ static int set_mux_gmac12_to_gephy_sgmii
- case MTK_ETH_PATH_GMAC2_SGMII:
- val |= SYSCFG0_SGMII_GMAC2_V2;
- break;
-+ case MTK_ETH_PATH_GMAC3_SGMII:
-+ val |= SYSCFG0_SGMII_GMAC3_V2;
-+ break;
- default:
- updated = false;
- }
-@@ -210,13 +285,25 @@ static const struct mtk_eth_muxc mtk_eth
- .cap_bit = MTK_ETH_MUX_U3_GMAC2_TO_QPHY,
- .set_path = set_mux_u3_gmac2_to_qphy,
- }, {
-+ .name = "mux_gmac2_to_2p5gphy",
-+ .cap_bit = MTK_ETH_MUX_GMAC2_TO_2P5GPHY,
-+ .set_path = set_mux_gmac2_to_2p5gphy,
-+ }, {
- .name = "mux_gmac1_gmac2_to_sgmii_rgmii",
- .cap_bit = MTK_ETH_MUX_GMAC1_GMAC2_TO_SGMII_RGMII,
- .set_path = set_mux_gmac1_gmac2_to_sgmii_rgmii,
- }, {
- .name = "mux_gmac12_to_gephy_sgmii",
- .cap_bit = MTK_ETH_MUX_GMAC12_TO_GEPHY_SGMII,
-- .set_path = set_mux_gmac12_to_gephy_sgmii,
-+ .set_path = set_mux_gmac123_to_gephy_sgmii,
-+ }, {
-+ .name = "mux_gmac123_to_gephy_sgmii",
-+ .cap_bit = MTK_ETH_MUX_GMAC123_TO_GEPHY_SGMII,
-+ .set_path = set_mux_gmac123_to_gephy_sgmii,
-+ }, {
-+ .name = "mux_gmac123_to_usxgmii",
-+ .cap_bit = MTK_ETH_MUX_GMAC123_TO_USXGMII,
-+ .set_path = set_mux_gmac123_to_usxgmii,
- },
- };
-
-@@ -249,12 +336,39 @@ out:
- return err;
- }
-
-+int mtk_gmac_usxgmii_path_setup(struct mtk_eth *eth, int mac_id)
-+{
-+ u64 path;
-+
-+ path = (mac_id == MTK_GMAC1_ID) ? MTK_ETH_PATH_GMAC1_USXGMII :
-+ (mac_id == MTK_GMAC2_ID) ? MTK_ETH_PATH_GMAC2_USXGMII :
-+ MTK_ETH_PATH_GMAC3_USXGMII;
-+
-+ /* Setup proper MUXes along the path */
-+ return mtk_eth_mux_setup(eth, path);
-+}
-+
- int mtk_gmac_sgmii_path_setup(struct mtk_eth *eth, int mac_id)
- {
- u64 path;
-
-- path = (mac_id == 0) ? MTK_ETH_PATH_GMAC1_SGMII :
-- MTK_ETH_PATH_GMAC2_SGMII;
-+ path = (mac_id == MTK_GMAC1_ID) ? MTK_ETH_PATH_GMAC1_SGMII :
-+ (mac_id == MTK_GMAC2_ID) ? MTK_ETH_PATH_GMAC2_SGMII :
-+ MTK_ETH_PATH_GMAC3_SGMII;
-+
-+ /* Setup proper MUXes along the path */
-+ return mtk_eth_mux_setup(eth, path);
-+}
-+
-+int mtk_gmac_2p5gphy_path_setup(struct mtk_eth *eth, int mac_id)
-+{
-+ u64 path = 0;
-+
-+ if (mac_id == MTK_GMAC2_ID)
-+ path = MTK_ETH_PATH_GMAC2_2P5GPHY;
-+
-+ if (!path)
-+ return -EINVAL;
-
- /* Setup proper MUXes along the path */
- return mtk_eth_mux_setup(eth, path);
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -22,6 +22,8 @@
- #include <linux/pinctrl/devinfo.h>
- #include <linux/phylink.h>
- #include <linux/pcs/pcs-mtk-lynxi.h>
-+#include <linux/pcs/pcs-mtk-usxgmii.h>
-+#include <linux/phy/phy.h>
- #include <linux/jhash.h>
- #include <linux/bitfield.h>
- #include <net/dsa.h>
-@@ -275,12 +277,8 @@ static const char * const mtk_clks_sourc
- "ethwarp_wocpu2",
- "ethwarp_wocpu1",
- "ethwarp_wocpu0",
-- "top_usxgmii0_sel",
-- "top_usxgmii1_sel",
- "top_sgm0_sel",
- "top_sgm1_sel",
-- "top_xfi_phy0_xtal_sel",
-- "top_xfi_phy1_xtal_sel",
- "top_eth_gmii_sel",
- "top_eth_refck_50m_sel",
- "top_eth_sys_200m_sel",
-@@ -523,6 +521,30 @@ static void mtk_setup_bridge_switch(stru
- MTK_GSW_CFG);
- }
-
-+static bool mtk_check_gmac23_idle(struct mtk_mac *mac)
-+{
-+ u32 mac_fsm, gdm_fsm;
-+
-+ mac_fsm = mtk_r32(mac->hw, MTK_MAC_FSM(mac->id));
-+
-+ switch (mac->id) {
-+ case MTK_GMAC2_ID:
-+ gdm_fsm = mtk_r32(mac->hw, MTK_FE_GDM2_FSM);
-+ break;
-+ case MTK_GMAC3_ID:
-+ gdm_fsm = mtk_r32(mac->hw, MTK_FE_GDM3_FSM);
-+ break;
-+ default:
-+ return true;
-+ };
-+
-+ if ((mac_fsm & 0xFFFF0000) == 0x01010000 &&
-+ (gdm_fsm & 0xFFFF0000) == 0x00000000)
-+ return true;
-+
-+ return false;
-+}
-+
- static struct phylink_pcs *mtk_mac_select_pcs(struct phylink_config *config,
- phy_interface_t interface)
- {
-@@ -531,6 +553,21 @@ static struct phylink_pcs *mtk_mac_selec
- struct mtk_eth *eth = mac->hw;
- unsigned int sid;
-
-+ if (mtk_is_netsys_v3_or_greater(eth)) {
-+ switch (interface) {
-+ case PHY_INTERFACE_MODE_1000BASEX:
-+ case PHY_INTERFACE_MODE_2500BASEX:
-+ case PHY_INTERFACE_MODE_SGMII:
-+ return mac->sgmii_pcs;
-+ case PHY_INTERFACE_MODE_5GBASER:
-+ case PHY_INTERFACE_MODE_10GBASER:
-+ case PHY_INTERFACE_MODE_USXGMII:
-+ return mac->usxgmii_pcs;
-+ default:
-+ return NULL;
-+ }
-+ }
-+
- if (interface == PHY_INTERFACE_MODE_SGMII ||
- phy_interface_mode_is_8023z(interface)) {
- sid = (MTK_HAS_CAPS(eth->soc->caps, MTK_SHARED_SGMII)) ?
-@@ -582,7 +619,22 @@ static void mtk_mac_config(struct phylin
- goto init_err;
- }
- break;
-+ case PHY_INTERFACE_MODE_USXGMII:
-+ case PHY_INTERFACE_MODE_10GBASER:
-+ case PHY_INTERFACE_MODE_5GBASER:
-+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_USXGMII)) {
-+ err = mtk_gmac_usxgmii_path_setup(eth, mac->id);
-+ if (err)
-+ goto init_err;
-+ }
-+ break;
- case PHY_INTERFACE_MODE_INTERNAL:
-+ if (mac->id == MTK_GMAC2_ID &&
-+ MTK_HAS_CAPS(eth->soc->caps, MTK_2P5GPHY)) {
-+ err = mtk_gmac_2p5gphy_path_setup(eth, mac->id);
-+ if (err)
-+ goto init_err;
-+ }
- break;
- default:
- goto err_phy;
-@@ -629,8 +681,6 @@ static void mtk_mac_config(struct phylin
- val &= ~SYSCFG0_GE_MODE(SYSCFG0_GE_MASK, mac->id);
- val |= SYSCFG0_GE_MODE(ge_mode, mac->id);
- regmap_write(eth->ethsys, ETHSYS_SYSCFG0, val);
--
-- mac->interface = state->interface;
- }
-
- /* SGMII */
-@@ -647,21 +697,40 @@ static void mtk_mac_config(struct phylin
-
- /* Save the syscfg0 value for mac_finish */
- mac->syscfg0 = val;
-- } else if (phylink_autoneg_inband(mode)) {
-+ } else if (state->interface != PHY_INTERFACE_MODE_USXGMII &&
-+ state->interface != PHY_INTERFACE_MODE_10GBASER &&
-+ state->interface != PHY_INTERFACE_MODE_5GBASER &&
-+ phylink_autoneg_inband(mode)) {
- dev_err(eth->dev,
-- "In-band mode not supported in non SGMII mode!\n");
-+ "In-band mode not supported in non-SerDes modes!\n");
- return;
- }
-
- /* Setup gmac */
-- if (mtk_is_netsys_v3_or_greater(eth) &&
-- mac->interface == PHY_INTERFACE_MODE_INTERNAL) {
-- mtk_w32(mac->hw, MTK_GDMA_XGDM_SEL, MTK_GDMA_EG_CTRL(mac->id));
-- mtk_w32(mac->hw, MAC_MCR_FORCE_LINK_DOWN, MTK_MAC_MCR(mac->id));
-+ if (mtk_is_netsys_v3_or_greater(eth)) {
-+ if (mtk_interface_mode_is_xgmii(state->interface)) {
-+ mtk_w32(mac->hw, MTK_GDMA_XGDM_SEL, MTK_GDMA_EG_CTRL(mac->id));
-+ mtk_w32(mac->hw, MAC_MCR_FORCE_LINK_DOWN, MTK_MAC_MCR(mac->id));
-+
-+ if (mac->id == MTK_GMAC1_ID)
-+ mtk_setup_bridge_switch(eth);
-+ } else {
-+ mtk_w32(eth, 0, MTK_GDMA_EG_CTRL(mac->id));
-
-- mtk_setup_bridge_switch(eth);
-+ /* FIXME: In current hardware design, we have to reset FE
-+ * when swtiching XGDM to GDM. Therefore, here trigger an SER
-+ * to let GDM go back to the initial state.
-+ */
-+ if ((mtk_interface_mode_is_xgmii(mac->interface) ||
-+ mac->interface == PHY_INTERFACE_MODE_NA) &&
-+ !mtk_check_gmac23_idle(mac) &&
-+ !test_bit(MTK_RESETTING, ð->state))
-+ schedule_work(ð->pending_work);
-+ }
- }
-
-+ mac->interface = state->interface;
-+
- return;
-
- err_phy:
-@@ -674,6 +743,18 @@ init_err:
- mac->id, phy_modes(state->interface), err);
- }
-
-+static int mtk_mac_prepare(struct phylink_config *config, unsigned int mode,
-+ phy_interface_t interface)
-+{
-+ struct mtk_mac *mac = container_of(config, struct mtk_mac,
-+ phylink_config);
-+
-+ if (mac->pextp && mac->interface != interface)
-+ phy_reset(mac->pextp);
-+
-+ return 0;
-+}
-+
- static int mtk_mac_finish(struct phylink_config *config, unsigned int mode,
- phy_interface_t interface)
- {
-@@ -682,6 +763,10 @@ static int mtk_mac_finish(struct phylink
- struct mtk_eth *eth = mac->hw;
- u32 mcr_cur, mcr_new;
-
-+ /* Setup PMA/PMD */
-+ if (mac->pextp)
-+ phy_set_mode_ext(mac->pextp, PHY_MODE_ETHERNET, interface);
-+
- /* Enable SGMII */
- if (interface == PHY_INTERFACE_MODE_SGMII ||
- phy_interface_mode_is_8023z(interface))
-@@ -706,10 +791,14 @@ static void mtk_mac_link_down(struct phy
- {
- struct mtk_mac *mac = container_of(config, struct mtk_mac,
- phylink_config);
-- u32 mcr = mtk_r32(mac->hw, MTK_MAC_MCR(mac->id));
-
-- mcr &= ~(MAC_MCR_TX_EN | MAC_MCR_RX_EN | MAC_MCR_FORCE_LINK);
-- mtk_w32(mac->hw, mcr, MTK_MAC_MCR(mac->id));
-+ if (!mtk_interface_mode_is_xgmii(interface)) {
-+ mtk_m32(mac->hw, MAC_MCR_TX_EN | MAC_MCR_RX_EN | MAC_MCR_FORCE_LINK, 0, MTK_MAC_MCR(mac->id));
-+ if (mtk_is_netsys_v3_or_greater(mac->hw))
-+ mtk_m32(mac->hw, MTK_XGMAC_FORCE_LINK(mac->id), 0, MTK_XGMAC_STS(mac->id));
-+ } else if (mtk_is_netsys_v3_or_greater(mac->hw) && mac->id != MTK_GMAC1_ID) {
-+ mtk_m32(mac->hw, XMAC_MCR_TRX_DISABLE, XMAC_MCR_TRX_DISABLE, MTK_XMAC_MCR(mac->id));
-+ }
- }
-
- static void mtk_set_queue_speed(struct mtk_eth *eth, unsigned int idx,
-@@ -781,13 +870,11 @@ static void mtk_set_queue_speed(struct m
- mtk_w32(eth, val, soc->reg_map->qdma.qtx_sch + ofs);
- }
-
--static void mtk_mac_link_up(struct phylink_config *config,
-- struct phy_device *phy,
-- unsigned int mode, phy_interface_t interface,
-- int speed, int duplex, bool tx_pause, bool rx_pause)
-+static void mtk_gdm_mac_link_up(struct mtk_mac *mac,
-+ struct phy_device *phy,
-+ unsigned int mode, phy_interface_t interface,
-+ int speed, int duplex, bool tx_pause, bool rx_pause)
- {
-- struct mtk_mac *mac = container_of(config, struct mtk_mac,
-- phylink_config);
- u32 mcr;
-
- mcr = mtk_r32(mac->hw, MTK_MAC_MCR(mac->id));
-@@ -831,9 +918,63 @@ static void mtk_mac_link_up(struct phyli
- mtk_w32(mac->hw, mcr, MTK_MAC_MCR(mac->id));
- }
-
-+static void mtk_xgdm_mac_link_up(struct mtk_mac *mac,
-+ struct phy_device *phy,
-+ unsigned int mode, phy_interface_t interface,
-+ int speed, int duplex, bool tx_pause, bool rx_pause)
-+{
-+ u32 mcr, force_link = 0;
-+
-+ if (mac->id == MTK_GMAC1_ID)
-+ return;
-+
-+ /* Eliminate the interference(before link-up) caused by PHY noise */
-+ mtk_m32(mac->hw, XMAC_LOGIC_RST, 0, MTK_XMAC_LOGIC_RST(mac->id));
-+ mdelay(20);
-+ mtk_m32(mac->hw, XMAC_GLB_CNTCLR, XMAC_GLB_CNTCLR, MTK_XMAC_CNT_CTRL(mac->id));
-+
-+ if (mac->interface == PHY_INTERFACE_MODE_INTERNAL || mac->id == MTK_GMAC3_ID)
-+ force_link = MTK_XGMAC_FORCE_LINK(mac->id);
-+
-+ mtk_m32(mac->hw, MTK_XGMAC_FORCE_LINK(mac->id), force_link, MTK_XGMAC_STS(mac->id));
-+
-+ mcr = mtk_r32(mac->hw, MTK_XMAC_MCR(mac->id));
-+ mcr &= ~(XMAC_MCR_FORCE_TX_FC | XMAC_MCR_FORCE_RX_FC | XMAC_MCR_TRX_DISABLE);
-+ /* Configure pause modes -
-+ * phylink will avoid these for half duplex
-+ */
-+ if (tx_pause)
-+ mcr |= XMAC_MCR_FORCE_TX_FC;
-+ if (rx_pause)
-+ mcr |= XMAC_MCR_FORCE_RX_FC;
-+
-+ mtk_w32(mac->hw, mcr, MTK_XMAC_MCR(mac->id));
-+}
-+
-+static void mtk_mac_link_up(struct phylink_config *config,
-+ struct phy_device *phy,
-+ unsigned int mode, phy_interface_t interface,
-+ int speed, int duplex, bool tx_pause, bool rx_pause)
-+{
-+ struct mtk_mac *mac = container_of(config, struct mtk_mac,
-+ phylink_config);
-+
-+ if (mtk_is_netsys_v3_or_greater(mac->hw) && mtk_interface_mode_is_xgmii(interface))
-+ mtk_xgdm_mac_link_up(mac, phy, mode, interface, speed, duplex,
-+ tx_pause, rx_pause);
-+ else
-+ mtk_gdm_mac_link_up(mac, phy, mode, interface, speed, duplex,
-+ tx_pause, rx_pause);
-+
-+ /* Repeat pextp setup to tune link */
-+ if (mac->pextp)
-+ phy_set_mode_ext(mac->pextp, PHY_MODE_ETHERNET, interface);
-+}
-+
- static const struct phylink_mac_ops mtk_phylink_ops = {
- .mac_select_pcs = mtk_mac_select_pcs,
- .mac_config = mtk_mac_config,
-+ .mac_prepare = mtk_mac_prepare,
- .mac_finish = mtk_mac_finish,
- .mac_link_down = mtk_mac_link_down,
- .mac_link_up = mtk_mac_link_up,
-@@ -3467,6 +3608,9 @@ static int mtk_open(struct net_device *d
-
- ppe_num = eth->soc->ppe_num;
-
-+ if (mac->pextp)
-+ phy_power_on(mac->pextp);
-+
- err = phylink_of_phy_connect(mac->phylink, mac->of_node, 0);
- if (err) {
- netdev_err(dev, "%s: could not attach PHY: %d\n", __func__,
-@@ -3617,6 +3761,9 @@ static int mtk_stop(struct net_device *d
- for (i = 0; i < ARRAY_SIZE(eth->ppe); i++)
- mtk_ppe_stop(eth->ppe[i]);
-
-+ if (mac->pextp)
-+ phy_power_off(mac->pextp);
-+
- return 0;
- }
-
-@@ -4703,6 +4850,7 @@ static const struct net_device_ops mtk_n
- static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np)
- {
- const __be32 *_id = of_get_property(np, "reg", NULL);
-+ struct device_node *pcs_np;
- phy_interface_t phy_mode;
- struct phylink *phylink;
- struct mtk_mac *mac;
-@@ -4741,16 +4889,41 @@ static int mtk_add_mac(struct mtk_eth *e
- mac->id = id;
- mac->hw = eth;
- mac->of_node = np;
-+ pcs_np = of_parse_phandle(mac->of_node, "pcs-handle", 0);
-+ if (pcs_np) {
-+ mac->sgmii_pcs = mtk_pcs_lynxi_get(eth->dev, pcs_np);
-+ if (IS_ERR(mac->sgmii_pcs)) {
-+ if (PTR_ERR(mac->sgmii_pcs) == -EPROBE_DEFER)
-+ return -EPROBE_DEFER;
-
-- err = of_get_ethdev_address(mac->of_node, eth->netdev[id]);
-- if (err == -EPROBE_DEFER)
-- return err;
-+ dev_err(eth->dev, "cannot select SGMII PCS, error %ld\n",
-+ PTR_ERR(mac->sgmii_pcs));
-+ return PTR_ERR(mac->sgmii_pcs);
-+ }
-+ }
-
-- if (err) {
-- /* If the mac address is invalid, use random mac address */
-- eth_hw_addr_random(eth->netdev[id]);
-- dev_err(eth->dev, "generated random MAC address %pM\n",
-- eth->netdev[id]->dev_addr);
-+ pcs_np = of_parse_phandle(mac->of_node, "pcs-handle", 1);
-+ if (pcs_np) {
-+ mac->usxgmii_pcs = mtk_usxgmii_pcs_get(eth->dev, pcs_np);
-+ if (IS_ERR(mac->usxgmii_pcs)) {
-+ if (PTR_ERR(mac->usxgmii_pcs) == -EPROBE_DEFER)
-+ return -EPROBE_DEFER;
-+
-+ dev_err(eth->dev, "cannot select USXGMII PCS, error %ld\n",
-+ PTR_ERR(mac->usxgmii_pcs));
-+ return PTR_ERR(mac->usxgmii_pcs);
-+ }
-+ }
-+
-+ if (mtk_is_netsys_v3_or_greater(eth) && (mac->sgmii_pcs || mac->usxgmii_pcs)) {
-+ mac->pextp = devm_of_phy_get(eth->dev, mac->of_node, NULL);
-+ if (IS_ERR(mac->pextp)) {
-+ if (PTR_ERR(mac->pextp) != -EPROBE_DEFER)
-+ dev_err(eth->dev, "cannot get PHY, error %ld\n",
-+ PTR_ERR(mac->pextp));
-+
-+ return PTR_ERR(mac->pextp);
-+ }
- }
-
- memset(mac->hwlro_ip, 0, sizeof(mac->hwlro_ip));
-@@ -4833,8 +5006,21 @@ static int mtk_add_mac(struct mtk_eth *e
- phy_interface_zero(mac->phylink_config.supported_interfaces);
- __set_bit(PHY_INTERFACE_MODE_INTERNAL,
- mac->phylink_config.supported_interfaces);
-+ } else if (MTK_HAS_CAPS(mac->hw->soc->caps, MTK_USXGMII)) {
-+ mac->phylink_config.mac_capabilities |= MAC_5000FD | MAC_10000FD;
-+ __set_bit(PHY_INTERFACE_MODE_5GBASER,
-+ mac->phylink_config.supported_interfaces);
-+ __set_bit(PHY_INTERFACE_MODE_10GBASER,
-+ mac->phylink_config.supported_interfaces);
-+ __set_bit(PHY_INTERFACE_MODE_USXGMII,
-+ mac->phylink_config.supported_interfaces);
- }
-
-+ if (MTK_HAS_CAPS(mac->hw->soc->caps, MTK_2P5GPHY) &&
-+ id == MTK_GMAC2_ID)
-+ __set_bit(PHY_INTERFACE_MODE_INTERNAL,
-+ mac->phylink_config.supported_interfaces);
-+
- phylink = phylink_create(&mac->phylink_config,
- of_fwnode_handle(mac->of_node),
- phy_mode, &mtk_phylink_ops);
-@@ -4885,6 +5071,26 @@ free_netdev:
- return err;
- }
-
-+static int mtk_mac_assign_address(struct mtk_eth *eth, int i, bool test_defer_only)
-+{
-+ int err = of_get_ethdev_address(eth->mac[i]->of_node, eth->netdev[i]);
-+
-+ if (err == -EPROBE_DEFER)
-+ return err;
-+
-+ if (test_defer_only)
-+ return 0;
-+
-+ if (err) {
-+ /* If the mac address is invalid, use random mac address */
-+ eth_hw_addr_random(eth->netdev[i]);
-+ dev_err(eth->dev, "generated random MAC address %pM\n",
-+ eth->netdev[i]);
-+ }
-+
-+ return 0;
-+}
-+
- void mtk_eth_set_dma_device(struct mtk_eth *eth, struct device *dma_dev)
- {
- struct net_device *dev, *tmp;
-@@ -5031,7 +5237,8 @@ static int mtk_probe(struct platform_dev
- regmap_write(cci, 0, 3);
- }
-
-- if (MTK_HAS_CAPS(eth->soc->caps, MTK_SGMII)) {
-+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_SGMII) &&
-+ !mtk_is_netsys_v3_or_greater(eth)) {
- err = mtk_sgmii_init(eth);
-
- if (err)
-@@ -5142,6 +5349,24 @@ static int mtk_probe(struct platform_dev
- }
- }
-
-+ for (i = 0; i < MTK_MAX_DEVS; i++) {
-+ if (!eth->netdev[i])
-+ continue;
-+
-+ err = mtk_mac_assign_address(eth, i, true);
-+ if (err)
-+ goto err_deinit_hw;
-+ }
-+
-+ for (i = 0; i < MTK_MAX_DEVS; i++) {
-+ if (!eth->netdev[i])
-+ continue;
-+
-+ err = mtk_mac_assign_address(eth, i, false);
-+ if (err)
-+ goto err_deinit_hw;
-+ }
-+
- if (MTK_HAS_CAPS(eth->soc->caps, MTK_SHARED_INT)) {
- err = devm_request_irq(eth->dev, eth->irq[0],
- mtk_handle_irq, 0,
-@@ -5245,6 +5470,11 @@ static int mtk_remove(struct platform_de
- mtk_stop(eth->netdev[i]);
- mac = netdev_priv(eth->netdev[i]);
- phylink_disconnect_phy(mac->phylink);
-+ if (mac->sgmii_pcs)
-+ mtk_pcs_lynxi_put(mac->sgmii_pcs);
-+
-+ if (mac->usxgmii_pcs)
-+ mtk_usxgmii_pcs_put(mac->usxgmii_pcs);
- }
-
- mtk_wed_exit();
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-@@ -15,6 +15,7 @@
- #include <linux/u64_stats_sync.h>
- #include <linux/refcount.h>
- #include <linux/phylink.h>
-+#include <linux/reset.h>
- #include <linux/rhashtable.h>
- #include <linux/dim.h>
- #include <linux/bitfield.h>
-@@ -527,6 +528,21 @@
- #define INTF_MODE_RGMII_1000 (TRGMII_MODE | TRGMII_CENTRAL_ALIGNED)
- #define INTF_MODE_RGMII_10_100 0
-
-+/* XFI Mac control registers */
-+#define MTK_XMAC_BASE(x) (0x12000 + (((x) - 1) * 0x1000))
-+#define MTK_XMAC_MCR(x) (MTK_XMAC_BASE(x))
-+#define XMAC_MCR_TRX_DISABLE 0xf
-+#define XMAC_MCR_FORCE_TX_FC BIT(5)
-+#define XMAC_MCR_FORCE_RX_FC BIT(4)
-+
-+/* XFI Mac logic reset registers */
-+#define MTK_XMAC_LOGIC_RST(x) (MTK_XMAC_BASE(x) + 0x10)
-+#define XMAC_LOGIC_RST BIT(0)
-+
-+/* XFI Mac count global control */
-+#define MTK_XMAC_CNT_CTRL(x) (MTK_XMAC_BASE(x) + 0x100)
-+#define XMAC_GLB_CNTCLR BIT(0)
-+
- /* GPIO port control registers for GMAC 2*/
- #define GPIO_OD33_CTRL8 0x4c0
- #define GPIO_BIAS_CTRL 0xed0
-@@ -552,6 +568,7 @@
- #define SYSCFG0_SGMII_GMAC2 ((3 << 8) & SYSCFG0_SGMII_MASK)
- #define SYSCFG0_SGMII_GMAC1_V2 BIT(9)
- #define SYSCFG0_SGMII_GMAC2_V2 BIT(8)
-+#define SYSCFG0_SGMII_GMAC3_V2 BIT(7)
-
-
- /* ethernet subsystem clock register */
-@@ -590,6 +607,11 @@
- #define GEPHY_MAC_SEL BIT(1)
-
- /* Top misc registers */
-+#define TOP_MISC_NETSYS_PCS_MUX 0x84
-+#define NETSYS_PCS_MUX_MASK GENMASK(1, 0)
-+#define MUX_G2_USXGMII_SEL BIT(1)
-+#define MUX_HSGMII1_G1_SEL BIT(0)
-+
- #define USB_PHY_SWITCH_REG 0x218
- #define QPHY_SEL_MASK GENMASK(1, 0)
- #define SGMII_QPHY_SEL 0x2
-@@ -614,6 +636,8 @@
- #define MT7628_SDM_RBCNT (MT7628_SDM_OFFSET + 0x10c)
- #define MT7628_SDM_CS_ERR (MT7628_SDM_OFFSET + 0x110)
-
-+/* Debug Purpose Register */
-+#define MTK_PSE_FQFC_CFG 0x100
- #define MTK_FE_CDM1_FSM 0x220
- #define MTK_FE_CDM2_FSM 0x224
- #define MTK_FE_CDM3_FSM 0x238
-@@ -622,6 +646,11 @@
- #define MTK_FE_CDM6_FSM 0x328
- #define MTK_FE_GDM1_FSM 0x228
- #define MTK_FE_GDM2_FSM 0x22C
-+#define MTK_FE_GDM3_FSM 0x23C
-+#define MTK_FE_PSE_FREE 0x240
-+#define MTK_FE_DROP_FQ 0x244
-+#define MTK_FE_DROP_FC 0x248
-+#define MTK_FE_DROP_PPE 0x24C
-
- #define MTK_MAC_FSM(x) (0x1010C + ((x) * 0x100))
-
-@@ -738,12 +767,8 @@ enum mtk_clks_map {
- MTK_CLK_ETHWARP_WOCPU2,
- MTK_CLK_ETHWARP_WOCPU1,
- MTK_CLK_ETHWARP_WOCPU0,
-- MTK_CLK_TOP_USXGMII_SBUS_0_SEL,
-- MTK_CLK_TOP_USXGMII_SBUS_1_SEL,
- MTK_CLK_TOP_SGM_0_SEL,
- MTK_CLK_TOP_SGM_1_SEL,
-- MTK_CLK_TOP_XFI_PHY_0_XTAL_SEL,
-- MTK_CLK_TOP_XFI_PHY_1_XTAL_SEL,
- MTK_CLK_TOP_ETH_GMII_SEL,
- MTK_CLK_TOP_ETH_REFCK_50M_SEL,
- MTK_CLK_TOP_ETH_SYS_200M_SEL,
-@@ -814,19 +839,9 @@ enum mtk_clks_map {
- BIT_ULL(MTK_CLK_GP3) | BIT_ULL(MTK_CLK_XGP1) | \
- BIT_ULL(MTK_CLK_XGP2) | BIT_ULL(MTK_CLK_XGP3) | \
- BIT_ULL(MTK_CLK_CRYPTO) | \
-- BIT_ULL(MTK_CLK_SGMII_TX_250M) | \
-- BIT_ULL(MTK_CLK_SGMII_RX_250M) | \
-- BIT_ULL(MTK_CLK_SGMII2_TX_250M) | \
-- BIT_ULL(MTK_CLK_SGMII2_RX_250M) | \
- BIT_ULL(MTK_CLK_ETHWARP_WOCPU2) | \
- BIT_ULL(MTK_CLK_ETHWARP_WOCPU1) | \
- BIT_ULL(MTK_CLK_ETHWARP_WOCPU0) | \
-- BIT_ULL(MTK_CLK_TOP_USXGMII_SBUS_0_SEL) | \
-- BIT_ULL(MTK_CLK_TOP_USXGMII_SBUS_1_SEL) | \
-- BIT_ULL(MTK_CLK_TOP_SGM_0_SEL) | \
-- BIT_ULL(MTK_CLK_TOP_SGM_1_SEL) | \
-- BIT_ULL(MTK_CLK_TOP_XFI_PHY_0_XTAL_SEL) | \
-- BIT_ULL(MTK_CLK_TOP_XFI_PHY_1_XTAL_SEL) | \
- BIT_ULL(MTK_CLK_TOP_ETH_GMII_SEL) | \
- BIT_ULL(MTK_CLK_TOP_ETH_REFCK_50M_SEL) | \
- BIT_ULL(MTK_CLK_TOP_ETH_SYS_200M_SEL) | \
-@@ -959,6 +974,8 @@ enum mkt_eth_capabilities {
- MTK_RGMII_BIT = 0,
- MTK_TRGMII_BIT,
- MTK_SGMII_BIT,
-+ MTK_USXGMII_BIT,
-+ MTK_2P5GPHY_BIT,
- MTK_ESW_BIT,
- MTK_GEPHY_BIT,
- MTK_MUX_BIT,
-@@ -979,8 +996,11 @@ enum mkt_eth_capabilities {
- MTK_ETH_MUX_GDM1_TO_GMAC1_ESW_BIT,
- MTK_ETH_MUX_GMAC2_GMAC0_TO_GEPHY_BIT,
- MTK_ETH_MUX_U3_GMAC2_TO_QPHY_BIT,
-+ MTK_ETH_MUX_GMAC2_TO_2P5GPHY_BIT,
- MTK_ETH_MUX_GMAC1_GMAC2_TO_SGMII_RGMII_BIT,
- MTK_ETH_MUX_GMAC12_TO_GEPHY_SGMII_BIT,
-+ MTK_ETH_MUX_GMAC123_TO_GEPHY_SGMII_BIT,
-+ MTK_ETH_MUX_GMAC123_TO_USXGMII_BIT,
-
- /* PATH BITS */
- MTK_ETH_PATH_GMAC1_RGMII_BIT,
-@@ -988,14 +1008,21 @@ enum mkt_eth_capabilities {
- MTK_ETH_PATH_GMAC1_SGMII_BIT,
- MTK_ETH_PATH_GMAC2_RGMII_BIT,
- MTK_ETH_PATH_GMAC2_SGMII_BIT,
-+ MTK_ETH_PATH_GMAC2_2P5GPHY_BIT,
- MTK_ETH_PATH_GMAC2_GEPHY_BIT,
-+ MTK_ETH_PATH_GMAC3_SGMII_BIT,
- MTK_ETH_PATH_GDM1_ESW_BIT,
-+ MTK_ETH_PATH_GMAC1_USXGMII_BIT,
-+ MTK_ETH_PATH_GMAC2_USXGMII_BIT,
-+ MTK_ETH_PATH_GMAC3_USXGMII_BIT,
- };
-
- /* Supported hardware group on SoCs */
- #define MTK_RGMII BIT_ULL(MTK_RGMII_BIT)
- #define MTK_TRGMII BIT_ULL(MTK_TRGMII_BIT)
- #define MTK_SGMII BIT_ULL(MTK_SGMII_BIT)
-+#define MTK_USXGMII BIT_ULL(MTK_USXGMII_BIT)
-+#define MTK_2P5GPHY BIT_ULL(MTK_2P5GPHY_BIT)
- #define MTK_ESW BIT_ULL(MTK_ESW_BIT)
- #define MTK_GEPHY BIT_ULL(MTK_GEPHY_BIT)
- #define MTK_MUX BIT_ULL(MTK_MUX_BIT)
-@@ -1018,10 +1045,16 @@ enum mkt_eth_capabilities {
- BIT_ULL(MTK_ETH_MUX_GMAC2_GMAC0_TO_GEPHY_BIT)
- #define MTK_ETH_MUX_U3_GMAC2_TO_QPHY \
- BIT_ULL(MTK_ETH_MUX_U3_GMAC2_TO_QPHY_BIT)
-+#define MTK_ETH_MUX_GMAC2_TO_2P5GPHY \
-+ BIT_ULL(MTK_ETH_MUX_GMAC2_TO_2P5GPHY_BIT)
- #define MTK_ETH_MUX_GMAC1_GMAC2_TO_SGMII_RGMII \
- BIT_ULL(MTK_ETH_MUX_GMAC1_GMAC2_TO_SGMII_RGMII_BIT)
- #define MTK_ETH_MUX_GMAC12_TO_GEPHY_SGMII \
- BIT_ULL(MTK_ETH_MUX_GMAC12_TO_GEPHY_SGMII_BIT)
-+#define MTK_ETH_MUX_GMAC123_TO_GEPHY_SGMII \
-+ BIT_ULL(MTK_ETH_MUX_GMAC123_TO_GEPHY_SGMII_BIT)
-+#define MTK_ETH_MUX_GMAC123_TO_USXGMII \
-+ BIT_ULL(MTK_ETH_MUX_GMAC123_TO_USXGMII_BIT)
-
- /* Supported path present on SoCs */
- #define MTK_ETH_PATH_GMAC1_RGMII BIT_ULL(MTK_ETH_PATH_GMAC1_RGMII_BIT)
-@@ -1029,8 +1062,13 @@ enum mkt_eth_capabilities {
- #define MTK_ETH_PATH_GMAC1_SGMII BIT_ULL(MTK_ETH_PATH_GMAC1_SGMII_BIT)
- #define MTK_ETH_PATH_GMAC2_RGMII BIT_ULL(MTK_ETH_PATH_GMAC2_RGMII_BIT)
- #define MTK_ETH_PATH_GMAC2_SGMII BIT_ULL(MTK_ETH_PATH_GMAC2_SGMII_BIT)
-+#define MTK_ETH_PATH_GMAC2_2P5GPHY BIT_ULL(MTK_ETH_PATH_GMAC2_2P5GPHY_BIT)
- #define MTK_ETH_PATH_GMAC2_GEPHY BIT_ULL(MTK_ETH_PATH_GMAC2_GEPHY_BIT)
-+#define MTK_ETH_PATH_GMAC3_SGMII BIT_ULL(MTK_ETH_PATH_GMAC3_SGMII_BIT)
- #define MTK_ETH_PATH_GDM1_ESW BIT_ULL(MTK_ETH_PATH_GDM1_ESW_BIT)
-+#define MTK_ETH_PATH_GMAC1_USXGMII BIT_ULL(MTK_ETH_PATH_GMAC1_USXGMII_BIT)
-+#define MTK_ETH_PATH_GMAC2_USXGMII BIT_ULL(MTK_ETH_PATH_GMAC2_USXGMII_BIT)
-+#define MTK_ETH_PATH_GMAC3_USXGMII BIT_ULL(MTK_ETH_PATH_GMAC3_USXGMII_BIT)
-
- #define MTK_GMAC1_RGMII (MTK_ETH_PATH_GMAC1_RGMII | MTK_RGMII)
- #define MTK_GMAC1_TRGMII (MTK_ETH_PATH_GMAC1_TRGMII | MTK_TRGMII)
-@@ -1038,7 +1076,12 @@ enum mkt_eth_capabilities {
- #define MTK_GMAC2_RGMII (MTK_ETH_PATH_GMAC2_RGMII | MTK_RGMII)
- #define MTK_GMAC2_SGMII (MTK_ETH_PATH_GMAC2_SGMII | MTK_SGMII)
- #define MTK_GMAC2_GEPHY (MTK_ETH_PATH_GMAC2_GEPHY | MTK_GEPHY)
-+#define MTK_GMAC2_2P5GPHY (MTK_ETH_PATH_GMAC2_2P5GPHY | MTK_2P5GPHY)
-+#define MTK_GMAC3_SGMII (MTK_ETH_PATH_GMAC3_SGMII | MTK_SGMII)
- #define MTK_GDM1_ESW (MTK_ETH_PATH_GDM1_ESW | MTK_ESW)
-+#define MTK_GMAC1_USXGMII (MTK_ETH_PATH_GMAC1_USXGMII | MTK_USXGMII)
-+#define MTK_GMAC2_USXGMII (MTK_ETH_PATH_GMAC2_USXGMII | MTK_USXGMII)
-+#define MTK_GMAC3_USXGMII (MTK_ETH_PATH_GMAC3_USXGMII | MTK_USXGMII)
-
- /* MUXes present on SoCs */
- /* 0: GDM1 -> GMAC1, 1: GDM1 -> ESW */
-@@ -1057,10 +1100,20 @@ enum mkt_eth_capabilities {
- (MTK_ETH_MUX_GMAC1_GMAC2_TO_SGMII_RGMII | MTK_MUX | \
- MTK_SHARED_SGMII)
-
-+/* 2: GMAC2 -> XGMII */
-+#define MTK_MUX_GMAC2_TO_2P5GPHY \
-+ (MTK_ETH_MUX_GMAC2_TO_2P5GPHY | MTK_MUX | MTK_INFRA)
-+
- /* 0: GMACx -> GEPHY, 1: GMACx -> SGMII where x is 1 or 2 */
- #define MTK_MUX_GMAC12_TO_GEPHY_SGMII \
- (MTK_ETH_MUX_GMAC12_TO_GEPHY_SGMII | MTK_MUX)
-
-+#define MTK_MUX_GMAC123_TO_GEPHY_SGMII \
-+ (MTK_ETH_MUX_GMAC123_TO_GEPHY_SGMII | MTK_MUX)
-+
-+#define MTK_MUX_GMAC123_TO_USXGMII \
-+ (MTK_ETH_MUX_GMAC123_TO_USXGMII | MTK_MUX | MTK_INFRA)
-+
- #define MTK_HAS_CAPS(caps, _x) (((caps) & (_x)) == (_x))
-
- #define MT7621_CAPS (MTK_GMAC1_RGMII | MTK_GMAC1_TRGMII | \
-@@ -1092,8 +1145,12 @@ enum mkt_eth_capabilities {
- MTK_MUX_GMAC12_TO_GEPHY_SGMII | MTK_QDMA | \
- MTK_RSTCTRL_PPE1 | MTK_SRAM)
-
--#define MT7988_CAPS (MTK_36BIT_DMA | MTK_GDM1_ESW | MTK_QDMA | \
-- MTK_RSTCTRL_PPE1 | MTK_RSTCTRL_PPE2 | MTK_SRAM)
-+#define MT7988_CAPS (MTK_36BIT_DMA | MTK_GDM1_ESW | MTK_GMAC1_SGMII | \
-+ MTK_GMAC2_2P5GPHY | MTK_GMAC2_SGMII | MTK_GMAC2_USXGMII | \
-+ MTK_GMAC3_SGMII | MTK_GMAC3_USXGMII | \
-+ MTK_MUX_GMAC123_TO_GEPHY_SGMII | \
-+ MTK_MUX_GMAC123_TO_USXGMII | MTK_MUX_GMAC2_TO_2P5GPHY | \
-+ MTK_QDMA | MTK_RSTCTRL_PPE1 | MTK_RSTCTRL_PPE2 | MTK_SRAM)
-
- struct mtk_tx_dma_desc_info {
- dma_addr_t addr;
-@@ -1340,6 +1397,9 @@ struct mtk_mac {
- struct device_node *of_node;
- struct phylink *phylink;
- struct phylink_config phylink_config;
-+ struct phylink_pcs *sgmii_pcs;
-+ struct phylink_pcs *usxgmii_pcs;
-+ struct phy *pextp;
- struct mtk_eth *hw;
- struct mtk_hw_stats *hw_stats;
- __be32 hwlro_ip[MTK_MAX_LRO_IP_CNT];
-@@ -1463,6 +1523,19 @@ static inline u32 mtk_get_ib2_multicast_
- return MTK_FOE_IB2_MULTICAST;
- }
-
-+static inline bool mtk_interface_mode_is_xgmii(phy_interface_t interface)
-+{
-+ switch (interface) {
-+ case PHY_INTERFACE_MODE_INTERNAL:
-+ case PHY_INTERFACE_MODE_USXGMII:
-+ case PHY_INTERFACE_MODE_10GBASER:
-+ case PHY_INTERFACE_MODE_5GBASER:
-+ return true;
-+ default:
-+ return false;
-+ }
-+}
-+
- /* read the hardware status register */
- void mtk_stats_update_mac(struct mtk_mac *mac);
-
-@@ -1471,8 +1544,10 @@ u32 mtk_r32(struct mtk_eth *eth, unsigne
- u32 mtk_m32(struct mtk_eth *eth, u32 mask, u32 set, unsigned int reg);
-
- int mtk_gmac_sgmii_path_setup(struct mtk_eth *eth, int mac_id);
-+int mtk_gmac_2p5gphy_path_setup(struct mtk_eth *eth, int mac_id);
- int mtk_gmac_gephy_path_setup(struct mtk_eth *eth, int mac_id);
- int mtk_gmac_rgmii_path_setup(struct mtk_eth *eth, int mac_id);
-+int mtk_gmac_usxgmii_path_setup(struct mtk_eth *eth, int mac_id);
-
- int mtk_eth_offload_init(struct mtk_eth *eth, u8 id);
- int mtk_eth_setup_tc(struct net_device *dev, enum tc_setup_type type,
+++ /dev/null
-Subject: [PATCH net-next 3/4] net: ethernet: mtk_eth_soc: reduce rx ring size for older chipsets
-Date: Tue, 15 Oct 2024 13:09:37 +0200
-
-Commit c57e55819443 ("net: ethernet: mtk_eth_soc: handle dma buffer
-size soc specific") resolved some tx timeout issues by bumping FQ and
-tx ring sizes from 512 to 2048 entries (the value used in the MediaTek
-SDK), however it also changed the rx ring size for all chipsets in the
-same way.
-
-Based on a few tests, it seems that a symmetric rx/tx ring size of 2048
-really only makes sense on MT7988, which is capable of 10G ethernet links.
-
-Older chipsets are typically deployed in systems that are more memory
-constrained and don't actually need the larger rings to handle received
-packets.
-
-In order to reduce wasted memory set the ring size based on the SoC to
-the following values:
-- 2048 on MT7988
-- 1024 on MT7986
-- 512 (previous value) on everything else, except:
-- 256 on RT5350 (the oldest supported chipset)
-
-Fixes: c57e55819443 ("net: ethernet: mtk_eth_soc: handle dma buffer size soc specific")
----
- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 16 ++++++++--------
- 1 file changed, 8 insertions(+), 8 deletions(-)
-
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -5509,7 +5509,7 @@ static const struct mtk_soc_data mt2701_
- DESC_SIZE(struct mtk_rx_dma),
- .irq_done_mask = MTK_RX_DONE_INT,
- .dma_l4_valid = RX_DMA_L4_VALID,
-- .dma_size = MTK_DMA_SIZE(2K),
-+ .dma_size = MTK_DMA_SIZE(512),
- .dma_max_len = MTK_TX_DMA_BUF_LEN,
- .dma_len_offset = 16,
- },
-@@ -5537,7 +5537,7 @@ static const struct mtk_soc_data mt7621_
- DESC_SIZE(struct mtk_rx_dma),
- .irq_done_mask = MTK_RX_DONE_INT,
- .dma_l4_valid = RX_DMA_L4_VALID,
-- .dma_size = MTK_DMA_SIZE(2K),
-+ .dma_size = MTK_DMA_SIZE(512),
- .dma_max_len = MTK_TX_DMA_BUF_LEN,
- .dma_len_offset = 16,
- },
-@@ -5567,7 +5567,7 @@ static const struct mtk_soc_data mt7622_
- DESC_SIZE(struct mtk_rx_dma),
- .irq_done_mask = MTK_RX_DONE_INT,
- .dma_l4_valid = RX_DMA_L4_VALID,
-- .dma_size = MTK_DMA_SIZE(2K),
-+ .dma_size = MTK_DMA_SIZE(512),
- .dma_max_len = MTK_TX_DMA_BUF_LEN,
- .dma_len_offset = 16,
- },
-@@ -5596,7 +5596,7 @@ static const struct mtk_soc_data mt7623_
- DESC_SIZE(struct mtk_rx_dma),
- .irq_done_mask = MTK_RX_DONE_INT,
- .dma_l4_valid = RX_DMA_L4_VALID,
-- .dma_size = MTK_DMA_SIZE(2K),
-+ .dma_size = MTK_DMA_SIZE(512),
- .dma_max_len = MTK_TX_DMA_BUF_LEN,
- .dma_len_offset = 16,
- },
-@@ -5622,7 +5622,7 @@ static const struct mtk_soc_data mt7629_
- DESC_SIZE(struct mtk_rx_dma),
- .irq_done_mask = MTK_RX_DONE_INT,
- .dma_l4_valid = RX_DMA_L4_VALID,
-- .dma_size = MTK_DMA_SIZE(2K),
-+ .dma_size = MTK_DMA_SIZE(512),
- .dma_max_len = MTK_TX_DMA_BUF_LEN,
- .dma_len_offset = 16,
- },
-@@ -5654,7 +5654,7 @@ static const struct mtk_soc_data mt7981_
- .dma_l4_valid = RX_DMA_L4_VALID_V2,
- .dma_max_len = MTK_TX_DMA_BUF_LEN,
- .dma_len_offset = 16,
-- .dma_size = MTK_DMA_SIZE(2K),
-+ .dma_size = MTK_DMA_SIZE(512),
- },
- };
-
-@@ -5684,7 +5684,7 @@ static const struct mtk_soc_data mt7986_
- .dma_l4_valid = RX_DMA_L4_VALID_V2,
- .dma_max_len = MTK_TX_DMA_BUF_LEN,
- .dma_len_offset = 16,
-- .dma_size = MTK_DMA_SIZE(2K),
-+ .dma_size = MTK_DMA_SIZE(1K),
- },
- };
-
-@@ -5737,7 +5737,7 @@ static const struct mtk_soc_data rt5350_
- .dma_l4_valid = RX_DMA_L4_VALID_PDMA,
- .dma_max_len = MTK_TX_DMA_BUF_LEN,
- .dma_len_offset = 16,
-- .dma_size = MTK_DMA_SIZE(2K),
-+ .dma_size = MTK_DMA_SIZE(256),
- },
- };
-
+++ /dev/null
-Date: Wed, 22 Jan 2025 06:48:45 +0100
-Subject: [PATCH] net: ethernet: mtk_eth_soc: do not enable page pool stats by
- default
-
-There is no reason for it to be enabled by default.
-Align mtk_eth_soc driver to mt76 driver.
-
-This option incurs additional CPU cost in allocation and recycle paths
-and additional memory cost to store the statistics.
-
----
-
---- a/drivers/net/ethernet/mediatek/Kconfig
-+++ b/drivers/net/ethernet/mediatek/Kconfig
-@@ -18,7 +18,6 @@ config NET_MEDIATEK_SOC
- select PHYLINK
- select DIMLIB
- select PAGE_POOL
-- select PAGE_POOL_STATS
- select PCS_MTK_LYNXI
- select REGMAP_MMIO
- help
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -4618,6 +4618,7 @@ static int mtk_get_sset_count(struct net
-
- static void mtk_ethtool_pp_stats(struct mtk_eth *eth, u64 *data)
- {
-+#ifdef CONFIG_PAGE_POOL_STATS
- struct page_pool_stats stats = {};
- int i;
-
-@@ -4630,6 +4631,7 @@ static void mtk_ethtool_pp_stats(struct
- page_pool_get_stats(ring->page_pool, &stats);
- }
- page_pool_ethtool_stats_get(data, &stats);
-+#endif
- }
-
- static void mtk_get_ethtool_stats(struct net_device *dev,
+++ /dev/null
-From patchwork Thu Feb 1 21:52:20 2024
-Content-Type: text/plain; charset="utf-8"
-MIME-Version: 1.0
-Content-Transfer-Encoding: 7bit
-X-Patchwork-Id: 13541842
-Date: Thu, 1 Feb 2024 21:52:20 +0000
-Subject: [PATCH 1/2] dt-bindings: phy: mediatek,xfi-tphy: add new bindings
-Message-ID:
- <702afb0c1246d95c90b22e57105304028bdd3083.1706823233.git.daniel@makrotopia.org>
-MIME-Version: 1.0
-Content-Disposition: inline
-List-Id: Linux Phy Mailing list <linux-phy.lists.infradead.org>
-
-Add bindings for the MediaTek XFI T-PHY Ethernet SerDes PHY found in the
-MediaTek MT7988 SoC which can operate at various interfaces modes:
-
-via USXGMII PCS:
- * USXGMII
- * 10GBase-R
- * 5GBase-R
-
-via LynxI SGMII PCS:
- * 2500Base-X
- * 1000Base-X
- * Cisco SGMII (MAC side)
-
----
- .../bindings/phy/mediatek,xfi-tphy.yaml | 80 +++++++++++++++++++
- 1 file changed, 80 insertions(+)
- create mode 100644 Documentation/devicetree/bindings/phy/mediatek,xfi-tphy.yaml
-
---- /dev/null
-+++ b/Documentation/devicetree/bindings/phy/mediatek,xfi-tphy.yaml
-@@ -0,0 +1,80 @@
-+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
-+%YAML 1.2
-+---
-+$id: http://devicetree.org/schemas/phy/mediatek,xfi-tphy.yaml#
-+$schema: http://devicetree.org/meta-schemas/core.yaml#
-+
-+title: MediaTek XFI T-PHY
-+
-+maintainers:
-+
-+description:
-+ The MediaTek XFI SerDes T-PHY provides the physical SerDes lanes
-+ used by the (10G/5G) USXGMII PCS and (1G/2.5G) LynxI PCS found in
-+ MediaTek's 10G-capabale SoCs.
-+
-+properties:
-+ $nodename:
-+ pattern: "^phy@[0-9a-f]+$"
-+
-+ compatible:
-+ const: mediatek,mt7988-xfi-tphy
-+
-+ reg:
-+ maxItems: 1
-+
-+ clocks:
-+ items:
-+ - description: XFI PHY clock
-+ - description: XFI register clock
-+
-+ clock-names:
-+ items:
-+ - const: xfipll
-+ - const: topxtal
-+
-+ resets:
-+ items:
-+ - description: PEXTP reset
-+
-+ mediatek,usxgmii-performance-errata:
-+ $ref: /schemas/types.yaml#/definitions/flag
-+ description:
-+ One instance of the T-PHY on MT7988 suffers from a performance
-+ problem in 10GBase-R mode which needs a work-around in the driver.
-+ The work-around is enabled using this flag.
-+
-+ "#phy-cells":
-+ const: 0
-+
-+required:
-+ - compatible
-+ - reg
-+ - clocks
-+ - clock-names
-+ - resets
-+ - "#phy-cells"
-+
-+additionalProperties: false
-+
-+examples:
-+ - |
-+ #include <dt-bindings/clock/mediatek,mt7988-clk.h>
-+ soc {
-+ #address-cells = <2>;
-+ #size-cells = <2>;
-+
-+ phy@11f20000 {
-+ compatible = "mediatek,mt7988-xfi-tphy";
-+ reg = <0 0x11f20000 0 0x10000>;
-+ clocks = <&xfi_pll CLK_XFIPLL_PLL_EN>,
-+ <&topckgen CLK_TOP_XFI_PHY_0_XTAL_SEL>;
-+ clock-names = "xfipll", "topxtal";
-+ resets = <&watchdog 14>;
-+ mediatek,usxgmii-performance-errata;
-+ #phy-cells = <0>;
-+ };
-+ };
-+
-+...
+++ /dev/null
-From 4b1a2716299c0e96a698044aebf3f80513509ae7 Mon Sep 17 00:00:00 2001
-Date: Tue, 12 Dec 2023 03:47:18 +0000
-Subject: [PATCH 3/5] net: pcs: pcs-mtk-lynxi: add platform driver for MT7988
-
-Introduce a proper platform MFD driver for the LynxI (H)SGMII PCS which
-is going to initially be used for the MT7988 SoC.
-
----
- drivers/net/pcs/pcs-mtk-lynxi.c | 227 ++++++++++++++++++++++++++++--
- include/linux/pcs/pcs-mtk-lynxi.h | 11 ++
- 2 files changed, 227 insertions(+), 11 deletions(-)
-
---- a/drivers/net/pcs/pcs-mtk-lynxi.c
-+++ b/drivers/net/pcs/pcs-mtk-lynxi.c
-@@ -1,6 +1,6 @@
- // SPDX-License-Identifier: GPL-2.0
- // Copyright (c) 2018-2019 MediaTek Inc.
--/* A library for MediaTek SGMII circuit
-+/* A library and platform driver for the MediaTek LynxI SGMII circuit
- *
-@@ -8,11 +8,17 @@
- *
- */
-
-+#include <linux/clk.h>
- #include <linux/mdio.h>
-+#include <linux/mfd/syscon.h>
-+#include <linux/mutex.h>
- #include <linux/of.h>
-+#include <linux/of_platform.h>
- #include <linux/pcs/pcs-mtk-lynxi.h>
- #include <linux/phylink.h>
-+#include <linux/platform_device.h>
- #include <linux/regmap.h>
-+#include <linux/reset.h>
-
- /* SGMII subsystem config registers */
- /* BMCR (low 16) BMSR (high 16) */
-@@ -65,6 +71,8 @@
- #define SGMII_PN_SWAP_MASK GENMASK(1, 0)
- #define SGMII_PN_SWAP_TX_RX (BIT(0) | BIT(1))
-
-+#define MTK_NETSYS_V3_AMA_RGC3 0x128
-+
- /* struct mtk_pcs_lynxi - This structure holds each sgmii regmap andassociated
- * data
- * @regmap: The register map pointing at the range used to setup
-@@ -74,15 +82,29 @@
- * @interface: Currently configured interface mode
- * @pcs: Phylink PCS structure
- * @flags: Flags indicating hardware properties
-+ * @rstc: Reset controller
-+ * @sgmii_sel: SGMII Register Clock
-+ * @sgmii_rx: SGMII RX Clock
-+ * @sgmii_tx: SGMII TX Clock
-+ * @node: List node
- */
- struct mtk_pcs_lynxi {
- struct regmap *regmap;
-+ struct device *dev;
- u32 ana_rgc3;
- phy_interface_t interface;
- struct phylink_pcs pcs;
- u32 flags;
-+ struct reset_control *rstc;
-+ struct clk *sgmii_sel;
-+ struct clk *sgmii_rx;
-+ struct clk *sgmii_tx;
-+ struct list_head node;
- };
-
-+static LIST_HEAD(mtk_pcs_lynxi_instances);
-+static DEFINE_MUTEX(instance_mutex);
-+
- static struct mtk_pcs_lynxi *pcs_to_mtk_pcs_lynxi(struct phylink_pcs *pcs)
- {
- return container_of(pcs, struct mtk_pcs_lynxi, pcs);
-@@ -117,6 +139,17 @@ static void mtk_pcs_lynxi_get_state(stru
- FIELD_GET(SGMII_LPA, adv));
- }
-
-+static void mtk_sgmii_reset(struct mtk_pcs_lynxi *mpcs)
-+{
-+ if (!mpcs->rstc)
-+ return;
-+
-+ reset_control_assert(mpcs->rstc);
-+ udelay(100);
-+ reset_control_deassert(mpcs->rstc);
-+ mdelay(1);
-+}
-+
- static int mtk_pcs_lynxi_config(struct phylink_pcs *pcs, unsigned int neg_mode,
- phy_interface_t interface,
- const unsigned long *advertising,
-@@ -162,6 +195,7 @@ static int mtk_pcs_lynxi_config(struct p
- SGMII_PHYA_PWD);
-
- /* Reset SGMII PCS state */
-+ mtk_sgmii_reset(mpcs);
- regmap_set_bits(mpcs->regmap, SGMSYS_RESERVED_0,
- SGMII_SW_RESET);
-
-@@ -248,10 +282,29 @@ static void mtk_pcs_lynxi_link_up(struct
- }
- }
-
-+static int mtk_pcs_lynxi_enable(struct phylink_pcs *pcs)
-+{
-+ struct mtk_pcs_lynxi *mpcs = pcs_to_mtk_pcs_lynxi(pcs);
-+
-+ if (mpcs->sgmii_tx && mpcs->sgmii_rx) {
-+ clk_prepare_enable(mpcs->sgmii_rx);
-+ clk_prepare_enable(mpcs->sgmii_tx);
-+ }
-+
-+ return 0;
-+}
-+
- static void mtk_pcs_lynxi_disable(struct phylink_pcs *pcs)
- {
- struct mtk_pcs_lynxi *mpcs = pcs_to_mtk_pcs_lynxi(pcs);
-
-+ regmap_set_bits(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, SGMII_PHYA_PWD);
-+
-+ if (mpcs->sgmii_tx && mpcs->sgmii_rx) {
-+ clk_disable_unprepare(mpcs->sgmii_tx);
-+ clk_disable_unprepare(mpcs->sgmii_rx);
-+ }
-+
- mpcs->interface = PHY_INTERFACE_MODE_NA;
- }
-
-@@ -262,11 +315,12 @@ static const struct phylink_pcs_ops mtk_
- .pcs_an_restart = mtk_pcs_lynxi_restart_an,
- .pcs_link_up = mtk_pcs_lynxi_link_up,
- .pcs_disable = mtk_pcs_lynxi_disable,
-+ .pcs_enable = mtk_pcs_lynxi_enable,
- };
-
--struct phylink_pcs *mtk_pcs_lynxi_create(struct device *dev,
-- struct regmap *regmap, u32 ana_rgc3,
-- u32 flags)
-+static struct phylink_pcs *mtk_pcs_lynxi_init(struct device *dev, struct regmap *regmap,
-+ u32 ana_rgc3, u32 flags,
-+ struct mtk_pcs_lynxi *prealloc)
- {
- struct mtk_pcs_lynxi *mpcs;
- u32 id, ver;
-@@ -274,29 +328,33 @@ struct phylink_pcs *mtk_pcs_lynxi_create
-
- ret = regmap_read(regmap, SGMSYS_PCS_DEVICE_ID, &id);
- if (ret < 0)
-- return NULL;
-+ return ERR_PTR(ret);
-
- if (id != SGMII_LYNXI_DEV_ID) {
- dev_err(dev, "unknown PCS device id %08x\n", id);
-- return NULL;
-+ return ERR_PTR(-ENODEV);
- }
-
- ret = regmap_read(regmap, SGMSYS_PCS_SCRATCH, &ver);
- if (ret < 0)
-- return NULL;
-+ return ERR_PTR(ret);
-
- ver = FIELD_GET(SGMII_DEV_VERSION, ver);
- if (ver != 0x1) {
- dev_err(dev, "unknown PCS device version %04x\n", ver);
-- return NULL;
-+ return ERR_PTR(-ENODEV);
- }
-
- dev_dbg(dev, "MediaTek LynxI SGMII PCS (id 0x%08x, ver 0x%04x)\n", id,
- ver);
-
-- mpcs = kzalloc(sizeof(*mpcs), GFP_KERNEL);
-- if (!mpcs)
-- return NULL;
-+ if (prealloc) {
-+ mpcs = prealloc;
-+ } else {
-+ mpcs = kzalloc(sizeof(*mpcs), GFP_KERNEL);
-+ if (!mpcs)
-+ return ERR_PTR(-ENOMEM);
-+ };
-
- mpcs->ana_rgc3 = ana_rgc3;
- mpcs->regmap = regmap;
-@@ -307,6 +365,13 @@ struct phylink_pcs *mtk_pcs_lynxi_create
- mpcs->interface = PHY_INTERFACE_MODE_NA;
-
- return &mpcs->pcs;
-+};
-+
-+struct phylink_pcs *mtk_pcs_lynxi_create(struct device *dev,
-+ struct regmap *regmap, u32 ana_rgc3,
-+ u32 flags)
-+{
-+ return mtk_pcs_lynxi_init(dev, regmap, ana_rgc3, flags, NULL);
- }
- EXPORT_SYMBOL(mtk_pcs_lynxi_create);
-
-@@ -319,4 +384,142 @@ void mtk_pcs_lynxi_destroy(struct phylin
- }
- EXPORT_SYMBOL(mtk_pcs_lynxi_destroy);
-
-+static int mtk_pcs_lynxi_probe(struct platform_device *pdev)
-+{
-+ struct device *dev = &pdev->dev;
-+ struct device_node *np = dev->of_node;
-+ struct mtk_pcs_lynxi *mpcs;
-+ struct phylink_pcs *pcs;
-+ struct regmap *regmap;
-+ u32 flags = 0;
-+
-+ mpcs = devm_kzalloc(dev, sizeof(*mpcs), GFP_KERNEL);
-+ if (!mpcs)
-+ return -ENOMEM;
-+
-+ mpcs->dev = dev;
-+ regmap = syscon_node_to_regmap(np->parent);
-+ if (IS_ERR(regmap))
-+ return PTR_ERR(regmap);
-+
-+ if (of_property_read_bool(np->parent, "mediatek,pnswap"))
-+ flags |= MTK_SGMII_FLAG_PN_SWAP;
-+
-+ mpcs->rstc = of_reset_control_get_shared(np->parent, NULL);
-+ if (IS_ERR(mpcs->rstc))
-+ return PTR_ERR(mpcs->rstc);
-+
-+ reset_control_deassert(mpcs->rstc);
-+ mpcs->sgmii_sel = devm_clk_get_enabled(dev, "sgmii_sel");
-+ if (IS_ERR(mpcs->sgmii_sel))
-+ return PTR_ERR(mpcs->sgmii_sel);
-+
-+ mpcs->sgmii_rx = devm_clk_get(dev, "sgmii_rx");
-+ if (IS_ERR(mpcs->sgmii_rx))
-+ return PTR_ERR(mpcs->sgmii_rx);
-+
-+ mpcs->sgmii_tx = devm_clk_get(dev, "sgmii_tx");
-+ if (IS_ERR(mpcs->sgmii_tx))
-+ return PTR_ERR(mpcs->sgmii_tx);
-+
-+ pcs = mtk_pcs_lynxi_init(dev, regmap, (uintptr_t)of_device_get_match_data(dev),
-+ flags, mpcs);
-+ if (IS_ERR(pcs))
-+ return PTR_ERR(pcs);
-+
-+ regmap_set_bits(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, SGMII_PHYA_PWD);
-+
-+ platform_set_drvdata(pdev, mpcs);
-+
-+ mutex_lock(&instance_mutex);
-+ list_add_tail(&mpcs->node, &mtk_pcs_lynxi_instances);
-+ mutex_unlock(&instance_mutex);
-+
-+ return 0;
-+}
-+
-+static void mtk_pcs_lynxi_remove(struct platform_device *pdev)
-+{
-+ struct device *dev = &pdev->dev;
-+ struct mtk_pcs_lynxi *cur, *tmp;
-+
-+ mutex_lock(&instance_mutex);
-+ list_for_each_entry_safe(cur, tmp, &mtk_pcs_lynxi_instances, node)
-+ if (cur->dev == dev) {
-+ list_del(&cur->node);
-+ kfree(cur);
-+ break;
-+ }
-+ mutex_unlock(&instance_mutex);
-+}
-+
-+static const struct of_device_id mtk_pcs_lynxi_of_match[] = {
-+ { .compatible = "mediatek,mt7988-sgmii", .data = (void *)MTK_NETSYS_V3_AMA_RGC3 },
-+ { /* sentinel */ },
-+};
-+MODULE_DEVICE_TABLE(of, mtk_pcs_lynxi_of_match);
-+
-+struct phylink_pcs *mtk_pcs_lynxi_get(struct device *dev, struct device_node *np)
-+{
-+ struct platform_device *pdev;
-+ struct mtk_pcs_lynxi *mpcs;
-+
-+ if (!np)
-+ return NULL;
-+
-+ if (!of_device_is_available(np))
-+ return ERR_PTR(-ENODEV);
-+
-+ if (!of_match_node(mtk_pcs_lynxi_of_match, np))
-+ return ERR_PTR(-EINVAL);
-+
-+ pdev = of_find_device_by_node(np);
-+ if (!pdev || !platform_get_drvdata(pdev)) {
-+ if (pdev)
-+ put_device(&pdev->dev);
-+ return ERR_PTR(-EPROBE_DEFER);
-+ }
-+
-+ mpcs = platform_get_drvdata(pdev);
-+ device_link_add(dev, mpcs->dev, DL_FLAG_AUTOREMOVE_CONSUMER);
-+
-+ return &mpcs->pcs;
-+}
-+EXPORT_SYMBOL(mtk_pcs_lynxi_get);
-+
-+void mtk_pcs_lynxi_put(struct phylink_pcs *pcs)
-+{
-+ struct mtk_pcs_lynxi *cur, *mpcs = NULL;
-+
-+ if (!pcs)
-+ return;
-+
-+ mutex_lock(&instance_mutex);
-+ list_for_each_entry(cur, &mtk_pcs_lynxi_instances, node)
-+ if (pcs == &cur->pcs) {
-+ mpcs = cur;
-+ break;
-+ }
-+ mutex_unlock(&instance_mutex);
-+
-+ if (WARN_ON(!mpcs))
-+ return;
-+
-+ put_device(mpcs->dev);
-+}
-+EXPORT_SYMBOL(mtk_pcs_lynxi_put);
-+
-+static struct platform_driver mtk_pcs_lynxi_driver = {
-+ .driver = {
-+ .name = "mtk-pcs-lynxi",
-+ .suppress_bind_attrs = true,
-+ .of_match_table = mtk_pcs_lynxi_of_match,
-+ },
-+ .probe = mtk_pcs_lynxi_probe,
-+ .remove_new = mtk_pcs_lynxi_remove,
-+};
-+module_platform_driver(mtk_pcs_lynxi_driver);
-+
-+MODULE_DESCRIPTION("MediaTek LynxI HSGMII PCS");
- MODULE_LICENSE("GPL");
---- a/include/linux/pcs/pcs-mtk-lynxi.h
-+++ b/include/linux/pcs/pcs-mtk-lynxi.h
-@@ -10,4 +10,15 @@ struct phylink_pcs *mtk_pcs_lynxi_create
- struct regmap *regmap,
- u32 ana_rgc3, u32 flags);
- void mtk_pcs_lynxi_destroy(struct phylink_pcs *pcs);
-+
-+#if IS_ENABLED(CONFIG_PCS_MTK_LYNXI)
-+struct phylink_pcs *mtk_pcs_lynxi_get(struct device *dev, struct device_node *np);
-+void mtk_pcs_lynxi_put(struct phylink_pcs *pcs);
-+#else
-+static inline struct phylink_pcs *mtk_pcs_lynxi_get(struct device *dev, struct device_node *np)
-+{
-+ return NULL;
-+}
-+static inline void mtk_pcs_lynxi_put(struct phylink_pcs *pcs) { }
-+#endif /* IS_ENABLED(CONFIG_PCS_MTK_LYNXI) */
- #endif
+++ /dev/null
-From 7d88d79c0f65b27a92754d7547f7af098b3de67b Mon Sep 17 00:00:00 2001
-Date: Tue, 12 Dec 2023 03:47:31 +0000
-Subject: [PATCH 4/5] dt-bindings: net: pcs: add bindings for MediaTek USXGMII
- PCS
-
-MediaTek's USXGMII can be found in the MT7988 SoC. We need to access
-it in order to configure and monitor the Ethernet SerDes link in
-USXGMII, 10GBase-R and 5GBase-R mode. By including a wrapped
-legacy 1000Base-X/2500Base-X/Cisco SGMII LynxI PCS as well, those
-interface modes are also available.
-
----
- .../bindings/net/pcs/mediatek,usxgmii.yaml | 60 +++++++++++++++++++
- 1 file changed, 60 insertions(+)
- create mode 100644 Documentation/devicetree/bindings/net/pcs/mediatek,usxgmii.yaml
-
---- /dev/null
-+++ b/Documentation/devicetree/bindings/net/pcs/mediatek,usxgmii.yaml
-@@ -0,0 +1,60 @@
-+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
-+%YAML 1.2
-+---
-+$id: http://devicetree.org/schemas/net/pcs/mediatek,usxgmii.yaml#
-+$schema: http://devicetree.org/meta-schemas/core.yaml#
-+
-+title: MediaTek USXGMII PCS
-+
-+maintainers:
-+
-+description:
-+ The MediaTek USXGMII PCS provides physical link control and status
-+ for USXGMII, 10GBase-R and 5GBase-R links on the SerDes interfaces
-+ provided by the PEXTP PHY.
-+ In order to also support legacy 2500Base-X, 1000Base-X and Cisco
-+ SGMII an existing mediatek,*-sgmiisys LynxI PCS is wrapped to
-+ provide those interfaces modes on the same SerDes interfaces shared
-+ with the USXGMII PCS.
-+
-+properties:
-+ $nodename:
-+ pattern: "^pcs@[0-9a-f]+$"
-+
-+ compatible:
-+ const: mediatek,mt7988-usxgmiisys
-+
-+ reg:
-+ maxItems: 1
-+
-+ clocks:
-+ items:
-+ - description: USXGMII top-level clock
-+
-+ resets:
-+ items:
-+ - description: XFI reset
-+
-+required:
-+ - compatible
-+ - reg
-+ - clocks
-+ - resets
-+
-+additionalProperties: false
-+
-+examples:
-+ - |
-+ #include <dt-bindings/clock/mediatek,mt7988-clk.h>
-+ #define MT7988_TOPRGU_XFI0_GRST 12
-+ soc {
-+ #address-cells = <2>;
-+ #size-cells = <2>;
-+ usxgmiisys0: pcs@10080000 {
-+ compatible = "mediatek,mt7988-usxgmiisys";
-+ reg = <0 0x10080000 0 0x1000>;
-+ clocks = <&topckgen CLK_TOP_USXGMII_SBUS_0_SEL>;
-+ resets = <&watchdog MT7988_TOPRGU_XFI0_GRST>;
-+ };
-+ };
+++ /dev/null
-From dde0e95fff92e9f5009f3bea75278e0e34a48822 Mon Sep 17 00:00:00 2001
-Date: Tue, 12 Dec 2023 03:47:47 +0000
-Subject: [PATCH 5/5] net: pcs: add driver for MediaTek USXGMII PCS
-
-Add driver for USXGMII PCS found in the MediaTek MT7988 SoC and supporting
-USXGMII, 10GBase-R and 5GBase-R interface modes.
-
----
- MAINTAINERS | 2 +
- drivers/net/pcs/Kconfig | 11 +
- drivers/net/pcs/Makefile | 1 +
- drivers/net/pcs/pcs-mtk-usxgmii.c | 456 ++++++++++++++++++++++++++++
- include/linux/pcs/pcs-mtk-usxgmii.h | 27 ++
- 5 files changed, 497 insertions(+)
- create mode 100644 drivers/net/pcs/pcs-mtk-usxgmii.c
- create mode 100644 include/linux/pcs/pcs-mtk-usxgmii.h
-
---- a/MAINTAINERS
-+++ b/MAINTAINERS
- S: Maintained
- F: drivers/net/pcs/pcs-mtk-lynxi.c
-+F: drivers/net/pcs/pcs-mtk-usxgmii.c
- F: include/linux/pcs/pcs-mtk-lynxi.h
-+F: include/linux/pcs/pcs-mtk-usxgmii.h
-
- MEDIATEK ETHERNET PHY DRIVERS
---- a/drivers/net/pcs/Kconfig
-+++ b/drivers/net/pcs/Kconfig
-@@ -25,6 +25,17 @@ config PCS_MTK_LYNXI
- This module provides helpers to phylink for managing the LynxI PCS
- which is part of MediaTek's SoC and Ethernet switch ICs.
-
-+config PCS_MTK_USXGMII
-+ tristate "MediaTek USXGMII PCS"
-+ select PCS_MTK_LYNXI
-+ select PHY_MTK_PEXTP
-+ select PHYLINK
-+ help
-+ This module provides a driver for MediaTek's USXGMII PCS supporting
-+ 10GBase-R, 5GBase-R and USXGMII interface modes.
-+ 1000Base-X, 2500Base-X and Cisco SGMII are supported on the same
-+ differential pairs via an embedded LynxI PHY.
-+
- config PCS_RZN1_MIIC
- tristate "Renesas RZ/N1 MII converter"
- depends on OF && (ARCH_RZN1 || COMPILE_TEST)
---- a/drivers/net/pcs/Makefile
-+++ b/drivers/net/pcs/Makefile
-@@ -7,3 +7,4 @@ obj-$(CONFIG_PCS_XPCS) += pcs_xpcs.o
- obj-$(CONFIG_PCS_LYNX) += pcs-lynx.o
- obj-$(CONFIG_PCS_MTK_LYNXI) += pcs-mtk-lynxi.o
- obj-$(CONFIG_PCS_RZN1_MIIC) += pcs-rzn1-miic.o
-+obj-$(CONFIG_PCS_MTK_USXGMII) += pcs-mtk-usxgmii.o
---- /dev/null
-+++ b/drivers/net/pcs/pcs-mtk-usxgmii.c
-@@ -0,0 +1,454 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/*
-+ * Copyright (c) 2023 MediaTek Inc.
-+ */
-+
-+#include <linux/clk.h>
-+#include <linux/io.h>
-+#include <linux/mfd/syscon.h>
-+#include <linux/mdio.h>
-+#include <linux/mutex.h>
-+#include <linux/of.h>
-+#include <linux/of_platform.h>
-+#include <linux/reset.h>
-+#include <linux/pcs/pcs-mtk-usxgmii.h>
-+#include <linux/platform_device.h>
-+
-+/* USXGMII subsystem config registers */
-+/* Register to control speed */
-+#define RG_PHY_TOP_SPEED_CTRL1 0x80c
-+#define USXGMII_RATE_UPDATE_MODE BIT(31)
-+#define USXGMII_MAC_CK_GATED BIT(29)
-+#define USXGMII_IF_FORCE_EN BIT(28)
-+#define USXGMII_RATE_ADAPT_MODE GENMASK(10, 8)
-+#define USXGMII_RATE_ADAPT_MODE_X1 0
-+#define USXGMII_RATE_ADAPT_MODE_X2 1
-+#define USXGMII_RATE_ADAPT_MODE_X4 2
-+#define USXGMII_RATE_ADAPT_MODE_X10 3
-+#define USXGMII_RATE_ADAPT_MODE_X100 4
-+#define USXGMII_RATE_ADAPT_MODE_X5 5
-+#define USXGMII_RATE_ADAPT_MODE_X50 6
-+#define USXGMII_XFI_RX_MODE GENMASK(6, 4)
-+#define USXGMII_XFI_TX_MODE GENMASK(2, 0)
-+#define USXGMII_XFI_MODE_10G 0
-+#define USXGMII_XFI_MODE_5G 1
-+#define USXGMII_XFI_MODE_2P5G 3
-+
-+/* Register to control PCS AN */
-+#define RG_PCS_AN_CTRL0 0x810
-+#define USXGMII_AN_RESTART BIT(31)
-+#define USXGMII_AN_SYNC_CNT GENMASK(30, 11)
-+#define USXGMII_AN_ENABLE BIT(0)
-+
-+#define RG_PCS_AN_CTRL2 0x818
-+#define USXGMII_LINK_TIMER_IDLE_DETECT GENMASK(29, 20)
-+#define USXGMII_LINK_TIMER_COMP_ACK_DETECT GENMASK(19, 10)
-+#define USXGMII_LINK_TIMER_AN_RESTART GENMASK(9, 0)
-+
-+/* Register to read PCS AN status */
-+#define RG_PCS_AN_STS0 0x81c
-+#define USXGMII_LPA GENMASK(15, 0)
-+#define USXGMII_LPA_LATCH BIT(31)
-+
-+/* Register to read PCS link status */
-+#define RG_PCS_RX_STATUS0 0x904
-+#define RG_PCS_RX_STATUS_UPDATE BIT(16)
-+#define RG_PCS_RX_LINK_STATUS BIT(2)
-+
-+/* struct mtk_usxgmii_pcs - This structure holds each usxgmii PCS
-+ * @pcs: Phylink PCS structure
-+ * @dev: Pointer to device structure
-+ * @base: IO memory to access PCS hardware
-+ * @clk: Pointer to USXGMII clk
-+ * @reset: Pointer to USXGMII reset control
-+ * @interface: Currently selected interface mode
-+ * @neg_mode: Currently used phylink neg_mode
-+ * @node: List node
-+ */
-+struct mtk_usxgmii_pcs {
-+ struct phylink_pcs pcs;
-+ struct device *dev;
-+ void __iomem *base;
-+ struct clk *clk;
-+ struct reset_control *reset;
-+ phy_interface_t interface;
-+ unsigned int neg_mode;
-+ struct list_head node;
-+};
-+
-+static LIST_HEAD(mtk_usxgmii_pcs_instances);
-+static DEFINE_MUTEX(instance_mutex);
-+
-+static u32 mtk_r32(struct mtk_usxgmii_pcs *mpcs, unsigned int reg)
-+{
-+ return ioread32(mpcs->base + reg);
-+}
-+
-+static void mtk_m32(struct mtk_usxgmii_pcs *mpcs, unsigned int reg, u32 mask, u32 set)
-+{
-+ u32 val;
-+
-+ val = ioread32(mpcs->base + reg);
-+ val &= ~mask;
-+ val |= set;
-+ iowrite32(val, mpcs->base + reg);
-+}
-+
-+static struct mtk_usxgmii_pcs *pcs_to_mtk_usxgmii_pcs(struct phylink_pcs *pcs)
-+{
-+ return container_of(pcs, struct mtk_usxgmii_pcs, pcs);
-+}
-+
-+static void mtk_usxgmii_reset(struct mtk_usxgmii_pcs *mpcs)
-+{
-+ reset_control_assert(mpcs->reset);
-+ udelay(100);
-+ reset_control_deassert(mpcs->reset);
-+
-+ mdelay(10);
-+}
-+
-+static int mtk_usxgmii_pcs_config(struct phylink_pcs *pcs, unsigned int neg_mode,
-+ phy_interface_t interface,
-+ const unsigned long *advertising,
-+ bool permit_pause_to_mac)
-+{
-+ struct mtk_usxgmii_pcs *mpcs = pcs_to_mtk_usxgmii_pcs(pcs);
-+ unsigned int an_ctrl = 0, link_timer = 0, xfi_mode = 0, adapt_mode = 0;
-+ bool mode_changed = false;
-+
-+ if (interface == PHY_INTERFACE_MODE_USXGMII) {
-+ an_ctrl = FIELD_PREP(USXGMII_AN_SYNC_CNT, 0x1FF) | USXGMII_AN_ENABLE;
-+ link_timer = FIELD_PREP(USXGMII_LINK_TIMER_IDLE_DETECT, 0x7B) |
-+ FIELD_PREP(USXGMII_LINK_TIMER_COMP_ACK_DETECT, 0x7B) |
-+ FIELD_PREP(USXGMII_LINK_TIMER_AN_RESTART, 0x7B);
-+ xfi_mode = FIELD_PREP(USXGMII_XFI_RX_MODE, USXGMII_XFI_MODE_10G) |
-+ FIELD_PREP(USXGMII_XFI_TX_MODE, USXGMII_XFI_MODE_10G);
-+ } else if (interface == PHY_INTERFACE_MODE_10GBASER) {
-+ an_ctrl = FIELD_PREP(USXGMII_AN_SYNC_CNT, 0x1FF);
-+ link_timer = FIELD_PREP(USXGMII_LINK_TIMER_IDLE_DETECT, 0x7B) |
-+ FIELD_PREP(USXGMII_LINK_TIMER_COMP_ACK_DETECT, 0x7B) |
-+ FIELD_PREP(USXGMII_LINK_TIMER_AN_RESTART, 0x7B);
-+ xfi_mode = FIELD_PREP(USXGMII_XFI_RX_MODE, USXGMII_XFI_MODE_10G) |
-+ FIELD_PREP(USXGMII_XFI_TX_MODE, USXGMII_XFI_MODE_10G);
-+ adapt_mode = USXGMII_RATE_UPDATE_MODE;
-+ } else if (interface == PHY_INTERFACE_MODE_5GBASER) {
-+ an_ctrl = FIELD_PREP(USXGMII_AN_SYNC_CNT, 0xFF);
-+ link_timer = FIELD_PREP(USXGMII_LINK_TIMER_IDLE_DETECT, 0x3D) |
-+ FIELD_PREP(USXGMII_LINK_TIMER_COMP_ACK_DETECT, 0x3D) |
-+ FIELD_PREP(USXGMII_LINK_TIMER_AN_RESTART, 0x3D);
-+ xfi_mode = FIELD_PREP(USXGMII_XFI_RX_MODE, USXGMII_XFI_MODE_5G) |
-+ FIELD_PREP(USXGMII_XFI_TX_MODE, USXGMII_XFI_MODE_5G);
-+ adapt_mode = USXGMII_RATE_UPDATE_MODE;
-+ } else {
-+ return -EINVAL;
-+ }
-+
-+ adapt_mode |= FIELD_PREP(USXGMII_RATE_ADAPT_MODE, USXGMII_RATE_ADAPT_MODE_X1);
-+
-+ if (mpcs->interface != interface) {
-+ mpcs->interface = interface;
-+ mode_changed = true;
-+ }
-+
-+ mtk_usxgmii_reset(mpcs);
-+
-+ /* Setup USXGMII AN ctrl */
-+ mtk_m32(mpcs, RG_PCS_AN_CTRL0,
-+ USXGMII_AN_SYNC_CNT | USXGMII_AN_ENABLE,
-+ an_ctrl);
-+
-+ mtk_m32(mpcs, RG_PCS_AN_CTRL2,
-+ USXGMII_LINK_TIMER_IDLE_DETECT |
-+ USXGMII_LINK_TIMER_COMP_ACK_DETECT |
-+ USXGMII_LINK_TIMER_AN_RESTART,
-+ link_timer);
-+
-+ mpcs->neg_mode = neg_mode;
-+
-+ /* Gated MAC CK */
-+ mtk_m32(mpcs, RG_PHY_TOP_SPEED_CTRL1,
-+ USXGMII_MAC_CK_GATED, USXGMII_MAC_CK_GATED);
-+
-+ /* Enable interface force mode */
-+ mtk_m32(mpcs, RG_PHY_TOP_SPEED_CTRL1,
-+ USXGMII_IF_FORCE_EN, USXGMII_IF_FORCE_EN);
-+
-+ /* Setup USXGMII adapt mode */
-+ mtk_m32(mpcs, RG_PHY_TOP_SPEED_CTRL1,
-+ USXGMII_RATE_UPDATE_MODE | USXGMII_RATE_ADAPT_MODE,
-+ adapt_mode);
-+
-+ /* Setup USXGMII speed */
-+ mtk_m32(mpcs, RG_PHY_TOP_SPEED_CTRL1,
-+ USXGMII_XFI_RX_MODE | USXGMII_XFI_TX_MODE,
-+ xfi_mode);
-+
-+ usleep_range(1, 10);
-+
-+ /* Un-gated MAC CK */
-+ mtk_m32(mpcs, RG_PHY_TOP_SPEED_CTRL1, USXGMII_MAC_CK_GATED, 0);
-+
-+ usleep_range(1, 10);
-+
-+ /* Disable interface force mode for the AN mode */
-+ if (an_ctrl & USXGMII_AN_ENABLE)
-+ mtk_m32(mpcs, RG_PHY_TOP_SPEED_CTRL1, USXGMII_IF_FORCE_EN, 0);
-+
-+ return mode_changed;
-+}
-+
-+static void mtk_usxgmii_pcs_get_fixed_speed(struct mtk_usxgmii_pcs *mpcs,
-+ struct phylink_link_state *state)
-+{
-+ u32 val = mtk_r32(mpcs, RG_PHY_TOP_SPEED_CTRL1);
-+ int speed;
-+
-+ /* Calculate speed from interface speed and rate adapt mode */
-+ switch (FIELD_GET(USXGMII_XFI_RX_MODE, val)) {
-+ case USXGMII_XFI_MODE_10G:
-+ speed = 10000;
-+ break;
-+ case USXGMII_XFI_MODE_5G:
-+ speed = 5000;
-+ break;
-+ case USXGMII_XFI_MODE_2P5G:
-+ speed = 2500;
-+ break;
-+ default:
-+ state->speed = SPEED_UNKNOWN;
-+ return;
-+ }
-+
-+ switch (FIELD_GET(USXGMII_RATE_ADAPT_MODE, val)) {
-+ case USXGMII_RATE_ADAPT_MODE_X100:
-+ speed /= 100;
-+ break;
-+ case USXGMII_RATE_ADAPT_MODE_X50:
-+ speed /= 50;
-+ break;
-+ case USXGMII_RATE_ADAPT_MODE_X10:
-+ speed /= 10;
-+ break;
-+ case USXGMII_RATE_ADAPT_MODE_X5:
-+ speed /= 5;
-+ break;
-+ case USXGMII_RATE_ADAPT_MODE_X4:
-+ speed /= 4;
-+ break;
-+ case USXGMII_RATE_ADAPT_MODE_X2:
-+ speed /= 2;
-+ break;
-+ case USXGMII_RATE_ADAPT_MODE_X1:
-+ break;
-+ default:
-+ state->speed = SPEED_UNKNOWN;
-+ return;
-+ }
-+
-+ state->speed = speed;
-+ state->duplex = DUPLEX_FULL;
-+}
-+
-+static void mtk_usxgmii_pcs_get_an_state(struct mtk_usxgmii_pcs *mpcs,
-+ struct phylink_link_state *state)
-+{
-+ u16 lpa;
-+
-+ /* Refresh LPA by toggling LPA_LATCH */
-+ mtk_m32(mpcs, RG_PCS_AN_STS0, USXGMII_LPA_LATCH, USXGMII_LPA_LATCH);
-+ ndelay(1020);
-+ mtk_m32(mpcs, RG_PCS_AN_STS0, USXGMII_LPA_LATCH, 0);
-+ ndelay(1020);
-+ lpa = FIELD_GET(USXGMII_LPA, mtk_r32(mpcs, RG_PCS_AN_STS0));
-+
-+ phylink_decode_usxgmii_word(state, lpa);
-+}
-+
-+static void mtk_usxgmii_pcs_get_state(struct phylink_pcs *pcs,
-+ struct phylink_link_state *state)
-+{
-+ struct mtk_usxgmii_pcs *mpcs = pcs_to_mtk_usxgmii_pcs(pcs);
-+
-+ /* Refresh USXGMII link status by toggling RG_PCS_AN_STATUS_UPDATE */
-+ mtk_m32(mpcs, RG_PCS_RX_STATUS0, RG_PCS_RX_STATUS_UPDATE,
-+ RG_PCS_RX_STATUS_UPDATE);
-+ ndelay(1020);
-+ mtk_m32(mpcs, RG_PCS_RX_STATUS0, RG_PCS_RX_STATUS_UPDATE, 0);
-+ ndelay(1020);
-+
-+ /* Read USXGMII link status */
-+ state->link = FIELD_GET(RG_PCS_RX_LINK_STATUS,
-+ mtk_r32(mpcs, RG_PCS_RX_STATUS0));
-+
-+ /* Continuously repeat re-configuration sequence until link comes up */
-+ if (!state->link) {
-+ mtk_usxgmii_pcs_config(pcs, mpcs->neg_mode,
-+ state->interface, NULL, false);
-+ return;
-+ }
-+
-+ if (FIELD_GET(USXGMII_AN_ENABLE, mtk_r32(mpcs, RG_PCS_AN_CTRL0)))
-+ mtk_usxgmii_pcs_get_an_state(mpcs, state);
-+ else
-+ mtk_usxgmii_pcs_get_fixed_speed(mpcs, state);
-+}
-+
-+static void mtk_usxgmii_pcs_restart_an(struct phylink_pcs *pcs)
-+{
-+ struct mtk_usxgmii_pcs *mpcs = pcs_to_mtk_usxgmii_pcs(pcs);
-+
-+ mtk_m32(mpcs, RG_PCS_AN_CTRL0, USXGMII_AN_RESTART, USXGMII_AN_RESTART);
-+}
-+
-+static void mtk_usxgmii_pcs_link_up(struct phylink_pcs *pcs, unsigned int neg_mode,
-+ phy_interface_t interface,
-+ int speed, int duplex)
-+{
-+ /* Reconfiguring USXGMII to ensure the quality of the RX signal
-+ * after the line side link up.
-+ */
-+ mtk_usxgmii_pcs_config(pcs, neg_mode, interface, NULL, false);
-+}
-+
-+static void mtk_usxgmii_pcs_disable(struct phylink_pcs *pcs)
-+{
-+ struct mtk_usxgmii_pcs *mpcs = pcs_to_mtk_usxgmii_pcs(pcs);
-+
-+ mpcs->interface = PHY_INTERFACE_MODE_NA;
-+ mpcs->neg_mode = -1;
-+}
-+
-+static const struct phylink_pcs_ops mtk_usxgmii_pcs_ops = {
-+ .pcs_config = mtk_usxgmii_pcs_config,
-+ .pcs_get_state = mtk_usxgmii_pcs_get_state,
-+ .pcs_an_restart = mtk_usxgmii_pcs_restart_an,
-+ .pcs_link_up = mtk_usxgmii_pcs_link_up,
-+ .pcs_disable = mtk_usxgmii_pcs_disable,
-+};
-+
-+static int mtk_usxgmii_probe(struct platform_device *pdev)
-+{
-+ struct device *dev = &pdev->dev;
-+ struct mtk_usxgmii_pcs *mpcs;
-+
-+ mpcs = devm_kzalloc(dev, sizeof(*mpcs), GFP_KERNEL);
-+ if (!mpcs)
-+ return -ENOMEM;
-+
-+ mpcs->base = devm_platform_ioremap_resource(pdev, 0);
-+ if (IS_ERR(mpcs->base))
-+ return PTR_ERR(mpcs->base);
-+
-+ mpcs->dev = dev;
-+ mpcs->pcs.ops = &mtk_usxgmii_pcs_ops;
-+ mpcs->pcs.poll = true;
-+ mpcs->pcs.neg_mode = true;
-+ mpcs->interface = PHY_INTERFACE_MODE_NA;
-+ mpcs->neg_mode = -1;
-+
-+ mpcs->clk = devm_clk_get_enabled(mpcs->dev, NULL);
-+ if (IS_ERR(mpcs->clk))
-+ return PTR_ERR(mpcs->clk);
-+
-+ mpcs->reset = devm_reset_control_get_shared(dev, NULL);
-+ if (IS_ERR(mpcs->reset))
-+ return PTR_ERR(mpcs->reset);
-+
-+ reset_control_deassert(mpcs->reset);
-+
-+ platform_set_drvdata(pdev, mpcs);
-+
-+ mutex_lock(&instance_mutex);
-+ list_add_tail(&mpcs->node, &mtk_usxgmii_pcs_instances);
-+ mutex_unlock(&instance_mutex);
-+
-+ return 0;
-+}
-+
-+static void mtk_usxgmii_remove(struct platform_device *pdev)
-+{
-+ struct device *dev = &pdev->dev;
-+ struct mtk_usxgmii_pcs *cur, *tmp;
-+
-+ mutex_lock(&instance_mutex);
-+ list_for_each_entry_safe(cur, tmp, &mtk_usxgmii_pcs_instances, node)
-+ if (cur->dev == dev) {
-+ list_del(&cur->node);
-+ break;
-+ }
-+ mutex_unlock(&instance_mutex);
-+}
-+
-+static const struct of_device_id mtk_usxgmii_of_mtable[] = {
-+ { .compatible = "mediatek,mt7988-usxgmiisys" },
-+ { /* sentinel */ },
-+};
-+MODULE_DEVICE_TABLE(of, mtk_usxgmii_of_mtable);
-+
-+struct phylink_pcs *mtk_usxgmii_pcs_get(struct device *dev, struct device_node *np)
-+{
-+ struct platform_device *pdev;
-+ struct mtk_usxgmii_pcs *mpcs;
-+
-+ if (!np)
-+ return NULL;
-+
-+ if (!of_device_is_available(np))
-+ return ERR_PTR(-ENODEV);
-+
-+ if (!of_match_node(mtk_usxgmii_of_mtable, np))
-+ return ERR_PTR(-EINVAL);
-+
-+ pdev = of_find_device_by_node(np);
-+ if (!pdev || !platform_get_drvdata(pdev)) {
-+ if (pdev)
-+ put_device(&pdev->dev);
-+ return ERR_PTR(-EPROBE_DEFER);
-+ }
-+
-+ mpcs = platform_get_drvdata(pdev);
-+ device_link_add(dev, mpcs->dev, DL_FLAG_AUTOREMOVE_CONSUMER);
-+
-+ return &mpcs->pcs;
-+}
-+EXPORT_SYMBOL(mtk_usxgmii_pcs_get);
-+
-+void mtk_usxgmii_pcs_put(struct phylink_pcs *pcs)
-+{
-+ struct mtk_usxgmii_pcs *cur, *mpcs = NULL;
-+
-+ if (!pcs)
-+ return;
-+
-+ mutex_lock(&instance_mutex);
-+ list_for_each_entry(cur, &mtk_usxgmii_pcs_instances, node)
-+ if (pcs == &cur->pcs) {
-+ mpcs = cur;
-+ break;
-+ }
-+ mutex_unlock(&instance_mutex);
-+
-+ if (WARN_ON(!mpcs))
-+ return;
-+
-+ put_device(mpcs->dev);
-+}
-+EXPORT_SYMBOL(mtk_usxgmii_pcs_put);
-+
-+static struct platform_driver mtk_usxgmii_driver = {
-+ .driver = {
-+ .name = "mtk_usxgmii",
-+ .suppress_bind_attrs = true,
-+ .of_match_table = mtk_usxgmii_of_mtable,
-+ },
-+ .probe = mtk_usxgmii_probe,
-+ .remove_new = mtk_usxgmii_remove,
-+};
-+module_platform_driver(mtk_usxgmii_driver);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_DESCRIPTION("MediaTek USXGMII PCS driver");
---- /dev/null
-+++ b/include/linux/pcs/pcs-mtk-usxgmii.h
-@@ -0,0 +1,27 @@
-+/* SPDX-License-Identifier: GPL-2.0 */
-+#ifndef __LINUX_PCS_MTK_USXGMII_H
-+#define __LINUX_PCS_MTK_USXGMII_H
-+
-+#include <linux/phylink.h>
-+
-+/**
-+ * mtk_usxgmii_select_pcs() - Get MediaTek PCS instance
-+ * @np: Pointer to device node indentifying a MediaTek USXGMII PCS
-+ * @mode: Ethernet PHY interface mode
-+ *
-+ * Return PCS identified by a device node and the PHY interface mode in use
-+ *
-+ * Return: Pointer to phylink PCS instance of NULL
-+ */
-+#if IS_ENABLED(CONFIG_PCS_MTK_USXGMII)
-+struct phylink_pcs *mtk_usxgmii_pcs_get(struct device *dev, struct device_node *np);
-+void mtk_usxgmii_pcs_put(struct phylink_pcs *pcs);
-+#else
-+static inline struct phylink_pcs *mtk_usxgmii_pcs_get(struct device *dev, struct device_node *np)
-+{
-+ return NULL;
-+}
-+static inline void mtk_usxgmii_pcs_put(struct phylink_pcs *pcs) { }
-+#endif /* IS_ENABLED(CONFIG_PCS_MTK_USXGMII) */
-+
-+#endif /* __LINUX_PCS_MTK_USXGMII_H */
+++ /dev/null
-From 6f291aa7da199c6486cc229b055dcbcd5cee7a21 Mon Sep 17 00:00:00 2001
-Date: Sun, 21 May 2023 22:24:56 +0200
-Subject: [PATCH] net: phy: motorcomm: Add missing include
-
-Directly include linux/bitfield.h which provides FIELD_PREP.
-
----
- drivers/net/phy/motorcomm.c | 1 +
- 1 file changed, 1 insertion(+)
-
---- a/drivers/net/phy/motorcomm.c
-+++ b/drivers/net/phy/motorcomm.c
-@@ -6,6 +6,7 @@
- */
-
-+#include <linux/bitfield.h>
- #include <linux/etherdevice.h>
- #include <linux/kernel.h>
- #include <linux/module.h>
+++ /dev/null
-From 1be3688b3eaa7ea2d9e19bd29ae6a6a51c121a0b Mon Sep 17 00:00:00 2001
-Date: Sat, 16 Nov 2024 22:36:15 +0100
-Subject: [PATCH] net: phy: broadcom: update dependency condition
-
-The broadcom PHY driver only has to depend upon PTP_1588_CLOCK_OPTIONAL
-if NETWORK_PHY_TIMESTAMPING is enabled. The PTP functionality is stubbed
-in this case.
-
-Reflect this circumstance in the dependence condition. This allows to
-build the driver as a built-in module even if PTP is built as a module.
-
-This is required to include the broadcom PHY module regardless of the
-built-setting of the PTP subsystem. On ath79 (and probably more)
-targets with Broadcom PHY, Gigabit operation is currently broken as the
-PHY driver is only built as a module in case all kernel-packages are
-built. Due to this circumstance, affected devices fall back to using the
-generic PHY driver.
-
----
- drivers/net/phy/Kconfig | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/net/phy/Kconfig
-+++ b/drivers/net/phy/Kconfig
-@@ -125,7 +125,7 @@ config BROADCOM_PHY
- tristate "Broadcom 54XX PHYs"
- select BCM_NET_PHYLIB
- select BCM_NET_PHYPTP if NETWORK_PHY_TIMESTAMPING
-- depends on PTP_1588_CLOCK_OPTIONAL
-+ depends on NETWORK_PHY_TIMESTAMPING=n || PTP_1588_CLOCK_OPTIONAL
- help
- Currently supports the BCM5411, BCM5421, BCM5461, BCM54616S, BCM5464,
- BCM5481, BCM54810 and BCM5482 PHYs.
+++ /dev/null
-From patchwork Thu Aug 5 22:23:30 2021
-Content-Type: text/plain; charset="utf-8"
-MIME-Version: 1.0
-Content-Transfer-Encoding: 7bit
-X-Patchwork-Id: 12422209
-Date: Thu, 5 Aug 2021 23:23:30 +0100
-Subject: [PATCH] ARM: kirkwood: add missing <linux/if_ether.h> for ETH_ALEN
-MIME-Version: 1.0
-Content-Disposition: inline
-X-Mailman-Version: 2.1.34
-Precedence: list
-List-Id: <linux-arm-kernel.lists.infradead.org>
-List-Archive: <http://lists.infradead.org/pipermail/linux-arm-kernel/>
-
-After commit 83216e3988cd1 ("of: net: pass the dst buffer to
-of_get_mac_address()") build fails for kirkwood as ETH_ALEN is not
-defined.
-
-arch/arm/mach-mvebu/kirkwood.c: In function 'kirkwood_dt_eth_fixup':
-arch/arm/mach-mvebu/kirkwood.c:87:13: error: 'ETH_ALEN' undeclared (first use in this function); did you mean 'ESTALE'?
- u8 tmpmac[ETH_ALEN];
- ^~~~~~~~
- ESTALE
-arch/arm/mach-mvebu/kirkwood.c:87:13: note: each undeclared identifier is reported only once for each function it appears in
-arch/arm/mach-mvebu/kirkwood.c:87:6: warning: unused variable 'tmpmac' [-Wunused-variable]
- u8 tmpmac[ETH_ALEN];
- ^~~~~~
-make[5]: *** [scripts/Makefile.build:262: arch/arm/mach-mvebu/kirkwood.o] Error 1
-make[5]: *** Waiting for unfinished jobs....
-
-Add missing #include <linux/if_ether.h> to fix this.
-
-Reported-by: https://buildbot.openwrt.org/master/images/#/builders/56/builds/220/steps/44/logs/stdio
-Fixes: 83216e3988cd1 ("of: net: pass the dst buffer to of_get_mac_address()")
----
- arch/arm/mach-mvebu/kirkwood.c | 1 +
- 1 file changed, 1 insertion(+)
-
---- a/arch/arm/mach-mvebu/kirkwood.c
-+++ b/arch/arm/mach-mvebu/kirkwood.c
-@@ -11,6 +11,7 @@
- #include <linux/kernel.h>
- #include <linux/init.h>
- #include <linux/mbus.h>
-+#include <linux/if_ether.h>
- #include <linux/of.h>
- #include <linux/of_address.h>
- #include <linux/of_net.h>
+++ /dev/null
-From 5f7c5e1c0d7a79be144e5efc1f24728ddd7fc25c Mon Sep 17 00:00:00 2001
-Date: Sat, 5 Nov 2022 20:02:56 +0100
-Subject: [PATCH 1/2] bus: mhi: core: add SBL state callback
-
-Add support for SBL state callback in MHI core.
-
-It is required for ath11k MHI devices in order to be able to set QRTR
-instance ID in the SBL state so that QRTR instance ID-s dont conflict in
-case of multiple PCI/MHI cards or AHB + PCI/MHI card.
-Setting QRTR instance ID is only possible in SBL state and there is
-currently no way to ensure that we are in that state, so provide a
-callback that the controller can trigger off.
-
----
- drivers/bus/mhi/host/main.c | 1 +
- include/linux/mhi.h | 2 ++
- 2 files changed, 3 insertions(+)
-
---- a/drivers/bus/mhi/host/main.c
-+++ b/drivers/bus/mhi/host/main.c
-@@ -916,6 +916,7 @@ int mhi_process_ctrl_ev_ring(struct mhi_
- switch (event) {
- case MHI_EE_SBL:
- st = DEV_ST_TRANSITION_SBL;
-+ mhi_cntrl->status_cb(mhi_cntrl, MHI_CB_EE_SBL_MODE);
- break;
- case MHI_EE_WFW:
- case MHI_EE_AMSS:
---- a/include/linux/mhi.h
-+++ b/include/linux/mhi.h
-@@ -34,6 +34,7 @@ struct mhi_buf_info;
- * @MHI_CB_SYS_ERROR: MHI device entered error state (may recover)
- * @MHI_CB_FATAL_ERROR: MHI device entered fatal error state
- * @MHI_CB_BW_REQ: Received a bandwidth switch request from device
-+ * @MHI_CB_EE_SBL_MODE: MHI device entered SBL mode
- */
- enum mhi_callback {
- MHI_CB_IDLE,
-@@ -45,6 +46,7 @@ enum mhi_callback {
- MHI_CB_SYS_ERROR,
- MHI_CB_FATAL_ERROR,
- MHI_CB_BW_REQ,
-+ MHI_CB_EE_SBL_MODE,
- };
-
- /**
+++ /dev/null
-From f992b15965177e2f280fb6f41f292214f9a6f8d5 Mon Sep 17 00:00:00 2001
-Date: Tue, 10 Dec 2024 03:28:31 -0800
-Subject: [PATCH] tg3: Fix DMA allocations on 57766 devices
-
-The coherent DMA mask of 31b may not be accepted if
-the DMA mask is configured to use higher memories of
-64b. Set the DMA mask also to lower 32b for 57766
-devices.
-
-Fixes: 614f4d166eee ("tg3: Set coherent DMA mask bits to 31 for BCM57766 chipsets")
----
- drivers/net/ethernet/broadcom/tg3.c | 4 +++-
- 1 file changed, 3 insertions(+), 1 deletion(-)
-
---- a/drivers/net/ethernet/broadcom/tg3.c
-+++ b/drivers/net/ethernet/broadcom/tg3.c
-@@ -17729,8 +17729,10 @@ static int tg3_init_one(struct pci_dev *
- } else
- persist_dma_mask = dma_mask = DMA_BIT_MASK(64);
-
-- if (tg3_asic_rev(tp) == ASIC_REV_57766)
-+ if (tg3_asic_rev(tp) == ASIC_REV_57766) {
-+ dma_mask = DMA_BIT_MASK(32);
- persist_dma_mask = DMA_BIT_MASK(31);
-+ }
-
- /* Configure DMA attributes. */
- if (dma_mask > DMA_BIT_MASK(32)) {
+++ /dev/null
-Subject: [PATCH] bcma: get SoC device struct & copy its DMA params to the
- subdevices
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-For bus devices to be fully usable it's required to set their DMA
-parameters.
-
-For years it has been missing and remained unnoticed because of
-mips_dma_alloc_coherent() silently handling the empty coherent_dma_mask.
-Kernel 4.19 came with a lot of DMA changes and caused a regression on
-the bcm47xx. Starting with the commit f8c55dc6e828 ("MIPS: use generic
-dma noncoherent ops for simple noncoherent platforms") DMA coherent
-allocations just fail. Example:
-[ 1.114914] bgmac_bcma bcma0:2: Allocation of TX ring 0x200 failed
-[ 1.121215] bgmac_bcma bcma0:2: Unable to alloc memory for DMA
-[ 1.127626] bgmac_bcma: probe of bcma0:2 failed with error -12
-[ 1.133838] bgmac_bcma: Broadcom 47xx GBit MAC driver loaded
-
-This change fixes above regression in addition to the MIPS bcm47xx
-commit 321c46b91550 ("MIPS: BCM47XX: Setup struct device for the SoC").
-
-It also fixes another *old* GPIO regression caused by a parent pointing
-to the NULL:
-[ 0.157054] missing gpiochip .dev parent pointer
-[ 0.157287] bcma: bus0: Error registering GPIO driver: -22
-introduced by the commit 74f4e0cc6108 ("bcma: switch GPIO portions to
-use GPIOLIB_IRQCHIP").
-
-Fixes: f8c55dc6e828 ("MIPS: use generic dma noncoherent ops for simple noncoherent platforms")
-Fixes: 74f4e0cc6108 ("bcma: switch GPIO portions to use GPIOLIB_IRQCHIP")
----
-
---- a/drivers/bcma/host_soc.c
-+++ b/drivers/bcma/host_soc.c
-@@ -191,6 +191,8 @@ int __init bcma_host_soc_init(struct bcm
- struct bcma_bus *bus = &soc->bus;
- int err;
-
-+ bus->dev = soc->dev;
-+
- /* Scan bus and initialize it */
- err = bcma_bus_early_register(bus);
- if (err)
---- a/drivers/bcma/main.c
-+++ b/drivers/bcma/main.c
-@@ -237,13 +237,17 @@ EXPORT_SYMBOL(bcma_core_irq);
-
- void bcma_prepare_core(struct bcma_bus *bus, struct bcma_device *core)
- {
-- device_initialize(&core->dev);
-+ struct device *dev = &core->dev;
-+
-+ device_initialize(dev);
- core->dev.release = bcma_release_core_dev;
- core->dev.bus = &bcma_bus_type;
-- dev_set_name(&core->dev, "bcma%d:%d", bus->num, core->core_index);
-+ dev_set_name(dev, "bcma%d:%d", bus->num, core->core_index);
- core->dev.parent = bus->dev;
-- if (bus->dev)
-+ if (bus->dev) {
- bcma_of_fill_device(bus->dev, core);
-+ dma_coerce_mask_and_coherent(dev, bus->dev->coherent_dma_mask);
-+ }
-
- switch (bus->hosttype) {
- case BCMA_HOSTTYPE_PCI:
+++ /dev/null
-From fc23ea48ba52c24f201fe5ca0132ee1a3de5a70a Mon Sep 17 00:00:00 2001
-Date: Thu, 25 Mar 2021 11:48:05 +0200
-Subject: [PATCH 2/2] gpio: gpio-cascade: add generic GPIO cascade
-
-Adds support for building cascades of GPIO lines. That is, it allows
-setups when there is one upstream line and multiple cascaded lines, out
-of which one can be chosen at a time. The status of the upstream line
-can be conveyed to the selected cascaded line or, vice versa, the status
-of the cascaded line can be conveyed to the upstream line.
-
-A multiplexer is being used to select, which cascaded GPIO line is being
-used at any given time.
-
-At the moment only input direction is supported. In future it should be
-possible to add support for output direction, too.
-
----
-v7 -> v8:
- - rearrange members in struct gpio_cascade
- - cosmetic changes in file header and in one function declaration
- - added Reviewed-by tags by Linus and Andy
-v6 -> v7:
- - In Kconfig add info about module name
- - adhere to new convention that allows lines longer than 80 chars
- - use dev_probe_err with upstream gpio line too
- - refactor for cleaner exit of probe function.
-v5 -> v6:
- - In Kconfig, remove dependency to OF_GPIO and select only MULTIPLEXER
- - refactor code preferring one-liners
- - clean up prints, removing them from success-path.
- - don't explicitly set gpio_chip.of_node as it's done in the GPIO library
- - use devm_gpiochip_add_data instead of gpiochip_add
-v4 -> v5:
- - renamed gpio-mux-input -> gpio-cascade. refactored code accordingly
- here and there and changed to use new bindings and compatible string
- - ambigious and vague 'pin' was rename to 'upstream_line'
- - dropped Tested-by and Reviewed-by due to changes in bindings
- - dropped Reported-by suggested by an automatic bot as it was not really
- appropriate to begin with
- - functionally it's the same as v4
-v3 -> v4:
- - Changed author email
- - Included Tested-by and Reviewed-by from Drew
-v2 -> v3:
- - use managed device resources
- - update Kconfig description
-v1 -> v2:
- - removed .owner from platform_driver as per test bot's instruction
- - added MODULE_AUTHOR, MODULE_DESCRIPTION, MODULE_LICENSE
- - added gpio_mux_input_get_direction as it's recommended for all chips
- - removed because this is input only chip: gpio_mux_input_set_value
- - removed because they are not needed for input/output only chips:
- gpio_mux_input_direction_input
- gpio_mux_input_direction_output
- - fixed typo in an error message
- - added info message about successful registration
- - removed can_sleep flag as this does not sleep while getting GPIO value
- like I2C or SPI do
- - Updated description in Kconfig
----
- drivers/gpio/Kconfig | 15 +++++
- drivers/gpio/Makefile | 1 +
- drivers/gpio/gpio-cascade.c | 117 ++++++++++++++++++++++++++++++++++++
- 3 files changed, 133 insertions(+)
- create mode 100644 drivers/gpio/gpio-cascade.c
-
---- a/drivers/gpio/Kconfig
-+++ b/drivers/gpio/Kconfig
-@@ -1820,4 +1820,19 @@ config GPIO_SIM
-
- endmenu
-
-+comment "Other GPIO expanders"
-+
-+config GPIO_CASCADE
-+ tristate "General GPIO cascade"
-+ select MULTIPLEXER
-+ help
-+ Say yes here to enable support for generic GPIO cascade.
-+
-+ This allows building one-to-many cascades of GPIO lines using
-+ different types of multiplexers readily available. At the
-+ moment only input lines are supported.
-+
-+ To build the driver as a module choose 'm' and the resulting module
-+ will be called 'gpio-cascade'.
-+
- endif
---- a/drivers/gpio/Makefile
-+++ b/drivers/gpio/Makefile
-@@ -44,6 +44,7 @@ obj-$(CONFIG_GPIO_BD9571MWV) += gpio-bd
- obj-$(CONFIG_GPIO_BRCMSTB) += gpio-brcmstb.o
- obj-$(CONFIG_GPIO_BT8XX) += gpio-bt8xx.o
- obj-$(CONFIG_GPIO_CADENCE) += gpio-cadence.o
-+obj-$(CONFIG_GPIO_CASCADE) += gpio-cascade.o
- obj-$(CONFIG_GPIO_CLPS711X) += gpio-clps711x.o
- obj-$(CONFIG_GPIO_SNPS_CREG) += gpio-creg-snps.o
- obj-$(CONFIG_GPIO_CRYSTAL_COVE) += gpio-crystalcove.o
---- /dev/null
-+++ b/drivers/gpio/gpio-cascade.c
-@@ -0,0 +1,112 @@
-+// SPDX-License-Identifier: GPL-2.0-only
-+/*
-+ * A generic GPIO cascade driver
-+ *
-+ *
-+ * This allows building cascades of GPIO lines in a manner illustrated
-+ * below:
-+ *
-+ * /|---- Cascaded GPIO line 0
-+ * Upstream | |---- Cascaded GPIO line 1
-+ * GPIO line ----+ | .
-+ * | | .
-+ * \|---- Cascaded GPIO line n
-+ *
-+ * A multiplexer is being used to select, which cascaded line is being
-+ * addressed at any given time.
-+ *
-+ * At the moment only input mode is supported due to lack of means for
-+ * testing output functionality. At least theoretically output should be
-+ * possible with open drain constructions.
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/slab.h>
-+#include <linux/platform_device.h>
-+#include <linux/mux/consumer.h>
-+
-+#include <linux/gpio/consumer.h>
-+#include <linux/gpio/driver.h>
-+
-+struct gpio_cascade {
-+ struct gpio_chip gpio_chip;
-+ struct device *parent;
-+ struct mux_control *mux_control;
-+ struct gpio_desc *upstream_line;
-+};
-+
-+static int gpio_cascade_get_direction(struct gpio_chip *gc, unsigned int offset)
-+{
-+ return GPIO_LINE_DIRECTION_IN;
-+}
-+
-+static int gpio_cascade_get_value(struct gpio_chip *gc, unsigned int offset)
-+{
-+ struct gpio_cascade *cas = gpiochip_get_data(gc);
-+ int ret;
-+
-+ ret = mux_control_select(cas->mux_control, offset);
-+ if (ret)
-+ return ret;
-+
-+ ret = gpiod_get_value(cas->upstream_line);
-+ mux_control_deselect(cas->mux_control);
-+ return ret;
-+}
-+
-+static int gpio_cascade_probe(struct platform_device *pdev)
-+{
-+ struct device *dev = &pdev->dev;
-+ struct gpio_cascade *cas;
-+ struct mux_control *mc;
-+ struct gpio_desc *upstream;
-+ struct gpio_chip *gc;
-+
-+ cas = devm_kzalloc(dev, sizeof(*cas), GFP_KERNEL);
-+ if (!cas)
-+ return -ENOMEM;
-+
-+ mc = devm_mux_control_get(dev, NULL);
-+ if (IS_ERR(mc))
-+ return dev_err_probe(dev, PTR_ERR(mc), "unable to get mux-control\n");
-+
-+ cas->mux_control = mc;
-+ upstream = devm_gpiod_get(dev, "upstream", GPIOD_IN);
-+ if (IS_ERR(upstream))
-+ return dev_err_probe(dev, PTR_ERR(upstream), "unable to claim upstream GPIO line\n");
-+
-+ cas->upstream_line = upstream;
-+ cas->parent = dev;
-+
-+ gc = &cas->gpio_chip;
-+ gc->get = gpio_cascade_get_value;
-+ gc->get_direction = gpio_cascade_get_direction;
-+ gc->base = -1;
-+ gc->ngpio = mux_control_states(mc);
-+ gc->label = dev_name(cas->parent);
-+ gc->parent = cas->parent;
-+ gc->owner = THIS_MODULE;
-+
-+ platform_set_drvdata(pdev, cas);
-+ return devm_gpiochip_add_data(dev, &cas->gpio_chip, cas);
-+}
-+
-+static const struct of_device_id gpio_cascade_id[] = {
-+ { .compatible = "gpio-cascade" },
-+ { /* sentinel */ }
-+};
-+MODULE_DEVICE_TABLE(of, gpio_cascade_id);
-+
-+static struct platform_driver gpio_cascade_driver = {
-+ .driver = {
-+ .name = "gpio-cascade",
-+ .of_match_table = gpio_cascade_id,
-+ },
-+ .probe = gpio_cascade_probe,
-+};
-+module_platform_driver(gpio_cascade_driver);
-+
-+MODULE_DESCRIPTION("Generic GPIO cascade");
-+MODULE_LICENSE("GPL");
+++ /dev/null
-From fd59b838dd90452f61a17dc9e5ff175205003068 Mon Sep 17 00:00:00 2001
-Date: Thu, 15 Sep 2022 18:49:43 +0200
-Subject: [PATCH] OPP: Provide old opp to config_clks on _set_opp
-
-With the target opp, also pass the old opp to config_clks function.
-This can be useful when a driver needs to take decision on what fequency
-to set based on what is the current frequency without using a
-clk_get_freq call.
-Update the only user of custom config_clks (tegra30 devfreq driver) to
-this new implementation.
-
----
- drivers/devfreq/tegra30-devfreq.c | 5 +++--
- drivers/opp/core.c | 11 ++++++-----
- include/linux/pm_opp.h | 11 ++++++-----
- 3 files changed, 15 insertions(+), 12 deletions(-)
-
---- a/drivers/devfreq/tegra30-devfreq.c
-+++ b/drivers/devfreq/tegra30-devfreq.c
-@@ -823,8 +823,9 @@ static int devm_tegra_devfreq_init_hw(st
-
- static int tegra_devfreq_config_clks_nop(struct device *dev,
- struct opp_table *opp_table,
-- struct dev_pm_opp *opp, void *data,
-- bool scaling_down)
-+ struct dev_pm_opp *old_opp,
-+ struct dev_pm_opp *opp,
-+ void *data, bool scaling_down)
- {
- /* We want to skip clk configuration via dev_pm_opp_set_opp() */
- return 0;
---- a/drivers/opp/core.c
-+++ b/drivers/opp/core.c
-@@ -925,7 +925,8 @@ static int _set_opp_voltage(struct devic
-
- static int
- _opp_config_clk_single(struct device *dev, struct opp_table *opp_table,
-- struct dev_pm_opp *opp, void *data, bool scaling_down)
-+ struct dev_pm_opp *old_opp, struct dev_pm_opp *opp,
-+ void *data, bool scaling_down)
- {
- unsigned long *target = data;
- unsigned long freq;
-@@ -957,8 +958,8 @@ _opp_config_clk_single(struct device *de
- * the order in which they are present in the array while scaling up.
- */
- int dev_pm_opp_config_clks_simple(struct device *dev,
-- struct opp_table *opp_table, struct dev_pm_opp *opp, void *data,
-- bool scaling_down)
-+ struct opp_table *opp_table, struct dev_pm_opp *old_opp,
-+ struct dev_pm_opp *opp, void *data, bool scaling_down)
- {
- int ret, i;
-
-@@ -1240,7 +1241,7 @@ static int _set_opp(struct device *dev,
- }
-
- if (opp_table->config_clks) {
-- ret = opp_table->config_clks(dev, opp_table, opp, clk_data, scaling_down);
-+ ret = opp_table->config_clks(dev, opp_table, old_opp, opp, clk_data, scaling_down);
- if (ret)
- return ret;
- }
-@@ -1315,7 +1316,7 @@ int dev_pm_opp_set_rate(struct device *d
- * equivalent to a clk_set_rate()
- */
- if (!_get_opp_count(opp_table)) {
-- ret = opp_table->config_clks(dev, opp_table, NULL,
-+ ret = opp_table->config_clks(dev, opp_table, NULL, NULL,
- &target_freq, false);
- goto put_opp_table;
- }
---- a/include/linux/pm_opp.h
-+++ b/include/linux/pm_opp.h
-@@ -61,7 +61,8 @@ typedef int (*config_regulators_t)(struc
- struct dev_pm_opp *old_opp, struct dev_pm_opp *new_opp,
- struct regulator **regulators, unsigned int count);
-
--typedef int (*config_clks_t)(struct device *dev, struct opp_table *opp_table,
-+typedef int (*config_clks_t)(struct device *dev,
-+ struct opp_table *opp_table, struct dev_pm_opp *old_opp,
- struct dev_pm_opp *opp, void *data, bool scaling_down);
-
- /**
-@@ -172,8 +173,8 @@ int dev_pm_opp_set_config(struct device
- int devm_pm_opp_set_config(struct device *dev, struct dev_pm_opp_config *config);
- void dev_pm_opp_clear_config(int token);
- int dev_pm_opp_config_clks_simple(struct device *dev,
-- struct opp_table *opp_table, struct dev_pm_opp *opp, void *data,
-- bool scaling_down);
-+ struct opp_table *opp_table, struct dev_pm_opp *old_opp,
-+ struct dev_pm_opp *opp, void *data, bool scaling_down);
-
- struct dev_pm_opp *dev_pm_opp_xlate_required_opp(struct opp_table *src_table, struct opp_table *dst_table, struct dev_pm_opp *src_opp);
- int dev_pm_opp_xlate_performance_state(struct opp_table *src_table, struct opp_table *dst_table, unsigned int pstate);
-@@ -377,8 +378,8 @@ static inline int devm_pm_opp_set_config
- static inline void dev_pm_opp_clear_config(int token) {}
-
- static inline int dev_pm_opp_config_clks_simple(struct device *dev,
-- struct opp_table *opp_table, struct dev_pm_opp *opp, void *data,
-- bool scaling_down)
-+ struct opp_table *opp_table, struct dev_pm_opp *old_opp,
-+ struct dev_pm_opp *opp, void *data, bool scaling_down)
- {
- return -EOPNOTSUPP;
- }
+++ /dev/null
-Date: Thu, 13 Jul 2023 18:29:19 +0200
-Subject: [PATCH] nvmem: core: support "mac-base" fixed layout cells
-
-Fixed layout binding allows specifying "mac-base" NVMEM cells. It's used
-for base MAC address (that can be used for calculating relative
-addresses). It can be stored in a raw binary format or as an ASCII
-string.
----
-
---- a/drivers/nvmem/Kconfig
-+++ b/drivers/nvmem/Kconfig
-@@ -2,6 +2,7 @@
- menuconfig NVMEM
- bool "NVMEM Support"
- imply NVMEM_LAYOUTS
-+ select GENERIC_NET_UTILS
- help
- Support for NVMEM(Non Volatile Memory) devices like EEPROM, EFUSES...
-
---- a/drivers/nvmem/core.c
-+++ b/drivers/nvmem/core.c
-@@ -7,9 +7,12 @@
- */
-
- #include <linux/device.h>
-+#include <linux/ctype.h>
-+#include <linux/etherdevice.h>
- #include <linux/export.h>
- #include <linux/fs.h>
- #include <linux/idr.h>
-+#include <linux/if_ether.h>
- #include <linux/init.h>
- #include <linux/kref.h>
- #include <linux/module.h>
-@@ -810,6 +813,62 @@ static int nvmem_validate_keepouts(struc
- return 0;
- }
-
-+static int nvmem_mac_base_raw_read(void *context, const char *id, int index, unsigned int offset,
-+ void *buf, size_t bytes)
-+{
-+ if (WARN_ON(bytes != ETH_ALEN))
-+ return -EINVAL;
-+
-+ if (index)
-+ eth_addr_add(buf, index);
-+
-+ return 0;
-+}
-+
-+static int nvmem_mac_base_ascii_read(void *context, const char *id, int index, unsigned int offset,
-+ void *buf, size_t bytes)
-+{
-+ u8 mac[ETH_ALEN];
-+
-+ if (WARN_ON(bytes != 3 * ETH_ALEN - 1))
-+ return -EINVAL;
-+
-+ if (!mac_pton(buf, mac))
-+ return -EINVAL;
-+
-+ if (index)
-+ eth_addr_add(mac, index);
-+
-+ ether_addr_copy(buf, mac);
-+
-+ return 0;
-+}
-+
-+static int nvmem_mac_base_hex_read(void *context, const char *id, int index, unsigned int offset,
-+ void *buf, size_t bytes)
-+{
-+ u8 mac[ETH_ALEN], *hexstr;
-+ int i;
-+
-+ if (WARN_ON(bytes != 2 * ETH_ALEN))
-+ return -EINVAL;
-+
-+ hexstr = (u8 *)buf;
-+ for (i = 0; i < ETH_ALEN; i++) {
-+ if (!isxdigit(hexstr[i * 2]) || !isxdigit(hexstr[i * 2 + 1]))
-+ return -EINVAL;
-+
-+ mac[i] = (hex_to_bin(hexstr[i * 2]) << 4) | hex_to_bin(hexstr[i * 2 + 1]);
-+ }
-+
-+ if (index)
-+ eth_addr_add(mac, index);
-+
-+ ether_addr_copy(buf, mac);
-+
-+ return 0;
-+}
-+
- static int nvmem_add_cells_from_dt(struct nvmem_device *nvmem, struct device_node *np)
- {
- struct device *dev = &nvmem->dev;
-@@ -849,6 +908,25 @@ static int nvmem_add_cells_from_dt(struc
- if (nvmem->fixup_dt_cell_info)
- nvmem->fixup_dt_cell_info(nvmem, &info);
-
-+ if (of_device_is_compatible(np, "fixed-layout")) {
-+ if (of_device_is_compatible(child, "mac-base")) {
-+ if (info.bytes == ETH_ALEN) {
-+ info.raw_len = info.bytes;
-+ info.bytes = ETH_ALEN;
-+ info.read_post_process = nvmem_mac_base_raw_read;
-+ } else if (info.bytes == 2 * ETH_ALEN) {
-+ info.raw_len = info.bytes;
-+ info.bytes = ETH_ALEN;
-+ info.read_post_process = nvmem_mac_base_hex_read;
-+ } else if (info.bytes == 3 * ETH_ALEN - 1) {
-+ info.raw_len = info.bytes;
-+ info.bytes = ETH_ALEN;
-+ info.read_post_process = nvmem_mac_base_ascii_read;
-+ }
-+
-+ }
-+ }
-+
- ret = nvmem_add_one_cell(nvmem, &info);
- kfree(info.name);
- if (ret) {
+++ /dev/null
-From fd0e523037439520813db7c57df5bd37cdf40f7e Mon Sep 17 00:00:00 2001
-Date: Mon, 3 Feb 2025 00:10:18 +0100
-Subject: [PATCH 1/2] nvmem: core: generalize "mac-base" cells handling
-
-Generalize support of "mac-base" nvmem cells and provide a GPL symbol to
-permit also other NVMEM layout driver to parse mac-base cells.
-
-It's VERY COMMON for some specially formatted NVMEM to expose a mac
-address in ASCII format or HEX format hence prevent code duplication by
-exposing a common helper.
-
-Such helper will change the nvmem_info_cell and apply the correct post
-process function to correctly parse the mac address.
-
-Since the API requires OF and is only related to layout, move the
-function in layouts.c to correctly handle non-OF NVMEM.
-
----
- drivers/nvmem/core.c | 79 +--------------------------------
- drivers/nvmem/layouts.c | 80 ++++++++++++++++++++++++++++++++++
- include/linux/nvmem-provider.h | 4 ++
- 3 files changed, 86 insertions(+), 77 deletions(-)
-
---- a/drivers/nvmem/core.c
-+++ b/drivers/nvmem/core.c
-@@ -7,12 +7,9 @@
- */
-
- #include <linux/device.h>
--#include <linux/ctype.h>
--#include <linux/etherdevice.h>
- #include <linux/export.h>
- #include <linux/fs.h>
- #include <linux/idr.h>
--#include <linux/if_ether.h>
- #include <linux/init.h>
- #include <linux/kref.h>
- #include <linux/module.h>
-@@ -813,62 +810,6 @@ static int nvmem_validate_keepouts(struc
- return 0;
- }
-
--static int nvmem_mac_base_raw_read(void *context, const char *id, int index, unsigned int offset,
-- void *buf, size_t bytes)
--{
-- if (WARN_ON(bytes != ETH_ALEN))
-- return -EINVAL;
--
-- if (index)
-- eth_addr_add(buf, index);
--
-- return 0;
--}
--
--static int nvmem_mac_base_ascii_read(void *context, const char *id, int index, unsigned int offset,
-- void *buf, size_t bytes)
--{
-- u8 mac[ETH_ALEN];
--
-- if (WARN_ON(bytes != 3 * ETH_ALEN - 1))
-- return -EINVAL;
--
-- if (!mac_pton(buf, mac))
-- return -EINVAL;
--
-- if (index)
-- eth_addr_add(mac, index);
--
-- ether_addr_copy(buf, mac);
--
-- return 0;
--}
--
--static int nvmem_mac_base_hex_read(void *context, const char *id, int index, unsigned int offset,
-- void *buf, size_t bytes)
--{
-- u8 mac[ETH_ALEN], *hexstr;
-- int i;
--
-- if (WARN_ON(bytes != 2 * ETH_ALEN))
-- return -EINVAL;
--
-- hexstr = (u8 *)buf;
-- for (i = 0; i < ETH_ALEN; i++) {
-- if (!isxdigit(hexstr[i * 2]) || !isxdigit(hexstr[i * 2 + 1]))
-- return -EINVAL;
--
-- mac[i] = (hex_to_bin(hexstr[i * 2]) << 4) | hex_to_bin(hexstr[i * 2 + 1]);
-- }
--
-- if (index)
-- eth_addr_add(mac, index);
--
-- ether_addr_copy(buf, mac);
--
-- return 0;
--}
--
- static int nvmem_add_cells_from_dt(struct nvmem_device *nvmem, struct device_node *np)
- {
- struct device *dev = &nvmem->dev;
-@@ -908,24 +849,8 @@ static int nvmem_add_cells_from_dt(struc
- if (nvmem->fixup_dt_cell_info)
- nvmem->fixup_dt_cell_info(nvmem, &info);
-
-- if (of_device_is_compatible(np, "fixed-layout")) {
-- if (of_device_is_compatible(child, "mac-base")) {
-- if (info.bytes == ETH_ALEN) {
-- info.raw_len = info.bytes;
-- info.bytes = ETH_ALEN;
-- info.read_post_process = nvmem_mac_base_raw_read;
-- } else if (info.bytes == 2 * ETH_ALEN) {
-- info.raw_len = info.bytes;
-- info.bytes = ETH_ALEN;
-- info.read_post_process = nvmem_mac_base_hex_read;
-- } else if (info.bytes == 3 * ETH_ALEN - 1) {
-- info.raw_len = info.bytes;
-- info.bytes = ETH_ALEN;
-- info.read_post_process = nvmem_mac_base_ascii_read;
-- }
--
-- }
-- }
-+ if (of_device_is_compatible(np, "fixed-layout"))
-+ nvmem_layout_parse_mac_base(&info);
-
- ret = nvmem_add_one_cell(nvmem, &info);
- kfree(info.name);
---- a/drivers/nvmem/layouts.c
-+++ b/drivers/nvmem/layouts.c
-@@ -6,8 +6,11 @@
- */
-
-+#include <linux/ctype.h>
- #include <linux/device.h>
- #include <linux/dma-mapping.h>
-+#include <linux/etherdevice.h>
-+#include <linux/if_ether.h>
- #include <linux/nvmem-consumer.h>
- #include <linux/nvmem-provider.h>
- #include <linux/of.h>
-@@ -21,6 +24,83 @@
- #define to_nvmem_layout_device(_dev) \
- container_of((_dev), struct nvmem_layout, dev)
-
-+static int nvmem_mac_base_raw_read(void *context, const char *id, int index, unsigned int offset,
-+ void *buf, size_t bytes)
-+{
-+ if (WARN_ON(bytes != ETH_ALEN))
-+ return -EINVAL;
-+
-+ if (index)
-+ eth_addr_add(buf, index);
-+
-+ return 0;
-+}
-+
-+static int nvmem_mac_base_ascii_read(void *context, const char *id, int index, unsigned int offset,
-+ void *buf, size_t bytes)
-+{
-+ u8 mac[ETH_ALEN];
-+
-+ if (WARN_ON(bytes != 3 * ETH_ALEN - 1))
-+ return -EINVAL;
-+
-+ if (!mac_pton(buf, mac))
-+ return -EINVAL;
-+
-+ if (index)
-+ eth_addr_add(mac, index);
-+
-+ ether_addr_copy(buf, mac);
-+
-+ return 0;
-+}
-+
-+static int nvmem_mac_base_hex_read(void *context, const char *id, int index, unsigned int offset,
-+ void *buf, size_t bytes)
-+{
-+ u8 mac[ETH_ALEN], *hexstr;
-+ int i;
-+
-+ if (WARN_ON(bytes != 2 * ETH_ALEN))
-+ return -EINVAL;
-+
-+ hexstr = (u8 *)buf;
-+ for (i = 0; i < ETH_ALEN; i++) {
-+ if (!isxdigit(hexstr[i * 2]) || !isxdigit(hexstr[i * 2 + 1]))
-+ return -EINVAL;
-+
-+ mac[i] = (hex_to_bin(hexstr[i * 2]) << 4) | hex_to_bin(hexstr[i * 2 + 1]);
-+ }
-+
-+ if (index)
-+ eth_addr_add(mac, index);
-+
-+ ether_addr_copy(buf, mac);
-+
-+ return 0;
-+}
-+
-+void nvmem_layout_parse_mac_base(struct nvmem_cell_info *info)
-+{
-+ if (!of_device_is_compatible(info->np, "mac-base"))
-+ return;
-+
-+ if (info->bytes == ETH_ALEN) {
-+ info->raw_len = info->bytes;
-+ info->bytes = ETH_ALEN;
-+ info->read_post_process = nvmem_mac_base_raw_read;
-+ } else if (info->bytes == 2 * ETH_ALEN) {
-+ info->raw_len = info->bytes;
-+ info->bytes = ETH_ALEN;
-+ info->read_post_process = nvmem_mac_base_hex_read;
-+ } else if (info->bytes == 3 * ETH_ALEN - 1) {
-+ info->raw_len = info->bytes;
-+ info->bytes = ETH_ALEN;
-+ info->read_post_process = nvmem_mac_base_ascii_read;
-+ }
-+}
-+EXPORT_SYMBOL_GPL(nvmem_layout_parse_mac_base);
-+
- static int nvmem_layout_bus_match(struct device *dev, struct device_driver *drv)
- {
- return of_driver_match_device(dev, drv);
---- a/include/linux/nvmem-provider.h
-+++ b/include/linux/nvmem-provider.h
-@@ -242,6 +242,8 @@ static inline void nvmem_layout_unregist
-
- #if IS_ENABLED(CONFIG_NVMEM) && IS_ENABLED(CONFIG_OF)
-
-+void nvmem_layout_parse_mac_base(struct nvmem_cell_info *info);
-+
- /**
- * of_nvmem_layout_get_container() - Get OF node of layout container
- *
-@@ -254,6 +256,8 @@ struct device_node *of_nvmem_layout_get_
-
- #else /* CONFIG_NVMEM && CONFIG_OF */
-
-+static inline void nvmem_layout_parse_mac_base(struct nvmem_cell_info *info) {}
-+
- static inline struct device_node *of_nvmem_layout_get_container(struct nvmem_device *nvmem)
- {
- return NULL;
+++ /dev/null
-From 38287e8ec5c0281377fc70f11f20bcd9986a05f5 Mon Sep 17 00:00:00 2001
-Date: Mon, 3 Feb 2025 00:36:12 +0100
-Subject: [PATCH 2/2] nvmem: layouts: add support for ascii-env driver
-
-Add support for simple ASCII envirorment driver for NVMEM layouts.
-
-It's very common for devices to store simple text file format in
-partition for environment varibles. The most common pattern is variable
-name, a delimiter and variable value all separated by a new line
-character (\n).
-
-This driver adds support for exporting such data and expose NVMEM cells
-so they can be referenced by other drivers. This driver also supports
-parsing mac-base NVMEM cells to parse ASCII or HEX mac address.
-
----
- drivers/nvmem/layouts/Kconfig | 13 +++
- drivers/nvmem/layouts/Makefile | 1 +
- drivers/nvmem/layouts/ascii-env.c | 140 ++++++++++++++++++++++++++++++
- 3 files changed, 154 insertions(+)
- create mode 100644 drivers/nvmem/layouts/ascii-env.c
-
---- a/drivers/nvmem/layouts/Kconfig
-+++ b/drivers/nvmem/layouts/Kconfig
-@@ -37,6 +37,19 @@ config NVMEM_LAYOUT_U_BOOT_ENV
-
- If unsure, say N.
-
-+config NVMEM_LAYOUT_ASCII_ENV
-+ tristate "ASCII environment variables layout"
-+ help
-+ It's very common for devices to store simple text file format in
-+ partition for environment varibles. The most common pattern is variable
-+ name, a delimiter and variable value all separated by a new line
-+ character (\n).
-+ This driver adds support for exporting such data and expose NVMEM cells
-+ so they can be referenced by other drivers. This driver also supports
-+ parsing mac-base NVMEM cells to parse ASCII or HEX mac address.
-+
-+ If unsure, say N.
-+
- endmenu
-
- endif
---- a/drivers/nvmem/layouts/Makefile
-+++ b/drivers/nvmem/layouts/Makefile
-@@ -6,3 +6,4 @@
- obj-$(CONFIG_NVMEM_LAYOUT_SL28_VPD) += sl28vpd.o
- obj-$(CONFIG_NVMEM_LAYOUT_ONIE_TLV) += onie-tlv.o
- obj-$(CONFIG_NVMEM_LAYOUT_U_BOOT_ENV) += u-boot-env.o
-+obj-$(CONFIG_NVMEM_LAYOUT_ASCII_ENV) += ascii-env.o
---- /dev/null
-+++ b/drivers/nvmem/layouts/ascii-env.c
-@@ -0,0 +1,148 @@
-+// SPDX-License-Identifier: GPL-2.0-only
-+/*
-+ *
-+ * This borrow some parse logic from u-boot-env.
-+ */
-+#include <linux/nvmem-consumer.h>
-+#include <linux/nvmem-provider.h>
-+#include <linux/of.h>
-+#include <linux/slab.h>
-+
-+struct ascii_env_match_data {
-+ const char delim;
-+};
-+
-+/*
-+ * Parse a buffer as an ASCII text with name delimiter value and each pattern separated
-+ * with a new line char '\n'
-+ * Example: (delimiter '=')
-+ * name=value\nname2=value2\n
-+ * 2 Cell:
-+ * - name: value
-+ * - name2: value2
-+ */
-+static int ascii_env_parse_cells(struct device *dev, struct nvmem_device *nvmem, uint8_t *buf,
-+ size_t data_len, const char delim)
-+{
-+ char *var, *value, *eq, *lf;
-+ char *data = buf;
-+
-+ /*
-+ * Warning the inner loop take care of replacing '\n'
-+ * with '\0', hence we can use strlen on value.
-+ */
-+ for (var = data; var < data + data_len && *var;
-+ var = value + strlen(value) + 1) {
-+ struct nvmem_cell_info info = {};
-+ struct device_node *child;
-+ const char *label;
-+
-+ eq = strchr(var, delim);
-+ if (!eq)
-+ break;
-+ *eq = '\0';
-+ value = eq + 1;
-+
-+ /* Replace '\n' with '\0' to use strlen for value */
-+ lf = strchr(value, '\n');
-+ if (!lf)
-+ break;
-+ *lf = '\0';
-+
-+ info.name = devm_kstrdup(dev, var, GFP_KERNEL);
-+ if (!info.name)
-+ return -ENOMEM;
-+ info.offset = value - data;
-+ info.bytes = strlen(value);
-+ info.np = of_get_child_by_name(dev->of_node, info.name);
-+ for_each_child_of_node(dev->of_node, child) {
-+ if (!of_property_read_string(child, "label", &label) &&
-+ !strncmp(info.name, label, info.bytes))
-+ info.np = child;
-+ else if (of_node_name_eq(child, info.name))
-+ info.np = child;
-+ }
-+
-+ nvmem_layout_parse_mac_base(&info);
-+
-+ nvmem_add_one_cell(nvmem, &info);
-+ }
-+
-+ return 0;
-+}
-+
-+static int ascii_env_add_cells(struct nvmem_layout *layout)
-+{
-+ struct nvmem_device *nvmem = layout->nvmem;
-+ const struct ascii_env_match_data *data;
-+ struct device *dev = &layout->dev;
-+ size_t dev_size;
-+ uint8_t *buf;
-+ int bytes;
-+ int ret;
-+
-+ /* Get the delimiter for name value pattern */
-+ data = device_get_match_data(dev);
-+
-+ dev_size = nvmem_dev_size(nvmem);
-+
-+ buf = kzalloc(dev_size, GFP_KERNEL);
-+ if (!buf) {
-+ ret = -ENOMEM;
-+ goto err_out;
-+ }
-+
-+ bytes = nvmem_device_read(nvmem, 0, dev_size, buf);
-+ if (bytes < 0) {
-+ ret = bytes;
-+ goto err_kfree;
-+ } else if (bytes != dev_size) {
-+ ret = -EIO;
-+ goto err_kfree;
-+ }
-+
-+ buf[dev_size - 1] = '\0';
-+ ret = ascii_env_parse_cells(dev, nvmem, buf, dev_size, data->delim);
-+
-+err_kfree:
-+ kfree(buf);
-+err_out:
-+ return ret;
-+}
-+
-+static int ascii_env_probe(struct nvmem_layout *layout)
-+{
-+ layout->add_cells = ascii_env_add_cells;
-+
-+ return nvmem_layout_register(layout);
-+}
-+
-+static void ascii_env_remove(struct nvmem_layout *layout)
-+{
-+ nvmem_layout_unregister(layout);
-+}
-+
-+static const struct ascii_env_match_data ascii_env_eq = {
-+ .delim = '=',
-+};
-+
-+static const struct of_device_id ascii_env_of_match_table[] = {
-+ { .compatible = "ascii-eq-delim-env", .data = &ascii_env_eq, },
-+ {},
-+};
-+
-+static struct nvmem_layout_driver ascii_env_layout = {
-+ .driver = {
-+ .name = "ascii-env-layout",
-+ .of_match_table = ascii_env_of_match_table,
-+ },
-+ .probe = ascii_env_probe,
-+ .remove = ascii_env_remove,
-+};
-+module_nvmem_layout_driver(ascii_env_layout);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_DEVICE_TABLE(of, ascii_env_of_match_table);
-+MODULE_DESCRIPTION("NVMEM layout driver for ASCII environment variables");
+++ /dev/null
-Date: Thu, 06 Feb 2025 21:55:28 +0400
-Subject: [PATCH] nvmem: layouts: ascii-env handle CRLF while parsing
-
-The current driver supports LF line endings only.
-
-For CRLF-based line endings in the ASCII env, the length of the value of
-the variable passed to nvmem_layout_parse_mac_base is 18 bytes instead
-of an expected length of 17 causing the parsing to fail.
-So, let's add the ability to handle CRLF line endings by adding a
-condition to check if the value ends with a '\r' character and replace it
-with '\0' to properly parse the mac address.
-
-Tested on Linksys MX2000, MX5500, and SPNMX56.
-
----
---- a/drivers/nvmem/layouts/ascii-env.c
-+++ b/drivers/nvmem/layouts/ascii-env.c
-@@ -25,18 +25,20 @@ struct ascii_env_match_data {
- static int ascii_env_parse_cells(struct device *dev, struct nvmem_device *nvmem, uint8_t *buf,
- size_t data_len, const char delim)
- {
-- char *var, *value, *eq, *lf;
-+ char *var, *value, *eq, *lf, *cr;
- char *data = buf;
-+ uint incr = 0;
-
- /*
- * Warning the inner loop take care of replacing '\n'
- * with '\0', hence we can use strlen on value.
- */
- for (var = data; var < data + data_len && *var;
-- var = value + strlen(value) + 1) {
-+ var = value + strlen(value) + incr) {
- struct nvmem_cell_info info = {};
- struct device_node *child;
- const char *label;
-+ incr = 0;
-
- eq = strchr(var, delim);
- if (!eq)
-@@ -49,6 +51,15 @@ static int ascii_env_parse_cells(struct
- if (!lf)
- break;
- *lf = '\0';
-+ incr++;
-+
-+ /* For CRLF based env, replace '\r' with '\0' too to use strlen
-+ * for value, and increment var by one in loop for next variable */
-+ cr = strchr(value, '\r');
-+ if (cr) {
-+ *cr = '\0';
-+ incr++;
-+ }
-
- info.name = devm_kstrdup(dev, var, GFP_KERNEL);
- if (!info.name)
+++ /dev/null
-Subject: debloat: add kernel config option to disabling common PCI quirks
-
----
- drivers/pci/Kconfig | 6 ++++++
- drivers/pci/quirks.c | 6 ++++++
- 2 files changed, 12 insertions(+)
-
---- a/drivers/pci/Kconfig
-+++ b/drivers/pci/Kconfig
-@@ -113,6 +113,13 @@ config XEN_PCIDEV_FRONTEND
- The PCI device frontend driver allows the kernel to import arbitrary
- PCI devices from a PCI backend to support PCI driver domains.
-
-+config PCI_DISABLE_COMMON_QUIRKS
-+ bool "PCI disable common quirks"
-+ depends on PCI
-+ help
-+ If you don't know what to do here, say N.
-+
-+
- config PCI_ATS
- bool
-
---- a/drivers/pci/quirks.c
-+++ b/drivers/pci/quirks.c
-@@ -313,6 +313,7 @@ static void quirk_mmio_always_on(struct
- DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_ANY_ID, PCI_ANY_ID,
- PCI_CLASS_BRIDGE_HOST, 8, quirk_mmio_always_on);
-
-+#ifndef CONFIG_PCI_DISABLE_COMMON_QUIRKS
- /*
- * The Mellanox Tavor device gives false positive parity errors. Disable
- * parity error reporting.
-@@ -3502,6 +3503,8 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_I
- DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x65f9, quirk_intel_mc_errata);
- DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x65fa, quirk_intel_mc_errata);
-
-+#endif /* !CONFIG_PCI_DISABLE_COMMON_QUIRKS */
-+
- /*
- * Ivytown NTB BAR sizes are misreported by the hardware due to an erratum.
- * To work around this, query the size it should be configured to by the
-@@ -3527,6 +3530,8 @@ static void quirk_intel_ntb(struct pci_d
- DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0e08, quirk_intel_ntb);
- DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0e0d, quirk_intel_ntb);
-
-+#ifndef CONFIG_PCI_DISABLE_COMMON_QUIRKS
-+
- /*
- * Some BIOS implementations leave the Intel GPU interrupts enabled, even
- * though no one is handling them (e.g., if the i915 driver is never
-@@ -3565,6 +3570,8 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_IN
- DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x010a, disable_igfx_irq);
- DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0152, disable_igfx_irq);
-
-+#endif /* !CONFIG_PCI_DISABLE_COMMON_QUIRKS */
-+
- /*
- * PCI devices which are on Intel chips can skip the 10ms delay
- * before entering D3 mode.
+++ /dev/null
-Subject: debloat: disable common USB quirks
-
----
- drivers/usb/host/pci-quirks.c | 16 ++++++++++++++++
- drivers/usb/host/pci-quirks.h | 18 +++++++++++++++++-
- include/linux/usb/hcd.h | 7 +++++++
- 3 files changed, 40 insertions(+), 1 deletion(-)
-
---- a/drivers/usb/host/pci-quirks.c
-+++ b/drivers/usb/host/pci-quirks.c
-@@ -128,6 +128,8 @@ struct amd_chipset_type {
- u8 rev;
- };
-
-+#ifndef CONFIG_PCI_DISABLE_COMMON_QUIRKS
-+
- static struct amd_chipset_info {
- struct pci_dev *nb_dev;
- struct pci_dev *smbus_dev;
-@@ -631,6 +633,10 @@ bool usb_amd_pt_check_port(struct device
- }
- EXPORT_SYMBOL_GPL(usb_amd_pt_check_port);
-
-+#endif /* CONFIG_PCI_DISABLE_COMMON_QUIRKS */
-+
-+#if IS_ENABLED(CONFIG_USB_UHCI_HCD)
-+
- /*
- * Make sure the controller is completely inactive, unable to
- * generate interrupts or do DMA.
-@@ -710,8 +716,17 @@ reset_needed:
- uhci_reset_hc(pdev, base);
- return 1;
- }
-+#else
-+int uhci_check_and_reset_hc(struct pci_dev *pdev, unsigned long base)
-+{
-+ return 0;
-+}
-+
-+#endif
- EXPORT_SYMBOL_GPL(uhci_check_and_reset_hc);
-
-+#ifndef CONFIG_PCI_DISABLE_COMMON_QUIRKS
-+
- static inline int io_type_enabled(struct pci_dev *pdev, unsigned int mask)
- {
- u16 cmd;
-@@ -1292,3 +1307,4 @@ static void quirk_usb_early_handoff(stru
- }
- DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_ANY_ID, PCI_ANY_ID,
- PCI_CLASS_SERIAL_USB, 8, quirk_usb_early_handoff);
-+#endif
---- a/drivers/usb/host/pci-quirks.h
-+++ b/drivers/usb/host/pci-quirks.h
-@@ -5,6 +5,9 @@
- #ifdef CONFIG_USB_PCI
- void uhci_reset_hc(struct pci_dev *pdev, unsigned long base);
- int uhci_check_and_reset_hc(struct pci_dev *pdev, unsigned long base);
-+#endif /* CONFIG_USB_PCI */
-+
-+#if defined(CONFIG_USB_PCI) && !defined(CONFIG_PCI_DISABLE_COMMON_QUIRKS)
- int usb_hcd_amd_remote_wakeup_quirk(struct pci_dev *pdev);
- bool usb_amd_hang_symptom_quirk(void);
- bool usb_amd_prefetch_quirk(void);
-@@ -19,6 +22,18 @@ void sb800_prefetch(struct device *dev,
- bool usb_amd_pt_check_port(struct device *device, int port);
- #else
- struct pci_dev;
-+static inline int usb_amd_quirk_pll_check(void)
-+{
-+ return 0;
-+}
-+static inline bool usb_amd_hang_symptom_quirk(void)
-+{
-+ return false;
-+}
-+static inline bool usb_amd_prefetch_quirk(void)
-+{
-+ return false;
-+}
- static inline void usb_amd_quirk_pll_disable(void) {}
- static inline void usb_amd_quirk_pll_enable(void) {}
- static inline void usb_asmedia_modifyflowcontrol(struct pci_dev *pdev) {}
-@@ -29,6 +44,11 @@ static inline bool usb_amd_pt_check_port
- {
- return false;
- }
-+static inline void usb_enable_intel_xhci_ports(struct pci_dev *xhci_pdev) {}
-+static inline bool usb_xhci_needs_pci_reset(struct pci_dev *pdev)
-+{
-+ return false;
-+}
- #endif /* CONFIG_USB_PCI */
-
- #endif /* __LINUX_USB_PCI_QUIRKS_H */
---- a/include/linux/usb/hcd.h
-+++ b/include/linux/usb/hcd.h
-@@ -485,7 +485,14 @@ extern int usb_hcd_pci_probe(struct pci_
- extern void usb_hcd_pci_remove(struct pci_dev *dev);
- extern void usb_hcd_pci_shutdown(struct pci_dev *dev);
-
-+#ifndef CONFIG_PCI_DISABLE_COMMON_QUIRKS
- extern int usb_hcd_amd_remote_wakeup_quirk(struct pci_dev *dev);
-+#else
-+static inline int usb_hcd_amd_remote_wakeup_quirk(struct pci_dev *dev)
-+{
-+ return 0;
-+}
-+#endif
-
- extern const struct dev_pm_ops usb_hcd_pci_pm_ops;
- #endif /* CONFIG_USB_PCI */
+++ /dev/null
-From d9c8bc8c1408f3e8529db6e4e04017b4c579c342 Mon Sep 17 00:00:00 2001
-Date: Sun, 18 Feb 2018 17:08:04 +0100
-Subject: [PATCH] w1: gpio: fix problem with platfom data in w1-gpio
-
-In devices, where fdt is used, is impossible to apply platform data
-without proper fdt node.
-
-This patch allow to use platform data in devices with fdt.
-
----
- drivers/w1/masters/w1-gpio.c | 7 +++----
- 1 file changed, 3 insertions(+), 4 deletions(-)
-
---- a/drivers/w1/masters/w1-gpio.c
-+++ b/drivers/w1/masters/w1-gpio.c
-@@ -76,7 +76,7 @@ static int w1_gpio_probe(struct platform
- enum gpiod_flags gflags = GPIOD_OUT_LOW_OPEN_DRAIN;
- int err;
-
-- if (of_have_populated_dt()) {
-+ if (of_have_populated_dt() && !dev_get_platdata(&pdev->dev)) {
- pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
- if (!pdata)
- return -ENOMEM;
+++ /dev/null
-Subject: libata: add ledtrig support
-
-This adds a LED trigger for each ATA port indicating disk activity.
-
-As this is needed only on specific platforms (NAS SoCs and such),
-these platforms should define ARCH_WANTS_LIBATA_LEDS if there
-are boards with LED(s) intended to indicate ATA disk activity and
-need the OS to take care of that.
-In that way, if not selected, LED trigger support not will be
-included in libata-core and both, codepaths and structures remain
-untouched.
-
----
- drivers/ata/Kconfig | 16 ++++++++++++++++
- drivers/ata/libata-core.c | 41 +++++++++++++++++++++++++++++++++++++++++
- include/linux/libata.h | 9 +++++++++
- 3 files changed, 66 insertions(+)
-
---- a/drivers/ata/Kconfig
-+++ b/drivers/ata/Kconfig
-@@ -67,6 +67,22 @@ config ATA_FORCE
-
- If unsure, say Y.
-
-+config ARCH_WANT_LIBATA_LEDS
-+ bool
-+
-+config ATA_LEDS
-+ bool "support ATA port LED triggers"
-+ depends on ARCH_WANT_LIBATA_LEDS
-+ select NEW_LEDS
-+ select LEDS_CLASS
-+ select LEDS_TRIGGERS
-+ default y
-+ help
-+ This option adds a LED trigger for each registered ATA port.
-+ It is used to drive disk activity leds connected via GPIO.
-+
-+ If unsure, say N.
-+
- config ATA_ACPI
- bool "ATA ACPI Support"
- depends on ACPI
---- a/drivers/ata/libata-core.c
-+++ b/drivers/ata/libata-core.c
-@@ -685,6 +685,17 @@ static inline void ata_set_tf_cdl(struct
- qc->flags |= ATA_QCFLAG_HAS_CDL | ATA_QCFLAG_RESULT_TF;
- }
-
-+#ifdef CONFIG_ATA_LEDS
-+#define LIBATA_BLINK_DELAY 20 /* ms */
-+static inline void ata_led_act(struct ata_port *ap)
-+{
-+ if (unlikely(!ap->ledtrig))
-+ return;
-+
-+ led_trigger_blink_oneshot(ap->ledtrig, LIBATA_BLINK_DELAY, LIBATA_BLINK_DELAY, 0);
-+}
-+#endif
-+
- /**
- * ata_build_rw_tf - Build ATA taskfile for given read/write request
- * @qc: Metadata associated with the taskfile to build
-@@ -4771,6 +4782,9 @@ void __ata_qc_complete(struct ata_queued
- link->active_tag = ATA_TAG_POISON;
- ap->nr_active_links--;
- }
-+#ifdef CONFIG_ATA_LEDS
-+ ata_led_act(ap);
-+#endif
-
- /* clear exclusive status */
- if (unlikely(qc->flags & ATA_QCFLAG_CLEAR_EXCL &&
-@@ -5502,6 +5516,9 @@ struct ata_port *ata_port_alloc(struct a
- ap->stats.unhandled_irq = 1;
- ap->stats.idle_irq = 1;
- #endif
-+#ifdef CONFIG_ATA_LEDS
-+ ap->ledtrig = kzalloc(sizeof(struct led_trigger), GFP_KERNEL);
-+#endif
- ata_sff_port_init(ap);
-
- return ap;
-@@ -5515,6 +5532,12 @@ void ata_port_free(struct ata_port *ap)
- kfree(ap->pmp_link);
- kfree(ap->slave_link);
- kfree(ap->ncq_sense_buf);
-+#ifdef CONFIG_ATA_LEDS
-+ if (ap->ledtrig) {
-+ led_trigger_unregister(ap->ledtrig);
-+ kfree(ap->ledtrig);
-+ };
-+#endif
- kfree(ap);
- }
- EXPORT_SYMBOL_GPL(ata_port_free);
-@@ -5937,7 +5960,23 @@ int ata_host_register(struct ata_host *h
- host->ports[i]->print_id = atomic_inc_return(&ata_print_id);
- host->ports[i]->local_port_no = i + 1;
- }
-+#ifdef CONFIG_ATA_LEDS
-+ for (i = 0; i < host->n_ports; i++) {
-+ if (unlikely(!host->ports[i]->ledtrig))
-+ continue;
-
-+ snprintf(host->ports[i]->ledtrig_name,
-+ sizeof(host->ports[i]->ledtrig_name), "ata%u",
-+ host->ports[i]->print_id);
-+
-+ host->ports[i]->ledtrig->name = host->ports[i]->ledtrig_name;
-+
-+ if (led_trigger_register(host->ports[i]->ledtrig)) {
-+ kfree(host->ports[i]->ledtrig);
-+ host->ports[i]->ledtrig = NULL;
-+ }
-+ }
-+#endif
- /* Create associated sysfs transport objects */
- for (i = 0; i < host->n_ports; i++) {
- rc = ata_tport_add(host->dev,host->ports[i]);
---- a/include/linux/libata.h
-+++ b/include/linux/libata.h
-@@ -23,6 +23,9 @@
- #include <linux/cdrom.h>
- #include <linux/sched.h>
- #include <linux/async.h>
-+#ifdef CONFIG_ATA_LEDS
-+#include <linux/leds.h>
-+#endif
-
- /*
- * Define if arch has non-standard setup. This is a _PCI_ standard
-@@ -875,6 +878,12 @@ struct ata_port {
- #ifdef CONFIG_ATA_ACPI
- struct ata_acpi_gtm __acpi_init_gtm; /* use ata_acpi_init_gtm() */
- #endif
-+
-+#ifdef CONFIG_ATA_LEDS
-+ struct led_trigger *ledtrig;
-+ char ledtrig_name[8];
-+#endif
-+
- /* owned by EH */
- u8 *ncq_sense_buf;
- u8 sector_buf[ATA_SECT_SIZE] ____cacheline_aligned;
+++ /dev/null
-From d6988cf1d16faac56899918bb2b1be8d85155e3f Mon Sep 17 00:00:00 2001
-Date: Sat, 20 Feb 2021 18:36:38 +0100
-Subject: [PATCH] hwrng: bcm2835: set quality to 1000
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-This allows devices without a high precission timer to reduce boot from >100s
-to <30s.
-
----
- drivers/char/hw_random/bcm2835-rng.c | 1 +
- 1 file changed, 1 insertion(+)
-
---- a/drivers/char/hw_random/bcm2835-rng.c
-+++ b/drivers/char/hw_random/bcm2835-rng.c
-@@ -171,6 +171,7 @@ static int bcm2835_rng_probe(struct plat
- priv->rng.init = bcm2835_rng_init;
- priv->rng.read = bcm2835_rng_read;
- priv->rng.cleanup = bcm2835_rng_cleanup;
-+ priv->rng.quality = 1000;
-
- if (dev_of_node(dev)) {
- rng_id = of_match_node(bcm2835_rng_of_match, dev->of_node);
+++ /dev/null
-From 663b9f99bb35dbc0c7b685f71ee3668a60d31320 Mon Sep 17 00:00:00 2001
-Date: Mon, 10 Jan 2022 02:02:00 +0100
-Subject: [PATCH] PCI: aardvark: Make main irq_chip structure a static driver
- structure
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Marc Zyngier says [1] that we should use struct irq_chip as a global
-static struct in the driver. Even though the structure currently
-contains a dynamic member (parent_device), Marc says [2] that he plans
-to kill it and make the structure completely static.
-
-We have already converted others irq_chip structures in this driver in
-this way, but we omitted this one because the .name member is
-dynamically created from device's name, and the name is displayed in
-sysfs, so changing it would break sysfs ABI.
-
-The rationale for changing the name (to "advk-INT") in spite of sysfs
-ABI, and thus allowing to convert to a static structure, is that after
-the other changes we made in this series, the IRQ chip is basically
-something different: it no logner generates ERR and PME interrupts (they
-are generated by emulated bridge's rp_irq_chip).
-
-
----
- drivers/pci/controller/pci-aardvark.c | 25 +++++++------------------
- 1 file changed, 7 insertions(+), 18 deletions(-)
-
---- a/drivers/pci/controller/pci-aardvark.c
-+++ b/drivers/pci/controller/pci-aardvark.c
-@@ -277,7 +277,6 @@ struct advk_pcie {
- u8 wins_count;
- struct irq_domain *rp_irq_domain;
- struct irq_domain *irq_domain;
-- struct irq_chip irq_chip;
- raw_spinlock_t irq_lock;
- struct irq_domain *msi_domain;
- struct irq_domain *msi_inner_domain;
-@@ -1426,14 +1425,19 @@ static void advk_pcie_irq_unmask(struct
- raw_spin_unlock_irqrestore(&pcie->irq_lock, flags);
- }
-
-+static struct irq_chip advk_irq_chip = {
-+ .name = "advk-INT",
-+ .irq_mask = advk_pcie_irq_mask,
-+ .irq_unmask = advk_pcie_irq_unmask,
-+};
-+
- static int advk_pcie_irq_map(struct irq_domain *h,
- unsigned int virq, irq_hw_number_t hwirq)
- {
- struct advk_pcie *pcie = h->host_data;
-
- irq_set_status_flags(virq, IRQ_LEVEL);
-- irq_set_chip_and_handler(virq, &pcie->irq_chip,
-- handle_level_irq);
-+ irq_set_chip_and_handler(virq, &advk_irq_chip, handle_level_irq);
- irq_set_chip_data(virq, pcie);
-
- return 0;
-@@ -1492,7 +1496,6 @@ static int advk_pcie_init_irq_domain(str
- struct device *dev = &pcie->pdev->dev;
- struct device_node *node = dev->of_node;
- struct device_node *pcie_intc_node;
-- struct irq_chip *irq_chip;
- int ret = 0;
-
- raw_spin_lock_init(&pcie->irq_lock);
-@@ -1503,28 +1506,14 @@ static int advk_pcie_init_irq_domain(str
- return -ENODEV;
- }
-
-- irq_chip = &pcie->irq_chip;
--
-- irq_chip->name = devm_kasprintf(dev, GFP_KERNEL, "%s-irq",
-- dev_name(dev));
-- if (!irq_chip->name) {
-- ret = -ENOMEM;
-- goto out_put_node;
-- }
--
-- irq_chip->irq_mask = advk_pcie_irq_mask;
-- irq_chip->irq_unmask = advk_pcie_irq_unmask;
--
- pcie->irq_domain =
- irq_domain_add_linear(pcie_intc_node, PCI_NUM_INTX,
- &advk_pcie_irq_domain_ops, pcie);
- if (!pcie->irq_domain) {
- dev_err(dev, "Failed to get a INTx IRQ domain\n");
- ret = -ENOMEM;
-- goto out_put_node;
- }
-
--out_put_node:
- of_node_put(pcie_intc_node);
- return ret;
- }
+++ /dev/null
-From df1357358eec062241bddd2995e7ef0ce86cf45a Mon Sep 17 00:00:00 2001
-X-Patchwork-Id: 13656881
-X-Mailer: git-send-email 2.25.1
-Precedence: bulk
-List-Id: <linux-usb.vger.kernel.org>
-Date: Tue, 7 May 2024 13:15:22 +0000
-Subject: [PATCH v7] usb: serial: add support for CH348
-
-The CH348 is an USB octo port serial adapter.
-The device multiplexes all 8 ports in the same pair of Bulk endpoints.
-Since there is no public datasheet, unfortunately it remains some magic values
-
----
- drivers/usb/serial/Kconfig | 9 +
- drivers/usb/serial/Makefile | 1 +
- drivers/usb/serial/ch348.c | 725 ++++++++++++++++++++++++++++++++++++
- 3 files changed, 735 insertions(+)
- create mode 100644 drivers/usb/serial/ch348.c
-
---- a/drivers/usb/serial/Kconfig
-+++ b/drivers/usb/serial/Kconfig
-@@ -112,6 +112,15 @@ config USB_SERIAL_CH341
- To compile this driver as a module, choose M here: the
- module will be called ch341.
-
-+config USB_SERIAL_CH348
-+ tristate "USB Winchiphead CH348 Octo Port Serial Driver"
-+ help
-+ Say Y here if you want to use a Winchiphead CH348 octo port
-+ USB to serial adapter.
-+
-+ To compile this driver as a module, choose M here: the
-+ module will be called ch348.
-+
- config USB_SERIAL_WHITEHEAT
- tristate "USB ConnectTech WhiteHEAT Serial Driver"
- select USB_EZUSB_FX2
---- a/drivers/usb/serial/Makefile
-+++ b/drivers/usb/serial/Makefile
-@@ -15,6 +15,7 @@ obj-$(CONFIG_USB_SERIAL_AIRCABLE) += ai
- obj-$(CONFIG_USB_SERIAL_ARK3116) += ark3116.o
- obj-$(CONFIG_USB_SERIAL_BELKIN) += belkin_sa.o
- obj-$(CONFIG_USB_SERIAL_CH341) += ch341.o
-+obj-$(CONFIG_USB_SERIAL_CH348) += ch348.o
- obj-$(CONFIG_USB_SERIAL_CP210X) += cp210x.o
- obj-$(CONFIG_USB_SERIAL_CYBERJACK) += cyberjack.o
- obj-$(CONFIG_USB_SERIAL_CYPRESS_M8) += cypress_m8.o
---- /dev/null
-+++ b/drivers/usb/serial/ch348.c
-@@ -0,0 +1,725 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/*
-+ * USB serial driver for USB to Octal UARTs chip ch348.
-+ *
-+ */
-+
-+#include <linux/completion.h>
-+#include <linux/errno.h>
-+#include <linux/init.h>
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/mutex.h>
-+#include <linux/overflow.h>
-+#include <linux/serial.h>
-+#include <linux/slab.h>
-+#include <linux/tty.h>
-+#include <linux/tty_driver.h>
-+#include <linux/tty_flip.h>
-+#include <linux/usb.h>
-+#include <linux/usb/serial.h>
-+
-+#define CH348_CMD_TIMEOUT 2000
-+
-+#define CH348_CTO_D 0x01
-+#define CH348_CTO_R 0x02
-+
-+#define CH348_CTI_C 0x10
-+#define CH348_CTI_DSR 0x20
-+#define CH348_CTI_R 0x40
-+#define CH348_CTI_DCD 0x80
-+
-+#define CH348_LO 0x02
-+#define CH348_LP 0x04
-+#define CH348_LF 0x08
-+#define CH348_LB 0x10
-+
-+#define CMD_W_R 0xC0
-+#define CMD_W_BR 0x80
-+
-+#define CMD_WB_E 0x90
-+#define CMD_RB_E 0xC0
-+
-+#define M_NOR 0x00
-+#define M_HF 0x03
-+
-+#define R_MOD 0x97
-+#define R_IO_D 0x98
-+#define R_IO_O 0x99
-+#define R_IO_I 0x9b
-+#define R_TM_O 0x9c
-+#define R_INIT 0xa1
-+
-+#define R_C1 0x01
-+#define R_C2 0x02
-+#define R_C4 0x04
-+#define R_C5 0x06
-+
-+#define R_II_B1 0x06
-+#define R_II_B2 0x02
-+#define R_II_B3 0x00
-+
-+#define CMD_VER 0x96
-+
-+#define CH348_RX_PORT_CHUNK_LENGTH 32
-+#define CH348_RX_PORT_MAX_LENGTH 30
-+
-+struct ch348_rxbuf {
-+ u8 port;
-+ u8 length;
-+ u8 data[CH348_RX_PORT_MAX_LENGTH];
-+} __packed;
-+
-+struct ch348_txbuf {
-+ u8 port;
-+ __le16 length;
-+ u8 data[];
-+} __packed;
-+
-+#define CH348_TX_HDRSIZE offsetof(struct ch348_txbuf, data)
-+
-+struct ch348_initbuf {
-+ u8 cmd;
-+ u8 reg;
-+ u8 port;
-+ __be32 baudrate;
-+ u8 format;
-+ u8 paritytype;
-+ u8 databits;
-+ u8 rate;
-+ u8 unknown;
-+} __packed;
-+
-+#define CH348_MAXPORT 8
-+
-+/*
-+ * The CH348 multiplexes rx & tx into a pair of Bulk USB endpoints for
-+ * the 8 serial ports, and another pair of Bulk USB endpoints to
-+ * set port settings and receive port status events.
-+ *
-+ * The USB serial cores ties every Bulk endpoints pairs to each ports,
-+ * but in our case it will set port 0 with the rx/tx endpoints
-+ * and port 1 with the setup/status endpoints.
-+ *
-+ * To still take advantage of the generic code, we (re-)initialize
-+ * the USB serial port structure with the correct USB endpoint
-+ * for read and write, and write proper process_read_urb()
-+ * and prepare_write_buffer() to correctly (de-)multiplex data.
-+ * Also we use a custom write() implementation to wait until the buffer
-+ * has been fully transmitted to prevent TX buffer overruns.
-+ */
-+
-+/*
-+ * struct ch348_port - per-port information
-+ * @uartmode: UART port current mode
-+ * @write_completion: completion event when the TX buffer has been written out
-+ */
-+struct ch348_port {
-+ u8 uartmode;
-+ struct completion write_completion;
-+};
-+
-+/*
-+ * struct ch348 - main container for all this driver information
-+ * @udev: pointer to the CH348 USB device
-+ * @ports: List of per-port information
-+ * @serial: pointer to the serial structure
-+ * @write_lock: protect against concurrent writes so we don't lose data
-+ * @cmd_ep: endpoint number for configure operations
-+ * @status_urb: URB for status
-+ * @status_buffer: buffer used by status_urb
-+ */
-+struct ch348 {
-+ struct usb_device *udev;
-+ struct ch348_port ports[CH348_MAXPORT];
-+ struct usb_serial *serial;
-+
-+ struct mutex write_lock;
-+
-+ int cmd_ep;
-+
-+ struct urb *status_urb;
-+ u8 status_buffer[];
-+};
-+
-+struct ch348_magic {
-+ u8 action;
-+ u8 reg;
-+ u8 control;
-+} __packed;
-+
-+struct ch348_status_entry {
-+ u8 portnum:4;
-+ u8 unused:4;
-+ u8 reg_iir;
-+ union {
-+ u8 lsr_signal;
-+ u8 modem_signal;
-+ u8 init_data[10];
-+ };
-+} __packed;
-+
-+static void ch348_process_status_urb(struct urb *urb)
-+{
-+ struct ch348_status_entry *status_entry;
-+ struct ch348 *ch348 = urb->context;
-+ int ret, status = urb->status;
-+ struct usb_serial_port *port;
-+ unsigned int i, status_len;
-+
-+ switch (status) {
-+ case 0:
-+ /* success */
-+ break;
-+ case -ECONNRESET:
-+ case -ENOENT:
-+ case -ESHUTDOWN:
-+ /* this urb is terminated, clean up */
-+ dev_dbg(&urb->dev->dev, "%s - urb shutting down with status: %d\n",
-+ __func__, status);
-+ return;
-+ default:
-+ dev_err(&urb->dev->dev, "%s - nonzero urb status received: %d\n",
-+ __func__, status);
-+ goto exit;
-+ }
-+
-+ if (urb->actual_length < 3) {
-+ dev_warn(&ch348->udev->dev,
-+ "Received too short status buffer with %u bytes\n",
-+ urb->actual_length);
-+ goto exit;
-+ }
-+
-+ for (i = 0; i < urb->actual_length;) {
-+ status_entry = urb->transfer_buffer + i;
-+
-+ if (status_entry->portnum >= CH348_MAXPORT) {
-+ dev_warn(&ch348->udev->dev,
-+ "Invalid port %d in status entry\n",
-+ status_entry->portnum);
-+ break;
-+ }
-+
-+ port = ch348->serial->port[status_entry->portnum];
-+ status_len = 3;
-+
-+ if (!status_entry->reg_iir) {
-+ dev_dbg(&port->dev, "Ignoring status with zero reg_iir\n");
-+ } else if (status_entry->reg_iir == R_INIT) {
-+ status_len = 12;
-+ } else if ((status_entry->reg_iir & 0x0f) == R_II_B1) {
-+ if (status_entry->lsr_signal & CH348_LO)
-+ port->icount.overrun++;
-+ if (status_entry->lsr_signal & CH348_LP)
-+ port->icount.parity++;
-+ if (status_entry->lsr_signal & CH348_LF)
-+ port->icount.frame++;
-+ if (status_entry->lsr_signal & CH348_LF)
-+ port->icount.brk++;
-+ } else if ((status_entry->reg_iir & 0x0f) == R_II_B2) {
-+ complete_all(&ch348->ports[status_entry->portnum].write_completion);
-+ } else {
-+ dev_warn(&port->dev,
-+ "Unsupported status with reg_iir 0x%02x\n",
-+ status_entry->reg_iir);
-+ }
-+
-+ usb_serial_debug_data(&port->dev, __func__, status_len,
-+ urb->transfer_buffer + i);
-+
-+ i += status_len;
-+ }
-+
-+exit:
-+ ret = usb_submit_urb(urb, GFP_ATOMIC);
-+ if (ret)
-+ dev_err(&urb->dev->dev, "%s - usb_submit_urb failed; %d\n",
-+ __func__, ret);
-+}
-+
-+/*
-+ * Some values came from vendor tree, and we have no meaning for them, this
-+ * function simply use them.
-+ */
-+static int ch348_do_magic(struct ch348 *ch348, int portnum, u8 action, u8 reg, u8 control)
-+{
-+ struct ch348_magic *buffer;
-+ int ret, len;
-+
-+ buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
-+ if (!buffer)
-+ return -ENOMEM;
-+
-+ if (portnum < 4)
-+ reg += 0x10 * portnum;
-+ else
-+ reg += 0x10 * (portnum - 4) + 0x08;
-+
-+ buffer->action = action;
-+ buffer->reg = reg;
-+ buffer->control = control;
-+
-+ ret = usb_bulk_msg(ch348->udev, ch348->cmd_ep, buffer, 3, &len,
-+ CH348_CMD_TIMEOUT);
-+ if (ret)
-+ dev_err(&ch348->udev->dev, "Failed to write magic err=%d\n", ret);
-+
-+ kfree(buffer);
-+
-+ return ret;
-+}
-+
-+static int ch348_configure(struct ch348 *ch348, int portnum)
-+{
-+ int ret;
-+
-+ ret = ch348_do_magic(ch348, portnum, CMD_W_R, R_C2, 0x87);
-+ if (ret)
-+ return ret;
-+
-+ return ch348_do_magic(ch348, portnum, CMD_W_R, R_C4, 0x08);
-+}
-+
-+static void ch348_process_read_urb(struct urb *urb)
-+{
-+ struct usb_serial_port *port = urb->context;
-+ struct ch348 *ch348 = usb_get_serial_data(port->serial);
-+ unsigned int portnum, usblen, i;
-+ struct ch348_rxbuf *rxb;
-+
-+ if (urb->actual_length < 2) {
-+ dev_dbg(&ch348->udev->dev, "Empty rx buffer\n");
-+ return;
-+ }
-+
-+ for (i = 0; i < urb->actual_length; i += CH348_RX_PORT_CHUNK_LENGTH) {
-+ rxb = urb->transfer_buffer + i;
-+ portnum = rxb->port;
-+ if (portnum >= CH348_MAXPORT) {
-+ dev_dbg(&ch348->udev->dev, "Invalid port %d\n", portnum);
-+ break;
-+ }
-+
-+ port = ch348->serial->port[portnum];
-+
-+ usblen = rxb->length;
-+ if (usblen > CH348_RX_PORT_MAX_LENGTH) {
-+ dev_dbg(&port->dev, "Invalid length %d for port %d\n",
-+ usblen, portnum);
-+ break;
-+ }
-+
-+ tty_insert_flip_string(&port->port, rxb->data, usblen);
-+ tty_flip_buffer_push(&port->port);
-+ port->icount.rx += usblen;
-+ usb_serial_debug_data(&port->dev, __func__, usblen, rxb->data);
-+ }
-+}
-+
-+static int ch348_prepare_write_buffer(struct usb_serial_port *port, void *dest, size_t size)
-+{
-+ struct ch348_txbuf *rxt = dest;
-+ int count;
-+
-+ count = kfifo_out_locked(&port->write_fifo, rxt->data,
-+ size - CH348_TX_HDRSIZE, &port->lock);
-+
-+ rxt->port = port->port_number;
-+ rxt->length = cpu_to_le16(count);
-+
-+ return count + CH348_TX_HDRSIZE;
-+}
-+
-+static int ch348_write(struct tty_struct *tty, struct usb_serial_port *port,
-+ const unsigned char *buf, int count)
-+{
-+ struct ch348 *ch348 = usb_get_serial_data(port->serial);
-+ struct ch348_port *ch348_port = &ch348->ports[port->port_number];
-+ int ret, max_tx_size;
-+
-+ if (tty_get_baud_rate(tty) < 9600 && count >= 128)
-+ /*
-+ * Writing larger buffers can take longer than the hardware
-+ * allows before discarding the write buffer. Limit the
-+ * transfer size in such cases.
-+ * These values have been found by empirical testing.
-+ */
-+ max_tx_size = 128;
-+ else
-+ /*
-+ * Only ingest as many bytes as we can transfer with one URB at
-+ * a time. Once an URB has been written we need to wait for the
-+ * R_II_B2 status event before we are allowed to send more data.
-+ * If we ingest more data then usb_serial_generic_write() will
-+ * internally try to process as much data as possible with any
-+ * number of URBs without giving us the chance to wait in
-+ * between transfers.
-+ */
-+ max_tx_size = port->bulk_out_size - CH348_TX_HDRSIZE;
-+
-+ reinit_completion(&ch348_port->write_completion);
-+
-+ mutex_lock(&ch348->write_lock);
-+
-+ /*
-+ * For any (remaining) bytes that we did not transfer TTY core will
-+ * call us again, with the buffer and count adjusted to the remaining
-+ * data.
-+ */
-+ ret = usb_serial_generic_write(tty, port, buf, min(count, max_tx_size));
-+
-+ mutex_unlock(&ch348->write_lock);
-+
-+ if (ret <= 0)
-+ return ret;
-+
-+ if (!wait_for_completion_interruptible_timeout(&ch348_port->write_completion,
-+ msecs_to_jiffies(CH348_CMD_TIMEOUT))) {
-+ dev_err_console(port, "Failed to wait for TX buffer flush\n");
-+ return -ETIMEDOUT;
-+ }
-+
-+ return ret;
-+}
-+
-+static int ch348_set_uartmode(struct ch348 *ch348, int portnum, u8 mode)
-+{
-+ int ret;
-+
-+ if (ch348->ports[portnum].uartmode == M_NOR && mode == M_HF) {
-+ ret = ch348_do_magic(ch348, portnum, CMD_W_BR, R_C4, 0x51);
-+ if (ret)
-+ return ret;
-+ ch348->ports[portnum].uartmode = M_HF;
-+ }
-+
-+ if (ch348->ports[portnum].uartmode == M_HF && mode == M_NOR) {
-+ ret = ch348_do_magic(ch348, portnum, CMD_W_BR, R_C4, 0x50);
-+ if (ret)
-+ return ret;
-+ ch348->ports[portnum].uartmode = M_NOR;
-+ }
-+ return 0;
-+}
-+
-+static void ch348_set_termios(struct tty_struct *tty, struct usb_serial_port *port,
-+ const struct ktermios *termios_old)
-+{
-+ struct ch348 *ch348 = usb_get_serial_data(port->serial);
-+ struct ktermios *termios = &tty->termios;
-+ int ret, portnum = port->port_number;
-+ struct ch348_initbuf *buffer;
-+ speed_t baudrate;
-+ u8 format;
-+
-+ if (termios_old && !tty_termios_hw_change(&tty->termios, termios_old))
-+ return;
-+
-+ buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
-+ if (!buffer) {
-+ if (termios_old)
-+ tty->termios = *termios_old;
-+ return;
-+ }
-+
-+ /*
-+ * The datasheet states that only baud rates in range of 1200..6000000
-+ * are supported. Tests however show that even baud rates as low as 50
-+ * and as high as 12000000 are working in practice.
-+ */
-+ baudrate = clamp(tty_get_baud_rate(tty), 50, 12000000);
-+
-+ format = termios->c_cflag & CSTOPB ? 2 : 1;
-+
-+ buffer->paritytype = 0;
-+ if (termios->c_cflag & PARENB) {
-+ if (termios->c_cflag & PARODD)
-+ buffer->paritytype += 1;
-+ else
-+ buffer->paritytype += 2;
-+ if (termios->c_cflag & CMSPAR)
-+ buffer->paritytype += 2;
-+ }
-+
-+ switch (C_CSIZE(tty)) {
-+ case CS5:
-+ buffer->databits = 5;
-+ break;
-+ case CS6:
-+ buffer->databits = 6;
-+ break;
-+ case CS7:
-+ buffer->databits = 7;
-+ break;
-+ case CS8:
-+ default:
-+ buffer->databits = 8;
-+ break;
-+ }
-+ buffer->cmd = CMD_WB_E | (portnum & 0x0F);
-+ buffer->reg = R_INIT;
-+ buffer->port = portnum;
-+ buffer->baudrate = cpu_to_be32(baudrate);
-+
-+ if (format == 2)
-+ buffer->format = 0x02;
-+ else if (format == 1)
-+ buffer->format = 0x00;
-+
-+ buffer->rate = max_t(speed_t, 5, (10000 * 15 / baudrate) + 1);
-+
-+ ret = usb_bulk_msg(ch348->udev, ch348->cmd_ep, buffer,
-+ sizeof(*buffer), NULL, CH348_CMD_TIMEOUT);
-+ if (ret < 0) {
-+ dev_err(&ch348->udev->dev, "Failed to change line settings: err=%d\n",
-+ ret);
-+ goto out;
-+ }
-+
-+ ret = ch348_do_magic(ch348, portnum, CMD_W_R, R_C1, 0x0F);
-+ if (ret < 0)
-+ goto out;
-+
-+ if (C_CRTSCTS(tty))
-+ ret = ch348_set_uartmode(ch348, portnum, M_HF);
-+ else
-+ ret = ch348_set_uartmode(ch348, portnum, M_NOR);
-+
-+out:
-+ kfree(buffer);
-+}
-+
-+static int ch348_open(struct tty_struct *tty, struct usb_serial_port *port)
-+{
-+ struct ch348 *ch348 = usb_get_serial_data(port->serial);
-+ int ret;
-+
-+ if (tty)
-+ ch348_set_termios(tty, port, NULL);
-+
-+ ret = ch348_configure(ch348, port->port_number);
-+ if (ret) {
-+ dev_err(&ch348->udev->dev, "Fail to configure err=%d\n", ret);
-+ return ret;
-+ }
-+
-+ return usb_serial_generic_open(tty, port);
-+}
-+
-+static int ch348_attach(struct usb_serial *serial)
-+{
-+ struct usb_endpoint_descriptor *epcmd, *epstatus;
-+ struct usb_serial_port *port0 = serial->port[1];
-+ struct usb_device *usb_dev = serial->dev;
-+ int status_buffer_size, i, ret;
-+ struct usb_interface *intf;
-+ struct ch348 *ch348;
-+
-+ intf = usb_ifnum_to_if(usb_dev, 0);
-+ epstatus = &intf->cur_altsetting->endpoint[2].desc;
-+ epcmd = &intf->cur_altsetting->endpoint[3].desc;
-+
-+ status_buffer_size = usb_endpoint_maxp(epstatus);
-+
-+ ch348 = kzalloc(struct_size(ch348, status_buffer, status_buffer_size),
-+ GFP_KERNEL);
-+ if (!ch348)
-+ return -ENOMEM;
-+
-+ usb_set_serial_data(serial, ch348);
-+
-+ ch348->udev = serial->dev;
-+ ch348->serial = serial;
-+ mutex_init(&ch348->write_lock);
-+
-+ for (i = 0; i < CH348_MAXPORT; i++)
-+ init_completion(&ch348->ports[i].write_completion);
-+
-+ ch348->status_urb = usb_alloc_urb(0, GFP_KERNEL);
-+ if (!ch348->status_urb) {
-+ ret = -ENOMEM;
-+ goto err_free_ch348;
-+ }
-+
-+ usb_fill_bulk_urb(ch348->status_urb, ch348->udev,
-+ usb_rcvbulkpipe(ch348->udev, epstatus->bEndpointAddress),
-+ ch348->status_buffer, status_buffer_size,
-+ ch348_process_status_urb, ch348);
-+
-+ ret = usb_submit_urb(ch348->status_urb, GFP_KERNEL);
-+ if (ret) {
-+ dev_err(&ch348->udev->dev,
-+ "%s - failed to submit status/interrupt urb %i\n",
-+ __func__, ret);
-+ goto err_free_status_urb;
-+ }
-+
-+ ret = usb_serial_generic_submit_read_urbs(port0, GFP_KERNEL);
-+ if (ret)
-+ goto err_kill_status_urb;
-+
-+ ch348->cmd_ep = usb_sndbulkpipe(usb_dev, epcmd->bEndpointAddress);
-+
-+ return 0;
-+
-+err_kill_status_urb:
-+ usb_kill_urb(ch348->status_urb);
-+err_free_status_urb:
-+ usb_free_urb(ch348->status_urb);
-+err_free_ch348:
-+ kfree(ch348);
-+ return ret;
-+}
-+
-+static void ch348_release(struct usb_serial *serial)
-+{
-+ struct ch348 *ch348 = usb_get_serial_data(serial);
-+
-+ usb_kill_urb(ch348->status_urb);
-+ usb_free_urb(ch348->status_urb);
-+
-+ kfree(ch348);
-+}
-+
-+static void ch348_print_version(struct usb_serial *serial)
-+{
-+ u8 *version_buf;
-+ int ret;
-+
-+ version_buf = kzalloc(4, GFP_KERNEL);
-+ if (!version_buf)
-+ return;
-+
-+ ret = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
-+ CMD_VER,
-+ USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
-+ 0, 0, version_buf, 4, CH348_CMD_TIMEOUT);
-+ if (ret < 0)
-+ dev_dbg(&serial->dev->dev, "Failed to read CMD_VER: %d\n", ret);
-+ else
-+ dev_info(&serial->dev->dev, "Found WCH CH348%s\n",
-+ (version_buf[1] & 0x80) ? "Q" : "L");
-+
-+ kfree(version_buf);
-+}
-+
-+static int ch348_probe(struct usb_serial *serial, const struct usb_device_id *id)
-+{
-+ struct usb_endpoint_descriptor *epread, *epwrite, *epstatus, *epcmd;
-+ struct usb_device *usb_dev = serial->dev;
-+ struct usb_interface *intf;
-+ int ret;
-+
-+ intf = usb_ifnum_to_if(usb_dev, 0);
-+
-+ ret = usb_find_common_endpoints(intf->cur_altsetting, &epread, &epwrite,
-+ NULL, NULL);
-+ if (ret) {
-+ dev_err(&serial->dev->dev, "Failed to find basic endpoints ret=%d\n", ret);
-+ return ret;
-+ }
-+
-+ epstatus = &intf->cur_altsetting->endpoint[2].desc;
-+ if (!usb_endpoint_is_bulk_in(epstatus)) {
-+ dev_err(&serial->dev->dev, "Missing second bulk in (STATUS/INT)\n");
-+ return -ENODEV;
-+ }
-+
-+ epcmd = &intf->cur_altsetting->endpoint[3].desc;
-+ if (!usb_endpoint_is_bulk_out(epcmd)) {
-+ dev_err(&serial->dev->dev, "Missing second bulk out (CMD)\n");
-+ return -ENODEV;
-+ }
-+
-+ ch348_print_version(serial);
-+
-+ return 0;
-+}
-+
-+static int ch348_calc_num_ports(struct usb_serial *serial,
-+ struct usb_serial_endpoints *epds)
-+{
-+ int i;
-+
-+ for (i = 1; i < CH348_MAXPORT; ++i) {
-+ epds->bulk_out[i] = epds->bulk_out[0];
-+ epds->bulk_in[i] = epds->bulk_in[0];
-+ }
-+
-+ epds->num_bulk_out = CH348_MAXPORT;
-+ epds->num_bulk_in = CH348_MAXPORT;
-+
-+ return CH348_MAXPORT;
-+}
-+
-+static int ch348_suspend(struct usb_serial *serial, pm_message_t message)
-+{
-+ struct ch348 *ch348 = usb_get_serial_data(serial);
-+
-+ usb_kill_urb(ch348->status_urb);
-+
-+ return 0;
-+}
-+
-+static int ch348_resume(struct usb_serial *serial)
-+{
-+ struct ch348 *ch348 = usb_get_serial_data(serial);
-+ int ret;
-+
-+ ret = usb_submit_urb(ch348->status_urb, GFP_KERNEL);
-+ if (ret) {
-+ dev_err(&ch348->udev->dev,
-+ "%s - failed to submit status/interrupt urb %i\n",
-+ __func__, ret);
-+ return ret;
-+ }
-+
-+ ret = usb_serial_generic_resume(serial);
-+ if (ret)
-+ usb_kill_urb(ch348->status_urb);
-+
-+ return ret;
-+}
-+
-+static const struct usb_device_id ch348_ids[] = {
-+ { USB_DEVICE(0x1a86, 0x55d9), },
-+ { /* sentinel */ }
-+};
-+
-+MODULE_DEVICE_TABLE(usb, ch348_ids);
-+
-+static struct usb_serial_driver ch348_device = {
-+ .driver = {
-+ .owner = THIS_MODULE,
-+ .name = "ch348",
-+ },
-+ .id_table = ch348_ids,
-+ .num_ports = CH348_MAXPORT,
-+ .num_bulk_in = 1,
-+ .num_bulk_out = 1,
-+ .open = ch348_open,
-+ .set_termios = ch348_set_termios,
-+ .process_read_urb = ch348_process_read_urb,
-+ .prepare_write_buffer = ch348_prepare_write_buffer,
-+ .write = ch348_write,
-+ .probe = ch348_probe,
-+ .calc_num_ports = ch348_calc_num_ports,
-+ .attach = ch348_attach,
-+ .release = ch348_release,
-+ .suspend = ch348_suspend,
-+ .resume = ch348_resume,
-+};
-+
-+static struct usb_serial_driver * const serial_drivers[] = {
-+ &ch348_device, NULL
-+};
-+
-+module_usb_serial_driver(serial_drivers, ch348_ids);
-+
-+MODULE_DESCRIPTION("USB CH348 Octo port serial converter driver");
-+MODULE_LICENSE("GPL");
+++ /dev/null
-Subject: [PATCH v11 2/3] dt-bindings: leds: Add LED1202 LED Controller
-Date: Wed, 18 Dec 2024 18:33:58 +0000 [thread overview]
-
-The LED1202 is a 12-channel low quiescent current LED driver with:
- * Supply range from 2.6 V to 5 V
- * 20 mA current capability per channel
- * 1.8 V compatible I2C control interface
- * 8-bit analog dimming individual control
- * 12-bit local PWM resolution
- * 8 programmable patterns
-
-If the led node is present in the controller then the channel is
-set to active.
-
----
- v1: https://lore.kernel.org/lkml/ZnCnnQfwuRueCIQ0@admins-Air/T/
- v2: https://lore.kernel.org/all/ZniNdGgKyUMV-hjq@admins-Air/T/
- v3: https://lore.kernel.org/all/ZniNdGgKyUMV-hjq@admins-Air/T/
-
- Changes in v4:
- - remove label property, use devm_led_classdev_register_ext instead
- Changes in v3:
- - remove active property
- Changes in v2:
- - renamed label to remove color from it
- - add color property for each node
- - add function and function-enumerator property for each node
-
- .../devicetree/bindings/leds/st,led1202.yaml | 132 ++++++++++++++++++
- 1 file changed, 132 insertions(+)
- create mode 100644 Documentation/devicetree/bindings/leds/st,led1202.yaml
-
---- /dev/null
-+++ b/Documentation/devicetree/bindings/leds/st,led1202.yaml
-@@ -0,0 +1,132 @@
-+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
-+%YAML 1.2
-+---
-+$id: http://devicetree.org/schemas/leds/st,led1202.yaml#
-+$schema: http://devicetree.org/meta-schemas/core.yaml#
-+
-+title: ST LED1202 LED controllers
-+
-+maintainers:
-+
-+description: |
-+ The LED1202 is a 12-channel low quiescent current LED controller
-+ programmable via I2C; The output current can be adjusted separately
-+ for each channel by 8-bit analog and 12-bit digital dimming control.
-+ Datasheet available at
-+ https://www.st.com/en/power-management/led1202.html
-+
-+properties:
-+ compatible:
-+ const: st,led1202
-+
-+ reg:
-+ maxItems: 1
-+
-+ "#address-cells":
-+ const: 1
-+
-+ "#size-cells":
-+ const: 0
-+
-+patternProperties:
-+ "^led@[0-9a-f]$":
-+ type: object
-+ $ref: common.yaml#
-+ unevaluatedProperties: false
-+
-+ properties:
-+ reg:
-+ minimum: 0
-+ maximum: 11
-+
-+ required:
-+ - reg
-+
-+required:
-+ - compatible
-+ - reg
-+ - "#address-cells"
-+ - "#size-cells"
-+
-+additionalProperties: false
-+
-+examples:
-+ - |
-+ #include <dt-bindings/leds/common.h>
-+
-+ i2c {
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ led-controller@58 {
-+ compatible = "st,led1202";
-+ reg = <0x58>;
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ led@0 {
-+ reg = <0x0>;
-+ function = LED_FUNCTION_STATUS;
-+ color = <LED_COLOR_ID_RED>;
-+ function-enumerator = <1>;
-+ };
-+
-+ led@1 {
-+ reg = <0x1>;
-+ function = LED_FUNCTION_STATUS;
-+ color = <LED_COLOR_ID_GREEN>;
-+ function-enumerator = <2>;
-+ };
-+
-+ led@2 {
-+ reg = <0x2>;
-+ function = LED_FUNCTION_STATUS;
-+ color = <LED_COLOR_ID_BLUE>;
-+ function-enumerator = <3>;
-+ };
-+
-+ led@3 {
-+ reg = <0x3>;
-+ function = LED_FUNCTION_STATUS;
-+ color = <LED_COLOR_ID_RED>;
-+ function-enumerator = <4>;
-+ };
-+
-+ led@4 {
-+ reg = <0x4>;
-+ function = LED_FUNCTION_STATUS;
-+ color = <LED_COLOR_ID_GREEN>;
-+ function-enumerator = <5>;
-+ };
-+
-+ led@5 {
-+ reg = <0x5>;
-+ function = LED_FUNCTION_STATUS;
-+ color = <LED_COLOR_ID_BLUE>;
-+ function-enumerator = <6>;
-+ };
-+
-+ led@6 {
-+ reg = <0x6>;
-+ function = LED_FUNCTION_STATUS;
-+ color = <LED_COLOR_ID_RED>;
-+ function-enumerator = <7>;
-+ };
-+
-+ led@7 {
-+ reg = <0x7>;
-+ function = LED_FUNCTION_STATUS;
-+ color = <LED_COLOR_ID_GREEN>;
-+ function-enumerator = <8>;
-+ };
-+
-+ led@8 {
-+ reg = <0x8>;
-+ function = LED_FUNCTION_STATUS;
-+ color = <LED_COLOR_ID_BLUE>;
-+ function-enumerator = <9>;
-+ };
-+ };
-+ };
-+...
+++ /dev/null
-Subject: [PATCH v11 3/3] leds: Add LED1202 I2C driver
-Date: Wed, 18 Dec 2024 18:33:59 +0000 [thread overview]
-
-The output current can be adjusted separately for each channel by 8-bit
-analog (current sink input) and 12-bit digital (PWM) dimming control. The
-LED1202 implements 12 low-side current generators with independent dimming
-control.
-Internal volatile memory allows the user to store up to 8 different patterns,
-each pattern is a particular output configuration in terms of PWM
-duty-cycle (on 4096 steps). Analog dimming (on 256 steps) is per channel but
-common to all patterns. Each device tree LED node will have a corresponding
-entry in /sys/class/leds with the label name. The brightness property
-corresponds to the per channel analog dimming, while the patterns[1-8] to the
-PWM dimming control.
-
----
- Changes in v10:
- - update description help in Kconfig
- - move st1202_led and st1202_chip into one line, declaration and definition
- Changes in v9:
- - log errors directly in st1202_write_reg and st1202_read_reg
- - use mutex guards instead of lock/unlock
- - remove i2c_set_clientdata
- Changes in v7:
- - fix st1202_brightness_get() error: uninitialized symbol 'value'
- Changes in v6:
- - fix build error
- Changes in v5:
- - remove unused macros
- - switch to using devm_led_classdev_register_ext (struct st1202_led update)
- - add prescalar_to_milliseconds (convert [22..5660]ms to [0..255] reg value)
- - remove register range check in dt_init (range protected by yaml)
- - address all review comments in v4
- Changes in v4:
- - Remove attributes/extended attributes implementation
- - Use /sys/class/leds/<led>/hw_pattern (Pavel suggestion)
- - Implement review findings of Christophe JAILLET
- Changes in v3:
- - Rename all ll1202 to st1202, including driver file name
- - Convert all magic numbers to defines
- - Refactor the show/store callbacks as per Lee's and Thomas's review
- - Remove ll1202_get_channel and use dev_ext_attributes instead
- - Log all error values for all the functions
- - Use sysfs_emit for show callbacks
- Changes in v2:
- - Fix build error for device_attribute modes
-
- drivers/leds/Kconfig | 10 +
- drivers/leds/Makefile | 1 +
- drivers/leds/leds-st1202.c | 416 +++++++++++++++++++++++++++++++++++++
- 3 files changed, 427 insertions(+)
- create mode 100644 drivers/leds/leds-st1202.c
-
---- a/drivers/leds/Kconfig
-+++ b/drivers/leds/Kconfig
-@@ -865,6 +865,16 @@ config LEDS_LM36274
- Say Y to enable the LM36274 LED driver for TI LMU devices.
- This supports the LED device LM36274.
-
-+config LEDS_ST1202
-+ tristate "LED Support for STMicroelectronics LED1202 I2C chips"
-+ depends on LEDS_CLASS
-+ depends on I2C
-+ depends on OF
-+ select LEDS_TRIGGERS
-+ help
-+ Say Y to enable support for LEDs connected to LED1202
-+ LED driver chips accessed via the I2C bus.
-+
- config LEDS_TPS6105X
- tristate "LED support for TI TPS6105X"
- depends on LEDS_CLASS
---- a/drivers/leds/Makefile
-+++ b/drivers/leds/Makefile
-@@ -78,6 +78,7 @@ obj-$(CONFIG_LEDS_POWERNV) += leds-powe
- obj-$(CONFIG_LEDS_PWM) += leds-pwm.o
- obj-$(CONFIG_LEDS_REGULATOR) += leds-regulator.o
- obj-$(CONFIG_LEDS_SC27XX_BLTC) += leds-sc27xx-bltc.o
-+obj-$(CONFIG_LEDS_ST1202) += leds-st1202.o
- obj-$(CONFIG_LEDS_SUNFIRE) += leds-sunfire.o
- obj-$(CONFIG_LEDS_SYSCON) += leds-syscon.o
- obj-$(CONFIG_LEDS_TCA6507) += leds-tca6507.o
---- /dev/null
-+++ b/drivers/leds/leds-st1202.c
-@@ -0,0 +1,416 @@
-+// SPDX-License-Identifier: GPL-2.0-only
-+/*
-+ * LED driver for STMicroelectronics LED1202 chip
-+ *
-+ * Copyright (C) 2024 Remote-Tech Ltd. UK
-+ */
-+
-+#include <linux/cleanup.h>
-+#include <linux/ctype.h>
-+#include <linux/delay.h>
-+#include <linux/err.h>
-+#include <linux/gpio.h>
-+#include <linux/i2c.h>
-+#include <linux/leds.h>
-+#include <linux/module.h>
-+#include <linux/slab.h>
-+#include <linux/string.h>
-+
-+#define ST1202_CHAN_DISABLE_ALL 0x00
-+#define ST1202_CHAN_ENABLE_HIGH 0x03
-+#define ST1202_CHAN_ENABLE_LOW 0x02
-+#define ST1202_CONFIG_REG 0x04
-+/* PATS: Pattern sequence feature enable */
-+#define ST1202_CONFIG_REG_PATS BIT(7)
-+/* PATSR: Pattern sequence runs (self-clear when sequence is finished) */
-+#define ST1202_CONFIG_REG_PATSR BIT(6)
-+#define ST1202_CONFIG_REG_SHFT BIT(3)
-+#define ST1202_DEV_ENABLE 0x01
-+#define ST1202_DEV_ENABLE_ON BIT(0)
-+#define ST1202_DEV_ENABLE_RESET BIT(7)
-+#define ST1202_DEVICE_ID 0x00
-+#define ST1202_ILED_REG0 0x09
-+#define ST1202_MAX_LEDS 12
-+#define ST1202_MAX_PATTERNS 8
-+#define ST1202_MILLIS_PATTERN_DUR_MAX 5660
-+#define ST1202_MILLIS_PATTERN_DUR_MIN 22
-+#define ST1202_PATTERN_DUR 0x16
-+#define ST1202_PATTERN_PWM 0x1E
-+#define ST1202_PATTERN_REP 0x15
-+
-+struct st1202_led {
-+ struct fwnode_handle *fwnode;
-+ struct led_classdev led_cdev;
-+ struct st1202_chip *chip;
-+ bool is_active;
-+ int led_num;
-+};
-+
-+struct st1202_chip {
-+ struct i2c_client *client;
-+ struct mutex lock;
-+ struct st1202_led leds[ST1202_MAX_LEDS];
-+};
-+
-+static struct st1202_led *cdev_to_st1202_led(struct led_classdev *cdev)
-+{
-+ return container_of(cdev, struct st1202_led, led_cdev);
-+}
-+
-+static int st1202_read_reg(struct st1202_chip *chip, int reg, uint8_t *val)
-+{
-+ struct device *dev = &chip->client->dev;
-+ int ret;
-+
-+ ret = i2c_smbus_read_byte_data(chip->client, reg);
-+ if (ret < 0) {
-+ dev_err(dev, "Failed to read register [0x%x]: %d\n", reg, ret);
-+ return ret;
-+ }
-+
-+ *val = (uint8_t)ret;
-+ return 0;
-+}
-+
-+static int st1202_write_reg(struct st1202_chip *chip, int reg, uint8_t val)
-+{
-+ struct device *dev = &chip->client->dev;
-+ int ret;
-+
-+ ret = i2c_smbus_write_byte_data(chip->client, reg, val);
-+ if (ret != 0)
-+ dev_err(dev, "Failed to write %d to register [0x%x]: %d\n", val, reg, ret);
-+
-+ return ret;
-+}
-+
-+static uint8_t st1202_prescalar_to_miliseconds(unsigned int value)
-+{
-+ return value / ST1202_MILLIS_PATTERN_DUR_MIN - 1;
-+}
-+
-+static int st1202_pwm_pattern_write(struct st1202_chip *chip, int led_num,
-+ int pattern, unsigned int value)
-+{
-+ u8 value_l, value_h;
-+ int ret;
-+
-+ value_l = (u8)value;
-+ value_h = (u8)(value >> 8);
-+
-+ /*
-+ * Datasheet: Register address low = 1Eh + 2*(xh) + 18h*(yh),
-+ * where x is the channel number (led number) in hexadecimal (x = 00h .. 0Bh)
-+ * and y is the pattern number in hexadecimal (y = 00h .. 07h)
-+ */
-+ ret = st1202_write_reg(chip, (ST1202_PATTERN_PWM + (led_num * 2) + 0x18 * pattern),
-+ value_l);
-+ if (ret != 0)
-+ return ret;
-+
-+ /*
-+ * Datasheet: Register address high = 1Eh + 01h + 2(xh) +18h*(yh),
-+ * where x is the channel number in hexadecimal (x = 00h .. 0Bh)
-+ * and y is the pattern number in hexadecimal (y = 00h .. 07h)
-+ */
-+ ret = st1202_write_reg(chip, (ST1202_PATTERN_PWM + 0x1 + (led_num * 2) + 0x18 * pattern),
-+ value_h);
-+ if (ret != 0)
-+ return ret;
-+
-+ return 0;
-+}
-+
-+static int st1202_duration_pattern_write(struct st1202_chip *chip, int pattern,
-+ unsigned int value)
-+{
-+ return st1202_write_reg(chip, (ST1202_PATTERN_DUR + pattern),
-+ st1202_prescalar_to_miliseconds(value));
-+}
-+
-+static void st1202_brightness_set(struct led_classdev *led_cdev,
-+ enum led_brightness value)
-+{
-+ struct st1202_led *led = cdev_to_st1202_led(led_cdev);
-+ struct st1202_chip *chip = led->chip;
-+
-+ guard(mutex)(&chip->lock);
-+
-+ st1202_write_reg(chip, ST1202_ILED_REG0 + led->led_num, value);
-+}
-+
-+static enum led_brightness st1202_brightness_get(struct led_classdev *led_cdev)
-+{
-+ struct st1202_led *led = cdev_to_st1202_led(led_cdev);
-+ struct st1202_chip *chip = led->chip;
-+ u8 value = 0;
-+
-+ guard(mutex)(&chip->lock);
-+
-+ st1202_read_reg(chip, ST1202_ILED_REG0 + led->led_num, &value);
-+
-+ return value;
-+}
-+
-+static int st1202_channel_set(struct st1202_chip *chip, int led_num, bool active)
-+{
-+ u8 chan_low, chan_high;
-+ int ret;
-+
-+ guard(mutex)(&chip->lock);
-+
-+ if (led_num <= 7) {
-+ ret = st1202_read_reg(chip, ST1202_CHAN_ENABLE_LOW, &chan_low);
-+ if (ret < 0)
-+ return ret;
-+
-+ chan_low = active ? chan_low | BIT(led_num) : chan_low & ~BIT(led_num);
-+
-+ ret = st1202_write_reg(chip, ST1202_CHAN_ENABLE_LOW, chan_low);
-+ if (ret < 0)
-+ return ret;
-+
-+ } else {
-+ ret = st1202_read_reg(chip, ST1202_CHAN_ENABLE_HIGH, &chan_high);
-+ if (ret < 0)
-+ return ret;
-+
-+ chan_high = active ? chan_high | (BIT(led_num) >> 8) :
-+ chan_high & ~(BIT(led_num) >> 8);
-+
-+ ret = st1202_write_reg(chip, ST1202_CHAN_ENABLE_HIGH, chan_high);
-+ if (ret < 0)
-+ return ret;
-+ }
-+
-+ return 0;
-+}
-+
-+static int st1202_led_set(struct led_classdev *ldev, enum led_brightness value)
-+{
-+ struct st1202_led *led = cdev_to_st1202_led(ldev);
-+ struct st1202_chip *chip = led->chip;
-+
-+ return st1202_channel_set(chip, led->led_num, value == LED_OFF ? false : true);
-+}
-+
-+static int st1202_led_pattern_clear(struct led_classdev *ldev)
-+{
-+ struct st1202_led *led = cdev_to_st1202_led(ldev);
-+ struct st1202_chip *chip = led->chip;
-+ int ret;
-+
-+ guard(mutex)(&chip->lock);
-+
-+ for (int patt = 0; patt < ST1202_MAX_PATTERNS; patt++) {
-+ ret = st1202_pwm_pattern_write(chip, led->led_num, patt, LED_OFF);
-+ if (ret != 0)
-+ return ret;
-+
-+ ret = st1202_duration_pattern_write(chip, patt, ST1202_MILLIS_PATTERN_DUR_MIN);
-+ if (ret != 0)
-+ return ret;
-+ }
-+
-+ return 0;
-+}
-+
-+static int st1202_led_pattern_set(struct led_classdev *ldev,
-+ struct led_pattern *pattern,
-+ u32 len, int repeat)
-+{
-+ struct st1202_led *led = cdev_to_st1202_led(ldev);
-+ struct st1202_chip *chip = led->chip;
-+ int ret;
-+
-+ if (len > ST1202_MAX_PATTERNS)
-+ return -EINVAL;
-+
-+ guard(mutex)(&chip->lock);
-+
-+ for (int patt = 0; patt < len; patt++) {
-+ if (pattern[patt].delta_t < ST1202_MILLIS_PATTERN_DUR_MIN ||
-+ pattern[patt].delta_t > ST1202_MILLIS_PATTERN_DUR_MAX)
-+ return -EINVAL;
-+
-+ ret = st1202_pwm_pattern_write(chip, led->led_num, patt, pattern[patt].brightness);
-+ if (ret != 0)
-+ return ret;
-+
-+ ret = st1202_duration_pattern_write(chip, patt, pattern[patt].delta_t);
-+ if (ret != 0)
-+ return ret;
-+ }
-+
-+ ret = st1202_write_reg(chip, ST1202_PATTERN_REP, repeat);
-+ if (ret != 0)
-+ return ret;
-+
-+ ret = st1202_write_reg(chip, ST1202_CONFIG_REG, (ST1202_CONFIG_REG_PATSR |
-+ ST1202_CONFIG_REG_PATS | ST1202_CONFIG_REG_SHFT));
-+ if (ret != 0)
-+ return ret;
-+
-+ return 0;
-+}
-+
-+static int st1202_dt_init(struct st1202_chip *chip)
-+{
-+ struct device *dev = &chip->client->dev;
-+ struct st1202_led *led;
-+ int err, reg;
-+
-+ for_each_available_child_of_node_scoped(dev_of_node(dev), child) {
-+ struct led_init_data init_data = {};
-+
-+ err = of_property_read_u32(child, "reg", ®);
-+ if (err)
-+ return dev_err_probe(dev, err, "Invalid register\n");
-+
-+ led = &chip->leds[reg];
-+ led->is_active = true;
-+ led->fwnode = of_fwnode_handle(child);
-+
-+ led->led_cdev.max_brightness = U8_MAX;
-+ led->led_cdev.brightness_set_blocking = st1202_led_set;
-+ led->led_cdev.pattern_set = st1202_led_pattern_set;
-+ led->led_cdev.pattern_clear = st1202_led_pattern_clear;
-+ led->led_cdev.default_trigger = "pattern";
-+
-+ init_data.fwnode = led->fwnode;
-+ init_data.devicename = "st1202";
-+ init_data.default_label = ":";
-+
-+ err = devm_led_classdev_register_ext(dev, &led->led_cdev, &init_data);
-+ if (err < 0)
-+ return dev_err_probe(dev, err, "Failed to register LED class device\n");
-+
-+ led->led_cdev.brightness_set = st1202_brightness_set;
-+ led->led_cdev.brightness_get = st1202_brightness_get;
-+ }
-+
-+ return 0;
-+}
-+
-+static int st1202_setup(struct st1202_chip *chip)
-+{
-+ int ret;
-+
-+ guard(mutex)(&chip->lock);
-+
-+ /*
-+ * Once the supply voltage is applied, the LED1202 executes some internal checks,
-+ * afterwords it stops the oscillator and puts the internal LDO in quiescent mode.
-+ * To start the device, EN bit must be set inside the “Device Enable” register at
-+ * address 01h. As soon as EN is set, the LED1202 loads the adjustment parameters
-+ * from the internal non-volatile memory and performs an auto-calibration procedure
-+ * in order to increase the output current precision.
-+ * Such initialization lasts about 6.5 ms.
-+ */
-+
-+ /* Reset the chip during setup */
-+ ret = st1202_write_reg(chip, ST1202_DEV_ENABLE, ST1202_DEV_ENABLE_RESET);
-+ if (ret < 0)
-+ return ret;
-+
-+ /* Enable phase-shift delay feature */
-+ ret = st1202_write_reg(chip, ST1202_CONFIG_REG, ST1202_CONFIG_REG_SHFT);
-+ if (ret < 0)
-+ return ret;
-+
-+ /* Enable the device */
-+ ret = st1202_write_reg(chip, ST1202_DEV_ENABLE, ST1202_DEV_ENABLE_ON);
-+ if (ret < 0)
-+ return ret;
-+
-+ /* Duration of initialization */
-+ usleep_range(6500, 10000);
-+
-+ /* Deactivate all LEDS (channels) and activate only the ones found in Device Tree */
-+ ret = st1202_write_reg(chip, ST1202_CHAN_ENABLE_LOW, ST1202_CHAN_DISABLE_ALL);
-+ if (ret < 0)
-+ return ret;
-+
-+ ret = st1202_write_reg(chip, ST1202_CHAN_ENABLE_HIGH, ST1202_CHAN_DISABLE_ALL);
-+ if (ret < 0)
-+ return ret;
-+
-+ ret = st1202_write_reg(chip, ST1202_CONFIG_REG,
-+ ST1202_CONFIG_REG_PATS | ST1202_CONFIG_REG_PATSR);
-+ if (ret < 0)
-+ return ret;
-+
-+ return 0;
-+}
-+
-+static int st1202_probe(struct i2c_client *client)
-+{
-+ struct st1202_chip *chip;
-+ struct st1202_led *led;
-+ int ret;
-+
-+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
-+ return dev_err_probe(&client->dev, -EIO, "SMBUS Byte Data not Supported\n");
-+
-+ chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
-+ if (!chip)
-+ return -ENOMEM;
-+
-+ devm_mutex_init(&client->dev, &chip->lock);
-+ chip->client = client;
-+
-+ ret = st1202_dt_init(chip);
-+ if (ret < 0)
-+ return ret;
-+
-+ ret = st1202_setup(chip);
-+ if (ret < 0)
-+ return ret;
-+
-+ for (int i = 0; i < ST1202_MAX_LEDS; i++) {
-+ led = &chip->leds[i];
-+ led->chip = chip;
-+ led->led_num = i;
-+
-+ if (!led->is_active)
-+ continue;
-+
-+ ret = st1202_channel_set(led->chip, led->led_num, true);
-+ if (ret < 0)
-+ return dev_err_probe(&client->dev, ret,
-+ "Failed to activate LED channel\n");
-+
-+ ret = st1202_led_pattern_clear(&led->led_cdev);
-+ if (ret < 0)
-+ return dev_err_probe(&client->dev, ret,
-+ "Failed to clear LED pattern\n");
-+ }
-+
-+ return 0;
-+}
-+
-+static const struct i2c_device_id st1202_id[] = {
-+ { "st1202-i2c" },
-+ { /* sentinel */ }
-+};
-+MODULE_DEVICE_TABLE(i2c, st1202_id);
-+
-+static const struct of_device_id st1202_dt_ids[] = {
-+ { .compatible = "st,led1202" },
-+ { /* sentinel */ }
-+};
-+MODULE_DEVICE_TABLE(of, st1202_dt_ids);
-+
-+static struct i2c_driver st1202_driver = {
-+ .driver = {
-+ .name = "leds-st1202",
-+ .of_match_table = of_match_ptr(st1202_dt_ids),
-+ },
-+ .probe = st1202_probe,
-+ .id_table = st1202_id,
-+};
-+module_i2c_driver(st1202_driver);
-+
-+MODULE_AUTHOR("Remote Tech LTD");
-+MODULE_DESCRIPTION("STMicroelectronics LED1202 : 12-channel constant current LED driver");
-+MODULE_LICENSE("GPL");
+++ /dev/null
-From e3da313ebcace17f1227566fe1b0d0c3883061f9 Mon Sep 17 00:00:00 2001
-Date: Fri, 17 Jan 2025 12:31:49 +0000
-Subject: [PATCH 1/5] leds: leds-st1202: fix NULL pointer access on race
- condition
-
-st1202_dt_init() calls devm_led_classdev_register_ext() before the
-internal data structures are properly setup, so the leds become visible
-to user space while being partially initialized, leading to a window
-where trying to access them causes a NULL pointer access.
-
-This change moves devm_led_classdev_register_ext() to the last thing to
-happen during initialization to eliminate it.
-
----
- drivers/leds/leds-st1202.c | 21 ++++++++++-----------
- 1 file changed, 10 insertions(+), 11 deletions(-)
-
---- a/drivers/leds/leds-st1202.c
-+++ b/drivers/leds/leds-st1202.c
-@@ -261,8 +261,6 @@ static int st1202_dt_init(struct st1202_
- int err, reg;
-
- for_each_available_child_of_node_scoped(dev_of_node(dev), child) {
-- struct led_init_data init_data = {};
--
- err = of_property_read_u32(child, "reg", ®);
- if (err)
- return dev_err_probe(dev, err, "Invalid register\n");
-@@ -276,15 +274,6 @@ static int st1202_dt_init(struct st1202_
- led->led_cdev.pattern_set = st1202_led_pattern_set;
- led->led_cdev.pattern_clear = st1202_led_pattern_clear;
- led->led_cdev.default_trigger = "pattern";
--
-- init_data.fwnode = led->fwnode;
-- init_data.devicename = "st1202";
-- init_data.default_label = ":";
--
-- err = devm_led_classdev_register_ext(dev, &led->led_cdev, &init_data);
-- if (err < 0)
-- return dev_err_probe(dev, err, "Failed to register LED class device\n");
--
- led->led_cdev.brightness_set = st1202_brightness_set;
- led->led_cdev.brightness_get = st1202_brightness_get;
- }
-@@ -368,6 +357,7 @@ static int st1202_probe(struct i2c_clien
- return ret;
-
- for (int i = 0; i < ST1202_MAX_LEDS; i++) {
-+ struct led_init_data init_data = {};
- led = &chip->leds[i];
- led->chip = chip;
- led->led_num = i;
-@@ -384,6 +374,15 @@ static int st1202_probe(struct i2c_clien
- if (ret < 0)
- return dev_err_probe(&client->dev, ret,
- "Failed to clear LED pattern\n");
-+
-+ init_data.fwnode = led->fwnode;
-+ init_data.devicename = "st1202";
-+ init_data.default_label = ":";
-+
-+ ret = devm_led_classdev_register_ext(&client->dev, &led->led_cdev, &init_data);
-+ if (ret < 0)
-+ return dev_err_probe(&client->dev, ret,
-+ "Failed to register LED class device\n");
- }
-
- return 0;
+++ /dev/null
-From 440415703692af4548e836832ef0434e87fbc357 Mon Sep 17 00:00:00 2001
-Date: Sat, 13 Jul 2024 18:56:59 +0300
-Subject: [PATCH] net: ag71xx: fix qca9530 and qca9550 mdio probe
-
-Newer QCA9530 and QCA9550 devices should use same div table as AR933X.
-
-Fixes: d51b6ce441d3 ("net: ethernet: add ag71xx driver")
----
- drivers/net/ethernet/atheros/ag71xx.c | 3 ++-
- 1 file changed, 2 insertions(+), 1 deletion(-)
-
---- a/drivers/net/ethernet/atheros/ag71xx.c
-+++ b/drivers/net/ethernet/atheros/ag71xx.c
-@@ -638,7 +638,8 @@ static int ag71xx_mdio_get_divider(struc
- if (!ref_clock)
- return -EINVAL;
-
-- if (ag71xx_is(ag, AR9330) || ag71xx_is(ag, AR9340)) {
-+ if (ag71xx_is(ag, AR9330) || ag71xx_is(ag, AR9340) ||
-+ ag71xx_is(ag, QCA9530) || ag71xx_is(ag, QCA9550)) {
- table = ar933x_mdio_div_table;
- ndivs = ARRAY_SIZE(ar933x_mdio_div_table);
- } else if (ag71xx_is(ag, AR7240)) {
+++ /dev/null
-Subject: init: add CONFIG_MANGLE_BOOTARGS and disable it by default
-
-Enabling this option renames the bootloader supplied root=
-and rootfstype= variables, which might have to be know but
-would break the automatisms OpenWrt uses.
-
----
- init/Kconfig | 9 +++++++++
- init/main.c | 24 ++++++++++++++++++++++++
- 2 files changed, 33 insertions(+)
-
---- a/init/Kconfig
-+++ b/init/Kconfig
-@@ -1821,6 +1821,15 @@ config DEBUG_RSEQ
-
- If unsure, say N.
-
-+config MANGLE_BOOTARGS
-+ bool "Rename offending bootargs"
-+ depends on EXPERT
-+ help
-+ Sometimes the bootloader passed bogus root= and rootfstype=
-+ parameters to the kernel, and while you want to ignore them,
-+ you need to know the values f.e. to support dual firmware
-+ layouts on the flash.
-+
- config HAVE_PERF_EVENTS
- bool
- help
---- a/init/main.c
-+++ b/init/main.c
-@@ -620,6 +620,29 @@ static inline void setup_nr_cpu_ids(void
- static inline void smp_prepare_cpus(unsigned int maxcpus) { }
- #endif
-
-+#ifdef CONFIG_MANGLE_BOOTARGS
-+static void __init mangle_bootargs(char *command_line)
-+{
-+ char *rootdev;
-+ char *rootfs;
-+
-+ rootdev = strstr(command_line, "root=/dev/mtdblock");
-+
-+ if (rootdev)
-+ strncpy(rootdev, "mangled_rootblock=", 18);
-+
-+ rootfs = strstr(command_line, "rootfstype");
-+
-+ if (rootfs)
-+ strncpy(rootfs, "mangled_fs", 10);
-+
-+}
-+#else
-+static void __init mangle_bootargs(char *command_line)
-+{
-+}
-+#endif
-+
- /*
- * We need to store the untouched command line for future reference.
- * We also need to store the touched command line since the parameter
-@@ -909,6 +932,7 @@ void start_kernel(void)
- pr_notice("%s", linux_banner);
- early_security_init();
- setup_arch(&command_line);
-+ mangle_bootargs(command_line);
- setup_boot_config();
- setup_command_line(command_line);
- setup_nr_cpu_ids();
+++ /dev/null
-# CONFIG_16KB_2LEVEL is not set
-CONFIG_16KB_3LEVEL=y
-# CONFIG_4KB_3LEVEL is not set
-# CONFIG_4KB_4LEVEL is not set
-CONFIG_64BIT=y
-# CONFIG_64KB_2LEVEL is not set
-# CONFIG_64KB_3LEVEL is not set
-CONFIG_AC97_BUS=y
-CONFIG_ACPI=y
-CONFIG_ACPI_AC=y
-CONFIG_ACPI_BATTERY=y
-CONFIG_ACPI_BUTTON=y
-CONFIG_ACPI_CONTAINER=y
-CONFIG_ACPI_CPU_FREQ_PSS=y
-# CONFIG_ACPI_DEBUG is not set
-# CONFIG_ACPI_DEBUGGER is not set
-# CONFIG_ACPI_DOCK is not set
-# CONFIG_ACPI_EC_DEBUGFS is not set
-CONFIG_ACPI_FAN=y
-# CONFIG_ACPI_FFH is not set
-CONFIG_ACPI_GENERIC_GSI=y
-CONFIG_ACPI_HOTPLUG_CPU=y
-CONFIG_ACPI_I2C_OPREGION=y
-CONFIG_ACPI_MCFG=y
-# CONFIG_ACPI_PCI_SLOT is not set
-# CONFIG_ACPI_PFRUT is not set
-CONFIG_ACPI_PPTT=y
-CONFIG_ACPI_PROCESSOR=y
-CONFIG_ACPI_PROCESSOR_IDLE=y
-CONFIG_ACPI_SLEEP=y
-# CONFIG_ACPI_SPCR_TABLE is not set
-CONFIG_ACPI_SYSTEM_POWER_STATES_SUPPORT=y
-CONFIG_ACPI_TABLE_UPGRADE=y
-# CONFIG_ACPI_TAD is not set
-CONFIG_ACPI_THERMAL=y
-CONFIG_ACPI_VIDEO=y
-CONFIG_APERTURE_HELPERS=y
-CONFIG_ARCH_DISABLE_KASAN_INLINE=y
-CONFIG_ARCH_DMA_ADDR_T_64BIT=y
-CONFIG_ARCH_HIBERNATION_POSSIBLE=y
-# CONFIG_ARCH_IOREMAP is not set
-CONFIG_ARCH_KEEP_MEMBLOCK=y
-CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y
-CONFIG_ARCH_MIGHT_HAVE_PC_SERIO=y
-CONFIG_ARCH_MMAP_RND_BITS=12
-CONFIG_ARCH_MMAP_RND_BITS_MAX=18
-CONFIG_ARCH_MMAP_RND_BITS_MIN=12
-CONFIG_ARCH_SELECT_MEMORY_MODEL=y
-CONFIG_ARCH_SPARSEMEM_ENABLE=y
-CONFIG_ARCH_STACKWALK=y
-CONFIG_ARCH_STRICT_ALIGN=y
-CONFIG_ARCH_SUSPEND_POSSIBLE=y
-CONFIG_ARCH_WANTS_NO_INSTR=y
-# CONFIG_ARCH_WRITECOMBINE is not set
-CONFIG_ASN1=y
-CONFIG_ASSOCIATIVE_ARRAY=y
-CONFIG_ATA=y
-CONFIG_ATA_ACPI=y
-CONFIG_ATA_FORCE=y
-# CONFIG_ATA_SFF is not set
-CONFIG_ATA_VERBOSE_ERROR=y
-CONFIG_AUDIT=y
-CONFIG_AUDITSYSCALL=y
-CONFIG_AUDIT_GENERIC=y
-CONFIG_BACKLIGHT_CLASS_DEVICE=y
-# CONFIG_BACKLIGHT_KTZ8866 is not set
-CONFIG_BLK_CGROUP=y
-CONFIG_BLK_CGROUP_IOCOST=y
-CONFIG_BLK_CGROUP_RWSTAT=y
-CONFIG_BLK_DEBUG_FS=y
-CONFIG_BLK_DEBUG_FS_ZONED=y
-CONFIG_BLK_DEV_BSGLIB=y
-CONFIG_BLK_DEV_BSG_COMMON=y
-CONFIG_BLK_DEV_INTEGRITY=y
-CONFIG_BLK_DEV_INTEGRITY_T10=y
-CONFIG_BLK_DEV_LOOP=y
-CONFIG_BLK_DEV_NVME=y
-CONFIG_BLK_DEV_SD=y
-CONFIG_BLK_DEV_SR=y
-CONFIG_BLK_DEV_THROTTLING=y
-# CONFIG_BLK_DEV_THROTTLING_LOW is not set
-CONFIG_BLK_DEV_ZONED=y
-CONFIG_BLK_MQ_PCI=y
-CONFIG_BLK_PM=y
-CONFIG_BLK_RQ_ALLOC_TIME=y
-CONFIG_BLK_SED_OPAL=y
-CONFIG_BLK_WBT=y
-CONFIG_BLK_WBT_MQ=y
-CONFIG_BLOCK_LEGACY_AUTOLOAD=y
-CONFIG_BOOT_PRINTK_DELAY=y
-CONFIG_BSD_PROCESS_ACCT=y
-CONFIG_BSD_PROCESS_ACCT_V3=y
-CONFIG_BUFFER_HEAD=y
-CONFIG_BUG_ON_DATA_CORRUPTION=y
-CONFIG_CACHESTAT_SYSCALL=y
-CONFIG_CDROM=y
-CONFIG_CFS_BANDWIDTH=y
-CONFIG_CGROUPS=y
-# CONFIG_CGROUP_BPF is not set
-# CONFIG_CGROUP_CPUACCT is not set
-# CONFIG_CGROUP_DEBUG is not set
-# CONFIG_CGROUP_DEVICE is not set
-# CONFIG_CGROUP_FREEZER is not set
-# CONFIG_CGROUP_HUGETLB is not set
-# CONFIG_CGROUP_NET_CLASSID is not set
-# CONFIG_CGROUP_NET_PRIO is not set
-# CONFIG_CGROUP_PIDS is not set
-# CONFIG_CGROUP_RDMA is not set
-CONFIG_CGROUP_SCHED=y
-CONFIG_CHECKPOINT_RESTORE=y
-CONFIG_CHR_DEV_SG=y
-CONFIG_CLZ_TAB=y
-CONFIG_CMA=y
-CONFIG_CMA_ALIGNMENT=8
-CONFIG_CMA_AREAS=7
-# CONFIG_CMA_DEBUG is not set
-# CONFIG_CMA_DEBUGFS is not set
-CONFIG_CMA_SIZE_MBYTES=16
-# CONFIG_CMA_SIZE_SEL_MAX is not set
-CONFIG_CMA_SIZE_SEL_MBYTES=y
-# CONFIG_CMA_SIZE_SEL_MIN is not set
-# CONFIG_CMA_SIZE_SEL_PERCENTAGE is not set
-# CONFIG_CMA_SYSFS is not set
-CONFIG_CMDLINE_BOOTLOADER=y
-CONFIG_COMMON_CLK=y
-# CONFIG_COMMON_CLK_LOONGSON2 is not set
-# CONFIG_COMMON_CLK_SI521XX is not set
-# CONFIG_COMMON_CLK_VC3 is not set
-CONFIG_COMPACT_UNEVICTABLE_DEFAULT=1
-# CONFIG_COMPAT_32BIT_TIME is not set
-CONFIG_CONNECTOR=y
-CONFIG_CONSOLE_TRANSLATIONS=y
-CONFIG_CONTEXT_TRACKING=y
-CONFIG_CONTEXT_TRACKING_IDLE=y
-CONFIG_CONTIG_ALLOC=y
-CONFIG_COREDUMP=y
-CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y
-CONFIG_CPUSETS=y
-CONFIG_CPU_HAS_FPU=y
-CONFIG_CPU_HAS_LASX=y
-CONFIG_CPU_HAS_LBT=y
-CONFIG_CPU_HAS_LSX=y
-CONFIG_CPU_HAS_PREFETCH=y
-CONFIG_CPU_ISOLATION=y
-CONFIG_CPU_PM=y
-CONFIG_CPU_RMAP=y
-CONFIG_CRC16=y
-CONFIG_CRC64=y
-CONFIG_CRC64_ROCKSOFT=y
-CONFIG_CRC_T10DIF=y
-CONFIG_CROSS_MEMORY_ATTACH=y
-CONFIG_CRYPTO_CBC=y
-CONFIG_CRYPTO_CRC32=y
-CONFIG_CRYPTO_CRC32C=y
-# CONFIG_CRYPTO_CRC32_LOONGARCH is not set
-CONFIG_CRYPTO_CRC64_ROCKSOFT=y
-CONFIG_CRYPTO_CRCT10DIF=y
-CONFIG_CRYPTO_HMAC=y
-CONFIG_CRYPTO_LIB_BLAKE2S_GENERIC=y
-CONFIG_CRYPTO_LIB_GF128MUL=y
-CONFIG_CRYPTO_LIB_POLY1305_RSIZE=1
-CONFIG_CRYPTO_LIB_SHA1=y
-CONFIG_CRYPTO_LIB_SHA256=y
-CONFIG_CRYPTO_LIB_UTILS=y
-CONFIG_CRYPTO_LZO=y
-CONFIG_CRYPTO_MD5=y
-CONFIG_CRYPTO_RNG=y
-CONFIG_CRYPTO_RNG2=y
-CONFIG_CRYPTO_RSA=y
-CONFIG_CRYPTO_SHA1=y
-CONFIG_CRYPTO_SHA256=y
-CONFIG_DEBUG_BUGVERBOSE=y
-CONFIG_DEBUG_INFO=y
-CONFIG_DEBUG_INFO_COMPRESSED_NONE=y
-# CONFIG_DEBUG_INFO_COMPRESSED_ZLIB is not set
-# CONFIG_DEBUG_INFO_COMPRESSED_ZSTD is not set
-CONFIG_DEBUG_LIST=y
-CONFIG_DEBUG_MEMORY_INIT=y
-CONFIG_DEBUG_MISC=y
-CONFIG_DETECT_HUNG_TASK=y
-# CONFIG_DEVFREQ_GOV_PASSIVE is not set
-# CONFIG_DEVFREQ_GOV_PERFORMANCE is not set
-# CONFIG_DEVFREQ_GOV_POWERSAVE is not set
-# CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND is not set
-# CONFIG_DEVFREQ_GOV_USERSPACE is not set
-CONFIG_DEVFREQ_THERMAL=y
-CONFIG_DEVMEM=y
-CONFIG_DEVTMPFS=y
-# CONFIG_DMAPOOL_TEST is not set
-CONFIG_DMA_CMA=y
-CONFIG_DMA_SHARED_BUFFER=y
-CONFIG_DMI=y
-CONFIG_DMIID=y
-CONFIG_DMI_SCAN_MACHINE_NON_EFI_FALLBACK=y
-CONFIG_DMI_SYSFS=y
-CONFIG_DRM=y
-# CONFIG_DRM_ACCEL is not set
-CONFIG_DRM_BRIDGE=y
-CONFIG_DRM_FBDEV_EMULATION=y
-CONFIG_DRM_FBDEV_OVERALLOC=100
-CONFIG_DRM_KMS_HELPER=y
-CONFIG_DRM_LOAD_EDID_FIRMWARE=y
-CONFIG_DRM_LOONGSON=y
-CONFIG_DRM_PANEL=y
-# CONFIG_DRM_PANEL_AUO_A030JTN01 is not set
-CONFIG_DRM_PANEL_BRIDGE=y
-CONFIG_DRM_PANEL_ORIENTATION_QUIRKS=y
-# CONFIG_DRM_PANEL_ORISETECH_OTA5601A is not set
-# CONFIG_DRM_PANEL_SAMSUNG_S6D7AA0 is not set
-# CONFIG_DRM_SAMSUNG_DSIM is not set
-CONFIG_DRM_TTM=y
-CONFIG_DTC=y
-CONFIG_DUMMY_CONSOLE=y
-CONFIG_EFI=y
-CONFIG_EFIVAR_FS=m
-# CONFIG_EFI_BOOTLOADER_CONTROL is not set
-# CONFIG_EFI_CAPSULE_LOADER is not set
-# CONFIG_EFI_COCO_SECRET is not set
-CONFIG_EFI_CUSTOM_SSDT_OVERLAYS=y
-# CONFIG_EFI_DISABLE_PCI_DMA is not set
-# CONFIG_EFI_DISABLE_RUNTIME is not set
-CONFIG_EFI_EARLYCON=y
-CONFIG_EFI_ESRT=y
-CONFIG_EFI_GENERIC_STUB=y
-CONFIG_EFI_RUNTIME_WRAPPERS=y
-CONFIG_EFI_STUB=y
-# CONFIG_EFI_TEST is not set
-CONFIG_EFI_ZBOOT=y
-CONFIG_ELF_CORE=y
-CONFIG_ENCRYPTED_KEYS=y
-CONFIG_EXCLUSIVE_SYSTEM_RAM=y
-CONFIG_EXPORTFS_BLOCK_OPS=y
-CONFIG_EXT4_FS=y
-CONFIG_FAILOVER=y
-CONFIG_FAIR_GROUP_SCHED=y
-CONFIG_FANOTIFY=y
-CONFIG_FB=y
-CONFIG_FB_CFB_COPYAREA=y
-CONFIG_FB_CFB_FILLRECT=y
-CONFIG_FB_CFB_IMAGEBLIT=y
-CONFIG_FB_CORE=y
-CONFIG_FB_DEFERRED_IO=y
-CONFIG_FB_DEVICE=y
-CONFIG_FB_EFI=y
-CONFIG_FB_IOMEM_FOPS=y
-CONFIG_FB_IOMEM_HELPERS=y
-CONFIG_FB_MODE_HELPERS=y
-CONFIG_FB_SIMPLE=y
-CONFIG_FB_SYSMEM_HELPERS=y
-CONFIG_FB_SYSMEM_HELPERS_DEFERRED=y
-CONFIG_FB_SYS_COPYAREA=y
-CONFIG_FB_SYS_FILLRECT=y
-CONFIG_FB_SYS_FOPS=y
-CONFIG_FB_SYS_IMAGEBLIT=y
-CONFIG_FB_TILEBLITTING=y
-CONFIG_FHANDLE=y
-CONFIG_FIRMWARE_EDID=y
-CONFIG_FIX_EARLYCON_MEM=y
-# CONFIG_FLATMEM_MANUAL is not set
-CONFIG_FONTS=y
-# CONFIG_FONT_10x18 is not set
-# CONFIG_FONT_6x10 is not set
-# CONFIG_FONT_6x11 is not set
-# CONFIG_FONT_7x14 is not set
-CONFIG_FONT_8x16=y
-CONFIG_FONT_8x8=y
-# CONFIG_FONT_ACORN_8x8 is not set
-# CONFIG_FONT_MINI_4x6 is not set
-# CONFIG_FONT_PEARL_8x8 is not set
-# CONFIG_FONT_SUN12x22 is not set
-# CONFIG_FONT_SUN8x16 is not set
-CONFIG_FONT_SUPPORT=y
-CONFIG_FONT_TER16x32=y
-CONFIG_FRAMEBUFFER_CONSOLE=y
-CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
-CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y
-CONFIG_FREEZER=y
-CONFIG_FS_IOMAP=y
-CONFIG_FS_MBCACHE=y
-CONFIG_FUNCTION_ALIGNMENT=0
-CONFIG_FW_CACHE=y
-# CONFIG_FW_DEVLINK_SYNC_STATE_TIMEOUT is not set
-CONFIG_FW_LOADER_PAGED_BUF=y
-CONFIG_FW_LOADER_SYSFS=y
-CONFIG_GENERIC_ALLOCATOR=y
-CONFIG_GENERIC_BUG=y
-CONFIG_GENERIC_BUG_RELATIVE_POINTERS=y
-CONFIG_GENERIC_CLOCKEVENTS=y
-CONFIG_GENERIC_CMOS_UPDATE=y
-CONFIG_GENERIC_CPU_AUTOPROBE=y
-CONFIG_GENERIC_CSUM=y
-CONFIG_GENERIC_ENTRY=y
-CONFIG_GENERIC_GETTIMEOFDAY=y
-CONFIG_GENERIC_IOREMAP=y
-CONFIG_GENERIC_IRQ_CHIP=y
-CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=y
-CONFIG_GENERIC_IRQ_MIGRATION=y
-CONFIG_GENERIC_IRQ_MULTI_HANDLER=y
-CONFIG_GENERIC_IRQ_SHOW=y
-CONFIG_GENERIC_LIB_ASHLDI3=y
-CONFIG_GENERIC_LIB_ASHRDI3=y
-CONFIG_GENERIC_LIB_CMPDI2=y
-CONFIG_GENERIC_LIB_DEVMEM_IS_ALLOWED=y
-CONFIG_GENERIC_LIB_LSHRDI3=y
-CONFIG_GENERIC_LIB_UCMPDI2=y
-CONFIG_GENERIC_MSI_IRQ=y
-CONFIG_GENERIC_PCI_IOMAP=y
-CONFIG_GENERIC_PHY=y
-CONFIG_GENERIC_SCHED_CLOCK=y
-CONFIG_GENERIC_SMP_IDLE_THREAD=y
-CONFIG_GENERIC_STRNCPY_FROM_USER=y
-CONFIG_GENERIC_STRNLEN_USER=y
-CONFIG_GENERIC_TIME_VSYSCALL=y
-CONFIG_GLOB=y
-CONFIG_GPIO_ACPI=y
-CONFIG_GPIO_CDEV=y
-CONFIG_GPIO_CDEV_V1=y
-# CONFIG_GPIO_DS4520 is not set
-# CONFIG_GPIO_FXL6408 is not set
-# CONFIG_GPIO_LATCH is not set
-# CONFIG_GPIO_LOONGSON_64BIT is not set
-CONFIG_HAMRADIO=y
-CONFIG_HAS_DMA=y
-CONFIG_HAS_IOMEM=y
-CONFIG_HAS_IOPORT=y
-CONFIG_HAS_IOPORT_MAP=y
-CONFIG_HDMI=y
-CONFIG_HIBERNATE_CALLBACKS=y
-CONFIG_HIBERNATION=y
-CONFIG_HIBERNATION_SNAPSHOT_DEV=y
-CONFIG_HID=y
-CONFIG_HIDRAW=y
-CONFIG_HID_GENERIC=y
-CONFIG_HID_SUPPORT=y
-CONFIG_HOTPLUG_CPU=y
-CONFIG_HUGETLBFS=y
-CONFIG_HUGETLB_PAGE=y
-CONFIG_HUGETLB_PAGE_OPTIMIZE_VMEMMAP=y
-CONFIG_HWMON=y
-CONFIG_HW_CONSOLE=y
-CONFIG_HZ=250
-# CONFIG_HZ_100 is not set
-CONFIG_HZ_250=y
-CONFIG_HZ_PERIODIC=y
-CONFIG_I2C=y
-CONFIG_I2C_ALGOBIT=y
-# CONFIG_I2C_AMD_MP2 is not set
-CONFIG_I2C_BOARDINFO=y
-# CONFIG_I2C_LS2X is not set
-CONFIG_INITRAMFS_PRESERVE_MTIME=y
-CONFIG_INITRAMFS_SOURCE=""
-CONFIG_INIT_STACK_ALL_ZERO=y
-# CONFIG_INIT_STACK_NONE is not set
-CONFIG_INPUT=y
-CONFIG_INPUT_KEYBOARD=y
-CONFIG_INPUT_LEDS=y
-# CONFIG_INPUT_MISC is not set
-CONFIG_INPUT_MOUSE=y
-CONFIG_INPUT_MOUSEDEV=y
-CONFIG_INPUT_MOUSEDEV_PSAUX=y
-CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
-CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
-CONFIG_INPUT_SPARSEKMAP=y
-# CONFIG_IOMMUFD is not set
-# CONFIG_IOMMU_DEBUGFS is not set
-CONFIG_IOMMU_SUPPORT=y
-CONFIG_IO_URING=y
-CONFIG_IRQCHIP=y
-CONFIG_IRQ_DOMAIN=y
-CONFIG_IRQ_DOMAIN_HIERARCHY=y
-CONFIG_IRQ_FASTEOI_HIERARCHY_HANDLERS=y
-CONFIG_IRQ_FORCED_THREADING=y
-CONFIG_IRQ_LOONGARCH_CPU=y
-CONFIG_IRQ_POLL=y
-CONFIG_IRQ_WORK=y
-# CONFIG_ISCSI_IBFT is not set
-CONFIG_ISO9660_FS=y
-CONFIG_JBD2=y
-CONFIG_JUMP_LABEL=y
-CONFIG_KALLSYMS=y
-# CONFIG_KALLSYMS_SELFTEST is not set
-CONFIG_KCMP=y
-CONFIG_KEYS=y
-CONFIG_KSM=y
-CONFIG_L1_CACHE_SHIFT=6
-# CONFIG_LEDS_AW200XX is not set
-# CONFIG_LEDS_BD2606MVV is not set
-# CONFIG_LEDS_GROUP_MULTICOLOR is not set
-# CONFIG_LEDS_LM3697 is not set
-# CONFIG_LEDS_PCA995X is not set
-CONFIG_LEDS_TRIGGER_AUDIO=y
-CONFIG_LEDS_TRIGGER_CPU=y
-CONFIG_LEDS_TRIGGER_DISK=y
-CONFIG_LEDS_TRIGGER_MTD=y
-CONFIG_LEDS_TRIGGER_PANIC=y
-CONFIG_LEGACY_TIOCSTI=y
-CONFIG_LIBFDT=y
-CONFIG_LOCKUP_DETECTOR=y
-CONFIG_LOCK_DEBUGGING_SUPPORT=y
-CONFIG_LOCK_SPIN_ON_OWNER=y
-CONFIG_LOONGARCH=y
-CONFIG_LOONGARCH_PLATFORM_DEVICES=y
-# CONFIG_LOONGSON2_GUTS is not set
-# CONFIG_LOONGSON2_PM is not set
-# CONFIG_LOONGSON2_THERMAL is not set
-CONFIG_LOONGSON_EIOINTC=y
-CONFIG_LOONGSON_HTVEC=y
-CONFIG_LOONGSON_LAPTOP=y
-CONFIG_LOONGSON_LIOINTC=y
-CONFIG_LOONGSON_PCH_LPC=y
-CONFIG_LOONGSON_PCH_MSI=y
-CONFIG_LOONGSON_PCH_PIC=y
-CONFIG_LSM="landlock,lockdown,yama,loadpin,safesetid,integrity,apparmor,selinux,smack,tomoyo,bpf"
-CONFIG_LZO_COMPRESS=y
-CONFIG_LZO_DECOMPRESS=y
-CONFIG_MACH_LOONGSON64=y
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0x01b6
-CONFIG_MAGIC_SYSRQ_SERIAL=y
-# CONFIG_MAX31827 is not set
-CONFIG_MAX_SKB_FRAGS=17
-# CONFIG_MEMCG is not set
-CONFIG_MEMFD_CREATE=y
-CONFIG_MEMORY=y
-CONFIG_MEMORY_ISOLATION=y
-# CONFIG_MFD_CS42L43_I2C is not set
-# CONFIG_MFD_INTEL_M10_BMC_SPI is not set
-# CONFIG_MFD_MAX5970 is not set
-# CONFIG_MFD_MAX77541 is not set
-# CONFIG_MFD_RK8XX_I2C is not set
-# CONFIG_MFD_RK8XX_SPI is not set
-# CONFIG_MFD_SMPRO is not set
-# CONFIG_MFD_TPS65219 is not set
-# CONFIG_MFD_TPS6594_I2C is not set
-# CONFIG_MFD_TPS6594_SPI is not set
-CONFIG_MIGRATION=y
-CONFIG_MMU_GATHER_MERGE_VMAS=y
-CONFIG_MMU_LAZY_TLB_REFCOUNT=y
-CONFIG_MODULES_USE_ELF_RELA=y
-# CONFIG_MODULE_DEBUG is not set
-CONFIG_MODULE_FORCE_LOAD=y
-CONFIG_MODULE_FORCE_UNLOAD=y
-# CONFIG_MOUSE_BCM5974 is not set
-# CONFIG_MOUSE_CYAPA is not set
-CONFIG_MOUSE_PS2=y
-CONFIG_MOUSE_PS2_ALPS=y
-CONFIG_MOUSE_PS2_BYD=y
-CONFIG_MOUSE_PS2_CYPRESS=y
-# CONFIG_MOUSE_PS2_ELANTECH is not set
-CONFIG_MOUSE_PS2_LOGIPS2PP=y
-CONFIG_MOUSE_PS2_SMBUS=y
-CONFIG_MOUSE_PS2_SYNAPTICS=y
-CONFIG_MOUSE_PS2_SYNAPTICS_SMBUS=y
-# CONFIG_MOUSE_PS2_TOUCHKIT is not set
-CONFIG_MOUSE_PS2_TRACKPOINT=y
-# CONFIG_MOUSE_SERIAL is not set
-# CONFIG_MOUSE_VSXXXAA is not set
-# CONFIG_MOXA_INTELLIO is not set
-# CONFIG_MOXA_SMARTIO is not set
-CONFIG_MPILIB=y
-CONFIG_MQ_IOSCHED_DEADLINE=y
-CONFIG_MUTEX_SPIN_ON_OWNER=y
-CONFIG_NEED_DMA_MAP_STATE=y
-CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK=y
-CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK=y
-# CONFIG_NET_CLS_CGROUP is not set
-CONFIG_NET_EGRESS=y
-CONFIG_NET_FAILOVER=y
-CONFIG_NET_FLOW_LIMIT=y
-CONFIG_NET_INGRESS=y
-CONFIG_NET_PTP_CLASSIFY=y
-CONFIG_NET_XGRESS=y
-CONFIG_NLS=y
-CONFIG_NR_CPUS=64
-CONFIG_NVMEM=y
-CONFIG_NVMEM_LAYOUTS=y
-CONFIG_NVMEM_SYSFS=y
-CONFIG_NVME_CORE=y
-CONFIG_NVME_HWMON=y
-CONFIG_NVME_MULTIPATH=y
-CONFIG_NVME_VERBOSE_ERRORS=y
-# CONFIG_N_HDLC is not set
-CONFIG_OF=y
-CONFIG_OF_ADDRESS=y
-CONFIG_OF_EARLY_FLATTREE=y
-CONFIG_OF_FLATTREE=y
-CONFIG_OF_GPIO=y
-CONFIG_OF_IRQ=y
-CONFIG_OF_KOBJ=y
-CONFIG_OID_REGISTRY=y
-# CONFIG_OVERLAY_FS_DEBUG is not set
-CONFIG_PADATA=y
-CONFIG_PAGE_EXTENSION=y
-CONFIG_PAGE_POISONING=y
-CONFIG_PAGE_POOL=y
-CONFIG_PAGE_POOL_STATS=y
-CONFIG_PAGE_REPORTING=y
-CONFIG_PAGE_SIZE_16KB=y
-CONFIG_PAGE_SIZE_LESS_THAN_256KB=y
-CONFIG_PAGE_SIZE_LESS_THAN_64KB=y
-# CONFIG_PANIC_ON_OOPS is not set
-CONFIG_PANIC_ON_OOPS_VALUE=0
-CONFIG_PATA_TIMINGS=y
-CONFIG_PCI=y
-CONFIG_PCIEAER=y
-CONFIG_PCIEASPM=y
-CONFIG_PCIEASPM_DEFAULT=y
-# CONFIG_PCIEASPM_PERFORMANCE is not set
-# CONFIG_PCIEASPM_POWERSAVE is not set
-# CONFIG_PCIEASPM_POWER_SUPERSAVE is not set
-CONFIG_PCIEPORTBUS=y
-CONFIG_PCIE_DPC=y
-# CONFIG_PCIE_EDR is not set
-CONFIG_PCIE_PME=y
-CONFIG_PCIE_PTM=y
-CONFIG_PCI_ATS=y
-CONFIG_PCI_DOMAINS=y
-CONFIG_PCI_DOMAINS_GENERIC=y
-# CONFIG_PCI_DYNAMIC_OF_NODES is not set
-CONFIG_PCI_ECAM=y
-CONFIG_PCI_IOV=y
-CONFIG_PCI_LABEL=y
-CONFIG_PCI_LOONGSON=y
-CONFIG_PCI_MSI=y
-CONFIG_PCI_MSI_ARCH_FALLBACKS=y
-CONFIG_PCI_REALLOC_ENABLE_AUTO=y
-# CONFIG_PDS_CORE is not set
-CONFIG_PERF_USE_VMALLOC=y
-CONFIG_PGTABLE_3LEVEL=y
-CONFIG_PGTABLE_LEVELS=3
-CONFIG_PHYS_ADDR_T_64BIT=y
-CONFIG_PM=y
-# CONFIG_PMIC_OPREGION is not set
-CONFIG_PM_ADVANCED_DEBUG=y
-CONFIG_PM_CLK=y
-CONFIG_PM_DEBUG=y
-CONFIG_PM_DEVFREQ=y
-# CONFIG_PM_DEVFREQ_EVENT is not set
-CONFIG_PM_OPP=y
-CONFIG_PM_SLEEP=y
-CONFIG_PM_SLEEP_DEBUG=y
-CONFIG_PM_SLEEP_SMP=y
-CONFIG_PM_STD_PARTITION=""
-# CONFIG_PM_TEST_SUSPEND is not set
-CONFIG_PNP=y
-CONFIG_PNPACPI=y
-# CONFIG_PNP_DEBUG_MESSAGES is not set
-CONFIG_POSIX_MQUEUE=y
-CONFIG_POSIX_MQUEUE_SYSCTL=y
-CONFIG_POWER_SUPPLY=y
-CONFIG_POWER_SUPPLY_HWMON=y
-CONFIG_PPS=y
-# CONFIG_PREEMPT_NONE is not set
-CONFIG_PREEMPT_VOLUNTARY=y
-CONFIG_PREEMPT_VOLUNTARY_BUILD=y
-CONFIG_PRINTK_TIME=y
-CONFIG_PROC_CHILDREN=y
-CONFIG_PROC_EVENTS=y
-CONFIG_PROC_PAGE_MONITOR=y
-CONFIG_PROC_PID_CPUSET=y
-CONFIG_PTP_1588_CLOCK=y
-# CONFIG_PTP_1588_CLOCK_MOCK is not set
-CONFIG_PTP_1588_CLOCK_OPTIONAL=y
-CONFIG_QUEUED_RWLOCKS=y
-CONFIG_QUEUED_SPINLOCKS=y
-# CONFIG_RANDOM_KMALLOC_CACHES is not set
-CONFIG_RANDSTRUCT_NONE=y
-CONFIG_RAS=y
-CONFIG_RATIONAL=y
-# CONFIG_RAVE_SP_CORE is not set
-# CONFIG_RCU_CPU_STALL_CPUTIME is not set
-CONFIG_REGMAP=y
-CONFIG_REGMAP_I2C=y
-CONFIG_REGMAP_MMIO=y
-CONFIG_REGMAP_SPI=y
-CONFIG_RELAY=y
-CONFIG_RELOCATABLE=y
-CONFIG_RESET_ATTACK_MITIGATION=y
-CONFIG_RFS_ACCEL=y
-CONFIG_RPS=y
-CONFIG_RSEQ=y
-CONFIG_RTC_CLASS=y
-# CONFIG_RTC_DRV_EFI is not set
-CONFIG_RTC_DRV_LOONGSON=y
-CONFIG_RTC_I2C_AND_SPI=y
-# CONFIG_RT_GROUP_SCHED is not set
-CONFIG_RWSEM_SPIN_ON_OWNER=y
-CONFIG_SATA_AHCI=y
-CONFIG_SATA_HOST=y
-# CONFIG_SATA_ZPODD is not set
-CONFIG_SCHEDSTATS=y
-CONFIG_SCHED_AUTOGROUP=y
-# CONFIG_SCHED_CORE is not set
-CONFIG_SCHED_DEBUG=y
-CONFIG_SCHED_INFO=y
-CONFIG_SCHED_MM_CID=y
-CONFIG_SCHED_SMT=y
-CONFIG_SCSI=y
-CONFIG_SCSI_COMMON=y
-CONFIG_SECCOMP=y
-CONFIG_SECCOMP_FILTER=y
-# CONFIG_SENSORS_HS3001 is not set
-# CONFIG_SENSORS_MC34VR500 is not set
-CONFIG_SERIAL_8250_EXTENDED=y
-CONFIG_SERIAL_8250_MANY_PORTS=y
-CONFIG_SERIAL_8250_NR_UARTS=4
-CONFIG_SERIAL_8250_PCI=y
-# CONFIG_SERIAL_8250_PCI1XXXX is not set
-CONFIG_SERIAL_8250_PCILIB=y
-CONFIG_SERIAL_8250_PERICOM=y
-CONFIG_SERIAL_8250_PNP=y
-CONFIG_SERIAL_8250_RSA=y
-CONFIG_SERIAL_8250_RUNTIME_UARTS=4
-CONFIG_SERIAL_8250_SHARE_IRQ=y
-CONFIG_SERIAL_DEV_BUS=y
-CONFIG_SERIAL_DEV_CTRL_TTYPORT=y
-CONFIG_SERIAL_MCTRL_GPIO=y
-CONFIG_SERIAL_NONSTANDARD=y
-CONFIG_SERIAL_OF_PLATFORM=y
-CONFIG_SERIO=y
-CONFIG_SERIO_I8042=y
-CONFIG_SERIO_LIBPS2=y
-CONFIG_SERIO_SERPORT=y
-CONFIG_SGL_ALLOC=y
-CONFIG_SG_POOL=y
-# CONFIG_SLAB_DEPRECATED is not set
-# CONFIG_SLUB_TINY is not set
-CONFIG_SMP=y
-CONFIG_SND=y
-CONFIG_SND_AC97_CODEC=y
-CONFIG_SND_COMPRESS_OFFLOAD=y
-CONFIG_SND_CTL_LED=y
-CONFIG_SND_DYNAMIC_MINORS=y
-CONFIG_SND_HDA=y
-# CONFIG_SND_HDA_CODEC_ANALOG is not set
-# CONFIG_SND_HDA_CODEC_CA0110 is not set
-# CONFIG_SND_HDA_CODEC_CA0132 is not set
-# CONFIG_SND_HDA_CODEC_CIRRUS is not set
-# CONFIG_SND_HDA_CODEC_CMEDIA is not set
-CONFIG_SND_HDA_CODEC_CONEXANT=y
-CONFIG_SND_HDA_CODEC_HDMI=y
-# CONFIG_SND_HDA_CODEC_REALTEK is not set
-# CONFIG_SND_HDA_CODEC_SI3054 is not set
-# CONFIG_SND_HDA_CODEC_SIGMATEL is not set
-# CONFIG_SND_HDA_CODEC_VIA is not set
-CONFIG_SND_HDA_CORE=y
-# CONFIG_SND_HDA_CTL_DEV_ID is not set
-CONFIG_SND_HDA_GENERIC=y
-CONFIG_SND_HDA_GENERIC_LEDS=y
-CONFIG_SND_HDA_HWDEP=y
-# CONFIG_SND_HDA_INPUT_BEEP is not set
-CONFIG_SND_HDA_INTEL=y
-# CONFIG_SND_HDA_PATCH_LOADER is not set
-# CONFIG_SND_HDA_RECONFIG is not set
-# CONFIG_SND_HDA_SCODEC_CS35L41_I2C is not set
-# CONFIG_SND_HDA_SCODEC_CS35L41_SPI is not set
-# CONFIG_SND_HDA_SCODEC_CS35L56_I2C is not set
-# CONFIG_SND_HDA_SCODEC_CS35L56_SPI is not set
-# CONFIG_SND_HDA_SCODEC_TAS2781_I2C is not set
-CONFIG_SND_HWDEP=y
-CONFIG_SND_INTEL_DSP_CONFIG=y
-CONFIG_SND_INTEL_NHLT=y
-CONFIG_SND_INTEL_SOUNDWIRE_ACPI=y
-CONFIG_SND_JACK=y
-CONFIG_SND_JACK_INPUT_DEV=y
-CONFIG_SND_MIXER_OSS=y
-CONFIG_SND_PCM=y
-CONFIG_SND_PCM_OSS=y
-CONFIG_SND_PCM_TIMER=y
-CONFIG_SND_RAWMIDI=y
-CONFIG_SND_SEQUENCER=y
-CONFIG_SND_SEQUENCER_OSS=y
-CONFIG_SND_SEQ_DEVICE=y
-CONFIG_SND_SEQ_DUMMY=y
-CONFIG_SND_SEQ_MIDI=y
-CONFIG_SND_SEQ_MIDI_EVENT=y
-CONFIG_SND_SEQ_VIRMIDI=y
-CONFIG_SND_SOC=y
-CONFIG_SND_SOC_AC97_BUS=y
-CONFIG_SND_SOC_AC97_CODEC=y
-CONFIG_SND_SOC_I2C_AND_SPI=y
-CONFIG_SND_SOC_LOONGSON_CARD=y
-CONFIG_SND_SOC_LOONGSON_I2S_PCI=y
-CONFIG_SND_TIMER=y
-CONFIG_SND_VIRMIDI=y
-CONFIG_SND_VMASTER=y
-CONFIG_SOCK_RX_QUEUE_MAPPING=y
-CONFIG_SOFTLOCKUP_DETECTOR=y
-CONFIG_SOUND=y
-CONFIG_SOUND_OSS_CORE=y
-CONFIG_SOUND_OSS_CORE_PRECLAIM=y
-CONFIG_SPARSEMEM=y
-CONFIG_SPARSEMEM_EXTREME=y
-CONFIG_SPARSEMEM_MANUAL=y
-CONFIG_SPARSEMEM_VMEMMAP=y
-CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y
-CONFIG_SPARSE_IRQ=y
-CONFIG_SPI=y
-CONFIG_SPI_DYNAMIC=y
-CONFIG_SPI_LOONGSON_CORE=y
-CONFIG_SPI_LOONGSON_PCI=y
-CONFIG_SPI_LOONGSON_PLATFORM=y
-CONFIG_SPI_MASTER=y
-CONFIG_SPI_MEM=y
-# CONFIG_SPI_PCI1XXXX is not set
-# CONFIG_SPI_SN_F_OSPI is not set
-CONFIG_SPI_SPIDEV=y
-# CONFIG_SQUASHFS_CHOICE_DECOMP_BY_MOUNT is not set
-# CONFIG_SQUASHFS_COMPILE_DECOMP_MULTI is not set
-# CONFIG_SQUASHFS_COMPILE_DECOMP_MULTI_PERCPU is not set
-CONFIG_SQUASHFS_COMPILE_DECOMP_SINGLE=y
-CONFIG_SQUASHFS_DECOMP_SINGLE=y
-CONFIG_STACKPROTECTOR=y
-CONFIG_STACKPROTECTOR_STRONG=y
-CONFIG_STACKTRACE=y
-CONFIG_STRICT_DEVMEM=y
-CONFIG_SUSPEND=y
-CONFIG_SUSPEND_FREEZER=y
-CONFIG_SWIOTLB=y
-# CONFIG_SWIOTLB_DYNAMIC is not set
-CONFIG_SYNC_FILE=y
-CONFIG_SYSCTL_ARCH_UNALIGN_ALLOW=y
-CONFIG_SYSCTL_ARCH_UNALIGN_NO_WARN=y
-CONFIG_SYSCTL_EXCEPTION_TRACE=y
-CONFIG_SYSFB=y
-# CONFIG_SYSFB_SIMPLEFB is not set
-CONFIG_TASKSTATS=y
-CONFIG_TASK_DELAY_ACCT=y
-CONFIG_TASK_IO_ACCOUNTING=y
-CONFIG_TASK_XACCT=y
-# CONFIG_TEST_DHRY is not set
-CONFIG_THERMAL=y
-# CONFIG_THERMAL_DEFAULT_GOV_BANG_BANG is not set
-CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y
-CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS=0
-CONFIG_THERMAL_GOV_BANG_BANG=y
-CONFIG_THERMAL_GOV_FAIR_SHARE=y
-CONFIG_THERMAL_GOV_STEP_WISE=y
-CONFIG_THERMAL_GOV_USER_SPACE=y
-CONFIG_THERMAL_HWMON=y
-CONFIG_THERMAL_OF=y
-CONFIG_THERMAL_STATISTICS=y
-CONFIG_THERMAL_WRITABLE_TRIPS=y
-CONFIG_TICK_CPU_ACCOUNTING=y
-CONFIG_TMPFS_INODE64=y
-# CONFIG_TMPFS_QUOTA is not set
-CONFIG_TRANSPARENT_HUGEPAGE=y
-CONFIG_TRANSPARENT_HUGEPAGE_ALWAYS=y
-# CONFIG_TRANSPARENT_HUGEPAGE_MADVISE is not set
-CONFIG_TREE_RCU=y
-CONFIG_TREE_SRCU=y
-CONFIG_UCS2_STRING=y
-# CONFIG_UEVENT_HELPER is not set
-# CONFIG_UNWINDER_GUESS is not set
-CONFIG_UNWINDER_PROLOGUE=y
-CONFIG_USB=y
-CONFIG_USB_COMMON=y
-CONFIG_USB_EHCI_HCD=y
-# CONFIG_USB_EHCI_HCD_PLATFORM is not set
-CONFIG_USB_EHCI_PCI=y
-CONFIG_USB_HID=y
-CONFIG_USB_HIDDEV=y
-CONFIG_USB_OHCI_HCD=y
-CONFIG_USB_OHCI_HCD_PCI=y
-# CONFIG_USB_OHCI_HCD_PLATFORM is not set
-CONFIG_USB_PCI=y
-CONFIG_USB_STORAGE=y
-CONFIG_USB_SUPPORT=y
-CONFIG_USB_UAS=y
-# CONFIG_USB_UHCI_HCD is not set
-CONFIG_USB_XHCI_HCD=y
-CONFIG_USB_XHCI_PCI=y
-# CONFIG_USB_XHCI_PLATFORM is not set
-CONFIG_USERFAULTFD=y
-CONFIG_USER_STACKTRACE_SUPPORT=y
-CONFIG_USE_PERCPU_NUMA_NODE_ID=y
-# CONFIG_VCAP is not set
-CONFIG_VGA_ARB=y
-CONFIG_VGA_ARB_MAX_GPUS=16
-CONFIG_VGA_CONSOLE=y
-CONFIG_VIDEO_CMDLINE=y
-CONFIG_VIDEO_NOMODESET=y
-CONFIG_VIRTIO_VSOCKETS_COMMON=y
-CONFIG_VM_EVENT_COUNTERS=y
-CONFIG_VSOCKETS=y
-CONFIG_VSOCKETS_LOOPBACK=y
-CONFIG_VT=y
-CONFIG_VT_CONSOLE=y
-CONFIG_VT_CONSOLE_SLEEP=y
-CONFIG_VT_HW_CONSOLE_BINDING=y
-# CONFIG_WPCM450_SOC is not set
-# CONFIG_WQ_CPU_INTENSIVE_REPORT is not set
-CONFIG_XARRAY_MULTI=y
-CONFIG_XPS=y
-CONFIG_XXHASH=y
-# CONFIG_ZONEFS_FS is not set
-CONFIG_ZONE_DMA32=y
define Device/bananapi_bpi-r4-poe
DEVICE_MODEL := BPi-R4 2.5GE
-ifneq ($(CONFIG_LINUX_6_6),)
- DEVICE_DTS := mt7988a-bananapi-bpi-r4-poe
-else
DEVICE_DTS := mt7988a-bananapi-bpi-r4-2g5
-endif
DEVICE_DTS_CONFIG := config-mt7988a-bananapi-bpi-r4-poe
$(call Device/bananapi_bpi-r4-common)
DEVICE_PACKAGES += mt7988-2p5g-phy-firmware