1
0
Fork 0
mirror of https://github.com/Ysurac/openmptcprouter.git synced 2025-03-09 15:40:20 +00:00

Update 6.12 kernel patches

This commit is contained in:
Ycarus (Yannick Chabanois) 2024-12-26 18:19:04 +01:00
parent bdb9b0046f
commit 9d83c70ced
247 changed files with 53301 additions and 589 deletions

View file

@ -11,7 +11,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
--- a/include/linux/compiler.h
+++ b/include/linux/compiler.h
@@ -202,6 +202,8 @@ void ftrace_likely_update(struct ftrace_
@@ -214,6 +214,8 @@ void ftrace_likely_update(struct ftrace_
__v; \
})
@ -20,7 +20,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
#endif /* __KERNEL__ */
/*
@@ -243,6 +245,4 @@ static inline void *offset_to_ptr(const
@@ -314,6 +316,4 @@ static inline void *offset_to_ptr(const
*/
#define prevent_tail_call_optimization() mb()

View file

@ -0,0 +1,21 @@
From 173019b66dcc9d68ad9333aa744dad1e369b5aa8 Mon Sep 17 00:00:00 2001
From: Felix Fietkau <nbd@nbd.name>
Date: Sun, 9 Jul 2017 00:26:53 +0200
Subject: [PATCH 34/34] kernel: add compile fix for linux 4.9 on x86
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
Makefile | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
--- a/Makefile
+++ b/Makefile
@@ -583,7 +583,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
export HOSTRUSTC KBUILD_HOSTRUSTFLAGS
export CPP AR NM STRIP OBJCOPY OBJDUMP READELF PAHOLE RESOLVE_BTFIDS LEX YACC AWK INSTALLKERNEL

View file

@ -71,7 +71,7 @@ Signed-off-by: Tobias Wolf <dev-NTEO@vplace.de>
--- a/mm/mm_init.c
+++ b/mm/mm_init.c
@@ -1673,7 +1673,7 @@ static void __init alloc_node_mem_map(st
@@ -1632,7 +1632,7 @@ static void __init alloc_node_mem_map(st
if (pgdat == NODE_DATA(0)) {
mem_map = NODE_DATA(0)->node_mem_map;
if (page_to_pfn(mem_map) != pgdat->node_start_pfn)

View file

@ -8,7 +8,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
--- a/fs/jffs2/dir.c
+++ b/fs/jffs2/dir.c
@@ -617,8 +617,8 @@ static int jffs2_rmdir (struct inode *di
@@ -620,8 +620,8 @@ static int jffs2_rmdir (struct inode *di
return ret;
}
@ -19,7 +19,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
{
struct jffs2_inode_info *f, *dir_f;
struct jffs2_sb_info *c;
@@ -758,7 +758,11 @@ static int jffs2_mknod (struct mnt_idmap
@@ -761,7 +761,11 @@ static int jffs2_mknod (struct mnt_idmap
mutex_unlock(&dir_f->sem);
jffs2_complete_reservation(c);
@ -32,7 +32,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
return 0;
fail:
@@ -766,6 +770,19 @@ static int jffs2_mknod (struct mnt_idmap
@@ -769,6 +773,19 @@ static int jffs2_mknod (struct mnt_idmap
return ret;
}
@ -52,7 +52,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
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
@@ -780,7 +797,7 @@ static int jffs2_rename (struct mnt_idma
uint8_t type;
uint32_t now;
@ -61,7 +61,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
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
@@ -846,9 +863,14 @@ static int jffs2_rename (struct mnt_idma
if (d_is_dir(old_dentry) && !victim_f)
inc_nlink(new_dir_i);

View file

@ -6,7 +6,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
--- a/fs/jffs2/dir.c
+++ b/fs/jffs2/dir.c
@@ -791,18 +791,31 @@ static int jffs2_rename (struct mnt_idma
@@ -794,18 +794,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;
@ -40,7 +40,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
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
@@ -840,7 +853,7 @@ static int jffs2_rename (struct mnt_idma
if (ret)
return ret;
@ -49,7 +49,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
/* 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
@@ -866,6 +879,12 @@ static int jffs2_rename (struct mnt_idma
if (flags & RENAME_WHITEOUT)
/* Replace with whiteout */
ret = jffs2_whiteout(idmap, old_dir_i, old_dentry);
@ -62,7 +62,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
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
@@ -898,7 +917,7 @@ static int jffs2_rename (struct mnt_idma
return ret;
}
@ -70,4 +70,4 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
+ 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));
inode_set_mtime_to_ts(old_dir_i,

View file

@ -0,0 +1,71 @@
From: Daniel González Cabanelas <dgcbueu@gmail.com>
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.
Signed-off-by: Daniel González Cabanelas <dgcbueu@gmail.com>
---
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:

View file

@ -11,7 +11,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -982,8 +982,10 @@ char *symbol_string(char *buf, char *end
@@ -983,8 +983,10 @@ char *symbol_string(char *buf, char *end
struct printf_spec spec, const char *fmt)
{
unsigned long value;
@ -23,7 +23,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
#endif
if (fmt[1] == 'R')
@@ -1004,8 +1006,14 @@ char *symbol_string(char *buf, char *end
@@ -1005,8 +1007,14 @@ char *symbol_string(char *buf, char *end
return string_nocheck(buf, end, sym, spec);
#else

View file

@ -0,0 +1,31 @@
From c2deb5ef01a0ef09088832744cbace9e239a6ee0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Thibaut=20VAR=C3=88NE?= <hacks@slashdirt.org>
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
Signed-off-by: Thibaut VARÈNE <hacks@slashdirt.org>
---
drivers/platform/Kconfig | 2 ++
drivers/platform/Makefile | 1 +
2 files changed, 3 insertions(+)
--- a/drivers/platform/Kconfig
+++ b/drivers/platform/Kconfig
@@ -18,3 +18,5 @@ source "drivers/platform/surface/Kconfig
source "drivers/platform/x86/Kconfig"
source "drivers/platform/arm64/Kconfig"
+
+source "drivers/platform/mikrotik/Kconfig"
--- a/drivers/platform/Makefile
+++ b/drivers/platform/Makefile
@@ -13,3 +13,4 @@ obj-$(CONFIG_CHROME_PLATFORMS) += chrome
obj-$(CONFIG_CZNIC_PLATFORMS) += cznic/
obj-$(CONFIG_SURFACE_PLATFORMS) += surface/
obj-$(CONFIG_ARM64_PLATFORM_DEVICES) += arm64/
+obj-$(CONFIG_MIKROTIK) += mikrotik/

View file

@ -9,7 +9,7 @@ Acked-by: Rob Landley <rob@landley.net>
---
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -1013,9 +1013,6 @@ config FW_ARC
@@ -1055,9 +1055,6 @@ config FW_ARC
config ARCH_MAY_HAVE_PC_FDC
bool
@ -19,7 +19,7 @@ Acked-by: Rob Landley <rob@landley.net>
config CEVT_BCM1480
bool
@@ -2996,6 +2993,18 @@ choice
@@ -2991,6 +2988,18 @@ choice
bool "Extend builtin kernel arguments with bootloader arguments"
endchoice

View file

@ -11,9 +11,9 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
--- 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
@@ -153,7 +153,7 @@ cflags-$(CONFIG_CPU_R4300) += $(call cc-
cflags-$(CONFIG_CPU_R4X00) += $(call cc-option,-march=r4600,-march=mips3) -Wa,--trap
cflags-$(CONFIG_CPU_TX49XX) += $(call cc-option,-march=r4600,-march=mips3) -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

View file

@ -9,7 +9,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
--- a/arch/arm/kernel/module.c
+++ b/arch/arm/kernel/module.c
@@ -146,6 +146,10 @@ apply_relocate(Elf32_Shdr *sechdrs, cons
@@ -112,6 +112,10 @@ apply_relocate(Elf32_Shdr *sechdrs, cons
return -ENOEXEC;
}

View file

@ -11,9 +11,9 @@ Signed-off-by: Yousong Zhou <yszhou4tech@gmail.com>
--- a/arch/mips/kernel/machine_kexec.c
+++ b/arch/mips/kernel/machine_kexec.c
@@ -9,14 +9,11 @@
#include <linux/delay.h>
@@ -10,14 +10,11 @@
#include <linux/libfdt.h>
#include <linux/reboot.h>
+#include <asm/bootinfo.h>
#include <asm/cacheflush.h>
@ -29,7 +29,7 @@ Signed-off-by: Yousong Zhou <yszhou4tech@gmail.com>
static unsigned long reboot_code_buffer;
@@ -30,6 +27,101 @@ void (*_crash_smp_send_stop)(void) = NUL
@@ -31,6 +28,101 @@ void (*_crash_smp_send_stop)(void) = NUL
void (*_machine_kexec_shutdown)(void) = NULL;
void (*_machine_crash_shutdown)(struct pt_regs *regs) = NULL;
@ -131,7 +131,7 @@ Signed-off-by: Yousong Zhou <yszhou4tech@gmail.com>
static void kexec_image_info(const struct kimage *kimage)
{
unsigned long i;
@@ -99,6 +191,18 @@ machine_kexec_prepare(struct kimage *kim
@@ -100,6 +192,18 @@ machine_kexec_prepare(struct kimage *kim
#endif
kexec_image_info(kimage);
@ -150,7 +150,7 @@ Signed-off-by: Yousong Zhou <yszhou4tech@gmail.com>
if (_machine_kexec_prepare)
return _machine_kexec_prepare(kimage);
@@ -161,7 +265,7 @@ machine_crash_shutdown(struct pt_regs *r
@@ -162,7 +266,7 @@ machine_crash_shutdown(struct pt_regs *r
void kexec_nonboot_cpu_jump(void)
{
local_flush_icache_range((unsigned long)relocated_kexec_smp_wait,
@ -159,7 +159,7 @@ Signed-off-by: Yousong Zhou <yszhou4tech@gmail.com>
relocated_kexec_smp_wait(NULL);
}
@@ -199,7 +303,7 @@ void kexec_reboot(void)
@@ -200,7 +304,7 @@ void kexec_reboot(void)
* machine_kexec() CPU.
*/
local_flush_icache_range(reboot_code_buffer,
@ -168,7 +168,7 @@ Signed-off-by: Yousong Zhou <yszhou4tech@gmail.com>
do_kexec = (void *)reboot_code_buffer;
do_kexec();
@@ -212,10 +316,12 @@ machine_kexec(struct kimage *image)
@@ -213,10 +317,12 @@ machine_kexec(struct kimage *image)
unsigned long *ptr;
reboot_code_buffer =
@ -182,7 +182,7 @@ Signed-off-by: Yousong Zhou <yszhou4tech@gmail.com>
if (image->type == KEXEC_TYPE_DEFAULT) {
kexec_indirection_page =
@@ -223,9 +329,19 @@ machine_kexec(struct kimage *image)
@@ -224,9 +330,19 @@ machine_kexec(struct kimage *image)
} else {
kexec_indirection_page = (unsigned long)&image->head;
}
@ -204,7 +204,7 @@ Signed-off-by: Yousong Zhou <yszhou4tech@gmail.com>
/*
* The generic kexec code builds a page list with physical
@@ -256,7 +372,7 @@ machine_kexec(struct kimage *image)
@@ -257,7 +373,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 +
@ -251,7 +251,7 @@ Signed-off-by: Yousong Zhou <yszhou4tech@gmail.com>
PTR_L a0, arg0
PTR_L a1, arg1
PTR_L a2, arg2
@@ -98,7 +99,7 @@ done:
@@ -97,7 +98,7 @@ done:
#endif
/* jump to kexec_start_address */
j s1
@ -260,7 +260,7 @@ Signed-off-by: Yousong Zhou <yszhou4tech@gmail.com>
#ifdef CONFIG_SMP
/*
@@ -177,8 +178,15 @@ EXPORT(kexec_indirection_page)
@@ -176,8 +177,15 @@ EXPORT(kexec_indirection_page)
PTR_WD 0
.size kexec_indirection_page, PTRSIZE

View file

@ -13,7 +13,7 @@ Signed-off-by: Alexey Brodkin <abrodkin@synopsys.com>
--- a/arch/arc/kernel/unaligned.c
+++ b/arch/arc/kernel/unaligned.c
@@ -202,7 +202,7 @@ int misaligned_fixup(unsigned long addre
@@ -203,7 +203,7 @@ int misaligned_fixup(unsigned long addre
char buf[TASK_COMM_LEN];
/* handle user mode only and only if enabled by sysadmin */

View file

@ -14,7 +14,7 @@ Signed-off-by: Pawel Dembicki <paweldembicki@gmail.com>
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -251,7 +251,7 @@ config PPC
@@ -254,7 +254,7 @@ config PPC
select HAVE_KERNEL_GZIP
select HAVE_KERNEL_LZMA if DEFAULT_UIMAGE
select HAVE_KERNEL_LZO if DEFAULT_UIMAGE

View file

@ -31,7 +31,7 @@ Signed-off-by: Shiji Yang <yangshiji66@outlook.com>
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 = {
@@ -86,21 +86,27 @@ static struct resource bss_resource = {
unsigned long __kaslr_offset __ro_after_init;
EXPORT_SYMBOL(__kaslr_offset);
@ -64,7 +64,7 @@ Signed-off-by: Shiji Yang <yangshiji66@outlook.com>
}
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
@@ -111,6 +117,7 @@ void __init detect_memory_region(phys_ad
memblock_add(start, size);
}

View file

@ -230,7 +230,7 @@ Subject: [PATCH] mtd: mtdsplit support
mtd_add_partition_attrs(child);
/* Look for subpartitions */
@@ -439,31 +584,6 @@ err_del_partitions:
@@ -443,31 +588,6 @@ err_del_partitions:
return ret;
}

View file

@ -16,7 +16,7 @@ Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
--- a/drivers/mtd/mtdcore.c
+++ b/drivers/mtd/mtdcore.c
@@ -548,6 +548,29 @@ static int mtd_nvmem_add(struct mtd_info
@@ -549,6 +549,29 @@ static int mtd_nvmem_add(struct mtd_info
struct device_node *node = mtd_get_of_node(mtd);
struct nvmem_config config = {};

View file

@ -0,0 +1,245 @@
From acacdac272927ae1d96e0bca51eb82899671eaea Mon Sep 17 00:00:00 2001
From: John Thomson <git@johnthomson.fastmail.com.au>
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
Signed-off-by: John Thomson <git@johnthomson.fastmail.com.au>
Signed-off-by: Thibaut VARÈNE <hacks+kernel@slashdirt.org>
---
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
Reported-by: kernel test robot <lkp@intel.com>
Reported-by: Dan Carpenter <dan.carpenter@oracle.com>
---
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
@@ -199,6 +199,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)
{
@@ -344,6 +353,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
@@ -1158,6 +1158,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_region.erase_mask;
}
@@ -2516,6 +2518,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;
int i;
@@ -2542,8 +2545,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];
}
}
@@ -2551,6 +2555,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

View file

@ -10,7 +10,7 @@ Signed-off-by: Adrian Schmutzler <freifunk@adrianschmutzler.de>
--- a/drivers/mtd/parsers/Kconfig
+++ b/drivers/mtd/parsers/Kconfig
@@ -67,6 +67,22 @@ config MTD_CMDLINE_PARTS
@@ -62,6 +62,22 @@ config MTD_CMDLINE_PARTS
If unsure, say 'N'.
@ -35,7 +35,7 @@ Signed-off-by: Adrian Schmutzler <freifunk@adrianschmutzler.de>
default y
--- a/drivers/mtd/parsers/Makefile
+++ b/drivers/mtd/parsers/Makefile
@@ -4,6 +4,7 @@ obj-$(CONFIG_MTD_BCM47XX_PARTS) += bcm4
@@ -3,6 +3,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

View file

@ -16,7 +16,7 @@ Signed-off-by: Thibaut VARÈNE <hacks@slashdirt.org>
--- a/drivers/mtd/parsers/Kconfig
+++ b/drivers/mtd/parsers/Kconfig
@@ -236,3 +236,12 @@ config MTD_SERCOMM_PARTS
@@ -231,3 +231,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.
@ -31,7 +31,7 @@ Signed-off-by: Thibaut VARÈNE <hacks@slashdirt.org>
+ formatted DTS.
--- a/drivers/mtd/parsers/Makefile
+++ b/drivers/mtd/parsers/Makefile
@@ -17,3 +17,4 @@ obj-$(CONFIG_MTD_SERCOMM_PARTS) += scpa
@@ -16,3 +16,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

View file

@ -0,0 +1,135 @@
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-Submitter: Daniel Golle <daniel@makrotopia.org>
X-Patchwork-Id: 13747816
Date: Tue, 30 Jul 2024 20:25:59 +0100
From: Daniel Golle <daniel@makrotopia.org>
To: Rob Herring <robh@kernel.org>, Krzysztof Kozlowski <krzk+dt@kernel.org>,
Conor Dooley <conor+dt@kernel.org>, Jens Axboe <axboe@kernel.dk>,
Daniel Golle <daniel@makrotopia.org>, Christian Brauner <brauner@kernel.org>,
Al Viro <viro@zeniv.linux.org.uk>, Li Lingfeng <lilingfeng3@huawei.com>,
Ming Lei <ming.lei@redhat.com>, Christian Heusel <christian@heusel.eu>,
=?utf-8?b?UmFmYcWCIE1pxYJlY2tp?= <rafal@milecki.pl>,
Felix Fietkau <nbd@nbd.name>, John Crispin <john@phrozen.org>,
Chad Monroe <chad.monroe@adtran.com>, Yangyu Chen <cyy@cyyself.name>,
Tianling Shen <cnsztl@immortalwrt.org>, Chuanhong Guo <gch981213@gmail.com>,
Chen Minqiang <ptpt52@gmail.com>, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org, linux-block@vger.kernel.org
Subject: [PATCH v5 2/4] block: partitions: populate fwnode
Message-ID:
<3051ac090ad3b3e2f5adb6b67c923261ead729a5.1722365899.git.daniel@makrotopia.org>
References: <cover.1722365899.git.daniel@makrotopia.org>
Precedence: bulk
X-Mailing-List: linux-block@vger.kernel.org
List-Id: <linux-block.vger.kernel.org>
List-Subscribe: <mailto:linux-block+subscribe@vger.kernel.org>
List-Unsubscribe: <mailto:linux-block+unsubscribe@vger.kernel.org>
MIME-Version: 1.0
Content-Disposition: inline
In-Reply-To: <cover.1722365899.git.daniel@makrotopia.org>
Assign matching firmware nodes to block partitions in order to allow
them to be referenced e.g. as NVMEM providers.
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
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 *) = {
@@ -284,6 +286,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 && (atomic_read(&bdev->__bd_flags) & 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.
@@ -358,6 +428,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);

View file

@ -1,7 +1,34 @@
From e07ace307ce598847074a096f408bec0e3a392ed Mon Sep 17 00:00:00 2001
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-Submitter: Daniel Golle <daniel@makrotopia.org>
X-Patchwork-Id: 13747817
Date: Tue, 30 Jul 2024 20:26:42 +0100
From: Daniel Golle <daniel@makrotopia.org>
Date: Thu, 30 May 2024 03:14:34 +0100
Subject: [PATCH 3/9] block: add support for notifications
To: Rob Herring <robh@kernel.org>, Krzysztof Kozlowski <krzk+dt@kernel.org>,
Conor Dooley <conor+dt@kernel.org>, Jens Axboe <axboe@kernel.dk>,
Daniel Golle <daniel@makrotopia.org>, Christian Brauner <brauner@kernel.org>,
Al Viro <viro@zeniv.linux.org.uk>, Li Lingfeng <lilingfeng3@huawei.com>,
Ming Lei <ming.lei@redhat.com>, Christian Heusel <christian@heusel.eu>,
=?utf-8?b?UmFmYcWCIE1pxYJlY2tp?= <rafal@milecki.pl>,
Felix Fietkau <nbd@nbd.name>, John Crispin <john@phrozen.org>,
Chad Monroe <chad.monroe@adtran.com>, Yangyu Chen <cyy@cyyself.name>,
Tianling Shen <cnsztl@immortalwrt.org>, Chuanhong Guo <gch981213@gmail.com>,
Chen Minqiang <ptpt52@gmail.com>, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org, linux-block@vger.kernel.org
Subject: [PATCH v5 3/4] block: add support for notifications
Message-ID:
<ca0022886e8f211a323a716653a1396a3bc91653.1722365899.git.daniel@makrotopia.org>
References: <cover.1722365899.git.daniel@makrotopia.org>
Precedence: bulk
X-Mailing-List: linux-block@vger.kernel.org
List-Id: <linux-block.vger.kernel.org>
List-Subscribe: <mailto:linux-block+subscribe@vger.kernel.org>
List-Unsubscribe: <mailto:linux-block+unsubscribe@vger.kernel.org>
MIME-Version: 1.0
Content-Disposition: inline
In-Reply-To: <cover.1722365899.git.daniel@makrotopia.org>
Add notifier block to notify other subsystems about the addition or
removal of block devices.
@ -10,14 +37,14 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
block/Kconfig | 6 +++
block/Makefile | 1 +
block/blk-notify.c | 88 ++++++++++++++++++++++++++++++++++++++++++
include/linux/blkdev.h | 8 ++++
4 files changed, 103 insertions(+)
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
@@ -209,6 +209,12 @@ config BLK_INLINE_ENCRYPTION_FALLBACK
by falling back to the kernel crypto API when inline
encryption hardware is not present.
@ -32,14 +59,14 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
config BLK_MQ_PCI
--- a/block/Makefile
+++ b/block/Makefile
@@ -40,3 +40,4 @@ obj-$(CONFIG_BLK_INLINE_ENCRYPTION) += b
@@ -38,3 +38,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,88 @@
@@ -0,0 +1,87 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Notifiers for addition and removal of block devices
@ -97,7 +124,6 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+ 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;
+}
+
@ -130,16 +156,19 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+device_initcall(blk_notifications_init);
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -1564,4 +1564,12 @@ struct io_comp_batch {
@@ -1689,4 +1689,15 @@ static inline bool bdev_can_atomic_write
#define DEFINE_IO_COMP_BATCH(name) struct io_comp_batch name = { }
+
+#ifdef CONFIG_BLOCK_NOTIFIERS
+#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 */

View file

@ -1,7 +1,34 @@
From f4487fa1cb7e55b3c17a33f41b9c9d66f4f853b7 Mon Sep 17 00:00:00 2001
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-Submitter: Daniel Golle <daniel@makrotopia.org>
X-Patchwork-Id: 13747818
Date: Tue, 30 Jul 2024 20:27:07 +0100
From: Daniel Golle <daniel@makrotopia.org>
Date: Thu, 30 May 2024 03:14:49 +0100
Subject: [PATCH 4/9] block: add new genhd flag GENHD_FL_NVMEM
To: Rob Herring <robh@kernel.org>, Krzysztof Kozlowski <krzk+dt@kernel.org>,
Conor Dooley <conor+dt@kernel.org>, Jens Axboe <axboe@kernel.dk>,
Daniel Golle <daniel@makrotopia.org>, Christian Brauner <brauner@kernel.org>,
Al Viro <viro@zeniv.linux.org.uk>, Li Lingfeng <lilingfeng3@huawei.com>,
Ming Lei <ming.lei@redhat.com>, Christian Heusel <christian@heusel.eu>,
=?utf-8?b?UmFmYcWCIE1pxYJlY2tp?= <rafal@milecki.pl>,
Felix Fietkau <nbd@nbd.name>, John Crispin <john@phrozen.org>,
Chad Monroe <chad.monroe@adtran.com>, Yangyu Chen <cyy@cyyself.name>,
Tianling Shen <cnsztl@immortalwrt.org>, Chuanhong Guo <gch981213@gmail.com>,
Chen Minqiang <ptpt52@gmail.com>, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org, linux-block@vger.kernel.org
Subject: [PATCH v5 4/4] block: add new genhd flag GENHD_FL_NVMEM
Message-ID:
<311ea569c23ce14e2896cd3b069dc494c58c49c2.1722365899.git.daniel@makrotopia.org>
References: <cover.1722365899.git.daniel@makrotopia.org>
Precedence: bulk
X-Mailing-List: linux-block@vger.kernel.org
List-Id: <linux-block.vger.kernel.org>
List-Subscribe: <mailto:linux-block+subscribe@vger.kernel.org>
List-Unsubscribe: <mailto:linux-block+unsubscribe@vger.kernel.org>
MIME-Version: 1.0
Content-Disposition: inline
In-Reply-To: <cover.1722365899.git.daniel@makrotopia.org>
Add new flag to destinguish block devices which may act as an NVMEM
provider.
@ -13,7 +40,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -80,11 +80,13 @@ struct partition_meta_info {
@@ -82,11 +82,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.
*

View file

@ -12,7 +12,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -364,6 +364,8 @@ int mmc_add_card(struct mmc_card *card)
@@ -368,6 +368,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);

View file

@ -0,0 +1,27 @@
From ef3e38fec26901b71975d7e810a2df6b8bd54a8e Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org>
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.
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
drivers/mmc/core/block.c | 7 +++++++
1 file changed, 7 insertions(+)
--- a/drivers/mmc/core/block.c
+++ b/drivers/mmc/core/block.c
@@ -2678,6 +2678,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)

View file

@ -12,7 +12,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
--- a/drivers/mmc/core/block.c
+++ b/drivers/mmc/core/block.c
@@ -2516,6 +2516,7 @@ static struct mmc_blk_data *mmc_blk_allo
@@ -2644,6 +2644,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;

View file

@ -8,7 +8,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
--- 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
@@ -194,6 +194,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;

View file

@ -0,0 +1,22 @@
From: Piotr Dymacz <pepe2k@gmail.com>
Subject: kernel/mtd: add support for EON EN25Q128
Signed-off-by: Piotr Dymacz <pepe2k@gmail.com>
---
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
@@ -18,6 +18,11 @@ static const struct flash_info eon_nor_p
.name = "en25p64",
.size = SZ_8M,
}, {
+ .id = SNOR_ID(0x1c, 0x30, 0x18),
+ .name = "en25q128",
+ .size = SZ_16M,
+ .no_sfdp_flags = SECT_4K,
+ }, {
.id = SNOR_ID(0x1c, 0x30, 0x14),
.name = "en25q80a",
.size = SZ_1M,

View file

@ -0,0 +1,24 @@
From: Christian Marangi <ansuelsmth@gmail.com>
Subject: kernel/mtd: add support for EON EN25QX128A
Add support for EON EN25QX128A with no flags as it does
support SFDP parsing.
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
---
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
@@ -23,6 +23,10 @@ static const struct flash_info eon_nor_p
.size = SZ_16M,
.no_sfdp_flags = SECT_4K,
}, {
+ .id = SNOR_ID(0x1c, 0x71, 0x18),
+ .name = "en25qx128a",
+ .size = SZ_16M,
+ }, {
.id = SNOR_ID(0x1c, 0x30, 0x14),
.name = "en25q80a",
.size = SZ_1M,

View file

@ -0,0 +1,84 @@
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-Submitter: Daniel Golle <daniel@makrotopia.org>
X-Patchwork-Id: 1234465
Date: Thu, 6 Feb 2020 19:19:41 +0200
From: Daniel Golle <daniel@makrotopia.org>
To: linux-mtd@lists.infradead.org
Subject: [PATCH v2] mtd: spi-nor: Add support for xt25f128b chip
Message-ID: <20200206171941.GA2398@makrotopia.org>
MIME-Version: 1.0
Content-Disposition: inline
List-Subscribe: <http://lists.infradead.org/mailman/listinfo/linux-mtd>,
<mailto:linux-mtd-request@lists.infradead.org?subject=subscribe>
Cc: Eitan Cohen <eitan@neot-semadar.com>, Piotr Dymacz <pepe2k@gmail.com>,
Tudor Ambarus <tudor.ambarus@microchip.com>
Sender: "linux-mtd" <linux-mtd-bounces@lists.infradead.org>
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.
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
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
@@ -14,6 +14,7 @@ spi-nor-objs += spansion.o
spi-nor-objs += sst.o
spi-nor-objs += winbond.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,20 @@
+// 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 */
+ {
+ .id = SNOR_ID(0x0B, 0x40, 0x18),
+ .name = "xt25f128b",
+ .size = SZ_16M,
+ .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
@@ -1979,6 +1979,7 @@ static const struct spi_nor_manufacturer
&spi_nor_sst,
&spi_nor_winbond,
&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
@@ -593,6 +593,7 @@ extern const struct spi_nor_manufacturer
extern const struct spi_nor_manufacturer spi_nor_sst;
extern const struct spi_nor_manufacturer spi_nor_winbond;
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[];

View file

@ -0,0 +1,25 @@
From d68b4aa22e8c625685bfad642dd7337948dc0ad1 Mon Sep 17 00:00:00 2001
From: Koen Vandeputte <koen.vandeputte@ncentric.com>
Date: Mon, 6 Jan 2020 13:07:56 +0100
Subject: [PATCH] mtd: spi-nor: add support for Gigadevice GD25D05
Signed-off-by: Koen Vandeputte <koen.vandeputte@ncentric.com>
---
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
@@ -35,6 +35,12 @@ static const struct spi_nor_fixups gd25q
static const struct flash_info gigadevice_nor_parts[] = {
{
+ .id = SNOR_ID(0xc8, 0x40, 0x10),
+ .name = "gd25q05",
+ .size = SZ_64K,
+ .flags = SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB,
+ .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ,
+ }, {
.id = SNOR_ID(0xc8, 0x40, 0x15),
.name = "gd25q16",
.size = SZ_2M,

View file

@ -0,0 +1,25 @@
From f8943df3beb0d3f9754bb35320c3a378727175a8 Mon Sep 17 00:00:00 2001
From: OpenWrt community <openwrt-devel@lists.openwrt.org>
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,13 @@ static const struct flash_info gigadevic
.fixups = &gd25q256_fixups,
.fixup_flags = SPI_NOR_4B_OPCODES,
}, {
+ .id = SNOR_ID(0xc8, 0x40, 0x20),
+ .name = "gd25q512",
+ .size = SZ_64M,
+ .flags = SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB,
+ .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ,
+ .fixup_flags = SPI_NOR_4B_OPCODES,
+ }, {
.id = SNOR_ID(0xc8, 0x60, 0x16),
.name = "gd25lq32",
.size = SZ_4M,

View file

@ -0,0 +1,27 @@
From 87363cc0e522de3294ea6ae10fb468d2a8d6fb2f Mon Sep 17 00:00:00 2001
From: OpenWrt community <openwrt-devel@lists.openwrt.org>
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,12 @@
static const struct flash_info esmt_nor_parts[] = {
{
+ .id = SNOR_ID(0x8c, 0x21, 0x15),
+ .name = "f25l16pa-2s",
+ .size = SZ_2M,
+ .flags = SPI_NOR_HAS_LOCK,
+ .no_sfdp_flags = SECT_4K,
+ }, {
.id = SNOR_ID(0x8c, 0x20, 0x16),
.name = "f25l32pa",
.size = SZ_4M,

View file

@ -0,0 +1,27 @@
From f6b33d850f7f12555df2fa0e3349b33427bf5890 Mon Sep 17 00:00:00 2001
From: OpenWrt community <openwrt-devel@lists.openwrt.org>
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
@@ -19,6 +19,11 @@ static const struct flash_info xmc_nor_p
.name = "XM25QH128A",
.size = SZ_16M,
.no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ,
+ }, {
+ .id = SNOR_ID(0x20, 0x40, 0x18),
+ .name = "XM25QH128C",
+ .size = SZ_16M,
+ .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ,
},
};

View file

@ -0,0 +1,170 @@
From f32085fc0b87049491b07e198d924d738a1a2834 Mon Sep 17 00:00:00 2001
From: Daniel Danzberger <daniel@dd-wrt.com>
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
-
Submitted-by: Daniel Danzberger <daniel@dd-wrt.com>
--- 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 += micron.o paragon.o toshiba.o winbond.o xtx.o
+spinand-objs := core.o alliancememory.o ato.o esmt.o etron.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
@@ -1112,6 +1112,7 @@ static const struct spinand_manufacturer
&alliancememory_spinand_manufacturer,
&ato_spinand_manufacturer,
&esmt_c8_spinand_manufacturer,
+ &etron_spinand_manufacturer,
&foresee_spinand_manufacturer,
&gigadevice_spinand_manufacturer,
&macronix_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 foresee_spinand_manufacturer;
extern const struct spinand_manufacturer gigadevice_spinand_manufacturer;
extern const struct spinand_manufacturer macronix_spinand_manufacturer;

View file

@ -0,0 +1,25 @@
From: Joe Mullally <jwmullally@gmail.com>
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
Signed-off-by: Joe Mullally <jwmullally@gmail.com>
---
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
@@ -15,6 +15,11 @@ static const struct flash_info xmc_nor_p
.size = SZ_8M,
.no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ,
}, {
+ .id = SNOR_ID(0x20, 0x40, 0x17),
+ .name = "XM25QH64C",
+ .size = SZ_8M,
+ .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ,
+ }, {
.id = SNOR_ID(0x20, 0x70, 0x18),
.name = "XM25QH128A",
.size = SZ_16M,

View file

@ -8,7 +8,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
--- a/drivers/mtd/ubi/build.c
+++ b/drivers/mtd/ubi/build.c
@@ -1258,6 +1258,80 @@ static struct mtd_notifier ubi_mtd_notif
@@ -1263,6 +1263,80 @@ static struct mtd_notifier ubi_mtd_notif
.remove = ubi_notify_remove,
};
@ -89,7 +89,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
static int __init ubi_init_attach(void)
{
int err, i, k;
@@ -1308,6 +1382,12 @@ static int __init ubi_init_attach(void)
@@ -1314,6 +1388,12 @@ static int __init ubi_init_attach(void)
}
}

View file

@ -8,7 +8,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
--- a/drivers/mtd/ubi/block.c
+++ b/drivers/mtd/ubi/block.c
@@ -570,10 +570,47 @@ match_volume_desc(struct ubi_volume_info
@@ -575,10 +575,47 @@ match_volume_desc(struct ubi_volume_info
return true;
}
@ -24,7 +24,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+ return magic == UBIFS_NODE_MAGIC;
+}
+
+static void __init ubiblock_create_auto_rootfs(struct ubi_volume_info *vi)
+static void ubiblock_create_auto_rootfs(struct ubi_volume_info *vi)
+{
+ int ret, is_ubifs;
+ struct ubi_volume_desc *desc;
@ -56,7 +56,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
struct ubiblock_param *p;
/*
@@ -586,6 +623,7 @@ ubiblock_create_from_param(struct ubi_vo
@@ -591,6 +628,7 @@ ubiblock_create_from_param(struct ubi_vo
if (!match_volume_desc(vi, p->name, p->ubi_num, p->vol_id))
continue;
@ -64,7 +64,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
ret = ubiblock_create(vi);
if (ret) {
pr_err(
@@ -594,6 +632,10 @@ ubiblock_create_from_param(struct ubi_vo
@@ -599,6 +637,10 @@ ubiblock_create_from_param(struct ubi_vo
}
break;
}

View file

@ -8,7 +8,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
--- a/init/do_mounts.c
+++ b/init/do_mounts.c
@@ -248,7 +248,30 @@ retry:
@@ -250,7 +250,30 @@ retry:
out:
put_page(page);
}
@ -40,7 +40,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
#ifdef CONFIG_ROOT_NFS
#define NFSROOT_TIMEOUT_MIN 5
@@ -385,6 +408,11 @@ static inline void mount_block_root(char
@@ -387,6 +410,11 @@ static inline void mount_block_root(char
void __init mount_root(char *root_device_name)
{

View file

@ -16,7 +16,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
#include "ubi-media.h"
#include "ubi.h"
@@ -428,6 +429,15 @@ int ubiblock_create(struct ubi_volume_in
@@ -431,6 +432,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);

View file

@ -50,7 +50,7 @@ Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
break;
--- a/drivers/mtd/ubi/ubi.h
+++ b/drivers/mtd/ubi/ubi.h
@@ -780,6 +780,7 @@ struct ubi_attach_info {
@@ -778,6 +778,7 @@ struct ubi_attach_info {
int mean_ec;
uint64_t ec_sum;
int ec_count;

View file

@ -85,7 +85,7 @@ Signed-off-by: Bernhard Frauendienst <kernel@nospam.obeliks.de>
+obj-$(CONFIG_MTD_VIRT_CONCAT) += virt_concat.o
--- /dev/null
+++ b/drivers/mtd/composite/virt_concat.c
@@ -0,0 +1,128 @@
@@ -0,0 +1,127 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Virtual concat MTD device driver
@ -94,6 +94,7 @@ Signed-off-by: Bernhard Frauendienst <kernel@nospam.obeliks.de>
+ * Author: Bernhard Frauendienst, kernel@nospam.obeliks.de
+ */
+
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/mtd/concat.h>
@ -115,14 +116,14 @@ Signed-off-by: Bernhard Frauendienst <kernel@nospam.obeliks.de>
+ struct mtd_info **devices;
+};
+
+static int virt_concat_remove(struct platform_device *pdev)
+static void virt_concat_remove(struct platform_device *pdev)
+{
+ struct of_virt_concat *info;
+ int i;
+
+ info = platform_get_drvdata(pdev);
+ if (!info)
+ return 0;
+ return;
+
+ // unset data for when this is called after a probe error
+ platform_set_drvdata(pdev, NULL);
@ -136,8 +137,6 @@ Signed-off-by: Bernhard Frauendienst <kernel@nospam.obeliks.de>
+ 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)

View file

@ -0,0 +1,32 @@
From 8bf2ce6ea4ee840b70f55a27f80e1cd308051b13 Mon Sep 17 00:00:00 2001
From: Nick Hainke <vincent@systemli.org>
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")
Signed-off-by: David Bauer <mail@david-bauer.net>
Signed-off-by: Nick Hainke <vincent@systemli.org>
---
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
@@ -66,6 +66,7 @@ static const struct flash_info macronix_
.id = SNOR_ID(0xc2, 0x20, 0x17),
.name = "mx25l6405d",
.size = SZ_8M,
+ .flags = SPI_NOR_HAS_LOCK | SPI_NOR_4BIT_BP,
.no_sfdp_flags = SECT_4K,
}, {
.id = SNOR_ID(0xc2, 0x20, 0x18),

View file

@ -20,7 +20,7 @@ Signed-off-by: Nick Hainke <vincent@systemli.org>
--- 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
@@ -195,6 +195,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;

View file

@ -36,7 +36,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -22014,6 +22014,12 @@ F: Documentation/filesystems/ubifs-authe
@@ -23658,6 +23658,12 @@ F: Documentation/filesystems/ubifs-authe
F: Documentation/filesystems/ubifs.rst
F: fs/ubifs/
@ -51,9 +51,9 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
L: linux-block@vger.kernel.org
--- 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.
@@ -363,6 +363,18 @@ config BLK_DEV_RUST_NULL
If unsure, say N.
+config UIMAGE_FIT_BLK
+ bool "uImage.FIT block driver"
@ -72,7 +72,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
depends on INET && BLOCK
--- a/drivers/block/Makefile
+++ b/drivers/block/Makefile
@@ -39,4 +39,6 @@ obj-$(CONFIG_BLK_DEV_NULL_BLK) += null_b
@@ -42,4 +42,6 @@ obj-$(CONFIG_BLK_DEV_NULL_BLK) += null_b
obj-$(CONFIG_BLK_DEV_UBLK) += ublk_drv.o
@ -81,7 +81,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
swim_mod-y := swim.o swim_asm.o
--- /dev/null
+++ b/drivers/block/fitblk.c
@@ -0,0 +1,659 @@
@@ -0,0 +1,658 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * uImage.FIT virtual block device driver.
@ -668,7 +668,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+ (imgmaxsect + MIN_FREE_SECT) < dsectors) {
+ add_fit_subimage_device(bdev, slot++, imgmaxsect,
+ dsectors - imgmaxsect, false);
+ dev_info(dev, "mapped remaing space as /dev/fitrw\n");
+ dev_info(dev, "mapped remaining space as /dev/fitrw\n");
+ }
+
+out_bootconf:
@ -714,7 +714,6 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+ .probe = fitblk_probe,
+ .driver = {
+ .name = "fitblk",
+ .owner = THIS_MODULE,
+ },
+};
+

View file

@ -13,7 +13,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
--- a/init/do_mounts.c
+++ b/init/do_mounts.c
@@ -463,7 +463,8 @@ static dev_t __init parse_root_device(ch
@@ -465,7 +465,8 @@ static dev_t __init parse_root_device(ch
int error;
dev_t dev;

File diff suppressed because it is too large Load diff

View file

@ -17,7 +17,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
#include <net/net_namespace.h>
#ifdef CONFIG_SYSCTL
#include <linux/sysctl.h>
@@ -461,6 +462,58 @@ static int ct_cpu_seq_show(struct seq_fi
@@ -458,6 +459,58 @@ static int ct_cpu_seq_show(struct seq_fi
return 0;
}
@ -76,7 +76,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
static const struct seq_operations ct_cpu_seq_ops = {
.start = ct_cpu_seq_start,
.next = ct_cpu_seq_next,
@@ -474,8 +527,9 @@ static int nf_conntrack_standalone_init_
@@ -471,8 +524,9 @@ static int nf_conntrack_standalone_init_
kuid_t root_uid;
kgid_t root_gid;

View file

@ -22,7 +22,7 @@ Link: https://bugzilla.kernel.org/show_bug.cgi?id=109581
--- a/net/sched/sch_codel.c
+++ b/net/sched/sch_codel.c
@@ -95,11 +95,17 @@ static struct sk_buff *codel_qdisc_deque
@@ -65,11 +65,17 @@ static struct sk_buff *codel_qdisc_deque
&q->stats, qdisc_pkt_len, codel_get_enqueue_time,
drop_func, dequeue_func);

View file

@ -30,7 +30,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
#define PACKET_FANOUT_LB 1
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -1864,6 +1864,7 @@ static int packet_rcv_spkt(struct sk_buf
@@ -1925,6 +1925,7 @@ static int packet_rcv_spkt(struct sk_buf
{
struct sock *sk;
struct sockaddr_pkt *spkt;
@ -38,7 +38,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
/*
* When we registered the protocol we saved the socket in the data
@@ -1871,6 +1872,7 @@ static int packet_rcv_spkt(struct sk_buf
@@ -1932,6 +1933,7 @@ static int packet_rcv_spkt(struct sk_buf
*/
sk = pt->af_packet_priv;
@ -46,7 +46,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
/*
* Yank back the headers [hope the device set this
@@ -1883,7 +1885,7 @@ static int packet_rcv_spkt(struct sk_buf
@@ -1944,7 +1946,7 @@ static int packet_rcv_spkt(struct sk_buf
* so that this procedure is noop.
*/
@ -55,9 +55,9 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
goto out;
if (!net_eq(dev_net(dev), sock_net(sk)))
@@ -2129,12 +2131,12 @@ static int packet_rcv(struct sk_buff *sk
@@ -2189,12 +2191,12 @@ static int packet_rcv(struct sk_buff *sk
int skb_len = skb->len;
unsigned int snaplen, res;
bool is_drop_n_account = false;
- if (skb->pkt_type == PACKET_LOOPBACK)
- goto drop;
@ -71,7 +71,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
if (!net_eq(dev_net(dev), sock_net(sk)))
goto drop;
@@ -2261,12 +2263,12 @@ static int tpacket_rcv(struct sk_buff *s
@@ -2318,12 +2320,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);
@ -87,7 +87,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
if (!net_eq(dev_net(dev), sock_net(sk)))
goto drop;
@@ -3385,6 +3387,7 @@ static int packet_create(struct net *net
@@ -3444,6 +3446,7 @@ static int packet_create(struct net *net
mutex_init(&po->pg_vec_lock);
po->rollover = NULL;
po->prot_hook.func = packet_rcv;
@ -95,7 +95,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
if (sock->type == SOCK_PACKET)
po->prot_hook.func = packet_rcv_spkt;
@@ -4034,6 +4037,16 @@ packet_setsockopt(struct socket *sock, i
@@ -4111,6 +4114,16 @@ packet_setsockopt(struct socket *sock, i
packet_sock_flag_set(po, PACKET_SOCK_QDISC_BYPASS, val);
return 0;
}
@ -112,9 +112,9 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
default:
return -ENOPROTOOPT;
}
@@ -4093,6 +4106,13 @@ static int packet_getsockopt(struct sock
case PACKET_VNET_HDR_SZ:
val = READ_ONCE(po->vnet_hdr_sz);
@@ -4173,6 +4186,13 @@ static int packet_getsockopt(struct sock
case PACKET_COPY_THRESH:
val = READ_ONCE(pkt_sk(sk)->copy_thresh);
break;
+ case PACKET_RECV_TYPE:
+ if (len > sizeof(unsigned int))

View file

@ -0,0 +1,42 @@
From: Felix Fietkau <nbd@nbd.name>
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.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
--- a/net/bridge/br_switchdev.c
+++ b/net/bridge/br_switchdev.c
@@ -568,10 +568,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

View file

@ -0,0 +1,38 @@
From: "Leon M. Busch-George" <leon@georgemail.eu>
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.
Co-developed-by: Felix Fietkau <nbd@nbd.name>
Signed-off-by: Felix Fietkau <nbd@nbd.name>
Signed-off-by: Leon M. Busch-George <leon@georgemail.eu>
---
--- a/net/bridge/br_switchdev.c
+++ b/net/bridge/br_switchdev.c
@@ -67,7 +67,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 */

View file

@ -9,7 +9,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -3062,7 +3062,7 @@ static inline int pskb_network_may_pull(
@@ -3180,7 +3180,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

View file

@ -39,8 +39,8 @@ Signed-off-by: Steven Barth <cyrus@openwrt.org>
struct in6_addr raddr; /* remote tunnel end-point address */
+ struct __ip6_tnl_fmr *fmrs; /* FMRs */
__be16 i_flags;
__be16 o_flags;
IP_TUNNEL_DECLARE_FLAGS(i_flags);
IP_TUNNEL_DECLARE_FLAGS(o_flags);
--- a/include/uapi/linux/if_tunnel.h
+++ b/include/uapi/linux/if_tunnel.h
@@ -77,10 +77,23 @@ enum {
@ -79,7 +79,7 @@ Signed-off-by: Steven Barth <cyrus@openwrt.org>
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -67,9 +70,9 @@ static bool log_ecn_error = true;
@@ -68,9 +71,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");
@ -91,7 +91,7 @@ Signed-off-by: Steven Barth <cyrus@openwrt.org>
return hash_32(hash, IP6_TUNNEL_HASH_SIZE_SHIFT);
}
@@ -114,17 +117,33 @@ static struct ip6_tnl *
@@ -115,17 +118,33 @@ static struct ip6_tnl *
ip6_tnl_lookup(struct net *net, int link,
const struct in6_addr *remote, const struct in6_addr *local)
{
@ -127,7 +127,7 @@ Signed-off-by: Steven Barth <cyrus@openwrt.org>
if (link == t->parms.link)
return t;
else
@@ -132,7 +151,7 @@ ip6_tnl_lookup(struct net *net, int link
@@ -133,7 +152,7 @@ ip6_tnl_lookup(struct net *net, int link
}
memset(&any, 0, sizeof(any));
@ -136,7 +136,7 @@ Signed-off-by: Steven Barth <cyrus@openwrt.org>
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
@@ -146,7 +165,7 @@ ip6_tnl_lookup(struct net *net, int link
cand = t;
}
@ -145,7 +145,7 @@ Signed-off-by: Steven Barth <cyrus@openwrt.org>
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,
@@ -195,7 +214,7 @@ ip6_tnl_bucket(struct ip6_tnl_net *ip6n,
if (!ipv6_addr_any(remote) || !ipv6_addr_any(local)) {
prio = 1;
@ -167,7 +167,7 @@ Signed-off-by: Steven Barth <cyrus@openwrt.org>
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,
@@ -790,6 +815,107 @@ int ip6_tnl_rcv_ctl(struct ip6_tnl *t,
}
EXPORT_SYMBOL_GPL(ip6_tnl_rcv_ctl);
@ -303,7 +303,7 @@ Signed-off-by: Steven Barth <cyrus@openwrt.org>
__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
@@ -1004,6 +1151,7 @@ static void init_tel_txopt(struct ipv6_t
opt->ops.opt_nflen = 8;
}
@ -311,7 +311,7 @@ Signed-off-by: Steven Barth <cyrus@openwrt.org>
/**
* ip6_tnl_addr_conflict - compare packet addresses to tunnel's own
* @t: the outgoing tunnel device
@@ -1292,6 +1440,7 @@ ipxip6_tnl_xmit(struct sk_buff *skb, str
@@ -1294,6 +1442,7 @@ ipxip6_tnl_xmit(struct sk_buff *skb, str
u8 protocol)
{
struct ip6_tnl *t = netdev_priv(dev);
@ -319,7 +319,7 @@ Signed-off-by: Steven Barth <cyrus@openwrt.org>
struct ipv6hdr *ipv6h;
const struct iphdr *iph;
int encap_limit = -1;
@@ -1391,6 +1540,18 @@ ipxip6_tnl_xmit(struct sk_buff *skb, str
@@ -1393,6 +1542,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);
@ -338,7 +338,7 @@ Signed-off-by: Steven Barth <cyrus@openwrt.org>
if (iptunnel_handle_offloads(skb, SKB_GSO_IPXIP6))
return -1;
@@ -1543,6 +1704,14 @@ ip6_tnl_change(struct ip6_tnl *t, const
@@ -1546,6 +1707,14 @@ ip6_tnl_change(struct ip6_tnl *t, const
t->parms.link = p->link;
t->parms.proto = p->proto;
t->parms.fwmark = p->fwmark;
@ -353,7 +353,7 @@ Signed-off-by: Steven Barth <cyrus@openwrt.org>
dst_cache_reset(&t->dst_cache);
ip6_tnl_link_config(t);
}
@@ -1577,6 +1746,7 @@ ip6_tnl_parm_from_user(struct __ip6_tnl_
@@ -1580,6 +1749,7 @@ ip6_tnl_parm_from_user(struct __ip6_tnl_
p->flowinfo = u->flowinfo;
p->link = u->link;
p->proto = u->proto;
@ -361,7 +361,7 @@ Signed-off-by: Steven Barth <cyrus@openwrt.org>
memcpy(p->name, u->name, sizeof(u->name));
}
@@ -1964,6 +2134,15 @@ static int ip6_tnl_validate(struct nlatt
@@ -1963,6 +2133,15 @@ static int ip6_tnl_validate(struct nlatt
return 0;
}
@ -377,7 +377,7 @@ Signed-off-by: Steven Barth <cyrus@openwrt.org>
static void ip6_tnl_netlink_parms(struct nlattr *data[],
struct __ip6_tnl_parm *parms)
{
@@ -2001,6 +2180,46 @@ static void ip6_tnl_netlink_parms(struct
@@ -2000,6 +2179,46 @@ static void ip6_tnl_netlink_parms(struct
if (data[IFLA_IPTUN_FWMARK])
parms->fwmark = nla_get_u32(data[IFLA_IPTUN_FWMARK]);
@ -424,7 +424,7 @@ Signed-off-by: Steven Barth <cyrus@openwrt.org>
}
static int ip6_tnl_newlink(struct net *src_net, struct net_device *dev,
@@ -2084,6 +2303,12 @@ static void ip6_tnl_dellink(struct net_d
@@ -2083,6 +2302,12 @@ static void ip6_tnl_dellink(struct net_d
static size_t ip6_tnl_get_size(const struct net_device *dev)
{
@ -437,7 +437,7 @@ Signed-off-by: Steven Barth <cyrus@openwrt.org>
return
/* IFLA_IPTUN_LINK */
nla_total_size(4) +
@@ -2113,6 +2338,24 @@ static size_t ip6_tnl_get_size(const str
@@ -2112,6 +2337,24 @@ static size_t ip6_tnl_get_size(const str
nla_total_size(0) +
/* IFLA_IPTUN_FWMARK */
nla_total_size(4) +
@ -462,7 +462,7 @@ Signed-off-by: Steven Barth <cyrus@openwrt.org>
0;
}
@@ -2120,6 +2363,9 @@ static int ip6_tnl_fill_info(struct sk_b
@@ -2119,6 +2362,9 @@ static int ip6_tnl_fill_info(struct sk_b
{
struct ip6_tnl *tunnel = netdev_priv(dev);
struct __ip6_tnl_parm *parm = &tunnel->parms;
@ -472,7 +472,7 @@ Signed-off-by: Steven Barth <cyrus@openwrt.org>
if (nla_put_u32(skb, IFLA_IPTUN_LINK, parm->link) ||
nla_put_in6_addr(skb, IFLA_IPTUN_LOCAL, &parm->laddr) ||
@@ -2129,9 +2375,27 @@ static int ip6_tnl_fill_info(struct sk_b
@@ -2128,9 +2374,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) ||
@ -501,7 +501,7 @@ Signed-off-by: Steven Barth <cyrus@openwrt.org>
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) ||
@@ -2171,6 +2435,7 @@ static const struct nla_policy ip6_tnl_p
@@ -2170,6 +2434,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 },

View file

@ -30,7 +30,7 @@ Signed-off-by: Jonas Gorski <jogo@openwrt.org>
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 {
@@ -83,6 +83,10 @@ enum {
FR_ACT_BLACKHOLE, /* Drop without notification */
FR_ACT_UNREACHABLE, /* Drop with ENETUNREACH */
FR_ACT_PROHIBIT, /* Drop with EACCES */
@ -66,7 +66,7 @@ Signed-off-by: Jonas Gorski <jogo@openwrt.org>
static void rt_fibinfo_free(struct rtable __rcu **rtp)
--- a/net/ipv4/fib_trie.c
+++ b/net/ipv4/fib_trie.c
@@ -2783,6 +2783,7 @@ static const char *const rtn_type_names[
@@ -2784,6 +2784,7 @@ static const char *const rtn_type_names[
[RTN_THROW] = "THROW",
[RTN_NAT] = "NAT",
[RTN_XRESOLVE] = "XRESOLVE",
@ -76,7 +76,7 @@ Signed-off-by: Jonas Gorski <jogo@openwrt.org>
static inline const char *rtn_type(char *buf, size_t len, unsigned int t)
--- a/net/ipv4/ipmr.c
+++ b/net/ipv4/ipmr.c
@@ -180,6 +180,7 @@ static int ipmr_rule_action(struct fib_r
@@ -191,6 +191,7 @@ static int ipmr_rule_action(struct fib_r
case FR_ACT_UNREACHABLE:
return -ENETUNREACH;
case FR_ACT_PROHIBIT:
@ -86,7 +86,7 @@ Signed-off-by: Jonas Gorski <jogo@openwrt.org>
default:
--- a/net/ipv6/fib6_rules.c
+++ b/net/ipv6/fib6_rules.c
@@ -221,6 +221,10 @@ static int __fib6_rule_action(struct fib
@@ -222,6 +222,10 @@ static int __fib6_rule_action(struct fib
err = -EACCES;
rt = net->ipv6.ip6_prohibit_entry;
goto discard_pkt;
@ -99,7 +99,7 @@ Signed-off-by: Jonas Gorski <jogo@openwrt.org>
tb_id = fib_rule_get_table(rule, arg);
--- a/net/ipv6/ip6mr.c
+++ b/net/ipv6/ip6mr.c
@@ -170,6 +170,8 @@ static int ip6mr_rule_action(struct fib_
@@ -180,6 +180,8 @@ static int ip6mr_rule_action(struct fib_
return -ENETUNREACH;
case FR_ACT_PROHIBIT:
return -EACCES;
@ -110,7 +110,7 @@ Signed-off-by: Jonas Gorski <jogo@openwrt.org>
return -EINVAL;
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -97,6 +97,8 @@ static int ip6_pkt_discard(struct sk_bu
@@ -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);
@ -119,7 +119,7 @@ Signed-off-by: Jonas Gorski <jogo@openwrt.org>
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,
@@ -317,6 +319,18 @@ static const struct rt6_info ip6_prohibi
@@ -316,6 +318,18 @@ static const struct rt6_info ip6_prohibi
.rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP),
};
@ -138,7 +138,7 @@ Signed-off-by: Jonas Gorski <jogo@openwrt.org>
static const struct rt6_info ip6_blk_hole_entry_template = {
.dst = {
.__rcuref = RCUREF_INIT(1),
@@ -1037,6 +1051,7 @@ static const int fib6_prop[RTN_MAX + 1]
@@ -1051,6 +1065,7 @@ static const int fib6_prop[RTN_MAX + 1]
[RTN_BLACKHOLE] = -EINVAL,
[RTN_UNREACHABLE] = -EHOSTUNREACH,
[RTN_PROHIBIT] = -EACCES,
@ -146,7 +146,7 @@ Signed-off-by: Jonas Gorski <jogo@openwrt.org>
[RTN_THROW] = -EAGAIN,
[RTN_NAT] = -EINVAL,
[RTN_XRESOLVE] = -EINVAL,
@@ -1072,6 +1087,10 @@ static void ip6_rt_init_dst_reject(struc
@@ -1086,6 +1101,10 @@ static void ip6_rt_init_dst_reject(struc
rt->dst.output = ip6_pkt_prohibit_out;
rt->dst.input = ip6_pkt_prohibit;
break;
@ -157,7 +157,7 @@ Signed-off-by: Jonas Gorski <jogo@openwrt.org>
case RTN_THROW:
case RTN_UNREACHABLE:
default:
@@ -4539,6 +4558,17 @@ static int ip6_pkt_prohibit_out(struct n
@@ -4555,6 +4574,17 @@ static int ip6_pkt_prohibit_out(struct n
return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_OUTNOROUTES);
}
@ -175,7 +175,7 @@ Signed-off-by: Jonas Gorski <jogo@openwrt.org>
/*
* Allocate a dst for local (unicast / anycast) address.
*/
@@ -5030,7 +5060,8 @@ static int rtm_to_fib6_config(struct sk_
@@ -5046,7 +5076,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 ||
@ -185,7 +185,7 @@ Signed-off-by: Jonas Gorski <jogo@openwrt.org>
cfg->fc_flags |= RTF_REJECT;
if (rtm->rtm_type == RTN_LOCAL)
@@ -6277,6 +6308,8 @@ static int ip6_route_dev_notify(struct n
@@ -6306,6 +6337,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);
@ -194,7 +194,7 @@ Signed-off-by: Jonas Gorski <jogo@openwrt.org>
net->ipv6.ip6_blk_hole_entry->dst.dev = dev;
net->ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(dev);
#endif
@@ -6288,6 +6321,7 @@ static int ip6_route_dev_notify(struct n
@@ -6317,6 +6350,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);
@ -202,7 +202,7 @@ Signed-off-by: Jonas Gorski <jogo@openwrt.org>
in6_dev_put_clear(&net->ipv6.ip6_blk_hole_entry->rt6i_idev);
#endif
}
@@ -6488,6 +6522,8 @@ static int __net_init ip6_route_net_init
@@ -6512,6 +6546,8 @@ static int __net_init ip6_route_net_init
#ifdef CONFIG_IPV6_MULTIPLE_TABLES
net->ipv6.fib6_has_custom_rules = false;
@ -211,7 +211,7 @@ Signed-off-by: Jonas Gorski <jogo@openwrt.org>
net->ipv6.ip6_prohibit_entry = kmemdup(&ip6_prohibit_entry_template,
sizeof(*net->ipv6.ip6_prohibit_entry),
GFP_KERNEL);
@@ -6498,11 +6534,21 @@ static int __net_init ip6_route_net_init
@@ -6522,11 +6558,21 @@ static int __net_init ip6_route_net_init
ip6_template_metrics, true);
INIT_LIST_HEAD(&net->ipv6.ip6_prohibit_entry->dst.rt_uncached);
@ -234,7 +234,7 @@ Signed-off-by: Jonas Gorski <jogo@openwrt.org>
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);
@@ -6529,6 +6575,8 @@ out:
@@ -6553,6 +6599,8 @@ out:
return ret;
#ifdef CONFIG_IPV6_MULTIPLE_TABLES
@ -243,7 +243,7 @@ Signed-off-by: Jonas Gorski <jogo@openwrt.org>
out_ip6_prohibit_entry:
kfree(net->ipv6.ip6_prohibit_entry);
out_ip6_null_entry:
@@ -6548,6 +6596,7 @@ static void __net_exit ip6_route_net_exi
@@ -6572,6 +6620,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);
@ -251,7 +251,7 @@ Signed-off-by: Jonas Gorski <jogo@openwrt.org>
kfree(net->ipv6.ip6_blk_hole_entry);
#endif
dst_entries_destroy(&net->ipv6.ip6_dst_ops);
@@ -6631,6 +6680,9 @@ void __init ip6_route_init_special_entri
@@ -6655,6 +6704,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);

View file

@ -17,7 +17,7 @@ Signed-off-by: Jonas Gorski <jogo@openwrt.org>
--- a/include/uapi/linux/fib_rules.h
+++ b/include/uapi/linux/fib_rules.h
@@ -89,6 +89,8 @@ enum {
@@ -90,6 +90,8 @@ enum {
__FR_ACT_MAX,
};
@ -28,7 +28,7 @@ Signed-off-by: Jonas Gorski <jogo@openwrt.org>
#endif
--- a/include/uapi/linux/icmpv6.h
+++ b/include/uapi/linux/icmpv6.h
@@ -126,6 +126,8 @@ struct icmp6hdr {
@@ -127,6 +127,8 @@ struct icmp6hdr {
#define ICMPV6_POLICY_FAIL 5
#define ICMPV6_REJECT_ROUTE 6

View file

@ -0,0 +1,129 @@
From: Felix Fietkau <nbd@nbd.name>
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.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
--- a/drivers/net/dummy.c
+++ b/drivers/net/dummy.c
@@ -111,7 +111,7 @@ static void dummy_setup(struct net_devic
dev->priv_flags |= IFF_LIVE_ADDR_CHANGE | IFF_NO_QUEUE;
dev->lltx = true;
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;
dev->features |= NETIF_F_GSO_ENCAP_ALL;
dev->hw_features |= dev->features;
--- a/drivers/net/loopback.c
+++ b/drivers/net/loopback.c
@@ -174,7 +174,7 @@ static void gen_lo_setup(struct net_devi
dev->lltx = true;
dev->netns_local = true;
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
@@ -897,7 +897,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
--- a/include/linux/netdev_features.h
+++ b/include/linux/netdev_features.h
@@ -211,13 +211,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
@@ -108,7 +108,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
@@ -561,7 +561,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_FCOE_CRC | NETIF_F_FSO;
@@ -657,7 +657,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);
return features;
}
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -2525,7 +2525,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
@@ -2012,7 +2012,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
@@ -109,7 +109,7 @@ static void do_setup(struct net_device *
netdev->rtnl_link_ops = &internal_dev_link_ops;
netdev->features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_HIGHDMA |
- NETIF_F_HW_CSUM | NETIF_F_GSO_SOFTWARE |
+ NETIF_F_HW_CSUM | NETIF_F_GSO_SOFTWARE_ALL |
NETIF_F_GSO_ENCAP_ALL;
netdev->vlan_features = netdev->features;

View file

@ -0,0 +1,110 @@
From: Pablo Neira Ayuso <pablo@netfilter.org>
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.
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
--- 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;
@@ -674,9 +691,14 @@ static int __init nf_flow_table_module_i
if (ret)
goto out_bpf;
+ ret = register_netdevice_notifier(&flow_offload_netdev_notifier);
+ if (ret)
+ goto out_offload_init;
+
return 0;
out_bpf:
+out_offload_init:
nf_flow_table_offload_exit();
out_offload:
unregister_pernet_subsys(&nf_flow_table_net_ops);
@@ -685,6 +707,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
@@ -481,47 +481,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);

View file

@ -18,7 +18,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -8268,7 +8268,7 @@ static int nft_register_flowtable_net_ho
@@ -8607,7 +8607,7 @@ static int nft_register_flowtable_net_ho
err = flowtable->data.type->setup(&flowtable->data,
hook->ops.dev,
FLOW_BLOCK_BIND);

View file

@ -0,0 +1,21 @@
From: Felix Fietkau <nbd@nbd.name>
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.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
@@ -5041,6 +5041,8 @@ static int mtk_probe(struct platform_dev
dev_err(eth->dev, "failed to allocated dummy device\n");
goto err_unreg_netdev;
}
+ eth->dummy_dev->threaded = 1;
+ strcpy(eth->dummy_dev->name, "mtk_eth");
netif_napi_add(eth->dummy_dev, &eth->tx_napi, mtk_napi_tx);
netif_napi_add(eth->dummy_dev, &eth->rx_napi, mtk_napi_rx);

View file

@ -11,7 +11,7 @@ Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -1908,6 +1908,9 @@ void phy_detach(struct phy_device *phyde
@@ -1986,6 +1986,9 @@ void phy_detach(struct phy_device *phyde
if (phydev->devlink)
device_link_del(phydev->devlink);
@ -23,7 +23,7 @@ Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
sysfs_remove_link(&dev->dev.kobj, "phydev");
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -976,6 +976,12 @@ struct phy_driver {
@@ -999,6 +999,12 @@ struct phy_driver {
/** @handle_interrupt: Override default interrupt handling */
irqreturn_t (*handle_interrupt)(struct phy_device *phydev);

View file

@ -0,0 +1,57 @@
From 4e432e530db0056450fbc4a3cee793f16adc39a7 Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org>
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.
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
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
@@ -2086,7 +2086,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 ||
@@ -2116,6 +2116,25 @@ int phylink_fwnode_phy_connect(struct ph
if (pl->config->mac_requires_rxc)
flags |= PHY_F_RXC_ALWAYS_ON;
+ /* 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);

View file

@ -106,7 +106,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
--- a/include/uapi/linux/if_link.h
+++ b/include/uapi/linux/if_link.h
@@ -571,6 +571,7 @@ enum {
@@ -1094,6 +1094,7 @@ enum {
IFLA_BRPORT_MCAST_MAX_GROUPS,
IFLA_BRPORT_NEIGH_VLAN_SUPPRESS,
IFLA_BRPORT_BACKUP_NHID,
@ -152,7 +152,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
(!(p->flags & BR_PORT_LOCKED) || !(p->flags & BR_LEARNING))) {
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -61,7 +61,7 @@
@@ -62,7 +62,7 @@
#include "dev.h"
#define RTNL_MAX_TYPE 50
@ -161,7 +161,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
struct rtnl_link {
rtnl_doit_func doit;
@@ -4949,7 +4949,9 @@ int ndo_dflt_bridge_getlink(struct sk_bu
@@ -5009,7 +5009,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,

View file

@ -16,7 +16,7 @@ Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
--- 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
@@ -2031,6 +2031,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,
@ -27,7 +27,7 @@ Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
.port_mirror_add = qca8k_port_mirror_add,
--- a/drivers/net/dsa/qca/qca8k-common.c
+++ b/drivers/net/dsa/qca/qca8k-common.c
@@ -1215,6 +1215,42 @@ int qca8k_port_lag_leave(struct dsa_swit
@@ -1234,6 +1234,42 @@ int qca8k_port_lag_leave(struct dsa_swit
return qca8k_lag_refresh_portmap(ds, port, lag, true);
}
@ -72,7 +72,7 @@ Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
u32 val;
--- a/drivers/net/dsa/qca/qca8k.h
+++ b/drivers/net/dsa/qca/qca8k.h
@@ -590,5 +590,11 @@ int qca8k_port_lag_join(struct dsa_switc
@@ -592,5 +592,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);

View file

@ -14,7 +14,7 @@ Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
--- 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)
@@ -1913,15 +1913,12 @@ qca8k_setup(struct dsa_switch *ds)
}
}

View file

@ -0,0 +1,158 @@
From b2d6ebf2f92f8695c83fa6979f4ab579c588df76 Mon Sep 17 00:00:00 2001
From: Christian Marangi <ansuelsmth@gmail.com>
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.
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
---
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
@@ -1750,6 +1750,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_conduit(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_conduit_change(struct dsa_switch *ds, const struct net_device *conduit,
bool operational)
@@ -2039,8 +2150,9 @@ static const struct dsa_switch_ops qca8k
.port_vlan_del = qca8k_port_vlan_del,
.phylink_get_caps = qca8k_phylink_get_caps,
.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_conduit = qca8k_port_change_master,
.conduit_state_change = qca8k_conduit_change,
.connect_tag_protocol = qca8k_connect_tag_protocol,
};

View file

@ -20,7 +20,7 @@ Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
--- 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)
@@ -2022,6 +2022,12 @@ qca8k_setup(struct dsa_switch *ds)
dev_err(priv->dev, "failed enabling QCA header mode on port %d", dp->index);
return ret;
}
@ -33,7 +33,7 @@ Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
}
/* Forward all unknown frames to CPU port for Linux processing */
@@ -2039,11 +2045,6 @@ qca8k_setup(struct dsa_switch *ds)
@@ -2051,11 +2057,6 @@ qca8k_setup(struct dsa_switch *ds)
if (ret)
return ret;
@ -45,7 +45,7 @@ Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
/* For port based vlans to work we need to set the
* default egress vid
*/
@@ -2095,6 +2096,9 @@ qca8k_setup(struct dsa_switch *ds)
@@ -2107,6 +2108,9 @@ qca8k_setup(struct dsa_switch *ds)
/* Set max number of LAGs supported */
ds->num_lag_ids = QCA8K_NUM_LAGS;

View file

@ -1,25 +0,0 @@
From 3b5a603bf66236b956287909556fd7ad4904450c Mon Sep 17 00:00:00 2001
From: Christian Marangi <ansuelsmth@gmail.com>
Date: Wed, 24 Jan 2024 19:38:01 +0100
Subject: [PATCH 3/3] 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.
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
---
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";
};

View file

@ -0,0 +1,81 @@
From 85cd45580f5e3b26068cccb7d6173f200e754dc0 Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org>
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.
Reported-by: Yevhen Kolomeiko <jarvis2709@gmail.com>
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
drivers/net/phy/realtek.c | 6 ++++++
1 file changed, 6 insertions(+)
--- a/drivers/net/phy/realtek.c
+++ b/drivers/net/phy/realtek.c
@@ -1375,6 +1375,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,
@@ -1387,6 +1388,7 @@ static struct phy_driver realtek_drvs[]
}, {
PHY_ID_MATCH_EXACT(0x001cc840),
.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,
@@ -1401,6 +1403,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,
@@ -1411,6 +1414,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,
@@ -1423,6 +1427,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,
.get_features = rtl822x_get_features,
.config_aneg = rtl822x_config_aneg,
.config_init = rtl822xb_config_init,
@@ -1435,6 +1440,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)",
+ .soft_reset = genphy_soft_reset,
.config_init = rtl822xb_config_init,
.get_rate_matching = rtl822xb_get_rate_matching,
.get_features = rtl822x_c45_get_features,
@@ -1445,6 +1451,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)",
+ .soft_reset = genphy_soft_reset,
.get_features = rtl822x_get_features,
.config_aneg = rtl822x_config_aneg,
.config_init = rtl822xb_config_init,
@@ -1457,6 +1464,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)",
+ .soft_reset = genphy_soft_reset,
.config_init = rtl822xb_config_init,
.get_rate_matching = rtl822xb_get_rate_matching,
.get_features = rtl822x_c45_get_features,

View file

@ -0,0 +1,63 @@
From d54ef6aea00e7a6ace439baade6ad0aa38ee4b04 Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org>
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.
Reported-by: Chen Minqiang <ptpt52@gmail.com>
Reported-by: Chukun Pan <amadeus@jmu.edu.cn>
Reported-by: Yevhen Kolomeiko <jarvis2709@gmail.com>
Tested-by: Yevhen Kolomeiko <jarvis2709@gmail.com>
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
drivers/net/phy/realtek.c | 27 +++++++++++++++++++++++++--
1 file changed, 25 insertions(+), 2 deletions(-)
--- a/drivers/net/phy/realtek.c
+++ b/drivers/net/phy/realtek.c
@@ -814,8 +814,8 @@ static int rtl822x_write_mmd(struct phy_
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) ||
@@ -865,7 +865,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,

View file

@ -18,7 +18,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
--- a/drivers/net/phy/realtek.c
+++ b/drivers/net/phy/realtek.c
@@ -765,9 +765,11 @@ static bool rtlgen_supports_2_5gbps(stru
@@ -1092,9 +1092,11 @@ static bool rtlgen_supports_2_5gbps(stru
{
int val;
@ -31,5 +31,5 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+ rtl821x_write_page(phydev, 0);
+ mutex_unlock(&phydev->mdio.bus->mdio_lock);
return val >= 0 && val & RTL_SUPPORTS_2500FULL;
return val >= 0 && val & MDIO_PMA_SPEED_2_5G;
}

View file

@ -0,0 +1,100 @@
From 9155098547fb1172d4fa536f3f6bc9d42f59d08c Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org>
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.
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
drivers/net/phy/realtek.c | 11 +++++++++++
1 file changed, 11 insertions(+)
--- a/drivers/net/phy/realtek.c
+++ b/drivers/net/phy/realtek.c
@@ -80,6 +80,10 @@
#define RTL822X_VND2_GANLPAR 0xa414
+#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)
@@ -1152,6 +1156,25 @@ static int rtl8251b_c45_match_phy_device
return rtlgen_is_c45_match(phydev, RTL_8251B, true);
}
+static int rtl822x_probe(struct phy_device *phydev)
+{
+ struct device *dev = &phydev->mdio.dev;
+ int val;
+
+ val = phy_read_mmd(phydev, MDIO_MMD_VEND1, RTL8221B_PHYCR1);
+ if (val < 0)
+ return val;
+
+ if (of_property_read_bool(dev->of_node, "realtek,aldps-enable"))
+ val |= RTL8221B_PHYCR1_ALDPS_EN | RTL8221B_PHYCR1_ALDPS_XTAL_OFF_EN;
+ else
+ val &= ~(RTL8221B_PHYCR1_ALDPS_EN | RTL8221B_PHYCR1_ALDPS_XTAL_OFF_EN);
+
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, RTL8221B_PHYCR1, val);
+
+ return 0;
+}
+
static int rtlgen_resume(struct phy_device *phydev)
{
int ret = genphy_resume(phydev);
@@ -1427,6 +1450,7 @@ static struct phy_driver realtek_drvs[]
}, {
PHY_ID_MATCH_EXACT(0x001cc838),
.name = "RTL8226-CG 2.5Gbps PHY",
+ .probe = rtl822x_probe,
.soft_reset = genphy_soft_reset,
.get_features = rtl822x_get_features,
.config_aneg = rtl822x_config_aneg,
@@ -1438,6 +1462,7 @@ static struct phy_driver realtek_drvs[]
}, {
PHY_ID_MATCH_EXACT(0x001cc848),
.name = "RTL8226B-CG_RTL8221B-CG 2.5Gbps PHY",
+ .probe = rtl822x_probe,
.soft_reset = genphy_soft_reset,
.get_features = rtl822x_get_features,
.config_aneg = rtl822x_config_aneg,
@@ -1451,6 +1476,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,
.soft_reset = genphy_soft_reset,
.get_features = rtl822x_get_features,
.config_aneg = rtl822x_config_aneg,
@@ -1464,6 +1490,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,
.soft_reset = genphy_soft_reset,
.config_init = rtl822xb_config_init,
.get_rate_matching = rtl822xb_get_rate_matching,
@@ -1475,6 +1502,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,
.soft_reset = genphy_soft_reset,
.get_features = rtl822x_get_features,
.config_aneg = rtl822x_config_aneg,
@@ -1488,6 +1516,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,
.soft_reset = genphy_soft_reset,
.config_init = rtl822xb_config_init,
.get_rate_matching = rtl822xb_get_rate_matching,

View file

@ -0,0 +1,52 @@
From 0de82310d2b32e78ff79d42c08b1122a6ede3778 Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org>
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.
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
[forward-port by @namiltd]
Signed-off-by: Mieczyslaw Nalewaj <namiltd@yahoo.com>
--- a/drivers/net/phy/realtek.c
+++ b/drivers/net/phy/realtek.c
@@ -1120,10 +1120,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_vb_cg_c22_match_phy_device(struct phy_device *phydev)

View file

@ -0,0 +1,102 @@
From d7943c31d57c11e1a517aa3ce2006fca44866870 Mon Sep 17 00:00:00 2001
From: Jianhui Zhao <zhaojh329@gmail.com>
Date: Sun, 24 Sep 2023 22:15:00 +0800
Subject: [PATCH] net: phy: realtek: add interrupt support for RTL8221B
This commit introduces interrupt support for RTL8221B.
Signed-off-by: Jianhui Zhao <zhaojh329@gmail.com>
---
drivers/net/phy/realtek.c | 47 +++++++++++++++++++++++++++++++++++++++
1 file changed, 47 insertions(+)
--- a/drivers/net/phy/realtek.c
+++ b/drivers/net/phy/realtek.c
@@ -1332,6 +1332,51 @@ 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, 0xa4d4);
+
+ 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, 0xa4d2, 0x7ff);
+ } else {
+ err = phy_write_mmd(phydev, MDIO_MMD_VEND2, 0xa4d2, 0x0);
+ 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),
@@ -1498,6 +1543,8 @@ static struct phy_driver realtek_drvs[]
}, {
.match_phy_device = rtl8221b_vb_cg_c22_match_phy_device,
.name = "RTL8221B-VB-CG 2.5Gbps PHY (C22)",
+ .config_intr = rtl8221b_config_intr,
+ .handle_interrupt = rtl8221b_handle_interrupt,
.probe = rtl822x_probe,
.soft_reset = genphy_soft_reset,
.get_features = rtl822x_get_features,
@@ -1512,6 +1559,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,
.soft_reset = genphy_soft_reset,
.config_init = rtl822xb_config_init,
@@ -1524,6 +1573,8 @@ static struct phy_driver realtek_drvs[]
}, {
.match_phy_device = rtl8221b_vn_cg_c22_match_phy_device,
.name = "RTL8221B-VM-CG 2.5Gbps PHY (C22)",
+ .config_intr = rtl8221b_config_intr,
+ .handle_interrupt = rtl8221b_handle_interrupt,
.probe = rtl822x_probe,
.soft_reset = genphy_soft_reset,
.get_features = rtl822x_get_features,
@@ -1538,6 +1589,8 @@ static struct phy_driver realtek_drvs[]
}, {
.match_phy_device = rtl8221b_vn_cg_c45_match_phy_device,
.name = "RTL8221B-VN-CG 2.5Gbps PHY (C45)",
+ .config_intr = rtl8221b_config_intr,
+ .handle_interrupt = rtl8221b_handle_interrupt,
.probe = rtl822x_probe,
.soft_reset = genphy_soft_reset,
.config_init = rtl822xb_config_init,

View file

@ -1,106 +0,0 @@
From ace6abaa0f9203083fe4c0a6a74da2d96410b625 Mon Sep 17 00:00:00 2001
From: Alexander Couzens <lynxis@fe80.eu>
Date: Sat, 13 Aug 2022 12:49:33 +0200
Subject: [PATCH 01/10] net: phy: realtek: rtl8221: allow to configure SERDES
mode
The rtl8221 supports multiple SERDES modes:
- SGMII
- 2500base-x
- HiSGMII
Further it supports rate adaption on SERDES links to allow
slow ethernet speeds (10/100/1000mbit) to work on 2500base-x/HiSGMII
links without reducing the SERDES speed.
When operating without rate adapters the SERDES link will follow the
ethernet speed.
Signed-off-by: Alexander Couzens <lynxis@fe80.eu>
---
drivers/net/phy/realtek.c | 48 +++++++++++++++++++++++++++++++++++++++
1 file changed, 48 insertions(+)
--- a/drivers/net/phy/realtek.c
+++ b/drivers/net/phy/realtek.c
@@ -54,6 +54,15 @@
RTL8201F_ISR_LINK)
#define RTL8201F_IER 0x13
+#define RTL8221B_MMD_SERDES_CTRL MDIO_MMD_VEND1
+#define RTL8221B_MMD_PHY_CTRL MDIO_MMD_VEND2
+#define RTL8221B_SERDES_OPTION 0x697a
+#define RTL8221B_SERDES_OPTION_MODE_MASK GENMASK(5, 0)
+#define RTL8221B_SERDES_OPTION_MODE_2500BASEX_SGMII 0
+#define RTL8221B_SERDES_OPTION_MODE_HISGMII_SGMII 1
+#define RTL8221B_SERDES_OPTION_MODE_2500BASEX 2
+#define RTL8221B_SERDES_OPTION_MODE_HISGMII 3
+
#define RTL8366RB_POWER_SAVE 0x15
#define RTL8366RB_POWER_SAVE_ON BIT(12)
@@ -879,6 +888,48 @@ static irqreturn_t rtl9000a_handle_inter
return IRQ_HANDLED;
}
+static int rtl8221b_config_init(struct phy_device *phydev)
+{
+ u16 option_mode;
+
+ switch (phydev->interface) {
+ case PHY_INTERFACE_MODE_2500BASEX:
+ if (!phydev->is_c45) {
+ option_mode = RTL8221B_SERDES_OPTION_MODE_2500BASEX;
+ break;
+ }
+ fallthrough;
+ case PHY_INTERFACE_MODE_SGMII:
+ option_mode = RTL8221B_SERDES_OPTION_MODE_2500BASEX_SGMII;
+ break;
+ default:
+ return 0;
+ }
+
+ phy_write_mmd(phydev, RTL8221B_MMD_SERDES_CTRL,
+ 0x75f3, 0);
+
+ phy_modify_mmd_changed(phydev, RTL8221B_MMD_SERDES_CTRL,
+ RTL8221B_SERDES_OPTION,
+ RTL8221B_SERDES_OPTION_MODE_MASK, option_mode);
+ switch (option_mode) {
+ case RTL8221B_SERDES_OPTION_MODE_2500BASEX_SGMII:
+ case RTL8221B_SERDES_OPTION_MODE_2500BASEX:
+ phy_write_mmd(phydev, RTL8221B_MMD_SERDES_CTRL, 0x6a04, 0x0503);
+ phy_write_mmd(phydev, RTL8221B_MMD_SERDES_CTRL, 0x6f10, 0xd455);
+ phy_write_mmd(phydev, RTL8221B_MMD_SERDES_CTRL, 0x6f11, 0x8020);
+ break;
+ case RTL8221B_SERDES_OPTION_MODE_HISGMII_SGMII:
+ case RTL8221B_SERDES_OPTION_MODE_HISGMII:
+ phy_write_mmd(phydev, RTL8221B_MMD_SERDES_CTRL, 0x6a04, 0x0503);
+ phy_write_mmd(phydev, RTL8221B_MMD_SERDES_CTRL, 0x6f10, 0xd433);
+ phy_write_mmd(phydev, RTL8221B_MMD_SERDES_CTRL, 0x6f11, 0x8020);
+ break;
+ }
+
+ return 0;
+}
+
static struct phy_driver realtek_drvs[] = {
{
PHY_ID_MATCH_EXACT(0x00008201),
@@ -1033,6 +1084,7 @@ static struct phy_driver realtek_drvs[]
PHY_ID_MATCH_EXACT(0x001cc849),
.name = "RTL8221B-VB-CG 2.5Gbps PHY",
.get_features = rtl822x_get_features,
+ .config_init = rtl8221b_config_init,
.config_aneg = rtl822x_config_aneg,
.read_status = rtl822x_read_status,
.suspend = genphy_suspend,
@@ -1044,6 +1096,7 @@ static struct phy_driver realtek_drvs[]
.name = "RTL8221B-VM-CG 2.5Gbps PHY",
.get_features = rtl822x_get_features,
.config_aneg = rtl822x_config_aneg,
+ .config_init = rtl8221b_config_init,
.read_status = rtl822x_read_status,
.suspend = genphy_suspend,
.resume = rtlgen_resume,

View file

@ -1,65 +0,0 @@
From 85cd45580f5e3b26068cccb7d6173f200e754dc0 Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org>
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.
Reported-by: Yevhen Kolomeiko <jarvis2709@gmail.com>
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
drivers/net/phy/realtek.c | 6 ++++++
1 file changed, 6 insertions(+)
--- a/drivers/net/phy/realtek.c
+++ b/drivers/net/phy/realtek.c
@@ -1070,6 +1070,7 @@ static struct phy_driver realtek_drvs[]
.write_page = rtl821x_write_page,
.read_mmd = rtl822x_read_mmd,
.write_mmd = rtl822x_write_mmd,
+ .soft_reset = genphy_soft_reset,
}, {
PHY_ID_MATCH_EXACT(0x001cc840),
.name = "RTL8226B_RTL8221B 2.5Gbps PHY",
@@ -1082,6 +1083,7 @@ static struct phy_driver realtek_drvs[]
.write_page = rtl821x_write_page,
.read_mmd = rtl822x_read_mmd,
.write_mmd = rtl822x_write_mmd,
+ .soft_reset = genphy_soft_reset,
}, {
PHY_ID_MATCH_EXACT(0x001cc838),
.name = "RTL8226-CG 2.5Gbps PHY",
@@ -1092,6 +1094,7 @@ static struct phy_driver realtek_drvs[]
.resume = rtlgen_resume,
.read_page = rtl821x_read_page,
.write_page = rtl821x_write_page,
+ .soft_reset = genphy_soft_reset,
}, {
PHY_ID_MATCH_EXACT(0x001cc848),
.name = "RTL8226B-CG_RTL8221B-CG 2.5Gbps PHY",
@@ -1102,6 +1105,7 @@ static struct phy_driver realtek_drvs[]
.resume = rtlgen_resume,
.read_page = rtl821x_read_page,
.write_page = rtl821x_write_page,
+ .soft_reset = genphy_soft_reset,
}, {
PHY_ID_MATCH_EXACT(0x001cc849),
.name = "RTL8221B-VB-CG 2.5Gbps PHY",
@@ -1113,6 +1117,7 @@ static struct phy_driver realtek_drvs[]
.resume = rtlgen_resume,
.read_page = rtl821x_read_page,
.write_page = rtl821x_write_page,
+ .soft_reset = genphy_soft_reset,
}, {
PHY_ID_MATCH_EXACT(0x001cc84a),
.name = "RTL8221B-VM-CG 2.5Gbps PHY",
@@ -1124,6 +1129,7 @@ static struct phy_driver realtek_drvs[]
.resume = rtlgen_resume,
.read_page = rtl821x_read_page,
.write_page = rtl821x_write_page,
+ .soft_reset = genphy_soft_reset,
}, {
PHY_ID_MATCH_EXACT(0x001cc961),
.name = "RTL8366RB Gigabit Ethernet",

View file

@ -1,43 +0,0 @@
From 2b1b8c4c215af7988136401c902338d091d408a1 Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org>
Date: Mon, 3 Apr 2023 01:21:57 +0300
Subject: [PATCH 2/2] 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.
Reported-by: Chen Minqiang <ptpt52@gmail.com>
Reported-by: Chukun Pan <amadeus@jmu.edu.cn>
Reported-by: Yevhen Kolomeiko <jarvis2709@gmail.com>
Tested-by: Yevhen Kolomeiko <jarvis2709@gmail.com>
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
drivers/net/phy/realtek.c | 8 ++++++++
1 file changed, 8 insertions(+)
--- a/drivers/net/phy/realtek.c
+++ b/drivers/net/phy/realtek.c
@@ -913,6 +913,7 @@ static irqreturn_t rtl9000a_handle_inter
static int rtl8221b_config_init(struct phy_device *phydev)
{
u16 option_mode;
+ int val;
switch (phydev->interface) {
case PHY_INTERFACE_MODE_2500BASEX:
@@ -949,6 +950,13 @@ static int rtl8221b_config_init(struct p
break;
}
+ /* Disable SGMII AN */
+ phy_write_mmd(phydev, RTL8221B_MMD_SERDES_CTRL, 0x7588, 0x2);
+ phy_write_mmd(phydev, RTL8221B_MMD_SERDES_CTRL, 0x7589, 0x71d0);
+ phy_write_mmd(phydev, RTL8221B_MMD_SERDES_CTRL, 0x7587, 0x3);
+ phy_read_mmd_poll_timeout(phydev, RTL8221B_MMD_SERDES_CTRL, 0x7587,
+ val, !(val & BIT(0)), 500, 100000, false);
+
return 0;
}

View file

@ -0,0 +1,49 @@
From 7d41a5a8e9c91cc6bb011dd953570738583dd091 Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org>
Date: Wed, 18 Sep 2024 02:01:01 +0100
Subject: [PATCH] net: ethernet: mtk_eth_soc: reset all TX queues on DMA free
The purpose of resetting the TX queue is to reset the
byte and packet count as well as to clear the software
flow control XOFF bit.
MediaTek developers pointed out that netdev_reset_queue would only
resets queue 0 of the network device.
Queues that are not reset may cause unexpected issues.
Packets may stop being sent after reset and "transmit timeout" log may
be displayed.
Import fix from MediaTek's SDK to resolve this issue.
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
drivers/net/ethernet/mediatek/mtk_eth_soc.c | 18 ++++++++++++++----
1 file changed, 14 insertions(+), 4 deletions(-)
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
@@ -3135,11 +3135,19 @@ static int mtk_dma_init(struct mtk_eth *
static void mtk_dma_free(struct mtk_eth *eth)
{
const struct mtk_soc_data *soc = eth->soc;
- int i;
+ int i, j, txqs = 1;
+
+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA))
+ txqs = MTK_QDMA_NUM_QUEUES;
+
+ for (i = 0; i < MTK_MAX_DEVS; i++) {
+ if (!eth->netdev[i])
+ continue;
+
+ for (j = 0; j < txqs; j++)
+ netdev_tx_reset_queue(netdev_get_tx_queue(eth->netdev[i], j));
+ }
- for (i = 0; i < MTK_MAX_DEVS; i++)
- if (eth->netdev[i])
- netdev_reset_queue(eth->netdev[i]);
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,

View file

@ -17,7 +17,7 @@ Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -2243,7 +2243,7 @@ struct net_device {
@@ -2224,7 +2224,7 @@ struct net_device {
#if IS_ENABLED(CONFIG_AX25)
void *ax25_ptr;
#endif

View file

@ -11,7 +11,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
@@ -1334,6 +1334,22 @@ struct mtk_mac {
@@ -1322,6 +1322,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[];
@ -34,7 +34,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
static inline bool mtk_is_netsys_v1(struct mtk_eth *eth)
{
return eth->soc->version == 1;
@@ -1348,6 +1364,7 @@ static inline bool mtk_is_netsys_v3_or_g
@@ -1336,6 +1352,7 @@ static inline bool mtk_is_netsys_v3_or_g
{
return eth->soc->version > 2;
}

View file

@ -24,7 +24,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
#include <net/page_pool/helpers.h>
#include "mtk_eth_soc.h"
@@ -1587,12 +1588,28 @@ static void mtk_wake_queue(struct mtk_et
@@ -1596,12 +1597,28 @@ static void mtk_wake_queue(struct mtk_et
}
}
@ -53,7 +53,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
bool gso = false;
int tx_num;
@@ -1614,6 +1631,18 @@ static netdev_tx_t mtk_start_xmit(struct
@@ -1623,6 +1640,18 @@ static netdev_tx_t mtk_start_xmit(struct
return NETDEV_TX_BUSY;
}
@ -72,7 +72,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
/* TSO: fill MSS info in tcp checksum field */
if (skb_is_gso(skb)) {
if (skb_cow_head(skb, 0)) {
@@ -1629,8 +1658,14 @@ static netdev_tx_t mtk_start_xmit(struct
@@ -1638,8 +1667,14 @@ static netdev_tx_t mtk_start_xmit(struct
}
}

View file

@ -10,7 +10,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
@@ -2129,7 +2129,7 @@ static int mtk_poll_rx(struct napi_struc
@@ -2140,7 +2140,7 @@ static int mtk_poll_rx(struct napi_struc
if (ret != XDP_PASS)
goto skip_rx;
@ -19,7 +19,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
if (unlikely(!skb)) {
page_pool_put_full_page(ring->page_pool,
page, true);
@@ -2167,7 +2167,7 @@ static int mtk_poll_rx(struct napi_struc
@@ -2178,7 +2178,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);

View file

@ -0,0 +1,44 @@
From: Chad Monroe <chad@monroe.io>
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
Signed-off-by: Chad Monroe <chad@monroe.io>
---
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
@@ -271,6 +271,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
@@ -3309,12 +3309,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 | MTK_LEAKY_BUCKET_EN;
- else
+ } else {
val |= MTK_RX_BT_32DWORDS;
+ }
mtk_w32(eth, val, reg_map->qdma.glo_cfg);
mtk_w32(eth,

View file

@ -0,0 +1,903 @@
From d5e337e7aecc2e1cc9e96768062610adb95f8f72 Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org>
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.
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
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>
@@ -270,12 +272,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",
@@ -518,6 +516,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)
{
@@ -526,6 +548,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)) ?
@@ -577,7 +614,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;
@@ -624,8 +676,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 */
@@ -642,21 +692,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, &eth->state))
+ schedule_work(&eth->pending_work);
+ }
}
+ mac->interface = state->interface;
+
return;
err_phy:
@@ -669,6 +738,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)
{
@@ -677,6 +758,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))
@@ -701,10 +786,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,
@@ -776,13 +865,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));
@@ -816,9 +903,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,
@@ -3417,6 +3558,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__,
@@ -3567,6 +3711,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;
}
@@ -4580,6 +4727,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;
@@ -4616,16 +4764,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));
@@ -4708,8 +4881,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);
@@ -4760,6 +4946,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;
@@ -4906,7 +5112,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)
@@ -5017,6 +5224,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,
@@ -5127,6 +5352,11 @@ static void mtk_remove(struct platform_d
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>
@@ -505,6 +506,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
@@ -530,6 +546,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 */
@@ -568,6 +585,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
@@ -592,6 +614,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
@@ -600,6 +624,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))
@@ -932,6 +961,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,
@@ -952,8 +983,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,
@@ -961,14 +995,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)
@@ -991,10 +1032,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)
@@ -1002,8 +1049,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)
@@ -1011,7 +1063,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 */
@@ -1030,10 +1087,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 | \
@@ -1065,8 +1132,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;
@@ -1311,6 +1382,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];
@@ -1434,6 +1508,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);
@@ -1442,8 +1529,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,

View file

@ -0,0 +1,369 @@
From 4b1a2716299c0e96a698044aebf3f80513509ae7 Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org>
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.
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
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
*
* Author: Sean Wang <sean.wang@mediatek.com>
* Author: Alexander Couzens <lynxis@fe80.eu>
@@ -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);
@@ -102,6 +124,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,
@@ -147,6 +180,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);
@@ -233,10 +267,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;
}
@@ -246,11 +299,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;
@@ -258,29 +312,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;
@@ -291,6 +349,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);
@@ -303,5 +368,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 = mtk_pcs_lynxi_remove,
+};
+module_platform_driver(mtk_pcs_lynxi_driver);
+
+MODULE_AUTHOR("Daniel Golle <daniel@makrotopia.org>");
MODULE_DESCRIPTION("MediaTek SGMII library for LynxI");
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

View file

@ -19,7 +19,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -13356,7 +13356,9 @@ M: Daniel Golle <daniel@makrotopia.org>
@@ -14419,7 +14419,9 @@ M: Daniel Golle <daniel@makrotopia.org>
L: netdev@vger.kernel.org
S: Maintained
F: drivers/net/pcs/pcs-mtk-lynxi.c
@ -51,14 +51,14 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
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
@@ -8,3 +8,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,456 @@
@@ -0,0 +1,454 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2023 MediaTek Inc.
@ -429,7 +429,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+ return 0;
+}
+
+static int mtk_usxgmii_remove(struct platform_device *pdev)
+static void mtk_usxgmii_remove(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct mtk_usxgmii_pcs *cur, *tmp;
@ -441,8 +441,6 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+ break;
+ }
+ mutex_unlock(&instance_mutex);
+
+ return 0;
+}
+
+static const struct of_device_id mtk_usxgmii_of_mtable[] = {

View file

@ -0,0 +1,35 @@
From 1be3688b3eaa7ea2d9e19bd29ae6a6a51c121a0b Mon Sep 17 00:00:00 2001
From: David Bauer <mail@david-bauer.net>
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.
Signed-off-by: David Bauer <mail@david-bauer.net>
---
drivers/net/phy/Kconfig | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -139,7 +139,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.

View file

@ -32,9 +32,9 @@ https://patchwork.kernel.org/project/netdevbpf/patch/20240425023325.15586-3-SkyL
--- 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);
@@ -548,6 +548,10 @@ static int air_hw_led_on_set(struct phy_
if (!on)
priv->led[index].rules = 0;
+ /* clear netdev trigger rules in case LED_OFF has been set */
+ if (!on)

View file

@ -1,27 +0,0 @@
From: Tobias Waldekranz <tobias@waldekranz.com>
Subject: [RFC net-next 7/7] net: dsa: mv88e6xxx: Request assisted learning on CPU port
Date: Sat, 16 Jan 2021 02:25:15 +0100
Archived-At: <https://lore.kernel.org/netdev/20210116012515.3152-8-tobias@waldekranz.com/>
While the hardware is capable of performing learning on the CPU port,
it requires alot of additions to the bridge's forwarding path in order
to handle multi-destination traffic correctly.
Until that is in place, opt for the next best thing and let DSA sync
the relevant addresses down to the hardware FDB.
Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
---
drivers/net/dsa/mv88e6xxx/chip.c | 1 +
1 file changed, 1 insertion(+)
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -6989,6 +6989,7 @@ static int mv88e6xxx_register_switch(str
ds->ops = &mv88e6xxx_switch_ops;
ds->ageing_time_min = chip->info->age_time_coeff;
ds->ageing_time_max = chip->info->age_time_coeff * U8_MAX;
+ ds->assisted_learning_on_cpu_port = true;
/* Some chips support up to 32, but that requires enabling the
* 5-bit port mode, which we do not support. 640k^W16 ought to

View file

@ -1,30 +0,0 @@
From 3f1a227cb071f65f6ecc4db9f399649869735a7c Mon Sep 17 00:00:00 2001
From: David Bauer <mail@david-bauer.net>
Date: Sat, 17 Feb 2024 22:34:59 +0100
Subject: [PATCH] net vxlan: don't learn non-unicast L2 destinations
This patch avoids learning non-unicast targets in the vxlan FDB.
They are non-unicast and thus should be sent to the broadcast-IPv6
instead of a unicast address.
Link: https://lore.kernel.org/netdev/15ee0cc7-9252-466b-8ce7-5225d605dde8@david-bauer.net/
Link: https://github.com/freifunk-gluon/gluon/issues/3191
Signed-off-by: David Bauer <mail@david-bauer.net>
---
drivers/net/vxlan.c | 4 ++++
1 file changed, 4 insertions(+)
--- a/drivers/net/vxlan/vxlan_core.c
+++ b/drivers/net/vxlan/vxlan_core.c
@@ -1446,6 +1446,10 @@ static bool vxlan_snoop(struct net_devic
struct vxlan_fdb *f;
u32 ifindex = 0;
+ /* Don't learn broadcast packets */
+ if (is_multicast_ether_addr(src_mac) || is_zero_ether_addr(src_mac))
+ return false;
+
#if IS_ENABLED(CONFIG_IPV6)
if (src_ip->sa.sa_family == AF_INET6 &&
(ipv6_addr_type(&src_ip->sin6.sin6_addr) & IPV6_ADDR_LINKLOCAL))

View file

@ -0,0 +1,31 @@
From f992b15965177e2f280fb6f41f292214f9a6f8d5 Mon Sep 17 00:00:00 2001
From: Pavan Chebbi <pavan.chebbi@broadcom.com>
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")
Reported-By: Rui Salvaterra <rsalvaterra@gmail.com>
Signed-off-by: Pavan Chebbi <pavan.chebbi@broadcom.com>
---
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
@@ -17801,8 +17801,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)) {

View file

@ -70,7 +70,7 @@ v1 -> v2:
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -1820,4 +1820,19 @@ config GPIO_SIM
@@ -1929,4 +1929,19 @@ config GPIO_VIRTUSER
endmenu
@ -92,17 +92,17 @@ v1 -> v2:
endif
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -44,6 +44,7 @@ obj-$(CONFIG_GPIO_BD9571MWV) += gpio-bd
@@ -45,6 +45,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
obj-$(CONFIG_GPIO_CROS_EC) += gpio-cros-ec.o
--- /dev/null
+++ b/drivers/gpio/gpio-cascade.c
@@ -0,0 +1,117 @@
@@ -0,0 +1,112 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * A generic GPIO cascade driver
@ -141,11 +141,6 @@ v1 -> v2:
+ struct gpio_desc *upstream_line;
+};
+
+static struct gpio_cascade *chip_to_cascade(struct gpio_chip *gc)
+{
+ return container_of(gc, struct gpio_cascade, gpio_chip);
+}
+
+static int gpio_cascade_get_direction(struct gpio_chip *gc, unsigned int offset)
+{
+ return GPIO_LINE_DIRECTION_IN;
@ -153,7 +148,7 @@ v1 -> v2:
+
+static int gpio_cascade_get_value(struct gpio_chip *gc, unsigned int offset)
+{
+ struct gpio_cascade *cas = chip_to_cascade(gc);
+ struct gpio_cascade *cas = gpiochip_get_data(gc);
+ int ret;
+
+ ret = mux_control_select(cas->mux_control, offset);
@ -199,7 +194,7 @@ v1 -> v2:
+ gc->owner = THIS_MODULE;
+
+ platform_set_drvdata(pdev, cas);
+ return devm_gpiochip_add_data(dev, &cas->gpio_chip, NULL);
+ return devm_gpiochip_add_data(dev, &cas->gpio_chip, cas);
+}
+
+static const struct of_device_id gpio_cascade_id[] = {

View file

@ -33,7 +33,7 @@ Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
return 0;
--- a/drivers/opp/core.c
+++ b/drivers/opp/core.c
@@ -902,7 +902,8 @@ static int _set_opp_voltage(struct devic
@@ -942,7 +942,8 @@ static int _set_opp_voltage(struct devic
static int
_opp_config_clk_single(struct device *dev, struct opp_table *opp_table,
@ -43,7 +43,7 @@ Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
{
unsigned long *target = data;
unsigned long freq;
@@ -934,8 +935,8 @@ _opp_config_clk_single(struct device *de
@@ -974,8 +975,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,
@ -54,7 +54,7 @@ Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
{
int ret, i;
@@ -1217,7 +1218,7 @@ static int _set_opp(struct device *dev,
@@ -1242,7 +1243,7 @@ static int _set_opp(struct device *dev,
}
if (opp_table->config_clks) {
@ -63,7 +63,7 @@ Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
if (ret)
return ret;
}
@@ -1292,7 +1293,7 @@ int dev_pm_opp_set_rate(struct device *d
@@ -1321,7 +1322,7 @@ int dev_pm_opp_set_rate(struct device *d
* equivalent to a clk_set_rate()
*/
if (!_get_opp_count(opp_table)) {
@ -74,7 +74,7 @@ Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
}
--- a/include/linux/pm_opp.h
+++ b/include/linux/pm_opp.h
@@ -61,7 +61,8 @@ typedef int (*config_regulators_t)(struc
@@ -50,7 +50,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);
@ -84,7 +84,7 @@ Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
struct dev_pm_opp *opp, void *data, bool scaling_down);
/**
@@ -172,8 +173,8 @@ int dev_pm_opp_set_config(struct device
@@ -184,8 +185,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,
@ -95,7 +95,7 @@ Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
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
@@ -395,8 +396,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,

View file

@ -0,0 +1,45 @@
From 0e71cac033bb7689c4dfa2e6814191337ef770f5 Mon Sep 17 00:00:00 2001
From: INAGAKI Hiroshi <musashino.open@gmail.com>
Date: Thu, 13 Oct 2022 00:51:33 +0900
Subject: [PATCH] nvmem: layouts: u-boot-env: align endianness of crc32 values
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This patch fixes crc32 error on Big-Endianness system by conversion of
calculated crc32 value.
Little-Endianness system:
obtained crc32: Little
calculated crc32: Little
Big-Endianness system:
obtained crc32: Little
calculated crc32: Big
log (APRESIA ApresiaLightGS120GT-SS, RTL8382M, Big-Endianness):
[ 8.570000] u_boot_env 18001200.spi:flash@0:partitions:partition@c0000: Invalid calculated CRC32: 0x88cd6f09 (expected: 0x096fcd88)
[ 8.580000] u_boot_env: probe of 18001200.spi:flash@0:partitions:partition@c0000 failed with error -22
Fixes: f955dc1445069 ("nvmem: add driver handling U-Boot environment variables")
Signed-off-by: INAGAKI Hiroshi <musashino.open@gmail.com>
Acked-by: Rafał Miłecki <rafal@milecki.pl>
Tested-by: Christian Lamparter <chunkeey@gmail.com>
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
--- a/drivers/nvmem/layouts/u-boot-env.c
+++ b/drivers/nvmem/layouts/u-boot-env.c
@@ -148,7 +148,7 @@ int u_boot_env_parse(struct device *dev,
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;
+ calc = le32_to_cpu((__le32)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;

View file

@ -33,7 +33,7 @@ string.
#include <linux/init.h>
#include <linux/kref.h>
#include <linux/module.h>
@@ -779,6 +782,62 @@ static int nvmem_validate_keepouts(struc
@@ -797,6 +800,62 @@ static int nvmem_validate_keepouts(struc
return 0;
}
@ -96,7 +96,7 @@ string.
static int nvmem_add_cells_from_dt(struct nvmem_device *nvmem, struct device_node *np)
{
struct device *dev = &nvmem->dev;
@@ -813,6 +872,25 @@ static int nvmem_add_cells_from_dt(struc
@@ -836,6 +895,25 @@ static int nvmem_add_cells_from_dt(struc
if (nvmem->fixup_dt_cell_info)
nvmem->fixup_dt_cell_info(nvmem, &info);

View file

@ -9,7 +9,7 @@ Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
--- a/drivers/pci/Kconfig
+++ b/drivers/pci/Kconfig
@@ -113,6 +113,13 @@ config XEN_PCIDEV_FRONTEND
@@ -118,6 +118,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.
@ -25,7 +25,7 @@ Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -300,6 +300,7 @@ static void quirk_mmio_always_on(struct
@@ -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);
@ -33,7 +33,7 @@ Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
/*
* The Mellanox Tavor device gives false positive parity errors. Disable
* parity error reporting.
@@ -3488,6 +3489,8 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_I
@@ -3508,6 +3509,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);
@ -42,7 +42,7 @@ Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
/*
* 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
@@ -3513,6 +3516,8 @@ static void quirk_intel_ntb(struct pci_d
@@ -3533,6 +3536,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);
@ -51,7 +51,7 @@ Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
/*
* Some BIOS implementations leave the Intel GPU interrupts enabled, even
* though no one is handling them (e.g., if the i915 driver is never
@@ -3551,6 +3556,8 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_IN
@@ -3571,6 +3576,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);

View file

@ -0,0 +1,145 @@
From: Daniel Golle <daniel@makrotopia.org>
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.
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
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
@@ -672,6 +672,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
@@ -4728,6 +4739,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 &&
@@ -5450,6 +5464,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;
@@ -5464,6 +5481,12 @@ void ata_port_free(struct ata_port *ap)
kfree(ap->pmp_link);
kfree(ap->slave_link);
ida_free(&ata_ida, ap->print_id);
+#ifdef CONFIG_ATA_LEDS
+ if (ap->ledtrig) {
+ led_trigger_unregister(ap->ledtrig);
+ kfree(ap->ledtrig);
+ };
+#endif
kfree(ap);
}
EXPORT_SYMBOL_GPL(ata_port_free);
@@ -5868,7 +5891,23 @@ int ata_host_register(struct ata_host *h
WARN_ON(1);
return -EINVAL;
}
+#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
@@ -726,6 +729,10 @@ struct ata_device {
union acpi_object *gtf_cache;
unsigned int gtf_filter;
#endif
+#ifdef CONFIG_ATA_LEDS
+ struct led_trigger *ledtrig;
+ char ledtrig_name[8];
+#endif
#ifdef CONFIG_SATA_ZPODD
void *zpodd;
#endif

View file

@ -33,7 +33,7 @@ Signed-off-by: Marek Behún <kabel@kernel.org>
--- a/drivers/pci/controller/pci-aardvark.c
+++ b/drivers/pci/controller/pci-aardvark.c
@@ -277,7 +277,6 @@ struct advk_pcie {
@@ -276,7 +276,6 @@ struct advk_pcie {
u8 wins_count;
struct irq_domain *rp_irq_domain;
struct irq_domain *irq_domain;
@ -41,7 +41,7 @@ Signed-off-by: Marek Behún <kabel@kernel.org>
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
@@ -1418,14 +1417,19 @@ static void advk_pcie_irq_unmask(struct
raw_spin_unlock_irqrestore(&pcie->irq_lock, flags);
}
@ -63,7 +63,7 @@ Signed-off-by: Marek Behún <kabel@kernel.org>
irq_set_chip_data(virq, pcie);
return 0;
@@ -1492,7 +1496,6 @@ static int advk_pcie_init_irq_domain(str
@@ -1485,7 +1489,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;
@ -71,7 +71,7 @@ Signed-off-by: Marek Behún <kabel@kernel.org>
int ret = 0;
raw_spin_lock_init(&pcie->irq_lock);
@@ -1503,28 +1506,14 @@ static int advk_pcie_init_irq_domain(str
@@ -1496,28 +1499,14 @@ static int advk_pcie_init_irq_domain(str
return -ENODEV;
}

View file

@ -26,8 +26,8 @@ Signed-off-by: Lech Perczak <lech.perczak@gmail.com>
--- 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>;
@@ -116,6 +116,14 @@
cpu-supply = <&sw1a_reg>;
};
+&cpu0 {

View file

@ -0,0 +1,783 @@
From df1357358eec062241bddd2995e7ef0ce86cf45a Mon Sep 17 00:00:00 2001
X-Patchwork-Submitter: Corentin Labbe <clabbe@baylibre.com>
X-Patchwork-Id: 13656881
Message-Id: <20240507131522.3546113-2-clabbe@baylibre.com>
X-Mailer: git-send-email 2.25.1
In-Reply-To: <20240507131522.3546113-1-clabbe@baylibre.com>
References: <20240507131522.3546113-1-clabbe@baylibre.com>
Precedence: bulk
X-Mailing-List: linux-usb@vger.kernel.org
List-Id: <linux-usb.vger.kernel.org>
From: Corentin Labbe <clabbe@baylibre.com>
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
Signed-off-by: Corentin Labbe <clabbe@baylibre.com>
Tested-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
---
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.
+ *
+ * Copyright (C) 2022 Corentin Labbe <clabbe@baylibre.com>
+ * With the help of Neil Armstrong <neil.armstrong@linaro.org>
+ * and the help of Martin Blumenstingl <martin.blumenstingl@googlemail.com>
+ */
+
+#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_AUTHOR("Corentin Labbe <clabbe@baylibre.com>");
+MODULE_DESCRIPTION("USB CH348 Octo port serial converter driver");
+MODULE_LICENSE("GPL");

Some files were not shown because too many files have changed in this diff Show more