mirror of
				https://github.com/Ysurac/openmptcprouter.git
				synced 2025-03-09 15:40:20 +00:00 
			
		
		
		
	Add first test for kernel 6.10 support
This commit is contained in:
		
							parent
							
								
									f735d6c75a
								
							
						
					
					
						commit
						f023e9c6e5
					
				
					 271 changed files with 57306 additions and 14 deletions
				
			
		
							
								
								
									
										8367
									
								
								6.10/target/linux/generic/config-6.10
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										8367
									
								
								6.10/target/linux/generic/config-6.10
									
										
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							|  | @ -0,0 +1,97 @@ | |||
| From a7ae4ed0a3951c45d4a59ee575951b64ae4a23fb Mon Sep 17 00:00:00 2001 | ||||
| From: Felix Fietkau <nbd@nbd.name> | ||||
| Date: Tue, 7 May 2024 12:22:15 +0200 | ||||
| Subject: [PATCH] kernel: fix tools build breakage on macos with x86 | ||||
| 
 | ||||
| Signed-off-by: Felix Fietkau <nbd@nbd.name> | ||||
| ---
 | ||||
| --- a/tools/scripts/Makefile.include
 | ||||
| +++ b/tools/scripts/Makefile.include
 | ||||
| @@ -72,8 +72,6 @@ $(call allow-override,CXX,$(CROSS_COMPIL
 | ||||
|  $(call allow-override,STRIP,$(CROSS_COMPILE)strip) | ||||
|  endif | ||||
|   | ||||
| -CC_NO_CLANG := $(shell $(CC) -dM -E -x c /dev/null | grep -Fq "__clang__"; echo $$?)
 | ||||
| -
 | ||||
|  ifneq ($(LLVM),) | ||||
|  HOSTAR  ?= $(LLVM_PREFIX)llvm-ar$(LLVM_SUFFIX) | ||||
|  HOSTCC  ?= $(LLVM_PREFIX)clang$(LLVM_SUFFIX) | ||||
| @@ -84,6 +82,9 @@ HOSTCC  ?= gcc
 | ||||
|  HOSTLD  ?= ld | ||||
|  endif | ||||
|   | ||||
| +CC_NO_CLANG := $(shell $(CC) -dM -E -x c /dev/null | grep -Fq "__clang__"; echo $$?)
 | ||||
| +HOSTCC_NO_CLANG := $(shell $(HOSTCC) -dM -E -x c /dev/null | grep -Fq "__clang__"; echo $$?)
 | ||||
| +
 | ||||
|  # Some tools require Clang, LLC and/or LLVM utils | ||||
|  CLANG		?= clang | ||||
|  LLC		?= llc | ||||
| @@ -92,8 +93,9 @@ LLVM_OBJCOPY	?= llvm-objcopy
 | ||||
|  LLVM_STRIP	?= llvm-strip | ||||
|   | ||||
|  ifeq ($(CC_NO_CLANG), 1) | ||||
| -EXTRA_WARNINGS += -Wstrict-aliasing=3
 | ||||
| -
 | ||||
| +  ifeq ($(HOSTCC_NO_CLANG), 1)
 | ||||
| +    EXTRA_WARNINGS += -Wstrict-aliasing=3
 | ||||
| +  endif
 | ||||
|  else ifneq ($(CROSS_COMPILE),) | ||||
|  # Allow userspace to override CLANG_CROSS_FLAGS to specify their own | ||||
|  # sysroots and flags or to avoid the GCC call in pure Clang builds. | ||||
| --- a/tools/include/linux/types.h
 | ||||
| +++ b/tools/include/linux/types.h
 | ||||
| @@ -56,6 +56,7 @@ typedef __s8  s8;
 | ||||
|  #define __user | ||||
|  #endif | ||||
|  #define __must_check | ||||
| +#undef __cold
 | ||||
|  #define __cold | ||||
|   | ||||
|  typedef __u16 __bitwise __le16; | ||||
| --- a/tools/objtool/include/objtool/objtool.h
 | ||||
| +++ b/tools/objtool/include/objtool/objtool.h
 | ||||
| @@ -12,6 +12,7 @@
 | ||||
|   | ||||
|  #include <objtool/elf.h> | ||||
|   | ||||
| +#undef __weak
 | ||||
|  #define __weak __attribute__((weak)) | ||||
|   | ||||
|  struct pv_state { | ||||
| --- a/tools/include/asm-generic/bitops/fls.h
 | ||||
| +++ b/tools/include/asm-generic/bitops/fls.h
 | ||||
| @@ -2,6 +2,8 @@
 | ||||
|  #ifndef _ASM_GENERIC_BITOPS_FLS_H_ | ||||
|  #define _ASM_GENERIC_BITOPS_FLS_H_ | ||||
|   | ||||
| +#include <string.h>
 | ||||
| +
 | ||||
|  /** | ||||
|   * fls - find last (most-significant) bit set | ||||
|   * @x: the word to search | ||||
| @@ -10,6 +12,7 @@
 | ||||
|   * Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32. | ||||
|   */ | ||||
|   | ||||
| +#define fls __linux_fls
 | ||||
|  static __always_inline int fls(unsigned int x) | ||||
|  { | ||||
|  	int r = 32; | ||||
| --- a/tools/lib/string.c
 | ||||
| +++ b/tools/lib/string.c
 | ||||
| @@ -96,6 +96,7 @@ int strtobool(const char *s, bool *res)
 | ||||
|   * If libc has strlcpy() then that version will override this | ||||
|   * implementation: | ||||
|   */ | ||||
| +#ifndef __APPLE__
 | ||||
|  #ifdef __clang__ | ||||
|  #pragma clang diagnostic push | ||||
|  #pragma clang diagnostic ignored "-Wignored-attributes" | ||||
| @@ -114,6 +115,7 @@ size_t __weak strlcpy(char *dest, const
 | ||||
|  #ifdef __clang__ | ||||
|  #pragma clang diagnostic pop | ||||
|  #endif | ||||
| +#endif
 | ||||
|   | ||||
|  /** | ||||
|   * skip_spaces - Removes leading whitespace from @str. | ||||
							
								
								
									
										210
									
								
								6.10/target/linux/generic/hack-6.10/204-module_strip.patch
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										210
									
								
								6.10/target/linux/generic/hack-6.10/204-module_strip.patch
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,210 @@ | |||
| From a779a482fb9b9f8fcdf8b2519c789b4b9bb5dd05 Mon Sep 17 00:00:00 2001 | ||||
| From: Felix Fietkau <nbd@nbd.name> | ||||
| Date: Fri, 7 Jul 2017 16:56:48 +0200 | ||||
| Subject: build: add a hack for removing non-essential module info | ||||
| 
 | ||||
| Signed-off-by: Felix Fietkau <nbd@nbd.name> | ||||
| ---
 | ||||
|  include/linux/module.h      | 13 ++++++++----- | ||||
|  include/linux/moduleparam.h | 15 ++++++++++++--- | ||||
|  init/Kconfig                |  7 +++++++ | ||||
|  kernel/module.c             |  5 ++++- | ||||
|  scripts/mod/modpost.c       | 12 ++++++++++++ | ||||
|  5 files changed, 43 insertions(+), 9 deletions(-) | ||||
| 
 | ||||
| --- a/include/linux/module.h
 | ||||
| +++ b/include/linux/module.h
 | ||||
| @@ -164,6 +164,7 @@ extern void cleanup_module(void);
 | ||||
|   | ||||
|  /* Generic info of form tag = "info" */ | ||||
|  #define MODULE_INFO(tag, info) __MODULE_INFO(tag, tag, info) | ||||
| +#define MODULE_INFO_STRIP(tag, info) __MODULE_INFO_STRIP(tag, tag, info)
 | ||||
|   | ||||
|  /* For userspace: you can also call me... */ | ||||
|  #define MODULE_ALIAS(_alias) MODULE_INFO(alias, _alias) | ||||
| @@ -233,12 +234,12 @@ extern void cleanup_module(void);
 | ||||
|   * Author(s), use "Name <email>" or just "Name", for multiple | ||||
|   * authors use multiple MODULE_AUTHOR() statements/lines. | ||||
|   */ | ||||
| -#define MODULE_AUTHOR(_author) MODULE_INFO(author, _author)
 | ||||
| +#define MODULE_AUTHOR(_author) MODULE_INFO_STRIP(author, _author)
 | ||||
|   | ||||
|  /* What your module does. */ | ||||
| -#define MODULE_DESCRIPTION(_description) MODULE_INFO(description, _description)
 | ||||
| +#define MODULE_DESCRIPTION(_description) MODULE_INFO_STRIP(description, _description)
 | ||||
|   | ||||
| -#ifdef MODULE
 | ||||
| +#if defined(MODULE) && !defined(CONFIG_MODULE_STRIPPED)
 | ||||
|  /* Creates an alias so file2alias.c can find device table. */ | ||||
|  #define MODULE_DEVICE_TABLE(type, name)					\ | ||||
|  extern typeof(name) __mod_##type##__##name##_device_table		\ | ||||
| @@ -265,7 +266,9 @@ extern typeof(name) __mod_##type##__##na
 | ||||
|   */ | ||||
|   | ||||
|  #if defined(MODULE) || !defined(CONFIG_SYSFS) | ||||
| -#define MODULE_VERSION(_version) MODULE_INFO(version, _version)
 | ||||
| +#define MODULE_VERSION(_version) MODULE_INFO_STRIP(version, _version)
 | ||||
| +#elif defined(CONFIG_MODULE_STRIPPED)
 | ||||
| +#define MODULE_VERSION(_version) __MODULE_INFO_DISABLED(version)
 | ||||
|  #else | ||||
|  #define MODULE_VERSION(_version)					\ | ||||
|  	MODULE_INFO(version, _version);					\ | ||||
| @@ -288,7 +291,7 @@ extern typeof(name) __mod_##type##__##na
 | ||||
|  /* Optional firmware file (or files) needed by the module | ||||
|   * format is simply firmware file name.  Multiple firmware | ||||
|   * files require multiple MODULE_FIRMWARE() specifiers */ | ||||
| -#define MODULE_FIRMWARE(_firmware) MODULE_INFO(firmware, _firmware)
 | ||||
| +#define MODULE_FIRMWARE(_firmware) MODULE_INFO_STRIP(firmware, _firmware)
 | ||||
|   | ||||
|  #define MODULE_IMPORT_NS(ns)	MODULE_INFO(import_ns, __stringify(ns)) | ||||
|   | ||||
| --- a/include/linux/moduleparam.h
 | ||||
| +++ b/include/linux/moduleparam.h
 | ||||
| @@ -20,6 +20,16 @@
 | ||||
|  /* Chosen so that structs with an unsigned long line up. */ | ||||
|  #define MAX_PARAM_PREFIX_LEN (64 - sizeof(unsigned long)) | ||||
|   | ||||
| +/* This struct is here for syntactic coherency, it is not used */
 | ||||
| +#define __MODULE_INFO_DISABLED(name)					  \
 | ||||
| +  struct __UNIQUE_ID(name) {}
 | ||||
| +
 | ||||
| +#ifdef CONFIG_MODULE_STRIPPED
 | ||||
| +#define __MODULE_INFO_STRIP(tag, name, info) __MODULE_INFO_DISABLED(name)
 | ||||
| +#else
 | ||||
| +#define __MODULE_INFO_STRIP(tag, name, info) __MODULE_INFO(tag, name, info)
 | ||||
| +#endif
 | ||||
| +
 | ||||
|  #define __MODULE_INFO(tag, name, info)					  \ | ||||
|  	static const char __UNIQUE_ID(name)[]				  \ | ||||
|  		__used __section(".modinfo") __aligned(1)		  \ | ||||
| @@ -31,7 +41,7 @@
 | ||||
|  /* One for each parameter, describing how to use it.  Some files do | ||||
|     multiple of these per line, so can't just use MODULE_INFO. */ | ||||
|  #define MODULE_PARM_DESC(_parm, desc) \ | ||||
| -	__MODULE_INFO(parm, _parm, #_parm ":" desc)
 | ||||
| +	__MODULE_INFO_STRIP(parm, _parm, #_parm ":" desc)
 | ||||
|   | ||||
|  struct kernel_param; | ||||
|   | ||||
| --- a/kernel/module/Kconfig
 | ||||
| +++ b/kernel/module/Kconfig
 | ||||
| @@ -389,4 +389,11 @@ config MODULES_TREE_LOOKUP
 | ||||
|  	def_bool y | ||||
|  	depends on PERF_EVENTS || TRACING || CFI_CLANG | ||||
|   | ||||
| +config MODULE_STRIPPED
 | ||||
| +	bool "Reduce module size"
 | ||||
| +	depends on MODULES
 | ||||
| +	help
 | ||||
| +	  Remove module parameter descriptions, author info, version, aliases,
 | ||||
| +	  device tables, etc.
 | ||||
| +
 | ||||
|  endif # MODULES | ||||
| --- a/kernel/module/main.c
 | ||||
| +++ b/kernel/module/main.c
 | ||||
| @@ -997,6 +997,7 @@ size_t modinfo_attrs_count = ARRAY_SIZE(
 | ||||
|   | ||||
|  static const char vermagic[] = VERMAGIC_STRING; | ||||
|   | ||||
| +#if defined(CONFIG_MODVERSIONS) || !defined(CONFIG_MODULE_STRIPPED)
 | ||||
|  int try_to_force_load(struct module *mod, const char *reason) | ||||
|  { | ||||
|  #ifdef CONFIG_MODULE_FORCE_LOAD | ||||
| @@ -1008,6 +1009,7 @@ int try_to_force_load(struct module *mod
 | ||||
|  	return -ENOEXEC; | ||||
|  #endif | ||||
|  } | ||||
| +#endif
 | ||||
|   | ||||
|  /* Parse tag=value strings from .modinfo section */ | ||||
|  char *module_next_tag_pair(char *string, unsigned long *secsize) | ||||
| @@ -2075,9 +2077,11 @@ static void module_augment_kernel_taints
 | ||||
|   | ||||
|  static int check_modinfo(struct module *mod, struct load_info *info, int flags) | ||||
|  { | ||||
| -	const char *modmagic = get_modinfo(info, "vermagic");
 | ||||
|  	int err; | ||||
|   | ||||
| +#ifndef CONFIG_MODULE_STRIPPED
 | ||||
| +	const char *modmagic = get_modinfo(info, "vermagic");
 | ||||
| +
 | ||||
|  	if (flags & MODULE_INIT_IGNORE_VERMAGIC) | ||||
|  		modmagic = NULL; | ||||
|   | ||||
| @@ -2091,6 +2095,7 @@ static int check_modinfo(struct module *
 | ||||
|  		       info->name, modmagic, vermagic); | ||||
|  		return -ENOEXEC; | ||||
|  	} | ||||
| +#endif
 | ||||
|   | ||||
|  	err = check_modinfo_livepatch(mod, info); | ||||
|  	if (err) | ||||
| --- a/scripts/mod/modpost.c
 | ||||
| +++ b/scripts/mod/modpost.c
 | ||||
| @@ -1692,7 +1692,9 @@ static void read_symbols(const char *mod
 | ||||
|  		symname = remove_dot(info.strtab + sym->st_name); | ||||
|   | ||||
|  		handle_symbol(mod, &info, sym, symname); | ||||
| +#ifndef CONFIG_MODULE_STRIPPED
 | ||||
|  		handle_moddevtable(mod, &info, sym, symname); | ||||
| +#endif
 | ||||
|  	} | ||||
|   | ||||
|  	check_sec_ref(mod, &info); | ||||
| @@ -1865,8 +1867,10 @@ static void add_header(struct buffer *b,
 | ||||
|  	buf_printf(b, "BUILD_SALT;\n"); | ||||
|  	buf_printf(b, "BUILD_LTO_INFO;\n"); | ||||
|  	buf_printf(b, "\n"); | ||||
| +#ifndef CONFIG_MODULE_STRIPPED
 | ||||
|  	buf_printf(b, "MODULE_INFO(vermagic, VERMAGIC_STRING);\n"); | ||||
|  	buf_printf(b, "MODULE_INFO(name, KBUILD_MODNAME);\n"); | ||||
| +#endif
 | ||||
|  	buf_printf(b, "\n"); | ||||
|  	buf_printf(b, "__visible struct module __this_module\n"); | ||||
|  	buf_printf(b, "__section(\".gnu.linkonce.this_module\") = {\n"); | ||||
| @@ -1880,8 +1884,10 @@ static void add_header(struct buffer *b,
 | ||||
|  	buf_printf(b, "\t.arch = MODULE_ARCH_INIT,\n"); | ||||
|  	buf_printf(b, "};\n"); | ||||
|   | ||||
| +#ifndef CONFIG_MODULE_STRIPPED
 | ||||
|  	if (!external_module) | ||||
|  		buf_printf(b, "\nMODULE_INFO(intree, \"Y\");\n"); | ||||
| +#endif
 | ||||
|   | ||||
|  	buf_printf(b, | ||||
|  		   "\n" | ||||
| @@ -1889,8 +1895,10 @@ static void add_header(struct buffer *b,
 | ||||
|  		   "MODULE_INFO(retpoline, \"Y\");\n" | ||||
|  		   "#endif\n"); | ||||
|   | ||||
| +#ifndef CONFIG_MODULE_STRIPPED
 | ||||
|  	if (strstarts(mod->name, "drivers/staging")) | ||||
|  		buf_printf(b, "\nMODULE_INFO(staging, \"Y\");\n"); | ||||
| +#endif
 | ||||
|   | ||||
|  	if (strstarts(mod->name, "tools/testing")) | ||||
|  		buf_printf(b, "\nMODULE_INFO(test, \"Y\");\n"); | ||||
| @@ -2000,11 +2008,13 @@ static void add_depends(struct buffer *b
 | ||||
|   | ||||
|  static void add_srcversion(struct buffer *b, struct module *mod) | ||||
|  { | ||||
| +#ifndef CONFIG_MODULE_STRIPPED
 | ||||
|  	if (mod->srcversion[0]) { | ||||
|  		buf_printf(b, "\n"); | ||||
|  		buf_printf(b, "MODULE_INFO(srcversion, \"%s\");\n", | ||||
|  			   mod->srcversion); | ||||
|  	} | ||||
| +#endif
 | ||||
|  } | ||||
|   | ||||
|  static void write_buf(struct buffer *b, const char *fname) | ||||
| @@ -2087,7 +2097,9 @@ static void write_mod_c_file(struct modu
 | ||||
|  	add_exported_symbols(&buf, mod); | ||||
|  	add_versions(&buf, mod); | ||||
|  	add_depends(&buf, mod); | ||||
| +#ifndef CONFIG_MODULE_STRIPPED
 | ||||
|  	add_moddevtable(&buf, mod); | ||||
| +#endif
 | ||||
|  	add_srcversion(&buf, mod); | ||||
|   | ||||
|  	ret = snprintf(fname, sizeof(fname), "%s.mod.c", mod->name); | ||||
|  | @ -0,0 +1,41 @@ | |||
| From 310e8e04a05d9eb43fa9dd7f00143300afcaa37a Mon Sep 17 00:00:00 2001 | ||||
| From: David Bauer <mail@david-bauer.net> | ||||
| Date: Fri, 11 Nov 2022 13:33:44 +0100 | ||||
| Subject: [PATCH] kconfig: abort configuration on unset symbol | ||||
| 
 | ||||
| When a target configuration has unset Kconfig symbols, the build will | ||||
| fail when OpenWrt is compiled with V=s and stdin is connected to a tty. | ||||
| 
 | ||||
| In case OpenWrt is compiled without either of these preconditions, the | ||||
| build will succeed with the symbols in question being unset. | ||||
| 
 | ||||
| Modify the kernel configuration in a way it fails on unset symbols | ||||
| regardless of the aforementioned preconditions. | ||||
| 
 | ||||
| Signed-off-by: David Bauer <mail@david-bauer.net> | ||||
| ---
 | ||||
|  scripts/kconfig/conf.c | 6 ++++++ | ||||
|  1 file changed, 6 insertions(+) | ||||
| 
 | ||||
| --- a/scripts/kconfig/conf.c
 | ||||
| +++ b/scripts/kconfig/conf.c
 | ||||
| @@ -338,6 +338,9 @@ static int conf_askvalue(struct symbol *
 | ||||
|  		} | ||||
|  		/* fall through */ | ||||
|  	default: | ||||
| +		if (!tty_stdio && getenv("FAIL_ON_UNCONFIGURED")) {
 | ||||
| +			exit(1);
 | ||||
| +		}
 | ||||
|  		fflush(stdout); | ||||
|  		xfgets(line, sizeof(line), stdin); | ||||
|  		break; | ||||
| @@ -520,6 +523,9 @@ static int conf_choice(struct menu *menu
 | ||||
|  			} | ||||
|  			/* fall through */ | ||||
|  		case oldaskconfig: | ||||
| +			if (!tty_stdio && getenv("FAIL_ON_UNCONFIGURED")) {
 | ||||
| +				exit(1);
 | ||||
| +			}
 | ||||
|  			fflush(stdout); | ||||
|  			xfgets(line, sizeof(line), stdin); | ||||
|  			strip(line); | ||||
							
								
								
									
										3053
									
								
								6.10/target/linux/generic/hack-6.10/210-darwin_scripts_include.patch
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										3053
									
								
								6.10/target/linux/generic/hack-6.10/210-darwin_scripts_include.patch
									
										
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							|  | @ -0,0 +1,22 @@ | |||
| From e44fc2af1ddc452b6659d08c16973d65c73b7d0a Mon Sep 17 00:00:00 2001 | ||||
| From: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk> | ||||
| Date: Wed, 5 Feb 2020 18:36:43 +0000 | ||||
| Subject: [PATCH] file2alias: build on macos | ||||
| 
 | ||||
| Signed-off-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk> | ||||
| ---
 | ||||
|  scripts/mod/file2alias.c | 3 +++ | ||||
|  1 file changed, 3 insertions(+) | ||||
| 
 | ||||
| --- a/scripts/mod/file2alias.c
 | ||||
| +++ b/scripts/mod/file2alias.c
 | ||||
| @@ -35,6 +35,9 @@ typedef uint32_t	__u32;
 | ||||
|  typedef uint16_t	__u16; | ||||
|  typedef unsigned char	__u8; | ||||
|   | ||||
| +#ifdef __APPLE__
 | ||||
| +#define uuid_t compat_uuid_t
 | ||||
| +#endif
 | ||||
|  /* UUID types for backward compatibility, don't use in new code */ | ||||
|  typedef struct { | ||||
|  	__u8 b[16]; | ||||
|  | @ -0,0 +1,24 @@ | |||
| From be9be95ff10e16a5b4ad36f903978d0cc5747024 Mon Sep 17 00:00:00 2001 | ||||
| From: Felix Fietkau <nbd@nbd.name> | ||||
| Date: Fri, 7 Jul 2017 17:04:08 +0200 | ||||
| Subject: kernel: fix linux/spi/spidev.h portability issues with musl | ||||
| 
 | ||||
| Felix will try to get this define included into musl | ||||
| 
 | ||||
| lede-commit: 795e7cf60de19e7a076a46874fab7bb88b43bbff | ||||
| Signed-off-by: Felix Fietkau <nbd@nbd.name> | ||||
| ---
 | ||||
|  include/uapi/linux/spi/spidev.h | 2 +- | ||||
|  1 file changed, 1 insertion(+), 1 deletion(-) | ||||
| 
 | ||||
| --- a/include/uapi/linux/spi/spidev.h
 | ||||
| +++ b/include/uapi/linux/spi/spidev.h
 | ||||
| @@ -93,7 +93,7 @@ struct spi_ioc_transfer {
 | ||||
|   | ||||
|  /* not all platforms use <asm-generic/ioctl.h> or _IOC_TYPECHECK() ... */ | ||||
|  #define SPI_MSGSIZE(N) \ | ||||
| -	((((N)*(sizeof (struct spi_ioc_transfer))) < (1 << _IOC_SIZEBITS)) \
 | ||||
| +	((((N)*(sizeof (struct spi_ioc_transfer))) < (1 << 13)) \
 | ||||
|  		? ((N)*(sizeof (struct spi_ioc_transfer))) : 0) | ||||
|  #define SPI_IOC_MESSAGE(N) _IOW(SPI_IOC_MAGIC, 0, char[SPI_MSGSIZE(N)]) | ||||
|   | ||||
							
								
								
									
										123
									
								
								6.10/target/linux/generic/hack-6.10/220-arm-gc_sections.patch
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										123
									
								
								6.10/target/linux/generic/hack-6.10/220-arm-gc_sections.patch
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,123 @@ | |||
| From e3d8676f5722b7622685581e06e8f53e6138e3ab Mon Sep 17 00:00:00 2001 | ||||
| From: Felix Fietkau <nbd@nbd.name> | ||||
| Date: Sat, 15 Jul 2017 23:42:36 +0200 | ||||
| Subject: use -ffunction-sections, -fdata-sections and --gc-sections | ||||
| 
 | ||||
| In combination with kernel symbol export stripping this significantly reduces | ||||
| the kernel image size. Used on both ARM and MIPS architectures. | ||||
| 
 | ||||
| Signed-off-by: Felix Fietkau <nbd@nbd.name> | ||||
| Signed-off-by: Jonas Gorski <jogo@openwrt.org> | ||||
| Signed-off-by: Gabor Juhos <juhosg@openwrt.org> | ||||
| ---
 | ||||
| --- a/arch/arm/Kconfig
 | ||||
| +++ b/arch/arm/Kconfig
 | ||||
| @@ -128,6 +128,7 @@ config ARM
 | ||||
|  	select HOTPLUG_CORE_SYNC_DEAD if HOTPLUG_CPU | ||||
|  	select IRQ_FORCED_THREADING | ||||
|  	select LOCK_MM_AND_FIND_VMA | ||||
| +	select HAVE_LD_DEAD_CODE_DATA_ELIMINATION
 | ||||
|  	select MODULES_USE_ELF_REL | ||||
|  	select NEED_DMA_MAP_STATE | ||||
|  	select OF_EARLY_FLATTREE if OF | ||||
| --- a/arch/arm/boot/compressed/Makefile
 | ||||
| +++ b/arch/arm/boot/compressed/Makefile
 | ||||
| @@ -92,6 +92,7 @@ endif
 | ||||
|  ifeq ($(CONFIG_USE_OF),y) | ||||
|  OBJS	+= $(libfdt_objs) fdt_check_mem_start.o | ||||
|  endif | ||||
| +KBUILD_CFLAGS_KERNEL := $(patsubst -f%-sections,,$(KBUILD_CFLAGS_KERNEL))
 | ||||
|   | ||||
|  OBJS	+= lib1funcs.o ashldi3.o bswapsdi2.o | ||||
|   | ||||
| --- a/arch/arm/kernel/vmlinux.lds.S
 | ||||
| +++ b/arch/arm/kernel/vmlinux.lds.S
 | ||||
| @@ -74,7 +74,7 @@ SECTIONS
 | ||||
|  	. = ALIGN(4); | ||||
|  	__ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) { | ||||
|  		__start___ex_table = .; | ||||
| -		ARM_MMU_KEEP(*(__ex_table))
 | ||||
| +		KEEP(*(__ex_table))
 | ||||
|  		__stop___ex_table = .; | ||||
|  	} | ||||
|   | ||||
| @@ -99,24 +99,24 @@ SECTIONS
 | ||||
|  	} | ||||
|  	.init.arch.info : { | ||||
|  		__arch_info_begin = .; | ||||
| -		*(.arch.info.init)
 | ||||
| +		KEEP(*(.arch.info.init))
 | ||||
|  		__arch_info_end = .; | ||||
|  	} | ||||
|  	.init.tagtable : { | ||||
|  		__tagtable_begin = .; | ||||
| -		*(.taglist.init)
 | ||||
| +		KEEP(*(.taglist.init))
 | ||||
|  		__tagtable_end = .; | ||||
|  	} | ||||
|  #ifdef CONFIG_SMP_ON_UP | ||||
|  	.init.smpalt : { | ||||
|  		__smpalt_begin = .; | ||||
| -		*(.alt.smp.init)
 | ||||
| +		KEEP(*(.alt.smp.init))
 | ||||
|  		__smpalt_end = .; | ||||
|  	} | ||||
|  #endif | ||||
|  	.init.pv_table : { | ||||
|  		__pv_table_begin = .; | ||||
| -		*(.pv_table)
 | ||||
| +		KEEP(*(.pv_table))
 | ||||
|  		__pv_table_end = .; | ||||
|  	} | ||||
|   | ||||
| --- a/arch/arm/include/asm/vmlinux.lds.h
 | ||||
| +++ b/arch/arm/include/asm/vmlinux.lds.h
 | ||||
| @@ -42,13 +42,13 @@
 | ||||
|  #define PROC_INFO							\ | ||||
|  		. = ALIGN(4);						\ | ||||
|  		__proc_info_begin = .;					\ | ||||
| -		*(.proc.info.init)					\
 | ||||
| +		KEEP(*(.proc.info.init))				\
 | ||||
|  		__proc_info_end = .; | ||||
|   | ||||
|  #define IDMAP_TEXT							\ | ||||
|  		ALIGN_FUNCTION();					\ | ||||
|  		__idmap_text_start = .;					\ | ||||
| -		*(.idmap.text)						\
 | ||||
| +		KEEP(*(.idmap.text))					\
 | ||||
|  		__idmap_text_end = .;					\ | ||||
|   | ||||
|  #define ARM_DISCARD							\ | ||||
| @@ -108,12 +108,12 @@
 | ||||
|  	. = ALIGN(8);							\ | ||||
|  	.ARM.unwind_idx : {						\ | ||||
|  		__start_unwind_idx = .;					\ | ||||
| -		*(.ARM.exidx*)						\
 | ||||
| +		KEEP(*(.ARM.exidx*))					\
 | ||||
|  		__stop_unwind_idx = .;					\ | ||||
|  	}								\ | ||||
|  	.ARM.unwind_tab : {						\ | ||||
|  		__start_unwind_tab = .;					\ | ||||
| -		*(.ARM.extab*)						\
 | ||||
| +		KEEP(*(.ARM.extab*))					\
 | ||||
|  		__stop_unwind_tab = .;					\ | ||||
|  	} | ||||
|   | ||||
| @@ -125,7 +125,7 @@
 | ||||
|  	__vectors_lma = .;						\ | ||||
|  	OVERLAY 0xffff0000 : NOCROSSREFS AT(__vectors_lma) {		\ | ||||
|  		.vectors {						\ | ||||
| -			*(.vectors)					\
 | ||||
| +			KEEP(*(.vectors))				\
 | ||||
|  		}							\ | ||||
|  		.vectors.bhb.loop8 {					\ | ||||
|  			*(.vectors.bhb.loop8)				\ | ||||
| @@ -143,7 +143,7 @@
 | ||||
|  									\ | ||||
|  	__stubs_lma = .;						\ | ||||
|  	.stubs ADDR(.vectors) + 0x1000 : AT(__stubs_lma) {		\ | ||||
| -		*(.stubs)						\
 | ||||
| +		KEEP(*(.stubs))						\
 | ||||
|  	}								\ | ||||
|  	ARM_LMA(__stubs, .stubs);					\ | ||||
|  	. = __stubs_lma + SIZEOF(.stubs);				\ | ||||
|  | @ -0,0 +1,38 @@ | |||
| From b3d00b452467f621317953d9e4c6f9ae8dcfd271 Mon Sep 17 00:00:00 2001 | ||||
| From: Imre Kaloz <kaloz@openwrt.org> | ||||
| Date: Fri, 7 Jul 2017 17:06:55 +0200 | ||||
| Subject: use the openwrt lzma options for now | ||||
| 
 | ||||
| lede-commit: 548de949f392049420a6a1feeef118b30ab8ea8c | ||||
| Signed-off-by: Imre Kaloz <kaloz@openwrt.org> | ||||
| ---
 | ||||
|  lib/decompress.c              |  1 + | ||||
|  scripts/Makefile.lib          |  2 +- | ||||
|  usr/gen_initramfs_list.sh | 10 +++++----- | ||||
|  3 files changed, 7 insertions(+), 6 deletions(-) | ||||
| 
 | ||||
| --- a/lib/decompress.c
 | ||||
| +++ b/lib/decompress.c
 | ||||
| @@ -53,6 +53,7 @@ static const struct compress_format comp
 | ||||
|  	{ {0x1f, 0x9e}, "gzip", gunzip }, | ||||
|  	{ {0x42, 0x5a}, "bzip2", bunzip2 }, | ||||
|  	{ {0x5d, 0x00}, "lzma", unlzma }, | ||||
| +	{ {0x6d, 0x00}, "lzma-openwrt", unlzma },
 | ||||
|  	{ {0xfd, 0x37}, "xz", unxz }, | ||||
|  	{ {0x89, 0x4c}, "lzo", unlzo }, | ||||
|  	{ {0x02, 0x21}, "lz4", unlz4 }, | ||||
| --- a/scripts/Makefile.lib
 | ||||
| +++ b/scripts/Makefile.lib
 | ||||
| @@ -456,10 +456,10 @@ quiet_cmd_bzip2_with_size = BZIP2   $@
 | ||||
|  # --------------------------------------------------------------------------- | ||||
|   | ||||
|  quiet_cmd_lzma = LZMA    $@ | ||||
| -      cmd_lzma = cat $(real-prereqs) | $(LZMA) -9 > $@
 | ||||
| +      cmd_lzma = cat $(real-prereqs) | $(LZMA) e -d20 -lc1 -lp2 -pb2 -eos -si -so > $@
 | ||||
|   | ||||
|  quiet_cmd_lzma_with_size = LZMA    $@ | ||||
| -      cmd_lzma_with_size = { cat $(real-prereqs) | $(LZMA) -9; $(size_append); } > $@
 | ||||
| +      cmd_lzma_with_size = { cat $(real-prereqs) | $(LZMA) e -d20 -lc1 -lp2 -pb2 -eos -si -so; $(size_append); } > $@
 | ||||
|   | ||||
|  quiet_cmd_lzo = LZO     $@ | ||||
|        cmd_lzo = cat $(real-prereqs) | $(KLZOP) -9 > $@ | ||||
|  | @ -0,0 +1,27 @@ | |||
| From: Felix Fietkau <nbd@nbd.name> | ||||
| Subject: hack: net: remove bogus netfilter dependencies | ||||
| 
 | ||||
| lede-commit: 589d2a377dee27d206fc3725325309cf649e4df6 | ||||
| Signed-off-by: Felix Fietkau <nbd@nbd.name> | ||||
| ---
 | ||||
|  net/netfilter/Kconfig | 2 -- | ||||
|  1 file changed, 2 deletions(-) | ||||
| 
 | ||||
| --- a/net/netfilter/Kconfig
 | ||||
| +++ b/net/netfilter/Kconfig
 | ||||
| @@ -259,7 +259,6 @@ config NF_CONNTRACK_FTP
 | ||||
|   | ||||
|  config NF_CONNTRACK_H323 | ||||
|  	tristate "H.323 protocol support" | ||||
| -	depends on IPV6 || IPV6=n
 | ||||
|  	depends on NETFILTER_ADVANCED | ||||
|  	help | ||||
|  	  H.323 is a VoIP signalling protocol from ITU-T. As one of the most | ||||
| @@ -1120,7 +1119,6 @@ config NETFILTER_XT_TARGET_SECMARK
 | ||||
|   | ||||
|  config NETFILTER_XT_TARGET_TCPMSS | ||||
|  	tristate '"TCPMSS" target support' | ||||
| -	depends on IPV6 || IPV6=n
 | ||||
|  	default m if NETFILTER_ADVANCED=n | ||||
|  	help | ||||
|  	  This option adds a `TCPMSS' target, which allows you to alter the | ||||
							
								
								
									
										157
									
								
								6.10/target/linux/generic/hack-6.10/251-kconfig.patch
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										157
									
								
								6.10/target/linux/generic/hack-6.10/251-kconfig.patch
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,157 @@ | |||
| From da3c50704f14132f4adf80d48e9a4cd5d46e54c9 Mon Sep 17 00:00:00 2001 | ||||
| From: John Crispin <john@phrozen.org> | ||||
| Date: Fri, 7 Jul 2017 17:09:21 +0200 | ||||
| Subject: kconfig: owrt specifc dependencies | ||||
| 
 | ||||
| Signed-off-by: John Crispin <john@phrozen.org> | ||||
| ---
 | ||||
|  crypto/Kconfig        | 10 +++++----- | ||||
|  drivers/bcma/Kconfig  |  1 + | ||||
|  drivers/ssb/Kconfig   |  3 ++- | ||||
|  lib/Kconfig           |  8 ++++---- | ||||
|  net/netfilter/Kconfig |  2 +- | ||||
|  net/wireless/Kconfig  | 17 ++++++++++------- | ||||
|  sound/core/Kconfig    |  4 ++-- | ||||
|  7 files changed, 25 insertions(+), 20 deletions(-) | ||||
| 
 | ||||
| --- a/crypto/Kconfig
 | ||||
| +++ b/crypto/Kconfig
 | ||||
| @@ -55,7 +55,7 @@ config CRYPTO_FIPS_VERSION
 | ||||
|  	  By default the KERNELRELEASE value is used. | ||||
|   | ||||
|  config CRYPTO_ALGAPI | ||||
| -	tristate
 | ||||
| +	tristate "ALGAPI"
 | ||||
|  	select CRYPTO_ALGAPI2 | ||||
|  	help | ||||
|  	  This option provides the API for cryptographic algorithms. | ||||
| @@ -64,7 +64,7 @@ config CRYPTO_ALGAPI2
 | ||||
|  	tristate | ||||
|   | ||||
|  config CRYPTO_AEAD | ||||
| -	tristate
 | ||||
| +	tristate "AEAD"
 | ||||
|  	select CRYPTO_AEAD2 | ||||
|  	select CRYPTO_ALGAPI | ||||
|   | ||||
| @@ -82,7 +82,7 @@ config CRYPTO_SIG2
 | ||||
|  	select CRYPTO_ALGAPI2 | ||||
|   | ||||
|  config CRYPTO_SKCIPHER | ||||
| -	tristate
 | ||||
| +	tristate "SKCIPHER"
 | ||||
|  	select CRYPTO_SKCIPHER2 | ||||
|  	select CRYPTO_ALGAPI | ||||
|   | ||||
| @@ -91,7 +91,7 @@ config CRYPTO_SKCIPHER2
 | ||||
|  	select CRYPTO_ALGAPI2 | ||||
|   | ||||
|  config CRYPTO_HASH | ||||
| -	tristate
 | ||||
| +	tristate "HASH"
 | ||||
|  	select CRYPTO_HASH2 | ||||
|  	select CRYPTO_ALGAPI | ||||
|   | ||||
| @@ -100,7 +100,7 @@ config CRYPTO_HASH2
 | ||||
|  	select CRYPTO_ALGAPI2 | ||||
|   | ||||
|  config CRYPTO_RNG | ||||
| -	tristate
 | ||||
| +	tristate "RNG"
 | ||||
|  	select CRYPTO_RNG2 | ||||
|  	select CRYPTO_ALGAPI | ||||
|   | ||||
| --- a/drivers/bcma/Kconfig
 | ||||
| +++ b/drivers/bcma/Kconfig
 | ||||
| @@ -16,6 +16,7 @@ if BCMA
 | ||||
|  # Support for Block-I/O. SELECT this from the driver that needs it. | ||||
|  config BCMA_BLOCKIO | ||||
|  	bool | ||||
| +	default y
 | ||||
|   | ||||
|  config BCMA_HOST_PCI_POSSIBLE | ||||
|  	bool | ||||
| --- a/drivers/ssb/Kconfig
 | ||||
| +++ b/drivers/ssb/Kconfig
 | ||||
| @@ -29,6 +29,7 @@ config SSB_SPROM
 | ||||
|  config SSB_BLOCKIO | ||||
|  	bool | ||||
|  	depends on SSB | ||||
| +	default y
 | ||||
|   | ||||
|  config SSB_PCIHOST_POSSIBLE | ||||
|  	bool | ||||
| @@ -49,7 +50,7 @@ config SSB_PCIHOST
 | ||||
|  config SSB_B43_PCI_BRIDGE | ||||
|  	bool | ||||
|  	depends on SSB_PCIHOST | ||||
| -	default n
 | ||||
| +	default y
 | ||||
|   | ||||
|  config SSB_PCMCIAHOST_POSSIBLE | ||||
|  	bool | ||||
| --- a/lib/Kconfig
 | ||||
| +++ b/lib/Kconfig
 | ||||
| @@ -460,16 +460,16 @@ config BCH_CONST_T
 | ||||
|  # Textsearch support is select'ed if needed | ||||
|  # | ||||
|  config TEXTSEARCH | ||||
| -	bool
 | ||||
| +	bool "Textsearch support"
 | ||||
|   | ||||
|  config TEXTSEARCH_KMP | ||||
| -	tristate
 | ||||
| +	tristate "Textsearch KMP"
 | ||||
|   | ||||
|  config TEXTSEARCH_BM | ||||
| -	tristate
 | ||||
| +	tristate "Textsearch BM"
 | ||||
|   | ||||
|  config TEXTSEARCH_FSM | ||||
| -	tristate
 | ||||
| +	tristate "Textsearch FSM"
 | ||||
|   | ||||
|  config BTREE | ||||
|  	bool | ||||
| --- a/net/netfilter/Kconfig
 | ||||
| +++ b/net/netfilter/Kconfig
 | ||||
| @@ -22,7 +22,7 @@ config NETFILTER_SKIP_EGRESS
 | ||||
|  	def_bool NETFILTER_EGRESS && (NET_CLS_ACT || IFB) | ||||
|   | ||||
|  config NETFILTER_NETLINK | ||||
| -	tristate
 | ||||
| +	tristate "Netfilter NFNETLINK interface"
 | ||||
|   | ||||
|  config NETFILTER_FAMILY_BRIDGE | ||||
|  	bool | ||||
| --- a/sound/core/Kconfig
 | ||||
| +++ b/sound/core/Kconfig
 | ||||
| @@ -17,7 +17,7 @@ config SND_DMAENGINE_PCM
 | ||||
|  	tristate | ||||
|   | ||||
|  config SND_HWDEP | ||||
| -	tristate
 | ||||
| +	tristate "Sound hardware support"
 | ||||
|   | ||||
|  config SND_SEQ_DEVICE | ||||
|  	tristate | ||||
| @@ -40,7 +40,7 @@ config SND_UMP_LEGACY_RAWMIDI
 | ||||
|  	  The device contains 16 substreams corresponding to UMP groups. | ||||
|   | ||||
|  config SND_COMPRESS_OFFLOAD | ||||
| -	tristate
 | ||||
| +	tristate "Compression offloading support"
 | ||||
|   | ||||
|  config SND_JACK | ||||
|  	bool | ||||
| --- a/net/Kconfig
 | ||||
| +++ b/net/Kconfig
 | ||||
| @@ -467,7 +467,7 @@ config NET_DEVLINK
 | ||||
|  	default n | ||||
|   | ||||
|  config PAGE_POOL | ||||
| -	bool
 | ||||
| +	bool "Page pool support"
 | ||||
|   | ||||
|  config PAGE_POOL_STATS | ||||
|  	default n | ||||
							
								
								
									
										32
									
								
								6.10/target/linux/generic/hack-6.10/253-ksmbd-config.patch
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								6.10/target/linux/generic/hack-6.10/253-ksmbd-config.patch
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,32 @@ | |||
| From dcd966fa7ca63f38cf7147e1184d13d66e2ca340 Mon Sep 17 00:00:00 2001 | ||||
| From: OpenWrt community <openwrt-devel@lists.openwrt.org> | ||||
| Date: Wed, 13 Jul 2022 13:33:30 +0200 | ||||
| Subject: [PATCH] Kconfig: add tristate for OID and ASNI string | ||||
| 
 | ||||
| ---
 | ||||
|  init/Kconfig | 2 +- | ||||
|  lib/Kconfig  | 2 +- | ||||
|  2 files changed, 2 insertions(+), 2 deletions(-) | ||||
| 
 | ||||
| --- a/init/Kconfig
 | ||||
| +++ b/init/Kconfig
 | ||||
| @@ -1989,7 +1989,7 @@ config PADATA
 | ||||
|  	bool | ||||
|   | ||||
|  config ASN1 | ||||
| -	tristate
 | ||||
| +	tristate "ASN1"
 | ||||
|  	help | ||||
|  	  Build a simple ASN.1 grammar compiler that produces a bytecode output | ||||
|  	  that can be interpreted by the ASN.1 stream decoder and used to | ||||
| --- a/lib/Kconfig
 | ||||
| +++ b/lib/Kconfig
 | ||||
| @@ -647,7 +647,7 @@ config LIBFDT
 | ||||
|  	bool | ||||
|   | ||||
|  config OID_REGISTRY | ||||
| -	tristate
 | ||||
| +	tristate "OID"
 | ||||
|  	help | ||||
|  	  Enable fast lookup object identifier registry. | ||||
|   | ||||
							
								
								
									
										156
									
								
								6.10/target/linux/generic/hack-6.10/259-regmap_dynamic.patch
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										156
									
								
								6.10/target/linux/generic/hack-6.10/259-regmap_dynamic.patch
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,156 @@ | |||
| From 811d9e2268a62b830cfe93cd8bc929afcb8b198b Mon Sep 17 00:00:00 2001 | ||||
| From: Felix Fietkau <nbd@nbd.name> | ||||
| Date: Sat, 15 Jul 2017 21:12:38 +0200 | ||||
| Subject: kernel: move regmap bloat out of the kernel image if it is only being used in modules | ||||
| 
 | ||||
| lede-commit: 96f39119815028073583e4fca3a9c5fe9141e998 | ||||
| Signed-off-by: Felix Fietkau <nbd@nbd.name> | ||||
| ---
 | ||||
|  drivers/base/regmap/Kconfig  | 15 ++++++++++----- | ||||
|  drivers/base/regmap/Makefile | 12 ++++++++---- | ||||
|  drivers/base/regmap/regmap.c |  3 +++ | ||||
|  include/linux/regmap.h       |  2 +- | ||||
|  4 files changed, 22 insertions(+), 10 deletions(-) | ||||
| 
 | ||||
| --- a/drivers/base/regmap/Kconfig
 | ||||
| +++ b/drivers/base/regmap/Kconfig
 | ||||
| @@ -4,8 +4,7 @@
 | ||||
|  # subsystems should select the appropriate symbols. | ||||
|   | ||||
|  config REGMAP | ||||
| -	bool
 | ||||
| -	default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_W1 || REGMAP_AC97 || REGMAP_MMIO || REGMAP_IRQ || REGMAP_SOUNDWIRE || REGMAP_SOUNDWIRE_MBQ || REGMAP_SCCB || REGMAP_I3C || REGMAP_SPI_AVMM || REGMAP_MDIO || REGMAP_FSI)
 | ||||
| +	tristate
 | ||||
|  	select IRQ_DOMAIN if REGMAP_IRQ | ||||
|  	select MDIO_BUS if REGMAP_MDIO | ||||
|  	help | ||||
| @@ -19,7 +18,7 @@ config REGMAP
 | ||||
|   | ||||
|  config REGMAP_KUNIT | ||||
|  	tristate "KUnit tests for regmap" | ||||
| -	depends on KUNIT && REGMAP
 | ||||
| +	depends on KUNIT
 | ||||
|  	default KUNIT_ALL_TESTS | ||||
|  	select REGMAP_RAM | ||||
|   | ||||
| @@ -34,60 +33,76 @@ config REGMAP_BUILD
 | ||||
|  	  normally enabled. | ||||
|   | ||||
|  config REGMAP_AC97 | ||||
| +	select REGMAP
 | ||||
|  	tristate | ||||
|   | ||||
|  config REGMAP_I2C | ||||
| +	select REGMAP
 | ||||
|  	tristate | ||||
|  	depends on I2C | ||||
|   | ||||
|  config REGMAP_SLIMBUS | ||||
| +	select REGMAP
 | ||||
|  	tristate | ||||
|  	depends on SLIMBUS | ||||
|   | ||||
|  config REGMAP_SPI | ||||
| +	select REGMAP
 | ||||
|  	tristate | ||||
|  	depends on SPI | ||||
|   | ||||
|  config REGMAP_SPMI | ||||
| +	select REGMAP
 | ||||
|  	tristate | ||||
|  	depends on SPMI | ||||
|   | ||||
|  config REGMAP_W1 | ||||
| +	select REGMAP
 | ||||
|  	tristate | ||||
|  	depends on W1 | ||||
|   | ||||
|  config REGMAP_MDIO | ||||
| +	select REGMAP
 | ||||
|  	tristate | ||||
|   | ||||
|  config REGMAP_MMIO | ||||
| +	select REGMAP
 | ||||
|  	tristate | ||||
|   | ||||
|  config REGMAP_IRQ | ||||
| +	select REGMAP
 | ||||
|  	bool | ||||
|   | ||||
|  config REGMAP_RAM | ||||
| +	select REGMAP
 | ||||
|  	tristate | ||||
|   | ||||
|  config REGMAP_SOUNDWIRE | ||||
| +	select REGMAP
 | ||||
|  	tristate | ||||
|  	depends on SOUNDWIRE | ||||
|   | ||||
|  config REGMAP_SOUNDWIRE_MBQ | ||||
| +	select REGMAP
 | ||||
|  	tristate | ||||
|  	depends on SOUNDWIRE | ||||
|   | ||||
|  config REGMAP_SCCB | ||||
| +	select REGMAP
 | ||||
|  	tristate | ||||
|  	depends on I2C | ||||
|   | ||||
|  config REGMAP_I3C | ||||
| +	select REGMAP
 | ||||
|  	tristate | ||||
|  	depends on I3C | ||||
|   | ||||
|  config REGMAP_SPI_AVMM | ||||
| +	select REGMAP
 | ||||
|  	tristate | ||||
|  	depends on SPI | ||||
|   | ||||
|  config REGMAP_FSI | ||||
| +	select REGMAP
 | ||||
|  	tristate | ||||
|  	depends on FSI | ||||
| --- a/drivers/base/regmap/Makefile
 | ||||
| +++ b/drivers/base/regmap/Makefile
 | ||||
| @@ -2,9 +2,11 @@
 | ||||
|  # For include/trace/define_trace.h to include trace.h | ||||
|  CFLAGS_regmap.o := -I$(src) | ||||
|   | ||||
| -obj-$(CONFIG_REGMAP) += regmap.o regcache.o
 | ||||
| -obj-$(CONFIG_REGMAP) += regcache-rbtree.o regcache-flat.o regcache-maple.o
 | ||||
| -obj-$(CONFIG_DEBUG_FS) += regmap-debugfs.o
 | ||||
| +regmap-core-objs = regmap.o regcache.o regcache-rbtree.o regcache-flat.o regcache-maple.o
 | ||||
| +ifdef CONFIG_DEBUG_FS
 | ||||
| +regmap-core-objs += regmap-debugfs.o
 | ||||
| +endif
 | ||||
| +obj-$(CONFIG_REGMAP) += regmap-core.o
 | ||||
|  obj-$(CONFIG_REGMAP_KUNIT) += regmap-kunit.o | ||||
|  obj-$(CONFIG_REGMAP_AC97) += regmap-ac97.o | ||||
|  obj-$(CONFIG_REGMAP_I2C) += regmap-i2c.o | ||||
| --- a/drivers/base/regmap/regmap.c
 | ||||
| +++ b/drivers/base/regmap/regmap.c
 | ||||
| @@ -9,6 +9,7 @@
 | ||||
|  #include <linux/device.h> | ||||
|  #include <linux/slab.h> | ||||
|  #include <linux/export.h> | ||||
| +#include <linux/module.h>
 | ||||
|  #include <linux/mutex.h> | ||||
|  #include <linux/err.h> | ||||
|  #include <linux/property.h> | ||||
| @@ -3470,3 +3471,5 @@ static int __init regmap_initcall(void)
 | ||||
|  	return 0; | ||||
|  } | ||||
|  postcore_initcall(regmap_initcall); | ||||
| +
 | ||||
| +MODULE_LICENSE("GPL");
 | ||||
| --- a/include/linux/regmap.h
 | ||||
| +++ b/include/linux/regmap.h
 | ||||
| @@ -197,7 +197,7 @@ struct reg_sequence {
 | ||||
|  	__ret ?: __tmp; \ | ||||
|  }) | ||||
|   | ||||
| -#ifdef CONFIG_REGMAP
 | ||||
| +#if IS_REACHABLE(CONFIG_REGMAP)
 | ||||
|   | ||||
|  enum regmap_endian { | ||||
|  	/* Unspecified -> 0 -> Backwards compatible default */ | ||||
|  | @ -0,0 +1,54 @@ | |||
| From fd1799b0bf5efa46dd3e6dfbbf3955564807e508 Mon Sep 17 00:00:00 2001 | ||||
| From: Felix Fietkau <nbd@nbd.name> | ||||
| Date: Fri, 7 Jul 2017 17:12:51 +0200 | ||||
| Subject: kernel: prevent cryptomgr from pulling in useless extra dependencies for tests that are not run | ||||
| 
 | ||||
| Reduces kernel size after LZMA by about 5k on MIPS | ||||
| 
 | ||||
| lede-commit: 044c316167e076479a344c59905e5b435b84a77f | ||||
| Signed-off-by: Felix Fietkau <nbd@nbd.name> | ||||
| ---
 | ||||
|  crypto/Kconfig   | 13 ++++++------- | ||||
|  crypto/algboss.c |  4 ++++ | ||||
|  2 files changed, 10 insertions(+), 7 deletions(-) | ||||
| 
 | ||||
| --- a/crypto/Kconfig
 | ||||
| +++ b/crypto/Kconfig
 | ||||
| @@ -148,15 +148,15 @@ config CRYPTO_MANAGER
 | ||||
|  	  cbc(aes). | ||||
|   | ||||
|  config CRYPTO_MANAGER2 | ||||
| -	def_tristate CRYPTO_MANAGER || (CRYPTO_MANAGER!=n && CRYPTO_ALGAPI=y)
 | ||||
| -	select CRYPTO_ACOMP2
 | ||||
| -	select CRYPTO_AEAD2
 | ||||
| -	select CRYPTO_AKCIPHER2
 | ||||
| -	select CRYPTO_SIG2
 | ||||
| -	select CRYPTO_HASH2
 | ||||
| -	select CRYPTO_KPP2
 | ||||
| -	select CRYPTO_RNG2
 | ||||
| -	select CRYPTO_SKCIPHER2
 | ||||
| +	def_tristate CRYPTO_MANAGER || (CRYPTO_MANAGER!=n && CRYPTO_ALGAPI=y && !CRYPTO_MANAGER_DISABLE_TESTS)
 | ||||
| +	select CRYPTO_ACOMP2 if !CRYPTO_MANAGER_DISABLE_TESTS
 | ||||
| +	select CRYPTO_AEAD2 if !CRYPTO_MANAGER_DISABLE_TESTS
 | ||||
| +	select CRYPTO_AKCIPHER2 if !CRYPTO_MANAGER_DISABLE_TESTS
 | ||||
| +	select CRYPTO_SIG2 if !CRYPTO_MANAGER_DISABLE_TESTS
 | ||||
| +	select CRYPTO_HASH2 if !CRYPTO_MANAGER_DISABLE_TESTS
 | ||||
| +	select CRYPTO_KPP2 if !CRYPTO_MANAGER_DISABLE_TESTS
 | ||||
| +	select CRYPTO_RNG2 if !CRYPTO_MANAGER_DISABLE_TESTS
 | ||||
| +	select CRYPTO_SKCIPHER2 if !CRYPTO_MANAGER_DISABLE_TESTS
 | ||||
|   | ||||
|  config CRYPTO_USER | ||||
|  	tristate "Userspace cryptographic algorithm configuration" | ||||
| --- a/crypto/algboss.c
 | ||||
| +++ b/crypto/algboss.c
 | ||||
| @@ -204,6 +204,10 @@ static int cryptomgr_schedule_test(struc
 | ||||
|  	memcpy(param->alg, alg->cra_name, sizeof(param->alg)); | ||||
|  	param->type = alg->cra_flags; | ||||
|   | ||||
| +#ifdef CONFIG_CRYPTO_MANAGER_DISABLE_TESTS
 | ||||
| +	param->type |= CRYPTO_ALG_TESTED;
 | ||||
| +#endif
 | ||||
| +
 | ||||
|  	thread = kthread_run(cryptomgr_test, param, "cryptomgr_test"); | ||||
|  	if (IS_ERR(thread)) | ||||
|  		goto err_free_param; | ||||
|  | @ -0,0 +1,24 @@ | |||
| From 241e5d3f7b0dd3c01f8c7fa83cbc9a3882286d53 Mon Sep 17 00:00:00 2001 | ||||
| From: OpenWrt community <openwrt-devel@lists.openwrt.org> | ||||
| Date: Wed, 13 Jul 2022 13:35:18 +0200 | ||||
| Subject: [PATCH] lib/crypto: add tristate string for ARC4 | ||||
| 
 | ||||
| This makes it possible to select CONFIG_CRYPTO_LIB_ARC4 directly. We  | ||||
| need this to be able to compile this into the kernel and make use of it  | ||||
| from backports. | ||||
| 
 | ||||
| ---
 | ||||
|  lib/crypto/Kconfig | 2 +- | ||||
|  1 file changed, 1 insertion(+), 1 deletion(-) | ||||
| 
 | ||||
| --- a/lib/crypto/Kconfig
 | ||||
| +++ b/lib/crypto/Kconfig
 | ||||
| @@ -15,7 +15,7 @@ config CRYPTO_LIB_AESGCM
 | ||||
|  	select CRYPTO_LIB_UTILS | ||||
|   | ||||
|  config CRYPTO_LIB_ARC4 | ||||
| -	tristate
 | ||||
| +	tristate "ARC4 cipher library"
 | ||||
|   | ||||
|  config CRYPTO_LIB_GF128MUL | ||||
|  	tristate | ||||
							
								
								
									
										84
									
								
								6.10/target/linux/generic/hack-6.10/280-rfkill-stubs.patch
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								6.10/target/linux/generic/hack-6.10/280-rfkill-stubs.patch
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,84 @@ | |||
| From 236c1acdfef5958010ac9814a9872e0a46fd78ee Mon Sep 17 00:00:00 2001 | ||||
| From: John Crispin <john@phrozen.org> | ||||
| Date: Fri, 7 Jul 2017 17:13:44 +0200 | ||||
| Subject: rfkill: add fake rfkill support | ||||
| 
 | ||||
| allow building of modules depending on RFKILL even if RFKILL is not enabled. | ||||
| 
 | ||||
| Signed-off-by: John Crispin <john@phrozen.org> | ||||
| ---
 | ||||
|  include/linux/rfkill.h |  2 +- | ||||
|  net/Makefile           |  2 +- | ||||
|  net/rfkill/Kconfig     | 14 +++++++++----- | ||||
|  net/rfkill/Makefile    |  2 +- | ||||
|  4 files changed, 12 insertions(+), 8 deletions(-) | ||||
| 
 | ||||
| --- a/include/linux/rfkill.h
 | ||||
| +++ b/include/linux/rfkill.h
 | ||||
| @@ -64,7 +64,7 @@ struct rfkill_ops {
 | ||||
|  	int	(*set_block)(void *data, bool blocked); | ||||
|  }; | ||||
|   | ||||
| -#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
 | ||||
| +#if defined(CONFIG_RFKILL_FULL) || defined(CONFIG_RFKILL_FULL_MODULE)
 | ||||
|  /** | ||||
|   * rfkill_alloc - Allocate rfkill structure | ||||
|   * @name: name of the struct -- the string is not copied internally | ||||
| --- a/net/Makefile
 | ||||
| +++ b/net/Makefile
 | ||||
| @@ -52,7 +52,7 @@ obj-$(CONFIG_TIPC)		+= tipc/
 | ||||
|  obj-$(CONFIG_NETLABEL)		+= netlabel/ | ||||
|  obj-$(CONFIG_IUCV)		+= iucv/ | ||||
|  obj-$(CONFIG_SMC)		+= smc/ | ||||
| -obj-$(CONFIG_RFKILL)		+= rfkill/
 | ||||
| +obj-$(CONFIG_RFKILL_FULL)	+= rfkill/
 | ||||
|  obj-$(CONFIG_NET_9P)		+= 9p/ | ||||
|  obj-$(CONFIG_CAIF)		+= caif/ | ||||
|  obj-$(CONFIG_DCB)		+= dcb/ | ||||
| --- a/net/rfkill/Kconfig
 | ||||
| +++ b/net/rfkill/Kconfig
 | ||||
| @@ -2,7 +2,11 @@
 | ||||
|  # | ||||
|  # RF switch subsystem configuration | ||||
|  # | ||||
| -menuconfig RFKILL
 | ||||
| +config RFKILL
 | ||||
| +	bool
 | ||||
| +	default y
 | ||||
| +
 | ||||
| +menuconfig RFKILL_FULL
 | ||||
|  	tristate "RF switch subsystem support" | ||||
|  	help | ||||
|  	  Say Y here if you want to have control over RF switches | ||||
| @@ -14,19 +18,19 @@ menuconfig RFKILL
 | ||||
|  # LED trigger support | ||||
|  config RFKILL_LEDS | ||||
|  	bool | ||||
| -	depends on RFKILL
 | ||||
| +	depends on RFKILL_FULL
 | ||||
|  	depends on LEDS_TRIGGERS = y || RFKILL = LEDS_TRIGGERS | ||||
|  	default y | ||||
|   | ||||
|  config RFKILL_INPUT | ||||
|  	bool "RF switch input support" if EXPERT | ||||
| -	depends on RFKILL
 | ||||
| +	depends on RFKILL_FULL
 | ||||
|  	depends on INPUT = y || RFKILL = INPUT | ||||
|  	default y if !EXPERT | ||||
|   | ||||
|  config RFKILL_GPIO | ||||
|  	tristate "GPIO RFKILL driver" | ||||
| -	depends on RFKILL
 | ||||
| +	depends on RFKILL_FULL
 | ||||
|  	depends on GPIOLIB || COMPILE_TEST | ||||
|  	default n | ||||
|  	help | ||||
| --- a/net/rfkill/Makefile
 | ||||
| +++ b/net/rfkill/Makefile
 | ||||
| @@ -5,5 +5,5 @@
 | ||||
|   | ||||
|  rfkill-y			+= core.o | ||||
|  rfkill-$(CONFIG_RFKILL_INPUT)	+= input.o | ||||
| -obj-$(CONFIG_RFKILL)		+= rfkill.o
 | ||||
| +obj-$(CONFIG_RFKILL_FULL)	+= rfkill.o
 | ||||
|  obj-$(CONFIG_RFKILL_GPIO)	+= rfkill-gpio.o | ||||
|  | @ -0,0 +1,64 @@ | |||
| From: Ben Menchaca <ben.menchaca@qca.qualcomm.com> | ||||
| Date: Fri, 7 Jun 2013 18:35:22 -0500 | ||||
| Subject: MIPS: r4k_cache: use more efficient cache blast | ||||
| 
 | ||||
| Optimize the compiler output for larger cache blast cases that are | ||||
| common for DMA-based networking. | ||||
| 
 | ||||
| Signed-off-by: Ben Menchaca <ben.menchaca@qca.qualcomm.com> | ||||
| Signed-off-by: Felix Fietkau <nbd@nbd.name> | ||||
| ---
 | ||||
| --- a/arch/mips/include/asm/r4kcache.h
 | ||||
| +++ b/arch/mips/include/asm/r4kcache.h
 | ||||
| @@ -286,14 +286,46 @@ static inline void prot##extra##blast_##
 | ||||
|  						    unsigned long end)	\ | ||||
|  {									\ | ||||
|  	unsigned long lsize = cpu_##desc##_line_size();			\ | ||||
| +	unsigned long lsize_2 = lsize * 2;				\
 | ||||
| +	unsigned long lsize_3 = lsize * 3;				\
 | ||||
| +	unsigned long lsize_4 = lsize * 4;				\
 | ||||
| +	unsigned long lsize_5 = lsize * 5;				\
 | ||||
| +	unsigned long lsize_6 = lsize * 6;				\
 | ||||
| +	unsigned long lsize_7 = lsize * 7;				\
 | ||||
| +	unsigned long lsize_8 = lsize * 8;				\
 | ||||
|  	unsigned long addr = start & ~(lsize - 1);			\ | ||||
| -	unsigned long aend = (end - 1) & ~(lsize - 1);			\
 | ||||
| +	unsigned long aend = (end + lsize - 1) & ~(lsize - 1);		\
 | ||||
| +	int lines = (aend - addr) / lsize;				\
 | ||||
|  									\ | ||||
| -	while (1) {							\
 | ||||
| +	while (lines >= 8) {						\
 | ||||
| +		prot##cache_op(hitop, addr);				\
 | ||||
| +		prot##cache_op(hitop, addr + lsize);			\
 | ||||
| +		prot##cache_op(hitop, addr + lsize_2);			\
 | ||||
| +		prot##cache_op(hitop, addr + lsize_3);			\
 | ||||
| +		prot##cache_op(hitop, addr + lsize_4);			\
 | ||||
| +		prot##cache_op(hitop, addr + lsize_5);			\
 | ||||
| +		prot##cache_op(hitop, addr + lsize_6);			\
 | ||||
| +		prot##cache_op(hitop, addr + lsize_7);			\
 | ||||
| +		addr += lsize_8;					\
 | ||||
| +		lines -= 8;						\
 | ||||
| +	}								\
 | ||||
| +									\
 | ||||
| +	if (lines & 0x4) {						\
 | ||||
| +		prot##cache_op(hitop, addr);				\
 | ||||
| +		prot##cache_op(hitop, addr + lsize);			\
 | ||||
| +		prot##cache_op(hitop, addr + lsize_2);			\
 | ||||
| +		prot##cache_op(hitop, addr + lsize_3);			\
 | ||||
| +		addr += lsize_4;					\
 | ||||
| +	}								\
 | ||||
| +									\
 | ||||
| +	if (lines & 0x2) {						\
 | ||||
| +		prot##cache_op(hitop, addr);				\
 | ||||
| +		prot##cache_op(hitop, addr + lsize);			\
 | ||||
| +		addr += lsize_2;					\
 | ||||
| +	}								\
 | ||||
| +									\
 | ||||
| +	if (lines & 0x1) {						\
 | ||||
|  		prot##cache_op(hitop, addr);				\ | ||||
| -		if (addr == aend)					\
 | ||||
| -			break;						\
 | ||||
| -		addr += lsize;						\
 | ||||
|  	}								\ | ||||
|  } | ||||
|   | ||||
|  | @ -0,0 +1,112 @@ | |||
| From 0bccc3722bdd88e8ae995e77ef9f7b77ee4cbdee Mon Sep 17 00:00:00 2001 | ||||
| From: Daniel Golle <daniel@makrotopia.org> | ||||
| Date: Wed, 7 Apr 2021 22:45:54 +0100 | ||||
| Subject: [PATCH 2/2] mtd: blktrans: call add disks after mtd device | ||||
| To: linux-mtd@lists.infradead.org | ||||
| Cc: Vignesh Raghavendra <vigneshr@ti.com>, | ||||
|     Richard Weinberger <richard@nod.at>, | ||||
|     Miquel Raynal <miquel.raynal@bootlin.com>, | ||||
|     David Woodhouse <dwmw2@infradead.org> | ||||
| 
 | ||||
| Calling device_add_disk while holding mtd_table_mutex leads | ||||
| to deadlock in case part_bits!=0 as block partition parsers | ||||
| will try to open the newly created disks, trying to acquire | ||||
| mutex once again. | ||||
| Move device_add_disk to additional function called after | ||||
| add partitions of an MTD device have been added and locks | ||||
| have been released. | ||||
| 
 | ||||
| Signed-off-by: Daniel Golle <daniel@makrotopia.org> | ||||
| ---
 | ||||
|  drivers/mtd/mtd_blkdevs.c    | 33 ++++++++++++++++++++++++++------- | ||||
|  drivers/mtd/mtdcore.c        |  3 +++ | ||||
|  include/linux/mtd/blktrans.h |  1 + | ||||
|  3 files changed, 30 insertions(+), 7 deletions(-) | ||||
| 
 | ||||
| --- a/drivers/mtd/mtd_blkdevs.c
 | ||||
| +++ b/drivers/mtd/mtd_blkdevs.c
 | ||||
| @@ -386,19 +386,8 @@ int add_mtd_blktrans_dev(struct mtd_blkt
 | ||||
|  	if (new->readonly) | ||||
|  		set_disk_ro(gd, 1); | ||||
|   | ||||
| -	ret = device_add_disk(&new->mtd->dev, gd, NULL);
 | ||||
| -	if (ret)
 | ||||
| -		goto out_cleanup_disk;
 | ||||
| -
 | ||||
| -	if (new->disk_attributes) {
 | ||||
| -		ret = sysfs_create_group(&disk_to_dev(gd)->kobj,
 | ||||
| -					new->disk_attributes);
 | ||||
| -		WARN_ON(ret);
 | ||||
| -	}
 | ||||
|  	return 0; | ||||
|   | ||||
| -out_cleanup_disk:
 | ||||
| -	put_disk(new->disk);
 | ||||
|  out_free_tag_set: | ||||
|  	blk_mq_free_tag_set(new->tag_set); | ||||
|  out_kfree_tag_set: | ||||
| @@ -408,6 +397,35 @@ out_list_del:
 | ||||
|  	return ret; | ||||
|  } | ||||
|   | ||||
| +void register_mtd_blktrans_devs(void)
 | ||||
| +{
 | ||||
| +	struct mtd_blktrans_ops *tr;
 | ||||
| +	struct mtd_blktrans_dev *dev, *next;
 | ||||
| +	int ret;
 | ||||
| +
 | ||||
| +	list_for_each_entry(tr, &blktrans_majors, list) {
 | ||||
| +		list_for_each_entry_safe(dev, next, &tr->devs, list) {
 | ||||
| +			if (disk_live(dev->disk))
 | ||||
| +				continue;
 | ||||
| +
 | ||||
| +			ret = device_add_disk(&dev->mtd->dev, dev->disk, NULL);
 | ||||
| +			if (ret)
 | ||||
| +				goto out_cleanup_disk;
 | ||||
| +
 | ||||
| +			if (dev->disk_attributes) {
 | ||||
| +				ret = sysfs_create_group(&disk_to_dev(dev->disk)->kobj,
 | ||||
| +							dev->disk_attributes);
 | ||||
| +				WARN_ON(ret);
 | ||||
| +			}
 | ||||
| +		}
 | ||||
| +	}
 | ||||
| +
 | ||||
| +	return;
 | ||||
| +
 | ||||
| +out_cleanup_disk:
 | ||||
| +	put_disk(dev->disk);
 | ||||
| +}
 | ||||
| +
 | ||||
|  int del_mtd_blktrans_dev(struct mtd_blktrans_dev *old) | ||||
|  { | ||||
|  	unsigned long flags; | ||||
| --- a/drivers/mtd/mtdcore.c
 | ||||
| +++ b/drivers/mtd/mtdcore.c
 | ||||
| @@ -33,6 +33,7 @@
 | ||||
|   | ||||
|  #include <linux/mtd/mtd.h> | ||||
|  #include <linux/mtd/partitions.h> | ||||
| +#include <linux/mtd/blktrans.h>
 | ||||
|   | ||||
|  #include "mtdcore.h" | ||||
|   | ||||
| @@ -1127,6 +1128,8 @@ int mtd_device_parse_register(struct mtd
 | ||||
|  		register_reboot_notifier(&mtd->reboot_notifier); | ||||
|  	} | ||||
|   | ||||
| +	register_mtd_blktrans_devs();
 | ||||
| +
 | ||||
|  out: | ||||
|  	if (ret) { | ||||
|  		nvmem_unregister(mtd->otp_user_nvmem); | ||||
| --- a/include/linux/mtd/blktrans.h
 | ||||
| +++ b/include/linux/mtd/blktrans.h
 | ||||
| @@ -76,6 +76,7 @@ extern int deregister_mtd_blktrans(struc
 | ||||
|  extern int add_mtd_blktrans_dev(struct mtd_blktrans_dev *dev); | ||||
|  extern int del_mtd_blktrans_dev(struct mtd_blktrans_dev *dev); | ||||
|  extern int mtd_blktrans_cease_background(struct mtd_blktrans_dev *dev); | ||||
| +extern void register_mtd_blktrans_devs(void);
 | ||||
|   | ||||
|  /** | ||||
|   * module_mtd_blktrans() - Helper macro for registering a mtd blktrans driver | ||||
|  | @ -0,0 +1,24 @@ | |||
| From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl> | ||||
| Date: Mon, 7 Nov 2022 23:48:24 +0100 | ||||
| Subject: [PATCH] mtd: support OpenWrt's MTD_ROOTFS_ROOT_DEV | ||||
| MIME-Version: 1.0 | ||||
| Content-Type: text/plain; charset=UTF-8 | ||||
| Content-Transfer-Encoding: 8bit | ||||
| 
 | ||||
| This allows setting ROOT_DEV to MTD partition named "rootfs". | ||||
| 
 | ||||
| Signed-off-by: Rafał Miłecki <rafal@milecki.pl> | ||||
| ---
 | ||||
| 
 | ||||
| --- a/drivers/mtd/mtdcore.c
 | ||||
| +++ b/drivers/mtd/mtdcore.c
 | ||||
| @@ -801,7 +801,8 @@ int add_mtd_device(struct mtd_info *mtd)
 | ||||
|   | ||||
|  	mutex_unlock(&mtd_table_mutex); | ||||
|   | ||||
| -	if (of_property_read_bool(mtd_get_of_node(mtd), "linux,rootfs")) {
 | ||||
| +	if (of_property_read_bool(mtd_get_of_node(mtd), "linux,rootfs") ||
 | ||||
| +	    (IS_ENABLED(CONFIG_MTD_ROOTFS_ROOT_DEV) && !strcmp(mtd->name, "rootfs") && ROOT_DEV == 0)) {
 | ||||
|  		if (IS_BUILTIN(CONFIG_MTD)) { | ||||
|  			pr_info("mtd: setting mtd%d (%s) as root device\n", mtd->index, mtd->name); | ||||
|  			ROOT_DEV = MKDEV(MTD_BLOCK_MAJOR, mtd->index); | ||||
|  | @ -0,0 +1,120 @@ | |||
| From 6fa9e3678eb002246df1280322b6a024853950a5 Mon Sep 17 00:00:00 2001 | ||||
| From: Ansuel Smith <ansuelsmth@gmail.com> | ||||
| Date: Mon, 11 Oct 2021 00:53:14 +0200 | ||||
| Subject: [PATCH] drivers: mtd: parsers: add nvmem support to cmdlinepart | ||||
| 
 | ||||
| Assuming cmdlinepart is only one level deep partition scheme and that | ||||
| static partition are also defined in DTS, we can assign an of_node for | ||||
| partition declared from bootargs. cmdlinepart have priority than | ||||
| fiexed-partition parser so in this specific case the parser doesn't | ||||
| assign an of_node. Fix this by searching a defined of_node using a | ||||
| similar fixed_partition parser and if a partition is found with the same | ||||
| label, check that it has the same offset and size and return the DT | ||||
| of_node to correctly use NVMEM cells. | ||||
| 
 | ||||
| Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com> | ||||
| ---
 | ||||
|  drivers/mtd/parsers/cmdlinepart.c | 71 +++++++++++++++++++++++++++++++ | ||||
|  1 file changed, 71 insertions(+) | ||||
| 
 | ||||
| --- a/drivers/mtd/parsers/cmdlinepart.c
 | ||||
| +++ b/drivers/mtd/parsers/cmdlinepart.c
 | ||||
| @@ -43,6 +43,7 @@
 | ||||
|  #include <linux/mtd/partitions.h> | ||||
|  #include <linux/module.h> | ||||
|  #include <linux/err.h> | ||||
| +#include <linux/of.h>
 | ||||
|   | ||||
|  /* debug macro */ | ||||
|  #if 0 | ||||
| @@ -323,6 +324,68 @@ static int mtdpart_setup_real(char *s)
 | ||||
|  	return 0; | ||||
|  } | ||||
|   | ||||
| +static int search_fixed_partition(struct mtd_info *master,
 | ||||
| +				  struct mtd_partition *target_part,
 | ||||
| +				  struct mtd_partition *fixed_part)
 | ||||
| +{
 | ||||
| +	struct device_node *mtd_node;
 | ||||
| +	struct device_node *ofpart_node;
 | ||||
| +	struct device_node *pp;
 | ||||
| +	struct mtd_partition part;
 | ||||
| +	const char *partname;
 | ||||
| +
 | ||||
| +	mtd_node = mtd_get_of_node(master);
 | ||||
| +	if (!mtd_node)
 | ||||
| +		return -EINVAL;
 | ||||
| +
 | ||||
| +	ofpart_node = of_get_child_by_name(mtd_node, "partitions");
 | ||||
| +
 | ||||
| +	for_each_child_of_node(ofpart_node,  pp) {
 | ||||
| +		const __be32 *reg;
 | ||||
| +		int len;
 | ||||
| +		int a_cells, s_cells;
 | ||||
| +
 | ||||
| +		reg = of_get_property(pp, "reg", &len);
 | ||||
| +		if (!reg) {
 | ||||
| +			pr_debug("%s: ofpart partition %pOF (%pOF) missing reg property.\n",
 | ||||
| +				 master->name, pp,
 | ||||
| +				 mtd_node);
 | ||||
| +			continue;
 | ||||
| +		}
 | ||||
| +
 | ||||
| +		a_cells = of_n_addr_cells(pp);
 | ||||
| +		s_cells = of_n_size_cells(pp);
 | ||||
| +		if (len / 4 != a_cells + s_cells) {
 | ||||
| +			pr_debug("%s: ofpart partition %pOF (%pOF) error parsing reg property.\n",
 | ||||
| +				 master->name, pp,
 | ||||
| +				 mtd_node);
 | ||||
| +			continue;
 | ||||
| +		}
 | ||||
| +
 | ||||
| +		part.offset = of_read_number(reg, a_cells);
 | ||||
| +		part.size = of_read_number(reg + a_cells, s_cells);
 | ||||
| +		part.of_node = pp;
 | ||||
| +
 | ||||
| +		partname = of_get_property(pp, "label", &len);
 | ||||
| +		if (!partname)
 | ||||
| +			partname = of_get_property(pp, "name", &len);
 | ||||
| +		part.name = partname;
 | ||||
| +
 | ||||
| +		if (!strncmp(target_part->name, part.name, len)) {
 | ||||
| +			if (part.offset != target_part->offset)
 | ||||
| +				return -EINVAL;
 | ||||
| +
 | ||||
| +			if (part.size != target_part->size)
 | ||||
| +				return -EINVAL;
 | ||||
| +
 | ||||
| +			memcpy(fixed_part, &part, sizeof(struct mtd_partition));
 | ||||
| +			return 0;
 | ||||
| +		}
 | ||||
| +	}
 | ||||
| +
 | ||||
| +	return -EINVAL;
 | ||||
| +}
 | ||||
| +
 | ||||
|  /* | ||||
|   * Main function to be called from the MTD mapping driver/device to | ||||
|   * obtain the partitioning information. At this point the command line | ||||
| @@ -338,6 +401,7 @@ static int parse_cmdline_partitions(stru
 | ||||
|  	int i, err; | ||||
|  	struct cmdline_mtd_partition *part; | ||||
|  	const char *mtd_id = master->name; | ||||
| +	struct mtd_partition fixed_part;
 | ||||
|   | ||||
|  	/* parse command line */ | ||||
|  	if (!cmdline_parsed) { | ||||
| @@ -382,6 +446,13 @@ static int parse_cmdline_partitions(stru
 | ||||
|  				sizeof(*part->parts) * (part->num_parts - i)); | ||||
|  			i--; | ||||
|  		} | ||||
| +
 | ||||
| +		err = search_fixed_partition(master, &part->parts[i], &fixed_part);
 | ||||
| +		if (!err) {
 | ||||
| +			part->parts[i].of_node = fixed_part.of_node;
 | ||||
| +			pr_info("Found partition defined in DT for %s. Assigning OF node to support nvmem.",
 | ||||
| +				part->parts[i].name);
 | ||||
| +		}
 | ||||
|  	} | ||||
|   | ||||
|  	*pparts = kmemdup(part->parts, sizeof(*part->parts) * part->num_parts, | ||||
|  | @ -0,0 +1,33 @@ | |||
| From ac84397efb3b3868c71c10ad7521161773228a17 Mon Sep 17 00:00:00 2001 | ||||
| From: OpenWrt community <openwrt-devel@lists.openwrt.org> | ||||
| Date: Wed, 13 Jul 2022 13:41:44 +0200 | ||||
| Subject: [PATCH] mtd/nand: add MediaTek NAND bad block managment table | ||||
| 
 | ||||
| ---
 | ||||
|  drivers/mtd/nand/Kconfig  | 4 ++++ | ||||
|  drivers/mtd/nand/Makefile | 1 + | ||||
|  2 files changed, 5 insertions(+) | ||||
| 
 | ||||
| --- a/drivers/mtd/nand/Kconfig
 | ||||
| +++ b/drivers/mtd/nand/Kconfig
 | ||||
| @@ -46,6 +46,10 @@ config MTD_NAND_ECC_SW_BCH
 | ||||
|  	  ECC codes. They are used with NAND devices requiring more than 1 bit | ||||
|  	  of error correction. | ||||
|   | ||||
| +config MTD_NAND_MTK_BMT
 | ||||
| +	bool "Support MediaTek NAND Bad-block Management Table"
 | ||||
| +	default n
 | ||||
| +
 | ||||
|  config MTD_NAND_ECC_MXIC | ||||
|  	bool "Macronix external hardware ECC engine" | ||||
|  	depends on HAS_IOMEM | ||||
| --- a/drivers/mtd/nand/Makefile
 | ||||
| +++ b/drivers/mtd/nand/Makefile
 | ||||
| @@ -3,6 +3,7 @@
 | ||||
|  nandcore-objs := core.o bbt.o | ||||
|  obj-$(CONFIG_MTD_NAND_CORE) += nandcore.o | ||||
|  obj-$(CONFIG_MTD_NAND_ECC_MEDIATEK) += ecc-mtk.o | ||||
| +obj-$(CONFIG_MTD_NAND_MTK_BMT)	+= mtk_bmt.o mtk_bmt_v2.o mtk_bmt_bbt.o mtk_bmt_nmbm.o
 | ||||
|   | ||||
|  obj-y	+= onenand/ | ||||
|  obj-y	+= raw/ | ||||
|  | @ -0,0 +1,24 @@ | |||
| From: Felix Fietkau <nbd@nbd.name> | ||||
| Date: Tue, 23 Apr 2024 12:35:21 +0200 | ||||
| Subject: [PATCH] net: enable fraglist GRO by default | ||||
| 
 | ||||
| This can significantly improve performance for packet forwarding/bridging | ||||
| 
 | ||||
| Signed-off-by: Felix Fietkau <nbd@nbd.name> | ||||
| ---
 | ||||
| 
 | ||||
| --- a/include/linux/netdev_features.h
 | ||||
| +++ b/include/linux/netdev_features.h
 | ||||
| @@ -242,10 +242,10 @@ static inline int find_next_netdev_featu
 | ||||
|  #define NETIF_F_UPPER_DISABLES	NETIF_F_LRO | ||||
|   | ||||
|  /* changeable features with no special hardware requirements */ | ||||
| -#define NETIF_F_SOFT_FEATURES	(NETIF_F_GSO | NETIF_F_GRO)
 | ||||
| +#define NETIF_F_SOFT_FEATURES	(NETIF_F_GSO | NETIF_F_GRO | NETIF_F_GRO_FRAGLIST)
 | ||||
|   | ||||
|  /* Changeable features with no special hardware requirements that defaults to off. */ | ||||
| -#define NETIF_F_SOFT_FEATURES_OFF	(NETIF_F_GRO_FRAGLIST | NETIF_F_GRO_UDP_FWD)
 | ||||
| +#define NETIF_F_SOFT_FEATURES_OFF	(NETIF_F_GRO_UDP_FWD)
 | ||||
|   | ||||
|  #define NETIF_F_VLAN_FEATURES	(NETIF_F_HW_VLAN_CTAG_FILTER | \ | ||||
|  				 NETIF_F_HW_VLAN_CTAG_RX | \ | ||||
|  | @ -0,0 +1,214 @@ | |||
| From eda40b8c8c82e0f2789d6bc8bf63846dce2e8f32 Mon Sep 17 00:00:00 2001 | ||||
| From: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk> | ||||
| Date: Sat, 23 Mar 2019 09:29:49 +0000 | ||||
| Subject: [PATCH] netfilter: connmark: introduce set-dscpmark | ||||
| 
 | ||||
| set-dscpmark is a method of storing the DSCP of an ip packet into | ||||
| conntrack mark.  In combination with a suitable tc filter action | ||||
| (act_ctinfo) DSCP values are able to be stored in the mark on egress and | ||||
| restored on ingress across links that otherwise alter or bleach DSCP. | ||||
| 
 | ||||
| This is useful for qdiscs such as CAKE which are able to shape according | ||||
| to policies based on DSCP. | ||||
| 
 | ||||
| Ingress classification is traditionally a challenging task since | ||||
| iptables rules haven't yet run and tc filter/eBPF programs are pre-NAT | ||||
| lookups, hence are unable to see internal IPv4 addresses as used on the | ||||
| typical home masquerading gateway. | ||||
| 
 | ||||
| x_tables CONNMARK set-dscpmark target solves the problem of storing the | ||||
| DSCP to the conntrack mark in a way suitable for the new act_ctinfo tc | ||||
| action to restore. | ||||
| 
 | ||||
| The set-dscpmark option accepts 2 parameters, a 32bit 'dscpmask' and a | ||||
| 32bit 'statemask'.  The dscp mask must be 6 contiguous bits and | ||||
| represents the area where the DSCP will be stored in the connmark.  The | ||||
| state mask is a minimum 1 bit length mask that must not overlap with the | ||||
| dscpmask.  It represents a flag which is set when the DSCP has been | ||||
| stored in the conntrack mark. This is useful to implement a 'one shot' | ||||
| iptables based classification where the 'complicated' iptables rules are | ||||
| only run once to classify the connection on initial (egress) packet and | ||||
| subsequent packets are all marked/restored with the same DSCP.  A state | ||||
| mask of zero disables the setting of a status bit/s. | ||||
| 
 | ||||
| example syntax with a suitably modified iptables user space application: | ||||
| 
 | ||||
| iptables -A QOS_MARK_eth0 -t mangle -j CONNMARK --set-dscpmark 0xfc000000/0x01000000 | ||||
| 
 | ||||
| Would store the DSCP in the top 6 bits of the 32bit mark field, and use | ||||
| the LSB of the top byte as the 'DSCP has been stored' marker. | ||||
| 
 | ||||
| |----0xFC----conntrack mark----000000---| | ||||
| | Bits 31-26 | bit 25 | bit24 |~~~ Bit 0| | ||||
| | DSCP       | unused | flag  |unused   | | ||||
| |-----------------------0x01---000000---| | ||||
|       ^                   ^ | ||||
|       |                   | | ||||
|       ---|             Conditional flag | ||||
|          |             set this when dscp | ||||
| |-ip diffserv-|        stored in mark | ||||
| | 6 bits      | | ||||
| |-------------| | ||||
| 
 | ||||
| an identically configured tc action to restore looks like: | ||||
| 
 | ||||
| tc filter show dev eth0 ingress | ||||
| filter parent ffff: protocol all pref 10 u32 chain 0 | ||||
| filter parent ffff: protocol all pref 10 u32 chain 0 fh 800: ht divisor 1 | ||||
| filter parent ffff: protocol all pref 10 u32 chain 0 fh 800::800 order 2048 key ht 800 bkt 0 flowid 1: not_in_hw | ||||
|   match 00000000/00000000 at 0 | ||||
| 	action order 1: ctinfo zone 0 pipe | ||||
| 	 index 2 ref 1 bind 1 dscp 0xfc000000/0x1000000 | ||||
| 
 | ||||
| 	action order 2: mirred (Egress Redirect to device ifb4eth0) stolen | ||||
| 	index 1 ref 1 bind 1 | ||||
| 
 | ||||
| |----0xFC----conntrack mark----000000---| | ||||
| | Bits 31-26 | bit 25 | bit24 |~~~ Bit 0| | ||||
| | DSCP       | unused | flag  |unused   | | ||||
| |-----------------------0x01---000000---| | ||||
|       |                   | | ||||
|       |                   | | ||||
|       ---|             Conditional flag | ||||
|          v             only restore if set | ||||
| |-ip diffserv-| | ||||
| | 6 bits      | | ||||
| |-------------| | ||||
| 
 | ||||
| Signed-off-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk> | ||||
| ---
 | ||||
|  include/uapi/linux/netfilter/xt_connmark.h | 10 ++++ | ||||
|  net/netfilter/xt_connmark.c                | 55 ++++++++++++++++++---- | ||||
|  2 files changed, 57 insertions(+), 8 deletions(-) | ||||
| 
 | ||||
| --- a/include/uapi/linux/netfilter/xt_connmark.h
 | ||||
| +++ b/include/uapi/linux/netfilter/xt_connmark.h
 | ||||
| @@ -15,6 +15,11 @@ enum {
 | ||||
|  }; | ||||
|   | ||||
|  enum { | ||||
| +	XT_CONNMARK_VALUE =	(1 << 0),
 | ||||
| +	XT_CONNMARK_DSCP = 	(1 << 1)
 | ||||
| +};
 | ||||
| +
 | ||||
| +enum {
 | ||||
|  	D_SHIFT_LEFT = 0, | ||||
|  	D_SHIFT_RIGHT, | ||||
|  }; | ||||
| @@ -29,6 +34,11 @@ struct xt_connmark_tginfo2 {
 | ||||
|  	__u8 shift_dir, shift_bits, mode; | ||||
|  }; | ||||
|   | ||||
| +struct xt_connmark_tginfo3 {
 | ||||
| +	__u32 ctmark, ctmask, nfmask;
 | ||||
| +	__u8 shift_dir, shift_bits, mode, func;
 | ||||
| +};
 | ||||
| +
 | ||||
|  struct xt_connmark_mtinfo1 { | ||||
|  	__u32 mark, mask; | ||||
|  	__u8 invert; | ||||
| --- a/net/netfilter/xt_connmark.c
 | ||||
| +++ b/net/netfilter/xt_connmark.c
 | ||||
| @@ -24,13 +24,13 @@ MODULE_ALIAS("ipt_connmark");
 | ||||
|  MODULE_ALIAS("ip6t_connmark"); | ||||
|   | ||||
|  static unsigned int | ||||
| -connmark_tg_shift(struct sk_buff *skb, const struct xt_connmark_tginfo2 *info)
 | ||||
| +connmark_tg_shift(struct sk_buff *skb, const struct xt_connmark_tginfo3 *info)
 | ||||
|  { | ||||
|  	enum ip_conntrack_info ctinfo; | ||||
|  	u_int32_t new_targetmark; | ||||
|  	struct nf_conn *ct; | ||||
|  	u_int32_t newmark; | ||||
| -	u_int32_t oldmark;
 | ||||
| +	u_int8_t dscp;
 | ||||
|   | ||||
|  	ct = nf_ct_get(skb, &ctinfo); | ||||
|  	if (ct == NULL) | ||||
| @@ -38,13 +38,24 @@ connmark_tg_shift(struct sk_buff *skb, c
 | ||||
|   | ||||
|  	switch (info->mode) { | ||||
|  	case XT_CONNMARK_SET: | ||||
| -		oldmark = READ_ONCE(ct->mark);
 | ||||
| -		newmark = (oldmark & ~info->ctmask) ^ info->ctmark;
 | ||||
| -		if (info->shift_dir == D_SHIFT_RIGHT)
 | ||||
| -			newmark >>= info->shift_bits;
 | ||||
| -		else
 | ||||
| -			newmark <<= info->shift_bits;
 | ||||
| +		newmark = READ_ONCE(ct->mark);
 | ||||
| +		if (info->func & XT_CONNMARK_VALUE) {
 | ||||
| +			newmark = (newmark & ~info->ctmask) ^ info->ctmark;
 | ||||
| +			if (info->shift_dir == D_SHIFT_RIGHT)
 | ||||
| +				newmark >>= info->shift_bits;
 | ||||
| +			else
 | ||||
| +				newmark <<= info->shift_bits;
 | ||||
| +		} else if (info->func & XT_CONNMARK_DSCP) {
 | ||||
| +			if (skb->protocol == htons(ETH_P_IP))
 | ||||
| +				dscp = ipv4_get_dsfield(ip_hdr(skb)) >> 2;
 | ||||
| +			else if (skb->protocol == htons(ETH_P_IPV6))
 | ||||
| +				dscp = ipv6_get_dsfield(ipv6_hdr(skb)) >> 2;
 | ||||
| +			else	/* protocol doesn't have diffserv */
 | ||||
| +				break;
 | ||||
|   | ||||
| +			newmark = (newmark & ~info->ctmark) |
 | ||||
| +				  (info->ctmask | (dscp << info->shift_bits));
 | ||||
| +		}
 | ||||
|  		if (READ_ONCE(ct->mark) != newmark) { | ||||
|  			WRITE_ONCE(ct->mark, newmark); | ||||
|  			nf_conntrack_event_cache(IPCT_MARK, ct); | ||||
| @@ -83,20 +94,36 @@ static unsigned int
 | ||||
|  connmark_tg(struct sk_buff *skb, const struct xt_action_param *par) | ||||
|  { | ||||
|  	const struct xt_connmark_tginfo1 *info = par->targinfo; | ||||
| -	const struct xt_connmark_tginfo2 info2 = {
 | ||||
| +	const struct xt_connmark_tginfo3 info3 = {
 | ||||
|  		.ctmark	= info->ctmark, | ||||
|  		.ctmask	= info->ctmask, | ||||
|  		.nfmask	= info->nfmask, | ||||
|  		.mode	= info->mode, | ||||
| +		.func	= XT_CONNMARK_VALUE
 | ||||
|  	}; | ||||
|   | ||||
| -	return connmark_tg_shift(skb, &info2);
 | ||||
| +	return connmark_tg_shift(skb, &info3);
 | ||||
|  } | ||||
|   | ||||
|  static unsigned int | ||||
|  connmark_tg_v2(struct sk_buff *skb, const struct xt_action_param *par) | ||||
|  { | ||||
|  	const struct xt_connmark_tginfo2 *info = par->targinfo; | ||||
| +	const struct xt_connmark_tginfo3 info3 = {
 | ||||
| +		.ctmark	= info->ctmark,
 | ||||
| +		.ctmask	= info->ctmask,
 | ||||
| +		.nfmask	= info->nfmask,
 | ||||
| +		.mode	= info->mode,
 | ||||
| +		.func	= XT_CONNMARK_VALUE
 | ||||
| +	};
 | ||||
| +
 | ||||
| +	return connmark_tg_shift(skb, &info3);
 | ||||
| +}
 | ||||
| +
 | ||||
| +static unsigned int
 | ||||
| +connmark_tg_v3(struct sk_buff *skb, const struct xt_action_param *par)
 | ||||
| +{
 | ||||
| +	const struct xt_connmark_tginfo3 *info = par->targinfo;
 | ||||
|   | ||||
|  	return connmark_tg_shift(skb, info); | ||||
|  } | ||||
| @@ -167,6 +194,16 @@ static struct xt_target connmark_tg_reg[
 | ||||
|  		.targetsize     = sizeof(struct xt_connmark_tginfo2), | ||||
|  		.destroy        = connmark_tg_destroy, | ||||
|  		.me             = THIS_MODULE, | ||||
| +	},
 | ||||
| +	{
 | ||||
| +		.name           = "CONNMARK",
 | ||||
| +		.revision       = 3,
 | ||||
| +		.family         = NFPROTO_UNSPEC,
 | ||||
| +		.checkentry     = connmark_tg_check,
 | ||||
| +		.target         = connmark_tg_v3,
 | ||||
| +		.targetsize     = sizeof(struct xt_connmark_tginfo3),
 | ||||
| +		.destroy        = connmark_tg_destroy,
 | ||||
| +		.me             = THIS_MODULE,
 | ||||
|  	} | ||||
|  }; | ||||
|   | ||||
|  | @ -0,0 +1,812 @@ | |||
| From: Felix Fietkau <nbd@nbd.name> | ||||
| Date: Tue, 20 Feb 2018 15:56:02 +0100 | ||||
| Subject: [PATCH] netfilter: add xt_FLOWOFFLOAD target | ||||
| 
 | ||||
| Signed-off-by: Felix Fietkau <nbd@nbd.name> | ||||
| ---
 | ||||
|  create mode 100644 net/netfilter/xt_OFFLOAD.c | ||||
| 
 | ||||
| --- a/net/netfilter/Kconfig
 | ||||
| +++ b/net/netfilter/Kconfig
 | ||||
| @@ -729,7 +729,6 @@ config NF_FLOW_TABLE
 | ||||
|  	tristate "Netfilter flow table module" | ||||
|  	depends on NETFILTER_INGRESS | ||||
|  	depends on NF_CONNTRACK | ||||
| -	depends on NF_TABLES
 | ||||
|  	help | ||||
|  	  This option adds the flow table core infrastructure. | ||||
|   | ||||
| @@ -1025,6 +1024,15 @@ config NETFILTER_XT_TARGET_NOTRACK
 | ||||
|  	depends on NETFILTER_ADVANCED | ||||
|  	select NETFILTER_XT_TARGET_CT | ||||
|   | ||||
| +config NETFILTER_XT_TARGET_FLOWOFFLOAD
 | ||||
| +	tristate '"FLOWOFFLOAD" target support'
 | ||||
| +	depends on NF_FLOW_TABLE
 | ||||
| +	depends on NETFILTER_INGRESS
 | ||||
| +	help
 | ||||
| +	  This option adds a `FLOWOFFLOAD' target, which uses the nf_flow_offload
 | ||||
| +	  module to speed up processing of packets by bypassing the usual
 | ||||
| +	  netfilter chains
 | ||||
| +
 | ||||
|  config NETFILTER_XT_TARGET_RATEEST | ||||
|  	tristate '"RATEEST" target support' | ||||
|  	depends on NETFILTER_ADVANCED | ||||
| --- a/net/netfilter/Makefile
 | ||||
| +++ b/net/netfilter/Makefile
 | ||||
| @@ -163,6 +163,7 @@ obj-$(CONFIG_NETFILTER_XT_TARGET_CLASSIF
 | ||||
|  obj-$(CONFIG_NETFILTER_XT_TARGET_CONNSECMARK) += xt_CONNSECMARK.o | ||||
|  obj-$(CONFIG_NETFILTER_XT_TARGET_CT) += xt_CT.o | ||||
|  obj-$(CONFIG_NETFILTER_XT_TARGET_DSCP) += xt_DSCP.o | ||||
| +obj-$(CONFIG_NETFILTER_XT_TARGET_FLOWOFFLOAD) += xt_FLOWOFFLOAD.o
 | ||||
|  obj-$(CONFIG_NETFILTER_XT_TARGET_HL) += xt_HL.o | ||||
|  obj-$(CONFIG_NETFILTER_XT_TARGET_HMARK) += xt_HMARK.o | ||||
|  obj-$(CONFIG_NETFILTER_XT_TARGET_LED) += xt_LED.o | ||||
| --- /dev/null
 | ||||
| +++ b/net/netfilter/xt_FLOWOFFLOAD.c
 | ||||
| @@ -0,0 +1,703 @@
 | ||||
| +/*
 | ||||
| + * Copyright (C) 2018-2021 Felix Fietkau <nbd@nbd.name>
 | ||||
| + *
 | ||||
| + * This program is free software; you can redistribute it and/or modify
 | ||||
| + * it under the terms of the GNU General Public License version 2 as
 | ||||
| + * published by the Free Software Foundation.
 | ||||
| + */
 | ||||
| +#include <linux/module.h>
 | ||||
| +#include <linux/init.h>
 | ||||
| +#include <linux/netfilter.h>
 | ||||
| +#include <linux/netfilter/xt_FLOWOFFLOAD.h>
 | ||||
| +#include <linux/if_vlan.h>
 | ||||
| +#include <net/ip.h>
 | ||||
| +#include <net/netfilter/nf_conntrack.h>
 | ||||
| +#include <net/netfilter/nf_conntrack_extend.h>
 | ||||
| +#include <net/netfilter/nf_conntrack_helper.h>
 | ||||
| +#include <net/netfilter/nf_flow_table.h>
 | ||||
| +
 | ||||
| +struct xt_flowoffload_hook {
 | ||||
| +	struct hlist_node list;
 | ||||
| +	struct nf_hook_ops ops;
 | ||||
| +	struct net *net;
 | ||||
| +	bool registered;
 | ||||
| +	bool used;
 | ||||
| +};
 | ||||
| +
 | ||||
| +struct xt_flowoffload_table {
 | ||||
| +	struct nf_flowtable ft;
 | ||||
| +	struct hlist_head hooks;
 | ||||
| +	struct delayed_work work;
 | ||||
| +};
 | ||||
| +
 | ||||
| +struct nf_forward_info {
 | ||||
| +	const struct net_device *indev;
 | ||||
| +	const struct net_device *outdev;
 | ||||
| +	const struct net_device *hw_outdev;
 | ||||
| +	struct id {
 | ||||
| +		__u16	id;
 | ||||
| +		__be16	proto;
 | ||||
| +	} encap[NF_FLOW_TABLE_ENCAP_MAX];
 | ||||
| +	u8 num_encaps;
 | ||||
| +	u8 ingress_vlans;
 | ||||
| +	u8 h_source[ETH_ALEN];
 | ||||
| +	u8 h_dest[ETH_ALEN];
 | ||||
| +	enum flow_offload_xmit_type xmit_type;
 | ||||
| +};
 | ||||
| +
 | ||||
| +static DEFINE_SPINLOCK(hooks_lock);
 | ||||
| +
 | ||||
| +struct xt_flowoffload_table flowtable[2];
 | ||||
| +
 | ||||
| +static unsigned int
 | ||||
| +xt_flowoffload_net_hook(void *priv, struct sk_buff *skb,
 | ||||
| +			const struct nf_hook_state *state)
 | ||||
| +{
 | ||||
| +	struct vlan_ethhdr *veth;
 | ||||
| +	__be16 proto;
 | ||||
| +
 | ||||
| +	switch (skb->protocol) {
 | ||||
| +	case htons(ETH_P_8021Q):
 | ||||
| +		veth = (struct vlan_ethhdr *)skb_mac_header(skb);
 | ||||
| +		proto = veth->h_vlan_encapsulated_proto;
 | ||||
| +		break;
 | ||||
| +	case htons(ETH_P_PPP_SES):
 | ||||
| +		if (!nf_flow_pppoe_proto(skb, &proto))
 | ||||
| +			return NF_ACCEPT;
 | ||||
| +		break;
 | ||||
| +	default:
 | ||||
| +		proto = skb->protocol;
 | ||||
| +		break;
 | ||||
| +	}
 | ||||
| +
 | ||||
| +	switch (proto) {
 | ||||
| +	case htons(ETH_P_IP):
 | ||||
| +		return nf_flow_offload_ip_hook(priv, skb, state);
 | ||||
| +	case htons(ETH_P_IPV6):
 | ||||
| +		return nf_flow_offload_ipv6_hook(priv, skb, state);
 | ||||
| +	}
 | ||||
| +
 | ||||
| +	return NF_ACCEPT;
 | ||||
| +}
 | ||||
| +
 | ||||
| +static int
 | ||||
| +xt_flowoffload_create_hook(struct xt_flowoffload_table *table,
 | ||||
| +			   struct net_device *dev)
 | ||||
| +{
 | ||||
| +	struct xt_flowoffload_hook *hook;
 | ||||
| +	struct nf_hook_ops *ops;
 | ||||
| +
 | ||||
| +	hook = kzalloc(sizeof(*hook), GFP_ATOMIC);
 | ||||
| +	if (!hook)
 | ||||
| +		return -ENOMEM;
 | ||||
| +
 | ||||
| +	ops = &hook->ops;
 | ||||
| +	ops->pf = NFPROTO_NETDEV;
 | ||||
| +	ops->hooknum = NF_NETDEV_INGRESS;
 | ||||
| +	ops->priority = 10;
 | ||||
| +	ops->priv = &table->ft;
 | ||||
| +	ops->hook = xt_flowoffload_net_hook;
 | ||||
| +	ops->dev = dev;
 | ||||
| +
 | ||||
| +	hlist_add_head(&hook->list, &table->hooks);
 | ||||
| +	mod_delayed_work(system_power_efficient_wq, &table->work, 0);
 | ||||
| +
 | ||||
| +	return 0;
 | ||||
| +}
 | ||||
| +
 | ||||
| +static struct xt_flowoffload_hook *
 | ||||
| +flow_offload_lookup_hook(struct xt_flowoffload_table *table,
 | ||||
| +			 struct net_device *dev)
 | ||||
| +{
 | ||||
| +	struct xt_flowoffload_hook *hook;
 | ||||
| +
 | ||||
| +	hlist_for_each_entry(hook, &table->hooks, list) {
 | ||||
| +		if (hook->ops.dev == dev)
 | ||||
| +			return hook;
 | ||||
| +	}
 | ||||
| +
 | ||||
| +	return NULL;
 | ||||
| +}
 | ||||
| +
 | ||||
| +static void
 | ||||
| +xt_flowoffload_check_device(struct xt_flowoffload_table *table,
 | ||||
| +			    struct net_device *dev)
 | ||||
| +{
 | ||||
| +	struct xt_flowoffload_hook *hook;
 | ||||
| +
 | ||||
| +	if (!dev)
 | ||||
| +		return;
 | ||||
| +
 | ||||
| +	spin_lock_bh(&hooks_lock);
 | ||||
| +	hook = flow_offload_lookup_hook(table, dev);
 | ||||
| +	if (hook)
 | ||||
| +		hook->used = true;
 | ||||
| +	else
 | ||||
| +		xt_flowoffload_create_hook(table, dev);
 | ||||
| +	spin_unlock_bh(&hooks_lock);
 | ||||
| +}
 | ||||
| +
 | ||||
| +static void
 | ||||
| +xt_flowoffload_register_hooks(struct xt_flowoffload_table *table)
 | ||||
| +{
 | ||||
| +	struct xt_flowoffload_hook *hook;
 | ||||
| +
 | ||||
| +restart:
 | ||||
| +	hlist_for_each_entry(hook, &table->hooks, list) {
 | ||||
| +		if (hook->registered)
 | ||||
| +			continue;
 | ||||
| +
 | ||||
| +		hook->registered = true;
 | ||||
| +		hook->net = dev_net(hook->ops.dev);
 | ||||
| +		spin_unlock_bh(&hooks_lock);
 | ||||
| +		nf_register_net_hook(hook->net, &hook->ops);
 | ||||
| +		if (table->ft.flags & NF_FLOWTABLE_HW_OFFLOAD)
 | ||||
| +			table->ft.type->setup(&table->ft, hook->ops.dev,
 | ||||
| +					      FLOW_BLOCK_BIND);
 | ||||
| +		spin_lock_bh(&hooks_lock);
 | ||||
| +		goto restart;
 | ||||
| +	}
 | ||||
| +
 | ||||
| +}
 | ||||
| +
 | ||||
| +static bool
 | ||||
| +xt_flowoffload_cleanup_hooks(struct xt_flowoffload_table *table)
 | ||||
| +{
 | ||||
| +	struct xt_flowoffload_hook *hook;
 | ||||
| +	bool active = false;
 | ||||
| +
 | ||||
| +restart:
 | ||||
| +	spin_lock_bh(&hooks_lock);
 | ||||
| +	hlist_for_each_entry(hook, &table->hooks, list) {
 | ||||
| +		if (hook->used || !hook->registered) {
 | ||||
| +			active = true;
 | ||||
| +			continue;
 | ||||
| +		}
 | ||||
| +
 | ||||
| +		hlist_del(&hook->list);
 | ||||
| +		spin_unlock_bh(&hooks_lock);
 | ||||
| +		if (table->ft.flags & NF_FLOWTABLE_HW_OFFLOAD)
 | ||||
| +			table->ft.type->setup(&table->ft, hook->ops.dev,
 | ||||
| +					      FLOW_BLOCK_UNBIND);
 | ||||
| +		nf_unregister_net_hook(hook->net, &hook->ops);
 | ||||
| +		kfree(hook);
 | ||||
| +		goto restart;
 | ||||
| +	}
 | ||||
| +	spin_unlock_bh(&hooks_lock);
 | ||||
| +
 | ||||
| +	return active;
 | ||||
| +}
 | ||||
| +
 | ||||
| +static void
 | ||||
| +xt_flowoffload_check_hook(struct nf_flowtable *flowtable,
 | ||||
| +			  struct flow_offload *flow, void *data)
 | ||||
| +{
 | ||||
| +	struct xt_flowoffload_table *table;
 | ||||
| +	struct flow_offload_tuple *tuple0 = &flow->tuplehash[0].tuple;
 | ||||
| +	struct flow_offload_tuple *tuple1 = &flow->tuplehash[1].tuple;
 | ||||
| +	struct xt_flowoffload_hook *hook;
 | ||||
| +
 | ||||
| +	table = container_of(flowtable, struct xt_flowoffload_table, ft);
 | ||||
| +
 | ||||
| +	spin_lock_bh(&hooks_lock);
 | ||||
| +	hlist_for_each_entry(hook, &table->hooks, list) {
 | ||||
| +		if (hook->ops.dev->ifindex != tuple0->iifidx &&
 | ||||
| +		    hook->ops.dev->ifindex != tuple1->iifidx)
 | ||||
| +			continue;
 | ||||
| +
 | ||||
| +		hook->used = true;
 | ||||
| +	}
 | ||||
| +	spin_unlock_bh(&hooks_lock);
 | ||||
| +}
 | ||||
| +
 | ||||
| +static void
 | ||||
| +xt_flowoffload_hook_work(struct work_struct *work)
 | ||||
| +{
 | ||||
| +	struct xt_flowoffload_table *table;
 | ||||
| +	struct xt_flowoffload_hook *hook;
 | ||||
| +	int err;
 | ||||
| +
 | ||||
| +	table = container_of(work, struct xt_flowoffload_table, work.work);
 | ||||
| +
 | ||||
| +	spin_lock_bh(&hooks_lock);
 | ||||
| +	xt_flowoffload_register_hooks(table);
 | ||||
| +	hlist_for_each_entry(hook, &table->hooks, list)
 | ||||
| +		hook->used = false;
 | ||||
| +	spin_unlock_bh(&hooks_lock);
 | ||||
| +
 | ||||
| +	err = nf_flow_table_iterate(&table->ft, xt_flowoffload_check_hook,
 | ||||
| +				    NULL);
 | ||||
| +	if (err && err != -EAGAIN)
 | ||||
| +		goto out;
 | ||||
| +
 | ||||
| +	if (!xt_flowoffload_cleanup_hooks(table))
 | ||||
| +		return;
 | ||||
| +
 | ||||
| +out:
 | ||||
| +	queue_delayed_work(system_power_efficient_wq, &table->work, HZ);
 | ||||
| +}
 | ||||
| +
 | ||||
| +static bool
 | ||||
| +xt_flowoffload_skip(struct sk_buff *skb, int family)
 | ||||
| +{
 | ||||
| +	if (skb_sec_path(skb))
 | ||||
| +		return true;
 | ||||
| +
 | ||||
| +	if (family == NFPROTO_IPV4) {
 | ||||
| +		const struct ip_options *opt = &(IPCB(skb)->opt);
 | ||||
| +
 | ||||
| +		if (unlikely(opt->optlen))
 | ||||
| +			return true;
 | ||||
| +	}
 | ||||
| +
 | ||||
| +	return false;
 | ||||
| +}
 | ||||
| +
 | ||||
| +static enum flow_offload_xmit_type nf_xmit_type(struct dst_entry *dst)
 | ||||
| +{
 | ||||
| +	if (dst_xfrm(dst))
 | ||||
| +		return FLOW_OFFLOAD_XMIT_XFRM;
 | ||||
| +
 | ||||
| +	return FLOW_OFFLOAD_XMIT_NEIGH;
 | ||||
| +}
 | ||||
| +
 | ||||
| +static void nf_default_forward_path(struct nf_flow_route *route,
 | ||||
| +				    struct dst_entry *dst_cache,
 | ||||
| +				    enum ip_conntrack_dir dir,
 | ||||
| +				    struct net_device **dev)
 | ||||
| +{
 | ||||
| +	dev[!dir] = dst_cache->dev;
 | ||||
| +	route->tuple[!dir].in.ifindex	= dst_cache->dev->ifindex;
 | ||||
| +	route->tuple[dir].dst		= dst_cache;
 | ||||
| +	route->tuple[dir].xmit_type	= nf_xmit_type(dst_cache);
 | ||||
| +}
 | ||||
| +
 | ||||
| +static bool nf_is_valid_ether_device(const struct net_device *dev)
 | ||||
| +{
 | ||||
| +	if (!dev || (dev->flags & IFF_LOOPBACK) || dev->type != ARPHRD_ETHER ||
 | ||||
| +	    dev->addr_len != ETH_ALEN || !is_valid_ether_addr(dev->dev_addr))
 | ||||
| +		return false;
 | ||||
| +
 | ||||
| +	return true;
 | ||||
| +}
 | ||||
| +
 | ||||
| +static void nf_dev_path_info(const struct net_device_path_stack *stack,
 | ||||
| +			     struct nf_forward_info *info,
 | ||||
| +			     unsigned char *ha)
 | ||||
| +{
 | ||||
| +	const struct net_device_path *path;
 | ||||
| +	int i;
 | ||||
| +
 | ||||
| +	memcpy(info->h_dest, ha, ETH_ALEN);
 | ||||
| +
 | ||||
| +	for (i = 0; i < stack->num_paths; i++) {
 | ||||
| +		path = &stack->path[i];
 | ||||
| +		switch (path->type) {
 | ||||
| +		case DEV_PATH_ETHERNET:
 | ||||
| +		case DEV_PATH_DSA:
 | ||||
| +		case DEV_PATH_VLAN:
 | ||||
| +		case DEV_PATH_PPPOE:
 | ||||
| +			info->indev = path->dev;
 | ||||
| +			if (is_zero_ether_addr(info->h_source))
 | ||||
| +				memcpy(info->h_source, path->dev->dev_addr, ETH_ALEN);
 | ||||
| +
 | ||||
| +			if (path->type == DEV_PATH_ETHERNET)
 | ||||
| +				break;
 | ||||
| +			if (path->type == DEV_PATH_DSA) {
 | ||||
| +				i = stack->num_paths;
 | ||||
| +				break;
 | ||||
| +			}
 | ||||
| +
 | ||||
| +			/* DEV_PATH_VLAN and DEV_PATH_PPPOE */
 | ||||
| +			if (info->num_encaps >= NF_FLOW_TABLE_ENCAP_MAX) {
 | ||||
| +				info->indev = NULL;
 | ||||
| +				break;
 | ||||
| +			}
 | ||||
| +			if (!info->outdev)
 | ||||
| +				info->outdev = path->dev;
 | ||||
| +			info->encap[info->num_encaps].id = path->encap.id;
 | ||||
| +			info->encap[info->num_encaps].proto = path->encap.proto;
 | ||||
| +			info->num_encaps++;
 | ||||
| +			if (path->type == DEV_PATH_PPPOE)
 | ||||
| +				memcpy(info->h_dest, path->encap.h_dest, ETH_ALEN);
 | ||||
| +			break;
 | ||||
| +		case DEV_PATH_BRIDGE:
 | ||||
| +			if (is_zero_ether_addr(info->h_source))
 | ||||
| +				memcpy(info->h_source, path->dev->dev_addr, ETH_ALEN);
 | ||||
| +
 | ||||
| +			switch (path->bridge.vlan_mode) {
 | ||||
| +			case DEV_PATH_BR_VLAN_UNTAG_HW:
 | ||||
| +				info->ingress_vlans |= BIT(info->num_encaps - 1);
 | ||||
| +				break;
 | ||||
| +			case DEV_PATH_BR_VLAN_TAG:
 | ||||
| +				info->encap[info->num_encaps].id = path->bridge.vlan_id;
 | ||||
| +				info->encap[info->num_encaps].proto = path->bridge.vlan_proto;
 | ||||
| +				info->num_encaps++;
 | ||||
| +				break;
 | ||||
| +			case DEV_PATH_BR_VLAN_UNTAG:
 | ||||
| +				info->num_encaps--;
 | ||||
| +				break;
 | ||||
| +			case DEV_PATH_BR_VLAN_KEEP:
 | ||||
| +				break;
 | ||||
| +			}
 | ||||
| +			break;
 | ||||
| +		default:
 | ||||
| +			info->indev = NULL;
 | ||||
| +			break;
 | ||||
| +		}
 | ||||
| +	}
 | ||||
| +	if (!info->outdev)
 | ||||
| +		info->outdev = info->indev;
 | ||||
| +
 | ||||
| +	info->hw_outdev = info->indev;
 | ||||
| +
 | ||||
| +	if (nf_is_valid_ether_device(info->indev))
 | ||||
| +		info->xmit_type = FLOW_OFFLOAD_XMIT_DIRECT;
 | ||||
| +}
 | ||||
| +
 | ||||
| +static int nf_dev_fill_forward_path(const struct nf_flow_route *route,
 | ||||
| +				     const struct dst_entry *dst_cache,
 | ||||
| +				     const struct nf_conn *ct,
 | ||||
| +				     enum ip_conntrack_dir dir, u8 *ha,
 | ||||
| +				     struct net_device_path_stack *stack)
 | ||||
| +{
 | ||||
| +	const void *daddr = &ct->tuplehash[!dir].tuple.src.u3;
 | ||||
| +	struct net_device *dev = dst_cache->dev;
 | ||||
| +	struct neighbour *n;
 | ||||
| +	u8 nud_state;
 | ||||
| +
 | ||||
| +	if (!nf_is_valid_ether_device(dev))
 | ||||
| +		goto out;
 | ||||
| +
 | ||||
| +	n = dst_neigh_lookup(dst_cache, daddr);
 | ||||
| +	if (!n)
 | ||||
| +		return -1;
 | ||||
| +
 | ||||
| +	read_lock_bh(&n->lock);
 | ||||
| +	nud_state = n->nud_state;
 | ||||
| +	ether_addr_copy(ha, n->ha);
 | ||||
| +	read_unlock_bh(&n->lock);
 | ||||
| +	neigh_release(n);
 | ||||
| +
 | ||||
| +	if (!(nud_state & NUD_VALID))
 | ||||
| +		return -1;
 | ||||
| +
 | ||||
| +out:
 | ||||
| +	return dev_fill_forward_path(dev, ha, stack);
 | ||||
| +}
 | ||||
| +
 | ||||
| +static void nf_dev_forward_path(struct nf_flow_route *route,
 | ||||
| +				const struct nf_conn *ct,
 | ||||
| +				enum ip_conntrack_dir dir,
 | ||||
| +				struct net_device **devs)
 | ||||
| +{
 | ||||
| +	const struct dst_entry *dst = route->tuple[dir].dst;
 | ||||
| +	struct net_device_path_stack stack;
 | ||||
| +	struct nf_forward_info info = {};
 | ||||
| +	unsigned char ha[ETH_ALEN];
 | ||||
| +	int i;
 | ||||
| +
 | ||||
| +	if (nf_dev_fill_forward_path(route, dst, ct, dir, ha, &stack) >= 0)
 | ||||
| +		nf_dev_path_info(&stack, &info, ha);
 | ||||
| +
 | ||||
| +	devs[!dir] = (struct net_device *)info.indev;
 | ||||
| +	if (!info.indev)
 | ||||
| +		return;
 | ||||
| +
 | ||||
| +	route->tuple[!dir].in.ifindex = info.indev->ifindex;
 | ||||
| +	for (i = 0; i < info.num_encaps; i++) {
 | ||||
| +		route->tuple[!dir].in.encap[i].id = info.encap[i].id;
 | ||||
| +		route->tuple[!dir].in.encap[i].proto = info.encap[i].proto;
 | ||||
| +	}
 | ||||
| +	route->tuple[!dir].in.num_encaps = info.num_encaps;
 | ||||
| +	route->tuple[!dir].in.ingress_vlans = info.ingress_vlans;
 | ||||
| +
 | ||||
| +	if (info.xmit_type == FLOW_OFFLOAD_XMIT_DIRECT) {
 | ||||
| +		memcpy(route->tuple[dir].out.h_source, info.h_source, ETH_ALEN);
 | ||||
| +		memcpy(route->tuple[dir].out.h_dest, info.h_dest, ETH_ALEN);
 | ||||
| +		route->tuple[dir].out.ifindex = info.outdev->ifindex;
 | ||||
| +		route->tuple[dir].out.hw_ifindex = info.hw_outdev->ifindex;
 | ||||
| +		route->tuple[dir].xmit_type = info.xmit_type;
 | ||||
| +	}
 | ||||
| +}
 | ||||
| +
 | ||||
| +static int
 | ||||
| +xt_flowoffload_route(struct sk_buff *skb, const struct nf_conn *ct,
 | ||||
| +		     const struct xt_action_param *par,
 | ||||
| +		     struct nf_flow_route *route, enum ip_conntrack_dir dir,
 | ||||
| +		     struct net_device **devs)
 | ||||
| +{
 | ||||
| +	struct dst_entry *this_dst = skb_dst(skb);
 | ||||
| +	struct dst_entry *other_dst = NULL;
 | ||||
| +	struct flowi fl;
 | ||||
| +
 | ||||
| +	memset(&fl, 0, sizeof(fl));
 | ||||
| +	switch (xt_family(par)) {
 | ||||
| +	case NFPROTO_IPV4:
 | ||||
| +		fl.u.ip4.daddr = ct->tuplehash[dir].tuple.src.u3.ip;
 | ||||
| +		fl.u.ip4.flowi4_oif = xt_in(par)->ifindex;
 | ||||
| +		break;
 | ||||
| +	case NFPROTO_IPV6:
 | ||||
| +		fl.u.ip6.saddr = ct->tuplehash[!dir].tuple.dst.u3.in6;
 | ||||
| +		fl.u.ip6.daddr = ct->tuplehash[dir].tuple.src.u3.in6;
 | ||||
| +		fl.u.ip6.flowi6_oif = xt_in(par)->ifindex;
 | ||||
| +		break;
 | ||||
| +	}
 | ||||
| +
 | ||||
| +	if (!dst_hold_safe(this_dst))
 | ||||
| +		return -ENOENT;
 | ||||
| +
 | ||||
| +	nf_route(xt_net(par), &other_dst, &fl, false, xt_family(par));
 | ||||
| +	if (!other_dst) {
 | ||||
| +		dst_release(this_dst);
 | ||||
| +		return -ENOENT;
 | ||||
| +	}
 | ||||
| +
 | ||||
| +	nf_default_forward_path(route, this_dst, dir, devs);
 | ||||
| +	nf_default_forward_path(route, other_dst, !dir, devs);
 | ||||
| +
 | ||||
| +	if (route->tuple[dir].xmit_type	== FLOW_OFFLOAD_XMIT_NEIGH &&
 | ||||
| +	    route->tuple[!dir].xmit_type == FLOW_OFFLOAD_XMIT_NEIGH) {
 | ||||
| +		nf_dev_forward_path(route, ct, dir, devs);
 | ||||
| +		nf_dev_forward_path(route, ct, !dir, devs);
 | ||||
| +	}
 | ||||
| +
 | ||||
| +	return 0;
 | ||||
| +}
 | ||||
| +
 | ||||
| +static unsigned int
 | ||||
| +flowoffload_tg(struct sk_buff *skb, const struct xt_action_param *par)
 | ||||
| +{
 | ||||
| +	struct xt_flowoffload_table *table;
 | ||||
| +	const struct xt_flowoffload_target_info *info = par->targinfo;
 | ||||
| +	struct tcphdr _tcph, *tcph = NULL;
 | ||||
| +	enum ip_conntrack_info ctinfo;
 | ||||
| +	enum ip_conntrack_dir dir;
 | ||||
| +	struct nf_flow_route route = {};
 | ||||
| +	struct flow_offload *flow = NULL;
 | ||||
| +	struct net_device *devs[2] = {};
 | ||||
| +	struct nf_conn *ct;
 | ||||
| +	struct net *net;
 | ||||
| +
 | ||||
| +	if (xt_flowoffload_skip(skb, xt_family(par)))
 | ||||
| +		return XT_CONTINUE;
 | ||||
| +
 | ||||
| +	ct = nf_ct_get(skb, &ctinfo);
 | ||||
| +	if (ct == NULL)
 | ||||
| +		return XT_CONTINUE;
 | ||||
| +
 | ||||
| +	switch (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum) {
 | ||||
| +	case IPPROTO_TCP:
 | ||||
| +		if (ct->proto.tcp.state != TCP_CONNTRACK_ESTABLISHED)
 | ||||
| +			return XT_CONTINUE;
 | ||||
| +
 | ||||
| +		tcph = skb_header_pointer(skb, par->thoff,
 | ||||
| +					  sizeof(_tcph), &_tcph);
 | ||||
| +		if (unlikely(!tcph || tcph->fin || tcph->rst))
 | ||||
| +			return XT_CONTINUE;
 | ||||
| +		break;
 | ||||
| +	case IPPROTO_UDP:
 | ||||
| +		break;
 | ||||
| +	default:
 | ||||
| +		return XT_CONTINUE;
 | ||||
| +	}
 | ||||
| +
 | ||||
| +	if (nf_ct_ext_exist(ct, NF_CT_EXT_HELPER) ||
 | ||||
| +	    ct->status & (IPS_SEQ_ADJUST | IPS_NAT_CLASH))
 | ||||
| +		return XT_CONTINUE;
 | ||||
| +
 | ||||
| +	if (!nf_ct_is_confirmed(ct))
 | ||||
| +		return XT_CONTINUE;
 | ||||
| +
 | ||||
| +	dir = CTINFO2DIR(ctinfo);
 | ||||
| +
 | ||||
| +	devs[dir] = xt_out(par);
 | ||||
| +	devs[!dir] = xt_in(par);
 | ||||
| +
 | ||||
| +	if (!devs[dir] || !devs[!dir])
 | ||||
| +		return XT_CONTINUE;
 | ||||
| +
 | ||||
| +	if (test_and_set_bit(IPS_OFFLOAD_BIT, &ct->status))
 | ||||
| +		return XT_CONTINUE;
 | ||||
| +
 | ||||
| +	if (xt_flowoffload_route(skb, ct, par, &route, dir, devs) < 0)
 | ||||
| +		goto err_flow_route;
 | ||||
| +
 | ||||
| +	flow = flow_offload_alloc(ct);
 | ||||
| +	if (!flow)
 | ||||
| +		goto err_flow_alloc;
 | ||||
| +
 | ||||
| +	flow_offload_route_init(flow, &route);
 | ||||
| +
 | ||||
| +	if (tcph) {
 | ||||
| +		ct->proto.tcp.seen[0].flags |= IP_CT_TCP_FLAG_BE_LIBERAL;
 | ||||
| +		ct->proto.tcp.seen[1].flags |= IP_CT_TCP_FLAG_BE_LIBERAL;
 | ||||
| +	}
 | ||||
| +
 | ||||
| +	table = &flowtable[!!(info->flags & XT_FLOWOFFLOAD_HW)];
 | ||||
| +
 | ||||
| +	net = read_pnet(&table->ft.net);
 | ||||
| +	if (!net)
 | ||||
| +		write_pnet(&table->ft.net, xt_net(par));
 | ||||
| +
 | ||||
| +	__set_bit(NF_FLOW_HW_BIDIRECTIONAL, &flow->flags);
 | ||||
| +	if (flow_offload_add(&table->ft, flow) < 0)
 | ||||
| +		goto err_flow_add;
 | ||||
| +
 | ||||
| +	xt_flowoffload_check_device(table, devs[0]);
 | ||||
| +	xt_flowoffload_check_device(table, devs[1]);
 | ||||
| +
 | ||||
| +	return XT_CONTINUE;
 | ||||
| +
 | ||||
| +err_flow_add:
 | ||||
| +	flow_offload_free(flow);
 | ||||
| +err_flow_alloc:
 | ||||
| +	dst_release(route.tuple[dir].dst);
 | ||||
| +	dst_release(route.tuple[!dir].dst);
 | ||||
| +err_flow_route:
 | ||||
| +	clear_bit(IPS_OFFLOAD_BIT, &ct->status);
 | ||||
| +
 | ||||
| +	return XT_CONTINUE;
 | ||||
| +}
 | ||||
| +
 | ||||
| +static int flowoffload_chk(const struct xt_tgchk_param *par)
 | ||||
| +{
 | ||||
| +	struct xt_flowoffload_target_info *info = par->targinfo;
 | ||||
| +
 | ||||
| +	if (info->flags & ~XT_FLOWOFFLOAD_MASK)
 | ||||
| +		return -EINVAL;
 | ||||
| +
 | ||||
| +	return 0;
 | ||||
| +}
 | ||||
| +
 | ||||
| +static struct xt_target offload_tg_reg __read_mostly = {
 | ||||
| +	.family		= NFPROTO_UNSPEC,
 | ||||
| +	.name		= "FLOWOFFLOAD",
 | ||||
| +	.revision	= 0,
 | ||||
| +	.targetsize	= sizeof(struct xt_flowoffload_target_info),
 | ||||
| +	.usersize	= sizeof(struct xt_flowoffload_target_info),
 | ||||
| +	.checkentry	= flowoffload_chk,
 | ||||
| +	.target		= flowoffload_tg,
 | ||||
| +	.me		= THIS_MODULE,
 | ||||
| +};
 | ||||
| +
 | ||||
| +static int flow_offload_netdev_event(struct notifier_block *this,
 | ||||
| +				     unsigned long event, void *ptr)
 | ||||
| +{
 | ||||
| +	struct xt_flowoffload_hook *hook0, *hook1;
 | ||||
| +	struct net_device *dev = netdev_notifier_info_to_dev(ptr);
 | ||||
| +
 | ||||
| +	if (event != NETDEV_UNREGISTER)
 | ||||
| +		return NOTIFY_DONE;
 | ||||
| +
 | ||||
| +	spin_lock_bh(&hooks_lock);
 | ||||
| +	hook0 = flow_offload_lookup_hook(&flowtable[0], dev);
 | ||||
| +	if (hook0)
 | ||||
| +		hlist_del(&hook0->list);
 | ||||
| +
 | ||||
| +	hook1 = flow_offload_lookup_hook(&flowtable[1], dev);
 | ||||
| +	if (hook1)
 | ||||
| +		hlist_del(&hook1->list);
 | ||||
| +	spin_unlock_bh(&hooks_lock);
 | ||||
| +
 | ||||
| +	if (hook0) {
 | ||||
| +		nf_unregister_net_hook(hook0->net, &hook0->ops);
 | ||||
| +		kfree(hook0);
 | ||||
| +	}
 | ||||
| +
 | ||||
| +	if (hook1) {
 | ||||
| +		nf_unregister_net_hook(hook1->net, &hook1->ops);
 | ||||
| +		kfree(hook1);
 | ||||
| +	}
 | ||||
| +
 | ||||
| +	nf_flow_table_cleanup(dev);
 | ||||
| +
 | ||||
| +	return NOTIFY_DONE;
 | ||||
| +}
 | ||||
| +
 | ||||
| +static struct notifier_block flow_offload_netdev_notifier = {
 | ||||
| +	.notifier_call	= flow_offload_netdev_event,
 | ||||
| +};
 | ||||
| +
 | ||||
| +static int nf_flow_rule_route_inet(struct net *net,
 | ||||
| +				   struct flow_offload *flow,
 | ||||
| +				   enum flow_offload_tuple_dir dir,
 | ||||
| +				   struct nf_flow_rule *flow_rule)
 | ||||
| +{
 | ||||
| +	const struct flow_offload_tuple *flow_tuple = &flow->tuplehash[dir].tuple;
 | ||||
| +	int err;
 | ||||
| +
 | ||||
| +	switch (flow_tuple->l3proto) {
 | ||||
| +	case NFPROTO_IPV4:
 | ||||
| +		err = nf_flow_rule_route_ipv4(net, flow, dir, flow_rule);
 | ||||
| +		break;
 | ||||
| +	case NFPROTO_IPV6:
 | ||||
| +		err = nf_flow_rule_route_ipv6(net, flow, dir, flow_rule);
 | ||||
| +		break;
 | ||||
| +	default:
 | ||||
| +		err = -1;
 | ||||
| +		break;
 | ||||
| +	}
 | ||||
| +
 | ||||
| +	return err;
 | ||||
| +}
 | ||||
| +
 | ||||
| +static struct nf_flowtable_type flowtable_inet = {
 | ||||
| +	.family		= NFPROTO_INET,
 | ||||
| +	.init		= nf_flow_table_init,
 | ||||
| +	.setup		= nf_flow_table_offload_setup,
 | ||||
| +	.action		= nf_flow_rule_route_inet,
 | ||||
| +	.free		= nf_flow_table_free,
 | ||||
| +	.hook		= xt_flowoffload_net_hook,
 | ||||
| +	.owner		= THIS_MODULE,
 | ||||
| +};
 | ||||
| +
 | ||||
| +static int init_flowtable(struct xt_flowoffload_table *tbl)
 | ||||
| +{
 | ||||
| +	INIT_DELAYED_WORK(&tbl->work, xt_flowoffload_hook_work);
 | ||||
| +	tbl->ft.type = &flowtable_inet;
 | ||||
| +	tbl->ft.flags = NF_FLOWTABLE_COUNTER;
 | ||||
| +
 | ||||
| +	return nf_flow_table_init(&tbl->ft);
 | ||||
| +}
 | ||||
| +
 | ||||
| +static int __init xt_flowoffload_tg_init(void)
 | ||||
| +{
 | ||||
| +	int ret;
 | ||||
| +
 | ||||
| +	register_netdevice_notifier(&flow_offload_netdev_notifier);
 | ||||
| +
 | ||||
| +	ret = init_flowtable(&flowtable[0]);
 | ||||
| +	if (ret)
 | ||||
| +		return ret;
 | ||||
| +
 | ||||
| +	ret = init_flowtable(&flowtable[1]);
 | ||||
| +	if (ret)
 | ||||
| +		goto cleanup;
 | ||||
| +
 | ||||
| +	flowtable[1].ft.flags |= NF_FLOWTABLE_HW_OFFLOAD;
 | ||||
| +
 | ||||
| +	ret = xt_register_target(&offload_tg_reg);
 | ||||
| +	if (ret)
 | ||||
| +		goto cleanup2;
 | ||||
| +
 | ||||
| +	return 0;
 | ||||
| +
 | ||||
| +cleanup2:
 | ||||
| +	nf_flow_table_free(&flowtable[1].ft);
 | ||||
| +cleanup:
 | ||||
| +	nf_flow_table_free(&flowtable[0].ft);
 | ||||
| +	return ret;
 | ||||
| +}
 | ||||
| +
 | ||||
| +static void __exit xt_flowoffload_tg_exit(void)
 | ||||
| +{
 | ||||
| +	xt_unregister_target(&offload_tg_reg);
 | ||||
| +	unregister_netdevice_notifier(&flow_offload_netdev_notifier);
 | ||||
| +	nf_flow_table_free(&flowtable[0].ft);
 | ||||
| +	nf_flow_table_free(&flowtable[1].ft);
 | ||||
| +}
 | ||||
| +
 | ||||
| +MODULE_LICENSE("GPL");
 | ||||
| +module_init(xt_flowoffload_tg_init);
 | ||||
| +module_exit(xt_flowoffload_tg_exit);
 | ||||
| --- a/net/netfilter/nf_flow_table_core.c
 | ||||
| +++ b/net/netfilter/nf_flow_table_core.c
 | ||||
| @@ -7,7 +7,6 @@
 | ||||
|  #include <linux/netdevice.h> | ||||
|  #include <net/ip.h> | ||||
|  #include <net/ip6_route.h> | ||||
| -#include <net/netfilter/nf_tables.h>
 | ||||
|  #include <net/netfilter/nf_flow_table.h> | ||||
|  #include <net/netfilter/nf_conntrack.h> | ||||
|  #include <net/netfilter/nf_conntrack_core.h> | ||||
| @@ -377,8 +376,7 @@ flow_offload_lookup(struct nf_flowtable
 | ||||
|  } | ||||
|  EXPORT_SYMBOL_GPL(flow_offload_lookup); | ||||
|   | ||||
| -static int
 | ||||
| -nf_flow_table_iterate(struct nf_flowtable *flow_table,
 | ||||
| +int nf_flow_table_iterate(struct nf_flowtable *flow_table,
 | ||||
|  		      void (*iter)(struct nf_flowtable *flowtable, | ||||
|  				   struct flow_offload *flow, void *data), | ||||
|  		      void *data) | ||||
| @@ -439,6 +437,7 @@ static void nf_flow_offload_gc_step(stru
 | ||||
|  		nf_flow_offload_stats(flow_table, flow); | ||||
|  	} | ||||
|  } | ||||
| +EXPORT_SYMBOL_GPL(nf_flow_table_iterate);
 | ||||
|   | ||||
|  void nf_flow_table_gc_run(struct nf_flowtable *flow_table) | ||||
|  { | ||||
| --- /dev/null
 | ||||
| +++ b/include/uapi/linux/netfilter/xt_FLOWOFFLOAD.h
 | ||||
| @@ -0,0 +1,17 @@
 | ||||
| +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
 | ||||
| +#ifndef _XT_FLOWOFFLOAD_H
 | ||||
| +#define _XT_FLOWOFFLOAD_H
 | ||||
| +
 | ||||
| +#include <linux/types.h>
 | ||||
| +
 | ||||
| +enum {
 | ||||
| +	XT_FLOWOFFLOAD_HW	= 1 << 0,
 | ||||
| +
 | ||||
| +	XT_FLOWOFFLOAD_MASK	= XT_FLOWOFFLOAD_HW
 | ||||
| +};
 | ||||
| +
 | ||||
| +struct xt_flowoffload_target_info {
 | ||||
| +	__u32 flags;
 | ||||
| +};
 | ||||
| +
 | ||||
| +#endif /* _XT_FLOWOFFLOAD_H */
 | ||||
| --- a/include/net/netfilter/nf_flow_table.h
 | ||||
| +++ b/include/net/netfilter/nf_flow_table.h
 | ||||
| @@ -293,6 +293,11 @@ void nf_flow_table_free(struct nf_flowta
 | ||||
|   | ||||
|  void flow_offload_teardown(struct flow_offload *flow); | ||||
|   | ||||
| +int nf_flow_table_iterate(struct nf_flowtable *flow_table,
 | ||||
| +                      void (*iter)(struct nf_flowtable *flowtable,
 | ||||
| +                                   struct flow_offload *flow, void *data),
 | ||||
| +                      void *data);
 | ||||
| +
 | ||||
|  void nf_flow_snat_port(const struct flow_offload *flow, | ||||
|  		       struct sk_buff *skb, unsigned int thoff, | ||||
|  		       u8 protocol, enum flow_offload_tuple_dir dir); | ||||
|  | @ -0,0 +1,24 @@ | |||
| From 6d3bc769657b0ee7c7506dad9911111c4226a7ea Mon Sep 17 00:00:00 2001 | ||||
| From: Imre Kaloz <kaloz@openwrt.org> | ||||
| Date: Fri, 7 Jul 2017 17:21:05 +0200 | ||||
| Subject: mac80211: increase wireless mesh header size | ||||
| 
 | ||||
| lede-commit 3d4466cfd8f75f717efdb1f96fdde3c70d865fc1 | ||||
| Signed-off-by: Imre Kaloz <kaloz@openwrt.org> | ||||
| ---
 | ||||
|  include/linux/netdevice.h | 4 ++-- | ||||
|  1 file changed, 2 insertions(+), 2 deletions(-) | ||||
| 
 | ||||
| --- a/include/linux/netdevice.h
 | ||||
| +++ b/include/linux/netdevice.h
 | ||||
| @@ -157,8 +157,8 @@ static inline bool dev_xmit_complete(int
 | ||||
|   | ||||
|  #if defined(CONFIG_HYPERV_NET) | ||||
|  # define LL_MAX_HEADER 128 | ||||
| -#elif defined(CONFIG_WLAN) || IS_ENABLED(CONFIG_AX25)
 | ||||
| -# if defined(CONFIG_MAC80211_MESH)
 | ||||
| +#elif defined(CONFIG_WLAN) || IS_ENABLED(CONFIG_AX25) || 1
 | ||||
| +# if defined(CONFIG_MAC80211_MESH) || 1
 | ||||
|  #  define LL_MAX_HEADER 128 | ||||
|  # else | ||||
|  #  define LL_MAX_HEADER 96 | ||||
|  | @ -0,0 +1,27 @@ | |||
| From a6ccb238939b25851474a279b20367fd24a0e816 Mon Sep 17 00:00:00 2001 | ||||
| From: Felix Fietkau <nbd@nbd.name> | ||||
| Date: Fri, 7 Jul 2017 17:21:53 +0200 | ||||
| Subject:  hack: net: fq_codel: tune defaults for small devices | ||||
| 
 | ||||
| Assume that x86_64 devices always have a big memory and do not need this  | ||||
| optimization compared to devices with only 32 MB or 64 MB RAM. | ||||
| 
 | ||||
| Signed-off-by: Felix Fietkau <nbd@nbd.name> | ||||
| ---
 | ||||
|  net/sched/sch_fq_codel.c | 2 +- | ||||
|  1 file changed, 1 insertion(+), 1 deletion(-) | ||||
| 
 | ||||
| --- a/net/sched/sch_fq_codel.c
 | ||||
| +++ b/net/sched/sch_fq_codel.c
 | ||||
| @@ -471,7 +471,11 @@ static int fq_codel_init(struct Qdisc *s
 | ||||
|   | ||||
|  	sch->limit = 10*1024; | ||||
|  	q->flows_cnt = 1024; | ||||
| +#ifdef CONFIG_X86_64
 | ||||
|  	q->memory_limit = 32 << 20; /* 32 MBytes */ | ||||
| +#else
 | ||||
| +	q->memory_limit = 4 << 20; /* 4 MBytes */
 | ||||
| +#endif
 | ||||
|  	q->drop_batch_size = 64; | ||||
|  	q->quantum = psched_mtu(qdisc_dev(sch)); | ||||
|  	INIT_LIST_HEAD(&q->new_flows); | ||||
|  | @ -0,0 +1,25 @@ | |||
| From 804fbb3f2ec9283f7b778e057a68bfff440a0be6 Mon Sep 17 00:00:00 2001 | ||||
| From: Rui Salvaterra <rsalvaterra@gmail.com> | ||||
| Date: Wed, 30 Mar 2022 22:51:55 +0100 | ||||
| Subject: [PATCH] kernel: ct: size the hashtable more adequately | ||||
| 
 | ||||
| To set the default size of the connection tracking hash table, a divider of | ||||
| 16384 becomes inadequate for a router handling lots of connections. Divide by | ||||
| 2048 instead, making the default size scale better with the available RAM. | ||||
| 
 | ||||
| Signed-off-by: Rui Salvaterra <rsalvaterra@gmail.com> | ||||
| ---
 | ||||
|  net/netfilter/nf_conntrack_core.c | 2 +- | ||||
|  1 file changed, 1 insertion(+), 1 deletion(-) | ||||
| 
 | ||||
| --- a/net/netfilter/nf_conntrack_core.c
 | ||||
| +++ b/net/netfilter/nf_conntrack_core.c
 | ||||
| @@ -2682,7 +2682,7 @@ int nf_conntrack_init_start(void)
 | ||||
|   | ||||
|  	if (!nf_conntrack_htable_size) { | ||||
|  		nf_conntrack_htable_size | ||||
| -			= (((nr_pages << PAGE_SHIFT) / 16384)
 | ||||
| +			= (((nr_pages << PAGE_SHIFT) / 2048)
 | ||||
|  			   / sizeof(struct hlist_head)); | ||||
|  		if (BITS_PER_LONG >= 64 && | ||||
|  		    nr_pages > (4 * (1024 * 1024 * 1024 / PAGE_SIZE))) | ||||
|  | @ -0,0 +1,131 @@ | |||
| From 36e516290611e613aa92996cb4339561452695b4 Mon Sep 17 00:00:00 2001 | ||||
| From: Felix Fietkau <nbd@nbd.name> | ||||
| Date: Fri, 7 Jul 2017 17:24:23 +0200 | ||||
| Subject: net: swconfig: adds openwrt switch layer | ||||
| 
 | ||||
| Signed-off-by: Felix Fietkau <nbd@nbd.name> | ||||
| ---
 | ||||
|  drivers/net/phy/Kconfig   | 83 +++++++++++++++++++++++++++++++++++++++++++++++ | ||||
|  drivers/net/phy/Makefile  | 15 +++++++++ | ||||
|  include/uapi/linux/Kbuild |  1 + | ||||
|  3 files changed, 99 insertions(+) | ||||
| 
 | ||||
| --- a/drivers/net/phy/Kconfig
 | ||||
| +++ b/drivers/net/phy/Kconfig
 | ||||
| @@ -66,6 +66,80 @@ config SFP
 | ||||
|  	depends on HWMON || HWMON=n | ||||
|  	select MDIO_I2C | ||||
|   | ||||
| +comment "Switch configuration API + drivers"
 | ||||
| +
 | ||||
| +config SWCONFIG
 | ||||
| +	tristate "Switch configuration API"
 | ||||
| +	help
 | ||||
| +	  Switch configuration API using netlink. This allows
 | ||||
| +	  you to configure the VLAN features of certain switches.
 | ||||
| +
 | ||||
| +config SWCONFIG_LEDS
 | ||||
| +	bool "Switch LED trigger support"
 | ||||
| +	depends on (SWCONFIG && LEDS_TRIGGERS)
 | ||||
| +
 | ||||
| +config ADM6996_PHY
 | ||||
| +	tristate "Driver for ADM6996 switches"
 | ||||
| +	select SWCONFIG
 | ||||
| +	help
 | ||||
| +	  Currently supports the ADM6996FC and ADM6996M switches.
 | ||||
| +	  Support for FC is very limited.
 | ||||
| +
 | ||||
| +config AR8216_PHY
 | ||||
| +	tristate "Driver for Atheros AR8216/8327 switches"
 | ||||
| +	select SWCONFIG
 | ||||
| +	select ETHERNET_PACKET_MANGLE
 | ||||
| +
 | ||||
| +config AR8216_PHY_LEDS
 | ||||
| +	bool "Atheros AR8216 switch LED support"
 | ||||
| +	depends on (AR8216_PHY && LEDS_CLASS)
 | ||||
| +
 | ||||
| +source "drivers/net/phy/b53/Kconfig"
 | ||||
| +
 | ||||
| +config IP17XX_PHY
 | ||||
| +	tristate "Driver for IC+ IP17xx switches"
 | ||||
| +	select SWCONFIG
 | ||||
| +
 | ||||
| +config PSB6970_PHY
 | ||||
| +	tristate "Lantiq XWAY Tantos (PSB6970) Ethernet switch"
 | ||||
| +	select SWCONFIG
 | ||||
| +
 | ||||
| +config RTL8306_PHY
 | ||||
| +	tristate "Driver for Realtek RTL8306S switches"
 | ||||
| +	select SWCONFIG
 | ||||
| +
 | ||||
| +config RTL8366_SMI
 | ||||
| +	tristate "Driver for the RTL8366 SMI interface"
 | ||||
| +	depends on GPIOLIB
 | ||||
| +	help
 | ||||
| +	  This module implements the SMI interface protocol which is used
 | ||||
| +	  by some RTL8366 ethernet switch devices via the generic GPIO API.
 | ||||
| +
 | ||||
| +if RTL8366_SMI
 | ||||
| +
 | ||||
| +config RTL8366_SMI_DEBUG_FS
 | ||||
| +	bool "RTL8366 SMI interface debugfs support"
 | ||||
| +        depends on DEBUG_FS
 | ||||
| +        default n
 | ||||
| +
 | ||||
| +config RTL8366S_PHY
 | ||||
| +	tristate "Driver for the Realtek RTL8366S switch"
 | ||||
| +	select SWCONFIG
 | ||||
| +
 | ||||
| +config RTL8366RB_PHY
 | ||||
| +	tristate "Driver for the Realtek RTL8366RB switch"
 | ||||
| +	select SWCONFIG
 | ||||
| +
 | ||||
| +config RTL8367_PHY
 | ||||
| +	tristate "Driver for the Realtek RTL8367R/M switches"
 | ||||
| +	select SWCONFIG
 | ||||
| +
 | ||||
| +config RTL8367B_PHY
 | ||||
| +	tristate "Driver fot the Realtek RTL8367R-VB switch"
 | ||||
| +	select SWCONFIG
 | ||||
| +
 | ||||
| +endif # RTL8366_SMI
 | ||||
| +
 | ||||
|  comment "MII PHY device drivers" | ||||
|   | ||||
|  config AIR_EN8811H_PHY | ||||
| --- a/drivers/net/phy/Makefile
 | ||||
| +++ b/drivers/net/phy/Makefile
 | ||||
| @@ -26,6 +26,21 @@ libphy-$(CONFIG_LED_TRIGGER_PHY)	+= phy_
 | ||||
|  obj-$(CONFIG_PHYLINK)		+= phylink.o | ||||
|  obj-$(CONFIG_PHYLIB)		+= libphy.o | ||||
|   | ||||
| +obj-$(CONFIG_SWCONFIG)		+= swconfig.o
 | ||||
| +obj-$(CONFIG_ADM6996_PHY)	+= adm6996.o
 | ||||
| +obj-$(CONFIG_AR8216_PHY)	+= ar8xxx.o
 | ||||
| +ar8xxx-y			+= ar8216.o
 | ||||
| +ar8xxx-y			+= ar8327.o
 | ||||
| +obj-$(CONFIG_SWCONFIG_B53)	+= b53/
 | ||||
| +obj-$(CONFIG_IP17XX_PHY)	+= ip17xx.o
 | ||||
| +obj-$(CONFIG_PSB6970_PHY)	+= psb6970.o
 | ||||
| +obj-$(CONFIG_RTL8306_PHY)	+= rtl8306.o
 | ||||
| +obj-$(CONFIG_RTL8366_SMI)	+= rtl8366_smi.o
 | ||||
| +obj-$(CONFIG_RTL8366S_PHY)	+= rtl8366s.o
 | ||||
| +obj-$(CONFIG_RTL8366RB_PHY)	+= rtl8366rb.o
 | ||||
| +obj-$(CONFIG_RTL8367_PHY)	+= rtl8367.o
 | ||||
| +obj-$(CONFIG_RTL8367B_PHY)	+= rtl8367b.o
 | ||||
| +
 | ||||
|  obj-$(CONFIG_NETWORK_PHY_TIMESTAMPING) += mii_timestamper.o | ||||
|   | ||||
|  obj-$(CONFIG_SFP)		+= sfp.o | ||||
| --- a/include/linux/platform_data/b53.h
 | ||||
| +++ b/include/linux/platform_data/b53.h
 | ||||
| @@ -29,6 +29,9 @@ struct b53_platform_data {
 | ||||
|  	u32 chip_id; | ||||
|  	u16 enabled_ports; | ||||
|   | ||||
| +	/* allow to specify an ethX alias */
 | ||||
| +	const char *alias;
 | ||||
| +
 | ||||
|  	/* only used by MMAP'd driver */ | ||||
|  	unsigned big_endian:1; | ||||
|  	void __iomem *regs; | ||||
|  | @ -0,0 +1,21 @@ | |||
| From ebd924d773223593142d417c41d4ee6fa16f1805 Mon Sep 17 00:00:00 2001 | ||||
| From: OpenWrt community <openwrt-devel@lists.openwrt.org> | ||||
| Date: Wed, 13 Jul 2022 13:45:56 +0200 | ||||
| Subject: [PATCH] net/dsa/mv88e6xxx: disable ATU violation | ||||
| 
 | ||||
| ---
 | ||||
|  drivers/net/dsa/mv88e6xxx/chip.c | 3 +++ | ||||
|  1 file changed, 3 insertions(+) | ||||
| 
 | ||||
| --- a/drivers/net/dsa/mv88e6xxx/chip.c
 | ||||
| +++ b/drivers/net/dsa/mv88e6xxx/chip.c
 | ||||
| @@ -3375,6 +3375,9 @@ static int mv88e6xxx_setup_port(struct m
 | ||||
|  	else | ||||
|  		reg = 1 << port; | ||||
|   | ||||
| +	/* Disable ATU member violation interrupt */
 | ||||
| +	reg |= MV88E6XXX_PORT_ASSOC_VECTOR_IGNORE_WRONG;
 | ||||
| +
 | ||||
|  	err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_ASSOC_VECTOR, | ||||
|  				   reg); | ||||
|  	if (err) | ||||
|  | @ -0,0 +1,167 @@ | |||
| From ffe387740bbe88dd88bbe04d6375902708003d6e Mon Sep 17 00:00:00 2001 | ||||
| From: Felix Fietkau <nbd@nbd.name> | ||||
| Date: Fri, 7 Jul 2017 17:25:00 +0200 | ||||
| Subject: net: add packet mangeling | ||||
| 
 | ||||
| ar8216 switches have a hardware bug, which renders normal 802.1q support | ||||
| unusable. Packet mangling is required to fix up the vlan for incoming | ||||
| packets. | ||||
| 
 | ||||
| Signed-off-by: Felix Fietkau <nbd@nbd.name> | ||||
| ---
 | ||||
|  include/linux/netdevice.h | 11 +++++++++++ | ||||
|  include/linux/skbuff.h    | 14 ++++---------- | ||||
|  net/Kconfig               |  6 ++++++ | ||||
|  net/core/dev.c            | 20 +++++++++++++++----- | ||||
|  net/core/skbuff.c         | 17 +++++++++++++++++ | ||||
|  net/ethernet/eth.c        |  6 ++++++ | ||||
|  6 files changed, 59 insertions(+), 15 deletions(-) | ||||
| 
 | ||||
| --- a/include/linux/netdevice.h
 | ||||
| +++ b/include/linux/netdevice.h
 | ||||
| @@ -1758,6 +1758,7 @@ enum netdev_priv_flags {
 | ||||
|  	IFF_TX_SKB_NO_LINEAR		= BIT_ULL(31), | ||||
|  	IFF_CHANGE_PROTO_DOWN		= BIT_ULL(32), | ||||
|  	IFF_SEE_ALL_HWTSTAMP_REQUESTS	= BIT_ULL(33), | ||||
| +	IFF_NO_IP_ALIGN			= BIT_ULL(34),
 | ||||
|  }; | ||||
|   | ||||
|  #define IFF_802_1Q_VLAN			IFF_802_1Q_VLAN | ||||
| @@ -1791,6 +1792,7 @@ enum netdev_priv_flags {
 | ||||
|  #define IFF_FAILOVER_SLAVE		IFF_FAILOVER_SLAVE | ||||
|  #define IFF_L3MDEV_RX_HANDLER		IFF_L3MDEV_RX_HANDLER | ||||
|  #define IFF_TX_SKB_NO_LINEAR		IFF_TX_SKB_NO_LINEAR | ||||
| +#define IFF_NO_IP_ALIGN		IFF_NO_IP_ALIGN
 | ||||
|   | ||||
|  /* Specifies the type of the struct net_device::ml_priv pointer */ | ||||
|  enum netdev_ml_priv_type { | ||||
| @@ -2183,6 +2185,11 @@ struct net_device {
 | ||||
|  	const struct tlsdev_ops *tlsdev_ops; | ||||
|  #endif | ||||
|   | ||||
| +#ifdef CONFIG_ETHERNET_PACKET_MANGLE
 | ||||
| +	void (*eth_mangle_rx)(struct net_device *dev, struct sk_buff *skb);
 | ||||
| +	struct sk_buff *(*eth_mangle_tx)(struct net_device *dev, struct sk_buff *skb);
 | ||||
| +#endif
 | ||||
| +
 | ||||
|  	const struct header_ops *header_ops; | ||||
|   | ||||
|  	unsigned char		operstate; | ||||
| @@ -2256,6 +2263,10 @@ struct net_device {
 | ||||
|  	struct mctp_dev __rcu	*mctp_ptr; | ||||
|  #endif | ||||
|   | ||||
| +#ifdef CONFIG_ETHERNET_PACKET_MANGLE
 | ||||
| +	void			*phy_ptr; /* PHY device specific data */
 | ||||
| +#endif
 | ||||
| +
 | ||||
|  /* | ||||
|   * Cache lines mostly used on receive path (including eth_type_trans()) | ||||
|   */ | ||||
| --- a/include/linux/skbuff.h
 | ||||
| +++ b/include/linux/skbuff.h
 | ||||
| @@ -3095,6 +3095,10 @@ static inline int pskb_trim(struct sk_bu
 | ||||
|  	return (len < skb->len) ? __pskb_trim(skb, len) : 0; | ||||
|  } | ||||
|   | ||||
| +extern struct sk_buff *__netdev_alloc_skb_ip_align(struct net_device *dev,
 | ||||
| +		unsigned int length, gfp_t gfp);
 | ||||
| +
 | ||||
| +
 | ||||
|  /** | ||||
|   *	pskb_trim_unique - remove end from a paged unique (not cloned) buffer | ||||
|   *	@skb: buffer to alter | ||||
| @@ -3260,16 +3264,6 @@ static inline struct sk_buff *dev_alloc_
 | ||||
|  } | ||||
|   | ||||
|   | ||||
| -static inline struct sk_buff *__netdev_alloc_skb_ip_align(struct net_device *dev,
 | ||||
| -		unsigned int length, gfp_t gfp)
 | ||||
| -{
 | ||||
| -	struct sk_buff *skb = __netdev_alloc_skb(dev, length + NET_IP_ALIGN, gfp);
 | ||||
| -
 | ||||
| -	if (NET_IP_ALIGN && skb)
 | ||||
| -		skb_reserve(skb, NET_IP_ALIGN);
 | ||||
| -	return skb;
 | ||||
| -}
 | ||||
| -
 | ||||
|  static inline struct sk_buff *netdev_alloc_skb_ip_align(struct net_device *dev, | ||||
|  		unsigned int length) | ||||
|  { | ||||
| --- a/net/Kconfig
 | ||||
| +++ b/net/Kconfig
 | ||||
| @@ -26,6 +26,12 @@ menuconfig NET
 | ||||
|   | ||||
|  if NET | ||||
|   | ||||
| +config ETHERNET_PACKET_MANGLE
 | ||||
| +	bool
 | ||||
| +	help
 | ||||
| +	  This option can be selected by phy drivers that need to mangle
 | ||||
| +	  packets going in or out of an ethernet device.
 | ||||
| +
 | ||||
|  config WANT_COMPAT_NETLINK_MESSAGES | ||||
|  	bool | ||||
|  	help | ||||
| --- a/net/core/dev.c
 | ||||
| +++ b/net/core/dev.c
 | ||||
| @@ -3597,6 +3597,11 @@ static int xmit_one(struct sk_buff *skb,
 | ||||
|  	if (dev_nit_active(dev)) | ||||
|  		dev_queue_xmit_nit(skb, dev); | ||||
|   | ||||
| +#ifdef CONFIG_ETHERNET_PACKET_MANGLE
 | ||||
| +	if (dev->eth_mangle_tx && !(skb = dev->eth_mangle_tx(dev, skb)))
 | ||||
| +		return NETDEV_TX_OK;
 | ||||
| +#endif
 | ||||
| +
 | ||||
|  	len = skb->len; | ||||
|  	trace_net_dev_start_xmit(skb, dev); | ||||
|  	rc = netdev_start_xmit(skb, dev, txq, more); | ||||
| --- a/net/core/skbuff.c
 | ||||
| +++ b/net/core/skbuff.c
 | ||||
| @@ -62,6 +62,7 @@
 | ||||
|  #include <linux/if_vlan.h> | ||||
|  #include <linux/mpls.h> | ||||
|  #include <linux/kcov.h> | ||||
| +#include <linux/if.h>
 | ||||
|   | ||||
|  #include <net/protocol.h> | ||||
|  #include <net/dst.h> | ||||
| @@ -844,6 +845,22 @@ skb_fail:
 | ||||
|  } | ||||
|  EXPORT_SYMBOL(__napi_alloc_skb); | ||||
|   | ||||
| +struct sk_buff *__netdev_alloc_skb_ip_align(struct net_device *dev,
 | ||||
| +		unsigned int length, gfp_t gfp)
 | ||||
| +{
 | ||||
| +	struct sk_buff *skb = __netdev_alloc_skb(dev, length + NET_IP_ALIGN, gfp);
 | ||||
| +
 | ||||
| +#ifdef CONFIG_ETHERNET_PACKET_MANGLE
 | ||||
| +	if (dev && (dev->priv_flags & IFF_NO_IP_ALIGN))
 | ||||
| +		return skb;
 | ||||
| +#endif
 | ||||
| +
 | ||||
| +	if (NET_IP_ALIGN && skb)
 | ||||
| +		skb_reserve(skb, NET_IP_ALIGN);
 | ||||
| +	return skb;
 | ||||
| +}
 | ||||
| +EXPORT_SYMBOL(__netdev_alloc_skb_ip_align);
 | ||||
| +
 | ||||
|  void skb_add_rx_frag(struct sk_buff *skb, int i, struct page *page, int off, | ||||
|  		     int size, unsigned int truesize) | ||||
|  { | ||||
| --- a/net/ethernet/eth.c
 | ||||
| +++ b/net/ethernet/eth.c
 | ||||
| @@ -159,6 +159,12 @@ __be16 eth_type_trans(struct sk_buff *sk
 | ||||
|  	const struct ethhdr *eth; | ||||
|   | ||||
|  	skb->dev = dev; | ||||
| +
 | ||||
| +#ifdef CONFIG_ETHERNET_PACKET_MANGLE
 | ||||
| +	if (dev->eth_mangle_rx)
 | ||||
| +		dev->eth_mangle_rx(dev, skb);
 | ||||
| +#endif
 | ||||
| +
 | ||||
|  	skb_reset_mac_header(skb); | ||||
|   | ||||
|  	eth = (struct ethhdr *)skb->data; | ||||
|  | @ -0,0 +1,117 @@ | |||
| From 5f62951fba63a9f9cfff564209426bdea5fcc371 Mon Sep 17 00:00:00 2001 | ||||
| From: Alex Marginean <alexandru.marginean@nxp.com> | ||||
| Date: Tue, 27 Aug 2019 15:16:56 +0300 | ||||
| Subject: [PATCH] drivers: net: phy: aquantia: enable AQR112 and AQR412 | ||||
| 
 | ||||
| Adds support for AQR112 and AQR412 which is mostly based on existing code | ||||
| with the addition of code configuring the protocol on system side. | ||||
| This allows changing the system side protocol without having to deploy a | ||||
| different firmware on the PHY.
 | ||||
| 
 | ||||
| Signed-off-by: Alex Marginean <alexandru.marginean@nxp.com> | ||||
| ---
 | ||||
|  drivers/net/phy/aquantia/aquantia_main.c | 88 +++++++++++++++++++++++++++++++++++++++++ | ||||
|  1 file changed, 88 insertions(+) | ||||
| 
 | ||||
| --- a/drivers/net/phy/aquantia/aquantia_main.c
 | ||||
| +++ b/drivers/net/phy/aquantia/aquantia_main.c
 | ||||
| @@ -127,6 +127,29 @@ struct aqr107_priv {
 | ||||
|  	u64 sgmii_stats[AQR107_SGMII_STAT_SZ]; | ||||
|  }; | ||||
|   | ||||
| +/* registers in MDIO_MMD_VEND1 region */
 | ||||
| +#define AQUANTIA_VND1_GLOBAL_SC			0x000
 | ||||
| +#define  AQUANTIA_VND1_GLOBAL_SC_LP		BIT(0xb)
 | ||||
| +
 | ||||
| +/* global start rate, the protocol associated with this speed is used by default
 | ||||
| + * on SI.
 | ||||
| + */
 | ||||
| +#define AQUANTIA_VND1_GSTART_RATE		0x31a
 | ||||
| +#define  AQUANTIA_VND1_GSTART_RATE_OFF		0
 | ||||
| +#define  AQUANTIA_VND1_GSTART_RATE_100M		1
 | ||||
| +#define  AQUANTIA_VND1_GSTART_RATE_1G		2
 | ||||
| +#define  AQUANTIA_VND1_GSTART_RATE_10G		3
 | ||||
| +#define  AQUANTIA_VND1_GSTART_RATE_2_5G		4
 | ||||
| +#define  AQUANTIA_VND1_GSTART_RATE_5G		5
 | ||||
| +
 | ||||
| +/* SYSCFG registers for 100M, 1G, 2.5G, 5G, 10G */
 | ||||
| +#define AQUANTIA_VND1_GSYSCFG_BASE		0x31b
 | ||||
| +#define AQUANTIA_VND1_GSYSCFG_100M		0
 | ||||
| +#define AQUANTIA_VND1_GSYSCFG_1G		1
 | ||||
| +#define AQUANTIA_VND1_GSYSCFG_2_5G		2
 | ||||
| +#define AQUANTIA_VND1_GSYSCFG_5G		3
 | ||||
| +#define AQUANTIA_VND1_GSYSCFG_10G		4
 | ||||
| +
 | ||||
|  static int aqr107_get_sset_count(struct phy_device *phydev) | ||||
|  { | ||||
|  	return AQR107_SGMII_STAT_SZ; | ||||
| @@ -233,6 +256,51 @@ static int aqr_config_aneg(struct phy_de
 | ||||
|  	return genphy_c45_check_and_restart_aneg(phydev, changed); | ||||
|  } | ||||
|   | ||||
| +static struct {
 | ||||
| +	u16 syscfg;
 | ||||
| +	int cnt;
 | ||||
| +	u16 start_rate;
 | ||||
| +} aquantia_syscfg[PHY_INTERFACE_MODE_MAX] = {
 | ||||
| +	[PHY_INTERFACE_MODE_SGMII] =      {0x04b, AQUANTIA_VND1_GSYSCFG_1G,
 | ||||
| +					   AQUANTIA_VND1_GSTART_RATE_1G},
 | ||||
| +	[PHY_INTERFACE_MODE_2500BASEX] = {0x144, AQUANTIA_VND1_GSYSCFG_2_5G,
 | ||||
| +					   AQUANTIA_VND1_GSTART_RATE_2_5G},
 | ||||
| +	[PHY_INTERFACE_MODE_XGMII] =      {0x100, AQUANTIA_VND1_GSYSCFG_10G,
 | ||||
| +					   AQUANTIA_VND1_GSTART_RATE_10G},
 | ||||
| +	[PHY_INTERFACE_MODE_USXGMII] =    {0x080, AQUANTIA_VND1_GSYSCFG_10G,
 | ||||
| +					   AQUANTIA_VND1_GSTART_RATE_10G},
 | ||||
| +};
 | ||||
| +
 | ||||
| +/* Sets up protocol on system side before calling aqr_config_aneg */
 | ||||
| +static int aqr_config_aneg_set_prot(struct phy_device *phydev)
 | ||||
| +{
 | ||||
| +	int if_type = phydev->interface;
 | ||||
| +	int i;
 | ||||
| +
 | ||||
| +	if (!aquantia_syscfg[if_type].cnt)
 | ||||
| +		return 0;
 | ||||
| +
 | ||||
| +	/* set PHY in low power mode so we can configure protocols */
 | ||||
| +	phy_write_mmd(phydev, MDIO_MMD_VEND1, AQUANTIA_VND1_GLOBAL_SC,
 | ||||
| +		      AQUANTIA_VND1_GLOBAL_SC_LP);
 | ||||
| +	mdelay(10);
 | ||||
| +
 | ||||
| +	/* set the default rate to enable the SI link */
 | ||||
| +	phy_write_mmd(phydev, MDIO_MMD_VEND1, AQUANTIA_VND1_GSTART_RATE,
 | ||||
| +		      aquantia_syscfg[if_type].start_rate);
 | ||||
| +
 | ||||
| +	for (i = 0; i <= aquantia_syscfg[if_type].cnt; i++)
 | ||||
| +		phy_write_mmd(phydev, MDIO_MMD_VEND1,
 | ||||
| +			      AQUANTIA_VND1_GSYSCFG_BASE + i,
 | ||||
| +			      aquantia_syscfg[if_type].syscfg);
 | ||||
| +
 | ||||
| +	/* wake PHY back up */
 | ||||
| +	phy_write_mmd(phydev, MDIO_MMD_VEND1, AQUANTIA_VND1_GLOBAL_SC, 0);
 | ||||
| +	mdelay(10);
 | ||||
| +
 | ||||
| +	return aqr_config_aneg(phydev);
 | ||||
| +}
 | ||||
| +
 | ||||
|  static int aqr_config_intr(struct phy_device *phydev) | ||||
|  { | ||||
|  	bool en = phydev->interrupts == PHY_INTERRUPT_ENABLED; | ||||
| @@ -838,7 +906,7 @@ static struct phy_driver aqr_driver[] =
 | ||||
|  	PHY_ID_MATCH_MODEL(PHY_ID_AQR112), | ||||
|  	.name		= "Aquantia AQR112", | ||||
|  	.probe		= aqr107_probe, | ||||
| -	.config_aneg    = aqr_config_aneg,
 | ||||
| +	.config_aneg    = aqr_config_aneg_set_prot,
 | ||||
|  	.config_intr	= aqr_config_intr, | ||||
|  	.handle_interrupt = aqr_handle_interrupt, | ||||
|  	.get_tunable    = aqr107_get_tunable, | ||||
| @@ -863,7 +931,7 @@ static struct phy_driver aqr_driver[] =
 | ||||
|  	PHY_ID_MATCH_MODEL(PHY_ID_AQR412), | ||||
|  	.name		= "Aquantia AQR412", | ||||
|  	.probe		= aqr107_probe, | ||||
| -	.config_aneg    = aqr_config_aneg,
 | ||||
| +	.config_aneg    = aqr_config_aneg_set_prot,
 | ||||
|  	.config_intr	= aqr_config_intr, | ||||
|  	.handle_interrupt = aqr_handle_interrupt, | ||||
|  	.get_tunable    = aqr107_get_tunable, | ||||
|  | @ -0,0 +1,34 @@ | |||
| From 5f008cb22f60da4e10375f22266c1a4e20b1252e Mon Sep 17 00:00:00 2001 | ||||
| From: Alex Marginean <alexandru.marginean@nxp.com> | ||||
| Date: Fri, 20 Sep 2019 18:22:52 +0300 | ||||
| Subject: [PATCH] drivers: net: phy: aquantia: fix system side protocol | ||||
|  misconfiguration | ||||
| 
 | ||||
| Do not set up protocols for speeds that are not supported by FW.  Enabling | ||||
| these protocols leads to link issues on system side. | ||||
| 
 | ||||
| Signed-off-by: Alex Marginean <alexandru.marginean@nxp.com> | ||||
| ---
 | ||||
|  drivers/net/phy/aquantia/aquantia_main.c | 8 +++++++- | ||||
|  1 file changed, 7 insertions(+), 1 deletion(-) | ||||
| 
 | ||||
| --- a/drivers/net/phy/aquantia/aquantia_main.c
 | ||||
| +++ b/drivers/net/phy/aquantia/aquantia_main.c
 | ||||
| @@ -289,10 +289,16 @@ static int aqr_config_aneg_set_prot(stru
 | ||||
|  	phy_write_mmd(phydev, MDIO_MMD_VEND1, AQUANTIA_VND1_GSTART_RATE, | ||||
|  		      aquantia_syscfg[if_type].start_rate); | ||||
|   | ||||
| -	for (i = 0; i <= aquantia_syscfg[if_type].cnt; i++)
 | ||||
| +	for (i = 0; i <= aquantia_syscfg[if_type].cnt; i++) {
 | ||||
| +		u16 reg = phy_read_mmd(phydev, MDIO_MMD_VEND1,
 | ||||
| +				       AQUANTIA_VND1_GSYSCFG_BASE + i);
 | ||||
| +		if (!reg)
 | ||||
| +			continue;
 | ||||
| +
 | ||||
|  		phy_write_mmd(phydev, MDIO_MMD_VEND1, | ||||
|  			      AQUANTIA_VND1_GSYSCFG_BASE + i, | ||||
|  			      aquantia_syscfg[if_type].syscfg); | ||||
| +	}
 | ||||
|   | ||||
|  	/* wake PHY back up */ | ||||
|  	phy_write_mmd(phydev, MDIO_MMD_VEND1, AQUANTIA_VND1_GLOBAL_SC, 0); | ||||
|  | @ -0,0 +1,63 @@ | |||
| From 3b92ee7b7899b6beffb2b484c58326e36612a873 Mon Sep 17 00:00:00 2001 | ||||
| From: Daniel Golle <daniel@makrotopia.org> | ||||
| Date: Thu, 23 Dec 2021 14:52:56 +0000 | ||||
| Subject: [PATCH] net: phy: aquantia: add PHY_ID for AQR112R | ||||
| 
 | ||||
| As advised by Ian Chang this PHY is used in Puzzle devices. | ||||
| 
 | ||||
| Signed-off-by: Daniel Golle <daniel@makrotopia.org> | ||||
| ---
 | ||||
|  drivers/net/phy/aquantia/aquantia_main.c | 10 ++++++++++ | ||||
|  1 file changed, 10 insertions(+) | ||||
| 
 | ||||
| --- a/drivers/net/phy/aquantia/aquantia_main.c
 | ||||
| +++ b/drivers/net/phy/aquantia/aquantia_main.c
 | ||||
| @@ -30,6 +30,8 @@
 | ||||
|  #define PHY_ID_AQR113C	0x31c31c12 | ||||
|  #define PHY_ID_AQR114C	0x31c31c22 | ||||
|  #define PHY_ID_AQR813	0x31c31cb2 | ||||
| +#define PHY_ID_AQR112C	0x03a1b790
 | ||||
| +#define PHY_ID_AQR112R	0x31c31d12
 | ||||
|   | ||||
|  #define MDIO_PHYXS_VEND_IF_STATUS		0xe812 | ||||
|  #define MDIO_PHYXS_VEND_IF_STATUS_TYPE_MASK	GENMASK(7, 3) | ||||
| @@ -1062,6 +1064,30 @@ static struct phy_driver aqr_driver[] =
 | ||||
|  	.led_polarity_set = aqr_phy_led_polarity_set, | ||||
|  #endif | ||||
|  }, | ||||
| +{
 | ||||
| +	PHY_ID_MATCH_MODEL(PHY_ID_AQR112C),
 | ||||
| +	.name		= "Aquantia AQR112C",
 | ||||
| +	.probe		= aqr107_probe,
 | ||||
| +	.config_aneg	= aqr_config_aneg_set_prot,
 | ||||
| +	.config_intr	= aqr_config_intr,
 | ||||
| +	.handle_interrupt = aqr_handle_interrupt,
 | ||||
| +	.read_status	= aqr107_read_status,
 | ||||
| +	.get_sset_count	= aqr107_get_sset_count,
 | ||||
| +	.get_strings	= aqr107_get_strings,
 | ||||
| +	.get_stats	= aqr107_get_stats,
 | ||||
| +},
 | ||||
| +{
 | ||||
| +	PHY_ID_MATCH_MODEL(PHY_ID_AQR112R),
 | ||||
| +	.name		= "Aquantia AQR112R",
 | ||||
| +	.probe		= aqr107_probe,
 | ||||
| +	.config_aneg	= aqr_config_aneg_set_prot,
 | ||||
| +	.config_intr	= aqr_config_intr,
 | ||||
| +	.handle_interrupt = aqr_handle_interrupt,
 | ||||
| +	.read_status	= aqr107_read_status,
 | ||||
| +	.get_sset_count	= aqr107_get_sset_count,
 | ||||
| +	.get_strings	= aqr107_get_strings,
 | ||||
| +	.get_stats	= aqr107_get_stats,
 | ||||
| +},
 | ||||
|  }; | ||||
|   | ||||
|  module_phy_driver(aqr_driver); | ||||
| @@ -1082,6 +1108,8 @@ static struct mdio_device_id __maybe_unu
 | ||||
|  	{ PHY_ID_MATCH_MODEL(PHY_ID_AQR113C) }, | ||||
|  	{ PHY_ID_MATCH_MODEL(PHY_ID_AQR114C) }, | ||||
|  	{ PHY_ID_MATCH_MODEL(PHY_ID_AQR813) }, | ||||
| +	{ PHY_ID_MATCH_MODEL(PHY_ID_AQR112C) },
 | ||||
| +	{ PHY_ID_MATCH_MODEL(PHY_ID_AQR112R) },
 | ||||
|  	{ } | ||||
|  }; | ||||
|   | ||||
|  | @ -0,0 +1,64 @@ | |||
| From 880d1311335120f64447ca9d11933872d734e19a Mon Sep 17 00:00:00 2001 | ||||
| From: Daniel Golle <daniel@makrotopia.org> | ||||
| Date: Mon, 27 Mar 2023 18:41:54 +0100 | ||||
| Subject: [PATCH] generic: pcs-mtk-lynxi: add hack to use 2500Base-X without AN | ||||
| 
 | ||||
| Using 2500Base-T SFP modules e.g. on the BananaPi R3 requires manually | ||||
| disabling auto-negotiation, e.g. using ethtool. While a proper fix | ||||
| using SFP quirks is being discussed upstream, bring a work-around to | ||||
| restore user experience to what it was before the switch to the | ||||
| dedicated SGMII PCS driver. | ||||
| 
 | ||||
| Signed-off-by: Daniel Golle <daniel@makrotopia.org> | ||||
| 
 | ||||
| --- a/drivers/net/pcs/pcs-mtk-lynxi.c
 | ||||
| +++ b/drivers/net/pcs/pcs-mtk-lynxi.c
 | ||||
| @@ -114,14 +114,23 @@ static void mtk_pcs_lynxi_get_state(stru
 | ||||
|  				    struct phylink_link_state *state) | ||||
|  { | ||||
|  	struct mtk_pcs_lynxi *mpcs = pcs_to_mtk_pcs_lynxi(pcs); | ||||
| -	unsigned int bm, adv;
 | ||||
| +	unsigned int bm, bmsr, adv;
 | ||||
|   | ||||
|  	/* Read the BMSR and LPA */ | ||||
|  	regmap_read(mpcs->regmap, SGMSYS_PCS_CONTROL_1, &bm); | ||||
| -	regmap_read(mpcs->regmap, SGMSYS_PCS_ADVERTISE, &adv);
 | ||||
| +	bmsr = FIELD_GET(SGMII_BMSR, bm);
 | ||||
| +
 | ||||
| +	if (state->interface == PHY_INTERFACE_MODE_2500BASEX) {
 | ||||
| +		state->link = !!(bmsr & BMSR_LSTATUS);
 | ||||
| +		state->an_complete = !!(bmsr & BMSR_ANEGCOMPLETE);
 | ||||
| +		state->speed = SPEED_2500;
 | ||||
| +		state->duplex = DUPLEX_FULL;
 | ||||
| +
 | ||||
| +		return;
 | ||||
| +	}
 | ||||
|   | ||||
| -	phylink_mii_c22_pcs_decode_state(state, FIELD_GET(SGMII_BMSR, bm),
 | ||||
| -					 FIELD_GET(SGMII_LPA, adv));
 | ||||
| +	regmap_read(mpcs->regmap, SGMSYS_PCS_ADVERTISE, &adv);
 | ||||
| +	phylink_mii_c22_pcs_decode_state(state, bmsr, FIELD_GET(SGMII_LPA, adv));
 | ||||
|  } | ||||
|   | ||||
|  static void mtk_sgmii_reset(struct mtk_pcs_lynxi *mpcs) | ||||
| @@ -142,7 +151,7 @@ static int mtk_pcs_lynxi_config(struct p
 | ||||
|  { | ||||
|  	struct mtk_pcs_lynxi *mpcs = pcs_to_mtk_pcs_lynxi(pcs); | ||||
|  	bool mode_changed = false, changed; | ||||
| -	unsigned int rgc3, sgm_mode, bmcr;
 | ||||
| +	unsigned int rgc3, sgm_mode, bmcr = 0;
 | ||||
|  	int advertise, link_timer; | ||||
|   | ||||
|  	advertise = phylink_mii_c22_pcs_encode_advertisement(interface, | ||||
| @@ -165,9 +174,8 @@ static int mtk_pcs_lynxi_config(struct p
 | ||||
|  	if (neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED) { | ||||
|  		if (interface == PHY_INTERFACE_MODE_SGMII) | ||||
|  			sgm_mode |= SGMII_SPEED_DUPLEX_AN; | ||||
| -		bmcr = BMCR_ANENABLE;
 | ||||
| -	} else {
 | ||||
| -		bmcr = 0;
 | ||||
| +		if (interface != PHY_INTERFACE_MODE_2500BASEX)
 | ||||
| +			bmcr = BMCR_ANENABLE;
 | ||||
|  	} | ||||
|   | ||||
|  	if (mpcs->interface != interface) { | ||||
|  | @ -0,0 +1,74 @@ | |||
| From 82985725e071f2a5735052f18e109a32aeac3a0b Mon Sep 17 00:00:00 2001 | ||||
| From: David Bauer <mail@david-bauer.net> | ||||
| Date: Sun, 26 Jul 2020 02:38:31 +0200 | ||||
| Subject: [PATCH] net: usb: r8152: add LED configuration from OF | ||||
| 
 | ||||
| This adds the ability to configure the LED configuration register using | ||||
| OF. This way, the correct value for board specific LED configuration can | ||||
| be determined. | ||||
| 
 | ||||
| Signed-off-by: David Bauer <mail@david-bauer.net> | ||||
| ---
 | ||||
|  drivers/net/usb/r8152.c | 23 +++++++++++++++++++++++ | ||||
|  1 file changed, 23 insertions(+) | ||||
| 
 | ||||
| --- a/drivers/net/usb/r8152.c
 | ||||
| +++ b/drivers/net/usb/r8152.c
 | ||||
| @@ -11,6 +11,7 @@
 | ||||
|  #include <linux/mii.h> | ||||
|  #include <linux/ethtool.h> | ||||
|  #include <linux/usb.h> | ||||
| +#include <linux/of.h>
 | ||||
|  #include <linux/crc32.h> | ||||
|  #include <linux/if_vlan.h> | ||||
|  #include <linux/uaccess.h> | ||||
| @@ -7035,6 +7036,22 @@ static void rtl_tally_reset(struct r8152
 | ||||
|  	ocp_write_word(tp, MCU_TYPE_PLA, PLA_RSTTALLY, ocp_data); | ||||
|  } | ||||
|   | ||||
| +static int r8152_led_configuration(struct r8152 *tp)
 | ||||
| +{
 | ||||
| +	u32 led_data;
 | ||||
| +	int ret;
 | ||||
| +
 | ||||
| +	ret = of_property_read_u32(tp->udev->dev.of_node, "realtek,led-data",
 | ||||
| +								&led_data);
 | ||||
| +
 | ||||
| +	if (ret)
 | ||||
| +		return ret;
 | ||||
| +
 | ||||
| +	ocp_write_word(tp, MCU_TYPE_PLA, PLA_LEDSEL, led_data);
 | ||||
| +
 | ||||
| +	return 0;
 | ||||
| +}
 | ||||
| +
 | ||||
|  static void r8152b_init(struct r8152 *tp) | ||||
|  { | ||||
|  	u32 ocp_data; | ||||
| @@ -7076,6 +7093,8 @@ static void r8152b_init(struct r8152 *tp
 | ||||
|  	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_USB_CTRL); | ||||
|  	ocp_data &= ~(RX_AGG_DISABLE | RX_ZERO_EN); | ||||
|  	ocp_write_word(tp, MCU_TYPE_USB, USB_USB_CTRL, ocp_data); | ||||
| +
 | ||||
| +	r8152_led_configuration(tp);
 | ||||
|  } | ||||
|   | ||||
|  static void r8153_init(struct r8152 *tp) | ||||
| @@ -7216,6 +7235,8 @@ static void r8153_init(struct r8152 *tp)
 | ||||
|  		tp->coalesce = COALESCE_SLOW; | ||||
|  		break; | ||||
|  	} | ||||
| +
 | ||||
| +	r8152_led_configuration(tp);
 | ||||
|  } | ||||
|   | ||||
|  static void r8153b_init(struct r8152 *tp) | ||||
| @@ -7298,6 +7319,8 @@ static void r8153b_init(struct r8152 *tp
 | ||||
|  	rtl_tally_reset(tp); | ||||
|   | ||||
|  	tp->coalesce = 15000;	/* 15 us */ | ||||
| +
 | ||||
| +	r8152_led_configuration(tp);
 | ||||
|  } | ||||
|   | ||||
|  static void r8153c_init(struct r8152 *tp) | ||||
|  | @ -0,0 +1,54 @@ | |||
| From 3ee05f4aa64fc86af3be5bc176ba5808de9260a7 Mon Sep 17 00:00:00 2001 | ||||
| From: David Bauer <mail@david-bauer.net> | ||||
| Date: Sun, 26 Jul 2020 15:30:33 +0200 | ||||
| Subject: [PATCH] dt-bindings: net: add RTL8152 binding documentation | ||||
| 
 | ||||
| Add binding documentation for the Realtek RTL8152 / RTL8153 USB ethernet | ||||
| adapters. | ||||
| 
 | ||||
| Signed-off-by: David Bauer <mail@david-bauer.net> | ||||
| ---
 | ||||
|  .../bindings/net/realtek,rtl8152.yaml         | 36 +++++++++++++++++++ | ||||
|  1 file changed, 36 insertions(+) | ||||
|  create mode 100644 Documentation/devicetree/bindings/net/realtek,rtl8152.yaml | ||||
| 
 | ||||
| --- /dev/null
 | ||||
| +++ b/Documentation/devicetree/bindings/net/realtek,rtl8152.yaml
 | ||||
| @@ -0,0 +1,36 @@
 | ||||
| +# SPDX-License-Identifier: GPL-2.0
 | ||||
| +%YAML 1.2
 | ||||
| +---
 | ||||
| +$id: http://devicetree.org/schemas/net/realtek,rtl8152.yaml#
 | ||||
| +$schema: http://devicetree.org/meta-schemas/core.yaml#
 | ||||
| +
 | ||||
| +title: Realtek RTL8152/RTL8153 series USB ethernet
 | ||||
| +
 | ||||
| +maintainers:
 | ||||
| +  - David Bauer <mail@david-bauer.net>
 | ||||
| +
 | ||||
| +properties:
 | ||||
| +  compatible:
 | ||||
| +    oneOf:
 | ||||
| +      - items:
 | ||||
| +          - enum:
 | ||||
| +              - realtek,rtl8152
 | ||||
| +              - realtek,rtl8153
 | ||||
| +
 | ||||
| +  reg:
 | ||||
| +    description: The device number on the USB bus
 | ||||
| +
 | ||||
| +  realtek,led-data:
 | ||||
| +    description: Value to be written to the LED configuration register.
 | ||||
| +
 | ||||
| +required:
 | ||||
| +  - compatible
 | ||||
| +  - reg
 | ||||
| +
 | ||||
| +examples:
 | ||||
| +  - |
 | ||||
| +    usb-eth@2 {
 | ||||
| +      compatible = "realtek,rtl8153";
 | ||||
| +      reg = <2>;
 | ||||
| +      realtek,led-data = <0x87>;
 | ||||
| +    };
 | ||||
| \ No newline at end of file | ||||
|  | @ -0,0 +1,105 @@ | |||
| From 94b90966095f3fa625897e8f53d215882f6e19b3 Mon Sep 17 00:00:00 2001 | ||||
| From: David Bauer <mail@david-bauer.net> | ||||
| Date: Sat, 11 Mar 2023 17:00:01 +0100 | ||||
| Subject: [PATCH] mxl-gpy: control LED reg from DT | ||||
| 
 | ||||
| Add dynamic configuration for the LED control registers on MXL PHYs. | ||||
| 
 | ||||
| This patch has been tested with MaxLinear GPY211C. It is unlikely to be | ||||
| accepted upstream, as upstream plans on integrating their own framework | ||||
| for handling these LEDs. | ||||
| 
 | ||||
| For the time being, use this hack to configure PHY driven device-LEDs to | ||||
| show the correct state. | ||||
| 
 | ||||
| A possible alternative might be to expose the LEDs using the kernel LED | ||||
| framework and bind it to the netdevice. This might also be upstreamable, | ||||
| although it is a considerable extra amount of work. | ||||
| 
 | ||||
| Signed-off-by: David Bauer <mail@david-bauer.net> | ||||
| ---
 | ||||
|  drivers/net/phy/mxl-gpy.c | 37 ++++++++++++++++++++++++++++++++++++- | ||||
|  1 file changed, 36 insertions(+), 1 deletion(-) | ||||
| 
 | ||||
| --- a/drivers/net/phy/mxl-gpy.c
 | ||||
| +++ b/drivers/net/phy/mxl-gpy.c
 | ||||
| @@ -10,6 +10,7 @@
 | ||||
|  #include <linux/bitfield.h> | ||||
|  #include <linux/hwmon.h> | ||||
|  #include <linux/mutex.h> | ||||
| +#include <linux/of.h>
 | ||||
|  #include <linux/phy.h> | ||||
|  #include <linux/polynomial.h> | ||||
|  #include <linux/property.h> | ||||
| @@ -38,6 +39,7 @@
 | ||||
|  #define PHY_MIISTAT		0x18	/* MII state */ | ||||
|  #define PHY_IMASK		0x19	/* interrupt mask */ | ||||
|  #define PHY_ISTAT		0x1A	/* interrupt status */ | ||||
| +#define PHY_LED			0x1B	/* LED control */
 | ||||
|  #define PHY_FWV			0x1E	/* firmware version */ | ||||
|   | ||||
|  #define PHY_MIISTAT_SPD_MASK	GENMASK(2, 0) | ||||
| @@ -61,10 +63,15 @@
 | ||||
|  				 PHY_IMASK_ADSC | \ | ||||
|  				 PHY_IMASK_ANC) | ||||
|   | ||||
| +#define PHY_LED_NUM_LEDS	4
 | ||||
| +
 | ||||
|  #define PHY_FWV_REL_MASK	BIT(15) | ||||
|  #define PHY_FWV_MAJOR_MASK	GENMASK(11, 8) | ||||
|  #define PHY_FWV_MINOR_MASK	GENMASK(7, 0) | ||||
|   | ||||
| +/* LED */
 | ||||
| +#define VSPEC1_LED(x)		(0x1 + x)
 | ||||
| +
 | ||||
|  #define PHY_PMA_MGBT_POLARITY	0x82 | ||||
|  #define PHY_MDI_MDI_X_MASK	GENMASK(1, 0) | ||||
|  #define PHY_MDI_MDI_X_NORMAL	0x3 | ||||
| @@ -260,6 +267,35 @@ out:
 | ||||
|  	return ret; | ||||
|  } | ||||
|   | ||||
| +static int gpy_led_write(struct phy_device *phydev)
 | ||||
| +{
 | ||||
| +	struct device_node *node = phydev->mdio.dev.of_node;
 | ||||
| +	u32 led_regs[PHY_LED_NUM_LEDS];
 | ||||
| +	int i, ret;
 | ||||
| +	u16 val = 0xff00;
 | ||||
| +
 | ||||
| +	if (!IS_ENABLED(CONFIG_OF_MDIO))
 | ||||
| +		return 0;
 | ||||
| +
 | ||||
| +	if (of_property_read_u32_array(node, "mxl,led-config", led_regs, PHY_LED_NUM_LEDS))
 | ||||
| +		return 0;
 | ||||
| +
 | ||||
| +	if (of_property_read_bool(node, "mxl,led-drive-vdd"))
 | ||||
| +		val &= 0x0fff;
 | ||||
| +
 | ||||
| +	/* Enable LED function handling on all ports*/
 | ||||
| +	phy_write(phydev, PHY_LED, val);
 | ||||
| +
 | ||||
| +	/* Write LED register values */
 | ||||
| +	for (i = 0; i < PHY_LED_NUM_LEDS; i++) {
 | ||||
| +		ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, VSPEC1_LED(i), (u16)led_regs[i]);
 | ||||
| +		if (ret < 0)
 | ||||
| +			return ret;
 | ||||
| +	}
 | ||||
| +
 | ||||
| +	return 0;
 | ||||
| +}
 | ||||
| +
 | ||||
|  static int gpy_config_init(struct phy_device *phydev) | ||||
|  { | ||||
|  	int ret; | ||||
| @@ -271,7 +307,10 @@ static int gpy_config_init(struct phy_de
 | ||||
|   | ||||
|  	/* Clear all pending interrupts */ | ||||
|  	ret = phy_read(phydev, PHY_ISTAT); | ||||
| -	return ret < 0 ? ret : 0;
 | ||||
| +	if (ret < 0)
 | ||||
| +		return ret;
 | ||||
| +
 | ||||
| +	return gpy_led_write(phydev);
 | ||||
|  } | ||||
|   | ||||
|  static int gpy_probe(struct phy_device *phydev) | ||||
|  | @ -0,0 +1,72 @@ | |||
| From cc225d163b5a4f7a0d1968298bf7927306646a47 Mon Sep 17 00:00:00 2001 | ||||
| From: David Bauer <mail@david-bauer.net> | ||||
| Date: Fri, 28 Apr 2023 01:53:01 +0200 | ||||
| Subject: [PATCH] net: phy: mediatek-ge: add LED configuration interface | ||||
| 
 | ||||
| This adds a small hack similar to the one used for ar8xxx switches to | ||||
| read a reg:value map for configuring the LED configuration registers. | ||||
| 
 | ||||
| This allows OpenWrt to write device-specific LED action as well as blink | ||||
| configurations. It is unlikely to be accepted upstream, as upstream | ||||
| plans on integrating their own framework for handling these LEDs. | ||||
| 
 | ||||
| Signed-off-by: David Bauer <mail@david-bauer.net> | ||||
| ---
 | ||||
|  drivers/net/phy/mediatek-ge.c | 33 +++++++++++++++++++++++++++++++++ | ||||
|  1 file changed, 33 insertions(+) | ||||
| 
 | ||||
| --- a/drivers/net/phy/mediatek-ge.c
 | ||||
| +++ b/drivers/net/phy/mediatek-ge.c
 | ||||
| @@ -1,4 +1,5 @@
 | ||||
|  // SPDX-License-Identifier: GPL-2.0+ | ||||
| +#include <linux/of.h>
 | ||||
|  #include <linux/bitfield.h> | ||||
|  #include <linux/module.h> | ||||
|  #include <linux/phy.h> | ||||
| @@ -53,6 +54,36 @@ static int mt7530_phy_config_init(struct
 | ||||
|  	return 0; | ||||
|  } | ||||
|   | ||||
| +static int mt7530_led_config_of(struct phy_device *phydev)
 | ||||
| +{
 | ||||
| +	struct device_node *np = phydev->mdio.dev.of_node;
 | ||||
| +	const __be32 *paddr;
 | ||||
| +	int len;
 | ||||
| +	int i;
 | ||||
| +
 | ||||
| +	paddr = of_get_property(np, "mediatek,led-config", &len);
 | ||||
| +	if (!paddr)
 | ||||
| +		return 0;
 | ||||
| +
 | ||||
| +	if (len < (2 * sizeof(*paddr)))
 | ||||
| +		return -EINVAL;
 | ||||
| +
 | ||||
| +	len /= sizeof(*paddr);
 | ||||
| +
 | ||||
| +	phydev_warn(phydev, "Configure LED registers (num=%d)\n", len);
 | ||||
| +	for (i = 0; i < len - 1; i += 2) {
 | ||||
| +		u32 reg;
 | ||||
| +		u32 val;
 | ||||
| +
 | ||||
| +		reg = be32_to_cpup(paddr + i);
 | ||||
| +		val = be32_to_cpup(paddr + i + 1);
 | ||||
| +
 | ||||
| +		phy_write_mmd(phydev, MDIO_MMD_VEND2, reg, val);
 | ||||
| +	}
 | ||||
| +
 | ||||
| +	return 0;
 | ||||
| +}
 | ||||
| +
 | ||||
|  static int mt7531_phy_config_init(struct phy_device *phydev) | ||||
|  { | ||||
|  	mtk_gephy_config_init(phydev); | ||||
| @@ -65,6 +96,9 @@ static int mt7531_phy_config_init(struct
 | ||||
|  	phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x13, 0x404); | ||||
|  	phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x14, 0x404); | ||||
|   | ||||
| +	/* LED Config*/
 | ||||
| +	mt7530_led_config_of(phydev);
 | ||||
| +
 | ||||
|  	return 0; | ||||
|  } | ||||
|   | ||||
|  | @ -0,0 +1,98 @@ | |||
| From 3cb240533ab787899dc7f17aa7d6c5b4810e2e58 Mon Sep 17 00:00:00 2001 | ||||
| From: Hauke Mehrtens <hauke@hauke-m.de> | ||||
| Date: Fri, 7 Jul 2017 17:26:01 +0200 | ||||
| Subject: bcm53xx: bgmac: use srab switch driver | ||||
| 
 | ||||
| use the srab switch driver on these SoCs. | ||||
| 
 | ||||
| Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de> | ||||
| ---
 | ||||
|  drivers/net/ethernet/broadcom/bgmac-bcma.c |  1 + | ||||
|  drivers/net/ethernet/broadcom/bgmac.c      | 24 ++++++++++++++++++++++++ | ||||
|  drivers/net/ethernet/broadcom/bgmac.h      |  4 ++++ | ||||
|  3 files changed, 29 insertions(+) | ||||
| 
 | ||||
| --- a/drivers/net/ethernet/broadcom/bgmac-bcma.c
 | ||||
| +++ b/drivers/net/ethernet/broadcom/bgmac-bcma.c
 | ||||
| @@ -280,6 +280,7 @@ static int bgmac_probe(struct bcma_devic
 | ||||
|  		bgmac->feature_flags |= BGMAC_FEAT_CLKCTLST; | ||||
|  		bgmac->feature_flags |= BGMAC_FEAT_NO_RESET; | ||||
|  		bgmac->feature_flags |= BGMAC_FEAT_FORCE_SPEED_2500; | ||||
| +		bgmac->feature_flags |= BGMAC_FEAT_SRAB;
 | ||||
|  		break; | ||||
|  	default: | ||||
|  		bgmac->feature_flags |= BGMAC_FEAT_CLKCTLST; | ||||
| --- a/drivers/net/ethernet/broadcom/bgmac.c
 | ||||
| +++ b/drivers/net/ethernet/broadcom/bgmac.c
 | ||||
| @@ -12,6 +12,7 @@
 | ||||
|  #include <linux/bcma/bcma.h> | ||||
|  #include <linux/etherdevice.h> | ||||
|  #include <linux/interrupt.h> | ||||
| +#include <linux/platform_data/b53.h>
 | ||||
|  #include <linux/bcm47xx_nvram.h> | ||||
|  #include <linux/phy.h> | ||||
|  #include <linux/phy_fixed.h> | ||||
| @@ -1408,6 +1409,17 @@ static const struct ethtool_ops bgmac_et
 | ||||
|  	.set_link_ksettings     = phy_ethtool_set_link_ksettings, | ||||
|  }; | ||||
|   | ||||
| +static struct b53_platform_data bgmac_b53_pdata = {
 | ||||
| +};
 | ||||
| +
 | ||||
| +static struct platform_device bgmac_b53_dev = {
 | ||||
| +	.name		= "b53-srab-switch",
 | ||||
| +	.id		= -1,
 | ||||
| +	.dev		= {
 | ||||
| +		.platform_data = &bgmac_b53_pdata,
 | ||||
| +	},
 | ||||
| +};
 | ||||
| +
 | ||||
|  /************************************************** | ||||
|   * MII | ||||
|   **************************************************/ | ||||
| @@ -1546,6 +1558,14 @@ int bgmac_enet_probe(struct bgmac *bgmac
 | ||||
|   | ||||
|  	bgmac->in_init = false; | ||||
|   | ||||
| +	if ((bgmac->feature_flags & BGMAC_FEAT_SRAB) && !bgmac_b53_pdata.regs) {
 | ||||
| +		bgmac_b53_pdata.regs = ioremap(0x18007000, 0x1000);
 | ||||
| +
 | ||||
| +		err = platform_device_register(&bgmac_b53_dev);
 | ||||
| +		if (!err)
 | ||||
| +			bgmac->b53_device = &bgmac_b53_dev;
 | ||||
| +	}
 | ||||
| +
 | ||||
|  	err = register_netdev(bgmac->net_dev); | ||||
|  	if (err) { | ||||
|  		dev_err(bgmac->dev, "Cannot register net device\n"); | ||||
| @@ -1568,6 +1588,10 @@ EXPORT_SYMBOL_GPL(bgmac_enet_probe);
 | ||||
|   | ||||
|  void bgmac_enet_remove(struct bgmac *bgmac) | ||||
|  { | ||||
| +	if (bgmac->b53_device)
 | ||||
| +		platform_device_unregister(&bgmac_b53_dev);
 | ||||
| +	bgmac->b53_device = NULL;
 | ||||
| +
 | ||||
|  	unregister_netdev(bgmac->net_dev); | ||||
|  	phy_disconnect(bgmac->net_dev->phydev); | ||||
|  	netif_napi_del(&bgmac->napi); | ||||
| --- a/drivers/net/ethernet/broadcom/bgmac.h
 | ||||
| +++ b/drivers/net/ethernet/broadcom/bgmac.h
 | ||||
| @@ -388,6 +388,7 @@
 | ||||
|  #define BGMAC_FEAT_CC4_IF_SW_TYPE_RGMII	BIT(18) | ||||
|  #define BGMAC_FEAT_CC7_IF_TYPE_RGMII	BIT(19) | ||||
|  #define BGMAC_FEAT_IDM_MASK		BIT(20) | ||||
| +#define BGMAC_FEAT_SRAB			BIT(21)
 | ||||
|   | ||||
|  struct bgmac_slot_info { | ||||
|  	union { | ||||
| @@ -495,6 +496,9 @@ struct bgmac {
 | ||||
|  	void (*cmn_maskset32)(struct bgmac *bgmac, u16 offset, u32 mask, | ||||
|  			      u32 set); | ||||
|  	int (*phy_connect)(struct bgmac *bgmac); | ||||
| +
 | ||||
| +	/* platform device for associated switch */
 | ||||
| +	struct platform_device *b53_device;
 | ||||
|  }; | ||||
|   | ||||
|  struct bgmac *bgmac_alloc(struct device *dev); | ||||
|  | @ -0,0 +1,69 @@ | |||
| From f81700b6bb2eda3756247bce472d8eaf6f466f61 Mon Sep 17 00:00:00 2001 | ||||
| From: OpenWrt community <openwrt-devel@lists.openwrt.org> | ||||
| Date: Wed, 13 Jul 2022 13:49:26 +0200 | ||||
| Subject: [PATCH] net/usb/qmi_wwan: add MeigLink modem support | ||||
| 
 | ||||
| ---
 | ||||
|  drivers/net/usb/qmi_wwan.c  | 1 + | ||||
|  drivers/usb/serial/option.c | 7 +++++++ | ||||
|  2 files changed, 8 insertions(+) | ||||
| 
 | ||||
| --- a/drivers/net/usb/qmi_wwan.c
 | ||||
| +++ b/drivers/net/usb/qmi_wwan.c
 | ||||
| @@ -1083,12 +1083,18 @@ static const struct usb_device_id produc
 | ||||
|  		USB_DEVICE_AND_INTERFACE_INFO(0x03f0, 0x581d, USB_CLASS_VENDOR_SPEC, 1, 7), | ||||
|  		.driver_info = (unsigned long)&qmi_wwan_info, | ||||
|  	}, | ||||
| +	{	/* Meiglink SGM828 */
 | ||||
| +		USB_DEVICE_AND_INTERFACE_INFO(0x2dee, 0x4d49, USB_CLASS_VENDOR_SPEC, 0x10, 0x05),
 | ||||
| +		.driver_info = (unsigned long)&qmi_wwan_info,
 | ||||
| +	},
 | ||||
| +
 | ||||
|  	{QMI_MATCH_FF_FF_FF(0x2c7c, 0x0125)},	/* Quectel EC25, EC20 R2.0  Mini PCIe */ | ||||
|  	{QMI_MATCH_FF_FF_FF(0x2c7c, 0x0306)},	/* Quectel EP06/EG06/EM06 */ | ||||
|  	{QMI_MATCH_FF_FF_FF(0x2c7c, 0x0512)},	/* Quectel EG12/EM12 */ | ||||
|  	{QMI_MATCH_FF_FF_FF(0x2c7c, 0x0620)},	/* Quectel EM160R-GL */ | ||||
|  	{QMI_MATCH_FF_FF_FF(0x2c7c, 0x0800)},	/* Quectel RM500Q-GL */ | ||||
|  	{QMI_MATCH_FF_FF_FF(0x2c7c, 0x0801)},	/* Quectel RM520N */ | ||||
| +	{QMI_MATCH_FF_FF_FF(0x05c6, 0xf601)},	/* MeigLink SLM750 */
 | ||||
|   | ||||
|  	/* 3. Combined interface devices matching on interface number */ | ||||
|  	{QMI_FIXED_INTF(0x0408, 0xea42, 4)},	/* Yota / Megafon M100-1 */ | ||||
| --- a/drivers/usb/serial/option.c
 | ||||
| +++ b/drivers/usb/serial/option.c
 | ||||
| @@ -247,6 +247,11 @@ static void option_instat_callback(struc
 | ||||
|  #define UBLOX_PRODUCT_R410M			0x90b2 | ||||
|  /* These Yuga products use Qualcomm's vendor ID */ | ||||
|  #define YUGA_PRODUCT_CLM920_NC5			0x9625 | ||||
| +/* These MeigLink products use Qualcomm's vendor ID */
 | ||||
| +#define MEIGLINK_PRODUCT_SLM750			0xf601
 | ||||
| +
 | ||||
| +#define MEIGLINK_VENDOR_ID			0x2dee
 | ||||
| +#define MEIGLINK_PRODUCT_SLM828			0x4d49
 | ||||
|   | ||||
|  #define QUECTEL_VENDOR_ID			0x2c7c | ||||
|  /* These Quectel products use Quectel's vendor ID */ | ||||
| @@ -1156,6 +1161,11 @@ static const struct usb_device_id option
 | ||||
|  	{ USB_DEVICE(QUALCOMM_VENDOR_ID, 0x0023)}, /* ONYX 3G device */ | ||||
|  	{ USB_DEVICE(QUALCOMM_VENDOR_ID, 0x9000), /* SIMCom SIM5218 */ | ||||
|  	  .driver_info = NCTRL(0) | NCTRL(1) | NCTRL(2) | NCTRL(3) | RSVD(4) }, | ||||
| +	/* MeiG */
 | ||||
| +	{ USB_DEVICE_AND_INTERFACE_INFO(MEIGLINK_VENDOR_ID, MEIGLINK_PRODUCT_SLM828, USB_CLASS_VENDOR_SPEC, 0x10, 0x01) },
 | ||||
| +	{ USB_DEVICE_AND_INTERFACE_INFO(MEIGLINK_VENDOR_ID, MEIGLINK_PRODUCT_SLM828, USB_CLASS_VENDOR_SPEC, 0x10, 0x02) },
 | ||||
| +	{ USB_DEVICE_AND_INTERFACE_INFO(MEIGLINK_VENDOR_ID, MEIGLINK_PRODUCT_SLM828, USB_CLASS_VENDOR_SPEC, 0x10, 0x03) },
 | ||||
| +	{ USB_DEVICE_AND_INTERFACE_INFO(MEIGLINK_VENDOR_ID, MEIGLINK_PRODUCT_SLM828, USB_CLASS_VENDOR_SPEC, 0x10, 0x04) },
 | ||||
|  	/* Quectel products using Qualcomm vendor ID */ | ||||
|  	{ USB_DEVICE(QUALCOMM_VENDOR_ID, QUECTEL_PRODUCT_UC15)}, | ||||
|  	{ USB_DEVICE(QUALCOMM_VENDOR_ID, QUECTEL_PRODUCT_UC20), | ||||
| @@ -1197,6 +1207,11 @@ static const struct usb_device_id option
 | ||||
|  	  .driver_info = ZLP }, | ||||
|  	{ USB_DEVICE(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_BG96), | ||||
|  	  .driver_info = RSVD(4) }, | ||||
| +	/* Meiglink products using Qualcomm vendor ID */
 | ||||
| +	// Works OK. In case of some issues check macros that are used by Quectel Products
 | ||||
| +	{ USB_DEVICE_AND_INTERFACE_INFO(QUALCOMM_VENDOR_ID, MEIGLINK_PRODUCT_SLM750, 0xff, 0xff, 0xff),
 | ||||
| +	  .driver_info = NUMEP2 },
 | ||||
| +	{ USB_DEVICE_AND_INTERFACE_INFO(QUALCOMM_VENDOR_ID, MEIGLINK_PRODUCT_SLM750, 0xff, 0, 0) },
 | ||||
|  	{ USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EP06, 0xff, 0xff, 0xff), | ||||
|  	  .driver_info = RSVD(1) | RSVD(2) | RSVD(3) | RSVD(4) | NUMEP2 }, | ||||
|  	{ USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EP06, 0xff, 0, 0) }, | ||||
|  | @ -0,0 +1,69 @@ | |||
| From 9fabf60187f1fa19e6f6bb5441587d485bd534b0 Mon Sep 17 00:00:00 2001 | ||||
| From: Daniel Golle <daniel@makrotopia.org> | ||||
| Date: Tue, 9 Apr 2024 17:06:38 +0100 | ||||
| Subject: [PATCH] rndis_host: add a bunch of USB IDs | ||||
| 
 | ||||
| Add a bunch of USB IDs found in various places online to the | ||||
| RNDIS USB network driver. | ||||
| 
 | ||||
| Signed-off-by: Daniel Golle <daniel@makrotopia.org> | ||||
| ---
 | ||||
|  drivers/net/usb/rndis_host.c | 40 ++++++++++++++++++++++ | ||||
|  1 file changed, 40 insertions(+) | ||||
| 
 | ||||
| --- a/drivers/net/usb/rndis_host.c
 | ||||
| +++ b/drivers/net/usb/rndis_host.c
 | ||||
| @@ -630,6 +630,16 @@ static const struct driver_info	zte_rndi
 | ||||
|  	.tx_fixup =	rndis_tx_fixup, | ||||
|  }; | ||||
|   | ||||
| +static const struct driver_info asr_rndis_info = {
 | ||||
| +	.description =	"Asr RNDIS device",
 | ||||
| +	.flags =	FLAG_WWAN | FLAG_POINTTOPOINT | FLAG_FRAMING_RN | FLAG_NO_SETINT | FLAG_NOARP,
 | ||||
| +	.bind =		rndis_bind,
 | ||||
| +	.unbind =	rndis_unbind,
 | ||||
| +	.status =	rndis_status,
 | ||||
| +	.rx_fixup =	rndis_rx_fixup,
 | ||||
| +	.tx_fixup =	rndis_tx_fixup,
 | ||||
| +};
 | ||||
| +
 | ||||
|  /*-------------------------------------------------------------------------*/ | ||||
|   | ||||
|  static const struct usb_device_id	products [] = { | ||||
| @@ -666,6 +676,36 @@ static const struct usb_device_id	produc
 | ||||
|  	USB_INTERFACE_INFO(USB_CLASS_WIRELESS_CONTROLLER, 1, 3), | ||||
|  	.driver_info = (unsigned long) &rndis_info, | ||||
|  }, { | ||||
| +	/* Quectel EG060V rndis device */
 | ||||
| +	USB_DEVICE_AND_INTERFACE_INFO(0x2c7c, 0x6004,
 | ||||
| +				      USB_CLASS_WIRELESS_CONTROLLER, 1, 3),
 | ||||
| +	.driver_info = (unsigned long) &asr_rndis_info,
 | ||||
| +}, {
 | ||||
| +	/* Quectel EC200A rndis device */
 | ||||
| +	USB_DEVICE_AND_INTERFACE_INFO(0x2c7c, 0x6005,
 | ||||
| +				      USB_CLASS_WIRELESS_CONTROLLER, 1, 3),
 | ||||
| +	.driver_info = (unsigned long) &asr_rndis_info,
 | ||||
| +}, {
 | ||||
| +	/* Quectel EC200T rndis device */
 | ||||
| +	USB_DEVICE_AND_INTERFACE_INFO(0x2c7c, 0x6026,
 | ||||
| +				      USB_CLASS_WIRELESS_CONTROLLER, 1, 3),
 | ||||
| +	.driver_info = (unsigned long) &asr_rndis_info,
 | ||||
| +}, {
 | ||||
| +	/* Simcom A7906E rndis device */
 | ||||
| +	USB_DEVICE_AND_INTERFACE_INFO(0x1e0e, 0x9011,
 | ||||
| +				      USB_CLASS_WIRELESS_CONTROLLER, 1, 3),
 | ||||
| +	.driver_info = (unsigned long) &asr_rndis_info,
 | ||||
| +}, {
 | ||||
| +	/* Meig SLM770A */
 | ||||
| +	USB_DEVICE_AND_INTERFACE_INFO(0x2dee, 0x4d57,
 | ||||
| +				      USB_CLASS_WIRELESS_CONTROLLER, 1, 3),
 | ||||
| +	.driver_info = (unsigned long) &asr_rndis_info,
 | ||||
| +}, {
 | ||||
| +	/* Meig SLM828 */
 | ||||
| +	USB_DEVICE_AND_INTERFACE_INFO(0x2dee, 0x4d49,
 | ||||
| +				      USB_CLASS_WIRELESS_CONTROLLER, 1, 3),
 | ||||
| +	.driver_info = (unsigned long) &asr_rndis_info,
 | ||||
| +}, {
 | ||||
|  	/* Novatel Verizon USB730L */ | ||||
|  	USB_INTERFACE_INFO(USB_CLASS_MISC, 4, 1), | ||||
|  	.driver_info = (unsigned long) &rndis_info, | ||||
|  | @ -0,0 +1,63 @@ | |||
| From 7cc39a6bedbd85f3ff7e16845f310e4ce8d9833f Mon Sep 17 00:00:00 2001 | ||||
| From: Daniel Golle <daniel@makrotopia.org> | ||||
| Date: Tue, 6 Sep 2022 00:31:19 +0100 | ||||
| Subject: [PATCH] net: sfp: add quirk for ATS SFP-GE-T 1000Base-TX module | ||||
| To: netdev@vger.kernel.org, | ||||
|     linux-kernel@vger.kernel.org, | ||||
|     Russell King <linux@armlinux.org.uk>, | ||||
|     Andrew Lunn <andrew@lunn.ch>, | ||||
|     Heiner Kallweit <hkallweit1@gmail.com> | ||||
| Cc: David S. Miller <davem@davemloft.net>, | ||||
|     Eric Dumazet <edumazet@google.com>, | ||||
|     Jakub Kicinski <kuba@kernel.org>, | ||||
|     Paolo Abeni <pabeni@redhat.com>, | ||||
|     Josef Schlehofer <pepe.schlehofer@gmail.com> | ||||
| 
 | ||||
| This copper module comes with broken TX_FAULT indicator which must be | ||||
| ignored for it to work. Implement ignoring TX_FAULT state bit also | ||||
| during reset/insertion and mute the warning telling the user that the | ||||
| module indicates TX_FAULT. | ||||
| 
 | ||||
| Co-authored-by: Josef Schlehofer <pepe.schlehofer@gmail.com> | ||||
| Signed-off-by: Daniel Golle <daniel@makrotopia.org> | ||||
| ---
 | ||||
|  drivers/net/phy/sfp.c | 14 +++++++++++--- | ||||
|  1 file changed, 11 insertions(+), 3 deletions(-) | ||||
| 
 | ||||
| --- a/drivers/net/phy/sfp.c
 | ||||
| +++ b/drivers/net/phy/sfp.c
 | ||||
| @@ -471,6 +471,9 @@ static const struct sfp_quirk sfp_quirks
 | ||||
|  	// FS 2.5G Base-T | ||||
|  	SFP_QUIRK_M("FS", "SFP-2.5G-T", sfp_quirk_oem_2_5g), | ||||
|   | ||||
| +	// OEM SFP-GE-T is 1000Base-T module
 | ||||
| +	SFP_QUIRK_F("OEM", "SFP-GE-T", sfp_fixup_ignore_tx_fault),
 | ||||
| +
 | ||||
|  	// Lantech 8330-262D-E can operate at 2500base-X, but incorrectly report | ||||
|  	// 2500MBd NRZ in their EEPROM | ||||
|  	SFP_QUIRK_M("Lantech", "8330-262D-E", sfp_quirk_2500basex), | ||||
| @@ -2587,7 +2590,8 @@ static void sfp_sm_main(struct sfp *sfp,
 | ||||
|  			 * or t_start_up, so assume there is a fault. | ||||
|  			 */ | ||||
|  			sfp_sm_fault(sfp, SFP_S_INIT_TX_FAULT, | ||||
| -				     sfp->sm_fault_retries == N_FAULT_INIT);
 | ||||
| +				     !sfp->tx_fault_ignore &&
 | ||||
| +				     (sfp->sm_fault_retries == N_FAULT_INIT));
 | ||||
|  		} else if (event == SFP_E_TIMEOUT || event == SFP_E_TX_CLEAR) { | ||||
|  	init_done: | ||||
|  			/* Create mdiobus and start trying for PHY */ | ||||
| @@ -2841,10 +2845,12 @@ static void sfp_check_state(struct sfp *
 | ||||
|  	mutex_lock(&sfp->st_mutex); | ||||
|  	state = sfp_get_state(sfp); | ||||
|  	changed = state ^ sfp->state; | ||||
| -	if (sfp->tx_fault_ignore)
 | ||||
| +	if (sfp->tx_fault_ignore) {
 | ||||
|  		changed &= SFP_F_PRESENT | SFP_F_LOS; | ||||
| -	else
 | ||||
| +		state &= ~SFP_F_TX_FAULT;
 | ||||
| +	} else {
 | ||||
|  		changed &= SFP_F_PRESENT | SFP_F_LOS | SFP_F_TX_FAULT; | ||||
| +	}
 | ||||
|   | ||||
|  	for (i = 0; i < GPIO_MAX; i++) | ||||
|  		if (changed & BIT(i)) | ||||
|  | @ -0,0 +1,173 @@ | |||
| From cc809a441d8f2924f785eb863dfa6aef47a25b0b Mon Sep 17 00:00:00 2001 | ||||
| From: John Crispin <blogic@openwrt.org> | ||||
| Date: Tue, 12 Aug 2014 20:49:27 +0200 | ||||
| Subject: [PATCH 30/36] GPIO: add named gpio exports | ||||
| 
 | ||||
| Signed-off-by: John Crispin <blogic@openwrt.org> | ||||
| --- a/drivers/gpio/gpiolib-of.c
 | ||||
| +++ b/drivers/gpio/gpiolib-of.c
 | ||||
| @@ -21,6 +21,8 @@
 | ||||
|   | ||||
|  #include <linux/gpio/consumer.h> | ||||
|  #include <linux/gpio/machine.h> | ||||
| +#include <linux/init.h>
 | ||||
| +#include <linux/platform_device.h>
 | ||||
|   | ||||
|  #include "gpiolib.h" | ||||
|  #include "gpiolib-of.h" | ||||
| @@ -1111,3 +1113,74 @@ void of_gpiochip_remove(struct gpio_chip
 | ||||
|  { | ||||
|  	of_node_put(dev_of_node(&chip->gpiodev->dev)); | ||||
|  } | ||||
| +
 | ||||
| +#ifdef CONFIG_GPIO_SYSFS
 | ||||
| +
 | ||||
| +static struct of_device_id gpio_export_ids[] = {
 | ||||
| +	{ .compatible = "gpio-export" },
 | ||||
| +	{ /* sentinel */ }
 | ||||
| +};
 | ||||
| +
 | ||||
| +static int of_gpio_export_probe(struct platform_device *pdev)
 | ||||
| +{
 | ||||
| +	struct device_node *np = pdev->dev.of_node;
 | ||||
| +	struct device_node *cnp;
 | ||||
| +	u32 val;
 | ||||
| +	int nb = 0;
 | ||||
| +
 | ||||
| +	for_each_child_of_node(np, cnp) {
 | ||||
| +		const char *name = NULL;
 | ||||
| +		int gpio;
 | ||||
| +		bool dmc;
 | ||||
| +		int max_gpio = 1;
 | ||||
| +		int i;
 | ||||
| +
 | ||||
| +		of_property_read_string(cnp, "gpio-export,name", &name);
 | ||||
| +
 | ||||
| +		if (!name)
 | ||||
| +			max_gpio = of_gpio_named_count(cnp, "gpios");
 | ||||
| +
 | ||||
| +		for (i = 0; i < max_gpio; i++) {
 | ||||
| +			struct gpio_desc *desc;
 | ||||
| +			unsigned flags = 0;
 | ||||
| +			enum of_gpio_flags of_flags;
 | ||||
| +
 | ||||
| +			desc = of_get_named_gpiod_flags(cnp, "gpios", i, &of_flags);
 | ||||
| +			if (IS_ERR(desc))
 | ||||
| +				return PTR_ERR(desc);
 | ||||
| +			gpio = desc_to_gpio(desc);
 | ||||
| +
 | ||||
| +			if (of_flags & OF_GPIO_ACTIVE_LOW)
 | ||||
| +				flags |= GPIOF_ACTIVE_LOW;
 | ||||
| +
 | ||||
| +			if (!of_property_read_u32(cnp, "gpio-export,output", &val))
 | ||||
| +				flags |= val ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW;
 | ||||
| +			else
 | ||||
| +				flags |= GPIOF_IN;
 | ||||
| +
 | ||||
| +			if (devm_gpio_request_one(&pdev->dev, gpio, flags, name ? name : of_node_full_name(np)))
 | ||||
| +				continue;
 | ||||
| +
 | ||||
| +			dmc = of_property_read_bool(cnp, "gpio-export,direction_may_change");
 | ||||
| +			gpio_export_with_name(gpio_to_desc(gpio), dmc, name);
 | ||||
| +			nb++;
 | ||||
| +		}
 | ||||
| +	}
 | ||||
| +
 | ||||
| +	dev_info(&pdev->dev, "%d gpio(s) exported\n", nb);
 | ||||
| +
 | ||||
| +	return 0;
 | ||||
| +}
 | ||||
| +
 | ||||
| +static struct platform_driver gpio_export_driver = {
 | ||||
| +	.driver		= {
 | ||||
| +		.name		= "gpio-export",
 | ||||
| +		.owner	= THIS_MODULE,
 | ||||
| +		.of_match_table	= of_match_ptr(gpio_export_ids),
 | ||||
| +	},
 | ||||
| +	.probe		= of_gpio_export_probe,
 | ||||
| +};
 | ||||
| +
 | ||||
| +module_platform_driver(gpio_export_driver);
 | ||||
| +
 | ||||
| +#endif
 | ||||
| --- a/include/linux/gpio/consumer.h
 | ||||
| +++ b/include/linux/gpio/consumer.h
 | ||||
| @@ -644,7 +644,10 @@ static inline struct gpio_desc *acpi_get
 | ||||
|   | ||||
|  #if IS_ENABLED(CONFIG_GPIOLIB) && IS_ENABLED(CONFIG_GPIO_SYSFS) | ||||
|   | ||||
| +int __gpiod_export(struct gpio_desc *desc, bool direction_may_change, const char *name);
 | ||||
|  int gpiod_export(struct gpio_desc *desc, bool direction_may_change); | ||||
| +int gpio_export_with_name(struct gpio_desc *desc, bool direction_may_change,
 | ||||
| +			  const char *name);
 | ||||
|  int gpiod_export_link(struct device *dev, const char *name, | ||||
|  		      struct gpio_desc *desc); | ||||
|  void gpiod_unexport(struct gpio_desc *desc); | ||||
| @@ -653,11 +656,25 @@ void gpiod_unexport(struct gpio_desc *de
 | ||||
|   | ||||
|  #include <asm/errno.h> | ||||
|   | ||||
| +static inline int __gpiod_export(struct gpio_desc *desc,
 | ||||
| +			       bool direction_may_change,
 | ||||
| +			       const char *name)
 | ||||
| +{
 | ||||
| +	return -ENOSYS;
 | ||||
| +}
 | ||||
| +
 | ||||
|  static inline int gpiod_export(struct gpio_desc *desc, | ||||
|  			       bool direction_may_change) | ||||
|  { | ||||
|  	return -ENOSYS; | ||||
|  } | ||||
| +
 | ||||
| +static inline int gpio_export_with_name(struct gpio_desc *desc,
 | ||||
| +					bool direction_may_change,
 | ||||
| +					const char *name)
 | ||||
| +{
 | ||||
| +	return -ENOSYS;
 | ||||
| +}
 | ||||
|   | ||||
|  static inline int gpiod_export_link(struct device *dev, const char *name, | ||||
|  				    struct gpio_desc *desc) | ||||
| --- a/drivers/gpio/gpiolib-sysfs.c
 | ||||
| +++ b/drivers/gpio/gpiolib-sysfs.c
 | ||||
| @@ -557,7 +557,7 @@ static struct class gpio_class = {
 | ||||
|   * | ||||
|   * Returns zero on success, else an error. | ||||
|   */ | ||||
| -int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
 | ||||
| +int __gpiod_export(struct gpio_desc *desc, bool direction_may_change, const char *name)
 | ||||
|  { | ||||
|  	struct gpio_chip	*chip; | ||||
|  	struct gpio_device	*gdev; | ||||
| @@ -619,6 +619,8 @@ int gpiod_export(struct gpio_desc *desc,
 | ||||
|  	offset = gpio_chip_hwgpio(desc); | ||||
|  	if (chip->names && chip->names[offset]) | ||||
|  		ioname = chip->names[offset]; | ||||
| +	if (name)
 | ||||
| +		ioname = name;
 | ||||
|   | ||||
|  	dev = device_create_with_groups(&gpio_class, &gdev->dev, | ||||
|  					MKDEV(0, 0), data, gpio_groups, | ||||
| @@ -640,8 +642,21 @@ err_unlock:
 | ||||
|  	gpiod_dbg(desc, "%s: status %d\n", __func__, status); | ||||
|  	return status; | ||||
|  } | ||||
| +EXPORT_SYMBOL_GPL(__gpiod_export);
 | ||||
| +
 | ||||
| +int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
 | ||||
| +{
 | ||||
| +	return __gpiod_export(desc, direction_may_change, NULL);
 | ||||
| +}
 | ||||
|  EXPORT_SYMBOL_GPL(gpiod_export); | ||||
|   | ||||
| +int gpio_export_with_name(struct gpio_desc *desc, bool direction_may_change,
 | ||||
| +			  const char *name)
 | ||||
| +{
 | ||||
| +	return __gpiod_export(desc, direction_may_change, name);
 | ||||
| +}
 | ||||
| +EXPORT_SYMBOL_GPL(gpio_export_with_name);
 | ||||
| +
 | ||||
|  static int match_export(struct device *dev, const void *desc) | ||||
|  { | ||||
|  	struct gpiod_data *data = dev_get_drvdata(dev); | ||||
|  | @ -0,0 +1,187 @@ | |||
| From e4d708702e6c98f2111e33201a264d6788564cb2 Mon Sep 17 00:00:00 2001 | ||||
| From: OpenWrt community <openwrt-devel@lists.openwrt.org> | ||||
| Date: Fri, 12 May 2023 11:08:43 +0200 | ||||
| Subject: [PATCH] ssb_sprom: add generic kernel support for Broadcom  Fallback SPROMs | ||||
| 
 | ||||
| ---
 | ||||
|  drivers/bcma/Kconfig        |  4 ++++ | ||||
|  drivers/bcma/Makefile       |  1 + | ||||
|  drivers/bcma/bcma_private.h |  4 ++++ | ||||
|  drivers/bcma/main.c         |  8 ++++++++ | ||||
|  drivers/bcma/sprom.c        | 23 ++++++++++++++--------- | ||||
|  drivers/ssb/Kconfig         |  5 +++++ | ||||
|  drivers/ssb/Makefile        |  1 + | ||||
|  drivers/ssb/main.c          |  8 ++++++++ | ||||
|  drivers/ssb/sprom.c         | 12 +++++++++++- | ||||
|  drivers/ssb/ssb_private.h   |  4 ++++ | ||||
|  10 files changed, 60 insertions(+), 10 deletions(-) | ||||
| 
 | ||||
| --- a/drivers/bcma/Kconfig
 | ||||
| +++ b/drivers/bcma/Kconfig
 | ||||
| @@ -18,6 +18,10 @@ config BCMA_BLOCKIO
 | ||||
|  	bool | ||||
|  	default y | ||||
|   | ||||
| +config BCMA_FALLBACK_SPROM
 | ||||
| +	bool
 | ||||
| +	default y
 | ||||
| +
 | ||||
|  config BCMA_HOST_PCI_POSSIBLE | ||||
|  	bool | ||||
|  	depends on PCI = y | ||||
| --- a/drivers/bcma/Makefile
 | ||||
| +++ b/drivers/bcma/Makefile
 | ||||
| @@ -11,6 +11,7 @@ bcma-$(CONFIG_BCMA_DRIVER_PCI_HOSTMODE)
 | ||||
|  bcma-$(CONFIG_BCMA_DRIVER_MIPS)		+= driver_mips.o | ||||
|  bcma-$(CONFIG_BCMA_DRIVER_GMAC_CMN)	+= driver_gmac_cmn.o | ||||
|  bcma-$(CONFIG_BCMA_DRIVER_GPIO)		+= driver_gpio.o | ||||
| +bcma-$(CONFIG_BCMA_FALLBACK_SPROM)	+= fallback-sprom.o
 | ||||
|  bcma-$(CONFIG_BCMA_HOST_PCI)		+= host_pci.o | ||||
|  bcma-$(CONFIG_BCMA_HOST_SOC)		+= host_soc.o | ||||
|  obj-$(CONFIG_BCMA)			+= bcma.o | ||||
| --- a/drivers/bcma/bcma_private.h
 | ||||
| +++ b/drivers/bcma/bcma_private.h
 | ||||
| @@ -38,6 +38,10 @@ int bcma_bus_resume(struct bcma_bus *bus
 | ||||
|  void bcma_detect_chip(struct bcma_bus *bus); | ||||
|  int bcma_bus_scan(struct bcma_bus *bus); | ||||
|   | ||||
| +/* fallback-sprom.c */
 | ||||
| +int __init bcma_fbs_register(void);
 | ||||
| +int bcma_get_fallback_sprom(struct bcma_bus *dev, struct ssb_sprom *out);
 | ||||
| +
 | ||||
|  /* sprom.c */ | ||||
|  int bcma_sprom_get(struct bcma_bus *bus); | ||||
|   | ||||
| --- a/drivers/bcma/main.c
 | ||||
| +++ b/drivers/bcma/main.c
 | ||||
| @@ -671,6 +671,14 @@ static int __init bcma_modinit(void)
 | ||||
|  { | ||||
|  	int err; | ||||
|   | ||||
| +#ifdef CONFIG_BCMA_FALLBACK_SPROM
 | ||||
| +	err = bcma_fbs_register();
 | ||||
| +	if (err) {
 | ||||
| +		pr_err("Fallback SPROM initialization failed\n");
 | ||||
| +		err = 0;
 | ||||
| +	}
 | ||||
| +#endif /* CONFIG_BCMA_FALLBACK_SPROM */
 | ||||
| +
 | ||||
|  	err = bcma_init_bus_register(); | ||||
|  	if (err) | ||||
|  		return err; | ||||
| --- a/drivers/bcma/sprom.c
 | ||||
| +++ b/drivers/bcma/sprom.c
 | ||||
| @@ -51,21 +51,26 @@ static int bcma_fill_sprom_with_fallback
 | ||||
|  { | ||||
|  	int err; | ||||
|   | ||||
| -	if (!get_fallback_sprom) {
 | ||||
| +	if (get_fallback_sprom)
 | ||||
| +		err = get_fallback_sprom(bus, out);
 | ||||
| +
 | ||||
| +#ifdef CONFIG_BCMA_FALLBACK_SPROM
 | ||||
| +	if (!get_fallback_sprom || err)
 | ||||
| +		err = bcma_get_fallback_sprom(bus, out);
 | ||||
| +#else
 | ||||
| +	if (!get_fallback_sprom)
 | ||||
|  		err = -ENOENT; | ||||
| -		goto fail;
 | ||||
| -	}
 | ||||
| +#endif /* CONFIG_BCMA_FALLBACK_SPROM */
 | ||||
|   | ||||
| -	err = get_fallback_sprom(bus, out);
 | ||||
| -	if (err)
 | ||||
| -		goto fail;
 | ||||
| +	if (err) {
 | ||||
| +		bcma_warn(bus, "Using fallback SPROM failed (err %d)\n", err);
 | ||||
| +		return err;
 | ||||
| +	}
 | ||||
|   | ||||
|  	bcma_debug(bus, "Using SPROM revision %d provided by platform.\n", | ||||
|  		   bus->sprom.revision); | ||||
| +
 | ||||
|  	return 0; | ||||
| -fail:
 | ||||
| -	bcma_warn(bus, "Using fallback SPROM failed (err %d)\n", err);
 | ||||
| -	return err;
 | ||||
|  } | ||||
|   | ||||
|  /************************************************** | ||||
| --- a/drivers/ssb/Kconfig
 | ||||
| +++ b/drivers/ssb/Kconfig
 | ||||
| @@ -25,6 +25,11 @@ if SSB
 | ||||
|  config SSB_SPROM | ||||
|  	bool | ||||
|   | ||||
| +config SSB_FALLBACK_SPROM
 | ||||
| +	bool
 | ||||
| +	depends on SSB_PCIHOST
 | ||||
| +	default y
 | ||||
| +
 | ||||
|  # Support for Block-I/O. SELECT this from the driver that needs it. | ||||
|  config SSB_BLOCKIO | ||||
|  	bool | ||||
| --- a/drivers/ssb/Makefile
 | ||||
| +++ b/drivers/ssb/Makefile
 | ||||
| @@ -2,6 +2,7 @@
 | ||||
|  # core | ||||
|  ssb-y					+= main.o scan.o | ||||
|  ssb-$(CONFIG_SSB_EMBEDDED)		+= embedded.o | ||||
| +ssb-$(CONFIG_SSB_FALLBACK_SPROM)	+= fallback-sprom.o
 | ||||
|  ssb-$(CONFIG_SSB_SPROM)			+= sprom.o | ||||
|   | ||||
|  # host support | ||||
| --- a/drivers/ssb/main.c
 | ||||
| +++ b/drivers/ssb/main.c
 | ||||
| @@ -1287,6 +1287,14 @@ static int __init ssb_modinit(void)
 | ||||
|  { | ||||
|  	int err; | ||||
|   | ||||
| +#ifdef CONFIG_SSB_FALLBACK_SPROM
 | ||||
| +	err = ssb_fbs_register();
 | ||||
| +	if (err) {
 | ||||
| +		pr_err("Fallback SPROM initialization failed\n");
 | ||||
| +		err = 0;
 | ||||
| +	}
 | ||||
| +#endif /* CONFIG_SSB_FALLBACK_SPROM */
 | ||||
| +
 | ||||
|  	/* See the comment at the ssb_is_early_boot definition */ | ||||
|  	ssb_is_early_boot = 0; | ||||
|  	err = bus_register(&ssb_bustype); | ||||
| --- a/drivers/ssb/sprom.c
 | ||||
| +++ b/drivers/ssb/sprom.c
 | ||||
| @@ -180,10 +180,20 @@ int ssb_arch_register_fallback_sprom(int
 | ||||
|   | ||||
|  int ssb_fill_sprom_with_fallback(struct ssb_bus *bus, struct ssb_sprom *out) | ||||
|  { | ||||
| +	int err;
 | ||||
| +
 | ||||
| +	if (get_fallback_sprom)
 | ||||
| +		err = get_fallback_sprom(bus, out);
 | ||||
| +
 | ||||
| +#ifdef CONFIG_SSB_FALLBACK_SPROM
 | ||||
| +	if (!get_fallback_sprom || err)
 | ||||
| +		err = ssb_get_fallback_sprom(bus, out);
 | ||||
| +#else
 | ||||
|  	if (!get_fallback_sprom) | ||||
|  		return -ENOENT; | ||||
| +#endif /* CONFIG_SSB_FALLBACK_SPROM */
 | ||||
|   | ||||
| -	return get_fallback_sprom(bus, out);
 | ||||
| +	return err;
 | ||||
|  } | ||||
|   | ||||
|  /* https://bcm-v4.sipsolutions.net/802.11/IsSpromAvailable */ | ||||
| --- a/drivers/ssb/ssb_private.h
 | ||||
| +++ b/drivers/ssb/ssb_private.h
 | ||||
| @@ -143,6 +143,10 @@ extern int ssb_bus_scan(struct ssb_bus *
 | ||||
|  extern void ssb_iounmap(struct ssb_bus *ssb); | ||||
|   | ||||
|   | ||||
| +/* fallback-sprom.c */
 | ||||
| +int __init ssb_fbs_register(void);
 | ||||
| +int ssb_get_fallback_sprom(struct ssb_bus *dev, struct ssb_sprom *out);
 | ||||
| +
 | ||||
|  /* sprom.c */ | ||||
|  extern | ||||
|  ssize_t ssb_attr_sprom_show(struct ssb_bus *bus, char *buf, | ||||
							
								
								
									
										181
									
								
								6.10/target/linux/generic/hack-6.10/901-debloat_sock_diag.patch
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										181
									
								
								6.10/target/linux/generic/hack-6.10/901-debloat_sock_diag.patch
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,181 @@ | |||
| From 3b6115d6b57a263bdc8c9b1df273bd4a7955eead Mon Sep 17 00:00:00 2001 | ||||
| From: Felix Fietkau <nbd@nbd.name> | ||||
| Date: Sat, 8 Jul 2017 08:16:31 +0200 | ||||
| Subject: debloat: add some debloat patches, strip down procfs and make O_DIRECT support optional, saves ~15K after lzma on MIPS | ||||
| 
 | ||||
| Signed-off-by: Felix Fietkau <nbd@nbd.name> | ||||
| ---
 | ||||
|  net/Kconfig         | 3 +++ | ||||
|  net/core/Makefile   | 3 ++- | ||||
|  net/core/sock.c     | 2 ++ | ||||
|  net/ipv4/Kconfig    | 1 + | ||||
|  net/netlink/Kconfig | 1 + | ||||
|  net/packet/Kconfig  | 1 + | ||||
|  net/unix/Kconfig    | 1 + | ||||
|  7 files changed, 11 insertions(+), 1 deletion(-) | ||||
| 
 | ||||
| --- a/net/Kconfig
 | ||||
| +++ b/net/Kconfig
 | ||||
| @@ -129,6 +129,9 @@ source "net/mptcp/Kconfig"
 | ||||
|   | ||||
|  endif # if INET | ||||
|   | ||||
| +config SOCK_DIAG
 | ||||
| +	bool
 | ||||
| +
 | ||||
|  config NETWORK_SECMARK | ||||
|  	bool "Security Marking" | ||||
|  	help | ||||
| --- a/net/core/Makefile
 | ||||
| +++ b/net/core/Makefile
 | ||||
| @@ -11,12 +11,13 @@ obj-$(CONFIG_SYSCTL) += sysctl_net_core.
 | ||||
|   | ||||
|  obj-y		     += dev.o dev_addr_lists.o dst.o netevent.o \ | ||||
|  			neighbour.o rtnetlink.o utils.o link_watch.o filter.o \ | ||||
| -			sock_diag.o dev_ioctl.o tso.o sock_reuseport.o \
 | ||||
| +			dev_ioctl.o tso.o sock_reuseport.o \
 | ||||
|  			fib_notifier.o xdp.o flow_offload.o gro.o \ | ||||
|  			netdev-genl.o netdev-genl-gen.o gso.o | ||||
|   | ||||
|  obj-$(CONFIG_NETDEV_ADDR_LIST_TEST) += dev_addr_lists_test.o | ||||
|   | ||||
| +obj-$(CONFIG_SOCK_DIAG) += sock_diag.o
 | ||||
|  obj-y += net-sysfs.o | ||||
|  obj-$(CONFIG_PAGE_POOL) += page_pool.o | ||||
|  obj-$(CONFIG_PROC_FS) += net-procfs.o | ||||
| --- a/net/core/sock.c
 | ||||
| +++ b/net/core/sock.c
 | ||||
| @@ -118,6 +118,7 @@
 | ||||
|  #include <linux/mroute.h> | ||||
|  #include <linux/mroute6.h> | ||||
|  #include <linux/icmpv6.h> | ||||
| +#include <linux/cookie.h>
 | ||||
|   | ||||
|  #include <linux/uaccess.h> | ||||
|   | ||||
| @@ -150,6 +151,7 @@
 | ||||
|   | ||||
|  static DEFINE_MUTEX(proto_list_mutex); | ||||
|  static LIST_HEAD(proto_list); | ||||
| +DEFINE_COOKIE(sock_cookie);
 | ||||
|   | ||||
|  static void sock_def_write_space_wfree(struct sock *sk); | ||||
|  static void sock_def_write_space(struct sock *sk); | ||||
| @@ -590,6 +592,21 @@ discard_and_relse:
 | ||||
|  } | ||||
|  EXPORT_SYMBOL(__sk_receive_skb); | ||||
|   | ||||
| +u64 __sock_gen_cookie(struct sock *sk)
 | ||||
| +{
 | ||||
| +	u64 res = atomic64_read(&sk->sk_cookie);
 | ||||
| +
 | ||||
| +	if (!res) {
 | ||||
| +		u64 new = gen_cookie_next(&sock_cookie);
 | ||||
| +
 | ||||
| +		atomic64_cmpxchg(&sk->sk_cookie, res, new);
 | ||||
| +
 | ||||
| +		/* Another thread might have changed sk_cookie before us. */
 | ||||
| +		res = atomic64_read(&sk->sk_cookie);
 | ||||
| +	}
 | ||||
| +	return res;
 | ||||
| +}
 | ||||
| +
 | ||||
|  INDIRECT_CALLABLE_DECLARE(struct dst_entry *ip6_dst_check(struct dst_entry *, | ||||
|  							  u32)); | ||||
|  INDIRECT_CALLABLE_DECLARE(struct dst_entry *ipv4_dst_check(struct dst_entry *, | ||||
| @@ -2247,9 +2264,11 @@ static void __sk_free(struct sock *sk)
 | ||||
|  	if (likely(sk->sk_net_refcnt)) | ||||
|  		sock_inuse_add(sock_net(sk), -1); | ||||
|   | ||||
| +#ifdef CONFIG_SOCK_DIAG
 | ||||
|  	if (unlikely(sk->sk_net_refcnt && sock_diag_has_destroy_listeners(sk))) | ||||
|  		sock_diag_broadcast_destroy(sk); | ||||
|  	else | ||||
| +#endif
 | ||||
|  		sk_destruct(sk); | ||||
|  } | ||||
|   | ||||
| --- a/net/core/sock_diag.c
 | ||||
| +++ b/net/core/sock_diag.c
 | ||||
| @@ -12,7 +12,6 @@
 | ||||
|  #include <linux/tcp.h> | ||||
|  #include <linux/workqueue.h> | ||||
|  #include <linux/nospec.h> | ||||
| -#include <linux/cookie.h>
 | ||||
|  #include <linux/inet_diag.h> | ||||
|  #include <linux/sock_diag.h> | ||||
|   | ||||
| @@ -21,23 +20,6 @@ static int (*inet_rcv_compat)(struct sk_
 | ||||
|  static DEFINE_MUTEX(sock_diag_table_mutex); | ||||
|  static struct workqueue_struct *broadcast_wq; | ||||
|   | ||||
| -DEFINE_COOKIE(sock_cookie);
 | ||||
| -
 | ||||
| -u64 __sock_gen_cookie(struct sock *sk)
 | ||||
| -{
 | ||||
| -	u64 res = atomic64_read(&sk->sk_cookie);
 | ||||
| -
 | ||||
| -	if (!res) {
 | ||||
| -		u64 new = gen_cookie_next(&sock_cookie);
 | ||||
| -
 | ||||
| -		atomic64_cmpxchg(&sk->sk_cookie, res, new);
 | ||||
| -
 | ||||
| -		/* Another thread might have changed sk_cookie before us. */
 | ||||
| -		res = atomic64_read(&sk->sk_cookie);
 | ||||
| -	}
 | ||||
| -	return res;
 | ||||
| -}
 | ||||
| -
 | ||||
|  int sock_diag_check_cookie(struct sock *sk, const __u32 *cookie) | ||||
|  { | ||||
|  	u64 res; | ||||
| --- a/net/ipv4/Kconfig
 | ||||
| +++ b/net/ipv4/Kconfig
 | ||||
| @@ -423,6 +423,7 @@ config INET_TUNNEL
 | ||||
|   | ||||
|  config INET_DIAG | ||||
|  	tristate "INET: socket monitoring interface" | ||||
| +	select SOCK_DIAG
 | ||||
|  	default y | ||||
|  	help | ||||
|  	  Support for INET (TCP, DCCP, etc) socket monitoring interface used by | ||||
| --- a/net/netlink/Kconfig
 | ||||
| +++ b/net/netlink/Kconfig
 | ||||
| @@ -5,6 +5,7 @@
 | ||||
|   | ||||
|  config NETLINK_DIAG | ||||
|  	tristate "NETLINK: socket monitoring interface" | ||||
| +	select SOCK_DIAG
 | ||||
|  	default n | ||||
|  	help | ||||
|  	  Support for NETLINK socket monitoring interface used by the ss tool. | ||||
| --- a/net/packet/Kconfig
 | ||||
| +++ b/net/packet/Kconfig
 | ||||
| @@ -19,6 +19,7 @@ config PACKET
 | ||||
|  config PACKET_DIAG | ||||
|  	tristate "Packet: sockets monitoring interface" | ||||
|  	depends on PACKET | ||||
| +	select SOCK_DIAG
 | ||||
|  	default n | ||||
|  	help | ||||
|  	  Support for PF_PACKET sockets monitoring interface used by the ss tool. | ||||
| --- a/net/unix/Kconfig
 | ||||
| +++ b/net/unix/Kconfig
 | ||||
| @@ -29,6 +29,7 @@ config	AF_UNIX_OOB
 | ||||
|  config UNIX_DIAG | ||||
|  	tristate "UNIX: socket monitoring interface" | ||||
|  	depends on UNIX | ||||
| +	select SOCK_DIAG
 | ||||
|  	default n | ||||
|  	help | ||||
|  	  Support for UNIX socket monitoring interface used by the ss tool. | ||||
| --- a/net/xdp/Kconfig
 | ||||
| +++ b/net/xdp/Kconfig
 | ||||
| @@ -10,6 +10,7 @@ config XDP_SOCKETS
 | ||||
|  config XDP_SOCKETS_DIAG | ||||
|  	tristate "XDP sockets: monitoring interface" | ||||
|  	depends on XDP_SOCKETS | ||||
| +	select SOCK_DIAG
 | ||||
|  	default n | ||||
|  	help | ||||
|  	  Support for PF_XDP sockets monitoring interface used by the ss tool. | ||||
							
								
								
									
										419
									
								
								6.10/target/linux/generic/hack-6.10/902-debloat_proc.patch
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										419
									
								
								6.10/target/linux/generic/hack-6.10/902-debloat_proc.patch
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,419 @@ | |||
| From 9e3f1d0805b2d919904dd9a4ff0d956314cc3cba Mon Sep 17 00:00:00 2001 | ||||
| From: Felix Fietkau <nbd@nbd.name> | ||||
| Date: Sat, 8 Jul 2017 08:20:09 +0200 | ||||
| Subject: debloat: procfs | ||||
| 
 | ||||
| Signed-off-by: Felix Fietkau <nbd@nbd.name> | ||||
| ---
 | ||||
|  fs/locks.c               |  2 ++ | ||||
|  fs/proc/Kconfig          |  5 +++++ | ||||
|  fs/proc/consoles.c       |  3 +++ | ||||
|  fs/proc/proc_tty.c       | 11 ++++++++++- | ||||
|  include/net/snmp.h       | 18 +++++++++++++++++- | ||||
|  ipc/msg.c                |  3 +++ | ||||
|  ipc/sem.c                |  2 ++ | ||||
|  ipc/shm.c                |  2 ++ | ||||
|  ipc/util.c               |  3 +++ | ||||
|  kernel/exec_domain.c     |  2 ++ | ||||
|  kernel/irq/proc.c        |  9 +++++++++ | ||||
|  kernel/time/timer_list.c |  2 ++ | ||||
|  mm/vmalloc.c             |  2 ++ | ||||
|  mm/vmstat.c              |  8 +++++--- | ||||
|  net/8021q/vlanproc.c     |  6 ++++++ | ||||
|  net/core/net-procfs.c    | 18 ++++++++++++------ | ||||
|  net/core/sock.c          |  2 ++ | ||||
|  net/ipv4/fib_trie.c      | 18 ++++++++++++------ | ||||
|  net/ipv4/proc.c          |  3 +++ | ||||
|  net/ipv4/route.c         |  3 +++ | ||||
|  20 files changed, 105 insertions(+), 17 deletions(-) | ||||
| 
 | ||||
| --- a/fs/locks.c
 | ||||
| +++ b/fs/locks.c
 | ||||
| @@ -2897,6 +2897,8 @@ static const struct seq_operations locks
 | ||||
|   | ||||
|  static int __init proc_locks_init(void) | ||||
|  { | ||||
| +	if (IS_ENABLED(CONFIG_PROC_STRIPPED))
 | ||||
| +		return 0;
 | ||||
|  	proc_create_seq_private("locks", 0, NULL, &locks_seq_operations, | ||||
|  			sizeof(struct locks_iterator), NULL); | ||||
|  	return 0; | ||||
| --- a/fs/proc/Kconfig
 | ||||
| +++ b/fs/proc/Kconfig
 | ||||
| @@ -101,6 +101,11 @@ config PROC_CHILDREN
 | ||||
|  	  Say Y if you are running any user-space software which takes benefit from | ||||
|  	  this interface. For example, rkt is such a piece of software. | ||||
|   | ||||
| +config PROC_STRIPPED
 | ||||
| +	default n
 | ||||
| +	depends on EXPERT
 | ||||
| +	bool "Strip non-essential /proc functionality to reduce code size"
 | ||||
| +
 | ||||
|  config PROC_PID_ARCH_STATUS | ||||
|  	def_bool n | ||||
|  	depends on PROC_FS | ||||
| --- a/fs/proc/consoles.c
 | ||||
| +++ b/fs/proc/consoles.c
 | ||||
| @@ -107,6 +107,9 @@ static const struct seq_operations conso
 | ||||
|   | ||||
|  static int __init proc_consoles_init(void) | ||||
|  { | ||||
| +	if (IS_ENABLED(CONFIG_PROC_STRIPPED))
 | ||||
| +		return 0;
 | ||||
| +
 | ||||
|  	proc_create_seq("consoles", 0, NULL, &consoles_op); | ||||
|  	return 0; | ||||
|  } | ||||
| --- a/fs/proc/proc_tty.c
 | ||||
| +++ b/fs/proc/proc_tty.c
 | ||||
| @@ -131,7 +131,10 @@ static const struct seq_operations tty_d
 | ||||
|  void proc_tty_register_driver(struct tty_driver *driver) | ||||
|  { | ||||
|  	struct proc_dir_entry *ent; | ||||
| -		
 | ||||
| +
 | ||||
| +	if (IS_ENABLED(CONFIG_PROC_STRIPPED))
 | ||||
| +		return;
 | ||||
| +
 | ||||
|  	if (!driver->driver_name || driver->proc_entry || | ||||
|  	    !driver->ops->proc_show) | ||||
|  		return; | ||||
| @@ -148,6 +151,9 @@ void proc_tty_unregister_driver(struct t
 | ||||
|  { | ||||
|  	struct proc_dir_entry *ent; | ||||
|   | ||||
| +	if (IS_ENABLED(CONFIG_PROC_STRIPPED))
 | ||||
| +		return;
 | ||||
| +
 | ||||
|  	ent = driver->proc_entry; | ||||
|  	if (!ent) | ||||
|  		return; | ||||
| @@ -162,6 +168,9 @@ void proc_tty_unregister_driver(struct t
 | ||||
|   */ | ||||
|  void __init proc_tty_init(void) | ||||
|  { | ||||
| +	if (IS_ENABLED(CONFIG_PROC_STRIPPED))
 | ||||
| +		return;
 | ||||
| +
 | ||||
|  	if (!proc_mkdir("tty", NULL)) | ||||
|  		return; | ||||
|  	proc_mkdir("tty/ldisc", NULL);	/* Preserved: it's userspace visible */ | ||||
| --- a/include/net/snmp.h
 | ||||
| +++ b/include/net/snmp.h
 | ||||
| @@ -124,6 +124,21 @@ struct linux_tls_mib {
 | ||||
|  #define DECLARE_SNMP_STAT(type, name)	\ | ||||
|  	extern __typeof__(type) __percpu *name | ||||
|   | ||||
| +#ifdef CONFIG_PROC_STRIPPED
 | ||||
| +#define __SNMP_STATS_DUMMY(mib)	\
 | ||||
| +	do { (void) mib->mibs[0]; } while(0)
 | ||||
| +
 | ||||
| +#define __SNMP_INC_STATS(mib, field) __SNMP_STATS_DUMMY(mib)
 | ||||
| +#define SNMP_INC_STATS_ATOMIC_LONG(mib, field) __SNMP_STATS_DUMMY(mib)
 | ||||
| +#define SNMP_INC_STATS(mib, field) __SNMP_STATS_DUMMY(mib)
 | ||||
| +#define SNMP_DEC_STATS(mib, field) __SNMP_STATS_DUMMY(mib)
 | ||||
| +#define __SNMP_ADD_STATS(mib, field, addend) __SNMP_STATS_DUMMY(mib)
 | ||||
| +#define SNMP_ADD_STATS(mib, field, addend) __SNMP_STATS_DUMMY(mib)
 | ||||
| +#define SNMP_UPD_PO_STATS(mib, basefield, addend) __SNMP_STATS_DUMMY(mib)
 | ||||
| +#define __SNMP_UPD_PO_STATS(mib, basefield, addend) __SNMP_STATS_DUMMY(mib)
 | ||||
| +
 | ||||
| +#else
 | ||||
| +
 | ||||
|  #define __SNMP_INC_STATS(mib, field)	\ | ||||
|  			__this_cpu_inc(mib->mibs[field]) | ||||
|   | ||||
| @@ -154,8 +169,9 @@ struct linux_tls_mib {
 | ||||
|  		__this_cpu_add(ptr[basefield##OCTETS], addend);	\ | ||||
|  	} while (0) | ||||
|   | ||||
| +#endif
 | ||||
|   | ||||
| -#if BITS_PER_LONG==32
 | ||||
| +#if (BITS_PER_LONG==32) && !defined(CONFIG_PROC_STRIPPED)
 | ||||
|   | ||||
|  #define __SNMP_ADD_STATS64(mib, field, addend) 				\ | ||||
|  	do {								\ | ||||
| --- a/ipc/msg.c
 | ||||
| +++ b/ipc/msg.c
 | ||||
| @@ -1370,6 +1370,9 @@ void __init msg_init(void)
 | ||||
|  { | ||||
|  	msg_init_ns(&init_ipc_ns); | ||||
|   | ||||
| +	if (IS_ENABLED(CONFIG_PROC_STRIPPED))
 | ||||
| +		return;
 | ||||
| +
 | ||||
|  	ipc_init_proc_interface("sysvipc/msg", | ||||
|  				"       key      msqid perms      cbytes       qnum lspid lrpid   uid   gid  cuid  cgid      stime      rtime      ctime\n", | ||||
|  				IPC_MSG_IDS, sysvipc_msg_proc_show); | ||||
| --- a/ipc/sem.c
 | ||||
| +++ b/ipc/sem.c
 | ||||
| @@ -268,6 +268,8 @@ void sem_exit_ns(struct ipc_namespace *n
 | ||||
|  void __init sem_init(void) | ||||
|  { | ||||
|  	sem_init_ns(&init_ipc_ns); | ||||
| +	if (IS_ENABLED(CONFIG_PROC_STRIPPED))
 | ||||
| +		return;
 | ||||
|  	ipc_init_proc_interface("sysvipc/sem", | ||||
|  				"       key      semid perms      nsems   uid   gid  cuid  cgid      otime      ctime\n", | ||||
|  				IPC_SEM_IDS, sysvipc_sem_proc_show); | ||||
| --- a/ipc/shm.c
 | ||||
| +++ b/ipc/shm.c
 | ||||
| @@ -154,6 +154,8 @@ pure_initcall(ipc_ns_init);
 | ||||
|   | ||||
|  void __init shm_init(void) | ||||
|  { | ||||
| +	if (IS_ENABLED(CONFIG_PROC_STRIPPED))
 | ||||
| +		return;
 | ||||
|  	ipc_init_proc_interface("sysvipc/shm", | ||||
|  #if BITS_PER_LONG <= 32 | ||||
|  				"       key      shmid perms       size  cpid  lpid nattch   uid   gid  cuid  cgid      atime      dtime      ctime        rss       swap\n", | ||||
| --- a/ipc/util.c
 | ||||
| +++ b/ipc/util.c
 | ||||
| @@ -141,6 +141,9 @@ void __init ipc_init_proc_interface(cons
 | ||||
|  	struct proc_dir_entry *pde; | ||||
|  	struct ipc_proc_iface *iface; | ||||
|   | ||||
| +	if (IS_ENABLED(CONFIG_PROC_STRIPPED))
 | ||||
| +		return;
 | ||||
| +
 | ||||
|  	iface = kmalloc(sizeof(*iface), GFP_KERNEL); | ||||
|  	if (!iface) | ||||
|  		return; | ||||
| --- a/kernel/exec_domain.c
 | ||||
| +++ b/kernel/exec_domain.c
 | ||||
| @@ -29,6 +29,8 @@ static int execdomains_proc_show(struct
 | ||||
|   | ||||
|  static int __init proc_execdomains_init(void) | ||||
|  { | ||||
| +	if (IS_ENABLED(CONFIG_PROC_STRIPPED))
 | ||||
| +		return 0;
 | ||||
|  	proc_create_single("execdomains", 0, NULL, execdomains_proc_show); | ||||
|  	return 0; | ||||
|  } | ||||
| --- a/kernel/irq/proc.c
 | ||||
| +++ b/kernel/irq/proc.c
 | ||||
| @@ -341,6 +341,9 @@ void register_irq_proc(unsigned int irq,
 | ||||
|  	void __maybe_unused *irqp = (void *)(unsigned long) irq; | ||||
|  	char name [MAX_NAMELEN]; | ||||
|   | ||||
| +	if (IS_ENABLED(CONFIG_PROC_STRIPPED) && !IS_ENABLED(CONFIG_SMP))
 | ||||
| +		return;
 | ||||
| +
 | ||||
|  	if (!root_irq_dir || (desc->irq_data.chip == &no_irq_chip)) | ||||
|  		return; | ||||
|   | ||||
| @@ -394,6 +397,9 @@ void unregister_irq_proc(unsigned int ir
 | ||||
|  { | ||||
|  	char name [MAX_NAMELEN]; | ||||
|   | ||||
| +	if (IS_ENABLED(CONFIG_PROC_STRIPPED) && !IS_ENABLED(CONFIG_SMP))
 | ||||
| +		return;
 | ||||
| +
 | ||||
|  	if (!root_irq_dir || !desc->dir) | ||||
|  		return; | ||||
|  #ifdef CONFIG_SMP | ||||
| @@ -432,6 +438,9 @@ void init_irq_proc(void)
 | ||||
|  	unsigned int irq; | ||||
|  	struct irq_desc *desc; | ||||
|   | ||||
| +	if (IS_ENABLED(CONFIG_PROC_STRIPPED) && !IS_ENABLED(CONFIG_SMP))
 | ||||
| +		return;
 | ||||
| +
 | ||||
|  	/* create /proc/irq */ | ||||
|  	root_irq_dir = proc_mkdir("irq", NULL); | ||||
|  	if (!root_irq_dir) | ||||
| --- a/kernel/time/timer_list.c
 | ||||
| +++ b/kernel/time/timer_list.c
 | ||||
| @@ -350,6 +350,8 @@ static int __init init_timer_list_procfs
 | ||||
|  { | ||||
|  	struct proc_dir_entry *pe; | ||||
|   | ||||
| +	if (IS_ENABLED(CONFIG_PROC_STRIPPED))
 | ||||
| +		return 0;
 | ||||
|  	pe = proc_create_seq_private("timer_list", 0400, NULL, &timer_list_sops, | ||||
|  			sizeof(struct timer_list_iter), NULL); | ||||
|  	if (!pe) | ||||
| --- a/mm/vmalloc.c
 | ||||
| +++ b/mm/vmalloc.c
 | ||||
| @@ -4439,6 +4439,8 @@ static const struct seq_operations vmall
 | ||||
|   | ||||
|  static int __init proc_vmalloc_init(void) | ||||
|  { | ||||
| +	if (IS_ENABLED(CONFIG_PROC_STRIPPED))
 | ||||
| +		return 0;
 | ||||
|  	if (IS_ENABLED(CONFIG_NUMA)) | ||||
|  		proc_create_seq_private("vmallocinfo", 0400, NULL, | ||||
|  				&vmalloc_op, | ||||
| --- a/mm/vmstat.c
 | ||||
| +++ b/mm/vmstat.c
 | ||||
| @@ -2135,10 +2135,12 @@ void __init init_mm_internals(void)
 | ||||
|  	start_shepherd_timer(); | ||||
|  #endif | ||||
|  #ifdef CONFIG_PROC_FS | ||||
| -	proc_create_seq("buddyinfo", 0444, NULL, &fragmentation_op);
 | ||||
| -	proc_create_seq("pagetypeinfo", 0400, NULL, &pagetypeinfo_op);
 | ||||
| +	if (!IS_ENABLED(CONFIG_PROC_STRIPPED)) {
 | ||||
| +		proc_create_seq("buddyinfo", 0444, NULL, &fragmentation_op);
 | ||||
| +		proc_create_seq("pagetypeinfo", 0400, NULL, &pagetypeinfo_op);
 | ||||
| +		proc_create_seq("zoneinfo", 0444, NULL, &zoneinfo_op);
 | ||||
| +	}
 | ||||
|  	proc_create_seq("vmstat", 0444, NULL, &vmstat_op); | ||||
| -	proc_create_seq("zoneinfo", 0444, NULL, &zoneinfo_op);
 | ||||
|  #endif | ||||
|  } | ||||
|   | ||||
| --- a/net/8021q/vlanproc.c
 | ||||
| +++ b/net/8021q/vlanproc.c
 | ||||
| @@ -93,6 +93,9 @@ void vlan_proc_cleanup(struct net *net)
 | ||||
|  { | ||||
|  	struct vlan_net *vn = net_generic(net, vlan_net_id); | ||||
|   | ||||
| +	if (IS_ENABLED(CONFIG_PROC_STRIPPED))
 | ||||
| +		return;
 | ||||
| +
 | ||||
|  	if (vn->proc_vlan_conf) | ||||
|  		remove_proc_entry(name_conf, vn->proc_vlan_dir); | ||||
|   | ||||
| @@ -112,6 +115,9 @@ int __net_init vlan_proc_init(struct net
 | ||||
|  { | ||||
|  	struct vlan_net *vn = net_generic(net, vlan_net_id); | ||||
|   | ||||
| +	if (IS_ENABLED(CONFIG_PROC_STRIPPED))
 | ||||
| +		return 0;
 | ||||
| +
 | ||||
|  	vn->proc_vlan_dir = proc_net_mkdir(net, name_root, net->proc_net); | ||||
|  	if (!vn->proc_vlan_dir) | ||||
|  		goto err; | ||||
| --- a/net/core/net-procfs.c
 | ||||
| +++ b/net/core/net-procfs.c
 | ||||
| @@ -327,10 +327,12 @@ static int __net_init dev_proc_net_init(
 | ||||
|  	if (!proc_create_net("dev", 0444, net->proc_net, &dev_seq_ops, | ||||
|  			sizeof(struct seq_net_private))) | ||||
|  		goto out; | ||||
| -	if (!proc_create_seq("softnet_stat", 0444, net->proc_net,
 | ||||
| +	if (!IS_ENABLED(CONFIG_PROC_STRIPPED) &&
 | ||||
| +			!proc_create_seq("softnet_stat", 0444, net->proc_net,
 | ||||
|  			 &softnet_seq_ops)) | ||||
|  		goto out_dev; | ||||
| -	if (!proc_create_net("ptype", 0444, net->proc_net, &ptype_seq_ops,
 | ||||
| +	if (!IS_ENABLED(CONFIG_PROC_STRIPPED) &&
 | ||||
| +			!proc_create_net("ptype", 0444, net->proc_net, &ptype_seq_ops,
 | ||||
|  			sizeof(struct seq_net_private))) | ||||
|  		goto out_softnet; | ||||
|   | ||||
| @@ -340,9 +342,11 @@ static int __net_init dev_proc_net_init(
 | ||||
|  out: | ||||
|  	return rc; | ||||
|  out_ptype: | ||||
| -	remove_proc_entry("ptype", net->proc_net);
 | ||||
| +	if (!IS_ENABLED(CONFIG_PROC_STRIPPED))
 | ||||
| +		remove_proc_entry("ptype", net->proc_net);
 | ||||
|  out_softnet: | ||||
| -	remove_proc_entry("softnet_stat", net->proc_net);
 | ||||
| +	if (!IS_ENABLED(CONFIG_PROC_STRIPPED))
 | ||||
| +		remove_proc_entry("softnet_stat", net->proc_net);
 | ||||
|  out_dev: | ||||
|  	remove_proc_entry("dev", net->proc_net); | ||||
|  	goto out; | ||||
| @@ -352,8 +356,10 @@ static void __net_exit dev_proc_net_exit
 | ||||
|  { | ||||
|  	wext_proc_exit(net); | ||||
|   | ||||
| -	remove_proc_entry("ptype", net->proc_net);
 | ||||
| -	remove_proc_entry("softnet_stat", net->proc_net);
 | ||||
| +	if (!IS_ENABLED(CONFIG_PROC_STRIPPED)) {
 | ||||
| +		remove_proc_entry("ptype", net->proc_net);
 | ||||
| +		remove_proc_entry("softnet_stat", net->proc_net);
 | ||||
| +	}
 | ||||
|  	remove_proc_entry("dev", net->proc_net); | ||||
|  } | ||||
|   | ||||
| --- a/net/core/sock.c
 | ||||
| +++ b/net/core/sock.c
 | ||||
| @@ -4145,6 +4145,8 @@ static __net_initdata struct pernet_oper
 | ||||
|   | ||||
|  static int __init proto_init(void) | ||||
|  { | ||||
| +	if (IS_ENABLED(CONFIG_PROC_STRIPPED))
 | ||||
| +		return 0;
 | ||||
|  	return register_pernet_subsys(&proto_net_ops); | ||||
|  } | ||||
|   | ||||
| --- a/net/ipv4/fib_trie.c
 | ||||
| +++ b/net/ipv4/fib_trie.c
 | ||||
| @@ -3036,11 +3036,13 @@ static const struct seq_operations fib_r
 | ||||
|   | ||||
|  int __net_init fib_proc_init(struct net *net) | ||||
|  { | ||||
| -	if (!proc_create_net("fib_trie", 0444, net->proc_net, &fib_trie_seq_ops,
 | ||||
| +	if (!IS_ENABLED(CONFIG_PROC_STRIPPED) &&
 | ||||
| +			!proc_create_net("fib_trie", 0444, net->proc_net, &fib_trie_seq_ops,
 | ||||
|  			sizeof(struct fib_trie_iter))) | ||||
|  		goto out1; | ||||
|   | ||||
| -	if (!proc_create_net_single("fib_triestat", 0444, net->proc_net,
 | ||||
| +	if (!IS_ENABLED(CONFIG_PROC_STRIPPED) &&
 | ||||
| +			!proc_create_net_single("fib_triestat", 0444, net->proc_net,
 | ||||
|  			fib_triestat_seq_show, NULL)) | ||||
|  		goto out2; | ||||
|   | ||||
| @@ -3051,17 +3053,21 @@ int __net_init fib_proc_init(struct net
 | ||||
|  	return 0; | ||||
|   | ||||
|  out3: | ||||
| -	remove_proc_entry("fib_triestat", net->proc_net);
 | ||||
| +	if (!IS_ENABLED(CONFIG_PROC_STRIPPED))
 | ||||
| +		remove_proc_entry("fib_triestat", net->proc_net);
 | ||||
|  out2: | ||||
| -	remove_proc_entry("fib_trie", net->proc_net);
 | ||||
| +	if (!IS_ENABLED(CONFIG_PROC_STRIPPED))
 | ||||
| +		remove_proc_entry("fib_trie", net->proc_net);
 | ||||
|  out1: | ||||
|  	return -ENOMEM; | ||||
|  } | ||||
|   | ||||
|  void __net_exit fib_proc_exit(struct net *net) | ||||
|  { | ||||
| -	remove_proc_entry("fib_trie", net->proc_net);
 | ||||
| -	remove_proc_entry("fib_triestat", net->proc_net);
 | ||||
| +	if (!IS_ENABLED(CONFIG_PROC_STRIPPED)) {
 | ||||
| +		remove_proc_entry("fib_trie", net->proc_net);
 | ||||
| +		remove_proc_entry("fib_triestat", net->proc_net);
 | ||||
| +	}
 | ||||
|  	remove_proc_entry("route", net->proc_net); | ||||
|  } | ||||
|   | ||||
| --- a/net/ipv4/proc.c
 | ||||
| +++ b/net/ipv4/proc.c
 | ||||
| @@ -557,5 +557,8 @@ static __net_initdata struct pernet_oper
 | ||||
|   | ||||
|  int __init ip_misc_proc_init(void) | ||||
|  { | ||||
| +	if (IS_ENABLED(CONFIG_PROC_STRIPPED))
 | ||||
| +		return 0;
 | ||||
| +
 | ||||
|  	return register_pernet_subsys(&ip_proc_ops); | ||||
|  } | ||||
| --- a/net/ipv4/route.c
 | ||||
| +++ b/net/ipv4/route.c
 | ||||
| @@ -380,6 +380,9 @@ static struct pernet_operations ip_rt_pr
 | ||||
|   | ||||
|  static int __init ip_rt_proc_init(void) | ||||
|  { | ||||
| +	if (IS_ENABLED(CONFIG_PROC_STRIPPED))
 | ||||
| +		return 0;
 | ||||
| +
 | ||||
|  	return register_pernet_subsys(&ip_rt_proc_ops); | ||||
|  } | ||||
|   | ||||
| --- a/net/ipv4/inet_timewait_sock.c
 | ||||
| +++ b/net/ipv4/inet_timewait_sock.c
 | ||||
| @@ -266,7 +266,7 @@ void __inet_twsk_schedule(struct inet_ti
 | ||||
|  	 */ | ||||
|   | ||||
|  	if (!rearm) { | ||||
| -		bool kill = timeo <= 4*HZ;
 | ||||
| +		bool __maybe_unused  kill = timeo <= 4*HZ;
 | ||||
|   | ||||
|  		__NET_INC_STATS(twsk_net(tw), kill ? LINUX_MIB_TIMEWAITKILLED : | ||||
|  						     LINUX_MIB_TIMEWAITED); | ||||
|  | @ -0,0 +1,93 @@ | |||
| From e3692cb2fcd5ba1244512a0f43b8118f65f1c375 Mon Sep 17 00:00:00 2001 | ||||
| From: Felix Fietkau <nbd@nbd.name> | ||||
| Date: Sat, 8 Jul 2017 08:20:43 +0200 | ||||
| Subject: debloat: dmabuf | ||||
| 
 | ||||
| Signed-off-by: Felix Fietkau <nbd@nbd.name> | ||||
| ---
 | ||||
|  drivers/base/Kconfig      |  2 +- | ||||
|  drivers/dma-buf/Makefile  | 10 +++++++--- | ||||
|  drivers/dma-buf/dma-buf.c |  4 +++- | ||||
|  kernel/sched/core.c       |  1 + | ||||
|  4 files changed, 12 insertions(+), 5 deletions(-) | ||||
| 
 | ||||
| --- a/drivers/base/Kconfig
 | ||||
| +++ b/drivers/base/Kconfig
 | ||||
| @@ -198,7 +198,7 @@ config SOC_BUS
 | ||||
|  source "drivers/base/regmap/Kconfig" | ||||
|   | ||||
|  config DMA_SHARED_BUFFER | ||||
| -	bool
 | ||||
| +	tristate
 | ||||
|  	default n | ||||
|  	select IRQ_WORK | ||||
|  	help | ||||
| --- a/drivers/dma-buf/heaps/Makefile
 | ||||
| +++ b/drivers/dma-buf/heaps/Makefile
 | ||||
| @@ -1,3 +1,3 @@
 | ||||
|  # SPDX-License-Identifier: GPL-2.0 | ||||
| -obj-$(CONFIG_DMABUF_HEAPS_SYSTEM)	+= system_heap.o
 | ||||
| -obj-$(CONFIG_DMABUF_HEAPS_CMA)		+= cma_heap.o
 | ||||
| +dma-buf-objs-$(CONFIG_DMABUF_HEAPS_SYSTEM)	+= system_heap.o
 | ||||
| +dma-buf-objs-$(CONFIG_DMABUF_HEAPS_CMA)		+= cma_heap.o
 | ||||
| --- a/drivers/dma-buf/Makefile
 | ||||
| +++ b/drivers/dma-buf/Makefile
 | ||||
| @@ -1,12 +1,14 @@
 | ||||
|  # SPDX-License-Identifier: GPL-2.0-only | ||||
| -obj-y := dma-buf.o dma-fence.o dma-fence-array.o dma-fence-chain.o \
 | ||||
| +obj-$(CONFIG_DMA_SHARED_BUFFER) := dma-shared-buffer.o
 | ||||
| +
 | ||||
| +dma-buf-objs-y := dma-buf.o dma-fence.o dma-fence-array.o dma-fence-chain.o \
 | ||||
|  	 dma-fence-unwrap.o dma-resv.o | ||||
| -obj-$(CONFIG_DMABUF_HEAPS)	+= dma-heap.o
 | ||||
| -obj-$(CONFIG_DMABUF_HEAPS)	+= heaps/
 | ||||
| -obj-$(CONFIG_SYNC_FILE)		+= sync_file.o
 | ||||
| -obj-$(CONFIG_SW_SYNC)		+= sw_sync.o sync_debug.o
 | ||||
| -obj-$(CONFIG_UDMABUF)		+= udmabuf.o
 | ||||
| -obj-$(CONFIG_DMABUF_SYSFS_STATS) += dma-buf-sysfs-stats.o
 | ||||
| +dma-buf-objs-$(CONFIG_DMABUF_HEAPS)	+= dma-heap.o
 | ||||
| +obj-$(CONFIG_DMABUF_HEAPS)		+= heaps/
 | ||||
| +dma-buf-objs-$(CONFIG_SYNC_FILE)	+= sync_file.o
 | ||||
| +dma-buf-objs-$(CONFIG_SW_SYNC)		+= sw_sync.o sync_debug.o
 | ||||
| +dma-buf-objs-$(CONFIG_UDMABUF)		+= udmabuf.o
 | ||||
| +dma-buf-objs-$(CONFIG_DMABUF_SYSFS_STATS) += dma-buf-sysfs-stats.o
 | ||||
|   | ||||
|  dmabuf_selftests-y := \ | ||||
|  	selftest.o \ | ||||
| @@ -15,4 +17,6 @@ dmabuf_selftests-y := \
 | ||||
|  	st-dma-fence-unwrap.o \ | ||||
|  	st-dma-resv.o | ||||
|   | ||||
| -obj-$(CONFIG_DMABUF_SELFTESTS)	+= dmabuf_selftests.o
 | ||||
| +dma-buf-objs-$(CONFIG_DMABUF_SELFTESTS)	+= dmabuf_selftests.o
 | ||||
| +
 | ||||
| +dma-shared-buffer-objs :=  $(dma-buf-objs-y)
 | ||||
| --- a/drivers/dma-buf/dma-buf.c
 | ||||
| +++ b/drivers/dma-buf/dma-buf.c
 | ||||
| @@ -1731,4 +1731,5 @@ static void __exit dma_buf_deinit(void)
 | ||||
|  	kern_unmount(dma_buf_mnt); | ||||
|  	dma_buf_uninit_sysfs_statistics(); | ||||
|  } | ||||
| -__exitcall(dma_buf_deinit);
 | ||||
| +module_exit(dma_buf_deinit);
 | ||||
| +MODULE_LICENSE("GPL");
 | ||||
| --- a/kernel/sched/core.c
 | ||||
| +++ b/kernel/sched/core.c
 | ||||
| @@ -4487,6 +4487,7 @@ int wake_up_state(struct task_struct *p,
 | ||||
|  { | ||||
|  	return try_to_wake_up(p, state, 0); | ||||
|  } | ||||
| +EXPORT_SYMBOL_GPL(wake_up_state);
 | ||||
|   | ||||
|  /* | ||||
|   * Perform scheduler related setup for a newly forked process p. | ||||
| --- a/fs/d_path.c
 | ||||
| +++ b/fs/d_path.c
 | ||||
| @@ -314,6 +314,7 @@ char *dynamic_dname(char *buffer, int bu
 | ||||
|  	buffer += buflen - sz; | ||||
|  	return memcpy(buffer, temp, sz); | ||||
|  } | ||||
| +EXPORT_SYMBOL_GPL(dynamic_dname);
 | ||||
|   | ||||
|  char *simple_dname(struct dentry *dentry, char *buffer, int buflen) | ||||
|  { | ||||
							
								
								
									
										32
									
								
								6.10/target/linux/generic/hack-6.10/910-kobject_uevent.patch
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								6.10/target/linux/generic/hack-6.10/910-kobject_uevent.patch
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,32 @@ | |||
| From 0d37e6edc09c99e683dd91ca0e83bbc0df8477b3 Mon Sep 17 00:00:00 2001 | ||||
| From: Felix Fietkau <nbd@nbd.name> | ||||
| Date: Sun, 16 Jul 2017 16:56:10 +0200 | ||||
| Subject: lib: add uevent_next_seqnum() | ||||
| 
 | ||||
| Signed-off-by: Felix Fietkau <nbd@nbd.name> | ||||
| ---
 | ||||
|  include/linux/kobject.h |  5 +++++ | ||||
|  lib/kobject_uevent.c    | 37 +++++++++++++++++++++++++++++++++++++ | ||||
|  2 files changed, 42 insertions(+) | ||||
| 
 | ||||
| --- a/lib/kobject_uevent.c
 | ||||
| +++ b/lib/kobject_uevent.c
 | ||||
| @@ -179,6 +179,18 @@ out:
 | ||||
|  	return r; | ||||
|  } | ||||
|   | ||||
| +u64 uevent_next_seqnum(void)
 | ||||
| +{
 | ||||
| +	u64 seq;
 | ||||
| +
 | ||||
| +	mutex_lock(&uevent_sock_mutex);
 | ||||
| +	seq = ++uevent_seqnum;
 | ||||
| +	mutex_unlock(&uevent_sock_mutex);
 | ||||
| +
 | ||||
| +	return seq;
 | ||||
| +}
 | ||||
| +EXPORT_SYMBOL_GPL(uevent_next_seqnum);
 | ||||
| +
 | ||||
|  /** | ||||
|   * kobject_synth_uevent - send synthetic uevent with arguments | ||||
|   * | ||||
|  | @ -0,0 +1,76 @@ | |||
| From 0d37e6edc09c99e683dd91ca0e83bbc0df8477b3 Mon Sep 17 00:00:00 2001 | ||||
| From: Felix Fietkau <nbd@nbd.name> | ||||
| Date: Sun, 16 Jul 2017 16:56:10 +0200 | ||||
| Subject: lib: add uevent_next_seqnum() | ||||
| 
 | ||||
| Signed-off-by: Felix Fietkau <nbd@nbd.name> | ||||
| ---
 | ||||
|  include/linux/kobject.h |  5 +++++ | ||||
|  lib/kobject_uevent.c    | 37 +++++++++++++++++++++++++++++++++++++ | ||||
|  2 files changed, 42 insertions(+) | ||||
| 
 | ||||
| --- a/include/linux/kobject.h
 | ||||
| +++ b/include/linux/kobject.h
 | ||||
| @@ -32,6 +32,8 @@
 | ||||
|  #define UEVENT_NUM_ENVP			64	/* number of env pointers */ | ||||
|  #define UEVENT_BUFFER_SIZE		2048	/* buffer for the variables */ | ||||
|   | ||||
| +struct sk_buff;
 | ||||
| +
 | ||||
|  #ifdef CONFIG_UEVENT_HELPER | ||||
|  /* path to the userspace helper executed on an event */ | ||||
|  extern char uevent_helper[]; | ||||
| @@ -219,4 +221,7 @@ int kobject_synth_uevent(struct kobject
 | ||||
|  __printf(2, 3) | ||||
|  int add_uevent_var(struct kobj_uevent_env *env, const char *format, ...); | ||||
|   | ||||
| +int broadcast_uevent(struct sk_buff *skb, __u32 pid, __u32 group,
 | ||||
| +		     gfp_t allocation);
 | ||||
| +
 | ||||
|  #endif /* _KOBJECT_H_ */ | ||||
| --- a/lib/kobject_uevent.c
 | ||||
| +++ b/lib/kobject_uevent.c
 | ||||
| @@ -691,6 +691,43 @@ int add_uevent_var(struct kobj_uevent_en
 | ||||
|  EXPORT_SYMBOL_GPL(add_uevent_var); | ||||
|   | ||||
|  #if defined(CONFIG_NET) | ||||
| +int broadcast_uevent(struct sk_buff *skb, __u32 pid, __u32 group,
 | ||||
| +		     gfp_t allocation)
 | ||||
| +{
 | ||||
| +	struct uevent_sock *ue_sk;
 | ||||
| +	int err = 0;
 | ||||
| +
 | ||||
| +	/* send netlink message */
 | ||||
| +	mutex_lock(&uevent_sock_mutex);
 | ||||
| +	list_for_each_entry(ue_sk, &uevent_sock_list, list) {
 | ||||
| +		struct sock *uevent_sock = ue_sk->sk;
 | ||||
| +		struct sk_buff *skb2;
 | ||||
| +
 | ||||
| +		skb2 = skb_clone(skb, allocation);
 | ||||
| +		if (!skb2)
 | ||||
| +			break;
 | ||||
| +
 | ||||
| +		err = netlink_broadcast(uevent_sock, skb2, pid, group,
 | ||||
| +					allocation);
 | ||||
| +		if (err)
 | ||||
| +			break;
 | ||||
| +	}
 | ||||
| +	mutex_unlock(&uevent_sock_mutex);
 | ||||
| +
 | ||||
| +	kfree_skb(skb);
 | ||||
| +	return err;
 | ||||
| +}
 | ||||
| +#else
 | ||||
| +int broadcast_uevent(struct sk_buff *skb, __u32 pid, __u32 group,
 | ||||
| +		     gfp_t allocation)
 | ||||
| +{
 | ||||
| +	kfree_skb(skb);
 | ||||
| +	return 0;
 | ||||
| +}
 | ||||
| +#endif
 | ||||
| +EXPORT_SYMBOL_GPL(broadcast_uevent);
 | ||||
| +
 | ||||
| +#if defined(CONFIG_NET)
 | ||||
|  static int uevent_net_broadcast(struct sock *usk, struct sk_buff *skb, | ||||
|  				struct netlink_ext_ack *extack) | ||||
|  { | ||||
|  | @ -0,0 +1,21 @@ | |||
| From e08bcbbaa52fcc41f02743fd2e62a33255ce52da Mon Sep 17 00:00:00 2001 | ||||
| From: OpenWrt community <openwrt-devel@lists.openwrt.org> | ||||
| Date: Wed, 13 Jul 2022 13:52:28 +0200 | ||||
| Subject: [PATCH] of/ftd: add device tree cmdline | ||||
| 
 | ||||
| ---
 | ||||
|  drivers/of/fdt.c | 3 +++ | ||||
|  1 file changed, 3 insertions(+) | ||||
| 
 | ||||
| --- a/drivers/of/fdt.c
 | ||||
| +++ b/drivers/of/fdt.c
 | ||||
| @@ -1185,6 +1185,9 @@ int __init early_init_dt_scan_chosen(cha
 | ||||
|  	p = of_get_flat_dt_prop(node, "bootargs", &l); | ||||
|  	if (p != NULL && l > 0) | ||||
|  		strscpy(cmdline, p, min(l, COMMAND_LINE_SIZE)); | ||||
| +	p = of_get_flat_dt_prop(node, "bootargs-append", &l);
 | ||||
| +	if (p != NULL && l > 0)
 | ||||
| +		strlcat(cmdline, p, min_t(int, strlen(cmdline) + (int)l, COMMAND_LINE_SIZE));
 | ||||
|   | ||||
|  handle_cmdline: | ||||
|  	/* | ||||
|  | @ -0,0 +1,30 @@ | |||
| From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl> | ||||
| Date: Tue, 19 Jul 2022 06:17:48 +0200 | ||||
| Subject: [PATCH] Revert "Revert "Revert "driver core: Set fw_devlink=on by | ||||
|  default""" | ||||
| MIME-Version: 1.0 | ||||
| Content-Type: text/plain; charset=UTF-8 | ||||
| Content-Transfer-Encoding: 8bit | ||||
| 
 | ||||
| This reverts commit ea718c699055c8566eb64432388a04974c43b2ea. | ||||
| 
 | ||||
| With of_platform_populate() called for MTD partitions that commit breaks | ||||
| probing devices which reference MTD in device tree. | ||||
| 
 | ||||
| Link: https://lore.kernel.org/all/696cb2da-20b9-b3dd-46d9-de4bf91a1506@gmail.com/T/#u | ||||
| Signed-off-by: Rafał Miłecki <rafal@milecki.pl> | ||||
| ---
 | ||||
|  drivers/base/core.c | 2 +- | ||||
|  1 file changed, 1 insertion(+), 1 deletion(-) | ||||
| 
 | ||||
| --- a/drivers/base/core.c
 | ||||
| +++ b/drivers/base/core.c
 | ||||
| @@ -1657,7 +1657,7 @@ static void device_links_purge(struct de
 | ||||
|  #define FW_DEVLINK_FLAGS_RPM		(FW_DEVLINK_FLAGS_ON | \ | ||||
|  					 DL_FLAG_PM_RUNTIME) | ||||
|   | ||||
| -static u32 fw_devlink_flags = FW_DEVLINK_FLAGS_ON;
 | ||||
| +static u32 fw_devlink_flags = FW_DEVLINK_FLAGS_PERMISSIVE;
 | ||||
|  static int __init fw_devlink_setup(char *arg) | ||||
|  { | ||||
|  	if (!arg) | ||||
							
								
								
									
										4011
									
								
								6.10/target/linux/generic/hack-6.10/997-BBRv3.patch
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										4011
									
								
								6.10/target/linux/generic/hack-6.10/997-BBRv3.patch
									
										
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										81
									
								
								6.10/target/linux/generic/hack-6.10/998-ndpi-hook.patch
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								6.10/target/linux/generic/hack-6.10/998-ndpi-hook.patch
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,81 @@ | |||
| diff -urpN linux-6.1.38.old/include/net/netfilter/nf_conntrack.h linux-6.1.38/include/net/netfilter/nf_conntrack.h
 | ||||
| --- linux-6.1.38.old/include/net/netfilter/nf_conntrack.h	2023-07-05 23:27:38.000000000 +0600
 | ||||
| +++ linux-6.1.38/include/net/netfilter/nf_conntrack.h	2023-07-14 12:34:56.663750711 +0600
 | ||||
| @@ -362,6 +362,11 @@ static inline struct nf_conntrack_net *n
 | ||||
|  	return net_generic(net, nf_conntrack_net_id); | ||||
|  } | ||||
|   | ||||
| +#ifdef CONFIG_NF_CONNTRACK_DESTROY_HOOK
 | ||||
| +void register_nf_ct_destroy_hook(void (*hook)(struct nf_conn *));
 | ||||
| +void unregister_nf_ct_destroy_hook(void);
 | ||||
| +#endif
 | ||||
| +
 | ||||
|  #define NF_CT_STAT_INC(net, count)	  __this_cpu_inc((net)->ct.stat->count) | ||||
|  #define NF_CT_STAT_INC_ATOMIC(net, count) this_cpu_inc((net)->ct.stat->count) | ||||
|  #define NF_CT_STAT_ADD_ATOMIC(net, count, v) this_cpu_add((net)->ct.stat->count, (v)) | ||||
| diff -urpN linux-6.1.38.old/net/netfilter/Kconfig linux-6.1.38/net/netfilter/Kconfig
 | ||||
| --- linux-6.1.38.old/net/netfilter/Kconfig	2023-07-05 23:27:38.000000000 +0600
 | ||||
| +++ linux-6.1.38/net/netfilter/Kconfig	2023-07-14 12:34:11.966879899 +0600
 | ||||
| @@ -76,11 +76,15 @@ config NETFILTER_NETLINK_OSF
 | ||||
|  	  If this option is enabled, the kernel will include support | ||||
|  	  for passive OS fingerprint via NFNETLINK. | ||||
|   | ||||
| +config NF_CONNTRACK_DESTROY_HOOK
 | ||||
| +	bool
 | ||||
| +
 | ||||
|  config NF_CONNTRACK | ||||
|  	tristate "Netfilter connection tracking support" | ||||
|  	default m if NETFILTER_ADVANCED=n | ||||
|  	select NF_DEFRAG_IPV4 | ||||
|  	select NF_DEFRAG_IPV6 if IPV6 != n | ||||
| +	select NF_CONNTRACK_DESTROY_HOOK
 | ||||
|  	help | ||||
|  	  Connection tracking keeps a record of what packets have passed | ||||
|  	  through your machine, in order to figure out how they are related | ||||
| diff -urpN linux-6.1.38.old/net/netfilter/nf_conntrack_core.c linux-6.1.38/net/netfilter/nf_conntrack_core.c
 | ||||
| --- linux-6.1.38.old/net/netfilter/nf_conntrack_core.c	2023-07-05 23:27:38.000000000 +0600
 | ||||
| +++ linux-6.1.38/net/netfilter/nf_conntrack_core.c	2023-07-14 12:33:45.580092713 +0600
 | ||||
| @@ -582,9 +582,30 @@ static void destroy_gre_conntrack(struct
 | ||||
|  #endif | ||||
|  } | ||||
|   | ||||
| +#ifdef CONFIG_NF_CONNTRACK_DESTROY_HOOK
 | ||||
| +
 | ||||
| +static void (*nf_ct_destroy_hook)(struct nf_conn *) __rcu __read_mostly = NULL;
 | ||||
| +
 | ||||
| +void register_nf_ct_destroy_hook(void (*hook)(struct nf_conn *))
 | ||||
| +{
 | ||||
| +	rcu_assign_pointer(nf_ct_destroy_hook, hook);
 | ||||
| +}
 | ||||
| +EXPORT_SYMBOL(register_nf_ct_destroy_hook);
 | ||||
| +
 | ||||
| +void unregister_nf_ct_destroy_hook(void)
 | ||||
| +{
 | ||||
| +	rcu_assign_pointer(nf_ct_destroy_hook, NULL);
 | ||||
| +}
 | ||||
| +
 | ||||
| +EXPORT_SYMBOL(unregister_nf_ct_destroy_hook);
 | ||||
| +#endif
 | ||||
| +
 | ||||
|  void nf_ct_destroy(struct nf_conntrack *nfct) | ||||
|  { | ||||
|  	struct nf_conn *ct = (struct nf_conn *)nfct; | ||||
| +#ifdef CONFIG_NF_CONNTRACK_DESTROY_HOOK
 | ||||
| +	void (*hook)(struct nf_conn *);
 | ||||
| +#endif
 | ||||
|   | ||||
|  	pr_debug("%s(%p)\n", __func__, ct); | ||||
|  	WARN_ON(refcount_read(&nfct->use) != 0); | ||||
| @@ -594,6 +615,12 @@ void nf_ct_destroy(struct nf_conntrack *
 | ||||
|  		return; | ||||
|  	} | ||||
|   | ||||
| +#ifdef CONFIG_NF_CONNTRACK_DESTROY_HOOK
 | ||||
| +	hook = rcu_dereference(nf_ct_destroy_hook);
 | ||||
| +	if (hook)
 | ||||
| +		hook(ct);
 | ||||
| +#endif
 | ||||
| +
 | ||||
|  	if (unlikely(nf_ct_protonum(ct) == IPPROTO_GRE)) | ||||
|  		destroy_gre_conntrack(ct); | ||||
|   | ||||
							
								
								
									
										427
									
								
								6.10/target/linux/generic/hack-6.10/999-mptcp-bpf.patch
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										427
									
								
								6.10/target/linux/generic/hack-6.10/999-mptcp-bpf.patch
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,427 @@ | |||
| From f1dfe037fdf0c300f38bab0bb8f256d4195d45e8 Mon Sep 17 00:00:00 2001 | ||||
| From: Geliang Tang <geliang.tang@suse.com> | ||||
| Date: Tue, 19 Dec 2023 13:27:59 +0100 | ||||
| Subject: [PATCH] mptcp: add sched_data helpers | ||||
| 
 | ||||
| Add a new helper mptcp_sched_data_set_contexts() to set the subflow | ||||
| pointers array in struct mptcp_sched_data. Add a new helper | ||||
| mptcp_subflow_ctx_by_pos() to get the given pos subflow from the | ||||
| contexts array in struct mptcp_sched_data. They will be invoked by | ||||
| the BPF schedulers to export the subflow pointers to the BPF contexts. | ||||
| 
 | ||||
| Signed-off-by: Geliang Tang <geliang.tang@suse.com> | ||||
| Reviewed-by: Mat Martineau <martineau@kernel.org> | ||||
| ---
 | ||||
|  net/mptcp/bpf.c      | 14 ++++++++++++++ | ||||
|  net/mptcp/protocol.h |  2 ++ | ||||
|  net/mptcp/sched.c    | 22 ++++++++++++++++++++++ | ||||
|  3 files changed, 38 insertions(+) | ||||
| 
 | ||||
| diff --git a/net/mptcp/bpf.c b/net/mptcp/bpf.c
 | ||||
| index 8a16672b94e23..c3d62535eb0cf 100644
 | ||||
| --- a/net/mptcp/bpf.c
 | ||||
| +++ b/net/mptcp/bpf.c
 | ||||
| @@ -29,6 +29,20 @@ static const struct btf_kfunc_id_set bpf_mptcp_fmodret_set = {
 | ||||
|  	.set   = &bpf_mptcp_fmodret_ids, | ||||
|  }; | ||||
|   | ||||
| +__diag_push();
 | ||||
| +__diag_ignore_all("-Wmissing-prototypes",
 | ||||
| +		  "kfuncs which will be used in BPF programs");
 | ||||
| +
 | ||||
| +__bpf_kfunc struct mptcp_subflow_context *
 | ||||
| +bpf_mptcp_subflow_ctx_by_pos(const struct mptcp_sched_data *data, unsigned int pos)
 | ||||
| +{
 | ||||
| +	if (pos >= MPTCP_SUBFLOWS_MAX)
 | ||||
| +		return NULL;
 | ||||
| +	return data->contexts[pos];
 | ||||
| +}
 | ||||
| +
 | ||||
| +__diag_pop();
 | ||||
| +
 | ||||
|  static int __init bpf_mptcp_kfunc_init(void) | ||||
|  { | ||||
|  	return register_btf_fmodret_id_set(&bpf_mptcp_fmodret_set); | ||||
| diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h
 | ||||
| index 3517f2d24a226..7cf5d2de74419 100644
 | ||||
| --- a/net/mptcp/protocol.h
 | ||||
| +++ b/net/mptcp/protocol.h
 | ||||
| @@ -636,6 +636,8 @@ void __mptcp_subflow_send_ack(struct sock *ssk);
 | ||||
|  void mptcp_subflow_reset(struct sock *ssk); | ||||
|  void mptcp_subflow_queue_clean(struct sock *sk, struct sock *ssk); | ||||
|  void mptcp_sock_graft(struct sock *sk, struct socket *parent); | ||||
| +struct mptcp_subflow_context *
 | ||||
| +bpf_mptcp_subflow_ctx_by_pos(const struct mptcp_sched_data *data, unsigned int pos);
 | ||||
|  struct sock *__mptcp_nmpc_sk(struct mptcp_sock *msk); | ||||
|  bool __mptcp_close(struct sock *sk, long timeout); | ||||
|  void mptcp_cancel_work(struct sock *sk); | ||||
| diff --git a/net/mptcp/sched.c b/net/mptcp/sched.c
 | ||||
| index 4ab0693c069c0..a7e1c10b19848 100644
 | ||||
| --- a/net/mptcp/sched.c
 | ||||
| +++ b/net/mptcp/sched.c
 | ||||
| @@ -121,6 +121,26 @@ void mptcp_subflow_set_scheduled(struct mptcp_subflow_context *subflow,
 | ||||
|  	WRITE_ONCE(subflow->scheduled, scheduled); | ||||
|  } | ||||
|   | ||||
| +static void mptcp_sched_data_set_contexts(const struct mptcp_sock *msk,
 | ||||
| +					  struct mptcp_sched_data *data)
 | ||||
| +{
 | ||||
| +	struct mptcp_subflow_context *subflow;
 | ||||
| +	int i = 0;
 | ||||
| +
 | ||||
| +	mptcp_for_each_subflow(msk, subflow) {
 | ||||
| +		if (i == MPTCP_SUBFLOWS_MAX) {
 | ||||
| +			pr_warn_once("too many subflows");
 | ||||
| +			break;
 | ||||
| +		}
 | ||||
| +		mptcp_subflow_set_scheduled(subflow, false);
 | ||||
| +		data->contexts[i++] = subflow;
 | ||||
| +	}
 | ||||
| +	data->subflows = i;
 | ||||
| +
 | ||||
| +	for (; i < MPTCP_SUBFLOWS_MAX; i++)
 | ||||
| +		data->contexts[i] = NULL;
 | ||||
| +}
 | ||||
| +
 | ||||
|  int mptcp_sched_get_send(struct mptcp_sock *msk) | ||||
|  { | ||||
|  	struct mptcp_subflow_context *subflow; | ||||
| @@ -147,6 +167,7 @@ int mptcp_sched_get_send(struct mptcp_sock *msk)
 | ||||
|  	data.reinject = false; | ||||
|  	if (msk->sched == &mptcp_sched_default || !msk->sched) | ||||
|  		return mptcp_sched_default_get_subflow(msk, &data); | ||||
| +	mptcp_sched_data_set_contexts(msk, &data);
 | ||||
|  	return msk->sched->get_subflow(msk, &data); | ||||
|  } | ||||
|   | ||||
| @@ -169,5 +190,6 @@ int mptcp_sched_get_retrans(struct mptcp_sock *msk)
 | ||||
|  	data.reinject = true; | ||||
|  	if (msk->sched == &mptcp_sched_default || !msk->sched) | ||||
|  		return mptcp_sched_default_get_subflow(msk, &data); | ||||
| +	mptcp_sched_data_set_contexts(msk, &data);
 | ||||
|  	return msk->sched->get_subflow(msk, &data); | ||||
|  } | ||||
| From 229208a99e76be925541e898fd9a272984b5958c Mon Sep 17 00:00:00 2001 | ||||
| From: Geliang Tang <geliang.tang@suse.com> | ||||
| Date: Tue, 19 Dec 2023 13:28:00 +0100 | ||||
| Subject: [PATCH] bpf: Add bpf_mptcp_sched_ops | ||||
| 
 | ||||
| This patch implements a new struct bpf_struct_ops: bpf_mptcp_sched_ops. | ||||
| Register and unregister the bpf scheduler in .reg and .unreg. | ||||
| 
 | ||||
| Add write access for the scheduled flag of struct mptcp_subflow_context | ||||
| in .btf_struct_access. | ||||
| 
 | ||||
| This MPTCP BPF scheduler implementation is similar to BPF TCP CC. And | ||||
| net/ipv4/bpf_tcp_ca.c is a frame of reference for this patch. | ||||
| 
 | ||||
| Acked-by: Paolo Abeni <pabeni@redhat.com> | ||||
| Reviewed-by: Mat Martineau <martineau@kernel.org> | ||||
| Co-developed-by: Matthieu Baerts <matttbe@kernel.org> | ||||
| Signed-off-by: Matthieu Baerts <matttbe@kernel.org> | ||||
| Signed-off-by: Geliang Tang <geliang.tang@suse.com> | ||||
| ---
 | ||||
|  kernel/bpf/bpf_struct_ops_types.h |   4 + | ||||
|  net/mptcp/bpf.c                   | 146 ++++++++++++++++++++++++++++++ | ||||
|  2 files changed, 150 insertions(+) | ||||
| 
 | ||||
| diff --git a/kernel/bpf/bpf_struct_ops_types.h b/kernel/bpf/bpf_struct_ops_types.h
 | ||||
| index 5678a9ddf8178..5a6b0c0d8d3db 100644
 | ||||
| --- a/kernel/bpf/bpf_struct_ops_types.h
 | ||||
| +++ b/kernel/bpf/bpf_struct_ops_types.h
 | ||||
| @@ -8,5 +8,9 @@ BPF_STRUCT_OPS_TYPE(bpf_dummy_ops)
 | ||||
|  #ifdef CONFIG_INET | ||||
|  #include <net/tcp.h> | ||||
|  BPF_STRUCT_OPS_TYPE(tcp_congestion_ops) | ||||
| +#ifdef CONFIG_MPTCP
 | ||||
| +#include <net/mptcp.h>
 | ||||
| +BPF_STRUCT_OPS_TYPE(mptcp_sched_ops)
 | ||||
| +#endif
 | ||||
|  #endif | ||||
|  #endif | ||||
| diff --git a/net/mptcp/bpf.c b/net/mptcp/bpf.c
 | ||||
| index c3d62535eb0cf..dfcaaf0e07dd5 100644
 | ||||
| --- a/net/mptcp/bpf.c
 | ||||
| +++ b/net/mptcp/bpf.c
 | ||||
| @@ -10,8 +10,153 @@
 | ||||
|  #define pr_fmt(fmt) "MPTCP: " fmt | ||||
|   | ||||
|  #include <linux/bpf.h> | ||||
| +#include <linux/bpf_verifier.h>
 | ||||
| +#include <linux/btf.h>
 | ||||
| +#include <linux/btf_ids.h>
 | ||||
| +#include <net/bpf_sk_storage.h>
 | ||||
|  #include "protocol.h" | ||||
|   | ||||
| +#ifdef CONFIG_BPF_JIT
 | ||||
| +extern struct bpf_struct_ops bpf_mptcp_sched_ops;
 | ||||
| +static const struct btf_type *mptcp_sock_type, *mptcp_subflow_type __read_mostly;
 | ||||
| +static u32 mptcp_sock_id, mptcp_subflow_id;
 | ||||
| +
 | ||||
| +static const struct bpf_func_proto *
 | ||||
| +bpf_mptcp_sched_get_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
 | ||||
| +{
 | ||||
| +	switch (func_id) {
 | ||||
| +	case BPF_FUNC_sk_storage_get:
 | ||||
| +		return &bpf_sk_storage_get_proto;
 | ||||
| +	case BPF_FUNC_sk_storage_delete:
 | ||||
| +		return &bpf_sk_storage_delete_proto;
 | ||||
| +	case BPF_FUNC_skc_to_tcp6_sock:
 | ||||
| +		return &bpf_skc_to_tcp6_sock_proto;
 | ||||
| +	case BPF_FUNC_skc_to_tcp_sock:
 | ||||
| +		return &bpf_skc_to_tcp_sock_proto;
 | ||||
| +	default:
 | ||||
| +		return bpf_base_func_proto(func_id);
 | ||||
| +	}
 | ||||
| +}
 | ||||
| +
 | ||||
| +static int bpf_mptcp_sched_btf_struct_access(struct bpf_verifier_log *log,
 | ||||
| +					     const struct bpf_reg_state *reg,
 | ||||
| +					     int off, int size)
 | ||||
| +{
 | ||||
| +	const struct btf_type *t;
 | ||||
| +	size_t end;
 | ||||
| +
 | ||||
| +	t = btf_type_by_id(reg->btf, reg->btf_id);
 | ||||
| +	if (t != mptcp_sock_type && t != mptcp_subflow_type) {
 | ||||
| +		bpf_log(log, "only access to mptcp sock or subflow is supported\n");
 | ||||
| +		return -EACCES;
 | ||||
| +	}
 | ||||
| +
 | ||||
| +	switch (off) {
 | ||||
| +	case offsetof(struct mptcp_sock, snd_burst):
 | ||||
| +		end = offsetofend(struct mptcp_sock, snd_burst);
 | ||||
| +		break;
 | ||||
| +	case offsetof(struct mptcp_subflow_context, scheduled):
 | ||||
| +		end = offsetofend(struct mptcp_subflow_context, scheduled);
 | ||||
| +		break;
 | ||||
| +	case offsetof(struct mptcp_subflow_context, avg_pacing_rate):
 | ||||
| +		end = offsetofend(struct mptcp_subflow_context, avg_pacing_rate);
 | ||||
| +		break;
 | ||||
| +	default:
 | ||||
| +		bpf_log(log, "no write support to %s at off %d\n",
 | ||||
| +			t == mptcp_sock_type ? "mptcp_sock" : "mptcp_subflow_context", off);
 | ||||
| +		return -EACCES;
 | ||||
| +	}
 | ||||
| +
 | ||||
| +	if (off + size > end) {
 | ||||
| +		bpf_log(log, "access beyond %s at off %u size %u ended at %zu",
 | ||||
| +			t == mptcp_sock_type ? "mptcp_sock" : "mptcp_subflow_context",
 | ||||
| +			off, size, end);
 | ||||
| +		return -EACCES;
 | ||||
| +	}
 | ||||
| +
 | ||||
| +	return NOT_INIT;
 | ||||
| +}
 | ||||
| +
 | ||||
| +static const struct bpf_verifier_ops bpf_mptcp_sched_verifier_ops = {
 | ||||
| +	.get_func_proto		= bpf_mptcp_sched_get_func_proto,
 | ||||
| +	.is_valid_access	= bpf_tracing_btf_ctx_access,
 | ||||
| +	.btf_struct_access	= bpf_mptcp_sched_btf_struct_access,
 | ||||
| +};
 | ||||
| +
 | ||||
| +static int bpf_mptcp_sched_reg(void *kdata)
 | ||||
| +{
 | ||||
| +	return mptcp_register_scheduler(kdata);
 | ||||
| +}
 | ||||
| +
 | ||||
| +static void bpf_mptcp_sched_unreg(void *kdata)
 | ||||
| +{
 | ||||
| +	mptcp_unregister_scheduler(kdata);
 | ||||
| +}
 | ||||
| +
 | ||||
| +static int bpf_mptcp_sched_check_member(const struct btf_type *t,
 | ||||
| +					const struct btf_member *member,
 | ||||
| +					const struct bpf_prog *prog)
 | ||||
| +{
 | ||||
| +	return 0;
 | ||||
| +}
 | ||||
| +
 | ||||
| +static int bpf_mptcp_sched_init_member(const struct btf_type *t,
 | ||||
| +				       const struct btf_member *member,
 | ||||
| +				       void *kdata, const void *udata)
 | ||||
| +{
 | ||||
| +	const struct mptcp_sched_ops *usched;
 | ||||
| +	struct mptcp_sched_ops *sched;
 | ||||
| +	u32 moff;
 | ||||
| +
 | ||||
| +	usched = (const struct mptcp_sched_ops *)udata;
 | ||||
| +	sched = (struct mptcp_sched_ops *)kdata;
 | ||||
| +
 | ||||
| +	moff = __btf_member_bit_offset(t, member) / 8;
 | ||||
| +	switch (moff) {
 | ||||
| +	case offsetof(struct mptcp_sched_ops, name):
 | ||||
| +		if (bpf_obj_name_cpy(sched->name, usched->name,
 | ||||
| +				     sizeof(sched->name)) <= 0)
 | ||||
| +			return -EINVAL;
 | ||||
| +		if (mptcp_sched_find(usched->name))
 | ||||
| +			return -EEXIST;
 | ||||
| +		return 1;
 | ||||
| +	}
 | ||||
| +
 | ||||
| +	return 0;
 | ||||
| +}
 | ||||
| +
 | ||||
| +static int bpf_mptcp_sched_init(struct btf *btf)
 | ||||
| +{
 | ||||
| +	s32 type_id;
 | ||||
| +
 | ||||
| +	type_id = btf_find_by_name_kind(btf, "mptcp_sock",
 | ||||
| +					BTF_KIND_STRUCT);
 | ||||
| +	if (type_id < 0)
 | ||||
| +		return -EINVAL;
 | ||||
| +	mptcp_sock_id = type_id;
 | ||||
| +	mptcp_sock_type = btf_type_by_id(btf, mptcp_sock_id);
 | ||||
| +
 | ||||
| +	type_id = btf_find_by_name_kind(btf, "mptcp_subflow_context",
 | ||||
| +					BTF_KIND_STRUCT);
 | ||||
| +	if (type_id < 0)
 | ||||
| +		return -EINVAL;
 | ||||
| +	mptcp_subflow_id = type_id;
 | ||||
| +	mptcp_subflow_type = btf_type_by_id(btf, mptcp_subflow_id);
 | ||||
| +
 | ||||
| +	return 0;
 | ||||
| +}
 | ||||
| +
 | ||||
| +struct bpf_struct_ops bpf_mptcp_sched_ops = {
 | ||||
| +	.verifier_ops	= &bpf_mptcp_sched_verifier_ops,
 | ||||
| +	.reg		= bpf_mptcp_sched_reg,
 | ||||
| +	.unreg		= bpf_mptcp_sched_unreg,
 | ||||
| +	.check_member	= bpf_mptcp_sched_check_member,
 | ||||
| +	.init_member	= bpf_mptcp_sched_init_member,
 | ||||
| +	.init		= bpf_mptcp_sched_init,
 | ||||
| +	.name		= "mptcp_sched_ops",
 | ||||
| +};
 | ||||
| +#endif /* CONFIG_BPF_JIT */
 | ||||
| +
 | ||||
|  struct mptcp_sock *bpf_mptcp_sock_from_subflow(struct sock *sk) | ||||
|  { | ||||
|  	if (sk && sk_fullsock(sk) && sk->sk_protocol == IPPROTO_TCP && sk_is_mptcp(sk)) | ||||
| From c128adc086aa390e8dba43bcad604fe223e50bf4 Mon Sep 17 00:00:00 2001 | ||||
| From: Geliang Tang <geliang.tang@suse.com> | ||||
| Date: Tue, 19 Dec 2023 13:28:01 +0100 | ||||
| Subject: [PATCH] bpf: Add bpf_mptcp_sched_kfunc_set | ||||
| 
 | ||||
| This patch adds a new struct btf_kfunc_id_set for MPTCP scheduler. Add | ||||
| mptcp_subflow_set_scheduled() and mptcp_sched_data_set_contexts() helpers | ||||
| into this id_set, and register it in bpf_mptcp_kfunc_init() to make sure | ||||
| these helpers can be accessed from the BPF context. | ||||
| 
 | ||||
| Reviewed-by: Mat Martineau <martineau@kernel.org> | ||||
| Signed-off-by: Geliang Tang <geliang.tang@suse.com> | ||||
| ---
 | ||||
|  net/mptcp/bpf.c | 16 +++++++++++++++- | ||||
|  1 file changed, 15 insertions(+), 1 deletion(-) | ||||
| 
 | ||||
| diff --git a/net/mptcp/bpf.c b/net/mptcp/bpf.c
 | ||||
| index dfcaaf0e07dd..aec9515888f7 100644
 | ||||
| --- a/net/mptcp/bpf.c
 | ||||
| +++ b/net/mptcp/bpf.c
 | ||||
| @@ -189,8 +189,22 @@ bpf_mptcp_subflow_ctx_by_pos(const struct mptcp_sched_data *data, unsigned int p
 | ||||
|   | ||||
|  __diag_pop(); | ||||
|   | ||||
| +BTF_SET8_START(bpf_mptcp_sched_kfunc_ids)
 | ||||
| +BTF_ID_FLAGS(func, mptcp_subflow_set_scheduled)
 | ||||
| +BTF_ID_FLAGS(func, bpf_mptcp_subflow_ctx_by_pos)
 | ||||
| +BTF_SET8_END(bpf_mptcp_sched_kfunc_ids)
 | ||||
| +
 | ||||
| +static const struct btf_kfunc_id_set bpf_mptcp_sched_kfunc_set = {
 | ||||
| +	.owner	= THIS_MODULE,
 | ||||
| +	.set	= &bpf_mptcp_sched_kfunc_ids,
 | ||||
| +};
 | ||||
| +
 | ||||
|  static int __init bpf_mptcp_kfunc_init(void) | ||||
|  { | ||||
| -	return register_btf_fmodret_id_set(&bpf_mptcp_fmodret_set);
 | ||||
| +	int ret;
 | ||||
| +
 | ||||
| +	ret = register_btf_fmodret_id_set(&bpf_mptcp_fmodret_set);
 | ||||
| +	return ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_STRUCT_OPS,
 | ||||
| +						&bpf_mptcp_sched_kfunc_set);
 | ||||
|  } | ||||
|  late_initcall(bpf_mptcp_kfunc_init); | ||||
| From f322294a8f32ddf7e40021d94c19665c302dbd79 Mon Sep 17 00:00:00 2001 | ||||
| From: Geliang Tang <geliang.tang@suse.com> | ||||
| Date: Tue, 19 Dec 2023 13:28:12 +0100 | ||||
| Subject: [PATCH] bpf: Export more bpf_burst related functions | ||||
| 
 | ||||
| sk_stream_memory_free() and tcp_rtx_and_write_queues_empty() are needed | ||||
| to export into the BPF context for bpf_burst scheduler. But these two | ||||
| functions are inline ones. So this patch added two wrappers for them, | ||||
| and export the wrappers in the BPF context. | ||||
| 
 | ||||
| Add more bpf_burst related functions into bpf_mptcp_sched_kfunc_set to make | ||||
| sure these helpers can be accessed from the BPF context. | ||||
| 
 | ||||
| Signed-off-by: Geliang Tang <geliang.tang@suse.com> | ||||
| Reviewed-by: Mat Martineau <martineau@kernel.org> | ||||
| ---
 | ||||
|  net/mptcp/bpf.c      | 11 +++++++++++ | ||||
|  net/mptcp/protocol.c |  4 ++-- | ||||
|  net/mptcp/protocol.h |  3 +++ | ||||
|  3 files changed, 16 insertions(+), 2 deletions(-) | ||||
| 
 | ||||
| diff --git a/net/mptcp/bpf.c b/net/mptcp/bpf.c
 | ||||
| index aec9515888f7..007c2034db65 100644
 | ||||
| --- a/net/mptcp/bpf.c
 | ||||
| +++ b/net/mptcp/bpf.c
 | ||||
| @@ -187,11 +187,22 @@ bpf_mptcp_subflow_ctx_by_pos(const struct mptcp_sched_data *data, unsigned int p
 | ||||
|  	return data->contexts[pos]; | ||||
|  } | ||||
|   | ||||
| +__bpf_kfunc bool bpf_mptcp_subflow_queues_empty(struct sock *sk)
 | ||||
| +{
 | ||||
| +	return tcp_rtx_queue_empty(sk);
 | ||||
| +}
 | ||||
| +
 | ||||
|  __diag_pop(); | ||||
|   | ||||
|  BTF_SET8_START(bpf_mptcp_sched_kfunc_ids) | ||||
|  BTF_ID_FLAGS(func, mptcp_subflow_set_scheduled) | ||||
|  BTF_ID_FLAGS(func, bpf_mptcp_subflow_ctx_by_pos) | ||||
| +BTF_ID_FLAGS(func, mptcp_subflow_active)
 | ||||
| +BTF_ID_FLAGS(func, mptcp_set_timeout)
 | ||||
| +BTF_ID_FLAGS(func, mptcp_wnd_end)
 | ||||
| +BTF_ID_FLAGS(func, tcp_stream_memory_free)
 | ||||
| +BTF_ID_FLAGS(func, bpf_mptcp_subflow_queues_empty)
 | ||||
| +BTF_ID_FLAGS(func, mptcp_pm_subflow_chk_stale)
 | ||||
|  BTF_SET8_END(bpf_mptcp_sched_kfunc_ids) | ||||
|   | ||||
|  static const struct btf_kfunc_id_set bpf_mptcp_sched_kfunc_set = { | ||||
| diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c
 | ||||
| index 8bfd266f2754..c12bf17691d7 100644
 | ||||
| --- a/net/mptcp/protocol.c
 | ||||
| +++ b/net/mptcp/protocol.c
 | ||||
| @@ -50,7 +50,7 @@ DEFINE_PER_CPU(struct mptcp_delegated_action, mptcp_delegated_actions);
 | ||||
|  static struct net_device mptcp_napi_dev; | ||||
|   | ||||
|  /* Returns end sequence number of the receiver's advertised window */ | ||||
| -static u64 mptcp_wnd_end(const struct mptcp_sock *msk)
 | ||||
| +u64 mptcp_wnd_end(const struct mptcp_sock *msk)
 | ||||
|  { | ||||
|  	return READ_ONCE(msk->wnd_end); | ||||
|  } | ||||
| @@ -485,7 +485,7 @@ static long mptcp_timeout_from_subflow(const struct mptcp_subflow_context *subfl
 | ||||
|  	       inet_csk(ssk)->icsk_timeout - jiffies : 0; | ||||
|  } | ||||
|   | ||||
| -static void mptcp_set_timeout(struct sock *sk)
 | ||||
| +void mptcp_set_timeout(struct sock *sk)
 | ||||
|  { | ||||
|  	struct mptcp_subflow_context *subflow; | ||||
|  	long tout = 0; | ||||
| diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h
 | ||||
| index 7cf5d2de7441..f7b9c1b995df 100644
 | ||||
| --- a/net/mptcp/protocol.h
 | ||||
| +++ b/net/mptcp/protocol.h
 | ||||
| @@ -636,6 +636,9 @@ void __mptcp_subflow_send_ack(struct sock *ssk);
 | ||||
|  void mptcp_subflow_reset(struct sock *ssk); | ||||
|  void mptcp_subflow_queue_clean(struct sock *sk, struct sock *ssk); | ||||
|  void mptcp_sock_graft(struct sock *sk, struct socket *parent); | ||||
| +u64 mptcp_wnd_end(const struct mptcp_sock *msk);
 | ||||
| +void mptcp_set_timeout(struct sock *sk);
 | ||||
| +bool bpf_mptcp_subflow_queues_empty(struct sock *sk);
 | ||||
|  struct mptcp_subflow_context * | ||||
|  bpf_mptcp_subflow_ctx_by_pos(const struct mptcp_sched_data *data, unsigned int pos); | ||||
|  struct sock *__mptcp_nmpc_sk(struct mptcp_sock *msk); | ||||
|  | @ -0,0 +1,29 @@ | |||
| From: Felix Fietkau <nbd@nbd.name> | ||||
| Date: Thu, 22 Oct 2020 22:00:03 +0200 | ||||
| Subject: [PATCH] compiler.h: only include asm/rwonce.h for kernel code | ||||
| 
 | ||||
| This header file is not in uapi, which makes any user space code that includes | ||||
| linux/compiler.h to fail with the error 'asm/rwonce.h: No such file or directory' | ||||
| 
 | ||||
| Fixes: e506ea451254 ("compiler.h: Split {READ,WRITE}_ONCE definitions out into rwonce.h") | ||||
| 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_
 | ||||
|  	__v;								\ | ||||
|  }) | ||||
|   | ||||
| +#include <asm/rwonce.h>
 | ||||
| +
 | ||||
|  #endif /* __KERNEL__ */ | ||||
|   | ||||
|  /* | ||||
| @@ -243,6 +245,4 @@ static inline void *offset_to_ptr(const
 | ||||
|   */ | ||||
|  #define prevent_tail_call_optimization()	mb() | ||||
|   | ||||
| -#include <asm/rwonce.h>
 | ||||
| -
 | ||||
|  #endif /* __LINUX_COMPILER_H */ | ||||
|  | @ -0,0 +1,57 @@ | |||
| From: Felix Fietkau <nbd@nbd.name> | ||||
| Date: Wed, 18 Apr 2018 10:50:05 +0200 | ||||
| Subject: [PATCH] MIPS: only process negative stack offsets on stack traces | ||||
| 
 | ||||
| Fixes endless back traces in cases where the compiler emits a stack | ||||
| pointer increase in a branch delay slot (probably for some form of | ||||
| function return). | ||||
| 
 | ||||
| [    3.475442] BUG: MAX_STACK_TRACE_ENTRIES too low! | ||||
| [    3.480070] turning off the locking correctness validator. | ||||
| [    3.485521] CPU: 0 PID: 1 Comm: swapper/0 Not tainted 4.14.34 #0 | ||||
| [    3.491475] Stack : 00000000 00000000 00000000 00000000 80e0fce2 00000034 00000000 00000000 | ||||
| [    3.499764]         87c3838c 80696377 8061047c 00000000 00000001 00000001 87c2d850 6534689f | ||||
| [    3.508059]         00000000 00000000 80e10000 00000000 00000000 000000cf 0000000f 00000000 | ||||
| [    3.516353]         00000000 806a0000 00076891 00000000 00000000 00000000 ffffffff 00000000 | ||||
| [    3.524648]         806c0000 00000004 80e10000 806a0000 00000003 80690000 00000000 80700000 | ||||
| [    3.532942]         ... | ||||
| [    3.535362] Call Trace: | ||||
| [    3.537818] [<80010a48>] show_stack+0x58/0x100 | ||||
| [    3.542207] [<804c2f78>] dump_stack+0xe8/0x170 | ||||
| [    3.546613] [<80079f90>] save_trace+0xf0/0x110 | ||||
| [    3.551010] [<8007b1ec>] mark_lock+0x33c/0x78c | ||||
| [    3.555413] [<8007bf48>] __lock_acquire+0x2ac/0x1a08 | ||||
| [    3.560337] [<8007de60>] lock_acquire+0x64/0x8c | ||||
| [    3.564846] [<804e1570>] _raw_spin_lock_irqsave+0x54/0x78 | ||||
| [    3.570186] [<801b618c>] kernfs_notify+0x94/0xac | ||||
| [    3.574770] [<801b7b10>] sysfs_notify+0x74/0xa0 | ||||
| [    3.579257] [<801b618c>] kernfs_notify+0x94/0xac | ||||
| [    3.583839] [<801b7b10>] sysfs_notify+0x74/0xa0 | ||||
| [    3.588329] [<801b618c>] kernfs_notify+0x94/0xac | ||||
| [    3.592911] [<801b7b10>] sysfs_notify+0x74/0xa0 | ||||
| [    3.597401] [<801b618c>] kernfs_notify+0x94/0xac | ||||
| [    3.601983] [<801b7b10>] sysfs_notify+0x74/0xa0 | ||||
| [    3.606473] [<801b618c>] kernfs_notify+0x94/0xac | ||||
| [    3.611055] [<801b7b10>] sysfs_notify+0x74/0xa0 | ||||
| [    3.615545] [<801b618c>] kernfs_notify+0x94/0xac | ||||
| [    3.620125] [<801b7b10>] sysfs_notify+0x74/0xa0 | ||||
| [    3.624619] [<801b618c>] kernfs_notify+0x94/0xac | ||||
| [    3.629197] [<801b7b10>] sysfs_notify+0x74/0xa0 | ||||
| [    3.633691] [<801b618c>] kernfs_notify+0x94/0xac | ||||
| [    3.638269] [<801b7b10>] sysfs_notify+0x74/0xa0 | ||||
| [    3.642763] [<801b618c>] kernfs_notify+0x94/0xac | ||||
| 
 | ||||
| Signed-off-by: Felix Fietkau <nbd@nbd.name> | ||||
| ---
 | ||||
| 
 | ||||
| --- a/arch/mips/kernel/process.c
 | ||||
| +++ b/arch/mips/kernel/process.c
 | ||||
| @@ -395,6 +395,8 @@ static inline int is_sp_move_ins(union m
 | ||||
|   | ||||
|  	if (ip->i_format.opcode == addiu_op || | ||||
|  	    ip->i_format.opcode == daddiu_op) { | ||||
| +		if (ip->i_format.simmediate > 0)
 | ||||
| +			return 0;
 | ||||
|  		*frame_size = -ip->i_format.simmediate; | ||||
|  		return 1; | ||||
|  	} | ||||
|  | @ -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
 | ||||
| @@ -599,7 +599,7 @@ endif
 | ||||
|  # Allows the usage of unstable features in stable compilers. | ||||
|  export RUSTC_BOOTSTRAP := 1 | ||||
|   | ||||
| -export ARCH SRCARCH CONFIG_SHELL BASH HOSTCC KBUILD_HOSTCFLAGS CROSS_COMPILE LD CC HOSTPKG_CONFIG
 | ||||
| +export ARCH SRCARCH SUBARCH CONFIG_SHELL BASH HOSTCC KBUILD_HOSTCFLAGS CROSS_COMPILE LD CC HOSTPKG_CONFIG
 | ||||
|  export RUSTC RUSTDOC RUSTFMT RUSTC_OR_CLIPPY_QUIET RUSTC_OR_CLIPPY BINDGEN CARGO | ||||
|  export HOSTRUSTC KBUILD_HOSTRUSTFLAGS | ||||
|  export CPP AR NM STRIP OBJCOPY OBJDUMP READELF PAHOLE RESOLVE_BTFIDS LEX YACC AWK INSTALLKERNEL | ||||
|  | @ -0,0 +1,75 @@ | |||
| From bd1b9f66d5134e518419f4c4dacf1884c1616983 Mon Sep 17 00:00:00 2001 | ||||
| From: =?UTF-8?q?Pali=20Roh=C3=A1r?= <pali@kernel.org> | ||||
| Date: Thu, 28 Apr 2022 11:13:23 +0200 | ||||
| Subject: [PATCH] watchdog: max63xx_wdt: Add support for specifying WDI logic | ||||
|  via GPIO | ||||
| MIME-Version: 1.0 | ||||
| Content-Type: text/plain; charset=UTF-8 | ||||
| Content-Transfer-Encoding: 8bit | ||||
| 
 | ||||
| On some boards is WDI logic of max6370 chip connected via GPIO. | ||||
| So extend max63xx_wdt driver to allow specifying WDI logic via GPIO. | ||||
| 
 | ||||
| Signed-off-by: Pali Rohár <pali@kernel.org> | ||||
| ---
 | ||||
|  drivers/watchdog/max63xx_wdt.c | 24 ++++++++++++++++++++++++ | ||||
|  1 file changed, 24 insertions(+) | ||||
| 
 | ||||
| --- a/drivers/watchdog/max63xx_wdt.c
 | ||||
| +++ b/drivers/watchdog/max63xx_wdt.c
 | ||||
| @@ -24,6 +24,7 @@
 | ||||
|  #include <linux/io.h> | ||||
|  #include <linux/slab.h> | ||||
|  #include <linux/property.h> | ||||
| +#include <linux/gpio/consumer.h>
 | ||||
|   | ||||
|  #define DEFAULT_HEARTBEAT 60 | ||||
|  #define MAX_HEARTBEAT     60 | ||||
| @@ -50,6 +51,9 @@ struct max63xx_wdt {
 | ||||
|  	void __iomem *base; | ||||
|  	spinlock_t lock; | ||||
|   | ||||
| +	/* GPIOs */
 | ||||
| +	struct gpio_desc *gpio_wdi;
 | ||||
| +
 | ||||
|  	/* WDI and WSET bits write access routines */ | ||||
|  	void (*ping)(struct max63xx_wdt *wdt); | ||||
|  	void (*set)(struct max63xx_wdt *wdt, u8 set); | ||||
| @@ -155,6 +159,17 @@ static const struct watchdog_info max63x
 | ||||
|  	.identity = "max63xx Watchdog", | ||||
|  }; | ||||
|   | ||||
| +static void max63xx_gpio_ping(struct max63xx_wdt *wdt)
 | ||||
| +{
 | ||||
| +	spin_lock(&wdt->lock);
 | ||||
| +
 | ||||
| +	gpiod_set_value(wdt->gpio_wdi, 1);
 | ||||
| +	udelay(1);
 | ||||
| +	gpiod_set_value(wdt->gpio_wdi, 0);
 | ||||
| +
 | ||||
| +	spin_unlock(&wdt->lock);
 | ||||
| +}
 | ||||
| +
 | ||||
|  static void max63xx_mmap_ping(struct max63xx_wdt *wdt) | ||||
|  { | ||||
|  	u8 val; | ||||
| @@ -222,10 +237,19 @@ static int max63xx_wdt_probe(struct plat
 | ||||
|  		return -EINVAL; | ||||
|  	} | ||||
|   | ||||
| +	wdt->gpio_wdi = devm_gpiod_get(dev, NULL, GPIOD_FLAGS_BIT_DIR_OUT);
 | ||||
| +	if (IS_ERR(wdt->gpio_wdi) && PTR_ERR(wdt->gpio_wdi) != -ENOENT)
 | ||||
| +		return dev_err_probe(dev, PTR_ERR(wdt->gpio_wdi),
 | ||||
| +				     "unable to request gpio: %ld\n",
 | ||||
| +				     PTR_ERR(wdt->gpio_wdi));
 | ||||
| +
 | ||||
|  	err = max63xx_mmap_init(pdev, wdt); | ||||
|  	if (err) | ||||
|  		return err; | ||||
|   | ||||
| +	if (!IS_ERR(wdt->gpio_wdi))
 | ||||
| +		wdt->ping = max63xx_gpio_ping;
 | ||||
| +
 | ||||
|  	platform_set_drvdata(pdev, &wdt->wdd); | ||||
|  	watchdog_set_drvdata(&wdt->wdd, wdt); | ||||
|   | ||||
|  | @ -0,0 +1,82 @@ | |||
| From: Tobias Wolf <dev-NTEO@vplace.de> | ||||
| Subject: mm: Fix alloc_node_mem_map with ARCH_PFN_OFFSET calculation | ||||
| 
 | ||||
| An rt288x (ralink) based router (Belkin F5D8235 v1) does not boot with any | ||||
| kernel beyond version 4.3 resulting in: | ||||
| 
 | ||||
| BUG: Bad page state in process swapper  pfn:086ac | ||||
| 
 | ||||
| bisect resulted in: | ||||
| 
 | ||||
| a1c34a3bf00af2cede839879502e12dc68491ad5 is the first bad commit | ||||
| commit a1c34a3bf00af2cede839879502e12dc68491ad5 | ||||
| Author: Laura Abbott <laura@labbott.name> | ||||
| Date:   Thu Nov 5 18:48:46 2015 -0800 | ||||
| 
 | ||||
|     mm: Don't offset memmap for flatmem | ||||
| 
 | ||||
|     Srinivas Kandagatla reported bad page messages when trying to remove the | ||||
|     bottom 2MB on an ARM based IFC6410 board | ||||
| 
 | ||||
|       BUG: Bad page state in process swapper  pfn:fffa8 | ||||
|       page:ef7fb500 count:0 mapcount:0 mapping:  (null) index:0x0 | ||||
|       flags: 0x96640253(locked|error|dirty|active|arch_1|reclaim|mlocked) | ||||
|       page dumped because: PAGE_FLAGS_CHECK_AT_FREE flag(s) set | ||||
|       bad because of flags: | ||||
|       flags: 0x200041(locked|active|mlocked) | ||||
|       Modules linked in: | ||||
|       CPU: 0 PID: 0 Comm: swapper Not tainted 3.19.0-rc3-00007-g412f9ba-dirty | ||||
| #816 | ||||
|       Hardware name: Qualcomm (Flattened Device Tree) | ||||
|         unwind_backtrace | ||||
|         show_stack | ||||
|         dump_stack | ||||
|         bad_page | ||||
|         free_pages_prepare | ||||
|         free_hot_cold_page | ||||
|         __free_pages | ||||
|         free_highmem_page | ||||
|         mem_init | ||||
|         start_kernel | ||||
|       Disabling lock debugging due to kernel taint | ||||
|     [...] | ||||
| :040000 040000 2de013c372345fd471cd58f0553c9b38b0ef1cc4 | ||||
| 0a8156f848733dfa21e16c196dfb6c0a76290709 M      mm | ||||
| 
 | ||||
| This fix for ARM does not account ARCH_PFN_OFFSET for mem_map as later used by | ||||
| page_to_pfn anymore. | ||||
| 
 | ||||
| The following output was generated with two hacked in printk statements: | ||||
| 
 | ||||
| printk("before %p vs. %p or %p\n", mem_map, mem_map - offset, mem_map - | ||||
| (pgdat->node_start_pfn - ARCH_PFN_OFFSET)); | ||||
| 		if (page_to_pfn(mem_map) != pgdat->node_start_pfn) | ||||
| 			mem_map -= offset + (pgdat->node_start_pfn - ARCH_PFN_OFFSET); | ||||
| printk("after %p\n", mem_map); | ||||
| 
 | ||||
| Output: | ||||
| 
 | ||||
| [    0.000000] before 8861b280 vs. 8861b280 or 8851b280 | ||||
| [    0.000000] after 8851b280 | ||||
| 
 | ||||
| As seen in the first line mem_map with subtraction of offset does not equal the | ||||
| mem_map after subtraction of ARCH_PFN_OFFSET. | ||||
| 
 | ||||
| After adding the offset of ARCH_PFN_OFFSET as well to mem_map as the | ||||
| previously calculated offset is zero for the named platform it is able to boot | ||||
| 4.4 and 4.9-rc7 again. | ||||
| 
 | ||||
| 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
 | ||||
|  	if (pgdat == NODE_DATA(0)) { | ||||
|  		mem_map = NODE_DATA(0)->node_mem_map; | ||||
|  		if (page_to_pfn(mem_map) != pgdat->node_start_pfn) | ||||
| -			mem_map -= offset;
 | ||||
| +			mem_map -= offset + (pgdat->node_start_pfn - ARCH_PFN_OFFSET);
 | ||||
|  	} | ||||
|  #endif | ||||
|  } | ||||
|  | @ -0,0 +1,81 @@ | |||
| From: Felix Fietkau <nbd@nbd.name> | ||||
| Subject: jffs2: use .rename2 and add RENAME_WHITEOUT support | ||||
| 
 | ||||
| It is required for renames on overlayfs | ||||
| 
 | ||||
| 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
 | ||||
|  	return ret; | ||||
|  } | ||||
|   | ||||
| -static int jffs2_mknod (struct mnt_idmap *idmap, struct inode *dir_i,
 | ||||
| -		        struct dentry *dentry, umode_t mode, dev_t rdev)
 | ||||
| +static int __jffs2_mknod (struct mnt_idmap *idmap, struct inode *dir_i,
 | ||||
| +		          struct dentry *dentry, umode_t mode, dev_t rdev, bool whiteout)
 | ||||
|  { | ||||
|  	struct jffs2_inode_info *f, *dir_f; | ||||
|  	struct jffs2_sb_info *c; | ||||
| @@ -758,7 +758,11 @@ static int jffs2_mknod (struct mnt_idmap
 | ||||
|  	mutex_unlock(&dir_f->sem); | ||||
|  	jffs2_complete_reservation(c); | ||||
|   | ||||
| -	d_instantiate_new(dentry, inode);
 | ||||
| +	if (!whiteout)
 | ||||
| +		d_instantiate_new(dentry, inode);
 | ||||
| +	else
 | ||||
| +		unlock_new_inode(inode);
 | ||||
| +
 | ||||
|  	return 0; | ||||
|   | ||||
|   fail: | ||||
| @@ -766,6 +770,19 @@ static int jffs2_mknod (struct mnt_idmap
 | ||||
|  	return ret; | ||||
|  } | ||||
|   | ||||
| +static int jffs2_mknod (struct mnt_idmap *idmap, struct inode *dir_i,
 | ||||
| +			struct dentry *dentry, umode_t mode, dev_t rdev)
 | ||||
| +{
 | ||||
| +	return __jffs2_mknod(idmap, dir_i, dentry, mode, rdev, false);
 | ||||
| +}
 | ||||
| +
 | ||||
| +static int jffs2_whiteout (struct mnt_idmap *idmap, struct inode *old_dir,
 | ||||
| +			   struct dentry *old_dentry)
 | ||||
| +{
 | ||||
| +	return __jffs2_mknod(idmap, old_dir, old_dentry, S_IFCHR | WHITEOUT_MODE,
 | ||||
| +			     WHITEOUT_DEV, true);
 | ||||
| +}
 | ||||
| +
 | ||||
|  static int jffs2_rename (struct mnt_idmap *idmap, | ||||
|  			 struct inode *old_dir_i, struct dentry *old_dentry, | ||||
|  			 struct inode *new_dir_i, struct dentry *new_dentry, | ||||
| @@ -777,7 +794,7 @@ static int jffs2_rename (struct mnt_idma
 | ||||
|  	uint8_t type; | ||||
|  	uint32_t now; | ||||
|   | ||||
| -	if (flags & ~RENAME_NOREPLACE)
 | ||||
| +	if (flags & ~(RENAME_NOREPLACE|RENAME_WHITEOUT))
 | ||||
|  		return -EINVAL; | ||||
|   | ||||
|  	/* The VFS will check for us and prevent trying to rename a | ||||
| @@ -843,9 +860,14 @@ static int jffs2_rename (struct mnt_idma
 | ||||
|  	if (d_is_dir(old_dentry) && !victim_f) | ||||
|  		inc_nlink(new_dir_i); | ||||
|   | ||||
| -	/* Unlink the original */
 | ||||
| -	ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i),
 | ||||
| -			      old_dentry->d_name.name, old_dentry->d_name.len, NULL, now);
 | ||||
| +	if (flags & RENAME_WHITEOUT)
 | ||||
| +		/* Replace with whiteout */
 | ||||
| +		ret = jffs2_whiteout(idmap, old_dir_i, old_dentry);
 | ||||
| +	else
 | ||||
| +		/* Unlink the original */
 | ||||
| +		ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i),
 | ||||
| +				      old_dentry->d_name.name,
 | ||||
| +				      old_dentry->d_name.len, NULL, now);
 | ||||
|   | ||||
|  	/* We don't touch inode->i_nlink */ | ||||
|   | ||||
|  | @ -0,0 +1,73 @@ | |||
| From: Felix Fietkau <nbd@nbd.name> | ||||
| Subject: jffs2: add RENAME_EXCHANGE support | ||||
| 
 | ||||
| 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
 | ||||
|  	int ret; | ||||
|  	struct jffs2_sb_info *c = JFFS2_SB_INFO(old_dir_i->i_sb); | ||||
|  	struct jffs2_inode_info *victim_f = NULL; | ||||
| +	struct inode *fst_inode = d_inode(old_dentry);
 | ||||
| +	struct inode *snd_inode = d_inode(new_dentry);
 | ||||
|  	uint8_t type; | ||||
|  	uint32_t now; | ||||
|   | ||||
| -	if (flags & ~(RENAME_NOREPLACE|RENAME_WHITEOUT))
 | ||||
| +	if (flags & ~(RENAME_NOREPLACE|RENAME_WHITEOUT|RENAME_EXCHANGE))
 | ||||
|  		return -EINVAL; | ||||
|   | ||||
| +	if ((flags & RENAME_EXCHANGE) && (old_dir_i != new_dir_i)) {
 | ||||
| +		if (S_ISDIR(fst_inode->i_mode) && !S_ISDIR(snd_inode->i_mode)) {
 | ||||
| +			inc_nlink(new_dir_i);
 | ||||
| +			drop_nlink(old_dir_i);
 | ||||
| +		}
 | ||||
| +		else if (!S_ISDIR(fst_inode->i_mode) && S_ISDIR(snd_inode->i_mode)) {
 | ||||
| +			drop_nlink(new_dir_i);
 | ||||
| +			inc_nlink(old_dir_i);
 | ||||
| +		}
 | ||||
| +	}
 | ||||
| +
 | ||||
|  	/* The VFS will check for us and prevent trying to rename a | ||||
|  	 * file over a directory and vice versa, but if it's a directory, | ||||
|  	 * the VFS can't check whether the victim is empty. The filesystem | ||||
|  	 * needs to do that for itself. | ||||
|  	 */ | ||||
| -	if (d_really_is_positive(new_dentry)) {
 | ||||
| +	if (d_really_is_positive(new_dentry) && !(flags & RENAME_EXCHANGE)) {
 | ||||
|  		victim_f = JFFS2_INODE_INFO(d_inode(new_dentry)); | ||||
|  		if (d_is_dir(new_dentry)) { | ||||
|  			struct jffs2_full_dirent *fd; | ||||
| @@ -837,7 +850,7 @@ static int jffs2_rename (struct mnt_idma
 | ||||
|  	if (ret) | ||||
|  		return ret; | ||||
|   | ||||
| -	if (victim_f) {
 | ||||
| +	if (victim_f && !(flags & RENAME_EXCHANGE)) {
 | ||||
|  		/* There was a victim. Kill it off nicely */ | ||||
|  		if (d_is_dir(new_dentry)) | ||||
|  			clear_nlink(d_inode(new_dentry)); | ||||
| @@ -863,6 +876,12 @@ static int jffs2_rename (struct mnt_idma
 | ||||
|  	if (flags & RENAME_WHITEOUT) | ||||
|  		/* Replace with whiteout */ | ||||
|  		ret = jffs2_whiteout(idmap, old_dir_i, old_dentry); | ||||
| +	else if (flags & RENAME_EXCHANGE)
 | ||||
| +		/* Replace the original */
 | ||||
| +		ret = jffs2_do_link(c, JFFS2_INODE_INFO(old_dir_i),
 | ||||
| +				    d_inode(new_dentry)->i_ino, type,
 | ||||
| +				    old_dentry->d_name.name, old_dentry->d_name.len,
 | ||||
| +				    now);
 | ||||
|  	else | ||||
|  		/* Unlink the original */ | ||||
|  		ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i), | ||||
| @@ -895,7 +914,7 @@ static int jffs2_rename (struct mnt_idma
 | ||||
|  		return ret; | ||||
|  	} | ||||
|   | ||||
| -	if (d_is_dir(old_dentry))
 | ||||
| +	if (d_is_dir(old_dentry) && !(flags & RENAME_EXCHANGE))
 | ||||
|  		drop_nlink(old_dir_i); | ||||
|   | ||||
|  	old_dir_i->i_mtime = inode_set_ctime_to_ts(old_dir_i, ITIME(now)); | ||||
|  | @ -0,0 +1,20 @@ | |||
| From: Felix Fietkau <nbd@nbd.name> | ||||
| Subject: jffs2: add splice ops | ||||
| 
 | ||||
| Add splice_read using generic_file_splice_read. | ||||
| Add splice_write using iter_file_splice_write | ||||
| 
 | ||||
| Signed-off-by: Felix Fietkau <nbd@nbd.name> | ||||
| ---
 | ||||
| 
 | ||||
| --- a/fs/jffs2/file.c
 | ||||
| +++ b/fs/jffs2/file.c
 | ||||
| @@ -53,6 +53,8 @@ const struct file_operations jffs2_file_
 | ||||
|  	.open =		generic_file_open, | ||||
|   	.read_iter =	generic_file_read_iter, | ||||
|   	.write_iter =	generic_file_write_iter, | ||||
| +	.splice_read =	filemap_splice_read,
 | ||||
| +	.splice_write =	iter_file_splice_write,
 | ||||
|  	.unlocked_ioctl=jffs2_ioctl, | ||||
|  	.mmap =		generic_file_readonly_mmap, | ||||
|  	.fsync =	jffs2_fsync, | ||||
|  | @ -0,0 +1,45 @@ | |||
| From: Stephen Hemminger <stephen@networkplumber.org> | ||||
| Subject: bridge: allow receiption on disabled port | ||||
| 
 | ||||
| When an ethernet device is enslaved to a bridge, and the bridge STP | ||||
| detects loss of carrier (or operational state down), then normally | ||||
| packet receiption is blocked. | ||||
| 
 | ||||
| This breaks control applications like WPA which maybe expecting to | ||||
| receive packets to negotiate to bring link up. The bridge needs to | ||||
| block forwarding packets from these disabled ports, but there is no | ||||
| hard requirement to not allow local packet delivery. | ||||
| 
 | ||||
| Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> | ||||
| Signed-off-by: Felix Fietkau <nbd@nbd.name> | ||||
| 
 | ||||
| --- a/net/bridge/br_input.c
 | ||||
| +++ b/net/bridge/br_input.c
 | ||||
| @@ -244,6 +244,9 @@ static void __br_handle_local_finish(str
 | ||||
|  /* note: already called with rcu_read_lock */ | ||||
|  static int br_handle_local_finish(struct net *net, struct sock *sk, struct sk_buff *skb) | ||||
|  { | ||||
| +	struct net_bridge_port *p = br_port_get_rcu(skb->dev);
 | ||||
| +
 | ||||
| +	if (p->state != BR_STATE_DISABLED)
 | ||||
|  	__br_handle_local_finish(skb); | ||||
|   | ||||
|  	/* return 1 to signal the okfn() was called so it's ok to use the skb */ | ||||
| @@ -415,6 +418,17 @@ forward:
 | ||||
|  		goto defer_stp_filtering; | ||||
|   | ||||
|  	switch (p->state) { | ||||
| +	case BR_STATE_DISABLED:
 | ||||
| +		if (ether_addr_equal(p->br->dev->dev_addr, dest))
 | ||||
| +			skb->pkt_type = PACKET_HOST;
 | ||||
| +
 | ||||
| +		if (NF_HOOK(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING,
 | ||||
| +			dev_net(skb->dev), NULL, skb, skb->dev, NULL,
 | ||||
| +			br_handle_local_finish) == 1) {
 | ||||
| +			return RX_HANDLER_PASS;
 | ||||
| +		}
 | ||||
| +		break;
 | ||||
| +
 | ||||
|  	case BR_STATE_FORWARDING: | ||||
|  	case BR_STATE_LEARNING: | ||||
|  defer_stp_filtering: | ||||
|  | @ -0,0 +1,37 @@ | |||
| From: Felix Fietkau <nbd@nbd.name> | ||||
| Date: Thu, 4 Jan 2024 15:21:21 +0100 | ||||
| Subject: [PATCH] net: bridge: do not send arp replies if src and target hw | ||||
|  addr is the same | ||||
| 
 | ||||
| There are broken devices in the wild that handle duplicate IP address | ||||
| detection by sending out ARP requests for the IP that they received from a | ||||
| DHCP server and refuse the address if they get a reply. | ||||
| When proxyarp is enabled, they would go into a loop of requesting an address | ||||
| and then NAKing it again. | ||||
| 
 | ||||
| Link: https://github.com/openwrt/openwrt/issues/14309 | ||||
| Signed-off-by: Felix Fietkau <nbd@nbd.name> | ||||
| ---
 | ||||
| 
 | ||||
| --- a/net/bridge/br_arp_nd_proxy.c
 | ||||
| +++ b/net/bridge/br_arp_nd_proxy.c
 | ||||
| @@ -204,7 +204,10 @@ void br_do_proxy_suppress_arp(struct sk_
 | ||||
|  			if ((p && (p->flags & BR_PROXYARP)) || | ||||
|  			    (f->dst && (f->dst->flags & BR_PROXYARP_WIFI)) || | ||||
|  			    br_is_neigh_suppress_enabled(f->dst, vid)) { | ||||
| -				if (!vid)
 | ||||
| +				replied = true;
 | ||||
| +				if (!memcmp(n->ha, sha, dev->addr_len))
 | ||||
| +					replied = false;
 | ||||
| +				else if (!vid)
 | ||||
|  					br_arp_send(br, p, skb->dev, sip, tip, | ||||
|  						    sha, n->ha, sha, 0, 0); | ||||
|  				else | ||||
| @@ -212,7 +215,6 @@ void br_do_proxy_suppress_arp(struct sk_
 | ||||
|  						    sha, n->ha, sha, | ||||
|  						    skb->vlan_proto, | ||||
|  						    skb_vlan_tag_get(skb)); | ||||
| -				replied = true;
 | ||||
|  			} | ||||
|   | ||||
|  			/* If we have replied or as long as we know the | ||||
|  | @ -0,0 +1,94 @@ | |||
| From: Daniel González Cabanelas <dgcbueu@gmail.com> | ||||
| Subject: [PATCH 1/2] rtc: rs5c372: support alarms up to 1 week | ||||
| 
 | ||||
| The Ricoh R2221x, R2223x, RS5C372, RV5C387A chips can handle 1 week | ||||
| alarms. | ||||
| 
 | ||||
| Read the "wday" alarm register and convert it to a date to support up 1 | ||||
| week in our driver. | ||||
| 
 | ||||
| Signed-off-by: Daniel González Cabanelas <dgcbueu@gmail.com> | ||||
| ---
 | ||||
|  drivers/rtc/rtc-rs5c372.c | 48 ++++++++++++++++++++++++++++++++++----- | ||||
|  1 file changed, 42 insertions(+), 6 deletions(-) | ||||
| 
 | ||||
| --- a/drivers/rtc/rtc-rs5c372.c
 | ||||
| +++ b/drivers/rtc/rtc-rs5c372.c
 | ||||
| @@ -399,7 +399,9 @@ static int rs5c_read_alarm(struct device
 | ||||
|  { | ||||
|  	struct i2c_client	*client = to_i2c_client(dev); | ||||
|  	struct rs5c372		*rs5c = i2c_get_clientdata(client); | ||||
| -	int			status;
 | ||||
| +	int			status, wday_offs;
 | ||||
| +	struct rtc_time 	rtc;
 | ||||
| +	unsigned long 		alarm_secs;
 | ||||
|   | ||||
|  	status = rs5c_get_regs(rs5c); | ||||
|  	if (status < 0) | ||||
| @@ -409,6 +411,30 @@ static int rs5c_read_alarm(struct device
 | ||||
|  	t->time.tm_sec = 0; | ||||
|  	t->time.tm_min = bcd2bin(rs5c->regs[RS5C_REG_ALARM_A_MIN] & 0x7f); | ||||
|  	t->time.tm_hour = rs5c_reg2hr(rs5c, rs5c->regs[RS5C_REG_ALARM_A_HOURS]); | ||||
| +	t->time.tm_wday = ffs(rs5c->regs[RS5C_REG_ALARM_A_WDAY] & 0x7f) - 1;
 | ||||
| +
 | ||||
| +	/* determine the day, month and year based on alarm wday, taking as a
 | ||||
| +	 * reference the current time from the rtc
 | ||||
| +	 */
 | ||||
| +	status = rs5c372_rtc_read_time(dev, &rtc);
 | ||||
| +	if (status < 0)
 | ||||
| +		return status;
 | ||||
| +
 | ||||
| +	wday_offs = t->time.tm_wday - rtc.tm_wday;
 | ||||
| +	alarm_secs = mktime64(rtc.tm_year + 1900,
 | ||||
| +			      rtc.tm_mon + 1,
 | ||||
| +			      rtc.tm_mday + wday_offs,
 | ||||
| +			      t->time.tm_hour,
 | ||||
| +			      t->time.tm_min,
 | ||||
| +			      t->time.tm_sec);
 | ||||
| +
 | ||||
| +	if (wday_offs < 0 || (wday_offs == 0 &&
 | ||||
| +			      (t->time.tm_hour < rtc.tm_hour ||
 | ||||
| +			       (t->time.tm_hour == rtc.tm_hour &&
 | ||||
| +				t->time.tm_min <= rtc.tm_min))))
 | ||||
| +		alarm_secs += 7 * 86400;
 | ||||
| +
 | ||||
| +	rtc_time64_to_tm(alarm_secs, &t->time);
 | ||||
|   | ||||
|  	/* ... and status */ | ||||
|  	t->enabled = !!(rs5c->regs[RS5C_REG_CTRL1] & RS5C_CTRL1_AALE); | ||||
| @@ -423,12 +449,20 @@ static int rs5c_set_alarm(struct device
 | ||||
|  	struct rs5c372		*rs5c = i2c_get_clientdata(client); | ||||
|  	int			status, addr, i; | ||||
|  	unsigned char		buf[3]; | ||||
| +	struct rtc_time 	rtc_tm;
 | ||||
| +	unsigned long 		rtc_secs, alarm_secs;
 | ||||
|   | ||||
| -	/* only handle up to 24 hours in the future, like RTC_ALM_SET */
 | ||||
| -	if (t->time.tm_mday != -1
 | ||||
| -			|| t->time.tm_mon != -1
 | ||||
| -			|| t->time.tm_year != -1)
 | ||||
| +	/* chip only can handle alarms up to one week in the future*/
 | ||||
| +	status = rs5c372_rtc_read_time(dev, &rtc_tm);
 | ||||
| +	if (status)
 | ||||
| +		return status;
 | ||||
| +	rtc_secs = rtc_tm_to_time64(&rtc_tm);
 | ||||
| +	alarm_secs = rtc_tm_to_time64(&t->time);
 | ||||
| +	if (alarm_secs >= rtc_secs + 7 * 86400) {
 | ||||
| +		dev_err(dev, "%s: alarm maximum is one week in the future (%d)\n",
 | ||||
| +			__func__, status);
 | ||||
|  		return -EINVAL; | ||||
| +	}
 | ||||
|   | ||||
|  	/* REVISIT: round up tm_sec */ | ||||
|   | ||||
| @@ -449,7 +483,9 @@ static int rs5c_set_alarm(struct device
 | ||||
|  	/* set alarm */ | ||||
|  	buf[0] = bin2bcd(t->time.tm_min); | ||||
|  	buf[1] = rs5c_hr2reg(rs5c, t->time.tm_hour); | ||||
| -	buf[2] = 0x7f;	/* any/all days */
 | ||||
| +	/* each bit is the day of the week, 0x7f means all days */
 | ||||
| +	buf[2] = (t->time.tm_wday >= 0 && t->time.tm_wday < 7) ?
 | ||||
| +		  BIT(t->time.tm_wday) : 0x7f;
 | ||||
|   | ||||
|  	for (i = 0; i < sizeof(buf); i++) { | ||||
|  		addr = RS5C_ADDR(RS5C_REG_ALARM_A_MIN + i); | ||||
|  | @ -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: | ||||
|  | @ -0,0 +1,167 @@ | |||
| From: Felix Fietkau <nbd@nbd.name> | ||||
| Subject: kernel: add a config option for keeping the kallsyms table uncompressed, saving ~9kb kernel size after lzma on ar71xx | ||||
| 
 | ||||
| [john@phrozen.org: added to my upstream queue 30.12.2016] | ||||
| lede-commit: e0e3509b5ce2ccf93d4d67ea907613f5f7ec2eed | ||||
| Signed-off-by: Felix Fietkau <nbd@nbd.name> | ||||
| ---
 | ||||
|  init/Kconfig            | 11 +++++++++++ | ||||
|  kernel/kallsyms.c       |  8 ++++++++ | ||||
|  scripts/kallsyms.c      | 12 ++++++++++++ | ||||
|  scripts/link-vmlinux.sh |  4 ++++ | ||||
|  4 files changed, 35 insertions(+) | ||||
| 
 | ||||
| --- a/init/Kconfig
 | ||||
| +++ b/init/Kconfig
 | ||||
| @@ -1451,6 +1451,17 @@ config SYSCTL_ARCH_UNALIGN_ALLOW
 | ||||
|  	  the unaligned access emulation. | ||||
|  	  see arch/parisc/kernel/unaligned.c for reference | ||||
|   | ||||
| +config KALLSYMS_UNCOMPRESSED
 | ||||
| +	bool "Keep kallsyms uncompressed"
 | ||||
| +	depends on KALLSYMS
 | ||||
| +	help
 | ||||
| +		Normally kallsyms contains compressed symbols (using a token table),
 | ||||
| +		reducing the uncompressed kernel image size. Keeping the symbol table
 | ||||
| +		uncompressed significantly improves the size of this part in compressed
 | ||||
| +		kernel images.
 | ||||
| +
 | ||||
| +		Say N unless you need compressed kernel images to be small.
 | ||||
| +
 | ||||
|  config HAVE_PCSPKR_PLATFORM | ||||
|  	bool | ||||
|   | ||||
| --- a/kernel/kallsyms.c
 | ||||
| +++ b/kernel/kallsyms.c
 | ||||
| @@ -69,6 +69,11 @@ static unsigned int kallsyms_expand_symb
 | ||||
|  	 * For every byte on the compressed symbol data, copy the table | ||||
|  	 * entry for that byte. | ||||
|  	 */ | ||||
| +#ifdef CONFIG_KALLSYMS_UNCOMPRESSED
 | ||||
| +	memcpy(result, data + 1, len - 1);
 | ||||
| +	result += len - 1;
 | ||||
| +	len = 0;
 | ||||
| +#endif
 | ||||
|  	while (len) { | ||||
|  		tptr = &kallsyms_token_table[kallsyms_token_index[*data]]; | ||||
|  		data++; | ||||
| @@ -101,6 +106,9 @@ tail:
 | ||||
|   */ | ||||
|  static char kallsyms_get_symbol_type(unsigned int off) | ||||
|  { | ||||
| +#ifdef CONFIG_KALLSYMS_UNCOMPRESSED
 | ||||
| +	return kallsyms_names[off + 1];
 | ||||
| +#endif
 | ||||
|  	/* | ||||
|  	 * Get just the first code, look it up in the token table, | ||||
|  	 * and return the first char from this token. | ||||
| --- a/scripts/kallsyms.c
 | ||||
| +++ b/scripts/kallsyms.c
 | ||||
| @@ -62,6 +62,7 @@ static struct addr_range percpu_range =
 | ||||
|  static struct sym_entry **table; | ||||
|  static unsigned int table_size, table_cnt; | ||||
|  static int all_symbols; | ||||
| +static int uncompressed;
 | ||||
|  static int absolute_percpu; | ||||
|  static int base_relative; | ||||
|  static int lto_clang; | ||||
| @@ -453,13 +454,15 @@ static void write_src(void)
 | ||||
|  	} | ||||
|  	printf("\n"); | ||||
|   | ||||
| -	/*
 | ||||
| -	 * Now that we wrote out the compressed symbol names, restore the
 | ||||
| -	 * original names, which are needed in some of the later steps.
 | ||||
| -	 */
 | ||||
| -	for (i = 0; i < table_cnt; i++) {
 | ||||
| -		expand_symbol(table[i]->sym, table[i]->len, buf);
 | ||||
| -		strcpy((char *)table[i]->sym, buf);
 | ||||
| +	if (!uncompressed) {
 | ||||
| +		/*
 | ||||
| +		 * Now that we wrote out the compressed symbol names, restore the
 | ||||
| +		 * original names, which are needed in some of the later steps.
 | ||||
| +		 */
 | ||||
| +		for (i = 0; i < table_cnt; i++) {
 | ||||
| +			expand_symbol(table[i]->sym, table[i]->len, buf);
 | ||||
| +			strcpy((char *)table[i]->sym, buf);
 | ||||
| +		}
 | ||||
|  	} | ||||
|   | ||||
|  	output_label("kallsyms_markers"); | ||||
| @@ -469,20 +472,22 @@ static void write_src(void)
 | ||||
|   | ||||
|  	free(markers); | ||||
|   | ||||
| -	output_label("kallsyms_token_table");
 | ||||
| -	off = 0;
 | ||||
| -	for (i = 0; i < 256; i++) {
 | ||||
| -		best_idx[i] = off;
 | ||||
| -		expand_symbol(best_table[i], best_table_len[i], buf);
 | ||||
| -		printf("\t.asciz\t\"%s\"\n", buf);
 | ||||
| -		off += strlen(buf) + 1;
 | ||||
| -	}
 | ||||
| -	printf("\n");
 | ||||
| +	if (!uncompressed) {
 | ||||
| +		output_label("kallsyms_token_table");
 | ||||
| +		off = 0;
 | ||||
| +		for (i = 0; i < 256; i++) {
 | ||||
| +			best_idx[i] = off;
 | ||||
| +			expand_symbol(best_table[i], best_table_len[i], buf);
 | ||||
| +			printf("\t.asciz\t\"%s\"\n", buf);
 | ||||
| +			off += strlen(buf) + 1;
 | ||||
| +		}
 | ||||
| +		printf("\n");
 | ||||
|   | ||||
| -	output_label("kallsyms_token_index");
 | ||||
| -	for (i = 0; i < 256; i++)
 | ||||
| -		printf("\t.short\t%d\n", best_idx[i]);
 | ||||
| -	printf("\n");
 | ||||
| +		output_label("kallsyms_token_index");
 | ||||
| +		for (i = 0; i < 256; i++)
 | ||||
| +			printf("\t.short\t%d\n", best_idx[i]);
 | ||||
| +		printf("\n");
 | ||||
| +	}
 | ||||
|   | ||||
|  	if (!base_relative) | ||||
|  		output_label("kallsyms_addresses"); | ||||
| @@ -582,6 +587,9 @@ static unsigned char *find_token(unsigne
 | ||||
|  { | ||||
|  	int i; | ||||
|   | ||||
| +	if (uncompressed)
 | ||||
| +		return NULL;
 | ||||
| +
 | ||||
|  	for (i = 0; i < len - 1; i++) { | ||||
|  		if (str[i] == token[0] && str[i+1] == token[1]) | ||||
|  			return &str[i]; | ||||
| @@ -654,6 +662,9 @@ static void optimize_result(void)
 | ||||
|  { | ||||
|  	int i, best; | ||||
|   | ||||
| +	if (uncompressed)
 | ||||
| +		return;
 | ||||
| +
 | ||||
|  	/* using the '\0' symbol last allows compress_symbols to use standard | ||||
|  	 * fast string functions */ | ||||
|  	for (i = 255; i >= 0; i--) { | ||||
| @@ -815,6 +826,7 @@ int main(int argc, char **argv)
 | ||||
|  			{"absolute-percpu", no_argument, &absolute_percpu, 1}, | ||||
|  			{"base-relative",   no_argument, &base_relative,   1}, | ||||
|  			{"lto-clang",       no_argument, <o_clang,       1}, | ||||
| +			{"uncompressed",   no_argument, &uncompressed,   1},
 | ||||
|  			{}, | ||||
|  		}; | ||||
|   | ||||
| --- a/scripts/link-vmlinux.sh
 | ||||
| +++ b/scripts/link-vmlinux.sh
 | ||||
| @@ -165,6 +165,10 @@ kallsyms()
 | ||||
|  		kallsymopt="${kallsymopt} --lto-clang" | ||||
|  	fi | ||||
|   | ||||
| +	if is_enabled CONFIG_KALLSYMS_UNCOMPRESSED; then
 | ||||
| +		kallsymopt="${kallsymopt} --uncompressed"
 | ||||
| +	fi
 | ||||
| +
 | ||||
|  	info KSYMS ${2} | ||||
|  	scripts/kallsyms ${kallsymopt} ${1} > ${2} | ||||
|  } | ||||
|  | @ -0,0 +1,41 @@ | |||
| From: Felix Fietkau <nbd@nbd.name> | ||||
| Subject: kernel: when KALLSYMS is disabled, print module address + size for matching backtrace entries | ||||
| 
 | ||||
| [john@phrozen.org: felix will add this to his upstream queue] | ||||
| 
 | ||||
| lede-commit 53827cdc824556cda910b23ce5030c363b8f1461 | ||||
| Signed-off-by: Felix Fietkau <nbd@nbd.name> | ||||
| ---
 | ||||
|  lib/vsprintf.c | 15 +++++++++++---- | ||||
|  1 file changed, 11 insertions(+), 4 deletions(-) | ||||
| 
 | ||||
| --- a/lib/vsprintf.c
 | ||||
| +++ b/lib/vsprintf.c
 | ||||
| @@ -982,8 +982,10 @@ char *symbol_string(char *buf, char *end
 | ||||
|  		    struct printf_spec spec, const char *fmt) | ||||
|  { | ||||
|  	unsigned long value; | ||||
| -#ifdef CONFIG_KALLSYMS
 | ||||
|  	char sym[KSYM_SYMBOL_LEN]; | ||||
| +#ifndef CONFIG_KALLSYMS
 | ||||
| +	struct module *mod;
 | ||||
| +	int len;
 | ||||
|  #endif | ||||
|   | ||||
|  	if (fmt[1] == 'R') | ||||
| @@ -1004,8 +1006,14 @@ char *symbol_string(char *buf, char *end
 | ||||
|   | ||||
|  	return string_nocheck(buf, end, sym, spec); | ||||
|  #else | ||||
| -	return special_hex_number(buf, end, value, sizeof(void *));
 | ||||
| +	len = snprintf(sym, sizeof(sym), "0x%lx", value);
 | ||||
| +	mod = __module_address(value);
 | ||||
| +	if (mod)
 | ||||
| +		snprintf(sym + len, sizeof(sym) - len, " [%s@%p+0x%x]",
 | ||||
| +			 mod->name, mod->mem[MOD_TEXT].base,
 | ||||
| +			 mod->mem[MOD_TEXT].size);
 | ||||
|  #endif | ||||
| +	return string(buf, end, sym, spec);
 | ||||
|  } | ||||
|   | ||||
|  static const struct printf_spec default_str_spec = { | ||||
|  | @ -0,0 +1,30 @@ | |||
| From: Gabor Juhos <juhosg@openwrt.org> | ||||
| Subject: usr: sanitize deps_initramfs list | ||||
| 
 | ||||
| If any filename in the intramfs dependency | ||||
| list contains a colon, that causes a kernel | ||||
| build error like this: | ||||
| 
 | ||||
| /devel/openwrt/build_dir/linux-ar71xx_generic/linux-3.6.6/usr/Makefile:58: *** multiple target patterns.  Stop. | ||||
| make[5]: *** [usr] Error 2 | ||||
| 
 | ||||
| Fix it by removing such filenames from the | ||||
| deps_initramfs list. | ||||
| 
 | ||||
| Signed-off-by: Gabor Juhos <juhosg@openwrt.org> | ||||
| Signed-off-by: Felix Fietkau <nbd@nbd.name> | ||||
| ---
 | ||||
|  usr/Makefile | 8 +++++--- | ||||
|  1 file changed, 5 insertions(+), 3 deletions(-) | ||||
| 
 | ||||
| --- a/usr/Makefile
 | ||||
| +++ b/usr/Makefile
 | ||||
| @@ -56,6 +56,8 @@ hostprogs := gen_init_cpio
 | ||||
|  # The dependency list is generated by gen_initramfs.sh -l | ||||
|  -include $(obj)/.initramfs_data.cpio.d | ||||
|   | ||||
| +deps_initramfs := $(foreach v,$(deps_initramfs),$(if $(findstring :,$(v)),,$(v)))
 | ||||
| +
 | ||||
|  # do not try to update files included in initramfs | ||||
|  $(deps_initramfs): ; | ||||
|   | ||||
|  | @ -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
 | ||||
| @@ -14,3 +14,5 @@ source "drivers/platform/olpc/Kconfig"
 | ||||
|  source "drivers/platform/surface/Kconfig" | ||||
|   | ||||
|  source "drivers/platform/x86/Kconfig" | ||||
| +
 | ||||
| +source "drivers/platform/mikrotik/Kconfig"
 | ||||
| --- a/drivers/platform/Makefile
 | ||||
| +++ b/drivers/platform/Makefile
 | ||||
| @@ -11,3 +11,4 @@ obj-$(CONFIG_OLPC_EC)		+= olpc/
 | ||||
|  obj-$(CONFIG_GOLDFISH)		+= goldfish/ | ||||
|  obj-$(CONFIG_CHROME_PLATFORMS)	+= chrome/ | ||||
|  obj-$(CONFIG_SURFACE_PLATFORMS)	+= surface/ | ||||
| +obj-$(CONFIG_MIKROTIK)		+= mikrotik/
 | ||||
|  | @ -0,0 +1,40 @@ | |||
| From: Mark Miller <mark@mirell.org> | ||||
| Subject: mips: expose CONFIG_BOOT_RAW | ||||
| 
 | ||||
| This exposes the CONFIG_BOOT_RAW symbol in Kconfig. This is needed on | ||||
| certain Broadcom chipsets running CFE in order to load the kernel. | ||||
| 
 | ||||
| Signed-off-by: Mark Miller <mark@mirell.org> | ||||
| Acked-by: Rob Landley <rob@landley.net> | ||||
| ---
 | ||||
| --- a/arch/mips/Kconfig
 | ||||
| +++ b/arch/mips/Kconfig
 | ||||
| @@ -1013,9 +1013,6 @@ config FW_ARC
 | ||||
|  config ARCH_MAY_HAVE_PC_FDC | ||||
|  	bool | ||||
|   | ||||
| -config BOOT_RAW
 | ||||
| -	bool
 | ||||
| -
 | ||||
|  config CEVT_BCM1480 | ||||
|  	bool | ||||
|   | ||||
| @@ -2996,6 +2993,18 @@ choice
 | ||||
|  		bool "Extend builtin kernel arguments with bootloader arguments" | ||||
|  endchoice | ||||
|   | ||||
| +config BOOT_RAW
 | ||||
| +	bool "Enable the kernel to be executed from the load address"
 | ||||
| +	default n
 | ||||
| +	help
 | ||||
| +	 Allow the kernel to be executed from the load address for
 | ||||
| +	 bootloaders which cannot read the ELF format. This places
 | ||||
| +	 a jump to start_kernel at the load address.
 | ||||
| +
 | ||||
| +	 If unsure, say N.
 | ||||
| +
 | ||||
| +
 | ||||
| +
 | ||||
|  endmenu | ||||
|   | ||||
|  config LOCKDEP_SUPPORT | ||||
|  | @ -0,0 +1,71 @@ | |||
| From e6e6ef4275978823ec3a84133fc91f4ffbef5c84 Mon Sep 17 00:00:00 2001 | ||||
| From: Paul Burton <paul.burton@imgtec.com> | ||||
| Date: Mon, 22 Feb 2016 18:09:44 +0000 | ||||
| Subject: [PATCH] MIPS: Add barriers between dcache & icache flushes | ||||
| 
 | ||||
| Index-based cache operations may be arbitrarily reordered by out of
 | ||||
| order CPUs. Thus code which writes back the dcache & then invalidates | ||||
| the icache using indexed cache ops must include a barrier between | ||||
| operating on the 2 caches in order to prevent the scenario in which: | ||||
| 
 | ||||
|   - icache invalidation occurs. | ||||
| 
 | ||||
|   - icache fetch occurs, due to speculation. | ||||
| 
 | ||||
|   - dcache writeback occurs. | ||||
| 
 | ||||
| If the above were allowed to happen then the icache would contain stale | ||||
| data. Forcing the dcache writeback to complete before the icache | ||||
| invalidation avoids this. | ||||
| 
 | ||||
| Signed-off-by: Paul Burton <paul.burton@imgtec.com> | ||||
| Cc: James Hogan <james.hogan@imgtec.com> | ||||
| ---
 | ||||
|  arch/mips/mm/c-r4k.c | 13 +++++++++++-- | ||||
|  1 file changed, 11 insertions(+), 2 deletions(-) | ||||
| 
 | ||||
| --- a/arch/mips/mm/c-r4k.c
 | ||||
| +++ b/arch/mips/mm/c-r4k.c
 | ||||
| @@ -403,6 +403,7 @@ static inline void local_r4k___flush_cac
 | ||||
|   | ||||
|  	default: | ||||
|  		r4k_blast_dcache(); | ||||
| +		mb(); /* cache instructions may be reordered */
 | ||||
|  		r4k_blast_icache(); | ||||
|  		break; | ||||
|  	} | ||||
| @@ -483,8 +484,10 @@ static inline void local_r4k_flush_cache
 | ||||
|  	if (cpu_has_dc_aliases || (exec && !cpu_has_ic_fills_f_dc)) | ||||
|  		r4k_blast_dcache(); | ||||
|  	/* If executable, blast stale lines from icache */ | ||||
| -	if (exec)
 | ||||
| +	if (exec) {
 | ||||
| +		mb(); /* cache instructions may be reordered */
 | ||||
|  		r4k_blast_icache(); | ||||
| +	}
 | ||||
|  } | ||||
|   | ||||
|  static void r4k_flush_cache_range(struct vm_area_struct *vma, | ||||
| @@ -586,8 +589,13 @@ static inline void local_r4k_flush_cache
 | ||||
|  	if (cpu_has_dc_aliases || (exec && !cpu_has_ic_fills_f_dc)) { | ||||
|  		vaddr ? r4k_blast_dcache_page(addr) : | ||||
|  			r4k_blast_dcache_user_page(addr); | ||||
| -		if (exec && !cpu_icache_snoops_remote_store)
 | ||||
| +		if (exec)
 | ||||
| +			mb(); /* cache instructions may be reordered */
 | ||||
| +
 | ||||
| +		if (exec && !cpu_icache_snoops_remote_store) {
 | ||||
|  			r4k_blast_scache_page(addr); | ||||
| +			mb(); /* cache instructions may be reordered */
 | ||||
| +		}
 | ||||
|  	} | ||||
|  	if (exec) { | ||||
|  		if (vaddr && cpu_has_vtag_icache && mm == current->active_mm) { | ||||
| @@ -654,6 +662,7 @@ static inline void __local_r4k_flush_ica
 | ||||
|  			else | ||||
|  				blast_dcache_range(start, end); | ||||
|  		} | ||||
| +		mb(); /* cache instructions may be reordered */
 | ||||
|  	} | ||||
|   | ||||
|  	if (type == R4K_INDEX || | ||||
|  | @ -0,0 +1,22 @@ | |||
| From: Felix Fietkau <nbd@nbd.name> | ||||
| Subject: mips: use -mno-branch-likely for kernel and userspace | ||||
| 
 | ||||
| saves ~11k kernel size after lzma and ~12k squashfs size in the | ||||
| 
 | ||||
| lede-commit: 41a039f46450ffae9483d6216422098669da2900 | ||||
| Signed-off-by: Felix Fietkau <nbd@nbd.name> | ||||
| ---
 | ||||
|  arch/mips/Makefile | 2 +- | ||||
|  1 file changed, 1 insertion(+), 1 deletion(-) | ||||
| 
 | ||||
| --- a/arch/mips/Makefile
 | ||||
| +++ b/arch/mips/Makefile
 | ||||
| @@ -94,7 +94,7 @@ all-$(CONFIG_SYS_SUPPORTS_ZBOOT)+= vmlin
 | ||||
|  # machines may also.  Since BFD is incredibly buggy with respect to | ||||
|  # crossformat linking we rely on the elf2ecoff tool for format conversion. | ||||
|  # | ||||
| -cflags-y			+= -G 0 -mno-abicalls -fno-pic -pipe
 | ||||
| +cflags-y			+= -G 0 -mno-abicalls -fno-pic -pipe -mno-branch-likely
 | ||||
|  cflags-y			+= -msoft-float -Wa,-msoft-float | ||||
|  LDFLAGS_vmlinux			+= -G 0 -static -n -nostdlib | ||||
|  KBUILD_AFLAGS_MODULE		+= -mlong-calls | ||||
|  | @ -0,0 +1,370 @@ | |||
| From: Felix Fietkau <nbd@nbd.name> | ||||
| Subject: mips: replace -mlong-calls with -mno-long-calls to make function calls faster in kernel modules to achieve this, try to | ||||
| 
 | ||||
| lede-commit: 3b3d64743ba2a874df9d70cd19e242205b0a788c | ||||
| Signed-off-by: Felix Fietkau <nbd@nbd.name> | ||||
| ---
 | ||||
|  arch/mips/Makefile             |   5 + | ||||
|  arch/mips/include/asm/module.h |   5 + | ||||
|  arch/mips/kernel/module.c      | 279 ++++++++++++++++++++++++++++++++++++++++- | ||||
|  3 files changed, 284 insertions(+), 5 deletions(-) | ||||
| 
 | ||||
| --- a/arch/mips/Makefile
 | ||||
| +++ b/arch/mips/Makefile
 | ||||
| @@ -97,8 +97,18 @@ all-$(CONFIG_SYS_SUPPORTS_ZBOOT)+= vmlin
 | ||||
|  cflags-y			+= -G 0 -mno-abicalls -fno-pic -pipe -mno-branch-likely | ||||
|  cflags-y			+= -msoft-float -Wa,-msoft-float | ||||
|  LDFLAGS_vmlinux			+= -G 0 -static -n -nostdlib | ||||
| +ifdef CONFIG_64BIT
 | ||||
|  KBUILD_AFLAGS_MODULE		+= -mlong-calls | ||||
|  KBUILD_CFLAGS_MODULE		+= -mlong-calls | ||||
| +else
 | ||||
| +  ifdef CONFIG_DYNAMIC_FTRACE
 | ||||
| +    KBUILD_AFLAGS_MODULE	+= -mlong-calls
 | ||||
| +    KBUILD_CFLAGS_MODULE	+= -mlong-calls
 | ||||
| +  else
 | ||||
| +    KBUILD_AFLAGS_MODULE	+= -mno-long-calls
 | ||||
| +    KBUILD_CFLAGS_MODULE	+= -mno-long-calls
 | ||||
| +  endif
 | ||||
| +endif
 | ||||
|   | ||||
|  ifeq ($(CONFIG_RELOCATABLE),y) | ||||
|  LDFLAGS_vmlinux			+= --emit-relocs | ||||
| --- a/arch/mips/include/asm/module.h
 | ||||
| +++ b/arch/mips/include/asm/module.h
 | ||||
| @@ -12,6 +12,11 @@ struct mod_arch_specific {
 | ||||
|  	const struct exception_table_entry *dbe_start; | ||||
|  	const struct exception_table_entry *dbe_end; | ||||
|  	struct mips_hi16 *r_mips_hi16_list; | ||||
| +
 | ||||
| +	void *phys_plt_tbl;
 | ||||
| +	void *virt_plt_tbl;
 | ||||
| +	unsigned int phys_plt_offset;
 | ||||
| +	unsigned int virt_plt_offset;
 | ||||
|  }; | ||||
|   | ||||
|  typedef uint8_t Elf64_Byte;		/* Type for a 8-bit quantity.  */ | ||||
| --- a/arch/mips/kernel/module.c
 | ||||
| +++ b/arch/mips/kernel/module.c
 | ||||
| @@ -32,23 +32,261 @@ struct mips_hi16 {
 | ||||
|  static LIST_HEAD(dbe_list); | ||||
|  static DEFINE_SPINLOCK(dbe_lock); | ||||
|   | ||||
| -#ifdef MODULE_START
 | ||||
| +/*
 | ||||
| + * Get the potential max trampolines size required of the init and
 | ||||
| + * non-init sections. Only used if we cannot find enough contiguous
 | ||||
| + * physically mapped memory to put the module into.
 | ||||
| + */
 | ||||
| +static unsigned int
 | ||||
| +get_plt_size(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs,
 | ||||
| +             const char *secstrings, unsigned int symindex, bool is_init)
 | ||||
| +{
 | ||||
| +	unsigned long ret = 0;
 | ||||
| +	unsigned int i, j;
 | ||||
| +	Elf_Sym *syms;
 | ||||
| +
 | ||||
| +	/* Everything marked ALLOC (this includes the exported symbols) */
 | ||||
| +	for (i = 1; i < hdr->e_shnum; ++i) {
 | ||||
| +		unsigned int info = sechdrs[i].sh_info;
 | ||||
| +
 | ||||
| +		if (sechdrs[i].sh_type != SHT_REL
 | ||||
| +		    && sechdrs[i].sh_type != SHT_RELA)
 | ||||
| +			continue;
 | ||||
| +
 | ||||
| +		/* Not a valid relocation section? */
 | ||||
| +		if (info >= hdr->e_shnum)
 | ||||
| +			continue;
 | ||||
| +
 | ||||
| +		/* Don't bother with non-allocated sections */
 | ||||
| +		if (!(sechdrs[info].sh_flags & SHF_ALLOC))
 | ||||
| +			continue;
 | ||||
| +
 | ||||
| +		/* If it's called *.init*, and we're not init, we're
 | ||||
| +                   not interested */
 | ||||
| +		if ((strstr(secstrings + sechdrs[i].sh_name, ".init") != 0)
 | ||||
| +		    != is_init)
 | ||||
| +			continue;
 | ||||
| +
 | ||||
| +		syms = (Elf_Sym *) sechdrs[symindex].sh_addr;
 | ||||
| +		if (sechdrs[i].sh_type == SHT_REL) {
 | ||||
| +			Elf_Mips_Rel *rel = (void *) sechdrs[i].sh_addr;
 | ||||
| +			unsigned int size = sechdrs[i].sh_size / sizeof(*rel);
 | ||||
| +
 | ||||
| +			for (j = 0; j < size; ++j) {
 | ||||
| +				Elf_Sym *sym;
 | ||||
| +
 | ||||
| +				if (ELF_MIPS_R_TYPE(rel[j]) != R_MIPS_26)
 | ||||
| +					continue;
 | ||||
| +
 | ||||
| +				sym = syms + ELF_MIPS_R_SYM(rel[j]);
 | ||||
| +				if (!is_init && sym->st_shndx != SHN_UNDEF)
 | ||||
| +					continue;
 | ||||
| +
 | ||||
| +				ret += 4 * sizeof(int);
 | ||||
| +			}
 | ||||
| +		} else {
 | ||||
| +			Elf_Mips_Rela *rela = (void *) sechdrs[i].sh_addr;
 | ||||
| +			unsigned int size = sechdrs[i].sh_size / sizeof(*rela);
 | ||||
| +
 | ||||
| +			for (j = 0; j < size; ++j) {
 | ||||
| +				Elf_Sym *sym;
 | ||||
| +
 | ||||
| +				if (ELF_MIPS_R_TYPE(rela[j]) != R_MIPS_26)
 | ||||
| +					continue;
 | ||||
| +
 | ||||
| +				sym = syms + ELF_MIPS_R_SYM(rela[j]);
 | ||||
| +				if (!is_init && sym->st_shndx != SHN_UNDEF)
 | ||||
| +					continue;
 | ||||
| +
 | ||||
| +				ret += 4 * sizeof(int);
 | ||||
| +			}
 | ||||
| +		}
 | ||||
| +	}
 | ||||
| +
 | ||||
| +	return ret;
 | ||||
| +}
 | ||||
| +
 | ||||
| +#ifndef MODULE_START
 | ||||
| +static void *alloc_phys(unsigned long size)
 | ||||
| +{
 | ||||
| +	unsigned order;
 | ||||
| +	struct page *page;
 | ||||
| +	struct page *p;
 | ||||
| +
 | ||||
| +	size = PAGE_ALIGN(size);
 | ||||
| +	order = get_order(size);
 | ||||
| +
 | ||||
| +	page = alloc_pages(GFP_KERNEL | __GFP_NORETRY | __GFP_NOWARN |
 | ||||
| +			__GFP_THISNODE, order);
 | ||||
| +	if (!page)
 | ||||
| +		return NULL;
 | ||||
| +
 | ||||
| +	split_page(page, order);
 | ||||
| +
 | ||||
| +	/* mark all pages except for the last one */
 | ||||
| +	for (p = page; p + 1 < page + (size >> PAGE_SHIFT); ++p)
 | ||||
| +		set_bit(PG_owner_priv_1, &p->flags);
 | ||||
| +
 | ||||
| +	for (p = page + (size >> PAGE_SHIFT); p < page + (1 << order); ++p)
 | ||||
| +		__free_page(p);
 | ||||
| +
 | ||||
| +	return page_address(page);
 | ||||
| +}
 | ||||
| +#endif
 | ||||
| +
 | ||||
| +static void free_phys(void *ptr)
 | ||||
| +{
 | ||||
| +	struct page *page;
 | ||||
| +	bool free;
 | ||||
| +
 | ||||
| +	page = virt_to_page(ptr);
 | ||||
| +	do {
 | ||||
| +		free = test_and_clear_bit(PG_owner_priv_1, &page->flags);
 | ||||
| +		__free_page(page);
 | ||||
| +		page++;
 | ||||
| +	} while (free);
 | ||||
| +}
 | ||||
| +
 | ||||
| +
 | ||||
|  void *module_alloc(unsigned long size) | ||||
|  { | ||||
| +#ifdef MODULE_START
 | ||||
|  	return __vmalloc_node_range(size, 1, MODULE_START, MODULE_END, | ||||
|  				GFP_KERNEL, PAGE_KERNEL, 0, NUMA_NO_NODE, | ||||
|  				__builtin_return_address(0)); | ||||
| +#else
 | ||||
| +	void *ptr;
 | ||||
| +
 | ||||
| +	if (size == 0)
 | ||||
| +		return NULL;
 | ||||
| +
 | ||||
| +	ptr = alloc_phys(size);
 | ||||
| +
 | ||||
| +	/* If we failed to allocate physically contiguous memory,
 | ||||
| +	 * fall back to regular vmalloc. The module loader code will
 | ||||
| +	 * create jump tables to handle long jumps */
 | ||||
| +	if (!ptr)
 | ||||
| +		return vmalloc(size);
 | ||||
| +
 | ||||
| +	return ptr;
 | ||||
| +#endif
 | ||||
|  } | ||||
| +
 | ||||
| +static inline bool is_phys_addr(void *ptr)
 | ||||
| +{
 | ||||
| +#ifdef CONFIG_64BIT
 | ||||
| +	return (KSEGX((unsigned long)ptr) == CKSEG0);
 | ||||
| +#else
 | ||||
| +	return (KSEGX(ptr) == KSEG0);
 | ||||
|  #endif | ||||
| +}
 | ||||
| +
 | ||||
| +/* Free memory returned from module_alloc */
 | ||||
| +void module_memfree(void *module_region)
 | ||||
| +{
 | ||||
| +	if (is_phys_addr(module_region))
 | ||||
| +		free_phys(module_region);
 | ||||
| +	else
 | ||||
| +		vfree(module_region);
 | ||||
| +}
 | ||||
| +
 | ||||
| +static void *__module_alloc(int size, bool phys)
 | ||||
| +{
 | ||||
| +	void *ptr;
 | ||||
| +
 | ||||
| +	if (phys)
 | ||||
| +		ptr = kmalloc(size, GFP_KERNEL);
 | ||||
| +	else
 | ||||
| +		ptr = vmalloc(size);
 | ||||
| +	return ptr;
 | ||||
| +}
 | ||||
| +
 | ||||
| +static void __module_free(void *ptr)
 | ||||
| +{
 | ||||
| +	if (is_phys_addr(ptr))
 | ||||
| +		kfree(ptr);
 | ||||
| +	else
 | ||||
| +		vfree(ptr);
 | ||||
| +}
 | ||||
| +
 | ||||
| +int module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs,
 | ||||
| +			      char *secstrings, struct module *mod)
 | ||||
| +{
 | ||||
| +	unsigned int symindex = 0;
 | ||||
| +	unsigned int core_size, init_size;
 | ||||
| +	int i;
 | ||||
| +
 | ||||
| +	mod->arch.phys_plt_offset = 0;
 | ||||
| +	mod->arch.virt_plt_offset = 0;
 | ||||
| +	mod->arch.phys_plt_tbl = NULL;
 | ||||
| +	mod->arch.virt_plt_tbl = NULL;
 | ||||
| +
 | ||||
| +	if (IS_ENABLED(CONFIG_64BIT))
 | ||||
| +		return 0;
 | ||||
| +
 | ||||
| +	for (i = 1; i < hdr->e_shnum; i++)
 | ||||
| +		if (sechdrs[i].sh_type == SHT_SYMTAB)
 | ||||
| +			symindex = i;
 | ||||
| +
 | ||||
| +	core_size = get_plt_size(hdr, sechdrs, secstrings, symindex, false);
 | ||||
| +	init_size = get_plt_size(hdr, sechdrs, secstrings, symindex, true);
 | ||||
| +
 | ||||
| +	if ((core_size + init_size) == 0)
 | ||||
| +		return 0;
 | ||||
| +
 | ||||
| +	mod->arch.phys_plt_tbl = __module_alloc(core_size + init_size, 1);
 | ||||
| +	if (!mod->arch.phys_plt_tbl)
 | ||||
| +		return -ENOMEM;
 | ||||
| +
 | ||||
| +	mod->arch.virt_plt_tbl = __module_alloc(core_size + init_size, 0);
 | ||||
| +	if (!mod->arch.virt_plt_tbl) {
 | ||||
| +		__module_free(mod->arch.phys_plt_tbl);
 | ||||
| +		mod->arch.phys_plt_tbl = NULL;
 | ||||
| +		return -ENOMEM;
 | ||||
| +	}
 | ||||
| +
 | ||||
| +	return 0;
 | ||||
| +}
 | ||||
|   | ||||
|  static void apply_r_mips_32(u32 *location, u32 base, Elf_Addr v) | ||||
|  { | ||||
|  	*location = base + v; | ||||
|  } | ||||
|   | ||||
| +static Elf_Addr add_plt_entry_to(unsigned *plt_offset,
 | ||||
| +				 void *start, Elf_Addr v)
 | ||||
| +{
 | ||||
| +	unsigned *tramp = start + *plt_offset;
 | ||||
| +	*plt_offset += 4 * sizeof(int);
 | ||||
| +
 | ||||
| +	/* adjust carry for addiu */
 | ||||
| +	if (v & 0x00008000)
 | ||||
| +		v += 0x10000;
 | ||||
| +
 | ||||
| +	tramp[0] = 0x3c190000 | (v >> 16);      /* lui t9, hi16 */
 | ||||
| +	tramp[1] = 0x27390000 | (v & 0xffff);   /* addiu t9, t9, lo16 */
 | ||||
| +	tramp[2] = 0x03200008;                  /* jr t9 */
 | ||||
| +	tramp[3] = 0x00000000;                  /* nop */
 | ||||
| +
 | ||||
| +	return (Elf_Addr) tramp;
 | ||||
| +}
 | ||||
| +
 | ||||
| +static Elf_Addr add_plt_entry(struct module *me, void *location, Elf_Addr v)
 | ||||
| +{
 | ||||
| +	if (is_phys_addr(location))
 | ||||
| +		return add_plt_entry_to(&me->arch.phys_plt_offset,
 | ||||
| +				me->arch.phys_plt_tbl, v);
 | ||||
| +	else
 | ||||
| +		return add_plt_entry_to(&me->arch.virt_plt_offset,
 | ||||
| +				me->arch.virt_plt_tbl, v);
 | ||||
| +
 | ||||
| +}
 | ||||
| +
 | ||||
|  static int apply_r_mips_26(struct module *me, u32 *location, u32 base, | ||||
|  			   Elf_Addr v) | ||||
|  { | ||||
| +	u32 ofs = base & 0x03ffffff;
 | ||||
| +
 | ||||
|  	if (v % 4) { | ||||
|  		pr_err("module %s: dangerous R_MIPS_26 relocation\n", | ||||
|  		       me->name); | ||||
| @@ -56,13 +294,17 @@ static int apply_r_mips_26(struct module
 | ||||
|  	} | ||||
|   | ||||
|  	if ((v & 0xf0000000) != (((unsigned long)location + 4) & 0xf0000000)) { | ||||
| -		pr_err("module %s: relocation overflow\n",
 | ||||
| -		       me->name);
 | ||||
| -		return -ENOEXEC;
 | ||||
| +		v = add_plt_entry(me, location, v + (ofs << 2));
 | ||||
| +		if (!v) {
 | ||||
| +			pr_err("module %s: relocation overflow\n",
 | ||||
| +			       me->name);
 | ||||
| +			return -ENOEXEC;
 | ||||
| +		}
 | ||||
| +		ofs = 0;
 | ||||
|  	} | ||||
|   | ||||
|  	*location = (*location & ~0x03ffffff) | | ||||
| -		    ((base + (v >> 2)) & 0x03ffffff);
 | ||||
| +		    ((ofs + (v >> 2)) & 0x03ffffff);
 | ||||
|   | ||||
|  	return 0; | ||||
|  } | ||||
| @@ -442,9 +684,36 @@ int module_finalize(const Elf_Ehdr *hdr,
 | ||||
|  		list_add(&me->arch.dbe_list, &dbe_list); | ||||
|  		spin_unlock_irq(&dbe_lock); | ||||
|  	} | ||||
| +
 | ||||
| +	/* Get rid of the fixup trampoline if we're running the module
 | ||||
| +	 * from physically mapped address space */
 | ||||
| +	if (me->arch.phys_plt_offset == 0) {
 | ||||
| +		__module_free(me->arch.phys_plt_tbl);
 | ||||
| +		me->arch.phys_plt_tbl = NULL;
 | ||||
| +	}
 | ||||
| +	if (me->arch.virt_plt_offset == 0) {
 | ||||
| +		__module_free(me->arch.virt_plt_tbl);
 | ||||
| +		me->arch.virt_plt_tbl = NULL;
 | ||||
| +	}
 | ||||
| +
 | ||||
|  	return 0; | ||||
|  } | ||||
|   | ||||
| +void module_arch_freeing_init(struct module *mod)
 | ||||
| +{
 | ||||
| +	if (mod->state == MODULE_STATE_LIVE)
 | ||||
| +		return;
 | ||||
| +
 | ||||
| +	if (mod->arch.phys_plt_tbl) {
 | ||||
| +		__module_free(mod->arch.phys_plt_tbl);
 | ||||
| +		mod->arch.phys_plt_tbl = NULL;
 | ||||
| +	}
 | ||||
| +	if (mod->arch.virt_plt_tbl) {
 | ||||
| +		__module_free(mod->arch.virt_plt_tbl);
 | ||||
| +		mod->arch.virt_plt_tbl = NULL;
 | ||||
| +	}
 | ||||
| +}
 | ||||
| +
 | ||||
|  void module_arch_cleanup(struct module *mod) | ||||
|  { | ||||
|  	spin_lock_irq(&dbe_lock); | ||||
|  | @ -0,0 +1,22 @@ | |||
| From: Felix Fietkau <nbd@nbd.name> | ||||
| Subject: kernel: add -mtune=34kc to MIPS CFLAGS when building for mips32r2 | ||||
| 
 | ||||
| This provides a good tradeoff across at least 24Kc-74Kc, while also | ||||
| producing smaller code. | ||||
| 
 | ||||
| Signed-off-by: Felix Fietkau <nbd@nbd.name> | ||||
| ---
 | ||||
|  arch/mips/Makefile | 2 +- | ||||
|  1 file changed, 1 insertion(+), 1 deletion(-) | ||||
| 
 | ||||
| --- a/arch/mips/Makefile
 | ||||
| +++ b/arch/mips/Makefile
 | ||||
| @@ -163,7 +163,7 @@ cflags-$(CONFIG_CPU_R4300)	+= -march=r43
 | ||||
|  cflags-$(CONFIG_CPU_R4X00)	+= -march=r4600 -Wa,--trap | ||||
|  cflags-$(CONFIG_CPU_TX49XX)	+= -march=r4600 -Wa,--trap | ||||
|  cflags-$(CONFIG_CPU_MIPS32_R1)	+= -march=mips32 -Wa,--trap | ||||
| -cflags-$(CONFIG_CPU_MIPS32_R2)	+= -march=mips32r2 -Wa,--trap
 | ||||
| +cflags-$(CONFIG_CPU_MIPS32_R2)	+= -march=mips32r2 -mtune=34kc -Wa,--trap
 | ||||
|  cflags-$(CONFIG_CPU_MIPS32_R5)	+= -march=mips32r5 -Wa,--trap -modd-spreg | ||||
|  cflags-$(CONFIG_CPU_MIPS32_R6)	+= -march=mips32r6 -Wa,--trap -modd-spreg | ||||
|  cflags-$(CONFIG_CPU_MIPS64_R1)	+= -march=mips64 -Wa,--trap | ||||
|  | @ -0,0 +1,22 @@ | |||
| From: Felix Fietkau <nbd@nbd.name> | ||||
| Subject: fix errors in unresolved weak symbols on arm | ||||
| 
 | ||||
| lede-commit: 570699d4838a907c3ef9f2819bf19eb72997b32f | ||||
| Signed-off-by: Felix Fietkau <nbd@nbd.name> | ||||
| ---
 | ||||
|  arch/arm/kernel/module.c | 4 ++++ | ||||
|  1 file changed, 4 insertions(+) | ||||
| 
 | ||||
| --- a/arch/arm/kernel/module.c
 | ||||
| +++ b/arch/arm/kernel/module.c
 | ||||
| @@ -146,6 +146,10 @@ apply_relocate(Elf32_Shdr *sechdrs, cons
 | ||||
|  			return -ENOEXEC; | ||||
|  		} | ||||
|   | ||||
| +		if ((IS_ERR_VALUE(sym->st_value) || !sym->st_value) &&
 | ||||
| +		    ELF_ST_BIND(sym->st_info) == STB_WEAK)
 | ||||
| +			continue;
 | ||||
| +
 | ||||
|  		loc = dstsec->sh_addr + rel->r_offset; | ||||
|   | ||||
|  		switch (ELF32_R_TYPE(rel->r_info)) { | ||||
|  | @ -0,0 +1,282 @@ | |||
| From: Yousong Zhou <yszhou4tech@gmail.com> | ||||
| Subject: MIPS: kexec: Accept command line parameters from userspace. | ||||
| 
 | ||||
| Signed-off-by: Yousong Zhou <yszhou4tech@gmail.com> | ||||
| ---
 | ||||
|  arch/mips/kernel/machine_kexec.c   |  153 +++++++++++++++++++++++++++++++----- | ||||
|  arch/mips/kernel/machine_kexec.h   |   20 +++++ | ||||
|  arch/mips/kernel/relocate_kernel.S |   21 +++-- | ||||
|  3 files changed, 167 insertions(+), 27 deletions(-) | ||||
|  create mode 100644 arch/mips/kernel/machine_kexec.h | ||||
| 
 | ||||
| --- a/arch/mips/kernel/machine_kexec.c
 | ||||
| +++ b/arch/mips/kernel/machine_kexec.c
 | ||||
| @@ -9,14 +9,11 @@
 | ||||
|  #include <linux/delay.h> | ||||
|  #include <linux/libfdt.h> | ||||
|   | ||||
| +#include <asm/bootinfo.h>
 | ||||
|  #include <asm/cacheflush.h> | ||||
|  #include <asm/page.h> | ||||
| -
 | ||||
| -extern const unsigned char relocate_new_kernel[];
 | ||||
| -extern const size_t relocate_new_kernel_size;
 | ||||
| -
 | ||||
| -extern unsigned long kexec_start_address;
 | ||||
| -extern unsigned long kexec_indirection_page;
 | ||||
| +#include <linux/uaccess.h>
 | ||||
| +#include "machine_kexec.h"
 | ||||
|   | ||||
|  static unsigned long reboot_code_buffer; | ||||
|   | ||||
| @@ -30,6 +27,101 @@ void (*_crash_smp_send_stop)(void) = NUL
 | ||||
|  void (*_machine_kexec_shutdown)(void) = NULL; | ||||
|  void (*_machine_crash_shutdown)(struct pt_regs *regs) = NULL; | ||||
|   | ||||
| +static void machine_kexec_print_args(void)
 | ||||
| +{
 | ||||
| +	unsigned long argc = (int)kexec_args[0];
 | ||||
| +	int i;
 | ||||
| +
 | ||||
| +	pr_info("kexec_args[0] (argc): %lu\n", argc);
 | ||||
| +	pr_info("kexec_args[1] (argv): %p\n", (void *)kexec_args[1]);
 | ||||
| +	pr_info("kexec_args[2] (env ): %p\n", (void *)kexec_args[2]);
 | ||||
| +	pr_info("kexec_args[3] (desc): %p\n", (void *)kexec_args[3]);
 | ||||
| +
 | ||||
| +	for (i = 0; i < argc; i++) {
 | ||||
| +		pr_info("kexec_argv[%d] = %p, %s\n",
 | ||||
| +				i, kexec_argv[i], kexec_argv[i]);
 | ||||
| +	}
 | ||||
| +}
 | ||||
| +
 | ||||
| +static void machine_kexec_init_argv(struct kimage *image)
 | ||||
| +{
 | ||||
| +	void __user *buf = NULL;
 | ||||
| +	size_t bufsz;
 | ||||
| +	size_t size;
 | ||||
| +	int i;
 | ||||
| +
 | ||||
| +	bufsz = 0;
 | ||||
| +	for (i = 0; i < image->nr_segments; i++) {
 | ||||
| +		struct kexec_segment *seg;
 | ||||
| +
 | ||||
| +		seg = &image->segment[i];
 | ||||
| +		if (seg->bufsz < 6)
 | ||||
| +			continue;
 | ||||
| +
 | ||||
| +		if (strncmp((char *) seg->buf, "kexec ", 6))
 | ||||
| +			continue;
 | ||||
| +
 | ||||
| +		buf = seg->buf;
 | ||||
| +		bufsz = seg->bufsz;
 | ||||
| +		break;
 | ||||
| +	}
 | ||||
| +
 | ||||
| +	if (!buf)
 | ||||
| +		return;
 | ||||
| +
 | ||||
| +	size = KEXEC_COMMAND_LINE_SIZE;
 | ||||
| +	size = min(size, bufsz);
 | ||||
| +	if (size < bufsz)
 | ||||
| +		pr_warn("kexec command line truncated to %zd bytes\n", size);
 | ||||
| +
 | ||||
| +	/* Copy to kernel space */
 | ||||
| +	if (copy_from_user(kexec_argv_buf, buf, size))
 | ||||
| +		pr_warn("kexec command line copy to kernel space failed\n");
 | ||||
| +
 | ||||
| +	kexec_argv_buf[size - 1] = 0;
 | ||||
| +}
 | ||||
| +
 | ||||
| +static void machine_kexec_parse_argv(struct kimage *image)
 | ||||
| +{
 | ||||
| +	char *reboot_code_buffer;
 | ||||
| +	int reloc_delta;
 | ||||
| +	char *ptr;
 | ||||
| +	int argc;
 | ||||
| +	int i;
 | ||||
| +
 | ||||
| +	ptr = kexec_argv_buf;
 | ||||
| +	argc = 0;
 | ||||
| +
 | ||||
| +	/*
 | ||||
| +	 * convert command line string to array of parameters
 | ||||
| +	 * (as bootloader does).
 | ||||
| +	 */
 | ||||
| +	while (ptr && *ptr && (KEXEC_MAX_ARGC > argc)) {
 | ||||
| +		if (*ptr == ' ') {
 | ||||
| +			*ptr++ = '\0';
 | ||||
| +			continue;
 | ||||
| +		}
 | ||||
| +
 | ||||
| +		kexec_argv[argc++] = ptr;
 | ||||
| +		ptr = strchr(ptr, ' ');
 | ||||
| +	}
 | ||||
| +
 | ||||
| +	if (!argc)
 | ||||
| +		return;
 | ||||
| +
 | ||||
| +	kexec_args[0] = argc;
 | ||||
| +	kexec_args[1] = (unsigned long)kexec_argv;
 | ||||
| +	kexec_args[2] = 0;
 | ||||
| +	kexec_args[3] = 0;
 | ||||
| +
 | ||||
| +	reboot_code_buffer = page_address(image->control_code_page);
 | ||||
| +	reloc_delta = reboot_code_buffer - (char *)kexec_relocate_new_kernel;
 | ||||
| +
 | ||||
| +	kexec_args[1] += reloc_delta;
 | ||||
| +	for (i = 0; i < argc; i++)
 | ||||
| +		kexec_argv[i] += reloc_delta;
 | ||||
| +}
 | ||||
| +
 | ||||
|  static void kexec_image_info(const struct kimage *kimage) | ||||
|  { | ||||
|  	unsigned long i; | ||||
| @@ -99,6 +191,18 @@ machine_kexec_prepare(struct kimage *kim
 | ||||
|  #endif | ||||
|   | ||||
|  	kexec_image_info(kimage); | ||||
| +	/*
 | ||||
| +	 * Whenever arguments passed from kexec-tools, Init the arguments as
 | ||||
| +	 * the original ones to try avoiding booting failure.
 | ||||
| +	 */
 | ||||
| +
 | ||||
| +	kexec_args[0] = fw_arg0;
 | ||||
| +	kexec_args[1] = fw_arg1;
 | ||||
| +	kexec_args[2] = fw_arg2;
 | ||||
| +	kexec_args[3] = fw_arg3;
 | ||||
| +
 | ||||
| +	machine_kexec_init_argv(kimage);
 | ||||
| +	machine_kexec_parse_argv(kimage);
 | ||||
|   | ||||
|  	if (_machine_kexec_prepare) | ||||
|  		return _machine_kexec_prepare(kimage); | ||||
| @@ -161,7 +265,7 @@ machine_crash_shutdown(struct pt_regs *r
 | ||||
|  void kexec_nonboot_cpu_jump(void) | ||||
|  { | ||||
|  	local_flush_icache_range((unsigned long)relocated_kexec_smp_wait, | ||||
| -				 reboot_code_buffer + relocate_new_kernel_size);
 | ||||
| +				 reboot_code_buffer + KEXEC_RELOCATE_NEW_KERNEL_SIZE);
 | ||||
|   | ||||
|  	relocated_kexec_smp_wait(NULL); | ||||
|  } | ||||
| @@ -199,7 +303,7 @@ void kexec_reboot(void)
 | ||||
|  	 * machine_kexec() CPU. | ||||
|  	 */ | ||||
|  	local_flush_icache_range(reboot_code_buffer, | ||||
| -				 reboot_code_buffer + relocate_new_kernel_size);
 | ||||
| +				 reboot_code_buffer + KEXEC_RELOCATE_NEW_KERNEL_SIZE);
 | ||||
|   | ||||
|  	do_kexec = (void *)reboot_code_buffer; | ||||
|  	do_kexec(); | ||||
| @@ -212,10 +316,12 @@ machine_kexec(struct kimage *image)
 | ||||
|  	unsigned long *ptr; | ||||
|   | ||||
|  	reboot_code_buffer = | ||||
| -	  (unsigned long)page_address(image->control_code_page);
 | ||||
| +		(unsigned long)page_address(image->control_code_page);
 | ||||
| +	pr_info("reboot_code_buffer = %p\n", (void *)reboot_code_buffer);
 | ||||
|   | ||||
|  	kexec_start_address = | ||||
|  		(unsigned long) phys_to_virt(image->start); | ||||
| +	pr_info("kexec_start_address = %p\n", (void *)kexec_start_address);
 | ||||
|   | ||||
|  	if (image->type == KEXEC_TYPE_DEFAULT) { | ||||
|  		kexec_indirection_page = | ||||
| @@ -223,9 +329,19 @@ machine_kexec(struct kimage *image)
 | ||||
|  	} else { | ||||
|  		kexec_indirection_page = (unsigned long)&image->head; | ||||
|  	} | ||||
| +	pr_info("kexec_indirection_page = %p\n", (void *)kexec_indirection_page);
 | ||||
|   | ||||
| -	memcpy((void*)reboot_code_buffer, relocate_new_kernel,
 | ||||
| -	       relocate_new_kernel_size);
 | ||||
| +	pr_info("Where is memcpy: %p\n", memcpy);
 | ||||
| +	pr_info("kexec_relocate_new_kernel = %p, kexec_relocate_new_kernel_end = %p\n",
 | ||||
| +		(void *)kexec_relocate_new_kernel, &kexec_relocate_new_kernel_end);
 | ||||
| +	pr_info("Copy %lu bytes from %p to %p\n", KEXEC_RELOCATE_NEW_KERNEL_SIZE,
 | ||||
| +		(void *)kexec_relocate_new_kernel, (void *)reboot_code_buffer);
 | ||||
| +	memcpy((void*)reboot_code_buffer, kexec_relocate_new_kernel,
 | ||||
| +	       KEXEC_RELOCATE_NEW_KERNEL_SIZE);
 | ||||
| +
 | ||||
| +	pr_info("Before _print_args().\n");
 | ||||
| +	machine_kexec_print_args();
 | ||||
| +	pr_info("Before eval loop.\n");
 | ||||
|   | ||||
|  	/* | ||||
|  	 * The generic kexec code builds a page list with physical | ||||
| @@ -256,7 +372,7 @@ machine_kexec(struct kimage *image)
 | ||||
|  #ifdef CONFIG_SMP | ||||
|  	/* All secondary cpus now may jump to kexec_wait cycle */ | ||||
|  	relocated_kexec_smp_wait = reboot_code_buffer + | ||||
| -		(void *)(kexec_smp_wait - relocate_new_kernel);
 | ||||
| +		(void *)(kexec_smp_wait - kexec_relocate_new_kernel);
 | ||||
|  	smp_wmb(); | ||||
|  	atomic_set(&kexec_ready_to_reboot, 1); | ||||
|  #endif | ||||
| --- /dev/null
 | ||||
| +++ b/arch/mips/kernel/machine_kexec.h
 | ||||
| @@ -0,0 +1,20 @@
 | ||||
| +#ifndef _MACHINE_KEXEC_H
 | ||||
| +#define _MACHINE_KEXEC_H
 | ||||
| +
 | ||||
| +#ifndef __ASSEMBLY__
 | ||||
| +extern const unsigned char kexec_relocate_new_kernel[];
 | ||||
| +extern unsigned long kexec_relocate_new_kernel_end;
 | ||||
| +extern unsigned long kexec_start_address;
 | ||||
| +extern unsigned long kexec_indirection_page;
 | ||||
| +
 | ||||
| +extern char kexec_argv_buf[];
 | ||||
| +extern char *kexec_argv[];
 | ||||
| +
 | ||||
| +#define KEXEC_RELOCATE_NEW_KERNEL_SIZE	((unsigned long)&kexec_relocate_new_kernel_end - (unsigned long)kexec_relocate_new_kernel)
 | ||||
| +#endif /* !__ASSEMBLY__ */
 | ||||
| +
 | ||||
| +#define KEXEC_COMMAND_LINE_SIZE		256
 | ||||
| +#define KEXEC_ARGV_SIZE			(KEXEC_COMMAND_LINE_SIZE / 16)
 | ||||
| +#define KEXEC_MAX_ARGC			(KEXEC_ARGV_SIZE / sizeof(long))
 | ||||
| +
 | ||||
| +#endif
 | ||||
| --- a/arch/mips/kernel/relocate_kernel.S
 | ||||
| +++ b/arch/mips/kernel/relocate_kernel.S
 | ||||
| @@ -10,10 +10,11 @@
 | ||||
|  #include <asm/mipsregs.h> | ||||
|  #include <asm/stackframe.h> | ||||
|  #include <asm/addrspace.h> | ||||
| +#include "machine_kexec.h"
 | ||||
|   | ||||
|  #include <kernel-entry-init.h> | ||||
|   | ||||
| -LEAF(relocate_new_kernel)
 | ||||
| +LEAF(kexec_relocate_new_kernel)
 | ||||
|  	PTR_L a0,	arg0 | ||||
|  	PTR_L a1,	arg1 | ||||
|  	PTR_L a2,	arg2 | ||||
| @@ -98,7 +99,7 @@ done:
 | ||||
|  #endif | ||||
|  	/* jump to kexec_start_address */ | ||||
|  	j		s1 | ||||
| -	END(relocate_new_kernel)
 | ||||
| +	END(kexec_relocate_new_kernel)
 | ||||
|   | ||||
|  #ifdef CONFIG_SMP | ||||
|  /* | ||||
| @@ -177,8 +178,15 @@ EXPORT(kexec_indirection_page)
 | ||||
|  	PTR_WD		0 | ||||
|  	.size		kexec_indirection_page, PTRSIZE | ||||
|   | ||||
| -relocate_new_kernel_end:
 | ||||
| +kexec_argv_buf:
 | ||||
| +	EXPORT(kexec_argv_buf)
 | ||||
| +	.skip		KEXEC_COMMAND_LINE_SIZE
 | ||||
| +	.size		kexec_argv_buf, KEXEC_COMMAND_LINE_SIZE
 | ||||
| +
 | ||||
| +kexec_argv:
 | ||||
| +	EXPORT(kexec_argv)
 | ||||
| +	.skip		KEXEC_ARGV_SIZE
 | ||||
| +	.size		kexec_argv, KEXEC_ARGV_SIZE
 | ||||
|   | ||||
| -EXPORT(relocate_new_kernel_size)
 | ||||
| -	PTR_WD		relocate_new_kernel_end - relocate_new_kernel
 | ||||
| -	.size		relocate_new_kernel_size, PTRSIZE
 | ||||
| +kexec_relocate_new_kernel_end:
 | ||||
| +	EXPORT(kexec_relocate_new_kernel_end)
 | ||||
|  | @ -0,0 +1,84 @@ | |||
| From bb0c3b0175240bf152fd7c644821a0cf9f77c37c Mon Sep 17 00:00:00 2001 | ||||
| From: Evgeniy Didin <Evgeniy.Didin@synopsys.com> | ||||
| Date: Fri, 15 Mar 2019 18:53:38 +0300 | ||||
| Subject: [PATCH] arc add OWRTDTB section | ||||
| 
 | ||||
| This change allows OpenWRT to patch resulting kernel binary with | ||||
| external .dtb. | ||||
| 
 | ||||
| That allows us to re-use exactky the same vmlinux on different boards | ||||
| given its ARC core configurations match (at least cache line sizes etc). | ||||
| 
 | ||||
| ""patch-dtb" searches for ASCII "OWRTDTB:" strign and copies external | ||||
| .dtb right after it, keeping the string in place. | ||||
| 
 | ||||
| Signed-off-by: Eugeniy Paltsev <Eugeniy.Paltsev@synopsys.com> | ||||
| Signed-off-by: Alexey Brodkin <abrodkin@synopsys.com> | ||||
| Signed-off-by: Evgeniy Didin <Evgeniy.Didin@synopsys.com> | ||||
| ---
 | ||||
|  arch/arc/kernel/head.S        | 10 ++++++++++ | ||||
|  arch/arc/kernel/setup.c       |  4 +++- | ||||
|  arch/arc/kernel/vmlinux.lds.S | 13 +++++++++++++ | ||||
|  3 files changed, 26 insertions(+), 1 deletion(-) | ||||
| 
 | ||||
| --- a/arch/arc/kernel/head.S
 | ||||
| +++ b/arch/arc/kernel/head.S
 | ||||
| @@ -88,6 +88,16 @@
 | ||||
|  	DSP_EARLY_INIT | ||||
|  .endm | ||||
|   | ||||
| +	; Here "patch-dtb" will embed external .dtb
 | ||||
| +	; Note "patch-dtb" searches for ASCII "OWRTDTB:" string
 | ||||
| +	; and pastes .dtb right after it, hense the string precedes
 | ||||
| +	; __image_dtb symbol.
 | ||||
| +	.section .owrt, "aw",@progbits
 | ||||
| +	.ascii  "OWRTDTB:"
 | ||||
| +ENTRY(__image_dtb)
 | ||||
| +	.fill   0x4000
 | ||||
| +END(__image_dtb)
 | ||||
| +
 | ||||
|  	.section .init.text, "ax",@progbits | ||||
|   | ||||
|  ;---------------------------------------------------------------- | ||||
| --- a/arch/arc/kernel/setup.c
 | ||||
| +++ b/arch/arc/kernel/setup.c
 | ||||
| @@ -450,6 +450,8 @@ static inline bool uboot_arg_invalid(uns
 | ||||
|  /* We always pass 0 as magic from U-boot */ | ||||
|  #define UBOOT_MAGIC_VALUE	0 | ||||
|   | ||||
| +extern struct boot_param_header __image_dtb;
 | ||||
| +
 | ||||
|  void __init handle_uboot_args(void) | ||||
|  { | ||||
|  	bool use_embedded_dtb = true; | ||||
| @@ -488,7 +490,7 @@ void __init handle_uboot_args(void)
 | ||||
|  ignore_uboot_args: | ||||
|   | ||||
|  	if (use_embedded_dtb) { | ||||
| -		machine_desc = setup_machine_fdt(__dtb_start);
 | ||||
| +		machine_desc = setup_machine_fdt(&__image_dtb);
 | ||||
|  		if (!machine_desc) | ||||
|  			panic("Embedded DT invalid\n"); | ||||
|  	} | ||||
| --- a/arch/arc/kernel/vmlinux.lds.S
 | ||||
| +++ b/arch/arc/kernel/vmlinux.lds.S
 | ||||
| @@ -27,6 +27,19 @@ SECTIONS
 | ||||
|   | ||||
|  	. = CONFIG_LINUX_LINK_BASE; | ||||
|   | ||||
| +	/*
 | ||||
| +	* In OpenWRT we want to patch built binary embedding .dtb of choice.
 | ||||
| +	* This is implemented with "patch-dtb" utility which searches for
 | ||||
| +	* "OWRTDTB:" string in first 16k of image and if it is found
 | ||||
| +	* copies .dtb right after mentioned string.
 | ||||
| +	*
 | ||||
| +	* Note: "OWRTDTB:" won't be overwritten with .dtb, .dtb will follow it.
 | ||||
| +	*/
 | ||||
| +	.owrt : {
 | ||||
| +		*(.owrt)
 | ||||
| +	. = ALIGN(PAGE_SIZE);
 | ||||
| +	}
 | ||||
| +
 | ||||
|  	_int_vec_base_lds = .; | ||||
|  	.vector : { | ||||
|  		*(.vector) | ||||
|  | @ -0,0 +1,24 @@ | |||
| From: Alexey Brodkin <abrodkin@synopsys.com> | ||||
| Subject: arc: enable unaligned access in kernel mode | ||||
| 
 | ||||
| This enables misaligned access handling even in kernel mode. | ||||
| Some wireless drivers (ath9k-htc and mt7601u) use misaligned accesses | ||||
| here and there and to cope with that without fixing stuff in the drivers | ||||
| we're just gracefully handling it on ARC. | ||||
| 
 | ||||
| Signed-off-by: Alexey Brodkin <abrodkin@synopsys.com> | ||||
| ---
 | ||||
|  arch/arc/kernel/unaligned.c | 2 +- | ||||
|  1 file changed, 1 insertion(+), 1 deletion(-) | ||||
| 
 | ||||
| --- a/arch/arc/kernel/unaligned.c
 | ||||
| +++ b/arch/arc/kernel/unaligned.c
 | ||||
| @@ -202,7 +202,7 @@ int misaligned_fixup(unsigned long addre
 | ||||
|  	char buf[TASK_COMM_LEN]; | ||||
|   | ||||
|  	/* handle user mode only and only if enabled by sysadmin */ | ||||
| -	if (!user_mode(regs) || !unaligned_enabled)
 | ||||
| +	if (!unaligned_enabled)
 | ||||
|  		return 1; | ||||
|   | ||||
|  	if (no_unaligned_warning) { | ||||
|  | @ -0,0 +1,25 @@ | |||
| From 66770a004afe10df11d3902e16eaa0c2c39436bb Mon Sep 17 00:00:00 2001 | ||||
| From: Pawel Dembicki <paweldembicki@gmail.com> | ||||
| Date: Fri, 24 May 2019 17:56:19 +0200 | ||||
| Subject: [PATCH] powerpc: Enable kernel XZ compression option on PPC_85xx | ||||
| 
 | ||||
| Enable kernel XZ compression option on PPC_85xx. Tested with | ||||
| simpleImage on TP-Link TL-WDR4900 (Freescale P1014 processor). | ||||
| 
 | ||||
| Suggested-by: Christian Lamparter <chunkeey@gmail.com> | ||||
| Signed-off-by: Pawel Dembicki <paweldembicki@gmail.com> | ||||
| ---
 | ||||
|  arch/powerpc/Kconfig | 2 +- | ||||
|  1 file changed, 1 insertion(+), 1 deletion(-) | ||||
| 
 | ||||
| --- a/arch/powerpc/Kconfig
 | ||||
| +++ b/arch/powerpc/Kconfig
 | ||||
| @@ -251,7 +251,7 @@ config PPC
 | ||||
|  	select HAVE_KERNEL_GZIP | ||||
|  	select HAVE_KERNEL_LZMA			if DEFAULT_UIMAGE | ||||
|  	select HAVE_KERNEL_LZO			if DEFAULT_UIMAGE | ||||
| -	select HAVE_KERNEL_XZ			if PPC_BOOK3S || 44x
 | ||||
| +	select HAVE_KERNEL_XZ			if PPC_BOOK3S || 44x || PPC_85xx
 | ||||
|  	select HAVE_KPROBES | ||||
|  	select HAVE_KPROBES_ON_FTRACE | ||||
|  	select HAVE_KRETPROBES | ||||
|  | @ -0,0 +1,74 @@ | |||
| From: Shiji Yang <yangshiji66@outlook.com> | ||||
| Date: Wed, 13 Mar 2024 20:28:37 +0800 | ||||
| Subject: [PATCH] mips: kernel: fix detect_memory_region() function | ||||
| 
 | ||||
| 1. Do not use memcmp() on unallocated memory, as the new introduced | ||||
|    fortify dynamic object size check[1] will report unexpected result. | ||||
| 2. Use a fixed pattern instead of a random function pointer as the | ||||
|    magic value. | ||||
| 3. Flip magic value and double check it. | ||||
| 4. Enable this feature only for 32-bit CPUs. Currently, only ath79 and | ||||
|    ralink CPUs are using it. | ||||
| 
 | ||||
| [1] 439a1bcac648 ("fortify: Use __builtin_dynamic_object_size() when available") | ||||
| Signed-off-by: Shiji Yang <yangshiji66@outlook.com> | ||||
| ---
 | ||||
|  arch/mips/include/asm/bootinfo.h |  2 ++ | ||||
|  arch/mips/kernel/setup.c         | 17 ++++++++++++----- | ||||
|  2 files changed, 14 insertions(+), 5 deletions(-) | ||||
| 
 | ||||
| --- a/arch/mips/include/asm/bootinfo.h
 | ||||
| +++ b/arch/mips/include/asm/bootinfo.h
 | ||||
| @@ -93,7 +93,9 @@ const char *get_system_type(void);
 | ||||
|   | ||||
|  extern unsigned long mips_machtype; | ||||
|   | ||||
| +#ifndef CONFIG_64BIT
 | ||||
|  extern void detect_memory_region(phys_addr_t start, phys_addr_t sz_min,  phys_addr_t sz_max); | ||||
| +#endif
 | ||||
|   | ||||
|  extern void prom_init(void); | ||||
|  extern void prom_free_prom_memory(void); | ||||
| --- a/arch/mips/kernel/setup.c
 | ||||
| +++ b/arch/mips/kernel/setup.c
 | ||||
| @@ -90,21 +90,27 @@ static struct resource bss_resource = {
 | ||||
|  unsigned long __kaslr_offset __ro_after_init; | ||||
|  EXPORT_SYMBOL(__kaslr_offset); | ||||
|   | ||||
| -static void *detect_magic __initdata = detect_memory_region;
 | ||||
| -
 | ||||
|  #ifdef CONFIG_MIPS_AUTO_PFN_OFFSET | ||||
|  unsigned long ARCH_PFN_OFFSET; | ||||
|  EXPORT_SYMBOL(ARCH_PFN_OFFSET); | ||||
|  #endif | ||||
|   | ||||
| +#ifndef CONFIG_64BIT
 | ||||
| +static u32 detect_magic __initdata;
 | ||||
| +#define MIPS_MEM_TEST_PATTERN		0xaa5555aa
 | ||||
| +
 | ||||
|  void __init detect_memory_region(phys_addr_t start, phys_addr_t sz_min, phys_addr_t sz_max) | ||||
|  { | ||||
| -	void *dm = &detect_magic;
 | ||||
| +	void *dm = (void *)KSEG1ADDR(&detect_magic);
 | ||||
|  	phys_addr_t size; | ||||
|   | ||||
|  	for (size = sz_min; size < sz_max; size <<= 1) { | ||||
| -		if (!memcmp(dm, dm + size, sizeof(detect_magic)))
 | ||||
| -			break;
 | ||||
| +		__raw_writel(MIPS_MEM_TEST_PATTERN, dm);
 | ||||
| +		if (__raw_readl(dm) == __raw_readl(dm + size)) {
 | ||||
| +			__raw_writel(~MIPS_MEM_TEST_PATTERN, dm);
 | ||||
| +			if (__raw_readl(dm) == __raw_readl(dm + size))
 | ||||
| +				break;
 | ||||
| +		}
 | ||||
|  	} | ||||
|   | ||||
|  	pr_debug("Memory: %lluMB of RAM detected at 0x%llx (min: %lluMB, max: %lluMB)\n", | ||||
| @@ -115,6 +121,7 @@ void __init detect_memory_region(phys_ad
 | ||||
|   | ||||
|  	memblock_add(start, size); | ||||
|  } | ||||
| +#endif /* CONFIG_64BIT */
 | ||||
|   | ||||
|  /* | ||||
|   * Manage initrd | ||||
|  | @ -0,0 +1,26 @@ | |||
| From ecb8f9a7d69698ce20fc6f4d107718d56fa861df Mon Sep 17 00:00:00 2001 | ||||
| From: Tony Ambardar <Tony.Ambardar@gmail.com> | ||||
| Date: Sat, 9 Mar 2024 16:44:53 -0800 | ||||
| Subject: [PATCH] selftests/bpf: Improve portability of unprivileged tests | ||||
| 
 | ||||
| The addition of general support for unprivileged tests in test_loader.c | ||||
| breaks building test_verifier on non-glibc (e.g. musl) systems, due to the | ||||
| inclusion of glibc extension '<error.h>' in 'unpriv_helpers.c'. However, | ||||
| the header is actually not needed, so remove it to restore building. | ||||
| 
 | ||||
| Fixes: 1d56ade032a4 ("selftests/bpf: Unprivileged tests for test_loader.c") | ||||
| Signed-off-by: Tony Ambardar <Tony.Ambardar@gmail.com> | ||||
| ---
 | ||||
|  tools/testing/selftests/bpf/unpriv_helpers.c | 1 - | ||||
|  1 file changed, 1 deletion(-) | ||||
| 
 | ||||
| --- a/tools/testing/selftests/bpf/unpriv_helpers.c
 | ||||
| +++ b/tools/testing/selftests/bpf/unpriv_helpers.c
 | ||||
| @@ -2,7 +2,6 @@
 | ||||
|   | ||||
|  #include <stdbool.h> | ||||
|  #include <stdlib.h> | ||||
| -#include <error.h>
 | ||||
|  #include <stdio.h> | ||||
|   | ||||
|  #include "unpriv_helpers.h" | ||||
|  | @ -0,0 +1,328 @@ | |||
| From 39717277d5c87bdb183cf2f258957b44ba99b4df Mon Sep 17 00:00:00 2001 | ||||
| From: OpenWrt community <openwrt-devel@lists.openwrt.org> | ||||
| Date: Wed, 13 Jul 2022 11:47:35 +0200 | ||||
| Subject: [PATCH] mtd: mtdsplit support | ||||
| 
 | ||||
| ---
 | ||||
|  drivers/mtd/Kconfig            |  19 ++++ | ||||
|  drivers/mtd/Makefile           |   2 + | ||||
|  drivers/mtd/mtdpart.c          | 169 ++++++++++++++++++++++++++++----- | ||||
|  include/linux/mtd/mtd.h        |  25 +++++ | ||||
|  include/linux/mtd/partitions.h |   7 ++ | ||||
|  5 files changed, 197 insertions(+), 25 deletions(-) | ||||
| 
 | ||||
| --- a/drivers/mtd/Kconfig
 | ||||
| +++ b/drivers/mtd/Kconfig
 | ||||
| @@ -12,6 +12,25 @@ menuconfig MTD
 | ||||
|   | ||||
|  if MTD | ||||
|   | ||||
| +menu "OpenWrt specific MTD options"
 | ||||
| +
 | ||||
| +config MTD_ROOTFS_ROOT_DEV
 | ||||
| +	bool "Automatically set 'rootfs' partition to be root filesystem"
 | ||||
| +	default y
 | ||||
| +
 | ||||
| +config MTD_SPLIT_FIRMWARE
 | ||||
| +	bool "Automatically split firmware partition for kernel+rootfs"
 | ||||
| +	default y
 | ||||
| +
 | ||||
| +config MTD_SPLIT_FIRMWARE_NAME
 | ||||
| +	string "Firmware partition name"
 | ||||
| +	depends on MTD_SPLIT_FIRMWARE
 | ||||
| +	default "firmware"
 | ||||
| +
 | ||||
| +source "drivers/mtd/mtdsplit/Kconfig"
 | ||||
| +
 | ||||
| +endmenu
 | ||||
| +
 | ||||
|  config MTD_TESTS | ||||
|  	tristate "MTD tests support (DANGEROUS)" | ||||
|  	depends on m | ||||
| --- a/drivers/mtd/Makefile
 | ||||
| +++ b/drivers/mtd/Makefile
 | ||||
| @@ -9,6 +9,8 @@ mtd-y				:= mtdcore.o mtdsuper.o mtdconc
 | ||||
|   | ||||
|  obj-y				+= parsers/ | ||||
|   | ||||
| +obj-$(CONFIG_MTD_SPLIT)		+= mtdsplit/
 | ||||
| +
 | ||||
|  # 'Users' - code which presents functionality to userspace. | ||||
|  obj-$(CONFIG_MTD_BLKDEVS)	+= mtd_blkdevs.o | ||||
|  obj-$(CONFIG_MTD_BLOCK)		+= mtdblock.o | ||||
| --- a/drivers/mtd/mtdpart.c
 | ||||
| +++ b/drivers/mtd/mtdpart.c
 | ||||
| @@ -15,11 +15,13 @@
 | ||||
|  #include <linux/kmod.h> | ||||
|  #include <linux/mtd/mtd.h> | ||||
|  #include <linux/mtd/partitions.h> | ||||
| +#include <linux/magic.h>
 | ||||
|  #include <linux/err.h> | ||||
|  #include <linux/of.h> | ||||
|  #include <linux/of_platform.h> | ||||
|   | ||||
|  #include "mtdcore.h" | ||||
| +#include "mtdsplit/mtdsplit.h"
 | ||||
|   | ||||
|  /* | ||||
|   * MTD methods which simply translate the effective address and pass through | ||||
| @@ -242,6 +244,147 @@ static int mtd_add_partition_attrs(struc
 | ||||
|  	return ret; | ||||
|  } | ||||
|   | ||||
| +static DEFINE_SPINLOCK(part_parser_lock);
 | ||||
| +static LIST_HEAD(part_parsers);
 | ||||
| +
 | ||||
| +static struct mtd_part_parser *mtd_part_parser_get(const char *name)
 | ||||
| +{
 | ||||
| +	struct mtd_part_parser *p, *ret = NULL;
 | ||||
| +
 | ||||
| +	spin_lock(&part_parser_lock);
 | ||||
| +
 | ||||
| +	list_for_each_entry(p, &part_parsers, list)
 | ||||
| +		if (!strcmp(p->name, name) && try_module_get(p->owner)) {
 | ||||
| +			ret = p;
 | ||||
| +			break;
 | ||||
| +		}
 | ||||
| +
 | ||||
| +	spin_unlock(&part_parser_lock);
 | ||||
| +
 | ||||
| +	return ret;
 | ||||
| +}
 | ||||
| +
 | ||||
| +static inline void mtd_part_parser_put(const struct mtd_part_parser *p)
 | ||||
| +{
 | ||||
| +	module_put(p->owner);
 | ||||
| +}
 | ||||
| +
 | ||||
| +static struct mtd_part_parser *
 | ||||
| +get_partition_parser_by_type(enum mtd_parser_type type,
 | ||||
| +			     struct mtd_part_parser *start)
 | ||||
| +{
 | ||||
| +	struct mtd_part_parser *p, *ret = NULL;
 | ||||
| +
 | ||||
| +	spin_lock(&part_parser_lock);
 | ||||
| +
 | ||||
| +	p = list_prepare_entry(start, &part_parsers, list);
 | ||||
| +	if (start)
 | ||||
| +		mtd_part_parser_put(start);
 | ||||
| +
 | ||||
| +	list_for_each_entry_continue(p, &part_parsers, list) {
 | ||||
| +		if (p->type == type && try_module_get(p->owner)) {
 | ||||
| +			ret = p;
 | ||||
| +			break;
 | ||||
| +		}
 | ||||
| +	}
 | ||||
| +
 | ||||
| +	spin_unlock(&part_parser_lock);
 | ||||
| +
 | ||||
| +	return ret;
 | ||||
| +}
 | ||||
| +
 | ||||
| +static int parse_mtd_partitions_by_type(struct mtd_info *master,
 | ||||
| +					enum mtd_parser_type type,
 | ||||
| +					const struct mtd_partition **pparts,
 | ||||
| +					struct mtd_part_parser_data *data)
 | ||||
| +{
 | ||||
| +	struct mtd_part_parser *prev = NULL;
 | ||||
| +	int ret = 0;
 | ||||
| +
 | ||||
| +	while (1) {
 | ||||
| +		struct mtd_part_parser *parser;
 | ||||
| +
 | ||||
| +		parser = get_partition_parser_by_type(type, prev);
 | ||||
| +		if (!parser)
 | ||||
| +			break;
 | ||||
| +
 | ||||
| +		ret = (*parser->parse_fn)(master, pparts, data);
 | ||||
| +
 | ||||
| +		if (ret > 0) {
 | ||||
| +			mtd_part_parser_put(parser);
 | ||||
| +			printk(KERN_NOTICE
 | ||||
| +			       "%d %s partitions found on MTD device %s\n",
 | ||||
| +			       ret, parser->name, master->name);
 | ||||
| +			break;
 | ||||
| +		}
 | ||||
| +
 | ||||
| +		prev = parser;
 | ||||
| +	}
 | ||||
| +
 | ||||
| +	return ret;
 | ||||
| +}
 | ||||
| +
 | ||||
| +static int
 | ||||
| +run_parsers_by_type(struct mtd_info *child, enum mtd_parser_type type)
 | ||||
| +{
 | ||||
| +	struct mtd_partition *parts;
 | ||||
| +	int nr_parts;
 | ||||
| +	int i;
 | ||||
| +
 | ||||
| +	nr_parts = parse_mtd_partitions_by_type(child, type, (const struct mtd_partition **)&parts,
 | ||||
| +						NULL);
 | ||||
| +	if (nr_parts <= 0)
 | ||||
| +		return nr_parts;
 | ||||
| +
 | ||||
| +	if (WARN_ON(!parts))
 | ||||
| +		return 0;
 | ||||
| +
 | ||||
| +	for (i = 0; i < nr_parts; i++) {
 | ||||
| +		/* adjust partition offsets */
 | ||||
| +		parts[i].offset += child->part.offset;
 | ||||
| +
 | ||||
| +		mtd_add_partition(child->parent,
 | ||||
| +				  parts[i].name,
 | ||||
| +				  parts[i].offset,
 | ||||
| +				  parts[i].size);
 | ||||
| +	}
 | ||||
| +
 | ||||
| +	kfree(parts);
 | ||||
| +
 | ||||
| +	return nr_parts;
 | ||||
| +}
 | ||||
| +
 | ||||
| +#ifdef CONFIG_MTD_SPLIT_FIRMWARE_NAME
 | ||||
| +#define SPLIT_FIRMWARE_NAME	CONFIG_MTD_SPLIT_FIRMWARE_NAME
 | ||||
| +#else
 | ||||
| +#define SPLIT_FIRMWARE_NAME	"unused"
 | ||||
| +#endif
 | ||||
| +
 | ||||
| +static void split_firmware(struct mtd_info *master, struct mtd_info *part)
 | ||||
| +{
 | ||||
| +	run_parsers_by_type(part, MTD_PARSER_TYPE_FIRMWARE);
 | ||||
| +}
 | ||||
| +
 | ||||
| +static void mtd_partition_split(struct mtd_info *master, struct mtd_info *part)
 | ||||
| +{
 | ||||
| +	static int rootfs_found = 0;
 | ||||
| +
 | ||||
| +	if (rootfs_found)
 | ||||
| +		return;
 | ||||
| +
 | ||||
| +	if (of_find_property(mtd_get_of_node(part), "linux,rootfs", NULL) ||
 | ||||
| +	    !strcmp(part->name, "rootfs")) {
 | ||||
| +		run_parsers_by_type(part, MTD_PARSER_TYPE_ROOTFS);
 | ||||
| +
 | ||||
| +		rootfs_found = 1;
 | ||||
| +	}
 | ||||
| +
 | ||||
| +	if (IS_ENABLED(CONFIG_MTD_SPLIT_FIRMWARE) &&
 | ||||
| +	    !strcmp(part->name, SPLIT_FIRMWARE_NAME) &&
 | ||||
| +	    !of_find_property(mtd_get_of_node(part), "compatible", NULL))
 | ||||
| +		split_firmware(master, part);
 | ||||
| +}
 | ||||
| +
 | ||||
|  int mtd_add_partition(struct mtd_info *parent, const char *name, | ||||
|  		      long long offset, long long length) | ||||
|  { | ||||
| @@ -280,6 +423,7 @@ int mtd_add_partition(struct mtd_info *p
 | ||||
|  	if (ret) | ||||
|  		goto err_remove_part; | ||||
|   | ||||
| +	mtd_partition_split(parent, child);
 | ||||
|  	mtd_add_partition_attrs(child); | ||||
|   | ||||
|  	return 0; | ||||
| @@ -423,6 +567,7 @@ int add_mtd_partitions(struct mtd_info *
 | ||||
|  			goto err_del_partitions; | ||||
|  		} | ||||
|   | ||||
| +		mtd_partition_split(master, child);
 | ||||
|  		mtd_add_partition_attrs(child); | ||||
|   | ||||
|  		/* Look for subpartitions */ | ||||
| @@ -439,31 +584,6 @@ err_del_partitions:
 | ||||
|  	return ret; | ||||
|  } | ||||
|   | ||||
| -static DEFINE_SPINLOCK(part_parser_lock);
 | ||||
| -static LIST_HEAD(part_parsers);
 | ||||
| -
 | ||||
| -static struct mtd_part_parser *mtd_part_parser_get(const char *name)
 | ||||
| -{
 | ||||
| -	struct mtd_part_parser *p, *ret = NULL;
 | ||||
| -
 | ||||
| -	spin_lock(&part_parser_lock);
 | ||||
| -
 | ||||
| -	list_for_each_entry(p, &part_parsers, list)
 | ||||
| -		if (!strcmp(p->name, name) && try_module_get(p->owner)) {
 | ||||
| -			ret = p;
 | ||||
| -			break;
 | ||||
| -		}
 | ||||
| -
 | ||||
| -	spin_unlock(&part_parser_lock);
 | ||||
| -
 | ||||
| -	return ret;
 | ||||
| -}
 | ||||
| -
 | ||||
| -static inline void mtd_part_parser_put(const struct mtd_part_parser *p)
 | ||||
| -{
 | ||||
| -	module_put(p->owner);
 | ||||
| -}
 | ||||
| -
 | ||||
|  /* | ||||
|   * Many partition parsers just expected the core to kfree() all their data in | ||||
|   * one chunk. Do that by default. | ||||
| --- a/include/linux/mtd/mtd.h
 | ||||
| +++ b/include/linux/mtd/mtd.h
 | ||||
| @@ -615,6 +615,24 @@ static inline void mtd_align_erase_req(s
 | ||||
|  		req->len += mtd->erasesize - mod; | ||||
|  } | ||||
|   | ||||
| +static inline uint64_t mtd_roundup_to_eb(uint64_t sz, struct mtd_info *mtd)
 | ||||
| +{
 | ||||
| +	if (mtd_mod_by_eb(sz, mtd) == 0)
 | ||||
| +		return sz;
 | ||||
| +
 | ||||
| +	/* Round up to next erase block */
 | ||||
| +	return (mtd_div_by_eb(sz, mtd) + 1) * mtd->erasesize;
 | ||||
| +}
 | ||||
| +
 | ||||
| +static inline uint64_t mtd_rounddown_to_eb(uint64_t sz, struct mtd_info *mtd)
 | ||||
| +{
 | ||||
| +	if (mtd_mod_by_eb(sz, mtd) == 0)
 | ||||
| +		return sz;
 | ||||
| +
 | ||||
| +	/* Round down to the start of the current erase block */
 | ||||
| +	return (mtd_div_by_eb(sz, mtd)) * mtd->erasesize;
 | ||||
| +}
 | ||||
| +
 | ||||
|  static inline uint32_t mtd_div_by_ws(uint64_t sz, struct mtd_info *mtd) | ||||
|  { | ||||
|  	if (mtd->writesize_shift) | ||||
| @@ -688,6 +706,13 @@ extern struct mtd_info *of_get_mtd_devic
 | ||||
|  extern struct mtd_info *get_mtd_device_nm(const char *name); | ||||
|  extern void put_mtd_device(struct mtd_info *mtd); | ||||
|   | ||||
| +static inline uint64_t mtdpart_get_offset(const struct mtd_info *mtd)
 | ||||
| +{
 | ||||
| +	if (!mtd_is_partition(mtd))
 | ||||
| +		return 0;
 | ||||
| +
 | ||||
| +	return mtd->part.offset;
 | ||||
| +}
 | ||||
|   | ||||
|  struct mtd_notifier { | ||||
|  	void (*add)(struct mtd_info *mtd); | ||||
| --- a/include/linux/mtd/partitions.h
 | ||||
| +++ b/include/linux/mtd/partitions.h
 | ||||
| @@ -75,6 +75,12 @@ struct mtd_part_parser_data {
 | ||||
|   * Functions dealing with the various ways of partitioning the space | ||||
|   */ | ||||
|   | ||||
| +enum mtd_parser_type {
 | ||||
| +	MTD_PARSER_TYPE_DEVICE = 0,
 | ||||
| +	MTD_PARSER_TYPE_ROOTFS,
 | ||||
| +	MTD_PARSER_TYPE_FIRMWARE,
 | ||||
| +};
 | ||||
| +
 | ||||
|  struct mtd_part_parser { | ||||
|  	struct list_head list; | ||||
|  	struct module *owner; | ||||
| @@ -83,6 +89,7 @@ struct mtd_part_parser {
 | ||||
|  	int (*parse_fn)(struct mtd_info *, const struct mtd_partition **, | ||||
|  			struct mtd_part_parser_data *); | ||||
|  	void (*cleanup)(const struct mtd_partition *pparts, int nr_parts); | ||||
| +	enum mtd_parser_type type;
 | ||||
|  }; | ||||
|   | ||||
|  /* Container for passing around a set of parsed partitions */ | ||||
|  | @ -0,0 +1,48 @@ | |||
| From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl> | ||||
| Date: Tue, 31 Oct 2023 15:51:01 +0100 | ||||
| Subject: [PATCH] mtd: don't register NVMEM devices for partitions with custom | ||||
|  drivers | ||||
| MIME-Version: 1.0 | ||||
| Content-Type: text/plain; charset=UTF-8 | ||||
| Content-Transfer-Encoding: 8bit | ||||
| 
 | ||||
| This fixes issue exposed by upstream commit f4cf4e5db331 ("Revert | ||||
| "nvmem: add new config option""). | ||||
| 
 | ||||
| Signed-off-by: Rafał Miłecki <rafal@milecki.pl> | ||||
| ---
 | ||||
|  drivers/mtd/mtdcore.c | 23 +++++++++++++++++++++++ | ||||
|  1 file changed, 23 insertions(+) | ||||
| 
 | ||||
| --- a/drivers/mtd/mtdcore.c
 | ||||
| +++ b/drivers/mtd/mtdcore.c
 | ||||
| @@ -548,6 +548,29 @@ static int mtd_nvmem_add(struct mtd_info
 | ||||
|  	struct device_node *node = mtd_get_of_node(mtd); | ||||
|  	struct nvmem_config config = {}; | ||||
|   | ||||
| +	/*
 | ||||
| +	 * Do NOT register NVMEM device for any partition that is meant to be
 | ||||
| +	 * handled by a U-Boot env driver. That would result in associating two
 | ||||
| +	 * different NVMEM devices with the same OF node.
 | ||||
| +	 *
 | ||||
| +	 * An example of unwanted behaviour of above (forwardtrace):
 | ||||
| +	 * of_get_mac_addr_nvmem()
 | ||||
| +	 * of_nvmem_cell_get()
 | ||||
| +	 * __nvmem_device_get()
 | ||||
| +	 *
 | ||||
| +	 * We can't have __nvmem_device_get() return "mtdX" NVMEM device instead
 | ||||
| +	 * of U-Boot env NVMEM device. That would result in failing to find
 | ||||
| +	 * NVMEM cell.
 | ||||
| +	 *
 | ||||
| +	 * This issue seems to affect U-Boot env case only and will go away with
 | ||||
| +	 * switch to NVMEM layouts.
 | ||||
| +	 */
 | ||||
| +	if (of_device_is_compatible(node, "u-boot,env") ||
 | ||||
| +	    of_device_is_compatible(node, "u-boot,env-redundant-bool") ||
 | ||||
| +	    of_device_is_compatible(node, "u-boot,env-redundant-count") ||
 | ||||
| +	    of_device_is_compatible(node, "brcm,env"))
 | ||||
| +		return 0;
 | ||||
| +
 | ||||
|  	config.id = NVMEM_DEVID_NONE; | ||||
|  	config.dev = &mtd->dev; | ||||
|  	config.name = dev_name(&mtd->dev); | ||||
|  | @ -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
 | ||||
| @@ -198,6 +198,15 @@ static ssize_t mtd_erasesize_show(struct
 | ||||
|  } | ||||
|  MTD_DEVICE_ATTR_RO(erasesize); | ||||
|   | ||||
| +static ssize_t mtd_erasesize_minor_show(struct device *dev,
 | ||||
| +		struct device_attribute *attr, char *buf)
 | ||||
| +{
 | ||||
| +	struct mtd_info *mtd = dev_get_drvdata(dev);
 | ||||
| +
 | ||||
| +	return sysfs_emit(buf, "%lu\n", (unsigned long)mtd->erasesize_minor);
 | ||||
| +}
 | ||||
| +MTD_DEVICE_ATTR_RO(erasesize_minor);
 | ||||
| +
 | ||||
|  static ssize_t mtd_writesize_show(struct device *dev, | ||||
|  		struct device_attribute *attr, char *buf) | ||||
|  { | ||||
| @@ -343,6 +352,7 @@ static struct attribute *mtd_attrs[] = {
 | ||||
|  	&dev_attr_flags.attr, | ||||
|  	&dev_attr_size.attr, | ||||
|  	&dev_attr_erasesize.attr, | ||||
| +	&dev_attr_erasesize_minor.attr,
 | ||||
|  	&dev_attr_writesize.attr, | ||||
|  	&dev_attr_subpagesize.attr, | ||||
|  	&dev_attr_oobsize.attr, | ||||
| --- a/drivers/mtd/mtdpart.c
 | ||||
| +++ b/drivers/mtd/mtdpart.c
 | ||||
| @@ -47,6 +47,7 @@ static struct mtd_info *allocate_partiti
 | ||||
|  	struct mtd_info *master = mtd_get_master(parent); | ||||
|  	int wr_alignment = (parent->flags & MTD_NO_ERASE) ? | ||||
|  			   master->writesize : master->erasesize; | ||||
| +	int wr_alignment_minor = 0;
 | ||||
|  	u64 parent_size = mtd_is_partition(parent) ? | ||||
|  			  parent->part.size : parent->size; | ||||
|  	struct mtd_info *child; | ||||
| @@ -171,6 +172,7 @@ static struct mtd_info *allocate_partiti
 | ||||
|  	} else { | ||||
|  		/* Single erase size */ | ||||
|  		child->erasesize = master->erasesize; | ||||
| +		child->erasesize_minor = master->erasesize_minor;
 | ||||
|  	} | ||||
|   | ||||
|  	/* | ||||
| @@ -178,26 +180,39 @@ static struct mtd_info *allocate_partiti
 | ||||
|  	 * exposes several regions with different erasesize. Adjust | ||||
|  	 * wr_alignment accordingly. | ||||
|  	 */ | ||||
| -	if (!(child->flags & MTD_NO_ERASE))
 | ||||
| +	if (!(child->flags & MTD_NO_ERASE)) {
 | ||||
|  		wr_alignment = child->erasesize; | ||||
| +		wr_alignment_minor = child->erasesize_minor;
 | ||||
| +	}
 | ||||
|   | ||||
|  	tmp = mtd_get_master_ofs(child, 0); | ||||
|  	remainder = do_div(tmp, wr_alignment); | ||||
|  	if ((child->flags & MTD_WRITEABLE) && remainder) { | ||||
| -		/* Doesn't start on a boundary of major erase size */
 | ||||
| -		/* FIXME: Let it be writable if it is on a boundary of
 | ||||
| -		 * _minor_ erase size though */
 | ||||
| -		child->flags &= ~MTD_WRITEABLE;
 | ||||
| -		printk(KERN_WARNING"mtd: partition \"%s\" doesn't start on an erase/write block boundary -- force read-only\n",
 | ||||
| -			part->name);
 | ||||
| +		if (wr_alignment_minor) {
 | ||||
| +			/* rely on minor being a factor of major erasesize */
 | ||||
| +			tmp = remainder;
 | ||||
| +			remainder = do_div(tmp, wr_alignment_minor);
 | ||||
| +		}
 | ||||
| +		if (remainder) {
 | ||||
| +			child->flags &= ~MTD_WRITEABLE;
 | ||||
| +			printk(KERN_WARNING"mtd: partition \"%s\" doesn't start on an erase/write block boundary -- force read-only\n",
 | ||||
| +				part->name);
 | ||||
| +		}
 | ||||
|  	} | ||||
|   | ||||
|  	tmp = mtd_get_master_ofs(child, 0) + child->part.size; | ||||
|  	remainder = do_div(tmp, wr_alignment); | ||||
|  	if ((child->flags & MTD_WRITEABLE) && remainder) { | ||||
| -		child->flags &= ~MTD_WRITEABLE;
 | ||||
| -		printk(KERN_WARNING"mtd: partition \"%s\" doesn't end on an erase/write block -- force read-only\n",
 | ||||
| -			part->name);
 | ||||
| +		if (wr_alignment_minor) {
 | ||||
| +			tmp = remainder;
 | ||||
| +			remainder = do_div(tmp, wr_alignment_minor);
 | ||||
| +		}
 | ||||
| +
 | ||||
| +		if (remainder) {
 | ||||
| +			child->flags &= ~MTD_WRITEABLE;
 | ||||
| +			printk(KERN_WARNING"mtd: partition \"%s\" doesn't end on an erase/write block -- force read-only\n",
 | ||||
| +				part->name);
 | ||||
| +		}
 | ||||
|  	} | ||||
|   | ||||
|  	child->size = child->part.size; | ||||
| --- a/drivers/mtd/spi-nor/Kconfig
 | ||||
| +++ b/drivers/mtd/spi-nor/Kconfig
 | ||||
| @@ -10,6 +10,16 @@ menuconfig MTD_SPI_NOR
 | ||||
|   | ||||
|  if MTD_SPI_NOR | ||||
|   | ||||
| +config MTD_SPI_NOR_USE_VARIABLE_ERASE
 | ||||
| +	bool "Disable uniform_erase to allow use of all hardware supported erasesizes"
 | ||||
| +	depends on !MTD_SPI_NOR_USE_4K_SECTORS
 | ||||
| +	default n
 | ||||
| +	help
 | ||||
| +	  Allow mixed use of all hardware supported erasesizes,
 | ||||
| +	  by forcing spi_nor to use the multiple eraseregions code path.
 | ||||
| +	  For example: A 68K erase will use one 64K erase, and one 4K erase
 | ||||
| +	  on supporting hardware.
 | ||||
| +
 | ||||
|  config MTD_SPI_NOR_USE_4K_SECTORS | ||||
|  	bool "Use small 4096 B erase sectors" | ||||
|  	default y | ||||
| --- a/drivers/mtd/spi-nor/core.c
 | ||||
| +++ b/drivers/mtd/spi-nor/core.c
 | ||||
| @@ -1150,6 +1150,8 @@ static u8 spi_nor_convert_3to4_erase(u8
 | ||||
|   | ||||
|  static bool spi_nor_has_uniform_erase(const struct spi_nor *nor) | ||||
|  { | ||||
| +	if (IS_ENABLED(CONFIG_MTD_SPI_NOR_USE_VARIABLE_ERASE))
 | ||||
| +		return false;
 | ||||
|  	return !!nor->params->erase_map.uniform_erase_type; | ||||
|  } | ||||
|   | ||||
| @@ -2582,6 +2584,7 @@ static int spi_nor_select_erase(struct s
 | ||||
|  { | ||||
|  	struct spi_nor_erase_map *map = &nor->params->erase_map; | ||||
|  	const struct spi_nor_erase_type *erase = NULL; | ||||
| +	const struct spi_nor_erase_type *erase_minor = NULL;
 | ||||
|  	struct mtd_info *mtd = &nor->mtd; | ||||
|  	u32 wanted_size = nor->info->sector_size; | ||||
|  	int i; | ||||
| @@ -2614,8 +2617,9 @@ static int spi_nor_select_erase(struct s
 | ||||
|  	 */ | ||||
|  	for (i = SNOR_ERASE_TYPE_MAX - 1; i >= 0; i--) { | ||||
|  		if (map->erase_type[i].size) { | ||||
| -			erase = &map->erase_type[i];
 | ||||
| -			break;
 | ||||
| +			if (!erase)
 | ||||
| +				erase = &map->erase_type[i];
 | ||||
| +			erase_minor = &map->erase_type[i];
 | ||||
|  		} | ||||
|  	} | ||||
|   | ||||
| @@ -2623,6 +2627,9 @@ static int spi_nor_select_erase(struct s
 | ||||
|  		return -EINVAL; | ||||
|   | ||||
|  	mtd->erasesize = erase->size; | ||||
| +	if (IS_ENABLED(CONFIG_MTD_SPI_NOR_USE_VARIABLE_ERASE) &&
 | ||||
| +			erase_minor && erase_minor->size < erase->size)
 | ||||
| +		mtd->erasesize_minor = erase_minor->size;
 | ||||
|  	return 0; | ||||
|  } | ||||
|   | ||||
| --- a/include/linux/mtd/mtd.h
 | ||||
| +++ b/include/linux/mtd/mtd.h
 | ||||
| @@ -245,6 +245,8 @@ struct mtd_info {
 | ||||
|  	 * information below if they desire | ||||
|  	 */ | ||||
|  	uint32_t erasesize; | ||||
| +	/* "Minor" (smallest) erase size supported by the whole device */
 | ||||
| +	uint32_t erasesize_minor;
 | ||||
|  	/* Minimal writable flash unit size. In case of NOR flash it is 1 (even | ||||
|  	 * though individual bits can be cleared), in case of NAND flash it is | ||||
|  	 * one NAND page (or half, or one-fourths of it), in case of ECC-ed NOR | ||||
|  | @ -0,0 +1,41 @@ | |||
| From: Felix Fietkau <nbd@nbd.name> | ||||
| Subject: add patch for including unpartitioned space in the rootfs partition for redboot devices (if applicable) | ||||
| 
 | ||||
| [john@phrozen.org: used by ixp and others] | ||||
| 
 | ||||
| lede-commit: 394918851f84e4d00fa16eb900e7700e95091f00 | ||||
| Signed-off-by: Felix Fietkau <nbd@nbd.name> | ||||
| ---
 | ||||
|  drivers/mtd/redboot.c | 19 +++++++++++++------ | ||||
|  1 file changed, 13 insertions(+), 6 deletions(-) | ||||
| 
 | ||||
| --- a/drivers/mtd/parsers/redboot.c
 | ||||
| +++ b/drivers/mtd/parsers/redboot.c
 | ||||
| @@ -278,14 +278,21 @@ nogood:
 | ||||
|  #endif | ||||
|  		names += strlen(names) + 1; | ||||
|   | ||||
| -#ifdef CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED
 | ||||
|  		if (fl->next && fl->img->flash_base + fl->img->size + master->erasesize <= fl->next->img->flash_base) { | ||||
| -			i++;
 | ||||
| -			parts[i].offset = parts[i - 1].size + parts[i - 1].offset;
 | ||||
| -			parts[i].size = fl->next->img->flash_base - parts[i].offset;
 | ||||
| -			parts[i].name = nullname;
 | ||||
| -		}
 | ||||
| +			if (!strcmp(parts[i].name, "rootfs")) {
 | ||||
| +				parts[i].size = fl->next->img->flash_base;
 | ||||
| +				parts[i].size &= ~(master->erasesize - 1);
 | ||||
| +				parts[i].size -= parts[i].offset;
 | ||||
| +#ifdef CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED
 | ||||
| +				nrparts--;
 | ||||
| +			} else {
 | ||||
| +				i++;
 | ||||
| +				parts[i].offset = parts[i-1].size + parts[i-1].offset;
 | ||||
| +				parts[i].size = fl->next->img->flash_base - parts[i].offset;
 | ||||
| +				parts[i].name = nullname;
 | ||||
|  #endif | ||||
| +			}
 | ||||
| +		}
 | ||||
|  		tmp_fl = fl; | ||||
|  		fl = fl->next; | ||||
|  		kfree(tmp_fl); | ||||
|  | @ -0,0 +1,229 @@ | |||
| From: Florian Fainelli <f.fainelli@gmail.com> | ||||
| Subject: Add myloader partition table parser | ||||
| 
 | ||||
| [john@phozen.org: shoud be upstreamable] | ||||
| 
 | ||||
| lede-commit: d8bf22859b51faa09d22c056fe221a45d2f7a3b8 | ||||
| Signed-off-by: Florian Fainelli <f.fainelli@gmail.com> | ||||
| [adjust for kernel 5.4, add myloader.c to patch] | ||||
| 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
 | ||||
|   | ||||
|  	  If unsure, say 'N'. | ||||
|   | ||||
| +config MTD_MYLOADER_PARTS
 | ||||
| +	tristate "MyLoader partition parsing"
 | ||||
| +	depends on ADM5120 || ATH79
 | ||||
| +	help
 | ||||
| +	  MyLoader is a bootloader which allows the user to define partitions
 | ||||
| +	  in flash devices, by putting a table in the second erase block
 | ||||
| +	  on the device, similar to a partition table. This table gives the
 | ||||
| +	  offsets and lengths of the user defined partitions.
 | ||||
| +
 | ||||
| +	  If you need code which can detect and parse these tables, and
 | ||||
| +	  register MTD 'partitions' corresponding to each image detected,
 | ||||
| +	  enable this option.
 | ||||
| +
 | ||||
| +	  You will still need the parsing functions to be called by the driver
 | ||||
| +	  for your particular device. It won't happen automatically.
 | ||||
| +
 | ||||
|  config MTD_OF_PARTS | ||||
|  	tristate "OpenFirmware (device tree) partitioning parser" | ||||
|  	default y | ||||
| --- a/drivers/mtd/parsers/Makefile
 | ||||
| +++ b/drivers/mtd/parsers/Makefile
 | ||||
| @@ -4,6 +4,7 @@ obj-$(CONFIG_MTD_BCM47XX_PARTS)		+= bcm4
 | ||||
|  obj-$(CONFIG_MTD_BCM63XX_PARTS)		+= bcm63xxpart.o | ||||
|  obj-$(CONFIG_MTD_BRCM_U_BOOT)		+= brcm_u-boot.o | ||||
|  obj-$(CONFIG_MTD_CMDLINE_PARTS)		+= cmdlinepart.o | ||||
| +obj-$(CONFIG_MTD_MYLOADER_PARTS)		+= myloader.o
 | ||||
|  obj-$(CONFIG_MTD_OF_PARTS)		+= ofpart.o | ||||
|  ofpart-y				+= ofpart_core.o | ||||
|  ofpart-$(CONFIG_MTD_OF_PARTS_BCM4908)	+= ofpart_bcm4908.o | ||||
| --- /dev/null
 | ||||
| +++ b/drivers/mtd/parsers/myloader.c
 | ||||
| @@ -0,0 +1,181 @@
 | ||||
| +/*
 | ||||
| + *  Parse MyLoader-style flash partition tables and produce a Linux partition
 | ||||
| + *  array to match.
 | ||||
| + *
 | ||||
| + *  Copyright (C) 2007-2009 Gabor Juhos <juhosg@openwrt.org>
 | ||||
| + *
 | ||||
| + *  This file was based on drivers/mtd/redboot.c
 | ||||
| + *  Author: Red Hat, Inc. - David Woodhouse <dwmw2@cambridge.redhat.com>
 | ||||
| + *
 | ||||
| + *  This program is free software; you can redistribute it and/or modify it
 | ||||
| + *  under the terms of the GNU General Public License version 2 as published
 | ||||
| + *  by the Free Software Foundation.
 | ||||
| + */
 | ||||
| +
 | ||||
| +#include <linux/kernel.h>
 | ||||
| +#include <linux/module.h>
 | ||||
| +#include <linux/version.h>
 | ||||
| +#include <linux/slab.h>
 | ||||
| +#include <linux/init.h>
 | ||||
| +#include <linux/vmalloc.h>
 | ||||
| +#include <linux/mtd/mtd.h>
 | ||||
| +#include <linux/mtd/partitions.h>
 | ||||
| +#include <linux/byteorder/generic.h>
 | ||||
| +#include <linux/myloader.h>
 | ||||
| +
 | ||||
| +#define BLOCK_LEN_MIN		0x10000
 | ||||
| +#define PART_NAME_LEN		32
 | ||||
| +
 | ||||
| +struct part_data {
 | ||||
| +	struct mylo_partition_table	tab;
 | ||||
| +	char names[MYLO_MAX_PARTITIONS][PART_NAME_LEN];
 | ||||
| +};
 | ||||
| +
 | ||||
| +static int myloader_parse_partitions(struct mtd_info *master,
 | ||||
| +				     const struct mtd_partition **pparts,
 | ||||
| +				     struct mtd_part_parser_data *data)
 | ||||
| +{
 | ||||
| +	struct part_data *buf;
 | ||||
| +	struct mylo_partition_table *tab;
 | ||||
| +	struct mylo_partition *part;
 | ||||
| +	struct mtd_partition *mtd_parts;
 | ||||
| +	struct mtd_partition *mtd_part;
 | ||||
| +	int num_parts;
 | ||||
| +	int ret, i;
 | ||||
| +	size_t retlen;
 | ||||
| +	char *names;
 | ||||
| +	unsigned long offset;
 | ||||
| +	unsigned long blocklen;
 | ||||
| +
 | ||||
| +	buf = vmalloc(sizeof(*buf));
 | ||||
| +	if (!buf) {
 | ||||
| +		return -ENOMEM;
 | ||||
| +		goto out;
 | ||||
| +	}
 | ||||
| +	tab = &buf->tab;
 | ||||
| +
 | ||||
| +	blocklen = master->erasesize;
 | ||||
| +	if (blocklen < BLOCK_LEN_MIN)
 | ||||
| +		blocklen = BLOCK_LEN_MIN;
 | ||||
| +
 | ||||
| +	offset = blocklen;
 | ||||
| +
 | ||||
| +	/* Find the partition table */
 | ||||
| +	for (i = 0; i < 4; i++, offset += blocklen) {
 | ||||
| +		printk(KERN_DEBUG "%s: searching for MyLoader partition table"
 | ||||
| +				" at offset 0x%lx\n", master->name, offset);
 | ||||
| +
 | ||||
| +		ret = mtd_read(master, offset, sizeof(*buf), &retlen,
 | ||||
| +			       (void *)buf);
 | ||||
| +		if (ret)
 | ||||
| +			goto out_free_buf;
 | ||||
| +
 | ||||
| +		if (retlen != sizeof(*buf)) {
 | ||||
| +			ret = -EIO;
 | ||||
| +			goto out_free_buf;
 | ||||
| +		}
 | ||||
| +
 | ||||
| +		/* Check for Partition Table magic number */
 | ||||
| +		if (tab->magic == le32_to_cpu(MYLO_MAGIC_PARTITIONS))
 | ||||
| +			break;
 | ||||
| +
 | ||||
| +	}
 | ||||
| +
 | ||||
| +	if (tab->magic != le32_to_cpu(MYLO_MAGIC_PARTITIONS)) {
 | ||||
| +		printk(KERN_DEBUG "%s: no MyLoader partition table found\n",
 | ||||
| +			master->name);
 | ||||
| +		ret = 0;
 | ||||
| +		goto out_free_buf;
 | ||||
| +	}
 | ||||
| +
 | ||||
| +	/* The MyLoader and the Partition Table is always present */
 | ||||
| +	num_parts = 2;
 | ||||
| +
 | ||||
| +	/* Detect number of used partitions */
 | ||||
| +	for (i = 0; i < MYLO_MAX_PARTITIONS; i++) {
 | ||||
| +		part = &tab->partitions[i];
 | ||||
| +
 | ||||
| +		if (le16_to_cpu(part->type) == PARTITION_TYPE_FREE)
 | ||||
| +			continue;
 | ||||
| +
 | ||||
| +		num_parts++;
 | ||||
| +	}
 | ||||
| +
 | ||||
| +	mtd_parts = kzalloc((num_parts * sizeof(*mtd_part) +
 | ||||
| +				num_parts * PART_NAME_LEN), GFP_KERNEL);
 | ||||
| +
 | ||||
| +	if (!mtd_parts) {
 | ||||
| +		ret = -ENOMEM;
 | ||||
| +		goto out_free_buf;
 | ||||
| +	}
 | ||||
| +
 | ||||
| +	mtd_part = mtd_parts;
 | ||||
| +	names = (char *)&mtd_parts[num_parts];
 | ||||
| +
 | ||||
| +	strncpy(names, "myloader", PART_NAME_LEN);
 | ||||
| +	mtd_part->name = names;
 | ||||
| +	mtd_part->offset = 0;
 | ||||
| +	mtd_part->size = offset;
 | ||||
| +	mtd_part->mask_flags = MTD_WRITEABLE;
 | ||||
| +	mtd_part++;
 | ||||
| +	names += PART_NAME_LEN;
 | ||||
| +
 | ||||
| +	strncpy(names, "partition_table", PART_NAME_LEN);
 | ||||
| +	mtd_part->name = names;
 | ||||
| +	mtd_part->offset = offset;
 | ||||
| +	mtd_part->size = blocklen;
 | ||||
| +	mtd_part->mask_flags = MTD_WRITEABLE;
 | ||||
| +	mtd_part++;
 | ||||
| +	names += PART_NAME_LEN;
 | ||||
| +
 | ||||
| +	for (i = 0; i < MYLO_MAX_PARTITIONS; i++) {
 | ||||
| +		part = &tab->partitions[i];
 | ||||
| +
 | ||||
| +		if (le16_to_cpu(part->type) == PARTITION_TYPE_FREE)
 | ||||
| +			continue;
 | ||||
| +
 | ||||
| +		if ((buf->names[i][0]) && (buf->names[i][0] != '\xff'))
 | ||||
| +			strncpy(names, buf->names[i], PART_NAME_LEN);
 | ||||
| +		else
 | ||||
| +			snprintf(names, PART_NAME_LEN, "partition%d", i);
 | ||||
| +
 | ||||
| +		mtd_part->offset = le32_to_cpu(part->addr);
 | ||||
| +		mtd_part->size = le32_to_cpu(part->size);
 | ||||
| +		mtd_part->name = names;
 | ||||
| +		mtd_part++;
 | ||||
| +		names += PART_NAME_LEN;
 | ||||
| +	}
 | ||||
| +
 | ||||
| +	*pparts = mtd_parts;
 | ||||
| +	ret = num_parts;
 | ||||
| +
 | ||||
| + out_free_buf:
 | ||||
| +	vfree(buf);
 | ||||
| + out:
 | ||||
| +	return ret;
 | ||||
| +}
 | ||||
| +
 | ||||
| +static struct mtd_part_parser myloader_mtd_parser = {
 | ||||
| +	.owner		= THIS_MODULE,
 | ||||
| +	.parse_fn	= myloader_parse_partitions,
 | ||||
| +	.name		= "MyLoader",
 | ||||
| +};
 | ||||
| +
 | ||||
| +static int __init myloader_mtd_parser_init(void)
 | ||||
| +{
 | ||||
| +	register_mtd_parser(&myloader_mtd_parser);
 | ||||
| +
 | ||||
| +	return 0;
 | ||||
| +}
 | ||||
| +
 | ||||
| +static void __exit myloader_mtd_parser_exit(void)
 | ||||
| +{
 | ||||
| +	deregister_mtd_parser(&myloader_mtd_parser);
 | ||||
| +}
 | ||||
| +
 | ||||
| +module_init(myloader_mtd_parser_init);
 | ||||
| +module_exit(myloader_mtd_parser_exit);
 | ||||
| +
 | ||||
| +MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
 | ||||
| +MODULE_DESCRIPTION("Parsing code for MyLoader partition tables");
 | ||||
| +MODULE_LICENSE("GPL v2");
 | ||||
|  | @ -0,0 +1,68 @@ | |||
| From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com> | ||||
| Subject: [PATCH] mtd: bcm47xxpart: check for bad blocks when calculating offsets | ||||
| 
 | ||||
| Signed-off-by: Rafał Miłecki <zajec5@gmail.com> | ||||
| ---
 | ||||
| 
 | ||||
| --- a/drivers/mtd/parsers/parser_trx.c
 | ||||
| +++ b/drivers/mtd/parsers/parser_trx.c
 | ||||
| @@ -25,6 +25,33 @@ struct trx_header {
 | ||||
|  	uint32_t offset[3]; | ||||
|  } __packed; | ||||
|   | ||||
| +/*
 | ||||
| + * Calculate real end offset (address) for a given amount of data. It checks
 | ||||
| + * all blocks skipping bad ones.
 | ||||
| + */
 | ||||
| +static size_t parser_trx_real_offset(struct mtd_info *mtd, size_t bytes)
 | ||||
| +{
 | ||||
| +	size_t real_offset = 0;
 | ||||
| +
 | ||||
| +	if (mtd_block_isbad(mtd, real_offset))
 | ||||
| +		pr_warn("Base offset shouldn't be at bad block");
 | ||||
| +
 | ||||
| +	while (bytes >= mtd->erasesize) {
 | ||||
| +		bytes -= mtd->erasesize;
 | ||||
| +		real_offset += mtd->erasesize;
 | ||||
| +		while (mtd_block_isbad(mtd, real_offset)) {
 | ||||
| +			real_offset += mtd->erasesize;
 | ||||
| +
 | ||||
| +			if (real_offset >= mtd->size)
 | ||||
| +				return real_offset - mtd->erasesize;
 | ||||
| +		}
 | ||||
| +	}
 | ||||
| +
 | ||||
| +	real_offset += bytes;
 | ||||
| +
 | ||||
| +	return real_offset;
 | ||||
| +}
 | ||||
| +
 | ||||
|  static const char *parser_trx_data_part_name(struct mtd_info *master, | ||||
|  					     size_t offset) | ||||
|  { | ||||
| @@ -86,21 +113,21 @@ static int parser_trx_parse(struct mtd_i
 | ||||
|  	if (trx.offset[2]) { | ||||
|  		part = &parts[curr_part++]; | ||||
|  		part->name = "loader"; | ||||
| -		part->offset = trx.offset[i];
 | ||||
| +		part->offset = parser_trx_real_offset(mtd, trx.offset[i]);
 | ||||
|  		i++; | ||||
|  	} | ||||
|   | ||||
|  	if (trx.offset[i]) { | ||||
|  		part = &parts[curr_part++]; | ||||
|  		part->name = "linux"; | ||||
| -		part->offset = trx.offset[i];
 | ||||
| +		part->offset = parser_trx_real_offset(mtd, trx.offset[i]);
 | ||||
|  		i++; | ||||
|  	} | ||||
|   | ||||
|  	if (trx.offset[i]) { | ||||
|  		part = &parts[curr_part++]; | ||||
| -		part->name = parser_trx_data_part_name(mtd, trx.offset[i]);
 | ||||
| -		part->offset = trx.offset[i];
 | ||||
| +		part->offset = parser_trx_real_offset(mtd, trx.offset[i]);
 | ||||
| +		part->name = parser_trx_data_part_name(mtd, part->offset);
 | ||||
|  		i++; | ||||
|  	} | ||||
|   | ||||
|  | @ -0,0 +1,37 @@ | |||
| From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com> | ||||
| Subject: mtd: bcm47xxpart: detect T_Meter partition | ||||
| 
 | ||||
| It can be found on many Netgear devices. It consists of many 0x30 blocks | ||||
| starting with 4D 54. | ||||
| 
 | ||||
| Signed-off-by: Rafał Miłecki <zajec5@gmail.com> | ||||
| ---
 | ||||
|  drivers/mtd/bcm47xxpart.c | 10 ++++++++++ | ||||
|  1 file changed, 10 insertions(+) | ||||
| 
 | ||||
| --- a/drivers/mtd/parsers/bcm47xxpart.c
 | ||||
| +++ b/drivers/mtd/parsers/bcm47xxpart.c
 | ||||
| @@ -35,6 +35,7 @@
 | ||||
|  #define NVRAM_HEADER			0x48534C46	/* FLSH */ | ||||
|  #define POT_MAGIC1			0x54544f50	/* POTT */ | ||||
|  #define POT_MAGIC2			0x504f		/* OP */ | ||||
| +#define T_METER_MAGIC			0x4D540000	/* MT */
 | ||||
|  #define ML_MAGIC1			0x39685a42 | ||||
|  #define ML_MAGIC2			0x26594131 | ||||
|  #define TRX_MAGIC			0x30524448 | ||||
| @@ -178,6 +179,15 @@ static int bcm47xxpart_parse(struct mtd_
 | ||||
|  					     MTD_WRITEABLE); | ||||
|  			continue; | ||||
|  		} | ||||
| +
 | ||||
| +		/* T_Meter */
 | ||||
| +		if ((le32_to_cpu(buf[0x000 / 4]) & 0xFFFF0000) == T_METER_MAGIC &&
 | ||||
| +		    (le32_to_cpu(buf[0x030 / 4]) & 0xFFFF0000) == T_METER_MAGIC &&
 | ||||
| +		    (le32_to_cpu(buf[0x060 / 4]) & 0xFFFF0000) == T_METER_MAGIC) {
 | ||||
| +			bcm47xxpart_add_part(&parts[curr_part++], "T_Meter", offset,
 | ||||
| +					     MTD_WRITEABLE);
 | ||||
| +			continue;
 | ||||
| +		}
 | ||||
|   | ||||
|  		/* TRX */ | ||||
|  		if (buf[0x000 / 4] == TRX_MAGIC) { | ||||
|  | @ -0,0 +1,38 @@ | |||
| From 4437e01fb6bca63fccdba5d6c44888b0935885c2 Mon Sep 17 00:00:00 2001 | ||||
| From: =?UTF-8?q?Thibaut=20VAR=C3=88NE?= <hacks@slashdirt.org> | ||||
| Date: Tue, 24 Mar 2020 11:45:07 +0100 | ||||
| Subject: [PATCH] generic: routerboot partition build bits (5.4) | ||||
| MIME-Version: 1.0 | ||||
| Content-Type: text/plain; charset=UTF-8 | ||||
| Content-Transfer-Encoding: 8bit | ||||
| 
 | ||||
| This patch adds routerbootpart kernel build bits | ||||
| 
 | ||||
| Signed-off-by: Thibaut VARÈNE <hacks@slashdirt.org> | ||||
| ---
 | ||||
|  drivers/mtd/parsers/Kconfig  | 9 +++++++++ | ||||
|  drivers/mtd/parsers/Makefile | 1 + | ||||
|  2 files changed, 10 insertions(+) | ||||
| 
 | ||||
| --- a/drivers/mtd/parsers/Kconfig
 | ||||
| +++ b/drivers/mtd/parsers/Kconfig
 | ||||
| @@ -236,3 +236,12 @@ config MTD_SERCOMM_PARTS
 | ||||
|  	  partition map. This partition table contains real partition | ||||
|  	  offsets, which may differ from device to device depending on the | ||||
|  	  number and location of bad blocks on NAND. | ||||
| +
 | ||||
| +config MTD_ROUTERBOOT_PARTS
 | ||||
| +	tristate "RouterBoot flash partition parser"
 | ||||
| +	depends on MTD && OF
 | ||||
| +	help
 | ||||
| +	 MikroTik RouterBoot is implemented as a multi segment system on the
 | ||||
| +	 flash, some of which are fixed and some of which are located at
 | ||||
| +	 variable offsets. This parser handles both cases via properly
 | ||||
| +	 formatted DTS.
 | ||||
| --- a/drivers/mtd/parsers/Makefile
 | ||||
| +++ b/drivers/mtd/parsers/Makefile
 | ||||
| @@ -17,3 +17,4 @@ obj-$(CONFIG_MTD_SERCOMM_PARTS)		+= scpa
 | ||||
|  obj-$(CONFIG_MTD_SHARPSL_PARTS)		+= sharpslpart.o | ||||
|  obj-$(CONFIG_MTD_REDBOOT_PARTS)		+= redboot.o | ||||
|  obj-$(CONFIG_MTD_QCOMSMEM_PARTS)	+= qcomsmempart.o | ||||
| +obj-$(CONFIG_MTD_ROUTERBOOT_PARTS)		+= routerbootpart.o
 | ||||
|  | @ -0,0 +1,120 @@ | |||
| From 3245921a87154bdfbe7a55d743ea62dd559a8fb0 Mon Sep 17 00:00:00 2001 | ||||
| From: Daniel Golle <daniel@makrotopia.org> | ||||
| Date: Thu, 30 May 2024 03:13:09 +0100 | ||||
| Subject: [PATCH 1/9] dt-bindings: block: add basic bindings for block devices | ||||
| 
 | ||||
| Add bindings for block devices which are used to allow referencing | ||||
| nvmem bits on them. | ||||
| 
 | ||||
| Signed-off-by: Daniel Golle <daniel@makrotopia.org> | ||||
| ---
 | ||||
|  .../bindings/block/block-device.yaml          | 22 ++++++++ | ||||
|  .../devicetree/bindings/block/partition.yaml  | 51 +++++++++++++++++++ | ||||
|  .../devicetree/bindings/block/partitions.yaml | 20 ++++++++ | ||||
|  3 files changed, 93 insertions(+) | ||||
|  create mode 100644 Documentation/devicetree/bindings/block/block-device.yaml | ||||
|  create mode 100644 Documentation/devicetree/bindings/block/partition.yaml | ||||
|  create mode 100644 Documentation/devicetree/bindings/block/partitions.yaml | ||||
| 
 | ||||
| --- /dev/null
 | ||||
| +++ b/Documentation/devicetree/bindings/block/block-device.yaml
 | ||||
| @@ -0,0 +1,22 @@
 | ||||
| +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
 | ||||
| +%YAML 1.2
 | ||||
| +---
 | ||||
| +$id: http://devicetree.org/schemas/block/block-device.yaml#
 | ||||
| +$schema: http://devicetree.org/meta-schemas/core.yaml#
 | ||||
| +
 | ||||
| +title: block storage device
 | ||||
| +
 | ||||
| +description: |
 | ||||
| +  This binding is generic and describes a block-oriented storage device.
 | ||||
| +
 | ||||
| +maintainers:
 | ||||
| +  - Daniel Golle <daniel@makrotopia.org>
 | ||||
| +
 | ||||
| +properties:
 | ||||
| +  partitions:
 | ||||
| +    $ref: /schemas/block/partitions.yaml
 | ||||
| +
 | ||||
| +  nvmem-layout:
 | ||||
| +    $ref: /schemas/nvmem/layouts/nvmem-layout.yaml#
 | ||||
| +
 | ||||
| +unevaluatedProperties: false
 | ||||
| --- /dev/null
 | ||||
| +++ b/Documentation/devicetree/bindings/block/partition.yaml
 | ||||
| @@ -0,0 +1,51 @@
 | ||||
| +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
 | ||||
| +%YAML 1.2
 | ||||
| +---
 | ||||
| +$id: http://devicetree.org/schemas/block/partition.yaml#
 | ||||
| +$schema: http://devicetree.org/meta-schemas/core.yaml#
 | ||||
| +
 | ||||
| +title: Partition on a block device
 | ||||
| +
 | ||||
| +description: |
 | ||||
| +  This binding describes a partition on a block device.
 | ||||
| +  Partitions may be matched by a combination of partition number, name,
 | ||||
| +  and UUID.
 | ||||
| +
 | ||||
| +maintainers:
 | ||||
| +  - Daniel Golle <daniel@makrotopia.org>
 | ||||
| +
 | ||||
| +properties:
 | ||||
| +  $nodename:
 | ||||
| +    pattern: '^block-partition-.+$'
 | ||||
| +
 | ||||
| +  partnum:
 | ||||
| +    $ref: /schemas/types.yaml#/definitions/uint32
 | ||||
| +    description:
 | ||||
| +      Matches partition by number if present.
 | ||||
| +
 | ||||
| +  partname:
 | ||||
| +    $ref: /schemas/types.yaml#/definitions/string
 | ||||
| +    description:
 | ||||
| +      Matches partition by PARTNAME if present.
 | ||||
| +
 | ||||
| +  partuuid:
 | ||||
| +    $ref: /schemas/types.yaml#/definitions/string
 | ||||
| +    description:
 | ||||
| +      Matches partition by PARTUUID if present.
 | ||||
| +
 | ||||
| +  nvmem-layout:
 | ||||
| +    $ref: /schemas/nvmem/layouts/nvmem-layout.yaml#
 | ||||
| +    description:
 | ||||
| +      This container may reference an NVMEM layout parser.
 | ||||
| +
 | ||||
| +anyOf:
 | ||||
| +  - required:
 | ||||
| +      - partnum
 | ||||
| +
 | ||||
| +  - required:
 | ||||
| +      - partname
 | ||||
| +
 | ||||
| +  - required:
 | ||||
| +      - partuuid
 | ||||
| +
 | ||||
| +unevaluatedProperties: false
 | ||||
| --- /dev/null
 | ||||
| +++ b/Documentation/devicetree/bindings/block/partitions.yaml
 | ||||
| @@ -0,0 +1,20 @@
 | ||||
| +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
 | ||||
| +%YAML 1.2
 | ||||
| +---
 | ||||
| +$id: http://devicetree.org/schemas/block/partitions.yaml#
 | ||||
| +$schema: http://devicetree.org/meta-schemas/core.yaml#
 | ||||
| +
 | ||||
| +title: Partitions on block devices
 | ||||
| +
 | ||||
| +description: |
 | ||||
| +  This binding is generic and describes the content of the partitions container
 | ||||
| +  node.
 | ||||
| +
 | ||||
| +maintainers:
 | ||||
| +  - Daniel Golle <daniel@makrotopia.org>
 | ||||
| +
 | ||||
| +patternProperties:
 | ||||
| +  "^block-partition-.+$":
 | ||||
| +    $ref: partition.yaml
 | ||||
| +
 | ||||
| +unevaluatedProperties: false
 | ||||
|  | @ -0,0 +1,74 @@ | |||
| From 7f4c9c534aabe1315669e076d3fe0af0fd374cda Mon Sep 17 00:00:00 2001 | ||||
| From: Daniel Golle <daniel@makrotopia.org> | ||||
| Date: Thu, 30 May 2024 03:13:19 +0100 | ||||
| Subject: [PATCH 2/9] block: partitions: populate fwnode | ||||
| 
 | ||||
| Let block partitions to be represented by a firmware node and hence | ||||
| allow them to being referenced e.g. for use with blk-nvmem. | ||||
| 
 | ||||
| Signed-off-by: Daniel Golle <daniel@makrotopia.org> | ||||
| ---
 | ||||
|  block/partitions/core.c | 41 +++++++++++++++++++++++++++++++++++++++++ | ||||
|  1 file changed, 41 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 *) = { | ||||
| @@ -292,6 +294,40 @@ static ssize_t whole_disk_show(struct de
 | ||||
|  } | ||||
|  static const DEVICE_ATTR(whole_disk, 0444, whole_disk_show, NULL); | ||||
|   | ||||
| +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;
 | ||||
| +
 | ||||
| +	fw_parts = device_get_named_child_node(ddev, "partitions");
 | ||||
| +	if (!fw_parts)
 | ||||
| +		return NULL;
 | ||||
| +
 | ||||
| +	fwnode_for_each_child_node(fw_parts, fw_part) {
 | ||||
| +		if (!fwnode_property_read_string(fw_part, "uuid", &uuid) &&
 | ||||
| +		    (!bdev->bd_meta_info || strncmp(uuid,
 | ||||
| +						    bdev->bd_meta_info->uuid,
 | ||||
| +						    PARTITION_META_INFO_UUIDLTH)))
 | ||||
| +			continue;
 | ||||
| +
 | ||||
| +		if (!fwnode_property_read_string(fw_part, "partname", &partname) &&
 | ||||
| +		    (!bdev->bd_meta_info || strncmp(partname,
 | ||||
| +						    bdev->bd_meta_info->volname,
 | ||||
| +						    PARTITION_META_INFO_VOLNAMELTH)))
 | ||||
| +			continue;
 | ||||
| +
 | ||||
| +		if (!fwnode_property_read_u32(fw_part, "partno", &partno) &&
 | ||||
| +		    bdev->bd_partno != 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. | ||||
| @@ -374,6 +410,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); | ||||
|  | @ -0,0 +1,145 @@ | |||
| From e07ace307ce598847074a096f408bec0e3a392ed Mon Sep 17 00:00:00 2001 | ||||
| From: Daniel Golle <daniel@makrotopia.org> | ||||
| Date: Thu, 30 May 2024 03:14:34 +0100 | ||||
| Subject: [PATCH 3/9] block: add support for notifications | ||||
| 
 | ||||
| Add notifier block to notify other subsystems about the addition or | ||||
| removal of block devices. | ||||
| 
 | ||||
| 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(+) | ||||
|  create mode 100644 block/blk-notify.c | ||||
| 
 | ||||
| --- a/block/Kconfig
 | ||||
| +++ b/block/Kconfig
 | ||||
| @@ -208,6 +208,12 @@ config BLK_INLINE_ENCRYPTION_FALLBACK
 | ||||
|  	  by falling back to the kernel crypto API when inline | ||||
|  	  encryption hardware is not present. | ||||
|   | ||||
| +config BLOCK_NOTIFIERS
 | ||||
| +	bool "Enable support for notifications in block layer"
 | ||||
| +	help
 | ||||
| +	  Enable this option to provide notifiers for other subsystems
 | ||||
| +	  upon addition or removal of block devices.
 | ||||
| +
 | ||||
|  source "block/partitions/Kconfig" | ||||
|   | ||||
|  config BLK_MQ_PCI | ||||
| --- a/block/Makefile
 | ||||
| +++ b/block/Makefile
 | ||||
| @@ -40,3 +40,4 @@ obj-$(CONFIG_BLK_INLINE_ENCRYPTION)	+= b
 | ||||
|  					   blk-crypto-sysfs.o | ||||
|  obj-$(CONFIG_BLK_INLINE_ENCRYPTION_FALLBACK)	+= blk-crypto-fallback.o | ||||
|  obj-$(CONFIG_BLOCK_HOLDER_DEPRECATED)	+= holder.o | ||||
| +obj-$(CONFIG_BLOCK_NOTIFIERS) += blk-notify.o
 | ||||
| --- /dev/null
 | ||||
| +++ b/block/blk-notify.c
 | ||||
| @@ -0,0 +1,88 @@
 | ||||
| +// SPDX-License-Identifier: GPL-2.0-or-later
 | ||||
| +/*
 | ||||
| + * Notifiers for addition and removal of block devices
 | ||||
| + *
 | ||||
| + * Copyright (c) 2024 Daniel Golle <daniel@makrotopia.org>
 | ||||
| + */
 | ||||
| +
 | ||||
| +#include <linux/list.h>
 | ||||
| +#include <linux/mutex.h>
 | ||||
| +#include <linux/notifier.h>
 | ||||
| +
 | ||||
| +#include "blk.h"
 | ||||
| +
 | ||||
| +struct blk_device_list {
 | ||||
| +	struct device *dev;
 | ||||
| +	struct list_head list;
 | ||||
| +};
 | ||||
| +
 | ||||
| +static RAW_NOTIFIER_HEAD(blk_notifier_list);
 | ||||
| +static DEFINE_MUTEX(blk_notifier_lock);
 | ||||
| +static LIST_HEAD(blk_devices);
 | ||||
| +
 | ||||
| +void blk_register_notify(struct notifier_block *nb)
 | ||||
| +{
 | ||||
| +	struct blk_device_list *existing_blkdev;
 | ||||
| +
 | ||||
| +	mutex_lock(&blk_notifier_lock);
 | ||||
| +	raw_notifier_chain_register(&blk_notifier_list, nb);
 | ||||
| +
 | ||||
| +	list_for_each_entry(existing_blkdev, &blk_devices, list)
 | ||||
| +		nb->notifier_call(nb, BLK_DEVICE_ADD, existing_blkdev->dev);
 | ||||
| +
 | ||||
| +	mutex_unlock(&blk_notifier_lock);
 | ||||
| +}
 | ||||
| +EXPORT_SYMBOL_GPL(blk_register_notify);
 | ||||
| +
 | ||||
| +void blk_unregister_notify(struct notifier_block *nb)
 | ||||
| +{
 | ||||
| +	mutex_lock(&blk_notifier_lock);
 | ||||
| +	raw_notifier_chain_unregister(&blk_notifier_list, nb);
 | ||||
| +	mutex_unlock(&blk_notifier_lock);
 | ||||
| +}
 | ||||
| +EXPORT_SYMBOL_GPL(blk_unregister_notify);
 | ||||
| +
 | ||||
| +static int blk_call_notifier_add(struct device *dev)
 | ||||
| +{
 | ||||
| +	struct blk_device_list *new_blkdev;
 | ||||
| +
 | ||||
| +	new_blkdev = kmalloc(sizeof(*new_blkdev), GFP_KERNEL);
 | ||||
| +	if (!new_blkdev)
 | ||||
| +		return -ENOMEM;
 | ||||
| +
 | ||||
| +	new_blkdev->dev = dev;
 | ||||
| +	mutex_lock(&blk_notifier_lock);
 | ||||
| +	list_add_tail(&new_blkdev->list, &blk_devices);
 | ||||
| +	raw_notifier_call_chain(&blk_notifier_list, BLK_DEVICE_ADD, dev);
 | ||||
| +	mutex_unlock(&blk_notifier_lock);
 | ||||
| +
 | ||||
| +	return 0;
 | ||||
| +}
 | ||||
| +
 | ||||
| +static void blk_call_notifier_remove(struct device *dev)
 | ||||
| +{
 | ||||
| +	struct blk_device_list *old_blkdev, *tmp;
 | ||||
| +
 | ||||
| +	mutex_lock(&blk_notifier_lock);
 | ||||
| +	list_for_each_entry_safe(old_blkdev, tmp, &blk_devices, list) {
 | ||||
| +		if (old_blkdev->dev != dev)
 | ||||
| +			continue;
 | ||||
| +
 | ||||
| +		list_del(&old_blkdev->list);
 | ||||
| +		kfree(old_blkdev);
 | ||||
| +	}
 | ||||
| +	raw_notifier_call_chain(&blk_notifier_list, BLK_DEVICE_REMOVE, dev);
 | ||||
| +	mutex_unlock(&blk_notifier_lock);
 | ||||
| +}
 | ||||
| +
 | ||||
| +static struct class_interface blk_notifications_bus_interface __refdata = {
 | ||||
| +	.class = &block_class,
 | ||||
| +	.add_dev = &blk_call_notifier_add,
 | ||||
| +	.remove_dev = &blk_call_notifier_remove,
 | ||||
| +};
 | ||||
| +
 | ||||
| +static int __init blk_notifications_init(void)
 | ||||
| +{
 | ||||
| +	return class_interface_register(&blk_notifications_bus_interface);
 | ||||
| +}
 | ||||
| +device_initcall(blk_notifications_init);
 | ||||
| --- a/include/linux/blkdev.h
 | ||||
| +++ b/include/linux/blkdev.h
 | ||||
| @@ -1564,4 +1564,12 @@ struct io_comp_batch {
 | ||||
|   | ||||
|  #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
 | ||||
| +void blk_register_notify(struct notifier_block *nb);
 | ||||
| +void blk_unregister_notify(struct notifier_block *nb);
 | ||||
| +#endif
 | ||||
| +
 | ||||
|  #endif /* _LINUX_BLKDEV_H */ | ||||
|  | @ -0,0 +1,29 @@ | |||
| From f4487fa1cb7e55b3c17a33f41b9c9d66f4f853b7 Mon Sep 17 00:00:00 2001 | ||||
| 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 | ||||
| 
 | ||||
| Add new flag to destinguish block devices which may act as an NVMEM | ||||
| provider. | ||||
| 
 | ||||
| Signed-off-by: Daniel Golle <daniel@makrotopia.org> | ||||
| ---
 | ||||
|  include/linux/blkdev.h | 2 ++ | ||||
|  1 file changed, 2 insertions(+) | ||||
| 
 | ||||
| --- a/include/linux/blkdev.h
 | ||||
| +++ b/include/linux/blkdev.h
 | ||||
| @@ -80,11 +80,13 @@ struct partition_meta_info {
 | ||||
|   * ``GENHD_FL_NO_PART``: partition support is disabled.  The kernel will not | ||||
|   * scan for partitions from add_disk, and users can't add partitions manually. | ||||
|   * | ||||
| + * ``GENHD_FL_NVMEM``: the block device should be considered as NVMEM provider.
 | ||||
|   */ | ||||
|  enum { | ||||
|  	GENHD_FL_REMOVABLE			= 1 << 0, | ||||
|  	GENHD_FL_HIDDEN				= 1 << 1, | ||||
|  	GENHD_FL_NO_PART			= 1 << 2, | ||||
| +	GENHD_FL_NVMEM				= 1 << 3,
 | ||||
|  }; | ||||
|   | ||||
|  enum { | ||||
|  | @ -0,0 +1,260 @@ | |||
| From 9703951cdfe868b130e64d6122420396c2807be8 Mon Sep 17 00:00:00 2001 | ||||
| From: Daniel Golle <daniel@makrotopia.org> | ||||
| Date: Thu, 30 May 2024 03:15:02 +0100 | ||||
| Subject: [PATCH 5/9] nvmem: implement block NVMEM provider | ||||
| 
 | ||||
| On embedded devices using an eMMC it is common that one or more partitions | ||||
| on the eMMC are used to store MAC addresses and Wi-Fi calibration EEPROM | ||||
| data. Allow referencing any block device or partition in Device Tree to | ||||
| allow e.g. Ethernet and Wi-Fi drivers accessing them via the NVMEM layer. | ||||
| 
 | ||||
| Signed-off-by: Daniel Golle <daniel@makrotopia.org> | ||||
| ---
 | ||||
|  drivers/nvmem/Kconfig  |  11 +++ | ||||
|  drivers/nvmem/Makefile |   2 + | ||||
|  drivers/nvmem/block.c  | 197 +++++++++++++++++++++++++++++++++++++++++ | ||||
|  3 files changed, 210 insertions(+) | ||||
|  create mode 100644 drivers/nvmem/block.c | ||||
| 
 | ||||
| --- a/drivers/nvmem/Kconfig
 | ||||
| +++ b/drivers/nvmem/Kconfig
 | ||||
| @@ -40,6 +40,17 @@ config NVMEM_APPLE_EFUSES
 | ||||
|  	  This driver can also be built as a module. If so, the module will | ||||
|  	  be called nvmem-apple-efuses. | ||||
|   | ||||
| +config NVMEM_BLOCK
 | ||||
| +	tristate "Block device NVMEM provider"
 | ||||
| +	depends on BLOCK
 | ||||
| +	depends on OF
 | ||||
| +	depends on NVMEM
 | ||||
| +	select BLOCK_NOTIFIERS
 | ||||
| +	help
 | ||||
| +	  Allow block devices (or partitions) to act as NVMEM prodivers,
 | ||||
| +	  typically used with eMMC to store MAC addresses or Wi-Fi
 | ||||
| +	  calibration data on embedded devices.
 | ||||
| +
 | ||||
|  config NVMEM_BCM_OCOTP | ||||
|  	tristate "Broadcom On-Chip OTP Controller support" | ||||
|  	depends on ARCH_BCM_IPROC || COMPILE_TEST | ||||
| --- a/drivers/nvmem/Makefile
 | ||||
| +++ b/drivers/nvmem/Makefile
 | ||||
| @@ -14,6 +14,8 @@ obj-$(CONFIG_NVMEM_APPLE_EFUSES)	+= nvme
 | ||||
|  nvmem-apple-efuses-y 			:= apple-efuses.o | ||||
|  obj-$(CONFIG_NVMEM_BCM_OCOTP)		+= nvmem-bcm-ocotp.o | ||||
|  nvmem-bcm-ocotp-y			:= bcm-ocotp.o | ||||
| +obj-$(CONFIG_NVMEM_BLOCK)		+= nvmem-block.o
 | ||||
| +nvmem-block-y				:= block.o
 | ||||
|  obj-$(CONFIG_NVMEM_BRCM_NVRAM)		+= nvmem_brcm_nvram.o | ||||
|  nvmem_brcm_nvram-y			:= brcm_nvram.o | ||||
|  obj-$(CONFIG_NVMEM_IMX_IIM)		+= nvmem-imx-iim.o | ||||
| --- /dev/null
 | ||||
| +++ b/drivers/nvmem/block.c
 | ||||
| @@ -0,0 +1,208 @@
 | ||||
| +// SPDX-License-Identifier: GPL-2.0-or-later
 | ||||
| +/*
 | ||||
| + * block device NVMEM provider
 | ||||
| + *
 | ||||
| + * Copyright (c) 2024 Daniel Golle <daniel@makrotopia.org>
 | ||||
| + *
 | ||||
| + * Useful on devices using a partition on an eMMC for MAC addresses or
 | ||||
| + * Wi-Fi calibration EEPROM data.
 | ||||
| + */
 | ||||
| +
 | ||||
| +#include <linux/blkdev.h>
 | ||||
| +#include <linux/nvmem-provider.h>
 | ||||
| +#include <linux/of.h>
 | ||||
| +#include <linux/pagemap.h>
 | ||||
| +#include <linux/property.h>
 | ||||
| +
 | ||||
| +/* List of all NVMEM devices */
 | ||||
| +static LIST_HEAD(nvmem_devices);
 | ||||
| +static DEFINE_MUTEX(devices_mutex);
 | ||||
| +
 | ||||
| +struct blk_nvmem {
 | ||||
| +	struct nvmem_device *nvmem;
 | ||||
| +	struct block_device *bdev;
 | ||||
| +	struct list_head list;
 | ||||
| +};
 | ||||
| +
 | ||||
| +static int blk_nvmem_reg_read(void *priv, unsigned int from,
 | ||||
| +			      void *val, size_t bytes)
 | ||||
| +{
 | ||||
| +	unsigned long offs = from & ~PAGE_MASK, to_read;
 | ||||
| +	pgoff_t f_index = from >> PAGE_SHIFT;
 | ||||
| +	struct address_space *mapping;
 | ||||
| +	struct blk_nvmem *bnv = priv;
 | ||||
| +	size_t bytes_left = bytes;
 | ||||
| +	struct folio *folio;
 | ||||
| +	void *p;
 | ||||
| +	int ret;
 | ||||
| +
 | ||||
| +	if (!bnv->bdev)
 | ||||
| +		return -ENODEV;
 | ||||
| +
 | ||||
| +	if (!bnv->bdev->bd_disk)
 | ||||
| +		return -EINVAL;
 | ||||
| +
 | ||||
| +	if (!bnv->bdev->bd_disk->fops)
 | ||||
| +		return -EIO;
 | ||||
| +
 | ||||
| +	if (!bnv->bdev->bd_disk->fops->open)
 | ||||
| +		return -EIO;
 | ||||
| +
 | ||||
| +	ret = bnv->bdev->bd_disk->fops->open(bnv->bdev->bd_disk, BLK_OPEN_READ);
 | ||||
| +	if (ret)
 | ||||
| +		return ret;
 | ||||
| +
 | ||||
| +	mapping = bnv->bdev->bd_inode->i_mapping;
 | ||||
| +
 | ||||
| +	while (bytes_left) {
 | ||||
| +		folio = read_mapping_folio(mapping, f_index++, NULL);
 | ||||
| +		if (IS_ERR(folio)) {
 | ||||
| +			ret = PTR_ERR(folio);
 | ||||
| +			goto err_release_bdev;
 | ||||
| +		}
 | ||||
| +		to_read = min_t(unsigned long, bytes_left, PAGE_SIZE - offs);
 | ||||
| +		p = folio_address(folio) + offset_in_folio(folio, offs);
 | ||||
| +		memcpy(val, p, to_read);
 | ||||
| +		offs = 0;
 | ||||
| +		bytes_left -= to_read;
 | ||||
| +		val += to_read;
 | ||||
| +		folio_put(folio);
 | ||||
| +	}
 | ||||
| +
 | ||||
| +err_release_bdev:
 | ||||
| +	bnv->bdev->bd_disk->fops->release(bnv->bdev->bd_disk);
 | ||||
| +
 | ||||
| +	return ret;
 | ||||
| +}
 | ||||
| +
 | ||||
| +static int blk_nvmem_register(struct device *dev)
 | ||||
| +{
 | ||||
| +	struct device_node *np = dev_of_node(dev);
 | ||||
| +	struct block_device *bdev = dev_to_bdev(dev);
 | ||||
| +	struct nvmem_config config = {};
 | ||||
| +	struct blk_nvmem *bnv;
 | ||||
| +
 | ||||
| +	/* skip devices which do not have a device tree node */
 | ||||
| +	if (!np)
 | ||||
| +		return 0;
 | ||||
| +
 | ||||
| +	/* skip devices without an nvmem layout defined */
 | ||||
| +	if (!of_get_child_by_name(np, "nvmem-layout"))
 | ||||
| +		return 0;
 | ||||
| +
 | ||||
| +	/*
 | ||||
| +	 * skip devices which don't have GENHD_FL_NVMEM set
 | ||||
| +	 *
 | ||||
| +	 * This flag is used for mtdblock and ubiblock devices because
 | ||||
| +	 * both, MTD and UBI already implement their own NVMEM provider.
 | ||||
| +	 * To avoid registering multiple NVMEM providers for the same
 | ||||
| +	 * device node, don't register the block NVMEM provider for them.
 | ||||
| +	 */
 | ||||
| +	if (!(bdev->bd_disk->flags & GENHD_FL_NVMEM))
 | ||||
| +		return 0;
 | ||||
| +
 | ||||
| +	/*
 | ||||
| +	 * skip block device too large to be represented as NVMEM devices
 | ||||
| +	 * which are using an 'int' as address
 | ||||
| +	 */
 | ||||
| +	if (bdev_nr_bytes(bdev) > INT_MAX)
 | ||||
| +		return -EFBIG;
 | ||||
| +
 | ||||
| +	bnv = kzalloc(sizeof(struct blk_nvmem), GFP_KERNEL);
 | ||||
| +	if (!bnv)
 | ||||
| +		return -ENOMEM;
 | ||||
| +
 | ||||
| +	config.id = NVMEM_DEVID_NONE;
 | ||||
| +	config.dev = &bdev->bd_device;
 | ||||
| +	config.name = dev_name(&bdev->bd_device);
 | ||||
| +	config.owner = THIS_MODULE;
 | ||||
| +	config.priv = bnv;
 | ||||
| +	config.reg_read = blk_nvmem_reg_read;
 | ||||
| +	config.size = bdev_nr_bytes(bdev);
 | ||||
| +	config.word_size = 1;
 | ||||
| +	config.stride = 1;
 | ||||
| +	config.read_only = true;
 | ||||
| +	config.root_only = true;
 | ||||
| +	config.ignore_wp = true;
 | ||||
| +	config.of_node = to_of_node(dev->fwnode);
 | ||||
| +
 | ||||
| +	bnv->bdev = bdev;
 | ||||
| +	bnv->nvmem = nvmem_register(&config);
 | ||||
| +	if (IS_ERR(bnv->nvmem)) {
 | ||||
| +		dev_err_probe(&bdev->bd_device, PTR_ERR(bnv->nvmem),
 | ||||
| +			      "Failed to register NVMEM device\n");
 | ||||
| +
 | ||||
| +		kfree(bnv);
 | ||||
| +		return PTR_ERR(bnv->nvmem);
 | ||||
| +	}
 | ||||
| +
 | ||||
| +	mutex_lock(&devices_mutex);
 | ||||
| +	list_add_tail(&bnv->list, &nvmem_devices);
 | ||||
| +	mutex_unlock(&devices_mutex);
 | ||||
| +
 | ||||
| +	return 0;
 | ||||
| +}
 | ||||
| +
 | ||||
| +static void blk_nvmem_unregister(struct device *dev)
 | ||||
| +{
 | ||||
| +	struct block_device *bdev = dev_to_bdev(dev);
 | ||||
| +	struct blk_nvmem *bnv_c, *bnv = NULL;
 | ||||
| +
 | ||||
| +	mutex_lock(&devices_mutex);
 | ||||
| +	list_for_each_entry(bnv_c, &nvmem_devices, list) {
 | ||||
| +		if (bnv_c->bdev == bdev) {
 | ||||
| +			bnv = bnv_c;
 | ||||
| +			break;
 | ||||
| +		}
 | ||||
| +	}
 | ||||
| +
 | ||||
| +	if (!bnv) {
 | ||||
| +		mutex_unlock(&devices_mutex);
 | ||||
| +		return;
 | ||||
| +	}
 | ||||
| +
 | ||||
| +	list_del(&bnv->list);
 | ||||
| +	mutex_unlock(&devices_mutex);
 | ||||
| +	nvmem_unregister(bnv->nvmem);
 | ||||
| +	kfree(bnv);
 | ||||
| +}
 | ||||
| +
 | ||||
| +static int blk_nvmem_handler(struct notifier_block *this, unsigned long code, void *obj)
 | ||||
| +{
 | ||||
| +	struct device *dev = (struct device *)obj;
 | ||||
| +
 | ||||
| +	switch (code) {
 | ||||
| +	case BLK_DEVICE_ADD:
 | ||||
| +		return blk_nvmem_register(dev);
 | ||||
| +	case BLK_DEVICE_REMOVE:
 | ||||
| +		blk_nvmem_unregister(dev);
 | ||||
| +		break;
 | ||||
| +	default:
 | ||||
| +		return -EINVAL;
 | ||||
| +	}
 | ||||
| +
 | ||||
| +	return 0;
 | ||||
| +}
 | ||||
| +
 | ||||
| +static struct notifier_block blk_nvmem_notifier = {
 | ||||
| +	.notifier_call = blk_nvmem_handler,
 | ||||
| +};
 | ||||
| +
 | ||||
| +static int __init blk_nvmem_init(void)
 | ||||
| +{
 | ||||
| +	blk_register_notify(&blk_nvmem_notifier);
 | ||||
| +
 | ||||
| +	return 0;
 | ||||
| +}
 | ||||
| +
 | ||||
| +static void __exit blk_nvmem_exit(void)
 | ||||
| +{
 | ||||
| +	blk_unregister_notify(&blk_nvmem_notifier);
 | ||||
| +}
 | ||||
| +
 | ||||
| +module_init(blk_nvmem_init);
 | ||||
| +module_exit(blk_nvmem_exit);
 | ||||
| +
 | ||||
| +MODULE_LICENSE("GPL");
 | ||||
| +MODULE_AUTHOR("Daniel Golle <daniel@makrotopia.org>");
 | ||||
| +MODULE_DESCRIPTION("block device NVMEM provider");
 | ||||
|  | @ -0,0 +1,74 @@ | |||
| From f7ec19b34d1b7e934a58ceb102369bbd30b2631d Mon Sep 17 00:00:00 2001 | ||||
| From: Daniel Golle <daniel@makrotopia.org> | ||||
| Date: Thu, 30 May 2024 03:15:11 +0100 | ||||
| Subject: [PATCH 6/9] dt-bindings: mmc: mmc-card: add block device nodes | ||||
| 
 | ||||
| Add nodes representing the block devices exposed by an MMC device | ||||
| including an example involving nvmem-cells. | ||||
| 
 | ||||
| Signed-off-by: Daniel Golle <daniel@makrotopia.org> | ||||
| ---
 | ||||
|  .../devicetree/bindings/mmc/mmc-card.yaml     | 45 +++++++++++++++++++ | ||||
|  1 file changed, 45 insertions(+) | ||||
| 
 | ||||
| --- a/Documentation/devicetree/bindings/mmc/mmc-card.yaml
 | ||||
| +++ b/Documentation/devicetree/bindings/mmc/mmc-card.yaml
 | ||||
| @@ -26,6 +26,18 @@ properties:
 | ||||
|        Use this to indicate that the mmc-card has a broken hpi | ||||
|        implementation, and that hpi should not be used. | ||||
|   | ||||
| +  block:
 | ||||
| +    $ref: /schemas/block/block-device.yaml#
 | ||||
| +    description:
 | ||||
| +      Represents the block storage provided by an SD card or the
 | ||||
| +      main hardware partition of an eMMC.
 | ||||
| +
 | ||||
| +patternProperties:
 | ||||
| +  '^boot[0-9]+':
 | ||||
| +    $ref: /schemas/block/block-device.yaml#
 | ||||
| +    description:
 | ||||
| +      Represents a boot hardware partition on an eMMC.
 | ||||
| +
 | ||||
|  required: | ||||
|    - compatible | ||||
|    - reg | ||||
| @@ -42,6 +54,39 @@ examples:
 | ||||
|              compatible = "mmc-card"; | ||||
|              reg = <0>; | ||||
|              broken-hpi; | ||||
| +
 | ||||
| +            block {
 | ||||
| +                partitions {
 | ||||
| +                    cal_data: block-partition-rf {
 | ||||
| +                        partnum = <3>;
 | ||||
| +                        partname = "rf";
 | ||||
| +
 | ||||
| +                        nvmem-layout {
 | ||||
| +                            compatible = "fixed-layout";
 | ||||
| +                            #address-cells = <1>;
 | ||||
| +                            #size-cells = <1>;
 | ||||
| +
 | ||||
| +                            eeprom@0 {
 | ||||
| +                                reg = <0x0 0x1000>;
 | ||||
| +                            };
 | ||||
| +                        };
 | ||||
| +                    };
 | ||||
| +                };
 | ||||
| +            };
 | ||||
| +
 | ||||
| +            boot1 {
 | ||||
| +                nvmem-layout {
 | ||||
| +                    compatible = "fixed-layout";
 | ||||
| +                    #address-cells = <1>;
 | ||||
| +                    #size-cells = <1>;
 | ||||
| +
 | ||||
| +                    macaddr: macaddr@a {
 | ||||
| +                        compatible = "mac-base";
 | ||||
| +                        reg = <0xa 0x6>;
 | ||||
| +                        #nvmem-cell-cells = <1>;
 | ||||
| +                    };
 | ||||
| +                };
 | ||||
| +            };
 | ||||
|          }; | ||||
|      }; | ||||
|   | ||||
|  | @ -0,0 +1,23 @@ | |||
| From 043c4f88476cc0f29c9bf82a8a516f58d848e1cd Mon Sep 17 00:00:00 2001 | ||||
| From: Daniel Golle <daniel@makrotopia.org> | ||||
| Date: Thu, 30 May 2024 03:15:25 +0100 | ||||
| Subject: [PATCH 7/9] mmc: core: set card fwnode_handle | ||||
| 
 | ||||
| Set fwnode in case it isn't set yet and of_node is present. | ||||
| 
 | ||||
| Signed-off-by: Daniel Golle <daniel@makrotopia.org> | ||||
| ---
 | ||||
|  drivers/mmc/core/bus.c | 2 ++ | ||||
|  1 file changed, 2 insertions(+) | ||||
| 
 | ||||
| --- a/drivers/mmc/core/bus.c
 | ||||
| +++ b/drivers/mmc/core/bus.c
 | ||||
| @@ -364,6 +364,8 @@ int mmc_add_card(struct mmc_card *card)
 | ||||
|   | ||||
|  	mmc_add_card_debugfs(card); | ||||
|  	card->dev.of_node = mmc_of_find_child_device(card->host, 0); | ||||
| +	if (card->dev.of_node && !card->dev.fwnode)
 | ||||
| +		card->dev.fwnode = &card->dev.of_node->fwnode;
 | ||||
|   | ||||
|  	device_enable_async_suspend(&card->dev); | ||||
|   | ||||
|  | @ -0,0 +1,37 @@ | |||
| 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
 | ||||
| @@ -2463,6 +2463,7 @@ static struct mmc_blk_data *mmc_blk_allo
 | ||||
|  					      int area_type, | ||||
|  					      unsigned int part_type) | ||||
|  { | ||||
| +	struct fwnode_handle *fwnode;
 | ||||
|  	struct mmc_blk_data *md; | ||||
|  	int devidx, ret; | ||||
|  	char cap_str[10]; | ||||
| @@ -2559,6 +2560,12 @@ static struct mmc_blk_data *mmc_blk_allo
 | ||||
|   | ||||
|  	blk_queue_write_cache(md->queue.queue, cache_enabled, fua_enabled); | ||||
|   | ||||
| +	fwnode = device_get_named_child_node(subname ? md->parent->parent :
 | ||||
| +						       md->parent,
 | ||||
| +					     subname ? subname : "block");
 | ||||
| +	if (fwnode)
 | ||||
| +		device_set_node(disk_to_dev(md->disk), fwnode);
 | ||||
| +
 | ||||
|  	string_get_size((u64)size, 512, STRING_UNITS_2, | ||||
|  			cap_str, sizeof(cap_str)); | ||||
|  	pr_info("%s: %s %s %s%s\n", | ||||
|  | @ -0,0 +1,22 @@ | |||
| From 7903b50441000365a6fe5badb39735889f562252 Mon Sep 17 00:00:00 2001 | ||||
| From: Daniel Golle <daniel@makrotopia.org> | ||||
| Date: Thu, 30 May 2024 03:15:46 +0100 | ||||
| Subject: [PATCH 9/9] mmc: block: set GENHD_FL_NVMEM | ||||
| 
 | ||||
| Set flag to consider MMC block devices as NVMEM providers. | ||||
| 
 | ||||
| Signed-off-by: Daniel Golle <daniel@makrotopia.org> | ||||
| ---
 | ||||
|  drivers/mmc/core/block.c | 1 + | ||||
|  1 file changed, 1 insertion(+) | ||||
| 
 | ||||
| --- a/drivers/mmc/core/block.c
 | ||||
| +++ b/drivers/mmc/core/block.c
 | ||||
| @@ -2516,6 +2516,7 @@ static struct mmc_blk_data *mmc_blk_allo
 | ||||
|  	md->disk->major	= MMC_BLOCK_MAJOR; | ||||
|  	md->disk->minors = perdev_minors; | ||||
|  	md->disk->first_minor = devidx * perdev_minors; | ||||
| +	md->disk->flags = GENHD_FL_NVMEM;
 | ||||
|  	md->disk->fops = &mmc_bdops; | ||||
|  	md->disk->private_data = md; | ||||
|  	md->parent = parent; | ||||
|  | @ -0,0 +1,25 @@ | |||
| From: Felix Fietkau <nbd@nbd.name> | ||||
| Subject: kernel: disable cfi cmdset 0002 erase suspend | ||||
| 
 | ||||
| on some platforms, erase suspend leads to data corruption and lockups when write | ||||
| ops collide with erase ops. this has been observed on the buffalo wzr-hp-g300nh. | ||||
| rather than play whack-a-mole with a hard to reproduce issue on a variety of devices, | ||||
| simply disable erase suspend, as it will usually not produce any useful gain on | ||||
| the small filesystems used on embedded hardware. | ||||
| 
 | ||||
| Signed-off-by: Felix Fietkau <nbd@nbd.name> | ||||
| ---
 | ||||
|  drivers/mtd/chips/cfi_cmdset_0002.c | 2 +- | ||||
|  1 file changed, 1 insertion(+), 1 deletion(-) | ||||
| 
 | ||||
| --- a/drivers/mtd/chips/cfi_cmdset_0002.c
 | ||||
| +++ b/drivers/mtd/chips/cfi_cmdset_0002.c
 | ||||
| @@ -906,7 +906,7 @@ static int get_chip(struct map_info *map
 | ||||
|  		return 0; | ||||
|   | ||||
|  	case FL_ERASING: | ||||
| -		if (!cfip || !(cfip->EraseSuspend & (0x1|0x2)) ||
 | ||||
| +		if (1 /* no suspend */ || !cfip || !(cfip->EraseSuspend & (0x1|0x2)) ||
 | ||||
|  		    !(mode == FL_READY || mode == FL_POINT || | ||||
|  		    (mode == FL_WRITING && (cfip->EraseSuspend & 0x2)))) | ||||
|  			goto sleep; | ||||
Some files were not shown because too many files have changed in this diff Show more
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue