Index: Baikal/M1000/create-5.4.211-5.7.226-host-limits-patch/file.list
===================================================================
--- Baikal/M1000/create-5.4.211-5.7.226-host-limits-patch/file.list (revision 384)
+++ Baikal/M1000/create-5.4.211-5.7.226-host-limits-patch/file.list (nonexistent)
@@ -1,7 +0,0 @@
-linux-m1-5.4.211-5.7.226/scripts/kconfig/conf.c
-linux-m1-5.4.211-5.7.226/scripts/kconfig/confdata.c
-linux-m1-5.4.211-5.7.226/scripts/kconfig/lexer.l
-linux-m1-5.4.211-5.7.226/scripts/mod/modpost.c
-linux-m1-5.4.211-5.7.226/scripts/mod/sumversion.c
-linux-m1-5.4.211-5.7.226/tools/build/fixdep.c
-linux-m1-5.4.211-5.7.226/usr/gen_init_cpio.c
Index: Baikal/M1000/create-5.4.211-5.7.226-host-limits-patch/linux-m1-5.4.211-5.7.226-new/scripts/mod/modpost.c
===================================================================
--- Baikal/M1000/create-5.4.211-5.7.226-host-limits-patch/linux-m1-5.4.211-5.7.226-new/scripts/mod/modpost.c (revision 384)
+++ Baikal/M1000/create-5.4.211-5.7.226-host-limits-patch/linux-m1-5.4.211-5.7.226-new/scripts/mod/modpost.c (nonexistent)
@@ -1,2698 +0,0 @@
-/* Postprocess module symbol versions
- *
- * Copyright 2003 Kai Germaschewski
- * Copyright 2002-2004 Rusty Russell, IBM Corporation
- * Copyright 2006-2008 Sam Ravnborg
- * Based in part on module-init-tools/depmod.c,file2alias
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- * Usage: modpost vmlinux module1.o module2.o ...
- */
-
-#define _GNU_SOURCE
-#include <stdio.h>
-#include <ctype.h>
-#include <string.h>
-#include <linux/limits.h>
-#include <stdbool.h>
-#include <errno.h>
-#include "modpost.h"
-#include "../../include/linux/license.h"
-
-/* Are we using CONFIG_MODVERSIONS? */
-static int modversions = 0;
-/* Warn about undefined symbols? (do so if we have vmlinux) */
-static int have_vmlinux = 0;
-/* Is CONFIG_MODULE_SRCVERSION_ALL set? */
-static int all_versions = 0;
-/* If we are modposting external module set to 1 */
-static int external_module = 0;
-/* Warn about section mismatch in vmlinux if set to 1 */
-static int vmlinux_section_warnings = 1;
-/* Only warn about unresolved symbols */
-static int warn_unresolved = 0;
-/* How a symbol is exported */
-static int sec_mismatch_count = 0;
-static int sec_mismatch_fatal = 0;
-/* ignore missing files */
-static int ignore_missing_files;
-/* write namespace dependencies */
-static int write_namespace_deps;
-
-enum export {
- export_plain, export_unused, export_gpl,
- export_unused_gpl, export_gpl_future, export_unknown
-};
-
-/* In kernel, this size is defined in linux/module.h;
- * here we use Elf_Addr instead of long for covering cross-compile
- */
-
-#define MODULE_NAME_LEN (64 - sizeof(Elf_Addr))
-
-#define PRINTF __attribute__ ((format (printf, 1, 2)))
-
-PRINTF void fatal(const char *fmt, ...)
-{
- va_list arglist;
-
- fprintf(stderr, "FATAL: ");
-
- va_start(arglist, fmt);
- vfprintf(stderr, fmt, arglist);
- va_end(arglist);
-
- exit(1);
-}
-
-PRINTF void warn(const char *fmt, ...)
-{
- va_list arglist;
-
- fprintf(stderr, "WARNING: ");
-
- va_start(arglist, fmt);
- vfprintf(stderr, fmt, arglist);
- va_end(arglist);
-}
-
-PRINTF void merror(const char *fmt, ...)
-{
- va_list arglist;
-
- fprintf(stderr, "ERROR: ");
-
- va_start(arglist, fmt);
- vfprintf(stderr, fmt, arglist);
- va_end(arglist);
-}
-
-static inline bool strends(const char *str, const char *postfix)
-{
- if (strlen(str) < strlen(postfix))
- return false;
-
- return strcmp(str + strlen(str) - strlen(postfix), postfix) == 0;
-}
-
-static int is_vmlinux(const char *modname)
-{
- const char *myname;
-
- myname = strrchr(modname, '/');
- if (myname)
- myname++;
- else
- myname = modname;
-
- return (strcmp(myname, "vmlinux") == 0) ||
- (strcmp(myname, "vmlinux.o") == 0);
-}
-
-void *do_nofail(void *ptr, const char *expr)
-{
- if (!ptr)
- fatal("modpost: Memory allocation failure: %s.\n", expr);
-
- return ptr;
-}
-
-/* A list of all modules we processed */
-static struct module *modules;
-
-static struct module *find_module(const char *modname)
-{
- struct module *mod;
-
- for (mod = modules; mod; mod = mod->next)
- if (strcmp(mod->name, modname) == 0)
- break;
- return mod;
-}
-
-static struct module *new_module(const char *modname)
-{
- struct module *mod;
- char *p;
-
- mod = NOFAIL(malloc(sizeof(*mod)));
- memset(mod, 0, sizeof(*mod));
- p = NOFAIL(strdup(modname));
-
- /* strip trailing .o */
- if (strends(p, ".o")) {
- p[strlen(p) - 2] = '\0';
- mod->is_dot_o = 1;
- }
-
- /* add to list */
- mod->name = p;
- mod->gpl_compatible = -1;
- mod->next = modules;
- modules = mod;
-
- return mod;
-}
-
-/* A hash of all exported symbols,
- * struct symbol is also used for lists of unresolved symbols */
-
-#define SYMBOL_HASH_SIZE 1024
-
-struct symbol {
- struct symbol *next;
- struct module *module;
- unsigned int crc;
- int crc_valid;
- char *namespace;
- unsigned int weak:1;
- unsigned int vmlinux:1; /* 1 if symbol is defined in vmlinux */
- unsigned int kernel:1; /* 1 if symbol is from kernel
- * (only for external modules) **/
- unsigned int preloaded:1; /* 1 if symbol from Module.symvers, or crc */
- unsigned int is_static:1; /* 1 if symbol is not global */
- enum export export; /* Type of export */
- char name[0];
-};
-
-static struct symbol *symbolhash[SYMBOL_HASH_SIZE];
-
-/* This is based on the hash agorithm from gdbm, via tdb */
-static inline unsigned int tdb_hash(const char *name)
-{
- unsigned value; /* Used to compute the hash value. */
- unsigned i; /* Used to cycle through random values. */
-
- /* Set the initial value from the key size. */
- for (value = 0x238F13AF * strlen(name), i = 0; name[i]; i++)
- value = (value + (((unsigned char *)name)[i] << (i*5 % 24)));
-
- return (1103515243 * value + 12345);
-}
-
-/**
- * Allocate a new symbols for use in the hash of exported symbols or
- * the list of unresolved symbols per module
- **/
-static struct symbol *alloc_symbol(const char *name, unsigned int weak,
- struct symbol *next)
-{
- struct symbol *s = NOFAIL(malloc(sizeof(*s) + strlen(name) + 1));
-
- memset(s, 0, sizeof(*s));
- strcpy(s->name, name);
- s->weak = weak;
- s->next = next;
- s->is_static = 1;
- return s;
-}
-
-/* For the hash of exported symbols */
-static struct symbol *new_symbol(const char *name, struct module *module,
- enum export export)
-{
- unsigned int hash;
- struct symbol *new;
-
- hash = tdb_hash(name) % SYMBOL_HASH_SIZE;
- new = symbolhash[hash] = alloc_symbol(name, 0, symbolhash[hash]);
- new->module = module;
- new->export = export;
- return new;
-}
-
-static struct symbol *find_symbol(const char *name)
-{
- struct symbol *s;
-
- /* For our purposes, .foo matches foo. PPC64 needs this. */
- if (name[0] == '.')
- name++;
-
- for (s = symbolhash[tdb_hash(name) % SYMBOL_HASH_SIZE]; s; s = s->next) {
- if (strcmp(s->name, name) == 0)
- return s;
- }
- return NULL;
-}
-
-static bool contains_namespace(struct namespace_list *list,
- const char *namespace)
-{
- struct namespace_list *ns_entry;
-
- for (ns_entry = list; ns_entry != NULL; ns_entry = ns_entry->next)
- if (strcmp(ns_entry->namespace, namespace) == 0)
- return true;
-
- return false;
-}
-
-static void add_namespace(struct namespace_list **list, const char *namespace)
-{
- struct namespace_list *ns_entry;
-
- if (!contains_namespace(*list, namespace)) {
- ns_entry = NOFAIL(malloc(sizeof(struct namespace_list) +
- strlen(namespace) + 1));
- strcpy(ns_entry->namespace, namespace);
- ns_entry->next = *list;
- *list = ns_entry;
- }
-}
-
-static bool module_imports_namespace(struct module *module,
- const char *namespace)
-{
- return contains_namespace(module->imported_namespaces, namespace);
-}
-
-static const struct {
- const char *str;
- enum export export;
-} export_list[] = {
- { .str = "EXPORT_SYMBOL", .export = export_plain },
- { .str = "EXPORT_UNUSED_SYMBOL", .export = export_unused },
- { .str = "EXPORT_SYMBOL_GPL", .export = export_gpl },
- { .str = "EXPORT_UNUSED_SYMBOL_GPL", .export = export_unused_gpl },
- { .str = "EXPORT_SYMBOL_GPL_FUTURE", .export = export_gpl_future },
- { .str = "(unknown)", .export = export_unknown },
-};
-
-
-static const char *export_str(enum export ex)
-{
- return export_list[ex].str;
-}
-
-static enum export export_no(const char *s)
-{
- int i;
-
- if (!s)
- return export_unknown;
- for (i = 0; export_list[i].export != export_unknown; i++) {
- if (strcmp(export_list[i].str, s) == 0)
- return export_list[i].export;
- }
- return export_unknown;
-}
-
-static const char *sech_name(struct elf_info *elf, Elf_Shdr *sechdr)
-{
- return (void *)elf->hdr +
- elf->sechdrs[elf->secindex_strings].sh_offset +
- sechdr->sh_name;
-}
-
-static const char *sec_name(struct elf_info *elf, int secindex)
-{
- return sech_name(elf, &elf->sechdrs[secindex]);
-}
-
-#define strstarts(str, prefix) (strncmp(str, prefix, strlen(prefix)) == 0)
-
-static enum export export_from_secname(struct elf_info *elf, unsigned int sec)
-{
- const char *secname = sec_name(elf, sec);
-
- if (strstarts(secname, "___ksymtab+"))
- return export_plain;
- else if (strstarts(secname, "___ksymtab_unused+"))
- return export_unused;
- else if (strstarts(secname, "___ksymtab_gpl+"))
- return export_gpl;
- else if (strstarts(secname, "___ksymtab_unused_gpl+"))
- return export_unused_gpl;
- else if (strstarts(secname, "___ksymtab_gpl_future+"))
- return export_gpl_future;
- else
- return export_unknown;
-}
-
-static enum export export_from_sec(struct elf_info *elf, unsigned int sec)
-{
- if (sec == elf->export_sec)
- return export_plain;
- else if (sec == elf->export_unused_sec)
- return export_unused;
- else if (sec == elf->export_gpl_sec)
- return export_gpl;
- else if (sec == elf->export_unused_gpl_sec)
- return export_unused_gpl;
- else if (sec == elf->export_gpl_future_sec)
- return export_gpl_future;
- else
- return export_unknown;
-}
-
-static const char *namespace_from_kstrtabns(struct elf_info *info,
- Elf_Sym *kstrtabns)
-{
- char *value = info->ksymtab_strings + kstrtabns->st_value;
- return value[0] ? value : NULL;
-}
-
-static void sym_update_namespace(const char *symname, const char *namespace)
-{
- struct symbol *s = find_symbol(symname);
-
- /*
- * That symbol should have been created earlier and thus this is
- * actually an assertion.
- */
- if (!s) {
- merror("Could not update namespace(%s) for symbol %s\n",
- namespace, symname);
- return;
- }
-
- free(s->namespace);
- s->namespace =
- namespace && namespace[0] ? NOFAIL(strdup(namespace)) : NULL;
-}
-
-/**
- * Add an exported symbol - it may have already been added without a
- * CRC, in this case just update the CRC
- **/
-static struct symbol *sym_add_exported(const char *name, struct module *mod,
- enum export export)
-{
- struct symbol *s = find_symbol(name);
-
- if (!s) {
- s = new_symbol(name, mod, export);
- } else {
- if (!s->preloaded) {
- warn("%s: '%s' exported twice. Previous export was in %s%s\n",
- mod->name, name, s->module->name,
- is_vmlinux(s->module->name) ? "" : ".ko");
- } else {
- /* In case Module.symvers was out of date */
- s->module = mod;
- }
- }
- s->preloaded = 0;
- s->vmlinux = is_vmlinux(mod->name);
- s->kernel = 0;
- s->export = export;
- return s;
-}
-
-static void sym_update_crc(const char *name, struct module *mod,
- unsigned int crc, enum export export)
-{
- struct symbol *s = find_symbol(name);
-
- if (!s) {
- s = new_symbol(name, mod, export);
- /* Don't complain when we find it later. */
- s->preloaded = 1;
- }
- s->crc = crc;
- s->crc_valid = 1;
-}
-
-void *grab_file(const char *filename, unsigned long *size)
-{
- struct stat st;
- void *map = MAP_FAILED;
- int fd;
-
- fd = open(filename, O_RDONLY);
- if (fd < 0)
- return NULL;
- if (fstat(fd, &st))
- goto failed;
-
- *size = st.st_size;
- map = mmap(NULL, *size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
-
-failed:
- close(fd);
- if (map == MAP_FAILED)
- return NULL;
- return map;
-}
-
-/**
- * Return a copy of the next line in a mmap'ed file.
- * spaces in the beginning of the line is trimmed away.
- * Return a pointer to a static buffer.
- **/
-char *get_next_line(unsigned long *pos, void *file, unsigned long size)
-{
- static char line[4096];
- int skip = 1;
- size_t len = 0;
- signed char *p = (signed char *)file + *pos;
- char *s = line;
-
- for (; *pos < size ; (*pos)++) {
- if (skip && isspace(*p)) {
- p++;
- continue;
- }
- skip = 0;
- if (*p != '\n' && (*pos < size)) {
- len++;
- *s++ = *p++;
- if (len > 4095)
- break; /* Too long, stop */
- } else {
- /* End of string */
- *s = '\0';
- return line;
- }
- }
- /* End of buffer */
- return NULL;
-}
-
-void release_file(void *file, unsigned long size)
-{
- munmap(file, size);
-}
-
-static int parse_elf(struct elf_info *info, const char *filename)
-{
- unsigned int i;
- Elf_Ehdr *hdr;
- Elf_Shdr *sechdrs;
- Elf_Sym *sym;
- const char *secstrings;
- unsigned int symtab_idx = ~0U, symtab_shndx_idx = ~0U;
-
- hdr = grab_file(filename, &info->size);
- if (!hdr) {
- if (ignore_missing_files) {
- fprintf(stderr, "%s: %s (ignored)\n", filename,
- strerror(errno));
- return 0;
- }
- perror(filename);
- exit(1);
- }
- info->hdr = hdr;
- if (info->size < sizeof(*hdr)) {
- /* file too small, assume this is an empty .o file */
- return 0;
- }
- /* Is this a valid ELF file? */
- if ((hdr->e_ident[EI_MAG0] != ELFMAG0) ||
- (hdr->e_ident[EI_MAG1] != ELFMAG1) ||
- (hdr->e_ident[EI_MAG2] != ELFMAG2) ||
- (hdr->e_ident[EI_MAG3] != ELFMAG3)) {
- /* Not an ELF file - silently ignore it */
- return 0;
- }
- /* Fix endianness in ELF header */
- hdr->e_type = TO_NATIVE(hdr->e_type);
- hdr->e_machine = TO_NATIVE(hdr->e_machine);
- hdr->e_version = TO_NATIVE(hdr->e_version);
- hdr->e_entry = TO_NATIVE(hdr->e_entry);
- hdr->e_phoff = TO_NATIVE(hdr->e_phoff);
- hdr->e_shoff = TO_NATIVE(hdr->e_shoff);
- hdr->e_flags = TO_NATIVE(hdr->e_flags);
- hdr->e_ehsize = TO_NATIVE(hdr->e_ehsize);
- hdr->e_phentsize = TO_NATIVE(hdr->e_phentsize);
- hdr->e_phnum = TO_NATIVE(hdr->e_phnum);
- hdr->e_shentsize = TO_NATIVE(hdr->e_shentsize);
- hdr->e_shnum = TO_NATIVE(hdr->e_shnum);
- hdr->e_shstrndx = TO_NATIVE(hdr->e_shstrndx);
- sechdrs = (void *)hdr + hdr->e_shoff;
- info->sechdrs = sechdrs;
-
- /* Check if file offset is correct */
- if (hdr->e_shoff > info->size) {
- fatal("section header offset=%lu in file '%s' is bigger than "
- "filesize=%lu\n", (unsigned long)hdr->e_shoff,
- filename, info->size);
- return 0;
- }
-
- if (hdr->e_shnum == SHN_UNDEF) {
- /*
- * There are more than 64k sections,
- * read count from .sh_size.
- */
- info->num_sections = TO_NATIVE(sechdrs[0].sh_size);
- }
- else {
- info->num_sections = hdr->e_shnum;
- }
- if (hdr->e_shstrndx == SHN_XINDEX) {
- info->secindex_strings = TO_NATIVE(sechdrs[0].sh_link);
- }
- else {
- info->secindex_strings = hdr->e_shstrndx;
- }
-
- /* Fix endianness in section headers */
- for (i = 0; i < info->num_sections; i++) {
- sechdrs[i].sh_name = TO_NATIVE(sechdrs[i].sh_name);
- sechdrs[i].sh_type = TO_NATIVE(sechdrs[i].sh_type);
- sechdrs[i].sh_flags = TO_NATIVE(sechdrs[i].sh_flags);
- sechdrs[i].sh_addr = TO_NATIVE(sechdrs[i].sh_addr);
- sechdrs[i].sh_offset = TO_NATIVE(sechdrs[i].sh_offset);
- sechdrs[i].sh_size = TO_NATIVE(sechdrs[i].sh_size);
- sechdrs[i].sh_link = TO_NATIVE(sechdrs[i].sh_link);
- sechdrs[i].sh_info = TO_NATIVE(sechdrs[i].sh_info);
- sechdrs[i].sh_addralign = TO_NATIVE(sechdrs[i].sh_addralign);
- sechdrs[i].sh_entsize = TO_NATIVE(sechdrs[i].sh_entsize);
- }
- /* Find symbol table. */
- secstrings = (void *)hdr + sechdrs[info->secindex_strings].sh_offset;
- for (i = 1; i < info->num_sections; i++) {
- const char *secname;
- int nobits = sechdrs[i].sh_type == SHT_NOBITS;
-
- if (!nobits && sechdrs[i].sh_offset > info->size) {
- fatal("%s is truncated. sechdrs[i].sh_offset=%lu > "
- "sizeof(*hrd)=%zu\n", filename,
- (unsigned long)sechdrs[i].sh_offset,
- sizeof(*hdr));
- return 0;
- }
- secname = secstrings + sechdrs[i].sh_name;
- if (strcmp(secname, ".modinfo") == 0) {
- if (nobits)
- fatal("%s has NOBITS .modinfo\n", filename);
- info->modinfo = (void *)hdr + sechdrs[i].sh_offset;
- info->modinfo_len = sechdrs[i].sh_size;
- } else if (strcmp(secname, "__ksymtab") == 0)
- info->export_sec = i;
- else if (strcmp(secname, "__ksymtab_unused") == 0)
- info->export_unused_sec = i;
- else if (strcmp(secname, "__ksymtab_gpl") == 0)
- info->export_gpl_sec = i;
- else if (strcmp(secname, "__ksymtab_unused_gpl") == 0)
- info->export_unused_gpl_sec = i;
- else if (strcmp(secname, "__ksymtab_gpl_future") == 0)
- info->export_gpl_future_sec = i;
- else if (strcmp(secname, "__ksymtab_strings") == 0)
- info->ksymtab_strings = (void *)hdr +
- sechdrs[i].sh_offset -
- sechdrs[i].sh_addr;
-
- if (sechdrs[i].sh_type == SHT_SYMTAB) {
- unsigned int sh_link_idx;
- symtab_idx = i;
- info->symtab_start = (void *)hdr +
- sechdrs[i].sh_offset;
- info->symtab_stop = (void *)hdr +
- sechdrs[i].sh_offset + sechdrs[i].sh_size;
- sh_link_idx = sechdrs[i].sh_link;
- info->strtab = (void *)hdr +
- sechdrs[sh_link_idx].sh_offset;
- }
-
- /* 32bit section no. table? ("more than 64k sections") */
- if (sechdrs[i].sh_type == SHT_SYMTAB_SHNDX) {
- symtab_shndx_idx = i;
- info->symtab_shndx_start = (void *)hdr +
- sechdrs[i].sh_offset;
- info->symtab_shndx_stop = (void *)hdr +
- sechdrs[i].sh_offset + sechdrs[i].sh_size;
- }
- }
- if (!info->symtab_start)
- fatal("%s has no symtab?\n", filename);
-
- /* Fix endianness in symbols */
- for (sym = info->symtab_start; sym < info->symtab_stop; sym++) {
- sym->st_shndx = TO_NATIVE(sym->st_shndx);
- sym->st_name = TO_NATIVE(sym->st_name);
- sym->st_value = TO_NATIVE(sym->st_value);
- sym->st_size = TO_NATIVE(sym->st_size);
- }
-
- if (symtab_shndx_idx != ~0U) {
- Elf32_Word *p;
- if (symtab_idx != sechdrs[symtab_shndx_idx].sh_link)
- fatal("%s: SYMTAB_SHNDX has bad sh_link: %u!=%u\n",
- filename, sechdrs[symtab_shndx_idx].sh_link,
- symtab_idx);
- /* Fix endianness */
- for (p = info->symtab_shndx_start; p < info->symtab_shndx_stop;
- p++)
- *p = TO_NATIVE(*p);
- }
-
- return 1;
-}
-
-static void parse_elf_finish(struct elf_info *info)
-{
- release_file(info->hdr, info->size);
-}
-
-static int ignore_undef_symbol(struct elf_info *info, const char *symname)
-{
- /* ignore __this_module, it will be resolved shortly */
- if (strcmp(symname, "__this_module") == 0)
- return 1;
- /* ignore global offset table */
- if (strcmp(symname, "_GLOBAL_OFFSET_TABLE_") == 0)
- return 1;
- if (info->hdr->e_machine == EM_PPC)
- /* Special register function linked on all modules during final link of .ko */
- if (strstarts(symname, "_restgpr_") ||
- strstarts(symname, "_savegpr_") ||
- strstarts(symname, "_rest32gpr_") ||
- strstarts(symname, "_save32gpr_") ||
- strstarts(symname, "_restvr_") ||
- strstarts(symname, "_savevr_"))
- return 1;
- if (info->hdr->e_machine == EM_PPC64)
- /* Special register function linked on all modules during final link of .ko */
- if (strstarts(symname, "_restgpr0_") ||
- strstarts(symname, "_savegpr0_") ||
- strstarts(symname, "_restvr_") ||
- strstarts(symname, "_savevr_") ||
- strcmp(symname, ".TOC.") == 0)
- return 1;
- /* Do not ignore this symbol */
- return 0;
-}
-
-static void handle_modversions(struct module *mod, struct elf_info *info,
- Elf_Sym *sym, const char *symname)
-{
- unsigned int crc;
- enum export export;
- bool is_crc = false;
- const char *name;
-
- if ((!is_vmlinux(mod->name) || mod->is_dot_o) &&
- strstarts(symname, "__ksymtab"))
- export = export_from_secname(info, get_secindex(info, sym));
- else
- export = export_from_sec(info, get_secindex(info, sym));
-
- /* CRC'd symbol */
- if (strstarts(symname, "__crc_")) {
- is_crc = true;
- crc = (unsigned int) sym->st_value;
- if (sym->st_shndx != SHN_UNDEF && sym->st_shndx != SHN_ABS) {
- unsigned int *crcp;
-
- /* symbol points to the CRC in the ELF object */
- crcp = (void *)info->hdr + sym->st_value +
- info->sechdrs[sym->st_shndx].sh_offset -
- (info->hdr->e_type != ET_REL ?
- info->sechdrs[sym->st_shndx].sh_addr : 0);
- crc = TO_NATIVE(*crcp);
- }
- sym_update_crc(symname + strlen("__crc_"), mod, crc,
- export);
- }
-
- switch (sym->st_shndx) {
- case SHN_COMMON:
- if (strstarts(symname, "__gnu_lto_")) {
- /* Should warn here, but modpost runs before the linker */
- } else
- warn("\"%s\" [%s] is COMMON symbol\n", symname, mod->name);
- break;
- case SHN_UNDEF:
- /* undefined symbol */
- if (ELF_ST_BIND(sym->st_info) != STB_GLOBAL &&
- ELF_ST_BIND(sym->st_info) != STB_WEAK)
- break;
- if (ignore_undef_symbol(info, symname))
- break;
-/* cope with newer glibc (2.3.4 or higher) STT_ definition in elf.h */
-#if defined(STT_REGISTER) || defined(STT_SPARC_REGISTER)
-/* add compatibility with older glibc */
-#ifndef STT_SPARC_REGISTER
-#define STT_SPARC_REGISTER STT_REGISTER
-#endif
- if (info->hdr->e_machine == EM_SPARC ||
- info->hdr->e_machine == EM_SPARCV9) {
- /* Ignore register directives. */
- if (ELF_ST_TYPE(sym->st_info) == STT_SPARC_REGISTER)
- break;
- if (symname[0] == '.') {
- char *munged = NOFAIL(strdup(symname));
- munged[0] = '_';
- munged[1] = toupper(munged[1]);
- symname = munged;
- }
- }
-#endif
-
- if (is_crc) {
- const char *e = is_vmlinux(mod->name) ?"":".ko";
- warn("EXPORT symbol \"%s\" [%s%s] version generation failed, symbol will not be versioned.\n",
- symname + strlen("__crc_"), mod->name, e);
- }
- mod->unres = alloc_symbol(symname,
- ELF_ST_BIND(sym->st_info) == STB_WEAK,
- mod->unres);
- break;
- default:
- /* All exported symbols */
- if (strstarts(symname, "__ksymtab_")) {
- name = symname + strlen("__ksymtab_");
- sym_add_exported(name, mod, export);
- }
- if (strcmp(symname, "init_module") == 0)
- mod->has_init = 1;
- if (strcmp(symname, "cleanup_module") == 0)
- mod->has_cleanup = 1;
- break;
- }
-}
-
-/**
- * Parse tag=value strings from .modinfo section
- **/
-static char *next_string(char *string, unsigned long *secsize)
-{
- /* Skip non-zero chars */
- while (string[0]) {
- string++;
- if ((*secsize)-- <= 1)
- return NULL;
- }
-
- /* Skip any zero padding. */
- while (!string[0]) {
- string++;
- if ((*secsize)-- <= 1)
- return NULL;
- }
- return string;
-}
-
-static char *get_next_modinfo(struct elf_info *info, const char *tag,
- char *prev)
-{
- char *p;
- unsigned int taglen = strlen(tag);
- char *modinfo = info->modinfo;
- unsigned long size = info->modinfo_len;
-
- if (prev) {
- size -= prev - modinfo;
- modinfo = next_string(prev, &size);
- }
-
- for (p = modinfo; p; p = next_string(p, &size)) {
- if (strncmp(p, tag, taglen) == 0 && p[taglen] == '=')
- return p + taglen + 1;
- }
- return NULL;
-}
-
-static char *get_modinfo(struct elf_info *info, const char *tag)
-
-{
- return get_next_modinfo(info, tag, NULL);
-}
-
-/**
- * Test if string s ends in string sub
- * return 0 if match
- **/
-static int strrcmp(const char *s, const char *sub)
-{
- int slen, sublen;
-
- if (!s || !sub)
- return 1;
-
- slen = strlen(s);
- sublen = strlen(sub);
-
- if ((slen == 0) || (sublen == 0))
- return 1;
-
- if (sublen > slen)
- return 1;
-
- return memcmp(s + slen - sublen, sub, sublen);
-}
-
-static const char *sym_name(struct elf_info *elf, Elf_Sym *sym)
-{
- if (sym)
- return elf->strtab + sym->st_name;
- else
- return "(unknown)";
-}
-
-/* The pattern is an array of simple patterns.
- * "foo" will match an exact string equal to "foo"
- * "*foo" will match a string that ends with "foo"
- * "foo*" will match a string that begins with "foo"
- * "*foo*" will match a string that contains "foo"
- */
-static int match(const char *sym, const char * const pat[])
-{
- const char *p;
- while (*pat) {
- p = *pat++;
- const char *endp = p + strlen(p) - 1;
-
- /* "*foo*" */
- if (*p == '*' && *endp == '*') {
- char *bare = NOFAIL(strndup(p + 1, strlen(p) - 2));
- char *here = strstr(sym, bare);
-
- free(bare);
- if (here != NULL)
- return 1;
- }
- /* "*foo" */
- else if (*p == '*') {
- if (strrcmp(sym, p + 1) == 0)
- return 1;
- }
- /* "foo*" */
- else if (*endp == '*') {
- if (strncmp(sym, p, strlen(p) - 1) == 0)
- return 1;
- }
- /* no wildcards */
- else {
- if (strcmp(p, sym) == 0)
- return 1;
- }
- }
- /* no match */
- return 0;
-}
-
-/* sections that we do not want to do full section mismatch check on */
-static const char *const section_white_list[] =
-{
- ".comment*",
- ".debug*",
- ".cranges", /* sh64 */
- ".zdebug*", /* Compressed debug sections. */
- ".GCC.command.line", /* record-gcc-switches */
- ".mdebug*", /* alpha, score, mips etc. */
- ".pdr", /* alpha, score, mips etc. */
- ".stab*",
- ".note*",
- ".got*",
- ".toc*",
- ".xt.prop", /* xtensa */
- ".xt.lit", /* xtensa */
- ".arcextmap*", /* arc */
- ".gnu.linkonce.arcext*", /* arc : modules */
- ".cmem*", /* EZchip */
- ".fmt_slot*", /* EZchip */
- ".gnu.lto*",
- ".discard.*",
- NULL
-};
-
-/*
- * This is used to find sections missing the SHF_ALLOC flag.
- * The cause of this is often a section specified in assembler
- * without "ax" / "aw".
- */
-static void check_section(const char *modname, struct elf_info *elf,
- Elf_Shdr *sechdr)
-{
- const char *sec = sech_name(elf, sechdr);
-
- if (sechdr->sh_type == SHT_PROGBITS &&
- !(sechdr->sh_flags & SHF_ALLOC) &&
- !match(sec, section_white_list)) {
- warn("%s (%s): unexpected non-allocatable section.\n"
- "Did you forget to use \"ax\"/\"aw\" in a .S file?\n"
- "Note that for example <linux/init.h> contains\n"
- "section definitions for use in .S files.\n\n",
- modname, sec);
- }
-}
-
-
-
-#define ALL_INIT_DATA_SECTIONS \
- ".init.setup", ".init.rodata", ".meminit.rodata", \
- ".init.data", ".meminit.data"
-#define ALL_EXIT_DATA_SECTIONS \
- ".exit.data", ".memexit.data"
-
-#define ALL_INIT_TEXT_SECTIONS \
- ".init.text", ".meminit.text"
-#define ALL_EXIT_TEXT_SECTIONS \
- ".exit.text", ".memexit.text"
-
-#define ALL_PCI_INIT_SECTIONS \
- ".pci_fixup_early", ".pci_fixup_header", ".pci_fixup_final", \
- ".pci_fixup_enable", ".pci_fixup_resume", \
- ".pci_fixup_resume_early", ".pci_fixup_suspend"
-
-#define ALL_XXXINIT_SECTIONS MEM_INIT_SECTIONS
-#define ALL_XXXEXIT_SECTIONS MEM_EXIT_SECTIONS
-
-#define ALL_INIT_SECTIONS INIT_SECTIONS, ALL_XXXINIT_SECTIONS
-#define ALL_EXIT_SECTIONS EXIT_SECTIONS, ALL_XXXEXIT_SECTIONS
-
-#define DATA_SECTIONS ".data", ".data.rel"
-#define TEXT_SECTIONS ".text", ".text.unlikely", ".sched.text", \
- ".kprobes.text", ".cpuidle.text", ".noinstr.text"
-#define OTHER_TEXT_SECTIONS ".ref.text", ".head.text", ".spinlock.text", \
- ".fixup", ".entry.text", ".exception.text", ".text.*", \
- ".coldtext"
-
-#define INIT_SECTIONS ".init.*"
-#define MEM_INIT_SECTIONS ".meminit.*"
-
-#define EXIT_SECTIONS ".exit.*"
-#define MEM_EXIT_SECTIONS ".memexit.*"
-
-#define ALL_TEXT_SECTIONS ALL_INIT_TEXT_SECTIONS, ALL_EXIT_TEXT_SECTIONS, \
- TEXT_SECTIONS, OTHER_TEXT_SECTIONS
-
-/* init data sections */
-static const char *const init_data_sections[] =
- { ALL_INIT_DATA_SECTIONS, NULL };
-
-/* all init sections */
-static const char *const init_sections[] = { ALL_INIT_SECTIONS, NULL };
-
-/* All init and exit sections (code + data) */
-static const char *const init_exit_sections[] =
- {ALL_INIT_SECTIONS, ALL_EXIT_SECTIONS, NULL };
-
-/* all text sections */
-static const char *const text_sections[] = { ALL_TEXT_SECTIONS, NULL };
-
-/* data section */
-static const char *const data_sections[] = { DATA_SECTIONS, NULL };
-
-
-/* symbols in .data that may refer to init/exit sections */
-#define DEFAULT_SYMBOL_WHITE_LIST \
- "*driver", \
- "*_template", /* scsi uses *_template a lot */ \
- "*_timer", /* arm uses ops structures named _timer a lot */ \
- "*_sht", /* scsi also used *_sht to some extent */ \
- "*_ops", \
- "*_probe", \
- "*_probe_one", \
- "*_console"
-
-static const char *const head_sections[] = { ".head.text*", NULL };
-static const char *const linker_symbols[] =
- { "__init_begin", "_sinittext", "_einittext", NULL };
-static const char *const optim_symbols[] = { "*.constprop.*", NULL };
-
-enum mismatch {
- TEXT_TO_ANY_INIT,
- DATA_TO_ANY_INIT,
- TEXT_TO_ANY_EXIT,
- DATA_TO_ANY_EXIT,
- XXXINIT_TO_SOME_INIT,
- XXXEXIT_TO_SOME_EXIT,
- ANY_INIT_TO_ANY_EXIT,
- ANY_EXIT_TO_ANY_INIT,
- EXPORT_TO_INIT_EXIT,
- EXTABLE_TO_NON_TEXT,
-};
-
-/**
- * Describe how to match sections on different criterias:
- *
- * @fromsec: Array of sections to be matched.
- *
- * @bad_tosec: Relocations applied to a section in @fromsec to a section in
- * this array is forbidden (black-list). Can be empty.
- *
- * @good_tosec: Relocations applied to a section in @fromsec must be
- * targetting sections in this array (white-list). Can be empty.
- *
- * @mismatch: Type of mismatch.
- *
- * @symbol_white_list: Do not match a relocation to a symbol in this list
- * even if it is targetting a section in @bad_to_sec.
- *
- * @handler: Specific handler to call when a match is found. If NULL,
- * default_mismatch_handler() will be called.
- *
- */
-struct sectioncheck {
- const char *fromsec[20];
- const char *bad_tosec[20];
- const char *good_tosec[20];
- enum mismatch mismatch;
- const char *symbol_white_list[20];
- void (*handler)(const char *modname, struct elf_info *elf,
- const struct sectioncheck* const mismatch,
- Elf_Rela *r, Elf_Sym *sym, const char *fromsec);
-
-};
-
-static void extable_mismatch_handler(const char *modname, struct elf_info *elf,
- const struct sectioncheck* const mismatch,
- Elf_Rela *r, Elf_Sym *sym,
- const char *fromsec);
-
-static const struct sectioncheck sectioncheck[] = {
-/* Do not reference init/exit code/data from
- * normal code and data
- */
-{
- .fromsec = { TEXT_SECTIONS, NULL },
- .bad_tosec = { ALL_INIT_SECTIONS, NULL },
- .mismatch = TEXT_TO_ANY_INIT,
- .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
-},
-{
- .fromsec = { DATA_SECTIONS, NULL },
- .bad_tosec = { ALL_XXXINIT_SECTIONS, NULL },
- .mismatch = DATA_TO_ANY_INIT,
- .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
-},
-{
- .fromsec = { DATA_SECTIONS, NULL },
- .bad_tosec = { INIT_SECTIONS, NULL },
- .mismatch = DATA_TO_ANY_INIT,
- .symbol_white_list = {
- "*_template", "*_timer", "*_sht", "*_ops",
- "*_probe", "*_probe_one", "*_console", NULL
- },
-},
-{
- .fromsec = { TEXT_SECTIONS, NULL },
- .bad_tosec = { ALL_EXIT_SECTIONS, NULL },
- .mismatch = TEXT_TO_ANY_EXIT,
- .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
-},
-{
- .fromsec = { DATA_SECTIONS, NULL },
- .bad_tosec = { ALL_EXIT_SECTIONS, NULL },
- .mismatch = DATA_TO_ANY_EXIT,
- .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
-},
-/* Do not reference init code/data from meminit code/data */
-{
- .fromsec = { ALL_XXXINIT_SECTIONS, NULL },
- .bad_tosec = { INIT_SECTIONS, NULL },
- .mismatch = XXXINIT_TO_SOME_INIT,
- .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
-},
-/* Do not reference exit code/data from memexit code/data */
-{
- .fromsec = { ALL_XXXEXIT_SECTIONS, NULL },
- .bad_tosec = { EXIT_SECTIONS, NULL },
- .mismatch = XXXEXIT_TO_SOME_EXIT,
- .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
-},
-/* Do not use exit code/data from init code */
-{
- .fromsec = { ALL_INIT_SECTIONS, NULL },
- .bad_tosec = { ALL_EXIT_SECTIONS, NULL },
- .mismatch = ANY_INIT_TO_ANY_EXIT,
- .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
-},
-/* Do not use init code/data from exit code */
-{
- .fromsec = { ALL_EXIT_SECTIONS, NULL },
- .bad_tosec = { ALL_INIT_SECTIONS, NULL },
- .mismatch = ANY_EXIT_TO_ANY_INIT,
- .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
-},
-{
- .fromsec = { ALL_PCI_INIT_SECTIONS, NULL },
- .bad_tosec = { INIT_SECTIONS, NULL },
- .mismatch = ANY_INIT_TO_ANY_EXIT,
- .symbol_white_list = { NULL },
-},
-/* Do not export init/exit functions or data */
-{
- .fromsec = { "___ksymtab*", NULL },
- .bad_tosec = { INIT_SECTIONS, EXIT_SECTIONS, NULL },
- .mismatch = EXPORT_TO_INIT_EXIT,
- .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
-},
-{
- .fromsec = { "__ex_table", NULL },
- /* If you're adding any new black-listed sections in here, consider
- * adding a special 'printer' for them in scripts/check_extable.
- */
- .bad_tosec = { ".altinstr_replacement", NULL },
- .good_tosec = {ALL_TEXT_SECTIONS , NULL},
- .mismatch = EXTABLE_TO_NON_TEXT,
- .handler = extable_mismatch_handler,
-}
-};
-
-static const struct sectioncheck *section_mismatch(
- const char *fromsec, const char *tosec)
-{
- int i;
- int elems = sizeof(sectioncheck) / sizeof(struct sectioncheck);
- const struct sectioncheck *check = §ioncheck[0];
-
- /*
- * The target section could be the SHT_NUL section when we're
- * handling relocations to un-resolved symbols, trying to match it
- * doesn't make much sense and causes build failures on parisc
- * architectures.
- */
- if (*tosec == '\0')
- return NULL;
-
- for (i = 0; i < elems; i++) {
- if (match(fromsec, check->fromsec)) {
- if (check->bad_tosec[0] && match(tosec, check->bad_tosec))
- return check;
- if (check->good_tosec[0] && !match(tosec, check->good_tosec))
- return check;
- }
- check++;
- }
- return NULL;
-}
-
-/**
- * Whitelist to allow certain references to pass with no warning.
- *
- * Pattern 1:
- * If a module parameter is declared __initdata and permissions=0
- * then this is legal despite the warning generated.
- * We cannot see value of permissions here, so just ignore
- * this pattern.
- * The pattern is identified by:
- * tosec = .init.data
- * fromsec = .data*
- * atsym =__param*
- *
- * Pattern 1a:
- * module_param_call() ops can refer to __init set function if permissions=0
- * The pattern is identified by:
- * tosec = .init.text
- * fromsec = .data*
- * atsym = __param_ops_*
- *
- * Pattern 2:
- * Many drivers utilise a *driver container with references to
- * add, remove, probe functions etc.
- * the pattern is identified by:
- * tosec = init or exit section
- * fromsec = data section
- * atsym = *driver, *_template, *_sht, *_ops, *_probe,
- * *probe_one, *_console, *_timer
- *
- * Pattern 3:
- * Whitelist all references from .head.text to any init section
- *
- * Pattern 4:
- * Some symbols belong to init section but still it is ok to reference
- * these from non-init sections as these symbols don't have any memory
- * allocated for them and symbol address and value are same. So even
- * if init section is freed, its ok to reference those symbols.
- * For ex. symbols marking the init section boundaries.
- * This pattern is identified by
- * refsymname = __init_begin, _sinittext, _einittext
- *
- * Pattern 5:
- * GCC may optimize static inlines when fed constant arg(s) resulting
- * in functions like cpumask_empty() -- generating an associated symbol
- * cpumask_empty.constprop.3 that appears in the audit. If the const that
- * is passed in comes from __init, like say nmi_ipi_mask, we get a
- * meaningless section warning. May need to add isra symbols too...
- * This pattern is identified by
- * tosec = init section
- * fromsec = text section
- * refsymname = *.constprop.*
- *
- * Pattern 6:
- * Hide section mismatch warnings for ELF local symbols. The goal
- * is to eliminate false positive modpost warnings caused by
- * compiler-generated ELF local symbol names such as ".LANCHOR1".
- * Autogenerated symbol names bypass modpost's "Pattern 2"
- * whitelisting, which relies on pattern-matching against symbol
- * names to work. (One situation where gcc can autogenerate ELF
- * local symbols is when "-fsection-anchors" is used.)
- **/
-static int secref_whitelist(const struct sectioncheck *mismatch,
- const char *fromsec, const char *fromsym,
- const char *tosec, const char *tosym)
-{
- /* Check for pattern 1 */
- if (match(tosec, init_data_sections) &&
- match(fromsec, data_sections) &&
- strstarts(fromsym, "__param"))
- return 0;
-
- /* Check for pattern 1a */
- if (strcmp(tosec, ".init.text") == 0 &&
- match(fromsec, data_sections) &&
- strstarts(fromsym, "__param_ops_"))
- return 0;
-
- /* Check for pattern 2 */
- if (match(tosec, init_exit_sections) &&
- match(fromsec, data_sections) &&
- match(fromsym, mismatch->symbol_white_list))
- return 0;
-
- /* Check for pattern 3 */
- if (match(fromsec, head_sections) &&
- match(tosec, init_sections))
- return 0;
-
- /* Check for pattern 4 */
- if (match(tosym, linker_symbols))
- return 0;
-
- /* Check for pattern 5 */
- if (match(fromsec, text_sections) &&
- match(tosec, init_sections) &&
- match(fromsym, optim_symbols))
- return 0;
-
- /* Check for pattern 6 */
- if (strstarts(fromsym, ".L"))
- return 0;
-
- return 1;
-}
-
-static inline int is_arm_mapping_symbol(const char *str)
-{
- return str[0] == '$' &&
- (str[1] == 'a' || str[1] == 'd' || str[1] == 't' || str[1] == 'x')
- && (str[2] == '\0' || str[2] == '.');
-}
-
-/*
- * If there's no name there, ignore it; likewise, ignore it if it's
- * one of the magic symbols emitted used by current ARM tools.
- *
- * Otherwise if find_symbols_between() returns those symbols, they'll
- * fail the whitelist tests and cause lots of false alarms ... fixable
- * only by merging __exit and __init sections into __text, bloating
- * the kernel (which is especially evil on embedded platforms).
- */
-static inline int is_valid_name(struct elf_info *elf, Elf_Sym *sym)
-{
- const char *name = elf->strtab + sym->st_name;
-
- if (!name || !strlen(name))
- return 0;
- return !is_arm_mapping_symbol(name);
-}
-
-/**
- * Find symbol based on relocation record info.
- * In some cases the symbol supplied is a valid symbol so
- * return refsym. If st_name != 0 we assume this is a valid symbol.
- * In other cases the symbol needs to be looked up in the symbol table
- * based on section and address.
- * **/
-static Elf_Sym *find_elf_symbol(struct elf_info *elf, Elf64_Sword addr,
- Elf_Sym *relsym)
-{
- Elf_Sym *sym;
- Elf_Sym *near = NULL;
- Elf64_Sword distance = 20;
- Elf64_Sword d;
- unsigned int relsym_secindex;
-
- if (relsym->st_name != 0)
- return relsym;
-
- relsym_secindex = get_secindex(elf, relsym);
- for (sym = elf->symtab_start; sym < elf->symtab_stop; sym++) {
- if (get_secindex(elf, sym) != relsym_secindex)
- continue;
- if (ELF_ST_TYPE(sym->st_info) == STT_SECTION)
- continue;
- if (!is_valid_name(elf, sym))
- continue;
- if (sym->st_value == addr)
- return sym;
- /* Find a symbol nearby - addr are maybe negative */
- d = sym->st_value - addr;
- if (d < 0)
- d = addr - sym->st_value;
- if (d < distance) {
- distance = d;
- near = sym;
- }
- }
- /* We need a close match */
- if (distance < 20)
- return near;
- else
- return NULL;
-}
-
-/*
- * Find symbols before or equal addr and after addr - in the section sec.
- * If we find two symbols with equal offset prefer one with a valid name.
- * The ELF format may have a better way to detect what type of symbol
- * it is, but this works for now.
- **/
-static Elf_Sym *find_elf_symbol2(struct elf_info *elf, Elf_Addr addr,
- const char *sec)
-{
- Elf_Sym *sym;
- Elf_Sym *near = NULL;
- Elf_Addr distance = ~0;
-
- for (sym = elf->symtab_start; sym < elf->symtab_stop; sym++) {
- const char *symsec;
-
- if (is_shndx_special(sym->st_shndx))
- continue;
- symsec = sec_name(elf, get_secindex(elf, sym));
- if (strcmp(symsec, sec) != 0)
- continue;
- if (!is_valid_name(elf, sym))
- continue;
- if (sym->st_value <= addr) {
- if ((addr - sym->st_value) < distance) {
- distance = addr - sym->st_value;
- near = sym;
- } else if ((addr - sym->st_value) == distance) {
- near = sym;
- }
- }
- }
- return near;
-}
-
-/*
- * Convert a section name to the function/data attribute
- * .init.text => __init
- * .memexitconst => __memconst
- * etc.
- *
- * The memory of returned value has been allocated on a heap. The user of this
- * method should free it after usage.
-*/
-static char *sec2annotation(const char *s)
-{
- if (match(s, init_exit_sections)) {
- char *p = NOFAIL(malloc(20));
- char *r = p;
-
- *p++ = '_';
- *p++ = '_';
- if (*s == '.')
- s++;
- while (*s && *s != '.')
- *p++ = *s++;
- *p = '\0';
- if (*s == '.')
- s++;
- if (strstr(s, "rodata") != NULL)
- strcat(p, "const ");
- else if (strstr(s, "data") != NULL)
- strcat(p, "data ");
- else
- strcat(p, " ");
- return r;
- } else {
- return NOFAIL(strdup(""));
- }
-}
-
-static int is_function(Elf_Sym *sym)
-{
- if (sym)
- return ELF_ST_TYPE(sym->st_info) == STT_FUNC;
- else
- return -1;
-}
-
-static void print_section_list(const char * const list[20])
-{
- const char *const *s = list;
-
- while (*s) {
- fprintf(stderr, "%s", *s);
- s++;
- if (*s)
- fprintf(stderr, ", ");
- }
- fprintf(stderr, "\n");
-}
-
-static inline void get_pretty_name(int is_func, const char** name, const char** name_p)
-{
- switch (is_func) {
- case 0: *name = "variable"; *name_p = ""; break;
- case 1: *name = "function"; *name_p = "()"; break;
- default: *name = "(unknown reference)"; *name_p = ""; break;
- }
-}
-
-/*
- * Print a warning about a section mismatch.
- * Try to find symbols near it so user can find it.
- * Check whitelist before warning - it may be a false positive.
- */
-static void report_sec_mismatch(const char *modname,
- const struct sectioncheck *mismatch,
- const char *fromsec,
- unsigned long long fromaddr,
- const char *fromsym,
- int from_is_func,
- const char *tosec, const char *tosym,
- int to_is_func)
-{
- const char *from, *from_p;
- const char *to, *to_p;
- char *prl_from;
- char *prl_to;
-
- sec_mismatch_count++;
-
- get_pretty_name(from_is_func, &from, &from_p);
- get_pretty_name(to_is_func, &to, &to_p);
-
- warn("%s(%s+0x%llx): Section mismatch in reference from the %s %s%s "
- "to the %s %s:%s%s\n",
- modname, fromsec, fromaddr, from, fromsym, from_p, to, tosec,
- tosym, to_p);
-
- switch (mismatch->mismatch) {
- case TEXT_TO_ANY_INIT:
- prl_from = sec2annotation(fromsec);
- prl_to = sec2annotation(tosec);
- fprintf(stderr,
- "The function %s%s() references\n"
- "the %s %s%s%s.\n"
- "This is often because %s lacks a %s\n"
- "annotation or the annotation of %s is wrong.\n",
- prl_from, fromsym,
- to, prl_to, tosym, to_p,
- fromsym, prl_to, tosym);
- free(prl_from);
- free(prl_to);
- break;
- case DATA_TO_ANY_INIT: {
- prl_to = sec2annotation(tosec);
- fprintf(stderr,
- "The variable %s references\n"
- "the %s %s%s%s\n"
- "If the reference is valid then annotate the\n"
- "variable with __init* or __refdata (see linux/init.h) "
- "or name the variable:\n",
- fromsym, to, prl_to, tosym, to_p);
- print_section_list(mismatch->symbol_white_list);
- free(prl_to);
- break;
- }
- case TEXT_TO_ANY_EXIT:
- prl_to = sec2annotation(tosec);
- fprintf(stderr,
- "The function %s() references a %s in an exit section.\n"
- "Often the %s %s%s has valid usage outside the exit section\n"
- "and the fix is to remove the %sannotation of %s.\n",
- fromsym, to, to, tosym, to_p, prl_to, tosym);
- free(prl_to);
- break;
- case DATA_TO_ANY_EXIT: {
- prl_to = sec2annotation(tosec);
- fprintf(stderr,
- "The variable %s references\n"
- "the %s %s%s%s\n"
- "If the reference is valid then annotate the\n"
- "variable with __exit* (see linux/init.h) or "
- "name the variable:\n",
- fromsym, to, prl_to, tosym, to_p);
- print_section_list(mismatch->symbol_white_list);
- free(prl_to);
- break;
- }
- case XXXINIT_TO_SOME_INIT:
- case XXXEXIT_TO_SOME_EXIT:
- prl_from = sec2annotation(fromsec);
- prl_to = sec2annotation(tosec);
- fprintf(stderr,
- "The %s %s%s%s references\n"
- "a %s %s%s%s.\n"
- "If %s is only used by %s then\n"
- "annotate %s with a matching annotation.\n",
- from, prl_from, fromsym, from_p,
- to, prl_to, tosym, to_p,
- tosym, fromsym, tosym);
- free(prl_from);
- free(prl_to);
- break;
- case ANY_INIT_TO_ANY_EXIT:
- prl_from = sec2annotation(fromsec);
- prl_to = sec2annotation(tosec);
- fprintf(stderr,
- "The %s %s%s%s references\n"
- "a %s %s%s%s.\n"
- "This is often seen when error handling "
- "in the init function\n"
- "uses functionality in the exit path.\n"
- "The fix is often to remove the %sannotation of\n"
- "%s%s so it may be used outside an exit section.\n",
- from, prl_from, fromsym, from_p,
- to, prl_to, tosym, to_p,
- prl_to, tosym, to_p);
- free(prl_from);
- free(prl_to);
- break;
- case ANY_EXIT_TO_ANY_INIT:
- prl_from = sec2annotation(fromsec);
- prl_to = sec2annotation(tosec);
- fprintf(stderr,
- "The %s %s%s%s references\n"
- "a %s %s%s%s.\n"
- "This is often seen when error handling "
- "in the exit function\n"
- "uses functionality in the init path.\n"
- "The fix is often to remove the %sannotation of\n"
- "%s%s so it may be used outside an init section.\n",
- from, prl_from, fromsym, from_p,
- to, prl_to, tosym, to_p,
- prl_to, tosym, to_p);
- free(prl_from);
- free(prl_to);
- break;
- case EXPORT_TO_INIT_EXIT:
- prl_to = sec2annotation(tosec);
- fprintf(stderr,
- "The symbol %s is exported and annotated %s\n"
- "Fix this by removing the %sannotation of %s "
- "or drop the export.\n",
- tosym, prl_to, prl_to, tosym);
- free(prl_to);
- break;
- case EXTABLE_TO_NON_TEXT:
- fatal("There's a special handler for this mismatch type, "
- "we should never get here.");
- break;
- }
- fprintf(stderr, "\n");
-}
-
-static void default_mismatch_handler(const char *modname, struct elf_info *elf,
- const struct sectioncheck* const mismatch,
- Elf_Rela *r, Elf_Sym *sym, const char *fromsec)
-{
- const char *tosec;
- Elf_Sym *to;
- Elf_Sym *from;
- const char *tosym;
- const char *fromsym;
-
- from = find_elf_symbol2(elf, r->r_offset, fromsec);
- fromsym = sym_name(elf, from);
-
- if (strstarts(fromsym, "reference___initcall"))
- return;
-
- tosec = sec_name(elf, get_secindex(elf, sym));
- to = find_elf_symbol(elf, r->r_addend, sym);
- tosym = sym_name(elf, to);
-
- /* check whitelist - we may ignore it */
- if (secref_whitelist(mismatch,
- fromsec, fromsym, tosec, tosym)) {
- report_sec_mismatch(modname, mismatch,
- fromsec, r->r_offset, fromsym,
- is_function(from), tosec, tosym,
- is_function(to));
- }
-}
-
-static int is_executable_section(struct elf_info* elf, unsigned int section_index)
-{
- if (section_index > elf->num_sections)
- fatal("section_index is outside elf->num_sections!\n");
-
- return ((elf->sechdrs[section_index].sh_flags & SHF_EXECINSTR) == SHF_EXECINSTR);
-}
-
-/*
- * We rely on a gross hack in section_rel[a]() calling find_extable_entry_size()
- * to know the sizeof(struct exception_table_entry) for the target architecture.
- */
-static unsigned int extable_entry_size = 0;
-static void find_extable_entry_size(const char* const sec, const Elf_Rela* r)
-{
- /*
- * If we're currently checking the second relocation within __ex_table,
- * that relocation offset tells us the offsetof(struct
- * exception_table_entry, fixup) which is equal to sizeof(struct
- * exception_table_entry) divided by two. We use that to our advantage
- * since there's no portable way to get that size as every architecture
- * seems to go with different sized types. Not pretty but better than
- * hard-coding the size for every architecture..
- */
- if (!extable_entry_size)
- extable_entry_size = r->r_offset * 2;
-}
-
-static inline bool is_extable_fault_address(Elf_Rela *r)
-{
- /*
- * extable_entry_size is only discovered after we've handled the
- * _second_ relocation in __ex_table, so only abort when we're not
- * handling the first reloc and extable_entry_size is zero.
- */
- if (r->r_offset && extable_entry_size == 0)
- fatal("extable_entry size hasn't been discovered!\n");
-
- return ((r->r_offset == 0) ||
- (r->r_offset % extable_entry_size == 0));
-}
-
-#define is_second_extable_reloc(Start, Cur, Sec) \
- (((Cur) == (Start) + 1) && (strcmp("__ex_table", (Sec)) == 0))
-
-static void report_extable_warnings(const char* modname, struct elf_info* elf,
- const struct sectioncheck* const mismatch,
- Elf_Rela* r, Elf_Sym* sym,
- const char* fromsec, const char* tosec)
-{
- Elf_Sym* fromsym = find_elf_symbol2(elf, r->r_offset, fromsec);
- const char* fromsym_name = sym_name(elf, fromsym);
- Elf_Sym* tosym = find_elf_symbol(elf, r->r_addend, sym);
- const char* tosym_name = sym_name(elf, tosym);
- const char* from_pretty_name;
- const char* from_pretty_name_p;
- const char* to_pretty_name;
- const char* to_pretty_name_p;
-
- get_pretty_name(is_function(fromsym),
- &from_pretty_name, &from_pretty_name_p);
- get_pretty_name(is_function(tosym),
- &to_pretty_name, &to_pretty_name_p);
-
- warn("%s(%s+0x%lx): Section mismatch in reference"
- " from the %s %s%s to the %s %s:%s%s\n",
- modname, fromsec, (long)r->r_offset, from_pretty_name,
- fromsym_name, from_pretty_name_p,
- to_pretty_name, tosec, tosym_name, to_pretty_name_p);
-
- if (!match(tosec, mismatch->bad_tosec) &&
- is_executable_section(elf, get_secindex(elf, sym)))
- fprintf(stderr,
- "The relocation at %s+0x%lx references\n"
- "section \"%s\" which is not in the list of\n"
- "authorized sections. If you're adding a new section\n"
- "and/or if this reference is valid, add \"%s\" to the\n"
- "list of authorized sections to jump to on fault.\n"
- "This can be achieved by adding \"%s\" to \n"
- "OTHER_TEXT_SECTIONS in scripts/mod/modpost.c.\n",
- fromsec, (long)r->r_offset, tosec, tosec, tosec);
-}
-
-static void extable_mismatch_handler(const char* modname, struct elf_info *elf,
- const struct sectioncheck* const mismatch,
- Elf_Rela* r, Elf_Sym* sym,
- const char *fromsec)
-{
- const char* tosec = sec_name(elf, get_secindex(elf, sym));
-
- sec_mismatch_count++;
-
- report_extable_warnings(modname, elf, mismatch, r, sym, fromsec, tosec);
-
- if (match(tosec, mismatch->bad_tosec))
- fatal("The relocation at %s+0x%lx references\n"
- "section \"%s\" which is black-listed.\n"
- "Something is seriously wrong and should be fixed.\n"
- "You might get more information about where this is\n"
- "coming from by using scripts/check_extable.sh %s\n",
- fromsec, (long)r->r_offset, tosec, modname);
- else if (!is_executable_section(elf, get_secindex(elf, sym))) {
- if (is_extable_fault_address(r))
- fatal("The relocation at %s+0x%lx references\n"
- "section \"%s\" which is not executable, IOW\n"
- "it is not possible for the kernel to fault\n"
- "at that address. Something is seriously wrong\n"
- "and should be fixed.\n",
- fromsec, (long)r->r_offset, tosec);
- else
- fatal("The relocation at %s+0x%lx references\n"
- "section \"%s\" which is not executable, IOW\n"
- "the kernel will fault if it ever tries to\n"
- "jump to it. Something is seriously wrong\n"
- "and should be fixed.\n",
- fromsec, (long)r->r_offset, tosec);
- }
-}
-
-static void check_section_mismatch(const char *modname, struct elf_info *elf,
- Elf_Rela *r, Elf_Sym *sym, const char *fromsec)
-{
- const char *tosec = sec_name(elf, get_secindex(elf, sym));
- const struct sectioncheck *mismatch = section_mismatch(fromsec, tosec);
-
- if (mismatch) {
- if (mismatch->handler)
- mismatch->handler(modname, elf, mismatch,
- r, sym, fromsec);
- else
- default_mismatch_handler(modname, elf, mismatch,
- r, sym, fromsec);
- }
-}
-
-static unsigned int *reloc_location(struct elf_info *elf,
- Elf_Shdr *sechdr, Elf_Rela *r)
-{
- Elf_Shdr *sechdrs = elf->sechdrs;
- int section = sechdr->sh_info;
-
- return (void *)elf->hdr + sechdrs[section].sh_offset +
- r->r_offset;
-}
-
-static int addend_386_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r)
-{
- unsigned int r_typ = ELF_R_TYPE(r->r_info);
- unsigned int *location = reloc_location(elf, sechdr, r);
-
- switch (r_typ) {
- case R_386_32:
- r->r_addend = TO_NATIVE(*location);
- break;
- case R_386_PC32:
- r->r_addend = TO_NATIVE(*location) + 4;
- /* For CONFIG_RELOCATABLE=y */
- if (elf->hdr->e_type == ET_EXEC)
- r->r_addend += r->r_offset;
- break;
- }
- return 0;
-}
-
-#ifndef R_ARM_CALL
-#define R_ARM_CALL 28
-#endif
-#ifndef R_ARM_JUMP24
-#define R_ARM_JUMP24 29
-#endif
-
-#ifndef R_ARM_THM_CALL
-#define R_ARM_THM_CALL 10
-#endif
-#ifndef R_ARM_THM_JUMP24
-#define R_ARM_THM_JUMP24 30
-#endif
-#ifndef R_ARM_THM_JUMP19
-#define R_ARM_THM_JUMP19 51
-#endif
-
-static int addend_arm_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r)
-{
- unsigned int r_typ = ELF_R_TYPE(r->r_info);
-
- switch (r_typ) {
- case R_ARM_ABS32:
- /* From ARM ABI: (S + A) | T */
- r->r_addend = (int)(long)
- (elf->symtab_start + ELF_R_SYM(r->r_info));
- break;
- case R_ARM_PC24:
- case R_ARM_CALL:
- case R_ARM_JUMP24:
- case R_ARM_THM_CALL:
- case R_ARM_THM_JUMP24:
- case R_ARM_THM_JUMP19:
- /* From ARM ABI: ((S + A) | T) - P */
- r->r_addend = (int)(long)(elf->hdr +
- sechdr->sh_offset +
- (r->r_offset - sechdr->sh_addr));
- break;
- default:
- return 1;
- }
- return 0;
-}
-
-static int addend_mips_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r)
-{
- unsigned int r_typ = ELF_R_TYPE(r->r_info);
- unsigned int *location = reloc_location(elf, sechdr, r);
- unsigned int inst;
-
- if (r_typ == R_MIPS_HI16)
- return 1; /* skip this */
- inst = TO_NATIVE(*location);
- switch (r_typ) {
- case R_MIPS_LO16:
- r->r_addend = inst & 0xffff;
- break;
- case R_MIPS_26:
- r->r_addend = (inst & 0x03ffffff) << 2;
- break;
- case R_MIPS_32:
- r->r_addend = inst;
- break;
- }
- return 0;
-}
-
-static void section_rela(const char *modname, struct elf_info *elf,
- Elf_Shdr *sechdr)
-{
- Elf_Sym *sym;
- Elf_Rela *rela;
- Elf_Rela r;
- unsigned int r_sym;
- const char *fromsec;
-
- Elf_Rela *start = (void *)elf->hdr + sechdr->sh_offset;
- Elf_Rela *stop = (void *)start + sechdr->sh_size;
-
- fromsec = sech_name(elf, sechdr);
- fromsec += strlen(".rela");
- /* if from section (name) is know good then skip it */
- if (match(fromsec, section_white_list))
- return;
-
- for (rela = start; rela < stop; rela++) {
- r.r_offset = TO_NATIVE(rela->r_offset);
-#if KERNEL_ELFCLASS == ELFCLASS64
- if (elf->hdr->e_machine == EM_MIPS) {
- unsigned int r_typ;
- r_sym = ELF64_MIPS_R_SYM(rela->r_info);
- r_sym = TO_NATIVE(r_sym);
- r_typ = ELF64_MIPS_R_TYPE(rela->r_info);
- r.r_info = ELF64_R_INFO(r_sym, r_typ);
- } else {
- r.r_info = TO_NATIVE(rela->r_info);
- r_sym = ELF_R_SYM(r.r_info);
- }
-#else
- r.r_info = TO_NATIVE(rela->r_info);
- r_sym = ELF_R_SYM(r.r_info);
-#endif
- r.r_addend = TO_NATIVE(rela->r_addend);
- sym = elf->symtab_start + r_sym;
- /* Skip special sections */
- if (is_shndx_special(sym->st_shndx))
- continue;
- if (is_second_extable_reloc(start, rela, fromsec))
- find_extable_entry_size(fromsec, &r);
- check_section_mismatch(modname, elf, &r, sym, fromsec);
- }
-}
-
-static void section_rel(const char *modname, struct elf_info *elf,
- Elf_Shdr *sechdr)
-{
- Elf_Sym *sym;
- Elf_Rel *rel;
- Elf_Rela r;
- unsigned int r_sym;
- const char *fromsec;
-
- Elf_Rel *start = (void *)elf->hdr + sechdr->sh_offset;
- Elf_Rel *stop = (void *)start + sechdr->sh_size;
-
- fromsec = sech_name(elf, sechdr);
- fromsec += strlen(".rel");
- /* if from section (name) is know good then skip it */
- if (match(fromsec, section_white_list))
- return;
-
- for (rel = start; rel < stop; rel++) {
- r.r_offset = TO_NATIVE(rel->r_offset);
-#if KERNEL_ELFCLASS == ELFCLASS64
- if (elf->hdr->e_machine == EM_MIPS) {
- unsigned int r_typ;
- r_sym = ELF64_MIPS_R_SYM(rel->r_info);
- r_sym = TO_NATIVE(r_sym);
- r_typ = ELF64_MIPS_R_TYPE(rel->r_info);
- r.r_info = ELF64_R_INFO(r_sym, r_typ);
- } else {
- r.r_info = TO_NATIVE(rel->r_info);
- r_sym = ELF_R_SYM(r.r_info);
- }
-#else
- r.r_info = TO_NATIVE(rel->r_info);
- r_sym = ELF_R_SYM(r.r_info);
-#endif
- r.r_addend = 0;
- switch (elf->hdr->e_machine) {
- case EM_386:
- if (addend_386_rel(elf, sechdr, &r))
- continue;
- break;
- case EM_ARM:
- if (addend_arm_rel(elf, sechdr, &r))
- continue;
- break;
- case EM_MIPS:
- if (addend_mips_rel(elf, sechdr, &r))
- continue;
- break;
- }
- sym = elf->symtab_start + r_sym;
- /* Skip special sections */
- if (is_shndx_special(sym->st_shndx))
- continue;
- if (is_second_extable_reloc(start, rel, fromsec))
- find_extable_entry_size(fromsec, &r);
- check_section_mismatch(modname, elf, &r, sym, fromsec);
- }
-}
-
-/**
- * A module includes a number of sections that are discarded
- * either when loaded or when used as built-in.
- * For loaded modules all functions marked __init and all data
- * marked __initdata will be discarded when the module has been initialized.
- * Likewise for modules used built-in the sections marked __exit
- * are discarded because __exit marked function are supposed to be called
- * only when a module is unloaded which never happens for built-in modules.
- * The check_sec_ref() function traverses all relocation records
- * to find all references to a section that reference a section that will
- * be discarded and warns about it.
- **/
-static void check_sec_ref(struct module *mod, const char *modname,
- struct elf_info *elf)
-{
- int i;
- Elf_Shdr *sechdrs = elf->sechdrs;
-
- /* Walk through all sections */
- for (i = 0; i < elf->num_sections; i++) {
- check_section(modname, elf, &elf->sechdrs[i]);
- /* We want to process only relocation sections and not .init */
- if (sechdrs[i].sh_type == SHT_RELA)
- section_rela(modname, elf, &elf->sechdrs[i]);
- else if (sechdrs[i].sh_type == SHT_REL)
- section_rel(modname, elf, &elf->sechdrs[i]);
- }
-}
-
-static char *remove_dot(char *s)
-{
- size_t n = strcspn(s, ".");
-
- if (n && s[n]) {
- size_t m = strspn(s + n + 1, "0123456789");
- if (m && (s[n + m + 1] == '.' || s[n + m + 1] == 0))
- s[n] = 0;
- }
- return s;
-}
-
-static void read_symbols(const char *modname)
-{
- const char *symname;
- char *version;
- char *license;
- char *namespace;
- struct module *mod;
- struct elf_info info = { };
- Elf_Sym *sym;
-
- if (!parse_elf(&info, modname))
- return;
-
- mod = new_module(modname);
-
- /* When there's no vmlinux, don't print warnings about
- * unresolved symbols (since there'll be too many ;) */
- if (is_vmlinux(modname)) {
- have_vmlinux = 1;
- mod->skip = 1;
- }
-
- license = get_modinfo(&info, "license");
- if (!license && !is_vmlinux(modname))
- warn("modpost: missing MODULE_LICENSE() in %s\n"
- "see include/linux/module.h for "
- "more information\n", modname);
- while (license) {
- if (license_is_gpl_compatible(license))
- mod->gpl_compatible = 1;
- else {
- mod->gpl_compatible = 0;
- break;
- }
- license = get_next_modinfo(&info, "license", license);
- }
-
- namespace = get_modinfo(&info, "import_ns");
- while (namespace) {
- add_namespace(&mod->imported_namespaces, namespace);
- namespace = get_next_modinfo(&info, "import_ns", namespace);
- }
-
- for (sym = info.symtab_start; sym < info.symtab_stop; sym++) {
- symname = remove_dot(info.strtab + sym->st_name);
-
- handle_modversions(mod, &info, sym, symname);
- handle_moddevtable(mod, &info, sym, symname);
- }
-
- /* Apply symbol namespaces from __kstrtabns_<symbol> entries. */
- for (sym = info.symtab_start; sym < info.symtab_stop; sym++) {
- symname = remove_dot(info.strtab + sym->st_name);
-
- if (strstarts(symname, "__kstrtabns_"))
- sym_update_namespace(symname + strlen("__kstrtabns_"),
- namespace_from_kstrtabns(&info,
- sym));
- }
-
- // check for static EXPORT_SYMBOL_* functions && global vars
- for (sym = info.symtab_start; sym < info.symtab_stop; sym++) {
- unsigned char bind = ELF_ST_BIND(sym->st_info);
-
- if (bind == STB_GLOBAL || bind == STB_WEAK) {
- struct symbol *s =
- find_symbol(remove_dot(info.strtab +
- sym->st_name));
-
- if (s)
- s->is_static = 0;
- }
- }
-
- if (!is_vmlinux(modname) || vmlinux_section_warnings)
- check_sec_ref(mod, modname, &info);
-
- version = get_modinfo(&info, "version");
- if (version)
- maybe_frob_rcs_version(modname, version, info.modinfo,
- version - (char *)info.hdr);
- if (version || (all_versions && !is_vmlinux(modname)))
- get_src_version(modname, mod->srcversion,
- sizeof(mod->srcversion)-1);
-
- parse_elf_finish(&info);
-
- /* Our trick to get versioning for module struct etc. - it's
- * never passed as an argument to an exported function, so
- * the automatic versioning doesn't pick it up, but it's really
- * important anyhow */
- if (modversions)
- mod->unres = alloc_symbol("module_layout", 0, mod->unres);
-}
-
-static void read_symbols_from_files(const char *filename)
-{
- FILE *in = stdin;
- char fname[PATH_MAX];
-
- if (strcmp(filename, "-") != 0) {
- in = fopen(filename, "r");
- if (!in)
- fatal("Can't open filenames file %s: %m", filename);
- }
-
- while (fgets(fname, PATH_MAX, in) != NULL) {
- if (strends(fname, "\n"))
- fname[strlen(fname)-1] = '\0';
- read_symbols(fname);
- }
-
- if (in != stdin)
- fclose(in);
-}
-
-#define SZ 500
-
-/* We first write the generated file into memory using the
- * following helper, then compare to the file on disk and
- * only update the later if anything changed */
-
-void __attribute__((format(printf, 2, 3))) buf_printf(struct buffer *buf,
- const char *fmt, ...)
-{
- char tmp[SZ];
- int len;
- va_list ap;
-
- va_start(ap, fmt);
- len = vsnprintf(tmp, SZ, fmt, ap);
- buf_write(buf, tmp, len);
- va_end(ap);
-}
-
-void buf_write(struct buffer *buf, const char *s, int len)
-{
- if (buf->size - buf->pos < len) {
- buf->size += len + SZ;
- buf->p = NOFAIL(realloc(buf->p, buf->size));
- }
- strncpy(buf->p + buf->pos, s, len);
- buf->pos += len;
-}
-
-static void check_for_gpl_usage(enum export exp, const char *m, const char *s)
-{
- const char *e = is_vmlinux(m) ?"":".ko";
-
- switch (exp) {
- case export_gpl:
- fatal("modpost: GPL-incompatible module %s%s "
- "uses GPL-only symbol '%s'\n", m, e, s);
- break;
- case export_unused_gpl:
- fatal("modpost: GPL-incompatible module %s%s "
- "uses GPL-only symbol marked UNUSED '%s'\n", m, e, s);
- break;
- case export_gpl_future:
- warn("modpost: GPL-incompatible module %s%s "
- "uses future GPL-only symbol '%s'\n", m, e, s);
- break;
- case export_plain:
- case export_unused:
- case export_unknown:
- /* ignore */
- break;
- }
-}
-
-static void check_for_unused(enum export exp, const char *m, const char *s)
-{
- const char *e = is_vmlinux(m) ?"":".ko";
-
- switch (exp) {
- case export_unused:
- case export_unused_gpl:
- warn("modpost: module %s%s "
- "uses symbol '%s' marked UNUSED\n", m, e, s);
- break;
- default:
- /* ignore */
- break;
- }
-}
-
-static int check_exports(struct module *mod)
-{
- struct symbol *s, *exp;
- int err = 0;
-
- for (s = mod->unres; s; s = s->next) {
- const char *basename;
- exp = find_symbol(s->name);
- if (!exp || exp->module == mod) {
- if (have_vmlinux && !s->weak) {
- if (warn_unresolved) {
- warn("\"%s\" [%s.ko] undefined!\n",
- s->name, mod->name);
- } else {
- merror("\"%s\" [%s.ko] undefined!\n",
- s->name, mod->name);
- err = 1;
- }
- }
- continue;
- }
- basename = strrchr(mod->name, '/');
- if (basename)
- basename++;
- else
- basename = mod->name;
-
- if (exp->namespace) {
- add_namespace(&mod->required_namespaces,
- exp->namespace);
-
- if (!write_namespace_deps &&
- !module_imports_namespace(mod, exp->namespace)) {
- warn("module %s uses symbol %s from namespace %s, but does not import it.\n",
- basename, exp->name, exp->namespace);
- }
- }
-
- if (!mod->gpl_compatible)
- check_for_gpl_usage(exp->export, basename, exp->name);
- check_for_unused(exp->export, basename, exp->name);
- }
-
- return err;
-}
-
-static int check_modname_len(struct module *mod)
-{
- const char *mod_name;
-
- mod_name = strrchr(mod->name, '/');
- if (mod_name == NULL)
- mod_name = mod->name;
- else
- mod_name++;
- if (strlen(mod_name) >= MODULE_NAME_LEN) {
- merror("module name is too long [%s.ko]\n", mod->name);
- return 1;
- }
-
- return 0;
-}
-
-/**
- * Header for the generated file
- **/
-static void add_header(struct buffer *b, struct module *mod)
-{
- buf_printf(b, "#include <linux/build-salt.h>\n");
- buf_printf(b, "#include <linux/module.h>\n");
- buf_printf(b, "#include <linux/vermagic.h>\n");
- buf_printf(b, "#include <linux/compiler.h>\n");
- buf_printf(b, "\n");
- buf_printf(b, "BUILD_SALT;\n");
- buf_printf(b, "\n");
- buf_printf(b, "MODULE_INFO(vermagic, VERMAGIC_STRING);\n");
- buf_printf(b, "MODULE_INFO(name, KBUILD_MODNAME);\n");
- buf_printf(b, "\n");
- buf_printf(b, "__visible struct module __this_module\n");
- buf_printf(b, "__section(.gnu.linkonce.this_module) = {\n");
- buf_printf(b, "\t.name = KBUILD_MODNAME,\n");
- if (mod->has_init)
- buf_printf(b, "\t.init = init_module,\n");
- if (mod->has_cleanup)
- buf_printf(b, "#ifdef CONFIG_MODULE_UNLOAD\n"
- "\t.exit = cleanup_module,\n"
- "#endif\n");
- buf_printf(b, "\t.arch = MODULE_ARCH_INIT,\n");
- buf_printf(b, "};\n");
-}
-
-static void add_intree_flag(struct buffer *b, int is_intree)
-{
- if (is_intree)
- buf_printf(b, "\nMODULE_INFO(intree, \"Y\");\n");
-}
-
-/* Cannot check for assembler */
-static void add_retpoline(struct buffer *b)
-{
- buf_printf(b, "\n#ifdef CONFIG_RETPOLINE\n");
- buf_printf(b, "MODULE_INFO(retpoline, \"Y\");\n");
- buf_printf(b, "#endif\n");
-}
-
-static void add_staging_flag(struct buffer *b, const char *name)
-{
- if (strstarts(name, "drivers/staging"))
- buf_printf(b, "\nMODULE_INFO(staging, \"Y\");\n");
-}
-
-/**
- * Record CRCs for unresolved symbols
- **/
-static int add_versions(struct buffer *b, struct module *mod)
-{
- struct symbol *s, *exp;
- int err = 0;
-
- for (s = mod->unres; s; s = s->next) {
- exp = find_symbol(s->name);
- if (!exp || exp->module == mod)
- continue;
- s->module = exp->module;
- s->crc_valid = exp->crc_valid;
- s->crc = exp->crc;
- }
-
- if (!modversions)
- return err;
-
- buf_printf(b, "\n");
- buf_printf(b, "static const struct modversion_info ____versions[]\n");
- buf_printf(b, "__used __section(__versions) = {\n");
-
- for (s = mod->unres; s; s = s->next) {
- if (!s->module)
- continue;
- if (!s->crc_valid) {
- warn("\"%s\" [%s.ko] has no CRC!\n",
- s->name, mod->name);
- continue;
- }
- if (strlen(s->name) >= MODULE_NAME_LEN) {
- merror("too long symbol \"%s\" [%s.ko]\n",
- s->name, mod->name);
- err = 1;
- break;
- }
- buf_printf(b, "\t{ %#8x, \"%s\" },\n",
- s->crc, s->name);
- }
-
- buf_printf(b, "};\n");
-
- return err;
-}
-
-static void add_depends(struct buffer *b, struct module *mod)
-{
- struct symbol *s;
- int first = 1;
-
- /* Clear ->seen flag of modules that own symbols needed by this. */
- for (s = mod->unres; s; s = s->next)
- if (s->module)
- s->module->seen = is_vmlinux(s->module->name);
-
- buf_printf(b, "\n");
- buf_printf(b, "MODULE_INFO(depends, \"");
- for (s = mod->unres; s; s = s->next) {
- const char *p;
- if (!s->module)
- continue;
-
- if (s->module->seen)
- continue;
-
- s->module->seen = 1;
- p = strrchr(s->module->name, '/');
- if (p)
- p++;
- else
- p = s->module->name;
- buf_printf(b, "%s%s", first ? "" : ",", p);
- first = 0;
- }
- buf_printf(b, "\");\n");
-}
-
-static void add_srcversion(struct buffer *b, struct module *mod)
-{
- if (mod->srcversion[0]) {
- buf_printf(b, "\n");
- buf_printf(b, "MODULE_INFO(srcversion, \"%s\");\n",
- mod->srcversion);
- }
-}
-
-static void write_if_changed(struct buffer *b, const char *fname)
-{
- char *tmp;
- FILE *file;
- struct stat st;
-
- file = fopen(fname, "r");
- if (!file)
- goto write;
-
- if (fstat(fileno(file), &st) < 0)
- goto close_write;
-
- if (st.st_size != b->pos)
- goto close_write;
-
- tmp = NOFAIL(malloc(b->pos));
- if (fread(tmp, 1, b->pos, file) != b->pos)
- goto free_write;
-
- if (memcmp(tmp, b->p, b->pos) != 0)
- goto free_write;
-
- free(tmp);
- fclose(file);
- return;
-
- free_write:
- free(tmp);
- close_write:
- fclose(file);
- write:
- file = fopen(fname, "w");
- if (!file) {
- perror(fname);
- exit(1);
- }
- if (fwrite(b->p, 1, b->pos, file) != b->pos) {
- perror(fname);
- exit(1);
- }
- fclose(file);
-}
-
-/* parse Module.symvers file. line format:
- * 0x12345678<tab>symbol<tab>module<tab>export<tab>namespace
- **/
-static void read_dump(const char *fname, unsigned int kernel)
-{
- unsigned long size, pos = 0;
- void *file = grab_file(fname, &size);
- char *line;
-
- if (!file)
- /* No symbol versions, silently ignore */
- return;
-
- while ((line = get_next_line(&pos, file, size))) {
- char *symname, *namespace, *modname, *d, *export;
- unsigned int crc;
- struct module *mod;
- struct symbol *s;
-
- if (!(symname = strchr(line, '\t')))
- goto fail;
- *symname++ = '\0';
- if (!(modname = strchr(symname, '\t')))
- goto fail;
- *modname++ = '\0';
- if (!(export = strchr(modname, '\t')))
- goto fail;
- *export++ = '\0';
- if (!(namespace = strchr(export, '\t')))
- goto fail;
- *namespace++ = '\0';
-
- crc = strtoul(line, &d, 16);
- if (*symname == '\0' || *modname == '\0' || *d != '\0')
- goto fail;
- mod = find_module(modname);
- if (!mod) {
- if (is_vmlinux(modname))
- have_vmlinux = 1;
- mod = new_module(modname);
- mod->skip = 1;
- }
- s = sym_add_exported(symname, mod, export_no(export));
- s->kernel = kernel;
- s->preloaded = 1;
- s->is_static = 0;
- sym_update_crc(symname, mod, crc, export_no(export));
- sym_update_namespace(symname, namespace);
- }
- release_file(file, size);
- return;
-fail:
- release_file(file, size);
- fatal("parse error in symbol dump file\n");
-}
-
-/* For normal builds always dump all symbols.
- * For external modules only dump symbols
- * that are not read from kernel Module.symvers.
- **/
-static int dump_sym(struct symbol *sym)
-{
- if (!external_module)
- return 1;
- if (sym->vmlinux || sym->kernel)
- return 0;
- return 1;
-}
-
-static void write_dump(const char *fname)
-{
- struct buffer buf = { };
- struct symbol *symbol;
- const char *namespace;
- int n;
-
- for (n = 0; n < SYMBOL_HASH_SIZE ; n++) {
- symbol = symbolhash[n];
- while (symbol) {
- if (dump_sym(symbol)) {
- namespace = symbol->namespace;
- buf_printf(&buf, "0x%08x\t%s\t%s\t%s\t%s\n",
- symbol->crc, symbol->name,
- symbol->module->name,
- export_str(symbol->export),
- namespace ? namespace : "");
- }
- symbol = symbol->next;
- }
- }
- write_if_changed(&buf, fname);
- free(buf.p);
-}
-
-static void write_namespace_deps_files(void)
-{
- struct module *mod;
- struct namespace_list *ns;
- struct buffer ns_deps_buf = {};
-
- for (mod = modules; mod; mod = mod->next) {
- char fname[PATH_MAX];
-
- if (mod->skip)
- continue;
-
- ns_deps_buf.pos = 0;
-
- for (ns = mod->required_namespaces; ns; ns = ns->next)
- buf_printf(&ns_deps_buf, "%s\n", ns->namespace);
-
- if (ns_deps_buf.pos == 0)
- continue;
-
- sprintf(fname, "%s.ns_deps", mod->name);
- write_if_changed(&ns_deps_buf, fname);
- }
-}
-
-struct ext_sym_list {
- struct ext_sym_list *next;
- const char *file;
-};
-
-int main(int argc, char **argv)
-{
- struct module *mod;
- struct buffer buf = { };
- char *kernel_read = NULL, *module_read = NULL;
- char *dump_write = NULL, *files_source = NULL;
- int opt;
- int err;
- int n;
- struct ext_sym_list *extsym_iter;
- struct ext_sym_list *extsym_start = NULL;
-
- while ((opt = getopt(argc, argv, "i:I:e:mnsT:o:awEd")) != -1) {
- switch (opt) {
- case 'i':
- kernel_read = optarg;
- break;
- case 'I':
- module_read = optarg;
- external_module = 1;
- break;
- case 'e':
- external_module = 1;
- extsym_iter =
- NOFAIL(malloc(sizeof(*extsym_iter)));
- extsym_iter->next = extsym_start;
- extsym_iter->file = optarg;
- extsym_start = extsym_iter;
- break;
- case 'm':
- modversions = 1;
- break;
- case 'n':
- ignore_missing_files = 1;
- break;
- case 'o':
- dump_write = optarg;
- break;
- case 'a':
- all_versions = 1;
- break;
- case 's':
- vmlinux_section_warnings = 0;
- break;
- case 'T':
- files_source = optarg;
- break;
- case 'w':
- warn_unresolved = 1;
- break;
- case 'E':
- sec_mismatch_fatal = 1;
- break;
- case 'd':
- write_namespace_deps = 1;
- break;
- default:
- exit(1);
- }
- }
-
- if (kernel_read)
- read_dump(kernel_read, 1);
- if (module_read)
- read_dump(module_read, 0);
- while (extsym_start) {
- read_dump(extsym_start->file, 0);
- extsym_iter = extsym_start->next;
- free(extsym_start);
- extsym_start = extsym_iter;
- }
-
- while (optind < argc)
- read_symbols(argv[optind++]);
-
- if (files_source)
- read_symbols_from_files(files_source);
-
- err = 0;
-
- for (mod = modules; mod; mod = mod->next) {
- char fname[PATH_MAX];
-
- if (mod->skip)
- continue;
-
- buf.pos = 0;
-
- err |= check_modname_len(mod);
- err |= check_exports(mod);
- if (write_namespace_deps)
- continue;
-
- add_header(&buf, mod);
- add_intree_flag(&buf, !external_module);
- add_retpoline(&buf);
- add_staging_flag(&buf, mod->name);
- err |= add_versions(&buf, mod);
- add_depends(&buf, mod);
- add_moddevtable(&buf, mod);
- add_srcversion(&buf, mod);
-
- sprintf(fname, "%s.mod.c", mod->name);
- write_if_changed(&buf, fname);
- }
-
- if (write_namespace_deps) {
- write_namespace_deps_files();
- return 0;
- }
-
- if (dump_write)
- write_dump(dump_write);
- if (sec_mismatch_count && sec_mismatch_fatal)
- fatal("modpost: Section mismatches detected.\n"
- "Set CONFIG_SECTION_MISMATCH_WARN_ONLY=y to allow them.\n");
- for (n = 0; n < SYMBOL_HASH_SIZE; n++) {
- struct symbol *s;
-
- for (s = symbolhash[n]; s; s = s->next) {
- /*
- * Do not check "vmlinux". This avoids the same warnings
- * shown twice, and false-positives for ARCH=um.
- */
- if (is_vmlinux(s->module->name) && !s->module->is_dot_o)
- continue;
-
- if (s->is_static)
- warn("\"%s\" [%s] is a static %s\n",
- s->name, s->module->name,
- export_str(s->export));
- }
- }
-
- free(buf.p);
-
- return err;
-}
Index: Baikal/M1000/create-5.4.211-5.7.226-host-limits-patch/linux-m1-5.4.211-5.7.226-new/scripts/mod/sumversion.c
===================================================================
--- Baikal/M1000/create-5.4.211-5.7.226-host-limits-patch/linux-m1-5.4.211-5.7.226-new/scripts/mod/sumversion.c (revision 384)
+++ Baikal/M1000/create-5.4.211-5.7.226-host-limits-patch/linux-m1-5.4.211-5.7.226-new/scripts/mod/sumversion.c (nonexistent)
@@ -1,497 +0,0 @@
-#include <netinet/in.h>
-#ifdef __sun__
-#include <inttypes.h>
-#else
-#include <stdint.h>
-#endif
-#include <ctype.h>
-#include <errno.h>
-#include <string.h>
-#include <linux/limits.h>
-#include "modpost.h"
-
-/*
- * Stolen form Cryptographic API.
- *
- * MD4 Message Digest Algorithm (RFC1320).
- *
- * Implementation derived from Andrew Tridgell and Steve French's
- * CIFS MD4 implementation, and the cryptoapi implementation
- * originally based on the public domain implementation written
- * by Colin Plumb in 1993.
- *
- * Copyright (c) Andrew Tridgell 1997-1998.
- * Modified by Steve French (sfrench@us.ibm.com) 2002
- * Copyright (c) Cryptoapi developers.
- * Copyright (c) 2002 David S. Miller (davem@redhat.com)
- * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- */
-#define MD4_DIGEST_SIZE 16
-#define MD4_HMAC_BLOCK_SIZE 64
-#define MD4_BLOCK_WORDS 16
-#define MD4_HASH_WORDS 4
-
-struct md4_ctx {
- uint32_t hash[MD4_HASH_WORDS];
- uint32_t block[MD4_BLOCK_WORDS];
- uint64_t byte_count;
-};
-
-static inline uint32_t lshift(uint32_t x, unsigned int s)
-{
- x &= 0xFFFFFFFF;
- return ((x << s) & 0xFFFFFFFF) | (x >> (32 - s));
-}
-
-static inline uint32_t F(uint32_t x, uint32_t y, uint32_t z)
-{
- return (x & y) | ((~x) & z);
-}
-
-static inline uint32_t G(uint32_t x, uint32_t y, uint32_t z)
-{
- return (x & y) | (x & z) | (y & z);
-}
-
-static inline uint32_t H(uint32_t x, uint32_t y, uint32_t z)
-{
- return x ^ y ^ z;
-}
-
-#define ROUND1(a,b,c,d,k,s) (a = lshift(a + F(b,c,d) + k, s))
-#define ROUND2(a,b,c,d,k,s) (a = lshift(a + G(b,c,d) + k + (uint32_t)0x5A827999,s))
-#define ROUND3(a,b,c,d,k,s) (a = lshift(a + H(b,c,d) + k + (uint32_t)0x6ED9EBA1,s))
-
-/* XXX: this stuff can be optimized */
-static inline void le32_to_cpu_array(uint32_t *buf, unsigned int words)
-{
- while (words--) {
- *buf = ntohl(*buf);
- buf++;
- }
-}
-
-static inline void cpu_to_le32_array(uint32_t *buf, unsigned int words)
-{
- while (words--) {
- *buf = htonl(*buf);
- buf++;
- }
-}
-
-static void md4_transform(uint32_t *hash, uint32_t const *in)
-{
- uint32_t a, b, c, d;
-
- a = hash[0];
- b = hash[1];
- c = hash[2];
- d = hash[3];
-
- ROUND1(a, b, c, d, in[0], 3);
- ROUND1(d, a, b, c, in[1], 7);
- ROUND1(c, d, a, b, in[2], 11);
- ROUND1(b, c, d, a, in[3], 19);
- ROUND1(a, b, c, d, in[4], 3);
- ROUND1(d, a, b, c, in[5], 7);
- ROUND1(c, d, a, b, in[6], 11);
- ROUND1(b, c, d, a, in[7], 19);
- ROUND1(a, b, c, d, in[8], 3);
- ROUND1(d, a, b, c, in[9], 7);
- ROUND1(c, d, a, b, in[10], 11);
- ROUND1(b, c, d, a, in[11], 19);
- ROUND1(a, b, c, d, in[12], 3);
- ROUND1(d, a, b, c, in[13], 7);
- ROUND1(c, d, a, b, in[14], 11);
- ROUND1(b, c, d, a, in[15], 19);
-
- ROUND2(a, b, c, d,in[ 0], 3);
- ROUND2(d, a, b, c, in[4], 5);
- ROUND2(c, d, a, b, in[8], 9);
- ROUND2(b, c, d, a, in[12], 13);
- ROUND2(a, b, c, d, in[1], 3);
- ROUND2(d, a, b, c, in[5], 5);
- ROUND2(c, d, a, b, in[9], 9);
- ROUND2(b, c, d, a, in[13], 13);
- ROUND2(a, b, c, d, in[2], 3);
- ROUND2(d, a, b, c, in[6], 5);
- ROUND2(c, d, a, b, in[10], 9);
- ROUND2(b, c, d, a, in[14], 13);
- ROUND2(a, b, c, d, in[3], 3);
- ROUND2(d, a, b, c, in[7], 5);
- ROUND2(c, d, a, b, in[11], 9);
- ROUND2(b, c, d, a, in[15], 13);
-
- ROUND3(a, b, c, d,in[ 0], 3);
- ROUND3(d, a, b, c, in[8], 9);
- ROUND3(c, d, a, b, in[4], 11);
- ROUND3(b, c, d, a, in[12], 15);
- ROUND3(a, b, c, d, in[2], 3);
- ROUND3(d, a, b, c, in[10], 9);
- ROUND3(c, d, a, b, in[6], 11);
- ROUND3(b, c, d, a, in[14], 15);
- ROUND3(a, b, c, d, in[1], 3);
- ROUND3(d, a, b, c, in[9], 9);
- ROUND3(c, d, a, b, in[5], 11);
- ROUND3(b, c, d, a, in[13], 15);
- ROUND3(a, b, c, d, in[3], 3);
- ROUND3(d, a, b, c, in[11], 9);
- ROUND3(c, d, a, b, in[7], 11);
- ROUND3(b, c, d, a, in[15], 15);
-
- hash[0] += a;
- hash[1] += b;
- hash[2] += c;
- hash[3] += d;
-}
-
-static inline void md4_transform_helper(struct md4_ctx *ctx)
-{
- le32_to_cpu_array(ctx->block, sizeof(ctx->block) / sizeof(uint32_t));
- md4_transform(ctx->hash, ctx->block);
-}
-
-static void md4_init(struct md4_ctx *mctx)
-{
- mctx->hash[0] = 0x67452301;
- mctx->hash[1] = 0xefcdab89;
- mctx->hash[2] = 0x98badcfe;
- mctx->hash[3] = 0x10325476;
- mctx->byte_count = 0;
-}
-
-static void md4_update(struct md4_ctx *mctx,
- const unsigned char *data, unsigned int len)
-{
- const uint32_t avail = sizeof(mctx->block) - (mctx->byte_count & 0x3f);
-
- mctx->byte_count += len;
-
- if (avail > len) {
- memcpy((char *)mctx->block + (sizeof(mctx->block) - avail),
- data, len);
- return;
- }
-
- memcpy((char *)mctx->block + (sizeof(mctx->block) - avail),
- data, avail);
-
- md4_transform_helper(mctx);
- data += avail;
- len -= avail;
-
- while (len >= sizeof(mctx->block)) {
- memcpy(mctx->block, data, sizeof(mctx->block));
- md4_transform_helper(mctx);
- data += sizeof(mctx->block);
- len -= sizeof(mctx->block);
- }
-
- memcpy(mctx->block, data, len);
-}
-
-static void md4_final_ascii(struct md4_ctx *mctx, char *out, unsigned int len)
-{
- const unsigned int offset = mctx->byte_count & 0x3f;
- char *p = (char *)mctx->block + offset;
- int padding = 56 - (offset + 1);
-
- *p++ = 0x80;
- if (padding < 0) {
- memset(p, 0x00, padding + sizeof (uint64_t));
- md4_transform_helper(mctx);
- p = (char *)mctx->block;
- padding = 56;
- }
-
- memset(p, 0, padding);
- mctx->block[14] = mctx->byte_count << 3;
- mctx->block[15] = mctx->byte_count >> 29;
- le32_to_cpu_array(mctx->block, (sizeof(mctx->block) -
- sizeof(uint64_t)) / sizeof(uint32_t));
- md4_transform(mctx->hash, mctx->block);
- cpu_to_le32_array(mctx->hash, sizeof(mctx->hash) / sizeof(uint32_t));
-
- snprintf(out, len, "%08X%08X%08X%08X",
- mctx->hash[0], mctx->hash[1], mctx->hash[2], mctx->hash[3]);
-}
-
-static inline void add_char(unsigned char c, struct md4_ctx *md)
-{
- md4_update(md, &c, 1);
-}
-
-static int parse_string(const char *file, unsigned long len,
- struct md4_ctx *md)
-{
- unsigned long i;
-
- add_char(file[0], md);
- for (i = 1; i < len; i++) {
- add_char(file[i], md);
- if (file[i] == '"' && file[i-1] != '\\')
- break;
- }
- return i;
-}
-
-static int parse_comment(const char *file, unsigned long len)
-{
- unsigned long i;
-
- for (i = 2; i < len; i++) {
- if (file[i-1] == '*' && file[i] == '/')
- break;
- }
- return i;
-}
-
-/* FIXME: Handle .s files differently (eg. # starts comments) --RR */
-static int parse_file(const char *fname, struct md4_ctx *md)
-{
- char *file;
- unsigned long i, len;
-
- file = grab_file(fname, &len);
- if (!file)
- return 0;
-
- for (i = 0; i < len; i++) {
- /* Collapse and ignore \ and CR. */
- if (file[i] == '\\' && (i+1 < len) && file[i+1] == '\n') {
- i++;
- continue;
- }
-
- /* Ignore whitespace */
- if (isspace(file[i]))
- continue;
-
- /* Handle strings as whole units */
- if (file[i] == '"') {
- i += parse_string(file+i, len - i, md);
- continue;
- }
-
- /* Comments: ignore */
- if (file[i] == '/' && file[i+1] == '*') {
- i += parse_comment(file+i, len - i);
- continue;
- }
-
- add_char(file[i], md);
- }
- release_file(file, len);
- return 1;
-}
-/* Check whether the file is a static library or not */
-static int is_static_library(const char *objfile)
-{
- int len = strlen(objfile);
- if (objfile[len - 2] == '.' && objfile[len - 1] == 'a')
- return 1;
- else
- return 0;
-}
-
-/* We have dir/file.o. Open dir/.file.o.cmd, look for source_ and deps_ line
- * to figure out source files. */
-static int parse_source_files(const char *objfile, struct md4_ctx *md)
-{
- char *cmd, *file, *line, *dir;
- const char *base;
- unsigned long flen, pos = 0;
- int dirlen, ret = 0, check_files = 0;
-
- cmd = NOFAIL(malloc(strlen(objfile) + sizeof("..cmd")));
-
- base = strrchr(objfile, '/');
- if (base) {
- base++;
- dirlen = base - objfile;
- sprintf(cmd, "%.*s.%s.cmd", dirlen, objfile, base);
- } else {
- dirlen = 0;
- sprintf(cmd, ".%s.cmd", objfile);
- }
- dir = NOFAIL(malloc(dirlen + 1));
- strncpy(dir, objfile, dirlen);
- dir[dirlen] = '\0';
-
- file = grab_file(cmd, &flen);
- if (!file) {
- warn("could not find %s for %s\n", cmd, objfile);
- goto out;
- }
-
- /* Sum all files in the same dir or subdirs. */
- while ((line = get_next_line(&pos, file, flen)) != NULL) {
- char* p = line;
-
- if (strncmp(line, "source_", sizeof("source_")-1) == 0) {
- p = strrchr(line, ' ');
- if (!p) {
- warn("malformed line: %s\n", line);
- goto out_file;
- }
- p++;
- if (!parse_file(p, md)) {
- warn("could not open %s: %s\n",
- p, strerror(errno));
- goto out_file;
- }
- continue;
- }
- if (strncmp(line, "deps_", sizeof("deps_")-1) == 0) {
- check_files = 1;
- continue;
- }
- if (!check_files)
- continue;
-
- /* Continue until line does not end with '\' */
- if ( *(p + strlen(p)-1) != '\\')
- break;
- /* Terminate line at first space, to get rid of final ' \' */
- while (*p) {
- if (isspace(*p)) {
- *p = '\0';
- break;
- }
- p++;
- }
-
- /* Check if this file is in same dir as objfile */
- if ((strstr(line, dir)+strlen(dir)-1) == strrchr(line, '/')) {
- if (!parse_file(line, md)) {
- warn("could not open %s: %s\n",
- line, strerror(errno));
- goto out_file;
- }
-
- }
-
- }
-
- /* Everyone parsed OK */
- ret = 1;
-out_file:
- release_file(file, flen);
-out:
- free(dir);
- free(cmd);
- return ret;
-}
-
-/* Calc and record src checksum. */
-void get_src_version(const char *modname, char sum[], unsigned sumlen)
-{
- void *file;
- unsigned long len;
- struct md4_ctx md;
- char *sources, *end, *fname;
- char filelist[PATH_MAX + 1];
-
- /* objects for a module are listed in the first line of *.mod file. */
- snprintf(filelist, sizeof(filelist), "%.*smod",
- (int)strlen(modname) - 1, modname);
-
- file = grab_file(filelist, &len);
- if (!file)
- /* not a module or .mod file missing - ignore */
- return;
-
- sources = file;
-
- end = strchr(sources, '\n');
- if (!end) {
- warn("bad ending versions file for %s\n", modname);
- goto release;
- }
- *end = '\0';
-
- md4_init(&md);
- while ((fname = strsep(&sources, " ")) != NULL) {
- if (!*fname)
- continue;
- if (!(is_static_library(fname)) &&
- !parse_source_files(fname, &md))
- goto release;
- }
-
- md4_final_ascii(&md, sum, sumlen);
-release:
- release_file(file, len);
-}
-
-static void write_version(const char *filename, const char *sum,
- unsigned long offset)
-{
- int fd;
-
- fd = open(filename, O_RDWR);
- if (fd < 0) {
- warn("changing sum in %s failed: %s\n",
- filename, strerror(errno));
- return;
- }
-
- if (lseek(fd, offset, SEEK_SET) == (off_t)-1) {
- warn("changing sum in %s:%lu failed: %s\n",
- filename, offset, strerror(errno));
- goto out;
- }
-
- if (write(fd, sum, strlen(sum)+1) != strlen(sum)+1) {
- warn("writing sum in %s failed: %s\n",
- filename, strerror(errno));
- goto out;
- }
-out:
- close(fd);
-}
-
-static int strip_rcs_crap(char *version)
-{
- unsigned int len, full_len;
-
- if (strncmp(version, "$Revision", strlen("$Revision")) != 0)
- return 0;
-
- /* Space for version string follows. */
- full_len = strlen(version) + strlen(version + strlen(version) + 1) + 2;
-
- /* Move string to start with version number: prefix will be
- * $Revision$ or $Revision: */
- len = strlen("$Revision");
- if (version[len] == ':' || version[len] == '$')
- len++;
- while (isspace(version[len]))
- len++;
- memmove(version, version+len, full_len-len);
- full_len -= len;
-
- /* Preserve up to next whitespace. */
- len = 0;
- while (version[len] && !isspace(version[len]))
- len++;
- memmove(version + len, version + strlen(version),
- full_len - strlen(version));
- return 1;
-}
-
-/* Clean up RCS-style version numbers. */
-void maybe_frob_rcs_version(const char *modfilename,
- char *version,
- void *modinfo,
- unsigned long version_offset)
-{
- if (strip_rcs_crap(version))
- write_version(modfilename, version, version_offset);
-}
Index: Baikal/M1000/create-5.4.211-5.7.226-host-limits-patch/linux-m1-5.4.211-5.7.226-new/scripts/mod
===================================================================
--- Baikal/M1000/create-5.4.211-5.7.226-host-limits-patch/linux-m1-5.4.211-5.7.226-new/scripts/mod (revision 384)
+++ Baikal/M1000/create-5.4.211-5.7.226-host-limits-patch/linux-m1-5.4.211-5.7.226-new/scripts/mod (nonexistent)
Property changes on: Baikal/M1000/create-5.4.211-5.7.226-host-limits-patch/linux-m1-5.4.211-5.7.226-new/scripts/mod
___________________________________________________________________
Deleted: svn:ignore
## -1,73 +0,0 ##
-
-# install dir
-dist
-
-# Target build dirs
-.a1x-newlib
-.a2x-newlib
-.at91sam7s-newlib
-
-.build-machine
-
-.a1x-glibc
-.a2x-glibc
-.h3-glibc
-.h5-glibc
-.i586-glibc
-.i686-glibc
-.imx6-glibc
-.jz47xx-glibc
-.makefile
-.am335x-glibc
-.omap543x-glibc
-.p5600-glibc
-.power8-glibc
-.power8le-glibc
-.power9-glibc
-.power9le-glibc
-.m1000-glibc
-.riscv64-glibc
-.rk328x-glibc
-.rk33xx-glibc
-.rk339x-glibc
-.s8xx-glibc
-.s9xx-glibc
-.x86_64-glibc
-
-# Hidden files (each file)
-.makefile
-.dist
-.rootfs
-
-# src & hw requires
-.src_requires
-.src_requires_depend
-.requires
-.requires_depend
-
-# Tarballs
-*.gz
-*.bz2
-*.lz
-*.xz
-*.tgz
-*.txz
-
-# Signatures
-*.asc
-*.sig
-*.sign
-*.sha1sum
-
-# Patches
-*.patch
-
-# Descriptions
-*.dsc
-*.txt
-
-# Default linux config files
-*.defconfig
-
-# backup copies
-*~
Index: Baikal/M1000/create-5.4.211-5.7.226-host-limits-patch/linux-m1-5.4.211-5.7.226-new/scripts/kconfig/lexer.l
===================================================================
--- Baikal/M1000/create-5.4.211-5.7.226-host-limits-patch/linux-m1-5.4.211-5.7.226-new/scripts/kconfig/lexer.l (revision 384)
+++ Baikal/M1000/create-5.4.211-5.7.226-host-limits-patch/linux-m1-5.4.211-5.7.226-new/scripts/kconfig/lexer.l (nonexistent)
@@ -1,471 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
- */
-%option nostdinit noyywrap never-interactive full ecs
-%option 8bit nodefault yylineno
-%x ASSIGN_VAL HELP STRING
-%{
-
-#include <assert.h>
-#include <linux/limits.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "lkc.h"
-#include "parser.tab.h"
-
-#define YY_DECL static int yylex1(void)
-
-#define START_STRSIZE 16
-
-static struct {
- struct file *file;
- int lineno;
-} current_pos;
-
-static int prev_prev_token = T_EOL;
-static int prev_token = T_EOL;
-static char *text;
-static int text_size, text_asize;
-
-struct buffer {
- struct buffer *parent;
- YY_BUFFER_STATE state;
-};
-
-struct buffer *current_buf;
-
-static int last_ts, first_ts;
-
-static char *expand_token(const char *in, size_t n);
-static void append_expanded_string(const char *in);
-static void zconf_endhelp(void);
-static void zconf_endfile(void);
-
-static void new_string(void)
-{
- text = xmalloc(START_STRSIZE);
- text_asize = START_STRSIZE;
- text_size = 0;
- *text = 0;
-}
-
-static void append_string(const char *str, int size)
-{
- int new_size = text_size + size + 1;
- if (new_size > text_asize) {
- new_size += START_STRSIZE - 1;
- new_size &= -START_STRSIZE;
- text = xrealloc(text, new_size);
- text_asize = new_size;
- }
- memcpy(text + text_size, str, size);
- text_size += size;
- text[text_size] = 0;
-}
-
-static void alloc_string(const char *str, int size)
-{
- text = xmalloc(size + 1);
- memcpy(text, str, size);
- text[size] = 0;
-}
-
-static void warn_ignored_character(char chr)
-{
- fprintf(stderr,
- "%s:%d:warning: ignoring unsupported character '%c'\n",
- current_file->name, yylineno, chr);
-}
-%}
-
-n [A-Za-z0-9_-]
-
-%%
- int str = 0;
- int ts, i;
-
-#.* /* ignore comment */
-[ \t]* /* whitespaces */
-\\\n /* escaped new line */
-\n return T_EOL;
-"allnoconfig_y" return T_ALLNOCONFIG_Y;
-"bool" return T_BOOL;
-"choice" return T_CHOICE;
-"comment" return T_COMMENT;
-"config" return T_CONFIG;
-"def_bool" return T_DEF_BOOL;
-"def_tristate" return T_DEF_TRISTATE;
-"default" return T_DEFAULT;
-"defconfig_list" return T_DEFCONFIG_LIST;
-"depends" return T_DEPENDS;
-"endchoice" return T_ENDCHOICE;
-"endif" return T_ENDIF;
-"endmenu" return T_ENDMENU;
-"help"|"---help---" return T_HELP;
-"hex" return T_HEX;
-"if" return T_IF;
-"imply" return T_IMPLY;
-"int" return T_INT;
-"mainmenu" return T_MAINMENU;
-"menu" return T_MENU;
-"menuconfig" return T_MENUCONFIG;
-"modules" return T_MODULES;
-"on" return T_ON;
-"option" return T_OPTION;
-"optional" return T_OPTIONAL;
-"prompt" return T_PROMPT;
-"range" return T_RANGE;
-"select" return T_SELECT;
-"source" return T_SOURCE;
-"string" return T_STRING;
-"tristate" return T_TRISTATE;
-"visible" return T_VISIBLE;
-"||" return T_OR;
-"&&" return T_AND;
-"=" return T_EQUAL;
-"!=" return T_UNEQUAL;
-"<" return T_LESS;
-"<=" return T_LESS_EQUAL;
-">" return T_GREATER;
-">=" return T_GREATER_EQUAL;
-"!" return T_NOT;
-"(" return T_OPEN_PAREN;
-")" return T_CLOSE_PAREN;
-":=" return T_COLON_EQUAL;
-"+=" return T_PLUS_EQUAL;
-\"|\' {
- str = yytext[0];
- new_string();
- BEGIN(STRING);
- }
-{n}+ {
- alloc_string(yytext, yyleng);
- yylval.string = text;
- return T_WORD;
- }
-({n}|$)+ {
- /* this token includes at least one '$' */
- yylval.string = expand_token(yytext, yyleng);
- if (strlen(yylval.string))
- return T_WORD;
- free(yylval.string);
- }
-. warn_ignored_character(*yytext);
-
-<ASSIGN_VAL>{
- [^[:blank:]\n]+.* {
- alloc_string(yytext, yyleng);
- yylval.string = text;
- return T_ASSIGN_VAL;
- }
- \n { BEGIN(INITIAL); return T_EOL; }
- .
-}
-
-<STRING>{
- "$".* append_expanded_string(yytext);
- [^$'"\\\n]+ {
- append_string(yytext, yyleng);
- }
- \\.? {
- append_string(yytext + 1, yyleng - 1);
- }
- \'|\" {
- if (str == yytext[0]) {
- BEGIN(INITIAL);
- yylval.string = text;
- return T_WORD_QUOTE;
- } else
- append_string(yytext, 1);
- }
- \n {
- fprintf(stderr,
- "%s:%d:warning: multi-line strings not supported\n",
- zconf_curname(), zconf_lineno());
- unput('\n');
- BEGIN(INITIAL);
- yylval.string = text;
- return T_WORD_QUOTE;
- }
- <<EOF>> {
- BEGIN(INITIAL);
- yylval.string = text;
- return T_WORD_QUOTE;
- }
-}
-
-<HELP>{
- [ \t]+ {
- ts = 0;
- for (i = 0; i < yyleng; i++) {
- if (yytext[i] == '\t')
- ts = (ts & ~7) + 8;
- else
- ts++;
- }
- last_ts = ts;
- if (first_ts) {
- if (ts < first_ts) {
- zconf_endhelp();
- return T_HELPTEXT;
- }
- ts -= first_ts;
- while (ts > 8) {
- append_string(" ", 8);
- ts -= 8;
- }
- append_string(" ", ts);
- }
- }
- [ \t]*\n/[^ \t\n] {
- zconf_endhelp();
- return T_HELPTEXT;
- }
- [ \t]*\n {
- append_string("\n", 1);
- }
- [^ \t\n].* {
- while (yyleng) {
- if ((yytext[yyleng-1] != ' ') && (yytext[yyleng-1] != '\t'))
- break;
- yyleng--;
- }
- append_string(yytext, yyleng);
- if (!first_ts)
- first_ts = last_ts;
- }
- <<EOF>> {
- zconf_endhelp();
- return T_HELPTEXT;
- }
-}
-
-<<EOF>> {
- BEGIN(INITIAL);
-
- if (prev_token != T_EOL && prev_token != T_HELPTEXT)
- fprintf(stderr, "%s:%d:warning: no new line at end of file\n",
- current_file->name, yylineno);
-
- if (current_file) {
- zconf_endfile();
- return T_EOL;
- }
- fclose(yyin);
- yyterminate();
-}
-
-%%
-
-/* second stage lexer */
-int yylex(void)
-{
- int token;
-
-repeat:
- token = yylex1();
-
- if (prev_token == T_EOL || prev_token == T_HELPTEXT) {
- if (token == T_EOL) {
- /* Do not pass unneeded T_EOL to the parser. */
- goto repeat;
- } else {
- /*
- * For the parser, update file/lineno at the first token
- * of each statement. Generally, \n is a statement
- * terminator in Kconfig, but it is not always true
- * because \n could be escaped by a backslash.
- */
- current_pos.file = current_file;
- current_pos.lineno = yylineno;
- }
- }
-
- if (prev_prev_token == T_EOL && prev_token == T_WORD &&
- (token == T_EQUAL || token == T_COLON_EQUAL || token == T_PLUS_EQUAL))
- BEGIN(ASSIGN_VAL);
-
- prev_prev_token = prev_token;
- prev_token = token;
-
- return token;
-}
-
-static char *expand_token(const char *in, size_t n)
-{
- char *out;
- int c;
- char c2;
- const char *rest, *end;
-
- new_string();
- append_string(in, n);
-
- /* get the whole line because we do not know the end of token. */
- while ((c = input()) != EOF) {
- if (c == '\n') {
- unput(c);
- break;
- }
- c2 = c;
- append_string(&c2, 1);
- }
-
- rest = text;
- out = expand_one_token(&rest);
-
- /* push back unused characters to the input stream */
- end = rest + strlen(rest);
- while (end > rest)
- unput(*--end);
-
- free(text);
-
- return out;
-}
-
-static void append_expanded_string(const char *str)
-{
- const char *end;
- char *res;
-
- str++;
-
- res = expand_dollar(&str);
-
- /* push back unused characters to the input stream */
- end = str + strlen(str);
- while (end > str)
- unput(*--end);
-
- append_string(res, strlen(res));
-
- free(res);
-}
-
-void zconf_starthelp(void)
-{
- new_string();
- last_ts = first_ts = 0;
- BEGIN(HELP);
-}
-
-static void zconf_endhelp(void)
-{
- yylval.string = text;
- BEGIN(INITIAL);
-}
-
-
-/*
- * Try to open specified file with following names:
- * ./name
- * $(srctree)/name
- * The latter is used when srctree is separate from objtree
- * when compiling the kernel.
- * Return NULL if file is not found.
- */
-FILE *zconf_fopen(const char *name)
-{
- char *env, fullname[PATH_MAX+1];
- FILE *f;
-
- f = fopen(name, "r");
- if (!f && name != NULL && name[0] != '/') {
- env = getenv(SRCTREE);
- if (env) {
- snprintf(fullname, sizeof(fullname),
- "%s/%s", env, name);
- f = fopen(fullname, "r");
- }
- }
- return f;
-}
-
-void zconf_initscan(const char *name)
-{
- yyin = zconf_fopen(name);
- if (!yyin) {
- fprintf(stderr, "can't find file %s\n", name);
- exit(1);
- }
-
- current_buf = xmalloc(sizeof(*current_buf));
- memset(current_buf, 0, sizeof(*current_buf));
-
- current_file = file_lookup(name);
- yylineno = 1;
-}
-
-void zconf_nextfile(const char *name)
-{
- struct file *iter;
- struct file *file = file_lookup(name);
- struct buffer *buf = xmalloc(sizeof(*buf));
- memset(buf, 0, sizeof(*buf));
-
- current_buf->state = YY_CURRENT_BUFFER;
- yyin = zconf_fopen(file->name);
- if (!yyin) {
- fprintf(stderr, "%s:%d: can't open file \"%s\"\n",
- zconf_curname(), zconf_lineno(), file->name);
- exit(1);
- }
- yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE));
- buf->parent = current_buf;
- current_buf = buf;
-
- current_file->lineno = yylineno;
- file->parent = current_file;
-
- for (iter = current_file; iter; iter = iter->parent) {
- if (!strcmp(iter->name, file->name)) {
- fprintf(stderr,
- "Recursive inclusion detected.\n"
- "Inclusion path:\n"
- " current file : %s\n", file->name);
- iter = file;
- do {
- iter = iter->parent;
- fprintf(stderr, " included from: %s:%d\n",
- iter->name, iter->lineno - 1);
- } while (strcmp(iter->name, file->name));
- exit(1);
- }
- }
-
- yylineno = 1;
- current_file = file;
-}
-
-static void zconf_endfile(void)
-{
- struct buffer *parent;
-
- current_file = current_file->parent;
- if (current_file)
- yylineno = current_file->lineno;
-
- parent = current_buf->parent;
- if (parent) {
- fclose(yyin);
- yy_delete_buffer(YY_CURRENT_BUFFER);
- yy_switch_to_buffer(parent->state);
- }
- free(current_buf);
- current_buf = parent;
-}
-
-int zconf_lineno(void)
-{
- return current_pos.lineno;
-}
-
-const char *zconf_curname(void)
-{
- return current_pos.file ? current_pos.file->name : "<none>";
-}
Index: Baikal/M1000/create-5.4.211-5.7.226-host-limits-patch/linux-m1-5.4.211-5.7.226-new/scripts/kconfig/confdata.c
===================================================================
--- Baikal/M1000/create-5.4.211-5.7.226-host-limits-patch/linux-m1-5.4.211-5.7.226-new/scripts/kconfig/confdata.c (revision 384)
+++ Baikal/M1000/create-5.4.211-5.7.226-host-limits-patch/linux-m1-5.4.211-5.7.226-new/scripts/kconfig/confdata.c (nonexistent)
@@ -1,1369 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
- */
-
-#include <sys/mman.h>
-#include <sys/stat.h>
-#include <ctype.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <linux/limits.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <unistd.h>
-
-#include "lkc.h"
-
-/* return true if 'path' exists, false otherwise */
-static bool is_present(const char *path)
-{
- struct stat st;
-
- return !stat(path, &st);
-}
-
-/* return true if 'path' exists and it is a directory, false otherwise */
-static bool is_dir(const char *path)
-{
- struct stat st;
-
- if (stat(path, &st))
- return 0;
-
- return S_ISDIR(st.st_mode);
-}
-
-/* return true if the given two files are the same, false otherwise */
-static bool is_same(const char *file1, const char *file2)
-{
- int fd1, fd2;
- struct stat st1, st2;
- void *map1, *map2;
- bool ret = false;
-
- fd1 = open(file1, O_RDONLY);
- if (fd1 < 0)
- return ret;
-
- fd2 = open(file2, O_RDONLY);
- if (fd2 < 0)
- goto close1;
-
- ret = fstat(fd1, &st1);
- if (ret)
- goto close2;
- ret = fstat(fd2, &st2);
- if (ret)
- goto close2;
-
- if (st1.st_size != st2.st_size)
- goto close2;
-
- map1 = mmap(NULL, st1.st_size, PROT_READ, MAP_PRIVATE, fd1, 0);
- if (map1 == MAP_FAILED)
- goto close2;
-
- map2 = mmap(NULL, st2.st_size, PROT_READ, MAP_PRIVATE, fd2, 0);
- if (map2 == MAP_FAILED)
- goto close2;
-
- if (bcmp(map1, map2, st1.st_size))
- goto close2;
-
- ret = true;
-close2:
- close(fd2);
-close1:
- close(fd1);
-
- return ret;
-}
-
-/*
- * Create the parent directory of the given path.
- *
- * For example, if 'include/config/auto.conf' is given, create 'include/config'.
- */
-static int make_parent_dir(const char *path)
-{
- char tmp[PATH_MAX + 1];
- char *p;
-
- strncpy(tmp, path, sizeof(tmp));
- tmp[sizeof(tmp) - 1] = 0;
-
- /* Remove the base name. Just return if nothing is left */
- p = strrchr(tmp, '/');
- if (!p)
- return 0;
- *(p + 1) = 0;
-
- /* Just in case it is an absolute path */
- p = tmp;
- while (*p == '/')
- p++;
-
- while ((p = strchr(p, '/'))) {
- *p = 0;
-
- /* skip if the directory exists */
- if (!is_dir(tmp) && mkdir(tmp, 0755))
- return -1;
-
- *p = '/';
- while (*p == '/')
- p++;
- }
-
- return 0;
-}
-
-static char depfile_path[PATH_MAX];
-static size_t depfile_prefix_len;
-
-/* touch depfile for symbol 'name' */
-static int conf_touch_dep(const char *name)
-{
- int fd, ret;
- const char *s;
- char *d, c;
-
- /* check overflow: prefix + name + ".h" + '\0' must fit in buffer. */
- if (depfile_prefix_len + strlen(name) + 3 > sizeof(depfile_path))
- return -1;
-
- d = depfile_path + depfile_prefix_len;
- s = name;
-
- while ((c = *s++))
- *d++ = (c == '_') ? '/' : tolower(c);
- strcpy(d, ".h");
-
- /* Assume directory path already exists. */
- fd = open(depfile_path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
- if (fd == -1) {
- if (errno != ENOENT)
- return -1;
-
- ret = make_parent_dir(depfile_path);
- if (ret)
- return ret;
-
- /* Try it again. */
- fd = open(depfile_path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
- if (fd == -1)
- return -1;
- }
- close(fd);
-
- return 0;
-}
-
-struct conf_printer {
- void (*print_symbol)(FILE *, struct symbol *, const char *, void *);
- void (*print_comment)(FILE *, const char *, void *);
-};
-
-static void conf_warning(const char *fmt, ...)
- __attribute__ ((format (printf, 1, 2)));
-
-static void conf_message(const char *fmt, ...)
- __attribute__ ((format (printf, 1, 2)));
-
-static const char *conf_filename;
-static int conf_lineno, conf_warnings;
-
-static void conf_warning(const char *fmt, ...)
-{
- va_list ap;
- va_start(ap, fmt);
- fprintf(stderr, "%s:%d:warning: ", conf_filename, conf_lineno);
- vfprintf(stderr, fmt, ap);
- fprintf(stderr, "\n");
- va_end(ap);
- conf_warnings++;
-}
-
-static void conf_default_message_callback(const char *s)
-{
- printf("#\n# ");
- printf("%s", s);
- printf("\n#\n");
-}
-
-static void (*conf_message_callback)(const char *s) =
- conf_default_message_callback;
-void conf_set_message_callback(void (*fn)(const char *s))
-{
- conf_message_callback = fn;
-}
-
-static void conf_message(const char *fmt, ...)
-{
- va_list ap;
- char buf[4096];
-
- if (!conf_message_callback)
- return;
-
- va_start(ap, fmt);
-
- vsnprintf(buf, sizeof(buf), fmt, ap);
- conf_message_callback(buf);
- va_end(ap);
-}
-
-const char *conf_get_configname(void)
-{
- char *name = getenv("KCONFIG_CONFIG");
-
- return name ? name : ".config";
-}
-
-static const char *conf_get_autoconfig_name(void)
-{
- char *name = getenv("KCONFIG_AUTOCONFIG");
-
- return name ? name : "include/config/auto.conf";
-}
-
-static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p)
-{
- char *p2;
-
- switch (sym->type) {
- case S_TRISTATE:
- if (p[0] == 'm') {
- sym->def[def].tri = mod;
- sym->flags |= def_flags;
- break;
- }
- /* fall through */
- case S_BOOLEAN:
- if (p[0] == 'y') {
- sym->def[def].tri = yes;
- sym->flags |= def_flags;
- break;
- }
- if (p[0] == 'n') {
- sym->def[def].tri = no;
- sym->flags |= def_flags;
- break;
- }
- if (def != S_DEF_AUTO)
- conf_warning("symbol value '%s' invalid for %s",
- p, sym->name);
- return 1;
- case S_STRING:
- if (*p++ != '"')
- break;
- for (p2 = p; (p2 = strpbrk(p2, "\"\\")); p2++) {
- if (*p2 == '"') {
- *p2 = 0;
- break;
- }
- memmove(p2, p2 + 1, strlen(p2));
- }
- if (!p2) {
- if (def != S_DEF_AUTO)
- conf_warning("invalid string found");
- return 1;
- }
- /* fall through */
- case S_INT:
- case S_HEX:
- if (sym_string_valid(sym, p)) {
- sym->def[def].val = xstrdup(p);
- sym->flags |= def_flags;
- } else {
- if (def != S_DEF_AUTO)
- conf_warning("symbol value '%s' invalid for %s",
- p, sym->name);
- return 1;
- }
- break;
- default:
- ;
- }
- return 0;
-}
-
-#define LINE_GROWTH 16
-static int add_byte(int c, char **lineptr, size_t slen, size_t *n)
-{
- char *nline;
- size_t new_size = slen + 1;
- if (new_size > *n) {
- new_size += LINE_GROWTH - 1;
- new_size *= 2;
- nline = xrealloc(*lineptr, new_size);
- if (!nline)
- return -1;
-
- *lineptr = nline;
- *n = new_size;
- }
-
- (*lineptr)[slen] = c;
-
- return 0;
-}
-
-static ssize_t compat_getline(char **lineptr, size_t *n, FILE *stream)
-{
- char *line = *lineptr;
- size_t slen = 0;
-
- for (;;) {
- int c = getc(stream);
-
- switch (c) {
- case '\n':
- if (add_byte(c, &line, slen, n) < 0)
- goto e_out;
- slen++;
- /* fall through */
- case EOF:
- if (add_byte('\0', &line, slen, n) < 0)
- goto e_out;
- *lineptr = line;
- if (slen == 0)
- return -1;
- return slen;
- default:
- if (add_byte(c, &line, slen, n) < 0)
- goto e_out;
- slen++;
- }
- }
-
-e_out:
- line[slen-1] = '\0';
- *lineptr = line;
- return -1;
-}
-
-int conf_read_simple(const char *name, int def)
-{
- FILE *in = NULL;
- char *line = NULL;
- size_t line_asize = 0;
- char *p, *p2;
- struct symbol *sym;
- int i, def_flags;
-
- if (name) {
- in = zconf_fopen(name);
- } else {
- struct property *prop;
-
- name = conf_get_configname();
- in = zconf_fopen(name);
- if (in)
- goto load;
- sym_add_change_count(1);
- if (!sym_defconfig_list)
- return 1;
-
- for_all_defaults(sym_defconfig_list, prop) {
- if (expr_calc_value(prop->visible.expr) == no ||
- prop->expr->type != E_SYMBOL)
- continue;
- sym_calc_value(prop->expr->left.sym);
- name = sym_get_string_value(prop->expr->left.sym);
- in = zconf_fopen(name);
- if (in) {
- conf_message("using defaults found in %s",
- name);
- goto load;
- }
- }
- }
- if (!in)
- return 1;
-
-load:
- conf_filename = name;
- conf_lineno = 0;
- conf_warnings = 0;
-
- def_flags = SYMBOL_DEF << def;
- for_all_symbols(i, sym) {
- sym->flags |= SYMBOL_CHANGED;
- sym->flags &= ~(def_flags|SYMBOL_VALID);
- if (sym_is_choice(sym))
- sym->flags |= def_flags;
- switch (sym->type) {
- case S_INT:
- case S_HEX:
- case S_STRING:
- if (sym->def[def].val)
- free(sym->def[def].val);
- /* fall through */
- default:
- sym->def[def].val = NULL;
- sym->def[def].tri = no;
- }
- }
-
- while (compat_getline(&line, &line_asize, in) != -1) {
- conf_lineno++;
- sym = NULL;
- if (line[0] == '#') {
- if (memcmp(line + 2, CONFIG_, strlen(CONFIG_)))
- continue;
- p = strchr(line + 2 + strlen(CONFIG_), ' ');
- if (!p)
- continue;
- *p++ = 0;
- if (strncmp(p, "is not set", 10))
- continue;
- if (def == S_DEF_USER) {
- sym = sym_find(line + 2 + strlen(CONFIG_));
- if (!sym) {
- sym_add_change_count(1);
- continue;
- }
- } else {
- sym = sym_lookup(line + 2 + strlen(CONFIG_), 0);
- if (sym->type == S_UNKNOWN)
- sym->type = S_BOOLEAN;
- }
- if (sym->flags & def_flags) {
- conf_warning("override: reassigning to symbol %s", sym->name);
- }
- switch (sym->type) {
- case S_BOOLEAN:
- case S_TRISTATE:
- sym->def[def].tri = no;
- sym->flags |= def_flags;
- break;
- default:
- ;
- }
- } else if (memcmp(line, CONFIG_, strlen(CONFIG_)) == 0) {
- p = strchr(line + strlen(CONFIG_), '=');
- if (!p)
- continue;
- *p++ = 0;
- p2 = strchr(p, '\n');
- if (p2) {
- *p2-- = 0;
- if (*p2 == '\r')
- *p2 = 0;
- }
-
- sym = sym_find(line + strlen(CONFIG_));
- if (!sym) {
- if (def == S_DEF_AUTO)
- /*
- * Reading from include/config/auto.conf
- * If CONFIG_FOO previously existed in
- * auto.conf but it is missing now,
- * include/config/foo.h must be touched.
- */
- conf_touch_dep(line + strlen(CONFIG_));
- else
- sym_add_change_count(1);
- continue;
- }
-
- if (sym->flags & def_flags) {
- conf_warning("override: reassigning to symbol %s", sym->name);
- }
- if (conf_set_sym_val(sym, def, def_flags, p))
- continue;
- } else {
- if (line[0] != '\r' && line[0] != '\n')
- conf_warning("unexpected data: %.*s",
- (int)strcspn(line, "\r\n"), line);
-
- continue;
- }
-
- if (sym && sym_is_choice_value(sym)) {
- struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym));
- switch (sym->def[def].tri) {
- case no:
- break;
- case mod:
- if (cs->def[def].tri == yes) {
- conf_warning("%s creates inconsistent choice state", sym->name);
- cs->flags &= ~def_flags;
- }
- break;
- case yes:
- if (cs->def[def].tri != no)
- conf_warning("override: %s changes choice state", sym->name);
- cs->def[def].val = sym;
- break;
- }
- cs->def[def].tri = EXPR_OR(cs->def[def].tri, sym->def[def].tri);
- }
- }
- free(line);
- fclose(in);
- return 0;
-}
-
-int conf_read(const char *name)
-{
- struct symbol *sym;
- int conf_unsaved = 0;
- int i;
-
- sym_set_change_count(0);
-
- if (conf_read_simple(name, S_DEF_USER)) {
- sym_calc_value(modules_sym);
- return 1;
- }
-
- sym_calc_value(modules_sym);
-
- for_all_symbols(i, sym) {
- sym_calc_value(sym);
- if (sym_is_choice(sym) || (sym->flags & SYMBOL_NO_WRITE))
- continue;
- if (sym_has_value(sym) && (sym->flags & SYMBOL_WRITE)) {
- /* check that calculated value agrees with saved value */
- switch (sym->type) {
- case S_BOOLEAN:
- case S_TRISTATE:
- if (sym->def[S_DEF_USER].tri == sym_get_tristate_value(sym))
- continue;
- break;
- default:
- if (!strcmp(sym->curr.val, sym->def[S_DEF_USER].val))
- continue;
- break;
- }
- } else if (!sym_has_value(sym) && !(sym->flags & SYMBOL_WRITE))
- /* no previous value and not saved */
- continue;
- conf_unsaved++;
- /* maybe print value in verbose mode... */
- }
-
- for_all_symbols(i, sym) {
- if (sym_has_value(sym) && !sym_is_choice_value(sym)) {
- /* Reset values of generates values, so they'll appear
- * as new, if they should become visible, but that
- * doesn't quite work if the Kconfig and the saved
- * configuration disagree.
- */
- if (sym->visible == no && !conf_unsaved)
- sym->flags &= ~SYMBOL_DEF_USER;
- switch (sym->type) {
- case S_STRING:
- case S_INT:
- case S_HEX:
- /* Reset a string value if it's out of range */
- if (sym_string_within_range(sym, sym->def[S_DEF_USER].val))
- break;
- sym->flags &= ~(SYMBOL_VALID|SYMBOL_DEF_USER);
- conf_unsaved++;
- break;
- default:
- break;
- }
- }
- }
-
- sym_add_change_count(conf_warnings || conf_unsaved);
-
- return 0;
-}
-
-/*
- * Kconfig configuration printer
- *
- * This printer is used when generating the resulting configuration after
- * kconfig invocation and `defconfig' files. Unset symbol might be omitted by
- * passing a non-NULL argument to the printer.
- *
- */
-static void
-kconfig_print_symbol(FILE *fp, struct symbol *sym, const char *value, void *arg)
-{
-
- switch (sym->type) {
- case S_BOOLEAN:
- case S_TRISTATE:
- if (*value == 'n') {
- bool skip_unset = (arg != NULL);
-
- if (!skip_unset)
- fprintf(fp, "# %s%s is not set\n",
- CONFIG_, sym->name);
- return;
- }
- break;
- default:
- break;
- }
-
- fprintf(fp, "%s%s=%s\n", CONFIG_, sym->name, value);
-}
-
-static void
-kconfig_print_comment(FILE *fp, const char *value, void *arg)
-{
- const char *p = value;
- size_t l;
-
- for (;;) {
- l = strcspn(p, "\n");
- fprintf(fp, "#");
- if (l) {
- fprintf(fp, " ");
- xfwrite(p, l, 1, fp);
- p += l;
- }
- fprintf(fp, "\n");
- if (*p++ == '\0')
- break;
- }
-}
-
-static struct conf_printer kconfig_printer_cb =
-{
- .print_symbol = kconfig_print_symbol,
- .print_comment = kconfig_print_comment,
-};
-
-/*
- * Header printer
- *
- * This printer is used when generating the `include/generated/autoconf.h' file.
- */
-static void
-header_print_symbol(FILE *fp, struct symbol *sym, const char *value, void *arg)
-{
-
- switch (sym->type) {
- case S_BOOLEAN:
- case S_TRISTATE: {
- const char *suffix = "";
-
- switch (*value) {
- case 'n':
- break;
- case 'm':
- suffix = "_MODULE";
- /* fall through */
- default:
- fprintf(fp, "#define %s%s%s 1\n",
- CONFIG_, sym->name, suffix);
- }
- break;
- }
- case S_HEX: {
- const char *prefix = "";
-
- if (value[0] != '0' || (value[1] != 'x' && value[1] != 'X'))
- prefix = "0x";
- fprintf(fp, "#define %s%s %s%s\n",
- CONFIG_, sym->name, prefix, value);
- break;
- }
- case S_STRING:
- case S_INT:
- fprintf(fp, "#define %s%s %s\n",
- CONFIG_, sym->name, value);
- break;
- default:
- break;
- }
-
-}
-
-static void
-header_print_comment(FILE *fp, const char *value, void *arg)
-{
- const char *p = value;
- size_t l;
-
- fprintf(fp, "/*\n");
- for (;;) {
- l = strcspn(p, "\n");
- fprintf(fp, " *");
- if (l) {
- fprintf(fp, " ");
- xfwrite(p, l, 1, fp);
- p += l;
- }
- fprintf(fp, "\n");
- if (*p++ == '\0')
- break;
- }
- fprintf(fp, " */\n");
-}
-
-static struct conf_printer header_printer_cb =
-{
- .print_symbol = header_print_symbol,
- .print_comment = header_print_comment,
-};
-
-/*
- * Tristate printer
- *
- * This printer is used when generating the `include/config/tristate.conf' file.
- */
-static void
-tristate_print_symbol(FILE *fp, struct symbol *sym, const char *value, void *arg)
-{
-
- if (sym->type == S_TRISTATE && *value != 'n')
- fprintf(fp, "%s%s=%c\n", CONFIG_, sym->name, (char)toupper(*value));
-}
-
-static struct conf_printer tristate_printer_cb =
-{
- .print_symbol = tristate_print_symbol,
- .print_comment = kconfig_print_comment,
-};
-
-static void conf_write_symbol(FILE *fp, struct symbol *sym,
- struct conf_printer *printer, void *printer_arg)
-{
- const char *str;
-
- switch (sym->type) {
- case S_UNKNOWN:
- break;
- case S_STRING:
- str = sym_get_string_value(sym);
- str = sym_escape_string_value(str);
- printer->print_symbol(fp, sym, str, printer_arg);
- free((void *)str);
- break;
- default:
- str = sym_get_string_value(sym);
- printer->print_symbol(fp, sym, str, printer_arg);
- }
-}
-
-static void
-conf_write_heading(FILE *fp, struct conf_printer *printer, void *printer_arg)
-{
- char buf[256];
-
- snprintf(buf, sizeof(buf),
- "\n"
- "Automatically generated file; DO NOT EDIT.\n"
- "%s\n",
- rootmenu.prompt->text);
-
- printer->print_comment(fp, buf, printer_arg);
-}
-
-/*
- * Write out a minimal config.
- * All values that has default values are skipped as this is redundant.
- */
-int conf_write_defconfig(const char *filename)
-{
- struct symbol *sym;
- struct menu *menu;
- FILE *out;
-
- out = fopen(filename, "w");
- if (!out)
- return 1;
-
- sym_clear_all_valid();
-
- /* Traverse all menus to find all relevant symbols */
- menu = rootmenu.list;
-
- while (menu != NULL)
- {
- sym = menu->sym;
- if (sym == NULL) {
- if (!menu_is_visible(menu))
- goto next_menu;
- } else if (!sym_is_choice(sym)) {
- sym_calc_value(sym);
- if (!(sym->flags & SYMBOL_WRITE))
- goto next_menu;
- sym->flags &= ~SYMBOL_WRITE;
- /* If we cannot change the symbol - skip */
- if (!sym_is_changeable(sym))
- goto next_menu;
- /* If symbol equals to default value - skip */
- if (strcmp(sym_get_string_value(sym), sym_get_string_default(sym)) == 0)
- goto next_menu;
-
- /*
- * If symbol is a choice value and equals to the
- * default for a choice - skip.
- * But only if value is bool and equal to "y" and
- * choice is not "optional".
- * (If choice is "optional" then all values can be "n")
- */
- if (sym_is_choice_value(sym)) {
- struct symbol *cs;
- struct symbol *ds;
-
- cs = prop_get_symbol(sym_get_choice_prop(sym));
- ds = sym_choice_default(cs);
- if (!sym_is_optional(cs) && sym == ds) {
- if ((sym->type == S_BOOLEAN) &&
- sym_get_tristate_value(sym) == yes)
- goto next_menu;
- }
- }
- conf_write_symbol(out, sym, &kconfig_printer_cb, NULL);
- }
-next_menu:
- if (menu->list != NULL) {
- menu = menu->list;
- }
- else if (menu->next != NULL) {
- menu = menu->next;
- } else {
- while ((menu = menu->parent)) {
- if (menu->next != NULL) {
- menu = menu->next;
- break;
- }
- }
- }
- }
- fclose(out);
- return 0;
-}
-
-int conf_write(const char *name)
-{
- FILE *out;
- struct symbol *sym;
- struct menu *menu;
- const char *str;
- char tmpname[PATH_MAX + 1], oldname[PATH_MAX + 1];
- char *env;
- int i;
- bool need_newline = false;
-
- if (!name)
- name = conf_get_configname();
-
- if (!*name) {
- fprintf(stderr, "config name is empty\n");
- return -1;
- }
-
- if (is_dir(name)) {
- fprintf(stderr, "%s: Is a directory\n", name);
- return -1;
- }
-
- if (make_parent_dir(name))
- return -1;
-
- env = getenv("KCONFIG_OVERWRITECONFIG");
- if (env && *env) {
- *tmpname = 0;
- out = fopen(name, "w");
- } else {
- snprintf(tmpname, sizeof(tmpname), "%s.%d.tmp",
- name, (int)getpid());
- out = fopen(tmpname, "w");
- }
- if (!out)
- return 1;
-
- conf_write_heading(out, &kconfig_printer_cb, NULL);
-
- if (!conf_get_changed())
- sym_clear_all_valid();
-
- menu = rootmenu.list;
- while (menu) {
- sym = menu->sym;
- if (!sym) {
- if (!menu_is_visible(menu))
- goto next;
- str = menu_get_prompt(menu);
- fprintf(out, "\n"
- "#\n"
- "# %s\n"
- "#\n", str);
- need_newline = false;
- } else if (!(sym->flags & SYMBOL_CHOICE) &&
- !(sym->flags & SYMBOL_WRITTEN)) {
- sym_calc_value(sym);
- if (!(sym->flags & SYMBOL_WRITE))
- goto next;
- if (need_newline) {
- fprintf(out, "\n");
- need_newline = false;
- }
- sym->flags |= SYMBOL_WRITTEN;
- conf_write_symbol(out, sym, &kconfig_printer_cb, NULL);
- }
-
-next:
- if (menu->list) {
- menu = menu->list;
- continue;
- }
- if (menu->next)
- menu = menu->next;
- else while ((menu = menu->parent)) {
- if (!menu->sym && menu_is_visible(menu) &&
- menu != &rootmenu) {
- str = menu_get_prompt(menu);
- fprintf(out, "# end of %s\n", str);
- need_newline = true;
- }
- if (menu->next) {
- menu = menu->next;
- break;
- }
- }
- }
- fclose(out);
-
- for_all_symbols(i, sym)
- sym->flags &= ~SYMBOL_WRITTEN;
-
- if (*tmpname) {
- if (is_same(name, tmpname)) {
- conf_message("No change to %s", name);
- unlink(tmpname);
- sym_set_change_count(0);
- return 0;
- }
-
- snprintf(oldname, sizeof(oldname), "%s.old", name);
- rename(name, oldname);
- if (rename(tmpname, name))
- return 1;
- }
-
- conf_message("configuration written to %s", name);
-
- sym_set_change_count(0);
-
- return 0;
-}
-
-/* write a dependency file as used by kbuild to track dependencies */
-static int conf_write_dep(const char *name)
-{
- struct file *file;
- FILE *out;
-
- out = fopen("..config.tmp", "w");
- if (!out)
- return 1;
- fprintf(out, "deps_config := \\\n");
- for (file = file_list; file; file = file->next) {
- if (file->next)
- fprintf(out, "\t%s \\\n", file->name);
- else
- fprintf(out, "\t%s\n", file->name);
- }
- fprintf(out, "\n%s: \\\n"
- "\t$(deps_config)\n\n", conf_get_autoconfig_name());
-
- env_write_dep(out, conf_get_autoconfig_name());
-
- fprintf(out, "\n$(deps_config): ;\n");
- fclose(out);
-
- if (make_parent_dir(name))
- return 1;
- rename("..config.tmp", name);
- return 0;
-}
-
-static int conf_touch_deps(void)
-{
- const char *name, *tmp;
- struct symbol *sym;
- int res, i;
-
- name = conf_get_autoconfig_name();
- tmp = strrchr(name, '/');
- depfile_prefix_len = tmp ? tmp - name + 1 : 0;
- if (depfile_prefix_len + 1 > sizeof(depfile_path))
- return -1;
-
- strncpy(depfile_path, name, depfile_prefix_len);
- depfile_path[depfile_prefix_len] = 0;
-
- conf_read_simple(name, S_DEF_AUTO);
- sym_calc_value(modules_sym);
-
- for_all_symbols(i, sym) {
- sym_calc_value(sym);
- if ((sym->flags & SYMBOL_NO_WRITE) || !sym->name)
- continue;
- if (sym->flags & SYMBOL_WRITE) {
- if (sym->flags & SYMBOL_DEF_AUTO) {
- /*
- * symbol has old and new value,
- * so compare them...
- */
- switch (sym->type) {
- case S_BOOLEAN:
- case S_TRISTATE:
- if (sym_get_tristate_value(sym) ==
- sym->def[S_DEF_AUTO].tri)
- continue;
- break;
- case S_STRING:
- case S_HEX:
- case S_INT:
- if (!strcmp(sym_get_string_value(sym),
- sym->def[S_DEF_AUTO].val))
- continue;
- break;
- default:
- break;
- }
- } else {
- /*
- * If there is no old value, only 'no' (unset)
- * is allowed as new value.
- */
- switch (sym->type) {
- case S_BOOLEAN:
- case S_TRISTATE:
- if (sym_get_tristate_value(sym) == no)
- continue;
- break;
- default:
- break;
- }
- }
- } else if (!(sym->flags & SYMBOL_DEF_AUTO))
- /* There is neither an old nor a new value. */
- continue;
- /* else
- * There is an old value, but no new value ('no' (unset)
- * isn't saved in auto.conf, so the old value is always
- * different from 'no').
- */
-
- res = conf_touch_dep(sym->name);
- if (res)
- return res;
- }
-
- return 0;
-}
-
-int conf_write_autoconf(int overwrite)
-{
- struct symbol *sym;
- const char *name;
- const char *autoconf_name = conf_get_autoconfig_name();
- FILE *out, *tristate, *out_h;
- int i;
-
- if (!overwrite && is_present(autoconf_name))
- return 0;
-
- conf_write_dep("include/config/auto.conf.cmd");
-
- if (conf_touch_deps())
- return 1;
-
- out = fopen(".tmpconfig", "w");
- if (!out)
- return 1;
-
- tristate = fopen(".tmpconfig_tristate", "w");
- if (!tristate) {
- fclose(out);
- return 1;
- }
-
- out_h = fopen(".tmpconfig.h", "w");
- if (!out_h) {
- fclose(out);
- fclose(tristate);
- return 1;
- }
-
- conf_write_heading(out, &kconfig_printer_cb, NULL);
-
- conf_write_heading(tristate, &tristate_printer_cb, NULL);
-
- conf_write_heading(out_h, &header_printer_cb, NULL);
-
- for_all_symbols(i, sym) {
- sym_calc_value(sym);
- if (!(sym->flags & SYMBOL_WRITE) || !sym->name)
- continue;
-
- /* write symbol to auto.conf, tristate and header files */
- conf_write_symbol(out, sym, &kconfig_printer_cb, (void *)1);
-
- conf_write_symbol(tristate, sym, &tristate_printer_cb, (void *)1);
-
- conf_write_symbol(out_h, sym, &header_printer_cb, NULL);
- }
- fclose(out);
- fclose(tristate);
- fclose(out_h);
-
- name = getenv("KCONFIG_AUTOHEADER");
- if (!name)
- name = "include/generated/autoconf.h";
- if (make_parent_dir(name))
- return 1;
- if (rename(".tmpconfig.h", name))
- return 1;
-
- name = getenv("KCONFIG_TRISTATE");
- if (!name)
- name = "include/config/tristate.conf";
- if (make_parent_dir(name))
- return 1;
- if (rename(".tmpconfig_tristate", name))
- return 1;
-
- if (make_parent_dir(autoconf_name))
- return 1;
- /*
- * This must be the last step, kbuild has a dependency on auto.conf
- * and this marks the successful completion of the previous steps.
- */
- if (rename(".tmpconfig", autoconf_name))
- return 1;
-
- return 0;
-}
-
-static int sym_change_count;
-static void (*conf_changed_callback)(void);
-
-void sym_set_change_count(int count)
-{
- int _sym_change_count = sym_change_count;
- sym_change_count = count;
- if (conf_changed_callback &&
- (bool)_sym_change_count != (bool)count)
- conf_changed_callback();
-}
-
-void sym_add_change_count(int count)
-{
- sym_set_change_count(count + sym_change_count);
-}
-
-bool conf_get_changed(void)
-{
- return sym_change_count;
-}
-
-void conf_set_changed_callback(void (*fn)(void))
-{
- conf_changed_callback = fn;
-}
-
-static bool randomize_choice_values(struct symbol *csym)
-{
- struct property *prop;
- struct symbol *sym;
- struct expr *e;
- int cnt, def;
-
- /*
- * If choice is mod then we may have more items selected
- * and if no then no-one.
- * In both cases stop.
- */
- if (csym->curr.tri != yes)
- return false;
-
- prop = sym_get_choice_prop(csym);
-
- /* count entries in choice block */
- cnt = 0;
- expr_list_for_each_sym(prop->expr, e, sym)
- cnt++;
-
- /*
- * find a random value and set it to yes,
- * set the rest to no so we have only one set
- */
- def = (rand() % cnt);
-
- cnt = 0;
- expr_list_for_each_sym(prop->expr, e, sym) {
- if (def == cnt++) {
- sym->def[S_DEF_USER].tri = yes;
- csym->def[S_DEF_USER].val = sym;
- }
- else {
- sym->def[S_DEF_USER].tri = no;
- }
- sym->flags |= SYMBOL_DEF_USER;
- /* clear VALID to get value calculated */
- sym->flags &= ~SYMBOL_VALID;
- }
- csym->flags |= SYMBOL_DEF_USER;
- /* clear VALID to get value calculated */
- csym->flags &= ~(SYMBOL_VALID);
-
- return true;
-}
-
-void set_all_choice_values(struct symbol *csym)
-{
- struct property *prop;
- struct symbol *sym;
- struct expr *e;
-
- prop = sym_get_choice_prop(csym);
-
- /*
- * Set all non-assinged choice values to no
- */
- expr_list_for_each_sym(prop->expr, e, sym) {
- if (!sym_has_value(sym))
- sym->def[S_DEF_USER].tri = no;
- }
- csym->flags |= SYMBOL_DEF_USER;
- /* clear VALID to get value calculated */
- csym->flags &= ~(SYMBOL_VALID | SYMBOL_NEED_SET_CHOICE_VALUES);
-}
-
-bool conf_set_all_new_symbols(enum conf_def_mode mode)
-{
- struct symbol *sym, *csym;
- int i, cnt, pby, pty, ptm; /* pby: probability of bool = y
- * pty: probability of tristate = y
- * ptm: probability of tristate = m
- */
-
- pby = 50; pty = ptm = 33; /* can't go as the default in switch-case
- * below, otherwise gcc whines about
- * -Wmaybe-uninitialized */
- if (mode == def_random) {
- int n, p[3];
- char *env = getenv("KCONFIG_PROBABILITY");
- n = 0;
- while( env && *env ) {
- char *endp;
- int tmp = strtol( env, &endp, 10 );
- if( tmp >= 0 && tmp <= 100 ) {
- p[n++] = tmp;
- } else {
- errno = ERANGE;
- perror( "KCONFIG_PROBABILITY" );
- exit( 1 );
- }
- env = (*endp == ':') ? endp+1 : endp;
- if( n >=3 ) {
- break;
- }
- }
- switch( n ) {
- case 1:
- pby = p[0]; ptm = pby/2; pty = pby-ptm;
- break;
- case 2:
- pty = p[0]; ptm = p[1]; pby = pty + ptm;
- break;
- case 3:
- pby = p[0]; pty = p[1]; ptm = p[2];
- break;
- }
-
- if( pty+ptm > 100 ) {
- errno = ERANGE;
- perror( "KCONFIG_PROBABILITY" );
- exit( 1 );
- }
- }
- bool has_changed = false;
-
- for_all_symbols(i, sym) {
- if (sym_has_value(sym) || (sym->flags & SYMBOL_VALID))
- continue;
- switch (sym_get_type(sym)) {
- case S_BOOLEAN:
- case S_TRISTATE:
- has_changed = true;
- switch (mode) {
- case def_yes:
- sym->def[S_DEF_USER].tri = yes;
- break;
- case def_mod:
- sym->def[S_DEF_USER].tri = mod;
- break;
- case def_no:
- if (sym->flags & SYMBOL_ALLNOCONFIG_Y)
- sym->def[S_DEF_USER].tri = yes;
- else
- sym->def[S_DEF_USER].tri = no;
- break;
- case def_random:
- sym->def[S_DEF_USER].tri = no;
- cnt = rand() % 100;
- if (sym->type == S_TRISTATE) {
- if (cnt < pty)
- sym->def[S_DEF_USER].tri = yes;
- else if (cnt < (pty+ptm))
- sym->def[S_DEF_USER].tri = mod;
- } else if (cnt < pby)
- sym->def[S_DEF_USER].tri = yes;
- break;
- default:
- continue;
- }
- if (!(sym_is_choice(sym) && mode == def_random))
- sym->flags |= SYMBOL_DEF_USER;
- break;
- default:
- break;
- }
-
- }
-
- sym_clear_all_valid();
-
- /*
- * We have different type of choice blocks.
- * If curr.tri equals to mod then we can select several
- * choice symbols in one block.
- * In this case we do nothing.
- * If curr.tri equals yes then only one symbol can be
- * selected in a choice block and we set it to yes,
- * and the rest to no.
- */
- if (mode != def_random) {
- for_all_symbols(i, csym) {
- if ((sym_is_choice(csym) && !sym_has_value(csym)) ||
- sym_is_choice_value(csym))
- csym->flags |= SYMBOL_NEED_SET_CHOICE_VALUES;
- }
- }
-
- for_all_symbols(i, csym) {
- if (sym_has_value(csym) || !sym_is_choice(csym))
- continue;
-
- sym_calc_value(csym);
- if (mode == def_random)
- has_changed |= randomize_choice_values(csym);
- else {
- set_all_choice_values(csym);
- has_changed = true;
- }
- }
-
- return has_changed;
-}
Index: Baikal/M1000/create-5.4.211-5.7.226-host-limits-patch/linux-m1-5.4.211-5.7.226-new/scripts/kconfig/conf.c
===================================================================
--- Baikal/M1000/create-5.4.211-5.7.226-host-limits-patch/linux-m1-5.4.211-5.7.226-new/scripts/kconfig/conf.c (revision 384)
+++ Baikal/M1000/create-5.4.211-5.7.226-host-limits-patch/linux-m1-5.4.211-5.7.226-new/scripts/kconfig/conf.c (nonexistent)
@@ -1,700 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
- */
-
-#include <ctype.h>
-#include <linux/limits.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <unistd.h>
-#include <getopt.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <errno.h>
-
-#include "lkc.h"
-
-static void conf(struct menu *menu);
-static void check_conf(struct menu *menu);
-
-enum input_mode {
- oldaskconfig,
- syncconfig,
- oldconfig,
- allnoconfig,
- allyesconfig,
- allmodconfig,
- alldefconfig,
- randconfig,
- defconfig,
- savedefconfig,
- listnewconfig,
- olddefconfig,
-};
-static enum input_mode input_mode = oldaskconfig;
-
-static int indent = 1;
-static int tty_stdio;
-static int sync_kconfig;
-static int conf_cnt;
-static char line[PATH_MAX];
-static struct menu *rootEntry;
-
-static void print_help(struct menu *menu)
-{
- struct gstr help = str_new();
-
- menu_get_ext_help(menu, &help);
-
- printf("\n%s\n", str_get(&help));
- str_free(&help);
-}
-
-static void strip(char *str)
-{
- char *p = str;
- int l;
-
- while ((isspace(*p)))
- p++;
- l = strlen(p);
- if (p != str)
- memmove(str, p, l + 1);
- if (!l)
- return;
- p = str + l - 1;
- while ((isspace(*p)))
- *p-- = 0;
-}
-
-/* Helper function to facilitate fgets() by Jean Sacren. */
-static void xfgets(char *str, int size, FILE *in)
-{
- if (!fgets(str, size, in))
- fprintf(stderr, "\nError in reading or end of file.\n");
-
- if (!tty_stdio)
- printf("%s", str);
-}
-
-static int conf_askvalue(struct symbol *sym, const char *def)
-{
- enum symbol_type type = sym_get_type(sym);
-
- if (!sym_has_value(sym))
- printf("(NEW) ");
-
- line[0] = '\n';
- line[1] = 0;
-
- if (!sym_is_changeable(sym)) {
- printf("%s\n", def);
- line[0] = '\n';
- line[1] = 0;
- return 0;
- }
-
- switch (input_mode) {
- case oldconfig:
- case syncconfig:
- if (sym_has_value(sym)) {
- printf("%s\n", def);
- return 0;
- }
- /* fall through */
- case oldaskconfig:
- fflush(stdout);
- xfgets(line, sizeof(line), stdin);
- return 1;
- default:
- break;
- }
-
- switch (type) {
- case S_INT:
- case S_HEX:
- case S_STRING:
- printf("%s\n", def);
- return 1;
- default:
- ;
- }
- printf("%s", line);
- return 1;
-}
-
-static int conf_string(struct menu *menu)
-{
- struct symbol *sym = menu->sym;
- const char *def;
-
- while (1) {
- printf("%*s%s ", indent - 1, "", menu->prompt->text);
- printf("(%s) ", sym->name);
- def = sym_get_string_value(sym);
- if (sym_get_string_value(sym))
- printf("[%s] ", def);
- if (!conf_askvalue(sym, def))
- return 0;
- switch (line[0]) {
- case '\n':
- break;
- case '?':
- /* print help */
- if (line[1] == '\n') {
- print_help(menu);
- def = NULL;
- break;
- }
- /* fall through */
- default:
- line[strlen(line)-1] = 0;
- def = line;
- }
- if (def && sym_set_string_value(sym, def))
- return 0;
- }
-}
-
-static int conf_sym(struct menu *menu)
-{
- struct symbol *sym = menu->sym;
- tristate oldval, newval;
-
- while (1) {
- printf("%*s%s ", indent - 1, "", menu->prompt->text);
- if (sym->name)
- printf("(%s) ", sym->name);
- putchar('[');
- oldval = sym_get_tristate_value(sym);
- switch (oldval) {
- case no:
- putchar('N');
- break;
- case mod:
- putchar('M');
- break;
- case yes:
- putchar('Y');
- break;
- }
- if (oldval != no && sym_tristate_within_range(sym, no))
- printf("/n");
- if (oldval != mod && sym_tristate_within_range(sym, mod))
- printf("/m");
- if (oldval != yes && sym_tristate_within_range(sym, yes))
- printf("/y");
- printf("/?] ");
- if (!conf_askvalue(sym, sym_get_string_value(sym)))
- return 0;
- strip(line);
-
- switch (line[0]) {
- case 'n':
- case 'N':
- newval = no;
- if (!line[1] || !strcmp(&line[1], "o"))
- break;
- continue;
- case 'm':
- case 'M':
- newval = mod;
- if (!line[1])
- break;
- continue;
- case 'y':
- case 'Y':
- newval = yes;
- if (!line[1] || !strcmp(&line[1], "es"))
- break;
- continue;
- case 0:
- newval = oldval;
- break;
- case '?':
- goto help;
- default:
- continue;
- }
- if (sym_set_tristate_value(sym, newval))
- return 0;
-help:
- print_help(menu);
- }
-}
-
-static int conf_choice(struct menu *menu)
-{
- struct symbol *sym, *def_sym;
- struct menu *child;
- bool is_new;
-
- sym = menu->sym;
- is_new = !sym_has_value(sym);
- if (sym_is_changeable(sym)) {
- conf_sym(menu);
- sym_calc_value(sym);
- switch (sym_get_tristate_value(sym)) {
- case no:
- return 1;
- case mod:
- return 0;
- case yes:
- break;
- }
- } else {
- switch (sym_get_tristate_value(sym)) {
- case no:
- return 1;
- case mod:
- printf("%*s%s\n", indent - 1, "", menu_get_prompt(menu));
- return 0;
- case yes:
- break;
- }
- }
-
- while (1) {
- int cnt, def;
-
- printf("%*s%s\n", indent - 1, "", menu_get_prompt(menu));
- def_sym = sym_get_choice_value(sym);
- cnt = def = 0;
- line[0] = 0;
- for (child = menu->list; child; child = child->next) {
- if (!menu_is_visible(child))
- continue;
- if (!child->sym) {
- printf("%*c %s\n", indent, '*', menu_get_prompt(child));
- continue;
- }
- cnt++;
- if (child->sym == def_sym) {
- def = cnt;
- printf("%*c", indent, '>');
- } else
- printf("%*c", indent, ' ');
- printf(" %d. %s", cnt, menu_get_prompt(child));
- if (child->sym->name)
- printf(" (%s)", child->sym->name);
- if (!sym_has_value(child->sym))
- printf(" (NEW)");
- printf("\n");
- }
- printf("%*schoice", indent - 1, "");
- if (cnt == 1) {
- printf("[1]: 1\n");
- goto conf_childs;
- }
- printf("[1-%d?]: ", cnt);
- switch (input_mode) {
- case oldconfig:
- case syncconfig:
- if (!is_new) {
- cnt = def;
- printf("%d\n", cnt);
- break;
- }
- /* fall through */
- case oldaskconfig:
- fflush(stdout);
- xfgets(line, sizeof(line), stdin);
- strip(line);
- if (line[0] == '?') {
- print_help(menu);
- continue;
- }
- if (!line[0])
- cnt = def;
- else if (isdigit(line[0]))
- cnt = atoi(line);
- else
- continue;
- break;
- default:
- break;
- }
-
- conf_childs:
- for (child = menu->list; child; child = child->next) {
- if (!child->sym || !menu_is_visible(child))
- continue;
- if (!--cnt)
- break;
- }
- if (!child)
- continue;
- if (line[0] && line[strlen(line) - 1] == '?') {
- print_help(child);
- continue;
- }
- sym_set_choice_value(sym, child->sym);
- for (child = child->list; child; child = child->next) {
- indent += 2;
- conf(child);
- indent -= 2;
- }
- return 1;
- }
-}
-
-static void conf(struct menu *menu)
-{
- struct symbol *sym;
- struct property *prop;
- struct menu *child;
-
- if (!menu_is_visible(menu))
- return;
-
- sym = menu->sym;
- prop = menu->prompt;
- if (prop) {
- const char *prompt;
-
- switch (prop->type) {
- case P_MENU:
- /*
- * Except in oldaskconfig mode, we show only menus that
- * contain new symbols.
- */
- if (input_mode != oldaskconfig && rootEntry != menu) {
- check_conf(menu);
- return;
- }
- /* fall through */
- case P_COMMENT:
- prompt = menu_get_prompt(menu);
- if (prompt)
- printf("%*c\n%*c %s\n%*c\n",
- indent, '*',
- indent, '*', prompt,
- indent, '*');
- default:
- ;
- }
- }
-
- if (!sym)
- goto conf_childs;
-
- if (sym_is_choice(sym)) {
- conf_choice(menu);
- if (sym->curr.tri != mod)
- return;
- goto conf_childs;
- }
-
- switch (sym->type) {
- case S_INT:
- case S_HEX:
- case S_STRING:
- conf_string(menu);
- break;
- default:
- conf_sym(menu);
- break;
- }
-
-conf_childs:
- if (sym)
- indent += 2;
- for (child = menu->list; child; child = child->next)
- conf(child);
- if (sym)
- indent -= 2;
-}
-
-static void check_conf(struct menu *menu)
-{
- struct symbol *sym;
- struct menu *child;
-
- if (!menu_is_visible(menu))
- return;
-
- sym = menu->sym;
- if (sym && !sym_has_value(sym)) {
- if (sym_is_changeable(sym) ||
- (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)) {
- if (input_mode == listnewconfig) {
- if (sym->name) {
- const char *str;
-
- if (sym->type == S_STRING) {
- str = sym_get_string_value(sym);
- str = sym_escape_string_value(str);
- printf("%s%s=%s\n", CONFIG_, sym->name, str);
- free((void *)str);
- } else {
- str = sym_get_string_value(sym);
- printf("%s%s=%s\n", CONFIG_, sym->name, str);
- }
- }
- } else {
- if (!conf_cnt++)
- printf("*\n* Restart config...\n*\n");
- rootEntry = menu_get_parent_menu(menu);
- conf(rootEntry);
- }
- }
- }
-
- for (child = menu->list; child; child = child->next)
- check_conf(child);
-}
-
-static struct option long_opts[] = {
- {"oldaskconfig", no_argument, NULL, oldaskconfig},
- {"oldconfig", no_argument, NULL, oldconfig},
- {"syncconfig", no_argument, NULL, syncconfig},
- {"defconfig", required_argument, NULL, defconfig},
- {"savedefconfig", required_argument, NULL, savedefconfig},
- {"allnoconfig", no_argument, NULL, allnoconfig},
- {"allyesconfig", no_argument, NULL, allyesconfig},
- {"allmodconfig", no_argument, NULL, allmodconfig},
- {"alldefconfig", no_argument, NULL, alldefconfig},
- {"randconfig", no_argument, NULL, randconfig},
- {"listnewconfig", no_argument, NULL, listnewconfig},
- {"olddefconfig", no_argument, NULL, olddefconfig},
- {NULL, 0, NULL, 0}
-};
-
-static void conf_usage(const char *progname)
-{
-
- printf("Usage: %s [-s] [option] <kconfig-file>\n", progname);
- printf("[option] is _one_ of the following:\n");
- printf(" --listnewconfig List new options\n");
- printf(" --oldaskconfig Start a new configuration using a line-oriented program\n");
- printf(" --oldconfig Update a configuration using a provided .config as base\n");
- printf(" --syncconfig Similar to oldconfig but generates configuration in\n"
- " include/{generated/,config/}\n");
- printf(" --olddefconfig Same as oldconfig but sets new symbols to their default value\n");
- printf(" --defconfig <file> New config with default defined in <file>\n");
- printf(" --savedefconfig <file> Save the minimal current configuration to <file>\n");
- printf(" --allnoconfig New config where all options are answered with no\n");
- printf(" --allyesconfig New config where all options are answered with yes\n");
- printf(" --allmodconfig New config where all options are answered with mod\n");
- printf(" --alldefconfig New config with all symbols set to default\n");
- printf(" --randconfig New config with random answer to all options\n");
-}
-
-int main(int ac, char **av)
-{
- const char *progname = av[0];
- int opt;
- const char *name, *defconfig_file = NULL /* gcc uninit */;
- int no_conf_write = 0;
-
- tty_stdio = isatty(0) && isatty(1);
-
- while ((opt = getopt_long(ac, av, "s", long_opts, NULL)) != -1) {
- if (opt == 's') {
- conf_set_message_callback(NULL);
- continue;
- }
- input_mode = (enum input_mode)opt;
- switch (opt) {
- case syncconfig:
- /*
- * syncconfig is invoked during the build stage.
- * Suppress distracting "configuration written to ..."
- */
- conf_set_message_callback(NULL);
- sync_kconfig = 1;
- break;
- case defconfig:
- case savedefconfig:
- defconfig_file = optarg;
- break;
- case randconfig:
- {
- struct timeval now;
- unsigned int seed;
- char *seed_env;
-
- /*
- * Use microseconds derived seed,
- * compensate for systems where it may be zero
- */
- gettimeofday(&now, NULL);
- seed = (unsigned int)((now.tv_sec + 1) * (now.tv_usec + 1));
-
- seed_env = getenv("KCONFIG_SEED");
- if( seed_env && *seed_env ) {
- char *endp;
- int tmp = (int)strtol(seed_env, &endp, 0);
- if (*endp == '\0') {
- seed = tmp;
- }
- }
- fprintf( stderr, "KCONFIG_SEED=0x%X\n", seed );
- srand(seed);
- break;
- }
- case oldaskconfig:
- case oldconfig:
- case allnoconfig:
- case allyesconfig:
- case allmodconfig:
- case alldefconfig:
- case listnewconfig:
- case olddefconfig:
- break;
- case '?':
- conf_usage(progname);
- exit(1);
- break;
- }
- }
- if (ac == optind) {
- fprintf(stderr, "%s: Kconfig file missing\n", av[0]);
- conf_usage(progname);
- exit(1);
- }
- name = av[optind];
- conf_parse(name);
- //zconfdump(stdout);
-
- switch (input_mode) {
- case defconfig:
- if (conf_read(defconfig_file)) {
- fprintf(stderr,
- "***\n"
- "*** Can't find default configuration \"%s\"!\n"
- "***\n",
- defconfig_file);
- exit(1);
- }
- break;
- case savedefconfig:
- case syncconfig:
- case oldaskconfig:
- case oldconfig:
- case listnewconfig:
- case olddefconfig:
- conf_read(NULL);
- break;
- case allnoconfig:
- case allyesconfig:
- case allmodconfig:
- case alldefconfig:
- case randconfig:
- name = getenv("KCONFIG_ALLCONFIG");
- if (!name)
- break;
- if ((strcmp(name, "") != 0) && (strcmp(name, "1") != 0)) {
- if (conf_read_simple(name, S_DEF_USER)) {
- fprintf(stderr,
- "*** Can't read seed configuration \"%s\"!\n",
- name);
- exit(1);
- }
- break;
- }
- switch (input_mode) {
- case allnoconfig: name = "allno.config"; break;
- case allyesconfig: name = "allyes.config"; break;
- case allmodconfig: name = "allmod.config"; break;
- case alldefconfig: name = "alldef.config"; break;
- case randconfig: name = "allrandom.config"; break;
- default: break;
- }
- if (conf_read_simple(name, S_DEF_USER) &&
- conf_read_simple("all.config", S_DEF_USER)) {
- fprintf(stderr,
- "*** KCONFIG_ALLCONFIG set, but no \"%s\" or \"all.config\" file found\n",
- name);
- exit(1);
- }
- break;
- default:
- break;
- }
-
- if (sync_kconfig) {
- name = getenv("KCONFIG_NOSILENTUPDATE");
- if (name && *name) {
- if (conf_get_changed()) {
- fprintf(stderr,
- "\n*** The configuration requires explicit update.\n\n");
- return 1;
- }
- no_conf_write = 1;
- }
- }
-
- switch (input_mode) {
- case allnoconfig:
- conf_set_all_new_symbols(def_no);
- break;
- case allyesconfig:
- conf_set_all_new_symbols(def_yes);
- break;
- case allmodconfig:
- conf_set_all_new_symbols(def_mod);
- break;
- case alldefconfig:
- conf_set_all_new_symbols(def_default);
- break;
- case randconfig:
- /* Really nothing to do in this loop */
- while (conf_set_all_new_symbols(def_random)) ;
- break;
- case defconfig:
- conf_set_all_new_symbols(def_default);
- break;
- case savedefconfig:
- break;
- case oldaskconfig:
- rootEntry = &rootmenu;
- conf(&rootmenu);
- input_mode = oldconfig;
- /* fall through */
- case oldconfig:
- case listnewconfig:
- case syncconfig:
- /* Update until a loop caused no more changes */
- do {
- conf_cnt = 0;
- check_conf(&rootmenu);
- } while (conf_cnt);
- break;
- case olddefconfig:
- default:
- break;
- }
-
- if (input_mode == savedefconfig) {
- if (conf_write_defconfig(defconfig_file)) {
- fprintf(stderr, "n*** Error while saving defconfig to: %s\n\n",
- defconfig_file);
- return 1;
- }
- } else if (input_mode != listnewconfig) {
- if (!no_conf_write && conf_write(NULL)) {
- fprintf(stderr, "\n*** Error during writing of the configuration.\n\n");
- exit(1);
- }
-
- /*
- * Create auto.conf if it does not exist.
- * This prevents GNU Make 4.1 or older from emitting
- * "include/config/auto.conf: No such file or directory"
- * in the top-level Makefile
- *
- * syncconfig always creates or updates auto.conf because it is
- * used during the build.
- */
- if (conf_write_autoconf(sync_kconfig) && sync_kconfig) {
- fprintf(stderr,
- "\n*** Error during sync of the configuration.\n\n");
- return 1;
- }
- }
- return 0;
-}
Index: Baikal/M1000/create-5.4.211-5.7.226-host-limits-patch/linux-m1-5.4.211-5.7.226-new/scripts/kconfig
===================================================================
--- Baikal/M1000/create-5.4.211-5.7.226-host-limits-patch/linux-m1-5.4.211-5.7.226-new/scripts/kconfig (revision 384)
+++ Baikal/M1000/create-5.4.211-5.7.226-host-limits-patch/linux-m1-5.4.211-5.7.226-new/scripts/kconfig (nonexistent)
Property changes on: Baikal/M1000/create-5.4.211-5.7.226-host-limits-patch/linux-m1-5.4.211-5.7.226-new/scripts/kconfig
___________________________________________________________________
Deleted: svn:ignore
## -1,73 +0,0 ##
-
-# install dir
-dist
-
-# Target build dirs
-.a1x-newlib
-.a2x-newlib
-.at91sam7s-newlib
-
-.build-machine
-
-.a1x-glibc
-.a2x-glibc
-.h3-glibc
-.h5-glibc
-.i586-glibc
-.i686-glibc
-.imx6-glibc
-.jz47xx-glibc
-.makefile
-.am335x-glibc
-.omap543x-glibc
-.p5600-glibc
-.power8-glibc
-.power8le-glibc
-.power9-glibc
-.power9le-glibc
-.m1000-glibc
-.riscv64-glibc
-.rk328x-glibc
-.rk33xx-glibc
-.rk339x-glibc
-.s8xx-glibc
-.s9xx-glibc
-.x86_64-glibc
-
-# Hidden files (each file)
-.makefile
-.dist
-.rootfs
-
-# src & hw requires
-.src_requires
-.src_requires_depend
-.requires
-.requires_depend
-
-# Tarballs
-*.gz
-*.bz2
-*.lz
-*.xz
-*.tgz
-*.txz
-
-# Signatures
-*.asc
-*.sig
-*.sign
-*.sha1sum
-
-# Patches
-*.patch
-
-# Descriptions
-*.dsc
-*.txt
-
-# Default linux config files
-*.defconfig
-
-# backup copies
-*~
Index: Baikal/M1000/create-5.4.211-5.7.226-host-limits-patch/linux-m1-5.4.211-5.7.226-new/scripts
===================================================================
--- Baikal/M1000/create-5.4.211-5.7.226-host-limits-patch/linux-m1-5.4.211-5.7.226-new/scripts (revision 384)
+++ Baikal/M1000/create-5.4.211-5.7.226-host-limits-patch/linux-m1-5.4.211-5.7.226-new/scripts (nonexistent)
Property changes on: Baikal/M1000/create-5.4.211-5.7.226-host-limits-patch/linux-m1-5.4.211-5.7.226-new/scripts
___________________________________________________________________
Deleted: svn:ignore
## -1,73 +0,0 ##
-
-# install dir
-dist
-
-# Target build dirs
-.a1x-newlib
-.a2x-newlib
-.at91sam7s-newlib
-
-.build-machine
-
-.a1x-glibc
-.a2x-glibc
-.h3-glibc
-.h5-glibc
-.i586-glibc
-.i686-glibc
-.imx6-glibc
-.jz47xx-glibc
-.makefile
-.am335x-glibc
-.omap543x-glibc
-.p5600-glibc
-.power8-glibc
-.power8le-glibc
-.power9-glibc
-.power9le-glibc
-.m1000-glibc
-.riscv64-glibc
-.rk328x-glibc
-.rk33xx-glibc
-.rk339x-glibc
-.s8xx-glibc
-.s9xx-glibc
-.x86_64-glibc
-
-# Hidden files (each file)
-.makefile
-.dist
-.rootfs
-
-# src & hw requires
-.src_requires
-.src_requires_depend
-.requires
-.requires_depend
-
-# Tarballs
-*.gz
-*.bz2
-*.lz
-*.xz
-*.tgz
-*.txz
-
-# Signatures
-*.asc
-*.sig
-*.sign
-*.sha1sum
-
-# Patches
-*.patch
-
-# Descriptions
-*.dsc
-*.txt
-
-# Default linux config files
-*.defconfig
-
-# backup copies
-*~
Index: Baikal/M1000/create-5.4.211-5.7.226-host-limits-patch/linux-m1-5.4.211-5.7.226-new/usr/gen_init_cpio.c
===================================================================
--- Baikal/M1000/create-5.4.211-5.7.226-host-limits-patch/linux-m1-5.4.211-5.7.226-new/usr/gen_init_cpio.c (revision 384)
+++ Baikal/M1000/create-5.4.211-5.7.226-host-limits-patch/linux-m1-5.4.211-5.7.226-new/usr/gen_init_cpio.c (nonexistent)
@@ -1,624 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <string.h>
-#include <unistd.h>
-#include <time.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <ctype.h>
-#include <linux/limits.h>
-
-/*
- * Original work by Jeff Garzik
- *
- * External file lists, symlink, pipe and fifo support by Thayne Harbaugh
- * Hard link support by Luciano Rocha
- */
-
-#define xstr(s) #s
-#define str(s) xstr(s)
-
-static unsigned int offset;
-static unsigned int ino = 721;
-static time_t default_mtime;
-
-struct file_handler {
- const char *type;
- int (*handler)(const char *line);
-};
-
-static void push_string(const char *name)
-{
- unsigned int name_len = strlen(name) + 1;
-
- fputs(name, stdout);
- putchar(0);
- offset += name_len;
-}
-
-static void push_pad (void)
-{
- while (offset & 3) {
- putchar(0);
- offset++;
- }
-}
-
-static void push_rest(const char *name)
-{
- unsigned int name_len = strlen(name) + 1;
- unsigned int tmp_ofs;
-
- fputs(name, stdout);
- putchar(0);
- offset += name_len;
-
- tmp_ofs = name_len + 110;
- while (tmp_ofs & 3) {
- putchar(0);
- offset++;
- tmp_ofs++;
- }
-}
-
-static void push_hdr(const char *s)
-{
- fputs(s, stdout);
- offset += 110;
-}
-
-static void cpio_trailer(void)
-{
- char s[256];
- const char name[] = "TRAILER!!!";
-
- sprintf(s, "%s%08X%08X%08lX%08lX%08X%08lX"
- "%08X%08X%08X%08X%08X%08X%08X",
- "070701", /* magic */
- 0, /* ino */
- 0, /* mode */
- (long) 0, /* uid */
- (long) 0, /* gid */
- 1, /* nlink */
- (long) 0, /* mtime */
- 0, /* filesize */
- 0, /* major */
- 0, /* minor */
- 0, /* rmajor */
- 0, /* rminor */
- (unsigned)strlen(name)+1, /* namesize */
- 0); /* chksum */
- push_hdr(s);
- push_rest(name);
-
- while (offset % 512) {
- putchar(0);
- offset++;
- }
-}
-
-static int cpio_mkslink(const char *name, const char *target,
- unsigned int mode, uid_t uid, gid_t gid)
-{
- char s[256];
-
- if (name[0] == '/')
- name++;
- sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
- "%08X%08X%08X%08X%08X%08X%08X",
- "070701", /* magic */
- ino++, /* ino */
- S_IFLNK | mode, /* mode */
- (long) uid, /* uid */
- (long) gid, /* gid */
- 1, /* nlink */
- (long) default_mtime, /* mtime */
- (unsigned)strlen(target)+1, /* filesize */
- 3, /* major */
- 1, /* minor */
- 0, /* rmajor */
- 0, /* rminor */
- (unsigned)strlen(name) + 1,/* namesize */
- 0); /* chksum */
- push_hdr(s);
- push_string(name);
- push_pad();
- push_string(target);
- push_pad();
- return 0;
-}
-
-static int cpio_mkslink_line(const char *line)
-{
- char name[PATH_MAX + 1];
- char target[PATH_MAX + 1];
- unsigned int mode;
- int uid;
- int gid;
- int rc = -1;
-
- if (5 != sscanf(line, "%" str(PATH_MAX) "s %" str(PATH_MAX) "s %o %d %d", name, target, &mode, &uid, &gid)) {
- fprintf(stderr, "Unrecognized dir format '%s'", line);
- goto fail;
- }
- rc = cpio_mkslink(name, target, mode, uid, gid);
- fail:
- return rc;
-}
-
-static int cpio_mkgeneric(const char *name, unsigned int mode,
- uid_t uid, gid_t gid)
-{
- char s[256];
-
- if (name[0] == '/')
- name++;
- sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
- "%08X%08X%08X%08X%08X%08X%08X",
- "070701", /* magic */
- ino++, /* ino */
- mode, /* mode */
- (long) uid, /* uid */
- (long) gid, /* gid */
- 2, /* nlink */
- (long) default_mtime, /* mtime */
- 0, /* filesize */
- 3, /* major */
- 1, /* minor */
- 0, /* rmajor */
- 0, /* rminor */
- (unsigned)strlen(name) + 1,/* namesize */
- 0); /* chksum */
- push_hdr(s);
- push_rest(name);
- return 0;
-}
-
-enum generic_types {
- GT_DIR,
- GT_PIPE,
- GT_SOCK
-};
-
-struct generic_type {
- const char *type;
- mode_t mode;
-};
-
-static struct generic_type generic_type_table[] = {
- [GT_DIR] = {
- .type = "dir",
- .mode = S_IFDIR
- },
- [GT_PIPE] = {
- .type = "pipe",
- .mode = S_IFIFO
- },
- [GT_SOCK] = {
- .type = "sock",
- .mode = S_IFSOCK
- }
-};
-
-static int cpio_mkgeneric_line(const char *line, enum generic_types gt)
-{
- char name[PATH_MAX + 1];
- unsigned int mode;
- int uid;
- int gid;
- int rc = -1;
-
- if (4 != sscanf(line, "%" str(PATH_MAX) "s %o %d %d", name, &mode, &uid, &gid)) {
- fprintf(stderr, "Unrecognized %s format '%s'",
- line, generic_type_table[gt].type);
- goto fail;
- }
- mode |= generic_type_table[gt].mode;
- rc = cpio_mkgeneric(name, mode, uid, gid);
- fail:
- return rc;
-}
-
-static int cpio_mkdir_line(const char *line)
-{
- return cpio_mkgeneric_line(line, GT_DIR);
-}
-
-static int cpio_mkpipe_line(const char *line)
-{
- return cpio_mkgeneric_line(line, GT_PIPE);
-}
-
-static int cpio_mksock_line(const char *line)
-{
- return cpio_mkgeneric_line(line, GT_SOCK);
-}
-
-static int cpio_mknod(const char *name, unsigned int mode,
- uid_t uid, gid_t gid, char dev_type,
- unsigned int maj, unsigned int min)
-{
- char s[256];
-
- if (dev_type == 'b')
- mode |= S_IFBLK;
- else
- mode |= S_IFCHR;
-
- if (name[0] == '/')
- name++;
- sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
- "%08X%08X%08X%08X%08X%08X%08X",
- "070701", /* magic */
- ino++, /* ino */
- mode, /* mode */
- (long) uid, /* uid */
- (long) gid, /* gid */
- 1, /* nlink */
- (long) default_mtime, /* mtime */
- 0, /* filesize */
- 3, /* major */
- 1, /* minor */
- maj, /* rmajor */
- min, /* rminor */
- (unsigned)strlen(name) + 1,/* namesize */
- 0); /* chksum */
- push_hdr(s);
- push_rest(name);
- return 0;
-}
-
-static int cpio_mknod_line(const char *line)
-{
- char name[PATH_MAX + 1];
- unsigned int mode;
- int uid;
- int gid;
- char dev_type;
- unsigned int maj;
- unsigned int min;
- int rc = -1;
-
- if (7 != sscanf(line, "%" str(PATH_MAX) "s %o %d %d %c %u %u",
- name, &mode, &uid, &gid, &dev_type, &maj, &min)) {
- fprintf(stderr, "Unrecognized nod format '%s'", line);
- goto fail;
- }
- rc = cpio_mknod(name, mode, uid, gid, dev_type, maj, min);
- fail:
- return rc;
-}
-
-static int cpio_mkfile(const char *name, const char *location,
- unsigned int mode, uid_t uid, gid_t gid,
- unsigned int nlinks)
-{
- char s[256];
- char *filebuf = NULL;
- struct stat buf;
- long size;
- int file = -1;
- int retval;
- int rc = -1;
- int namesize;
- unsigned int i;
-
- mode |= S_IFREG;
-
- file = open (location, O_RDONLY);
- if (file < 0) {
- fprintf (stderr, "File %s could not be opened for reading\n", location);
- goto error;
- }
-
- retval = fstat(file, &buf);
- if (retval) {
- fprintf(stderr, "File %s could not be stat()'ed\n", location);
- goto error;
- }
-
- filebuf = malloc(buf.st_size);
- if (!filebuf) {
- fprintf (stderr, "out of memory\n");
- goto error;
- }
-
- retval = read (file, filebuf, buf.st_size);
- if (retval < 0) {
- fprintf (stderr, "Can not read %s file\n", location);
- goto error;
- }
-
- size = 0;
- for (i = 1; i <= nlinks; i++) {
- /* data goes on last link */
- if (i == nlinks) size = buf.st_size;
-
- if (name[0] == '/')
- name++;
- namesize = strlen(name) + 1;
- sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
- "%08lX%08X%08X%08X%08X%08X%08X",
- "070701", /* magic */
- ino, /* ino */
- mode, /* mode */
- (long) uid, /* uid */
- (long) gid, /* gid */
- nlinks, /* nlink */
- (long) buf.st_mtime, /* mtime */
- size, /* filesize */
- 3, /* major */
- 1, /* minor */
- 0, /* rmajor */
- 0, /* rminor */
- namesize, /* namesize */
- 0); /* chksum */
- push_hdr(s);
- push_string(name);
- push_pad();
-
- if (size) {
- if (fwrite(filebuf, size, 1, stdout) != 1) {
- fprintf(stderr, "writing filebuf failed\n");
- goto error;
- }
- offset += size;
- push_pad();
- }
-
- name += namesize;
- }
- ino++;
- rc = 0;
-
-error:
- if (filebuf) free(filebuf);
- if (file >= 0) close(file);
- return rc;
-}
-
-static char *cpio_replace_env(char *new_location)
-{
- char expanded[PATH_MAX + 1];
- char *start, *end, *var;
-
- while ((start = strstr(new_location, "${")) &&
- (end = strchr(start + 2, '}'))) {
- *start = *end = 0;
- var = getenv(start + 2);
- snprintf(expanded, sizeof expanded, "%s%s%s",
- new_location, var ? var : "", end + 1);
- strcpy(new_location, expanded);
- }
-
- return new_location;
-}
-
-static int cpio_mkfile_line(const char *line)
-{
- char name[PATH_MAX + 1];
- char *dname = NULL; /* malloc'ed buffer for hard links */
- char location[PATH_MAX + 1];
- unsigned int mode;
- int uid;
- int gid;
- int nlinks = 1;
- int end = 0, dname_len = 0;
- int rc = -1;
-
- if (5 > sscanf(line, "%" str(PATH_MAX) "s %" str(PATH_MAX)
- "s %o %d %d %n",
- name, location, &mode, &uid, &gid, &end)) {
- fprintf(stderr, "Unrecognized file format '%s'", line);
- goto fail;
- }
- if (end && isgraph(line[end])) {
- int len;
- int nend;
-
- dname = malloc(strlen(line));
- if (!dname) {
- fprintf (stderr, "out of memory (%d)\n", dname_len);
- goto fail;
- }
-
- dname_len = strlen(name) + 1;
- memcpy(dname, name, dname_len);
-
- do {
- nend = 0;
- if (sscanf(line + end, "%" str(PATH_MAX) "s %n",
- name, &nend) < 1)
- break;
- len = strlen(name) + 1;
- memcpy(dname + dname_len, name, len);
- dname_len += len;
- nlinks++;
- end += nend;
- } while (isgraph(line[end]));
- } else {
- dname = name;
- }
- rc = cpio_mkfile(dname, cpio_replace_env(location),
- mode, uid, gid, nlinks);
- fail:
- if (dname_len) free(dname);
- return rc;
-}
-
-static void usage(const char *prog)
-{
- fprintf(stderr, "Usage:\n"
- "\t%s [-t <timestamp>] <cpio_list>\n"
- "\n"
- "<cpio_list> is a file containing newline separated entries that\n"
- "describe the files to be included in the initramfs archive:\n"
- "\n"
- "# a comment\n"
- "file <name> <location> <mode> <uid> <gid> [<hard links>]\n"
- "dir <name> <mode> <uid> <gid>\n"
- "nod <name> <mode> <uid> <gid> <dev_type> <maj> <min>\n"
- "slink <name> <target> <mode> <uid> <gid>\n"
- "pipe <name> <mode> <uid> <gid>\n"
- "sock <name> <mode> <uid> <gid>\n"
- "\n"
- "<name> name of the file/dir/nod/etc in the archive\n"
- "<location> location of the file in the current filesystem\n"
- " expands shell variables quoted with ${}\n"
- "<target> link target\n"
- "<mode> mode/permissions of the file\n"
- "<uid> user id (0=root)\n"
- "<gid> group id (0=root)\n"
- "<dev_type> device type (b=block, c=character)\n"
- "<maj> major number of nod\n"
- "<min> minor number of nod\n"
- "<hard links> space separated list of other links to file\n"
- "\n"
- "example:\n"
- "# A simple initramfs\n"
- "dir /dev 0755 0 0\n"
- "nod /dev/console 0600 0 0 c 5 1\n"
- "dir /root 0700 0 0\n"
- "dir /sbin 0755 0 0\n"
- "file /sbin/kinit /usr/src/klibc/kinit/kinit 0755 0 0\n"
- "\n"
- "<timestamp> is time in seconds since Epoch that will be used\n"
- "as mtime for symlinks, special files and directories. The default\n"
- "is to use the current time for these entries.\n",
- prog);
-}
-
-struct file_handler file_handler_table[] = {
- {
- .type = "file",
- .handler = cpio_mkfile_line,
- }, {
- .type = "nod",
- .handler = cpio_mknod_line,
- }, {
- .type = "dir",
- .handler = cpio_mkdir_line,
- }, {
- .type = "slink",
- .handler = cpio_mkslink_line,
- }, {
- .type = "pipe",
- .handler = cpio_mkpipe_line,
- }, {
- .type = "sock",
- .handler = cpio_mksock_line,
- }, {
- .type = NULL,
- .handler = NULL,
- }
-};
-
-#define LINE_SIZE (2 * PATH_MAX + 50)
-
-int main (int argc, char *argv[])
-{
- FILE *cpio_list;
- char line[LINE_SIZE];
- char *args, *type;
- int ec = 0;
- int line_nr = 0;
- const char *filename;
-
- default_mtime = time(NULL);
- while (1) {
- int opt = getopt(argc, argv, "t:h");
- char *invalid;
-
- if (opt == -1)
- break;
- switch (opt) {
- case 't':
- default_mtime = strtol(optarg, &invalid, 10);
- if (!*optarg || *invalid) {
- fprintf(stderr, "Invalid timestamp: %s\n",
- optarg);
- usage(argv[0]);
- exit(1);
- }
- break;
- case 'h':
- case '?':
- usage(argv[0]);
- exit(opt == 'h' ? 0 : 1);
- }
- }
-
- if (argc - optind != 1) {
- usage(argv[0]);
- exit(1);
- }
- filename = argv[optind];
- if (!strcmp(filename, "-"))
- cpio_list = stdin;
- else if (!(cpio_list = fopen(filename, "r"))) {
- fprintf(stderr, "ERROR: unable to open '%s': %s\n\n",
- filename, strerror(errno));
- usage(argv[0]);
- exit(1);
- }
-
- while (fgets(line, LINE_SIZE, cpio_list)) {
- int type_idx;
- size_t slen = strlen(line);
-
- line_nr++;
-
- if ('#' == *line) {
- /* comment - skip to next line */
- continue;
- }
-
- if (! (type = strtok(line, " \t"))) {
- fprintf(stderr,
- "ERROR: incorrect format, could not locate file type line %d: '%s'\n",
- line_nr, line);
- ec = -1;
- break;
- }
-
- if ('\n' == *type) {
- /* a blank line */
- continue;
- }
-
- if (slen == strlen(type)) {
- /* must be an empty line */
- continue;
- }
-
- if (! (args = strtok(NULL, "\n"))) {
- fprintf(stderr,
- "ERROR: incorrect format, newline required line %d: '%s'\n",
- line_nr, line);
- ec = -1;
- }
-
- for (type_idx = 0; file_handler_table[type_idx].type; type_idx++) {
- int rc;
- if (! strcmp(line, file_handler_table[type_idx].type)) {
- if ((rc = file_handler_table[type_idx].handler(args))) {
- ec = rc;
- fprintf(stderr, " line %d\n", line_nr);
- }
- break;
- }
- }
-
- if (NULL == file_handler_table[type_idx].type) {
- fprintf(stderr, "unknown file type line %d: '%s'\n",
- line_nr, line);
- }
- }
- if (ec == 0)
- cpio_trailer();
-
- exit(ec);
-}
Index: Baikal/M1000/create-5.4.211-5.7.226-host-limits-patch/linux-m1-5.4.211-5.7.226-new/usr
===================================================================
--- Baikal/M1000/create-5.4.211-5.7.226-host-limits-patch/linux-m1-5.4.211-5.7.226-new/usr (revision 384)
+++ Baikal/M1000/create-5.4.211-5.7.226-host-limits-patch/linux-m1-5.4.211-5.7.226-new/usr (nonexistent)
Property changes on: Baikal/M1000/create-5.4.211-5.7.226-host-limits-patch/linux-m1-5.4.211-5.7.226-new/usr
___________________________________________________________________
Deleted: svn:ignore
## -1,73 +0,0 ##
-
-# install dir
-dist
-
-# Target build dirs
-.a1x-newlib
-.a2x-newlib
-.at91sam7s-newlib
-
-.build-machine
-
-.a1x-glibc
-.a2x-glibc
-.h3-glibc
-.h5-glibc
-.i586-glibc
-.i686-glibc
-.imx6-glibc
-.jz47xx-glibc
-.makefile
-.am335x-glibc
-.omap543x-glibc
-.p5600-glibc
-.power8-glibc
-.power8le-glibc
-.power9-glibc
-.power9le-glibc
-.m1000-glibc
-.riscv64-glibc
-.rk328x-glibc
-.rk33xx-glibc
-.rk339x-glibc
-.s8xx-glibc
-.s9xx-glibc
-.x86_64-glibc
-
-# Hidden files (each file)
-.makefile
-.dist
-.rootfs
-
-# src & hw requires
-.src_requires
-.src_requires_depend
-.requires
-.requires_depend
-
-# Tarballs
-*.gz
-*.bz2
-*.lz
-*.xz
-*.tgz
-*.txz
-
-# Signatures
-*.asc
-*.sig
-*.sign
-*.sha1sum
-
-# Patches
-*.patch
-
-# Descriptions
-*.dsc
-*.txt
-
-# Default linux config files
-*.defconfig
-
-# backup copies
-*~
Index: Baikal/M1000/create-5.4.211-5.7.226-host-limits-patch/linux-m1-5.4.211-5.7.226-new/tools/build/fixdep.c
===================================================================
--- Baikal/M1000/create-5.4.211-5.7.226-host-limits-patch/linux-m1-5.4.211-5.7.226-new/tools/build/fixdep.c (revision 384)
+++ Baikal/M1000/create-5.4.211-5.7.226-host-limits-patch/linux-m1-5.4.211-5.7.226-new/tools/build/fixdep.c (nonexistent)
@@ -1,170 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * "Optimize" a list of dependencies as spit out by gcc -MD
- * for the build framework.
- *
- * Original author:
- * Copyright 2002 by Kai Germaschewski <kai.germaschewski@gmx.de>
- *
- * This code has been borrowed from kbuild's fixdep (scripts/basic/fixdep.c),
- * Please check it for detailed explanation. This fixdep borow only the
- * base transformation of dependecies without the CONFIG mangle.
- */
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/mman.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <string.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <linux/limits.h>
-
-char *target;
-char *depfile;
-char *cmdline;
-
-static void usage(void)
-{
- fprintf(stderr, "Usage: fixdep <depfile> <target> <cmdline>\n");
- exit(1);
-}
-
-/*
- * Print out the commandline prefixed with cmd_<target filename> :=
- */
-static void print_cmdline(void)
-{
- printf("cmd_%s := %s\n\n", target, cmdline);
-}
-
-/*
- * Important: The below generated source_foo.o and deps_foo.o variable
- * assignments are parsed not only by make, but also by the rather simple
- * parser in scripts/mod/sumversion.c.
- */
-static void parse_dep_file(void *map, size_t len)
-{
- char *m = map;
- char *end = m + len;
- char *p;
- char s[PATH_MAX];
- int is_target, has_target = 0;
- int saw_any_target = 0;
- int is_first_dep = 0;
-
- while (m < end) {
- /* Skip any "white space" */
- while (m < end && (*m == ' ' || *m == '\\' || *m == '\n'))
- m++;
- /* Find next "white space" */
- p = m;
- while (p < end && *p != ' ' && *p != '\\' && *p != '\n')
- p++;
- /* Is the token we found a target name? */
- is_target = (*(p-1) == ':');
- /* Don't write any target names into the dependency file */
- if (is_target) {
- /* The /next/ file is the first dependency */
- is_first_dep = 1;
- has_target = 1;
- } else if (has_target) {
- /* Save this token/filename */
- memcpy(s, m, p-m);
- s[p - m] = 0;
-
- /*
- * Do not list the source file as dependency,
- * so that kbuild is not confused if a .c file
- * is rewritten into .S or vice versa. Storing
- * it in source_* is needed for modpost to
- * compute srcversions.
- */
- if (is_first_dep) {
- /*
- * If processing the concatenation of
- * multiple dependency files, only
- * process the first target name, which
- * will be the original source name,
- * and ignore any other target names,
- * which will be intermediate temporary
- * files.
- */
- if (!saw_any_target) {
- saw_any_target = 1;
- printf("source_%s := %s\n\n",
- target, s);
- printf("deps_%s := \\\n",
- target);
- }
- is_first_dep = 0;
- } else
- printf(" %s \\\n", s);
- }
- /*
- * Start searching for next token immediately after the first
- * "whitespace" character that follows this token.
- */
- m = p + 1;
- }
-
- if (!saw_any_target) {
- fprintf(stderr, "fixdep: parse error; no targets found\n");
- exit(1);
- }
-
- printf("\n%s: $(deps_%s)\n\n", target, target);
- printf("$(deps_%s):\n", target);
-}
-
-static void print_deps(void)
-{
- struct stat st;
- int fd;
- void *map;
-
- fd = open(depfile, O_RDONLY);
- if (fd < 0) {
- fprintf(stderr, "fixdep: error opening depfile: ");
- perror(depfile);
- exit(2);
- }
- if (fstat(fd, &st) < 0) {
- fprintf(stderr, "fixdep: error fstat'ing depfile: ");
- perror(depfile);
- exit(2);
- }
- if (st.st_size == 0) {
- fprintf(stderr, "fixdep: %s is empty\n", depfile);
- close(fd);
- return;
- }
- map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
- if ((long) map == -1) {
- perror("fixdep: mmap");
- close(fd);
- return;
- }
-
- parse_dep_file(map, st.st_size);
-
- munmap(map, st.st_size);
-
- close(fd);
-}
-
-int main(int argc, char **argv)
-{
- if (argc != 4)
- usage();
-
- depfile = argv[1];
- target = argv[2];
- cmdline = argv[3];
-
- print_cmdline();
- print_deps();
-
- return 0;
-}
Index: Baikal/M1000/create-5.4.211-5.7.226-host-limits-patch/linux-m1-5.4.211-5.7.226-new/tools/build
===================================================================
--- Baikal/M1000/create-5.4.211-5.7.226-host-limits-patch/linux-m1-5.4.211-5.7.226-new/tools/build (revision 384)
+++ Baikal/M1000/create-5.4.211-5.7.226-host-limits-patch/linux-m1-5.4.211-5.7.226-new/tools/build (nonexistent)
Property changes on: Baikal/M1000/create-5.4.211-5.7.226-host-limits-patch/linux-m1-5.4.211-5.7.226-new/tools/build
___________________________________________________________________
Deleted: svn:ignore
## -1,73 +0,0 ##
-
-# install dir
-dist
-
-# Target build dirs
-.a1x-newlib
-.a2x-newlib
-.at91sam7s-newlib
-
-.build-machine
-
-.a1x-glibc
-.a2x-glibc
-.h3-glibc
-.h5-glibc
-.i586-glibc
-.i686-glibc
-.imx6-glibc
-.jz47xx-glibc
-.makefile
-.am335x-glibc
-.omap543x-glibc
-.p5600-glibc
-.power8-glibc
-.power8le-glibc
-.power9-glibc
-.power9le-glibc
-.m1000-glibc
-.riscv64-glibc
-.rk328x-glibc
-.rk33xx-glibc
-.rk339x-glibc
-.s8xx-glibc
-.s9xx-glibc
-.x86_64-glibc
-
-# Hidden files (each file)
-.makefile
-.dist
-.rootfs
-
-# src & hw requires
-.src_requires
-.src_requires_depend
-.requires
-.requires_depend
-
-# Tarballs
-*.gz
-*.bz2
-*.lz
-*.xz
-*.tgz
-*.txz
-
-# Signatures
-*.asc
-*.sig
-*.sign
-*.sha1sum
-
-# Patches
-*.patch
-
-# Descriptions
-*.dsc
-*.txt
-
-# Default linux config files
-*.defconfig
-
-# backup copies
-*~
Index: Baikal/M1000/create-5.4.211-5.7.226-host-limits-patch/linux-m1-5.4.211-5.7.226-new/tools
===================================================================
--- Baikal/M1000/create-5.4.211-5.7.226-host-limits-patch/linux-m1-5.4.211-5.7.226-new/tools (revision 384)
+++ Baikal/M1000/create-5.4.211-5.7.226-host-limits-patch/linux-m1-5.4.211-5.7.226-new/tools (nonexistent)
Property changes on: Baikal/M1000/create-5.4.211-5.7.226-host-limits-patch/linux-m1-5.4.211-5.7.226-new/tools
___________________________________________________________________
Deleted: svn:ignore
## -1,73 +0,0 ##
-
-# install dir
-dist
-
-# Target build dirs
-.a1x-newlib
-.a2x-newlib
-.at91sam7s-newlib
-
-.build-machine
-
-.a1x-glibc
-.a2x-glibc
-.h3-glibc
-.h5-glibc
-.i586-glibc
-.i686-glibc
-.imx6-glibc
-.jz47xx-glibc
-.makefile
-.am335x-glibc
-.omap543x-glibc
-.p5600-glibc
-.power8-glibc
-.power8le-glibc
-.power9-glibc
-.power9le-glibc
-.m1000-glibc
-.riscv64-glibc
-.rk328x-glibc
-.rk33xx-glibc
-.rk339x-glibc
-.s8xx-glibc
-.s9xx-glibc
-.x86_64-glibc
-
-# Hidden files (each file)
-.makefile
-.dist
-.rootfs
-
-# src & hw requires
-.src_requires
-.src_requires_depend
-.requires
-.requires_depend
-
-# Tarballs
-*.gz
-*.bz2
-*.lz
-*.xz
-*.tgz
-*.txz
-
-# Signatures
-*.asc
-*.sig
-*.sign
-*.sha1sum
-
-# Patches
-*.patch
-
-# Descriptions
-*.dsc
-*.txt
-
-# Default linux config files
-*.defconfig
-
-# backup copies
-*~
Index: Baikal/M1000/create-5.4.211-5.7.226-host-limits-patch/linux-m1-5.4.211-5.7.226-new
===================================================================
--- Baikal/M1000/create-5.4.211-5.7.226-host-limits-patch/linux-m1-5.4.211-5.7.226-new (revision 384)
+++ Baikal/M1000/create-5.4.211-5.7.226-host-limits-patch/linux-m1-5.4.211-5.7.226-new (nonexistent)
Property changes on: Baikal/M1000/create-5.4.211-5.7.226-host-limits-patch/linux-m1-5.4.211-5.7.226-new
___________________________________________________________________
Deleted: svn:ignore
## -1,73 +0,0 ##
-
-# install dir
-dist
-
-# Target build dirs
-.a1x-newlib
-.a2x-newlib
-.at91sam7s-newlib
-
-.build-machine
-
-.a1x-glibc
-.a2x-glibc
-.h3-glibc
-.h5-glibc
-.i586-glibc
-.i686-glibc
-.imx6-glibc
-.jz47xx-glibc
-.makefile
-.am335x-glibc
-.omap543x-glibc
-.p5600-glibc
-.power8-glibc
-.power8le-glibc
-.power9-glibc
-.power9le-glibc
-.m1000-glibc
-.riscv64-glibc
-.rk328x-glibc
-.rk33xx-glibc
-.rk339x-glibc
-.s8xx-glibc
-.s9xx-glibc
-.x86_64-glibc
-
-# Hidden files (each file)
-.makefile
-.dist
-.rootfs
-
-# src & hw requires
-.src_requires
-.src_requires_depend
-.requires
-.requires_depend
-
-# Tarballs
-*.gz
-*.bz2
-*.lz
-*.xz
-*.tgz
-*.txz
-
-# Signatures
-*.asc
-*.sig
-*.sign
-*.sha1sum
-
-# Patches
-*.patch
-
-# Descriptions
-*.dsc
-*.txt
-
-# Default linux config files
-*.defconfig
-
-# backup copies
-*~
Index: Baikal/M1000/create-5.4.211-5.7.226-host-limits-patch/create.patch.sh
===================================================================
--- Baikal/M1000/create-5.4.211-5.7.226-host-limits-patch/create.patch.sh (revision 384)
+++ Baikal/M1000/create-5.4.211-5.7.226-host-limits-patch/create.patch.sh (nonexistent)
@@ -1,15 +0,0 @@
-#!/bin/sh
-
-VERSION=5.4.211-5.7.226
-
-tar --files-from=file.list -xJvf ../linux-m1-$VERSION.tar.xz
-mv linux-m1-$VERSION linux-m1-$VERSION-orig
-
-cp -rf ./linux-m1-$VERSION-new ./linux-m1-$VERSION
-
-diff --unified -Nr linux-m1-$VERSION-orig linux-m1-$VERSION > linux-m1-$VERSION-host-limits.patch
-
-mv linux-m1-$VERSION-host-limits.patch ../patches
-
-rm -rf ./linux-m1-$VERSION
-rm -rf ./linux-m1-$VERSION-orig
Property changes on: Baikal/M1000/create-5.4.211-5.7.226-host-limits-patch/create.patch.sh
___________________________________________________________________
Deleted: svn:executable
## -1 +0,0 ##
-*
\ No newline at end of property
Index: Baikal/M1000/create-5.4.211-5.7.226-host-limits-patch
===================================================================
--- Baikal/M1000/create-5.4.211-5.7.226-host-limits-patch (revision 384)
+++ Baikal/M1000/create-5.4.211-5.7.226-host-limits-patch (nonexistent)
Property changes on: Baikal/M1000/create-5.4.211-5.7.226-host-limits-patch
___________________________________________________________________
Deleted: svn:ignore
## -1,73 +0,0 ##
-
-# install dir
-dist
-
-# Target build dirs
-.a1x-newlib
-.a2x-newlib
-.at91sam7s-newlib
-
-.build-machine
-
-.a1x-glibc
-.a2x-glibc
-.h3-glibc
-.h5-glibc
-.i586-glibc
-.i686-glibc
-.imx6-glibc
-.jz47xx-glibc
-.makefile
-.am335x-glibc
-.omap543x-glibc
-.p5600-glibc
-.power8-glibc
-.power8le-glibc
-.power9-glibc
-.power9le-glibc
-.m1000-glibc
-.riscv64-glibc
-.rk328x-glibc
-.rk33xx-glibc
-.rk339x-glibc
-.s8xx-glibc
-.s9xx-glibc
-.x86_64-glibc
-
-# Hidden files (each file)
-.makefile
-.dist
-.rootfs
-
-# src & hw requires
-.src_requires
-.src_requires_depend
-.requires
-.requires_depend
-
-# Tarballs
-*.gz
-*.bz2
-*.lz
-*.xz
-*.tgz
-*.txz
-
-# Signatures
-*.asc
-*.sig
-*.sign
-*.sha1sum
-
-# Patches
-*.patch
-
-# Descriptions
-*.dsc
-*.txt
-
-# Default linux config files
-*.defconfig
-
-# backup copies
-*~
Index: Baikal/M1000/Makefile
===================================================================
--- Baikal/M1000/Makefile (revision 384)
+++ Baikal/M1000/Makefile (revision 385)
@@ -7,12 +7,12 @@
url = $(DOWNLOAD_SERVER)/sources/Linux/Baikal/M1000
-versions = m1-5.4.211-5.7.226
+versions = m1-6.1.63-6.4.92
tarballs = $(addsuffix .tar.xz, $(addprefix linux-, $(versions)))
sha1s = $(addsuffix .sha1sum, $(tarballs))
-patches = $(CURDIR)/patches/linux-m1-5.4.211-5.7.226-host-limits.patch
+patches = $(CURDIR)/patches/linux-m1-6.1.63-6.4.92-host-limits.patch
.NOTPARALLEL: $(patches)
@@ -47,7 +47,7 @@
$(patches): $(sha1s)
@echo -e "\n======= Create Patches =======\n" ; \
- ( cd create-5.4.211-5.7.226-host-limits-patch ; ./create.patch.sh ) ; \
+ ( cd create-6.1.63-6.4.92-host-limits-patch ; ./create.patch.sh ) ; \
echo -e "\n"
download_clean:
Index: Baikal/M1000/create-6.1.63-6.4.92-host-limits-patch/create.patch.sh
===================================================================
--- Baikal/M1000/create-6.1.63-6.4.92-host-limits-patch/create.patch.sh (nonexistent)
+++ Baikal/M1000/create-6.1.63-6.4.92-host-limits-patch/create.patch.sh (revision 385)
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+VERSION=6.1.63-6.4.92
+
+tar --files-from=file.list -xJvf ../linux-m1-$VERSION.tar.xz
+mv linux-m1-$VERSION linux-m1-$VERSION-orig
+
+cp -rf ./linux-m1-$VERSION-new ./linux-m1-$VERSION
+
+diff --unified -Nr linux-m1-$VERSION-orig linux-m1-$VERSION > linux-m1-$VERSION-host-limits.patch
+
+mv linux-m1-$VERSION-host-limits.patch ../patches
+
+rm -rf ./linux-m1-$VERSION
+rm -rf ./linux-m1-$VERSION-orig
Property changes on: Baikal/M1000/create-6.1.63-6.4.92-host-limits-patch/create.patch.sh
___________________________________________________________________
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: Baikal/M1000/create-6.1.63-6.4.92-host-limits-patch/file.list
===================================================================
--- Baikal/M1000/create-6.1.63-6.4.92-host-limits-patch/file.list (nonexistent)
+++ Baikal/M1000/create-6.1.63-6.4.92-host-limits-patch/file.list (revision 385)
@@ -0,0 +1,7 @@
+linux-m1-6.1.63-6.4.92/scripts/kconfig/conf.c
+linux-m1-6.1.63-6.4.92/scripts/kconfig/confdata.c
+linux-m1-6.1.63-6.4.92/scripts/kconfig/lexer.l
+linux-m1-6.1.63-6.4.92/scripts/mod/modpost.c
+linux-m1-6.1.63-6.4.92/scripts/mod/sumversion.c
+linux-m1-6.1.63-6.4.92/tools/build/fixdep.c
+linux-m1-6.1.63-6.4.92/usr/gen_init_cpio.c
Index: Baikal/M1000/create-6.1.63-6.4.92-host-limits-patch/linux-m1-6.1.63-6.4.92-new/scripts/kconfig/conf.c
===================================================================
--- Baikal/M1000/create-6.1.63-6.4.92-host-limits-patch/linux-m1-6.1.63-6.4.92-new/scripts/kconfig/conf.c (nonexistent)
+++ Baikal/M1000/create-6.1.63-6.4.92-host-limits-patch/linux-m1-6.1.63-6.4.92-new/scripts/kconfig/conf.c (revision 385)
@@ -0,0 +1,921 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ */
+
+#include <ctype.h>
+#include <linux/limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <sys/time.h>
+#include <errno.h>
+
+#include "lkc.h"
+
+static void conf(struct menu *menu);
+static void check_conf(struct menu *menu);
+
+enum input_mode {
+ oldaskconfig,
+ syncconfig,
+ oldconfig,
+ allnoconfig,
+ allyesconfig,
+ allmodconfig,
+ alldefconfig,
+ randconfig,
+ defconfig,
+ savedefconfig,
+ listnewconfig,
+ helpnewconfig,
+ olddefconfig,
+ yes2modconfig,
+ mod2yesconfig,
+ mod2noconfig,
+};
+static enum input_mode input_mode = oldaskconfig;
+static int input_mode_opt;
+static int indent = 1;
+static int tty_stdio;
+static int sync_kconfig;
+static int conf_cnt;
+static char line[PATH_MAX];
+static struct menu *rootEntry;
+
+static void print_help(struct menu *menu)
+{
+ struct gstr help = str_new();
+
+ menu_get_ext_help(menu, &help);
+
+ printf("\n%s\n", str_get(&help));
+ str_free(&help);
+}
+
+static void strip(char *str)
+{
+ char *p = str;
+ int l;
+
+ while ((isspace(*p)))
+ p++;
+ l = strlen(p);
+ if (p != str)
+ memmove(str, p, l + 1);
+ if (!l)
+ return;
+ p = str + l - 1;
+ while ((isspace(*p)))
+ *p-- = 0;
+}
+
+/* Helper function to facilitate fgets() by Jean Sacren. */
+static void xfgets(char *str, int size, FILE *in)
+{
+ if (!fgets(str, size, in))
+ fprintf(stderr, "\nError in reading or end of file.\n");
+
+ if (!tty_stdio)
+ printf("%s", str);
+}
+
+static void set_randconfig_seed(void)
+{
+ unsigned int seed;
+ char *env;
+ bool seed_set = false;
+
+ env = getenv("KCONFIG_SEED");
+ if (env && *env) {
+ char *endp;
+
+ seed = strtol(env, &endp, 0);
+ if (*endp == '\0')
+ seed_set = true;
+ }
+
+ if (!seed_set) {
+ struct timeval now;
+
+ /*
+ * Use microseconds derived seed, compensate for systems where it may
+ * be zero.
+ */
+ gettimeofday(&now, NULL);
+ seed = (now.tv_sec + 1) * (now.tv_usec + 1);
+ }
+
+ printf("KCONFIG_SEED=0x%X\n", seed);
+ srand(seed);
+}
+
+static bool randomize_choice_values(struct symbol *csym)
+{
+ struct property *prop;
+ struct symbol *sym;
+ struct expr *e;
+ int cnt, def;
+
+ /*
+ * If choice is mod then we may have more items selected
+ * and if no then no-one.
+ * In both cases stop.
+ */
+ if (csym->curr.tri != yes)
+ return false;
+
+ prop = sym_get_choice_prop(csym);
+
+ /* count entries in choice block */
+ cnt = 0;
+ expr_list_for_each_sym(prop->expr, e, sym)
+ cnt++;
+
+ /*
+ * find a random value and set it to yes,
+ * set the rest to no so we have only one set
+ */
+ def = rand() % cnt;
+
+ cnt = 0;
+ expr_list_for_each_sym(prop->expr, e, sym) {
+ if (def == cnt++) {
+ sym->def[S_DEF_USER].tri = yes;
+ csym->def[S_DEF_USER].val = sym;
+ } else {
+ sym->def[S_DEF_USER].tri = no;
+ }
+ sym->flags |= SYMBOL_DEF_USER;
+ /* clear VALID to get value calculated */
+ sym->flags &= ~SYMBOL_VALID;
+ }
+ csym->flags |= SYMBOL_DEF_USER;
+ /* clear VALID to get value calculated */
+ csym->flags &= ~SYMBOL_VALID;
+
+ return true;
+}
+
+enum conf_def_mode {
+ def_default,
+ def_yes,
+ def_mod,
+ def_no,
+ def_random
+};
+
+static bool conf_set_all_new_symbols(enum conf_def_mode mode)
+{
+ struct symbol *sym, *csym;
+ int i, cnt;
+ /*
+ * can't go as the default in switch-case below, otherwise gcc whines
+ * about -Wmaybe-uninitialized
+ */
+ int pby = 50; /* probability of bool = y */
+ int pty = 33; /* probability of tristate = y */
+ int ptm = 33; /* probability of tristate = m */
+ bool has_changed = false;
+
+ if (mode == def_random) {
+ int n, p[3];
+ char *env = getenv("KCONFIG_PROBABILITY");
+
+ n = 0;
+ while (env && *env) {
+ char *endp;
+ int tmp = strtol(env, &endp, 10);
+
+ if (tmp >= 0 && tmp <= 100) {
+ p[n++] = tmp;
+ } else {
+ errno = ERANGE;
+ perror("KCONFIG_PROBABILITY");
+ exit(1);
+ }
+ env = (*endp == ':') ? endp + 1 : endp;
+ if (n >= 3)
+ break;
+ }
+ switch (n) {
+ case 1:
+ pby = p[0];
+ ptm = pby / 2;
+ pty = pby - ptm;
+ break;
+ case 2:
+ pty = p[0];
+ ptm = p[1];
+ pby = pty + ptm;
+ break;
+ case 3:
+ pby = p[0];
+ pty = p[1];
+ ptm = p[2];
+ break;
+ }
+
+ if (pty + ptm > 100) {
+ errno = ERANGE;
+ perror("KCONFIG_PROBABILITY");
+ exit(1);
+ }
+ }
+
+ for_all_symbols(i, sym) {
+ if (sym_has_value(sym) || sym->flags & SYMBOL_VALID)
+ continue;
+ switch (sym_get_type(sym)) {
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ has_changed = true;
+ switch (mode) {
+ case def_yes:
+ sym->def[S_DEF_USER].tri = yes;
+ break;
+ case def_mod:
+ sym->def[S_DEF_USER].tri = mod;
+ break;
+ case def_no:
+ sym->def[S_DEF_USER].tri = no;
+ break;
+ case def_random:
+ sym->def[S_DEF_USER].tri = no;
+ cnt = rand() % 100;
+ if (sym->type == S_TRISTATE) {
+ if (cnt < pty)
+ sym->def[S_DEF_USER].tri = yes;
+ else if (cnt < pty + ptm)
+ sym->def[S_DEF_USER].tri = mod;
+ } else if (cnt < pby)
+ sym->def[S_DEF_USER].tri = yes;
+ break;
+ default:
+ continue;
+ }
+ if (!(sym_is_choice(sym) && mode == def_random))
+ sym->flags |= SYMBOL_DEF_USER;
+ break;
+ default:
+ break;
+ }
+
+ }
+
+ sym_clear_all_valid();
+
+ /*
+ * We have different type of choice blocks.
+ * If curr.tri equals to mod then we can select several
+ * choice symbols in one block.
+ * In this case we do nothing.
+ * If curr.tri equals yes then only one symbol can be
+ * selected in a choice block and we set it to yes,
+ * and the rest to no.
+ */
+ if (mode != def_random) {
+ for_all_symbols(i, csym) {
+ if ((sym_is_choice(csym) && !sym_has_value(csym)) ||
+ sym_is_choice_value(csym))
+ csym->flags |= SYMBOL_NEED_SET_CHOICE_VALUES;
+ }
+ }
+
+ for_all_symbols(i, csym) {
+ if (sym_has_value(csym) || !sym_is_choice(csym))
+ continue;
+
+ sym_calc_value(csym);
+ if (mode == def_random)
+ has_changed |= randomize_choice_values(csym);
+ else {
+ set_all_choice_values(csym);
+ has_changed = true;
+ }
+ }
+
+ return has_changed;
+}
+
+static void conf_rewrite_tristates(tristate old_val, tristate new_val)
+{
+ struct symbol *sym;
+ int i;
+
+ for_all_symbols(i, sym) {
+ if (sym_get_type(sym) == S_TRISTATE &&
+ sym->def[S_DEF_USER].tri == old_val)
+ sym->def[S_DEF_USER].tri = new_val;
+ }
+ sym_clear_all_valid();
+}
+
+static int conf_askvalue(struct symbol *sym, const char *def)
+{
+ if (!sym_has_value(sym))
+ printf("(NEW) ");
+
+ line[0] = '\n';
+ line[1] = 0;
+
+ if (!sym_is_changeable(sym)) {
+ printf("%s\n", def);
+ line[0] = '\n';
+ line[1] = 0;
+ return 0;
+ }
+
+ switch (input_mode) {
+ case oldconfig:
+ case syncconfig:
+ if (sym_has_value(sym)) {
+ printf("%s\n", def);
+ return 0;
+ }
+ /* fall through */
+ default:
+ fflush(stdout);
+ xfgets(line, sizeof(line), stdin);
+ break;
+ }
+
+ return 1;
+}
+
+static int conf_string(struct menu *menu)
+{
+ struct symbol *sym = menu->sym;
+ const char *def;
+
+ while (1) {
+ printf("%*s%s ", indent - 1, "", menu->prompt->text);
+ printf("(%s) ", sym->name);
+ def = sym_get_string_value(sym);
+ if (def)
+ printf("[%s] ", def);
+ if (!conf_askvalue(sym, def))
+ return 0;
+ switch (line[0]) {
+ case '\n':
+ break;
+ case '?':
+ /* print help */
+ if (line[1] == '\n') {
+ print_help(menu);
+ def = NULL;
+ break;
+ }
+ /* fall through */
+ default:
+ line[strlen(line)-1] = 0;
+ def = line;
+ }
+ if (def && sym_set_string_value(sym, def))
+ return 0;
+ }
+}
+
+static int conf_sym(struct menu *menu)
+{
+ struct symbol *sym = menu->sym;
+ tristate oldval, newval;
+
+ while (1) {
+ printf("%*s%s ", indent - 1, "", menu->prompt->text);
+ if (sym->name)
+ printf("(%s) ", sym->name);
+ putchar('[');
+ oldval = sym_get_tristate_value(sym);
+ switch (oldval) {
+ case no:
+ putchar('N');
+ break;
+ case mod:
+ putchar('M');
+ break;
+ case yes:
+ putchar('Y');
+ break;
+ }
+ if (oldval != no && sym_tristate_within_range(sym, no))
+ printf("/n");
+ if (oldval != mod && sym_tristate_within_range(sym, mod))
+ printf("/m");
+ if (oldval != yes && sym_tristate_within_range(sym, yes))
+ printf("/y");
+ printf("/?] ");
+ if (!conf_askvalue(sym, sym_get_string_value(sym)))
+ return 0;
+ strip(line);
+
+ switch (line[0]) {
+ case 'n':
+ case 'N':
+ newval = no;
+ if (!line[1] || !strcmp(&line[1], "o"))
+ break;
+ continue;
+ case 'm':
+ case 'M':
+ newval = mod;
+ if (!line[1])
+ break;
+ continue;
+ case 'y':
+ case 'Y':
+ newval = yes;
+ if (!line[1] || !strcmp(&line[1], "es"))
+ break;
+ continue;
+ case 0:
+ newval = oldval;
+ break;
+ case '?':
+ goto help;
+ default:
+ continue;
+ }
+ if (sym_set_tristate_value(sym, newval))
+ return 0;
+help:
+ print_help(menu);
+ }
+}
+
+static int conf_choice(struct menu *menu)
+{
+ struct symbol *sym, *def_sym;
+ struct menu *child;
+ bool is_new;
+
+ sym = menu->sym;
+ is_new = !sym_has_value(sym);
+ if (sym_is_changeable(sym)) {
+ conf_sym(menu);
+ sym_calc_value(sym);
+ switch (sym_get_tristate_value(sym)) {
+ case no:
+ return 1;
+ case mod:
+ return 0;
+ case yes:
+ break;
+ }
+ } else {
+ switch (sym_get_tristate_value(sym)) {
+ case no:
+ return 1;
+ case mod:
+ printf("%*s%s\n", indent - 1, "", menu_get_prompt(menu));
+ return 0;
+ case yes:
+ break;
+ }
+ }
+
+ while (1) {
+ int cnt, def;
+
+ printf("%*s%s\n", indent - 1, "", menu_get_prompt(menu));
+ def_sym = sym_get_choice_value(sym);
+ cnt = def = 0;
+ line[0] = 0;
+ for (child = menu->list; child; child = child->next) {
+ if (!menu_is_visible(child))
+ continue;
+ if (!child->sym) {
+ printf("%*c %s\n", indent, '*', menu_get_prompt(child));
+ continue;
+ }
+ cnt++;
+ if (child->sym == def_sym) {
+ def = cnt;
+ printf("%*c", indent, '>');
+ } else
+ printf("%*c", indent, ' ');
+ printf(" %d. %s", cnt, menu_get_prompt(child));
+ if (child->sym->name)
+ printf(" (%s)", child->sym->name);
+ if (!sym_has_value(child->sym))
+ printf(" (NEW)");
+ printf("\n");
+ }
+ printf("%*schoice", indent - 1, "");
+ if (cnt == 1) {
+ printf("[1]: 1\n");
+ goto conf_childs;
+ }
+ printf("[1-%d?]: ", cnt);
+ switch (input_mode) {
+ case oldconfig:
+ case syncconfig:
+ if (!is_new) {
+ cnt = def;
+ printf("%d\n", cnt);
+ break;
+ }
+ /* fall through */
+ case oldaskconfig:
+ fflush(stdout);
+ xfgets(line, sizeof(line), stdin);
+ strip(line);
+ if (line[0] == '?') {
+ print_help(menu);
+ continue;
+ }
+ if (!line[0])
+ cnt = def;
+ else if (isdigit(line[0]))
+ cnt = atoi(line);
+ else
+ continue;
+ break;
+ default:
+ break;
+ }
+
+ conf_childs:
+ for (child = menu->list; child; child = child->next) {
+ if (!child->sym || !menu_is_visible(child))
+ continue;
+ if (!--cnt)
+ break;
+ }
+ if (!child)
+ continue;
+ if (line[0] && line[strlen(line) - 1] == '?') {
+ print_help(child);
+ continue;
+ }
+ sym_set_tristate_value(child->sym, yes);
+ for (child = child->list; child; child = child->next) {
+ indent += 2;
+ conf(child);
+ indent -= 2;
+ }
+ return 1;
+ }
+}
+
+static void conf(struct menu *menu)
+{
+ struct symbol *sym;
+ struct property *prop;
+ struct menu *child;
+
+ if (!menu_is_visible(menu))
+ return;
+
+ sym = menu->sym;
+ prop = menu->prompt;
+ if (prop) {
+ const char *prompt;
+
+ switch (prop->type) {
+ case P_MENU:
+ /*
+ * Except in oldaskconfig mode, we show only menus that
+ * contain new symbols.
+ */
+ if (input_mode != oldaskconfig && rootEntry != menu) {
+ check_conf(menu);
+ return;
+ }
+ /* fall through */
+ case P_COMMENT:
+ prompt = menu_get_prompt(menu);
+ if (prompt)
+ printf("%*c\n%*c %s\n%*c\n",
+ indent, '*',
+ indent, '*', prompt,
+ indent, '*');
+ default:
+ ;
+ }
+ }
+
+ if (!sym)
+ goto conf_childs;
+
+ if (sym_is_choice(sym)) {
+ conf_choice(menu);
+ if (sym->curr.tri != mod)
+ return;
+ goto conf_childs;
+ }
+
+ switch (sym->type) {
+ case S_INT:
+ case S_HEX:
+ case S_STRING:
+ conf_string(menu);
+ break;
+ default:
+ conf_sym(menu);
+ break;
+ }
+
+conf_childs:
+ if (sym)
+ indent += 2;
+ for (child = menu->list; child; child = child->next)
+ conf(child);
+ if (sym)
+ indent -= 2;
+}
+
+static void check_conf(struct menu *menu)
+{
+ struct symbol *sym;
+ struct menu *child;
+
+ if (!menu_is_visible(menu))
+ return;
+
+ sym = menu->sym;
+ if (sym && !sym_has_value(sym) &&
+ (sym_is_changeable(sym) ||
+ (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes))) {
+
+ switch (input_mode) {
+ case listnewconfig:
+ if (sym->name)
+ print_symbol_for_listconfig(sym);
+ break;
+ case helpnewconfig:
+ printf("-----\n");
+ print_help(menu);
+ printf("-----\n");
+ break;
+ default:
+ if (!conf_cnt++)
+ printf("*\n* Restart config...\n*\n");
+ rootEntry = menu_get_parent_menu(menu);
+ conf(rootEntry);
+ break;
+ }
+ }
+
+ for (child = menu->list; child; child = child->next)
+ check_conf(child);
+}
+
+static const struct option long_opts[] = {
+ {"help", no_argument, NULL, 'h'},
+ {"silent", no_argument, NULL, 's'},
+ {"oldaskconfig", no_argument, &input_mode_opt, oldaskconfig},
+ {"oldconfig", no_argument, &input_mode_opt, oldconfig},
+ {"syncconfig", no_argument, &input_mode_opt, syncconfig},
+ {"defconfig", required_argument, &input_mode_opt, defconfig},
+ {"savedefconfig", required_argument, &input_mode_opt, savedefconfig},
+ {"allnoconfig", no_argument, &input_mode_opt, allnoconfig},
+ {"allyesconfig", no_argument, &input_mode_opt, allyesconfig},
+ {"allmodconfig", no_argument, &input_mode_opt, allmodconfig},
+ {"alldefconfig", no_argument, &input_mode_opt, alldefconfig},
+ {"randconfig", no_argument, &input_mode_opt, randconfig},
+ {"listnewconfig", no_argument, &input_mode_opt, listnewconfig},
+ {"helpnewconfig", no_argument, &input_mode_opt, helpnewconfig},
+ {"olddefconfig", no_argument, &input_mode_opt, olddefconfig},
+ {"yes2modconfig", no_argument, &input_mode_opt, yes2modconfig},
+ {"mod2yesconfig", no_argument, &input_mode_opt, mod2yesconfig},
+ {"mod2noconfig", no_argument, &input_mode_opt, mod2noconfig},
+ {NULL, 0, NULL, 0}
+};
+
+static void conf_usage(const char *progname)
+{
+ printf("Usage: %s [options] <kconfig-file>\n", progname);
+ printf("\n");
+ printf("Generic options:\n");
+ printf(" -h, --help Print this message and exit.\n");
+ printf(" -s, --silent Do not print log.\n");
+ printf("\n");
+ printf("Mode options:\n");
+ printf(" --listnewconfig List new options\n");
+ printf(" --helpnewconfig List new options and help text\n");
+ printf(" --oldaskconfig Start a new configuration using a line-oriented program\n");
+ printf(" --oldconfig Update a configuration using a provided .config as base\n");
+ printf(" --syncconfig Similar to oldconfig but generates configuration in\n"
+ " include/{generated/,config/}\n");
+ printf(" --olddefconfig Same as oldconfig but sets new symbols to their default value\n");
+ printf(" --defconfig <file> New config with default defined in <file>\n");
+ printf(" --savedefconfig <file> Save the minimal current configuration to <file>\n");
+ printf(" --allnoconfig New config where all options are answered with no\n");
+ printf(" --allyesconfig New config where all options are answered with yes\n");
+ printf(" --allmodconfig New config where all options are answered with mod\n");
+ printf(" --alldefconfig New config with all symbols set to default\n");
+ printf(" --randconfig New config with random answer to all options\n");
+ printf(" --yes2modconfig Change answers from yes to mod if possible\n");
+ printf(" --mod2yesconfig Change answers from mod to yes if possible\n");
+ printf(" --mod2noconfig Change answers from mod to no if possible\n");
+ printf(" (If none of the above is given, --oldaskconfig is the default)\n");
+}
+
+int main(int ac, char **av)
+{
+ const char *progname = av[0];
+ int opt;
+ const char *name, *defconfig_file = NULL /* gcc uninit */;
+ int no_conf_write = 0;
+
+ tty_stdio = isatty(0) && isatty(1);
+
+ while ((opt = getopt_long(ac, av, "hs", long_opts, NULL)) != -1) {
+ switch (opt) {
+ case 'h':
+ conf_usage(progname);
+ exit(1);
+ break;
+ case 's':
+ conf_set_message_callback(NULL);
+ break;
+ case 0:
+ input_mode = input_mode_opt;
+ switch (input_mode) {
+ case syncconfig:
+ /*
+ * syncconfig is invoked during the build stage.
+ * Suppress distracting
+ * "configuration written to ..."
+ */
+ conf_set_message_callback(NULL);
+ sync_kconfig = 1;
+ break;
+ case defconfig:
+ case savedefconfig:
+ defconfig_file = optarg;
+ break;
+ case randconfig:
+ set_randconfig_seed();
+ break;
+ default:
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ if (ac == optind) {
+ fprintf(stderr, "%s: Kconfig file missing\n", av[0]);
+ conf_usage(progname);
+ exit(1);
+ }
+ conf_parse(av[optind]);
+ //zconfdump(stdout);
+
+ switch (input_mode) {
+ case defconfig:
+ if (conf_read(defconfig_file)) {
+ fprintf(stderr,
+ "***\n"
+ "*** Can't find default configuration \"%s\"!\n"
+ "***\n",
+ defconfig_file);
+ exit(1);
+ }
+ break;
+ case savedefconfig:
+ case syncconfig:
+ case oldaskconfig:
+ case oldconfig:
+ case listnewconfig:
+ case helpnewconfig:
+ case olddefconfig:
+ case yes2modconfig:
+ case mod2yesconfig:
+ case mod2noconfig:
+ conf_read(NULL);
+ break;
+ case allnoconfig:
+ case allyesconfig:
+ case allmodconfig:
+ case alldefconfig:
+ case randconfig:
+ name = getenv("KCONFIG_ALLCONFIG");
+ if (!name)
+ break;
+ if ((strcmp(name, "") != 0) && (strcmp(name, "1") != 0)) {
+ if (conf_read_simple(name, S_DEF_USER)) {
+ fprintf(stderr,
+ "*** Can't read seed configuration \"%s\"!\n",
+ name);
+ exit(1);
+ }
+ break;
+ }
+ switch (input_mode) {
+ case allnoconfig: name = "allno.config"; break;
+ case allyesconfig: name = "allyes.config"; break;
+ case allmodconfig: name = "allmod.config"; break;
+ case alldefconfig: name = "alldef.config"; break;
+ case randconfig: name = "allrandom.config"; break;
+ default: break;
+ }
+ if (conf_read_simple(name, S_DEF_USER) &&
+ conf_read_simple("all.config", S_DEF_USER)) {
+ fprintf(stderr,
+ "*** KCONFIG_ALLCONFIG set, but no \"%s\" or \"all.config\" file found\n",
+ name);
+ exit(1);
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (sync_kconfig) {
+ name = getenv("KCONFIG_NOSILENTUPDATE");
+ if (name && *name) {
+ if (conf_get_changed()) {
+ fprintf(stderr,
+ "\n*** The configuration requires explicit update.\n\n");
+ return 1;
+ }
+ no_conf_write = 1;
+ }
+ }
+
+ switch (input_mode) {
+ case allnoconfig:
+ conf_set_all_new_symbols(def_no);
+ break;
+ case allyesconfig:
+ conf_set_all_new_symbols(def_yes);
+ break;
+ case allmodconfig:
+ conf_set_all_new_symbols(def_mod);
+ break;
+ case alldefconfig:
+ conf_set_all_new_symbols(def_default);
+ break;
+ case randconfig:
+ /* Really nothing to do in this loop */
+ while (conf_set_all_new_symbols(def_random)) ;
+ break;
+ case defconfig:
+ conf_set_all_new_symbols(def_default);
+ break;
+ case savedefconfig:
+ break;
+ case yes2modconfig:
+ conf_rewrite_tristates(yes, mod);
+ break;
+ case mod2yesconfig:
+ conf_rewrite_tristates(mod, yes);
+ break;
+ case mod2noconfig:
+ conf_rewrite_tristates(mod, no);
+ break;
+ case oldaskconfig:
+ rootEntry = &rootmenu;
+ conf(&rootmenu);
+ input_mode = oldconfig;
+ /* fall through */
+ case oldconfig:
+ case listnewconfig:
+ case helpnewconfig:
+ case syncconfig:
+ /* Update until a loop caused no more changes */
+ do {
+ conf_cnt = 0;
+ check_conf(&rootmenu);
+ } while (conf_cnt);
+ break;
+ case olddefconfig:
+ default:
+ break;
+ }
+
+ if (input_mode == savedefconfig) {
+ if (conf_write_defconfig(defconfig_file)) {
+ fprintf(stderr, "n*** Error while saving defconfig to: %s\n\n",
+ defconfig_file);
+ return 1;
+ }
+ } else if (input_mode != listnewconfig && input_mode != helpnewconfig) {
+ if (!no_conf_write && conf_write(NULL)) {
+ fprintf(stderr, "\n*** Error during writing of the configuration.\n\n");
+ exit(1);
+ }
+
+ /*
+ * Create auto.conf if it does not exist.
+ * This prevents GNU Make 4.1 or older from emitting
+ * "include/config/auto.conf: No such file or directory"
+ * in the top-level Makefile
+ *
+ * syncconfig always creates or updates auto.conf because it is
+ * used during the build.
+ */
+ if (conf_write_autoconf(sync_kconfig) && sync_kconfig) {
+ fprintf(stderr,
+ "\n*** Error during sync of the configuration.\n\n");
+ return 1;
+ }
+ }
+ return 0;
+}
Index: Baikal/M1000/create-6.1.63-6.4.92-host-limits-patch/linux-m1-6.1.63-6.4.92-new/scripts/kconfig/confdata.c
===================================================================
--- Baikal/M1000/create-6.1.63-6.4.92-host-limits-patch/linux-m1-6.1.63-6.4.92-new/scripts/kconfig/confdata.c (nonexistent)
+++ Baikal/M1000/create-6.1.63-6.4.92-host-limits-patch/linux-m1-6.1.63-6.4.92-new/scripts/kconfig/confdata.c (revision 385)
@@ -0,0 +1,1265 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ */
+
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <linux/limits.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "lkc.h"
+
+/* return true if 'path' exists, false otherwise */
+static bool is_present(const char *path)
+{
+ struct stat st;
+
+ return !stat(path, &st);
+}
+
+/* return true if 'path' exists and it is a directory, false otherwise */
+static bool is_dir(const char *path)
+{
+ struct stat st;
+
+ if (stat(path, &st))
+ return false;
+
+ return S_ISDIR(st.st_mode);
+}
+
+/* return true if the given two files are the same, false otherwise */
+static bool is_same(const char *file1, const char *file2)
+{
+ int fd1, fd2;
+ struct stat st1, st2;
+ void *map1, *map2;
+ bool ret = false;
+
+ fd1 = open(file1, O_RDONLY);
+ if (fd1 < 0)
+ return ret;
+
+ fd2 = open(file2, O_RDONLY);
+ if (fd2 < 0)
+ goto close1;
+
+ ret = fstat(fd1, &st1);
+ if (ret)
+ goto close2;
+ ret = fstat(fd2, &st2);
+ if (ret)
+ goto close2;
+
+ if (st1.st_size != st2.st_size)
+ goto close2;
+
+ map1 = mmap(NULL, st1.st_size, PROT_READ, MAP_PRIVATE, fd1, 0);
+ if (map1 == MAP_FAILED)
+ goto close2;
+
+ map2 = mmap(NULL, st2.st_size, PROT_READ, MAP_PRIVATE, fd2, 0);
+ if (map2 == MAP_FAILED)
+ goto close2;
+
+ if (bcmp(map1, map2, st1.st_size))
+ goto close2;
+
+ ret = true;
+close2:
+ close(fd2);
+close1:
+ close(fd1);
+
+ return ret;
+}
+
+/*
+ * Create the parent directory of the given path.
+ *
+ * For example, if 'include/config/auto.conf' is given, create 'include/config'.
+ */
+static int make_parent_dir(const char *path)
+{
+ char tmp[PATH_MAX + 1];
+ char *p;
+
+ strncpy(tmp, path, sizeof(tmp));
+ tmp[sizeof(tmp) - 1] = 0;
+
+ /* Remove the base name. Just return if nothing is left */
+ p = strrchr(tmp, '/');
+ if (!p)
+ return 0;
+ *(p + 1) = 0;
+
+ /* Just in case it is an absolute path */
+ p = tmp;
+ while (*p == '/')
+ p++;
+
+ while ((p = strchr(p, '/'))) {
+ *p = 0;
+
+ /* skip if the directory exists */
+ if (!is_dir(tmp) && mkdir(tmp, 0755))
+ return -1;
+
+ *p = '/';
+ while (*p == '/')
+ p++;
+ }
+
+ return 0;
+}
+
+static char depfile_path[PATH_MAX];
+static size_t depfile_prefix_len;
+
+/* touch depfile for symbol 'name' */
+static int conf_touch_dep(const char *name)
+{
+ int fd;
+
+ /* check overflow: prefix + name + '\0' must fit in buffer. */
+ if (depfile_prefix_len + strlen(name) + 1 > sizeof(depfile_path))
+ return -1;
+
+ strcpy(depfile_path + depfile_prefix_len, name);
+
+ fd = open(depfile_path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
+ if (fd == -1)
+ return -1;
+ close(fd);
+
+ return 0;
+}
+
+static void conf_warning(const char *fmt, ...)
+ __attribute__ ((format (printf, 1, 2)));
+
+static void conf_message(const char *fmt, ...)
+ __attribute__ ((format (printf, 1, 2)));
+
+static const char *conf_filename;
+static int conf_lineno, conf_warnings;
+
+static void conf_warning(const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ fprintf(stderr, "%s:%d:warning: ", conf_filename, conf_lineno);
+ vfprintf(stderr, fmt, ap);
+ fprintf(stderr, "\n");
+ va_end(ap);
+ conf_warnings++;
+}
+
+static void conf_default_message_callback(const char *s)
+{
+ printf("#\n# ");
+ printf("%s", s);
+ printf("\n#\n");
+}
+
+static void (*conf_message_callback)(const char *s) =
+ conf_default_message_callback;
+void conf_set_message_callback(void (*fn)(const char *s))
+{
+ conf_message_callback = fn;
+}
+
+static void conf_message(const char *fmt, ...)
+{
+ va_list ap;
+ char buf[4096];
+
+ if (!conf_message_callback)
+ return;
+
+ va_start(ap, fmt);
+
+ vsnprintf(buf, sizeof(buf), fmt, ap);
+ conf_message_callback(buf);
+ va_end(ap);
+}
+
+const char *conf_get_configname(void)
+{
+ char *name = getenv("KCONFIG_CONFIG");
+
+ return name ? name : ".config";
+}
+
+static const char *conf_get_autoconfig_name(void)
+{
+ char *name = getenv("KCONFIG_AUTOCONFIG");
+
+ return name ? name : "include/config/auto.conf";
+}
+
+static const char *conf_get_autoheader_name(void)
+{
+ char *name = getenv("KCONFIG_AUTOHEADER");
+
+ return name ? name : "include/generated/autoconf.h";
+}
+
+static const char *conf_get_rustccfg_name(void)
+{
+ char *name = getenv("KCONFIG_RUSTCCFG");
+
+ return name ? name : "include/generated/rustc_cfg";
+}
+
+static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p)
+{
+ char *p2;
+
+ switch (sym->type) {
+ case S_TRISTATE:
+ if (p[0] == 'm') {
+ sym->def[def].tri = mod;
+ sym->flags |= def_flags;
+ break;
+ }
+ /* fall through */
+ case S_BOOLEAN:
+ if (p[0] == 'y') {
+ sym->def[def].tri = yes;
+ sym->flags |= def_flags;
+ break;
+ }
+ if (p[0] == 'n') {
+ sym->def[def].tri = no;
+ sym->flags |= def_flags;
+ break;
+ }
+ if (def != S_DEF_AUTO)
+ conf_warning("symbol value '%s' invalid for %s",
+ p, sym->name);
+ return 1;
+ case S_STRING:
+ /* No escaping for S_DEF_AUTO (include/config/auto.conf) */
+ if (def != S_DEF_AUTO) {
+ if (*p++ != '"')
+ break;
+ for (p2 = p; (p2 = strpbrk(p2, "\"\\")); p2++) {
+ if (*p2 == '"') {
+ *p2 = 0;
+ break;
+ }
+ memmove(p2, p2 + 1, strlen(p2));
+ }
+ if (!p2) {
+ conf_warning("invalid string found");
+ return 1;
+ }
+ }
+ /* fall through */
+ case S_INT:
+ case S_HEX:
+ if (sym_string_valid(sym, p)) {
+ sym->def[def].val = xstrdup(p);
+ sym->flags |= def_flags;
+ } else {
+ if (def != S_DEF_AUTO)
+ conf_warning("symbol value '%s' invalid for %s",
+ p, sym->name);
+ return 1;
+ }
+ break;
+ default:
+ ;
+ }
+ return 0;
+}
+
+#define LINE_GROWTH 16
+static int add_byte(int c, char **lineptr, size_t slen, size_t *n)
+{
+ char *nline;
+ size_t new_size = slen + 1;
+ if (new_size > *n) {
+ new_size += LINE_GROWTH - 1;
+ new_size *= 2;
+ nline = xrealloc(*lineptr, new_size);
+ if (!nline)
+ return -1;
+
+ *lineptr = nline;
+ *n = new_size;
+ }
+
+ (*lineptr)[slen] = c;
+
+ return 0;
+}
+
+static ssize_t compat_getline(char **lineptr, size_t *n, FILE *stream)
+{
+ char *line = *lineptr;
+ size_t slen = 0;
+
+ for (;;) {
+ int c = getc(stream);
+
+ switch (c) {
+ case '\n':
+ if (add_byte(c, &line, slen, n) < 0)
+ goto e_out;
+ slen++;
+ /* fall through */
+ case EOF:
+ if (add_byte('\0', &line, slen, n) < 0)
+ goto e_out;
+ *lineptr = line;
+ if (slen == 0)
+ return -1;
+ return slen;
+ default:
+ if (add_byte(c, &line, slen, n) < 0)
+ goto e_out;
+ slen++;
+ }
+ }
+
+e_out:
+ line[slen-1] = '\0';
+ *lineptr = line;
+ return -1;
+}
+
+int conf_read_simple(const char *name, int def)
+{
+ FILE *in = NULL;
+ char *line = NULL;
+ size_t line_asize = 0;
+ char *p, *p2;
+ struct symbol *sym;
+ int i, def_flags;
+
+ if (name) {
+ in = zconf_fopen(name);
+ } else {
+ char *env;
+
+ name = conf_get_configname();
+ in = zconf_fopen(name);
+ if (in)
+ goto load;
+ conf_set_changed(true);
+
+ env = getenv("KCONFIG_DEFCONFIG_LIST");
+ if (!env)
+ return 1;
+
+ while (1) {
+ bool is_last;
+
+ while (isspace(*env))
+ env++;
+
+ if (!*env)
+ break;
+
+ p = env;
+ while (*p && !isspace(*p))
+ p++;
+
+ is_last = (*p == '\0');
+
+ *p = '\0';
+
+ in = zconf_fopen(env);
+ if (in) {
+ conf_message("using defaults found in %s",
+ env);
+ goto load;
+ }
+
+ if (is_last)
+ break;
+
+ env = p + 1;
+ }
+ }
+ if (!in)
+ return 1;
+
+load:
+ conf_filename = name;
+ conf_lineno = 0;
+ conf_warnings = 0;
+
+ def_flags = SYMBOL_DEF << def;
+ for_all_symbols(i, sym) {
+ sym->flags |= SYMBOL_CHANGED;
+ sym->flags &= ~(def_flags|SYMBOL_VALID);
+ if (sym_is_choice(sym))
+ sym->flags |= def_flags;
+ switch (sym->type) {
+ case S_INT:
+ case S_HEX:
+ case S_STRING:
+ if (sym->def[def].val)
+ free(sym->def[def].val);
+ /* fall through */
+ default:
+ sym->def[def].val = NULL;
+ sym->def[def].tri = no;
+ }
+ }
+
+ while (compat_getline(&line, &line_asize, in) != -1) {
+ conf_lineno++;
+ sym = NULL;
+ if (line[0] == '#') {
+ if (memcmp(line + 2, CONFIG_, strlen(CONFIG_)))
+ continue;
+ p = strchr(line + 2 + strlen(CONFIG_), ' ');
+ if (!p)
+ continue;
+ *p++ = 0;
+ if (strncmp(p, "is not set", 10))
+ continue;
+ if (def == S_DEF_USER) {
+ sym = sym_find(line + 2 + strlen(CONFIG_));
+ if (!sym) {
+ conf_set_changed(true);
+ continue;
+ }
+ } else {
+ sym = sym_lookup(line + 2 + strlen(CONFIG_), 0);
+ if (sym->type == S_UNKNOWN)
+ sym->type = S_BOOLEAN;
+ }
+ if (sym->flags & def_flags) {
+ conf_warning("override: reassigning to symbol %s", sym->name);
+ }
+ switch (sym->type) {
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ sym->def[def].tri = no;
+ sym->flags |= def_flags;
+ break;
+ default:
+ ;
+ }
+ } else if (memcmp(line, CONFIG_, strlen(CONFIG_)) == 0) {
+ p = strchr(line + strlen(CONFIG_), '=');
+ if (!p)
+ continue;
+ *p++ = 0;
+ p2 = strchr(p, '\n');
+ if (p2) {
+ *p2-- = 0;
+ if (*p2 == '\r')
+ *p2 = 0;
+ }
+
+ sym = sym_find(line + strlen(CONFIG_));
+ if (!sym) {
+ if (def == S_DEF_AUTO)
+ /*
+ * Reading from include/config/auto.conf
+ * If CONFIG_FOO previously existed in
+ * auto.conf but it is missing now,
+ * include/config/FOO must be touched.
+ */
+ conf_touch_dep(line + strlen(CONFIG_));
+ else
+ conf_set_changed(true);
+ continue;
+ }
+
+ if (sym->flags & def_flags) {
+ conf_warning("override: reassigning to symbol %s", sym->name);
+ }
+ if (conf_set_sym_val(sym, def, def_flags, p))
+ continue;
+ } else {
+ if (line[0] != '\r' && line[0] != '\n')
+ conf_warning("unexpected data: %.*s",
+ (int)strcspn(line, "\r\n"), line);
+
+ continue;
+ }
+
+ if (sym && sym_is_choice_value(sym)) {
+ struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym));
+ switch (sym->def[def].tri) {
+ case no:
+ break;
+ case mod:
+ if (cs->def[def].tri == yes) {
+ conf_warning("%s creates inconsistent choice state", sym->name);
+ cs->flags &= ~def_flags;
+ }
+ break;
+ case yes:
+ if (cs->def[def].tri != no)
+ conf_warning("override: %s changes choice state", sym->name);
+ cs->def[def].val = sym;
+ break;
+ }
+ cs->def[def].tri = EXPR_OR(cs->def[def].tri, sym->def[def].tri);
+ }
+ }
+ free(line);
+ fclose(in);
+ return 0;
+}
+
+int conf_read(const char *name)
+{
+ struct symbol *sym;
+ int conf_unsaved = 0;
+ int i;
+
+ conf_set_changed(false);
+
+ if (conf_read_simple(name, S_DEF_USER)) {
+ sym_calc_value(modules_sym);
+ return 1;
+ }
+
+ sym_calc_value(modules_sym);
+
+ for_all_symbols(i, sym) {
+ sym_calc_value(sym);
+ if (sym_is_choice(sym) || (sym->flags & SYMBOL_NO_WRITE))
+ continue;
+ if (sym_has_value(sym) && (sym->flags & SYMBOL_WRITE)) {
+ /* check that calculated value agrees with saved value */
+ switch (sym->type) {
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ if (sym->def[S_DEF_USER].tri == sym_get_tristate_value(sym))
+ continue;
+ break;
+ default:
+ if (!strcmp(sym->curr.val, sym->def[S_DEF_USER].val))
+ continue;
+ break;
+ }
+ } else if (!sym_has_value(sym) && !(sym->flags & SYMBOL_WRITE))
+ /* no previous value and not saved */
+ continue;
+ conf_unsaved++;
+ /* maybe print value in verbose mode... */
+ }
+
+ for_all_symbols(i, sym) {
+ if (sym_has_value(sym) && !sym_is_choice_value(sym)) {
+ /* Reset values of generates values, so they'll appear
+ * as new, if they should become visible, but that
+ * doesn't quite work if the Kconfig and the saved
+ * configuration disagree.
+ */
+ if (sym->visible == no && !conf_unsaved)
+ sym->flags &= ~SYMBOL_DEF_USER;
+ switch (sym->type) {
+ case S_STRING:
+ case S_INT:
+ case S_HEX:
+ /* Reset a string value if it's out of range */
+ if (sym_string_within_range(sym, sym->def[S_DEF_USER].val))
+ break;
+ sym->flags &= ~(SYMBOL_VALID|SYMBOL_DEF_USER);
+ conf_unsaved++;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ if (conf_warnings || conf_unsaved)
+ conf_set_changed(true);
+
+ return 0;
+}
+
+struct comment_style {
+ const char *decoration;
+ const char *prefix;
+ const char *postfix;
+};
+
+static const struct comment_style comment_style_pound = {
+ .decoration = "#",
+ .prefix = "#",
+ .postfix = "#",
+};
+
+static const struct comment_style comment_style_c = {
+ .decoration = " *",
+ .prefix = "/*",
+ .postfix = " */",
+};
+
+static void conf_write_heading(FILE *fp, const struct comment_style *cs)
+{
+ if (!cs)
+ return;
+
+ fprintf(fp, "%s\n", cs->prefix);
+
+ fprintf(fp, "%s Automatically generated file; DO NOT EDIT.\n",
+ cs->decoration);
+
+ fprintf(fp, "%s %s\n", cs->decoration, rootmenu.prompt->text);
+
+ fprintf(fp, "%s\n", cs->postfix);
+}
+
+/* The returned pointer must be freed on the caller side */
+static char *escape_string_value(const char *in)
+{
+ const char *p;
+ char *out;
+ size_t len;
+
+ len = strlen(in) + strlen("\"\"") + 1;
+
+ p = in;
+ while (1) {
+ p += strcspn(p, "\"\\");
+
+ if (p[0] == '\0')
+ break;
+
+ len++;
+ p++;
+ }
+
+ out = xmalloc(len);
+ out[0] = '\0';
+
+ strcat(out, "\"");
+
+ p = in;
+ while (1) {
+ len = strcspn(p, "\"\\");
+ strncat(out, p, len);
+ p += len;
+
+ if (p[0] == '\0')
+ break;
+
+ strcat(out, "\\");
+ strncat(out, p++, 1);
+ }
+
+ strcat(out, "\"");
+
+ return out;
+}
+
+enum output_n { OUTPUT_N, OUTPUT_N_AS_UNSET, OUTPUT_N_NONE };
+
+static void __print_symbol(FILE *fp, struct symbol *sym, enum output_n output_n,
+ bool escape_string)
+{
+ const char *val;
+ char *escaped = NULL;
+
+ if (sym->type == S_UNKNOWN)
+ return;
+
+ val = sym_get_string_value(sym);
+
+ if ((sym->type == S_BOOLEAN || sym->type == S_TRISTATE) &&
+ output_n != OUTPUT_N && *val == 'n') {
+ if (output_n == OUTPUT_N_AS_UNSET)
+ fprintf(fp, "# %s%s is not set\n", CONFIG_, sym->name);
+ return;
+ }
+
+ if (sym->type == S_STRING && escape_string) {
+ escaped = escape_string_value(val);
+ val = escaped;
+ }
+
+ fprintf(fp, "%s%s=%s\n", CONFIG_, sym->name, val);
+
+ free(escaped);
+}
+
+static void print_symbol_for_dotconfig(FILE *fp, struct symbol *sym)
+{
+ __print_symbol(fp, sym, OUTPUT_N_AS_UNSET, true);
+}
+
+static void print_symbol_for_autoconf(FILE *fp, struct symbol *sym)
+{
+ __print_symbol(fp, sym, OUTPUT_N_NONE, false);
+}
+
+void print_symbol_for_listconfig(struct symbol *sym)
+{
+ __print_symbol(stdout, sym, OUTPUT_N, true);
+}
+
+static void print_symbol_for_c(FILE *fp, struct symbol *sym)
+{
+ const char *val;
+ const char *sym_suffix = "";
+ const char *val_prefix = "";
+ char *escaped = NULL;
+
+ if (sym->type == S_UNKNOWN)
+ return;
+
+ val = sym_get_string_value(sym);
+
+ switch (sym->type) {
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ switch (*val) {
+ case 'n':
+ return;
+ case 'm':
+ sym_suffix = "_MODULE";
+ /* fall through */
+ default:
+ val = "1";
+ }
+ break;
+ case S_HEX:
+ if (val[0] != '0' || (val[1] != 'x' && val[1] != 'X'))
+ val_prefix = "0x";
+ break;
+ case S_STRING:
+ escaped = escape_string_value(val);
+ val = escaped;
+ default:
+ break;
+ }
+
+ fprintf(fp, "#define %s%s%s %s%s\n", CONFIG_, sym->name, sym_suffix,
+ val_prefix, val);
+
+ free(escaped);
+}
+
+static void print_symbol_for_rustccfg(FILE *fp, struct symbol *sym)
+{
+ const char *val;
+ const char *val_prefix = "";
+ char *val_prefixed = NULL;
+ size_t val_prefixed_len;
+ char *escaped = NULL;
+
+ if (sym->type == S_UNKNOWN)
+ return;
+
+ val = sym_get_string_value(sym);
+
+ switch (sym->type) {
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ /*
+ * We do not care about disabled ones, i.e. no need for
+ * what otherwise are "comments" in other printers.
+ */
+ if (*val == 'n')
+ return;
+
+ /*
+ * To have similar functionality to the C macro `IS_ENABLED()`
+ * we provide an empty `--cfg CONFIG_X` here in both `y`
+ * and `m` cases.
+ *
+ * Then, the common `fprintf()` below will also give us
+ * a `--cfg CONFIG_X="y"` or `--cfg CONFIG_X="m"`, which can
+ * be used as the equivalent of `IS_BUILTIN()`/`IS_MODULE()`.
+ */
+ fprintf(fp, "--cfg=%s%s\n", CONFIG_, sym->name);
+ break;
+ case S_HEX:
+ if (val[0] != '0' || (val[1] != 'x' && val[1] != 'X'))
+ val_prefix = "0x";
+ break;
+ default:
+ break;
+ }
+
+ if (strlen(val_prefix) > 0) {
+ val_prefixed_len = strlen(val) + strlen(val_prefix) + 1;
+ val_prefixed = xmalloc(val_prefixed_len);
+ snprintf(val_prefixed, val_prefixed_len, "%s%s", val_prefix, val);
+ val = val_prefixed;
+ }
+
+ /* All values get escaped: the `--cfg` option only takes strings */
+ escaped = escape_string_value(val);
+ val = escaped;
+
+ fprintf(fp, "--cfg=%s%s=%s\n", CONFIG_, sym->name, val);
+
+ free(escaped);
+ free(val_prefixed);
+}
+
+/*
+ * Write out a minimal config.
+ * All values that has default values are skipped as this is redundant.
+ */
+int conf_write_defconfig(const char *filename)
+{
+ struct symbol *sym;
+ struct menu *menu;
+ FILE *out;
+
+ out = fopen(filename, "w");
+ if (!out)
+ return 1;
+
+ sym_clear_all_valid();
+
+ /* Traverse all menus to find all relevant symbols */
+ menu = rootmenu.list;
+
+ while (menu != NULL)
+ {
+ sym = menu->sym;
+ if (sym == NULL) {
+ if (!menu_is_visible(menu))
+ goto next_menu;
+ } else if (!sym_is_choice(sym)) {
+ sym_calc_value(sym);
+ if (!(sym->flags & SYMBOL_WRITE))
+ goto next_menu;
+ sym->flags &= ~SYMBOL_WRITE;
+ /* If we cannot change the symbol - skip */
+ if (!sym_is_changeable(sym))
+ goto next_menu;
+ /* If symbol equals to default value - skip */
+ if (strcmp(sym_get_string_value(sym), sym_get_string_default(sym)) == 0)
+ goto next_menu;
+
+ /*
+ * If symbol is a choice value and equals to the
+ * default for a choice - skip.
+ * But only if value is bool and equal to "y" and
+ * choice is not "optional".
+ * (If choice is "optional" then all values can be "n")
+ */
+ if (sym_is_choice_value(sym)) {
+ struct symbol *cs;
+ struct symbol *ds;
+
+ cs = prop_get_symbol(sym_get_choice_prop(sym));
+ ds = sym_choice_default(cs);
+ if (!sym_is_optional(cs) && sym == ds) {
+ if ((sym->type == S_BOOLEAN) &&
+ sym_get_tristate_value(sym) == yes)
+ goto next_menu;
+ }
+ }
+ print_symbol_for_dotconfig(out, sym);
+ }
+next_menu:
+ if (menu->list != NULL) {
+ menu = menu->list;
+ }
+ else if (menu->next != NULL) {
+ menu = menu->next;
+ } else {
+ while ((menu = menu->parent)) {
+ if (menu->next != NULL) {
+ menu = menu->next;
+ break;
+ }
+ }
+ }
+ }
+ fclose(out);
+ return 0;
+}
+
+int conf_write(const char *name)
+{
+ FILE *out;
+ struct symbol *sym;
+ struct menu *menu;
+ const char *str;
+ char tmpname[PATH_MAX + 1], oldname[PATH_MAX + 1];
+ char *env;
+ int i;
+ bool need_newline = false;
+
+ if (!name)
+ name = conf_get_configname();
+
+ if (!*name) {
+ fprintf(stderr, "config name is empty\n");
+ return -1;
+ }
+
+ if (is_dir(name)) {
+ fprintf(stderr, "%s: Is a directory\n", name);
+ return -1;
+ }
+
+ if (make_parent_dir(name))
+ return -1;
+
+ env = getenv("KCONFIG_OVERWRITECONFIG");
+ if (env && *env) {
+ *tmpname = 0;
+ out = fopen(name, "w");
+ } else {
+ snprintf(tmpname, sizeof(tmpname), "%s.%d.tmp",
+ name, (int)getpid());
+ out = fopen(tmpname, "w");
+ }
+ if (!out)
+ return 1;
+
+ conf_write_heading(out, &comment_style_pound);
+
+ if (!conf_get_changed())
+ sym_clear_all_valid();
+
+ menu = rootmenu.list;
+ while (menu) {
+ sym = menu->sym;
+ if (!sym) {
+ if (!menu_is_visible(menu))
+ goto next;
+ str = menu_get_prompt(menu);
+ fprintf(out, "\n"
+ "#\n"
+ "# %s\n"
+ "#\n", str);
+ need_newline = false;
+ } else if (!(sym->flags & SYMBOL_CHOICE) &&
+ !(sym->flags & SYMBOL_WRITTEN)) {
+ sym_calc_value(sym);
+ if (!(sym->flags & SYMBOL_WRITE))
+ goto next;
+ if (need_newline) {
+ fprintf(out, "\n");
+ need_newline = false;
+ }
+ sym->flags |= SYMBOL_WRITTEN;
+ print_symbol_for_dotconfig(out, sym);
+ }
+
+next:
+ if (menu->list) {
+ menu = menu->list;
+ continue;
+ }
+
+end_check:
+ if (!menu->sym && menu_is_visible(menu) && menu != &rootmenu &&
+ menu->prompt->type == P_MENU) {
+ fprintf(out, "# end of %s\n", menu_get_prompt(menu));
+ need_newline = true;
+ }
+
+ if (menu->next) {
+ menu = menu->next;
+ } else {
+ menu = menu->parent;
+ if (menu)
+ goto end_check;
+ }
+ }
+ fclose(out);
+
+ for_all_symbols(i, sym)
+ sym->flags &= ~SYMBOL_WRITTEN;
+
+ if (*tmpname) {
+ if (is_same(name, tmpname)) {
+ conf_message("No change to %s", name);
+ unlink(tmpname);
+ conf_set_changed(false);
+ return 0;
+ }
+
+ snprintf(oldname, sizeof(oldname), "%s.old", name);
+ rename(name, oldname);
+ if (rename(tmpname, name))
+ return 1;
+ }
+
+ conf_message("configuration written to %s", name);
+
+ conf_set_changed(false);
+
+ return 0;
+}
+
+/* write a dependency file as used by kbuild to track dependencies */
+static int conf_write_autoconf_cmd(const char *autoconf_name)
+{
+ char name[PATH_MAX], tmp[PATH_MAX];
+ struct file *file;
+ FILE *out;
+ int ret;
+
+ ret = snprintf(name, sizeof(name), "%s.cmd", autoconf_name);
+ if (ret >= sizeof(name)) /* check truncation */
+ return -1;
+
+ if (make_parent_dir(name))
+ return -1;
+
+ ret = snprintf(tmp, sizeof(tmp), "%s.cmd.tmp", autoconf_name);
+ if (ret >= sizeof(tmp)) /* check truncation */
+ return -1;
+
+ out = fopen(tmp, "w");
+ if (!out) {
+ perror("fopen");
+ return -1;
+ }
+
+ fprintf(out, "deps_config := \\\n");
+ for (file = file_list; file; file = file->next)
+ fprintf(out, "\t%s \\\n", file->name);
+
+ fprintf(out, "\n%s: $(deps_config)\n\n", autoconf_name);
+
+ env_write_dep(out, autoconf_name);
+
+ fprintf(out, "\n$(deps_config): ;\n");
+
+ fflush(out);
+ ret = ferror(out); /* error check for all fprintf() calls */
+ fclose(out);
+ if (ret)
+ return -1;
+
+ if (rename(tmp, name)) {
+ perror("rename");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int conf_touch_deps(void)
+{
+ const char *name, *tmp;
+ struct symbol *sym;
+ int res, i;
+
+ name = conf_get_autoconfig_name();
+ tmp = strrchr(name, '/');
+ depfile_prefix_len = tmp ? tmp - name + 1 : 0;
+ if (depfile_prefix_len + 1 > sizeof(depfile_path))
+ return -1;
+
+ strncpy(depfile_path, name, depfile_prefix_len);
+ depfile_path[depfile_prefix_len] = 0;
+
+ conf_read_simple(name, S_DEF_AUTO);
+ sym_calc_value(modules_sym);
+
+ for_all_symbols(i, sym) {
+ sym_calc_value(sym);
+ if ((sym->flags & SYMBOL_NO_WRITE) || !sym->name)
+ continue;
+ if (sym->flags & SYMBOL_WRITE) {
+ if (sym->flags & SYMBOL_DEF_AUTO) {
+ /*
+ * symbol has old and new value,
+ * so compare them...
+ */
+ switch (sym->type) {
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ if (sym_get_tristate_value(sym) ==
+ sym->def[S_DEF_AUTO].tri)
+ continue;
+ break;
+ case S_STRING:
+ case S_HEX:
+ case S_INT:
+ if (!strcmp(sym_get_string_value(sym),
+ sym->def[S_DEF_AUTO].val))
+ continue;
+ break;
+ default:
+ break;
+ }
+ } else {
+ /*
+ * If there is no old value, only 'no' (unset)
+ * is allowed as new value.
+ */
+ switch (sym->type) {
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ if (sym_get_tristate_value(sym) == no)
+ continue;
+ break;
+ default:
+ break;
+ }
+ }
+ } else if (!(sym->flags & SYMBOL_DEF_AUTO))
+ /* There is neither an old nor a new value. */
+ continue;
+ /* else
+ * There is an old value, but no new value ('no' (unset)
+ * isn't saved in auto.conf, so the old value is always
+ * different from 'no').
+ */
+
+ res = conf_touch_dep(sym->name);
+ if (res)
+ return res;
+ }
+
+ return 0;
+}
+
+static int __conf_write_autoconf(const char *filename,
+ void (*print_symbol)(FILE *, struct symbol *),
+ const struct comment_style *comment_style)
+{
+ char tmp[PATH_MAX];
+ FILE *file;
+ struct symbol *sym;
+ int ret, i;
+
+ if (make_parent_dir(filename))
+ return -1;
+
+ ret = snprintf(tmp, sizeof(tmp), "%s.tmp", filename);
+ if (ret >= sizeof(tmp)) /* check truncation */
+ return -1;
+
+ file = fopen(tmp, "w");
+ if (!file) {
+ perror("fopen");
+ return -1;
+ }
+
+ conf_write_heading(file, comment_style);
+
+ for_all_symbols(i, sym)
+ if ((sym->flags & SYMBOL_WRITE) && sym->name)
+ print_symbol(file, sym);
+
+ fflush(file);
+ /* check possible errors in conf_write_heading() and print_symbol() */
+ ret = ferror(file);
+ fclose(file);
+ if (ret)
+ return -1;
+
+ if (rename(tmp, filename)) {
+ perror("rename");
+ return -1;
+ }
+
+ return 0;
+}
+
+int conf_write_autoconf(int overwrite)
+{
+ struct symbol *sym;
+ const char *autoconf_name = conf_get_autoconfig_name();
+ int ret, i;
+
+ if (!overwrite && is_present(autoconf_name))
+ return 0;
+
+ ret = conf_write_autoconf_cmd(autoconf_name);
+ if (ret)
+ return -1;
+
+ if (conf_touch_deps())
+ return 1;
+
+ for_all_symbols(i, sym)
+ sym_calc_value(sym);
+
+ ret = __conf_write_autoconf(conf_get_autoheader_name(),
+ print_symbol_for_c,
+ &comment_style_c);
+ if (ret)
+ return ret;
+
+ ret = __conf_write_autoconf(conf_get_rustccfg_name(),
+ print_symbol_for_rustccfg,
+ NULL);
+ if (ret)
+ return ret;
+
+ /*
+ * Create include/config/auto.conf. This must be the last step because
+ * Kbuild has a dependency on auto.conf and this marks the successful
+ * completion of the previous steps.
+ */
+ ret = __conf_write_autoconf(conf_get_autoconfig_name(),
+ print_symbol_for_autoconf,
+ &comment_style_pound);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static bool conf_changed;
+static void (*conf_changed_callback)(void);
+
+void conf_set_changed(bool val)
+{
+ bool changed = conf_changed != val;
+
+ conf_changed = val;
+
+ if (conf_changed_callback && changed)
+ conf_changed_callback();
+}
+
+bool conf_get_changed(void)
+{
+ return conf_changed;
+}
+
+void conf_set_changed_callback(void (*fn)(void))
+{
+ conf_changed_callback = fn;
+}
+
+void set_all_choice_values(struct symbol *csym)
+{
+ struct property *prop;
+ struct symbol *sym;
+ struct expr *e;
+
+ prop = sym_get_choice_prop(csym);
+
+ /*
+ * Set all non-assinged choice values to no
+ */
+ expr_list_for_each_sym(prop->expr, e, sym) {
+ if (!sym_has_value(sym))
+ sym->def[S_DEF_USER].tri = no;
+ }
+ csym->flags |= SYMBOL_DEF_USER;
+ /* clear VALID to get value calculated */
+ csym->flags &= ~(SYMBOL_VALID | SYMBOL_NEED_SET_CHOICE_VALUES);
+}
Index: Baikal/M1000/create-6.1.63-6.4.92-host-limits-patch/linux-m1-6.1.63-6.4.92-new/scripts/kconfig/lexer.l
===================================================================
--- Baikal/M1000/create-6.1.63-6.4.92-host-limits-patch/linux-m1-6.1.63-6.4.92-new/scripts/kconfig/lexer.l (nonexistent)
+++ Baikal/M1000/create-6.1.63-6.4.92-host-limits-patch/linux-m1-6.1.63-6.4.92-new/scripts/kconfig/lexer.l (revision 385)
@@ -0,0 +1,468 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ */
+%option nostdinit noyywrap never-interactive full ecs
+%option 8bit nodefault yylineno
+%x ASSIGN_VAL HELP STRING
+%{
+
+#include <assert.h>
+#include <linux/limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "lkc.h"
+#include "parser.tab.h"
+
+#define YY_DECL static int yylex1(void)
+
+#define START_STRSIZE 16
+
+static struct {
+ struct file *file;
+ int lineno;
+} current_pos;
+
+static int prev_prev_token = T_EOL;
+static int prev_token = T_EOL;
+static char *text;
+static int text_size, text_asize;
+
+struct buffer {
+ struct buffer *parent;
+ YY_BUFFER_STATE state;
+};
+
+static struct buffer *current_buf;
+
+static int last_ts, first_ts;
+
+static char *expand_token(const char *in, size_t n);
+static void append_expanded_string(const char *in);
+static void zconf_endhelp(void);
+static void zconf_endfile(void);
+
+static void new_string(void)
+{
+ text = xmalloc(START_STRSIZE);
+ text_asize = START_STRSIZE;
+ text_size = 0;
+ *text = 0;
+}
+
+static void append_string(const char *str, int size)
+{
+ int new_size = text_size + size + 1;
+ if (new_size > text_asize) {
+ new_size += START_STRSIZE - 1;
+ new_size &= -START_STRSIZE;
+ text = xrealloc(text, new_size);
+ text_asize = new_size;
+ }
+ memcpy(text + text_size, str, size);
+ text_size += size;
+ text[text_size] = 0;
+}
+
+static void alloc_string(const char *str, int size)
+{
+ text = xmalloc(size + 1);
+ memcpy(text, str, size);
+ text[size] = 0;
+}
+
+static void warn_ignored_character(char chr)
+{
+ fprintf(stderr,
+ "%s:%d:warning: ignoring unsupported character '%c'\n",
+ current_file->name, yylineno, chr);
+}
+%}
+
+n [A-Za-z0-9_-]
+
+%%
+ char open_quote = 0;
+
+#.* /* ignore comment */
+[ \t]* /* whitespaces */
+\\\n /* escaped new line */
+\n return T_EOL;
+"bool" return T_BOOL;
+"choice" return T_CHOICE;
+"comment" return T_COMMENT;
+"config" return T_CONFIG;
+"def_bool" return T_DEF_BOOL;
+"def_tristate" return T_DEF_TRISTATE;
+"default" return T_DEFAULT;
+"depends" return T_DEPENDS;
+"endchoice" return T_ENDCHOICE;
+"endif" return T_ENDIF;
+"endmenu" return T_ENDMENU;
+"help" return T_HELP;
+"hex" return T_HEX;
+"if" return T_IF;
+"imply" return T_IMPLY;
+"int" return T_INT;
+"mainmenu" return T_MAINMENU;
+"menu" return T_MENU;
+"menuconfig" return T_MENUCONFIG;
+"modules" return T_MODULES;
+"on" return T_ON;
+"optional" return T_OPTIONAL;
+"prompt" return T_PROMPT;
+"range" return T_RANGE;
+"select" return T_SELECT;
+"source" return T_SOURCE;
+"string" return T_STRING;
+"tristate" return T_TRISTATE;
+"visible" return T_VISIBLE;
+"||" return T_OR;
+"&&" return T_AND;
+"=" return T_EQUAL;
+"!=" return T_UNEQUAL;
+"<" return T_LESS;
+"<=" return T_LESS_EQUAL;
+">" return T_GREATER;
+">=" return T_GREATER_EQUAL;
+"!" return T_NOT;
+"(" return T_OPEN_PAREN;
+")" return T_CLOSE_PAREN;
+":=" return T_COLON_EQUAL;
+"+=" return T_PLUS_EQUAL;
+\"|\' {
+ open_quote = yytext[0];
+ new_string();
+ BEGIN(STRING);
+ }
+{n}+ {
+ alloc_string(yytext, yyleng);
+ yylval.string = text;
+ return T_WORD;
+ }
+({n}|$)+ {
+ /* this token includes at least one '$' */
+ yylval.string = expand_token(yytext, yyleng);
+ if (strlen(yylval.string))
+ return T_WORD;
+ free(yylval.string);
+ }
+. warn_ignored_character(*yytext);
+
+<ASSIGN_VAL>{
+ [^[:blank:]\n]+.* {
+ alloc_string(yytext, yyleng);
+ yylval.string = text;
+ return T_ASSIGN_VAL;
+ }
+ \n { BEGIN(INITIAL); return T_EOL; }
+ .
+}
+
+<STRING>{
+ "$".* append_expanded_string(yytext);
+ [^$'"\\\n]+ {
+ append_string(yytext, yyleng);
+ }
+ \\.? {
+ append_string(yytext + 1, yyleng - 1);
+ }
+ \'|\" {
+ if (open_quote == yytext[0]) {
+ BEGIN(INITIAL);
+ yylval.string = text;
+ return T_WORD_QUOTE;
+ } else
+ append_string(yytext, 1);
+ }
+ \n {
+ fprintf(stderr,
+ "%s:%d:warning: multi-line strings not supported\n",
+ zconf_curname(), zconf_lineno());
+ unput('\n');
+ BEGIN(INITIAL);
+ yylval.string = text;
+ return T_WORD_QUOTE;
+ }
+ <<EOF>> {
+ BEGIN(INITIAL);
+ yylval.string = text;
+ return T_WORD_QUOTE;
+ }
+}
+
+<HELP>{
+ [ \t]+ {
+ int ts, i;
+
+ ts = 0;
+ for (i = 0; i < yyleng; i++) {
+ if (yytext[i] == '\t')
+ ts = (ts & ~7) + 8;
+ else
+ ts++;
+ }
+ last_ts = ts;
+ if (first_ts) {
+ if (ts < first_ts) {
+ zconf_endhelp();
+ return T_HELPTEXT;
+ }
+ ts -= first_ts;
+ while (ts > 8) {
+ append_string(" ", 8);
+ ts -= 8;
+ }
+ append_string(" ", ts);
+ }
+ }
+ [ \t]*\n/[^ \t\n] {
+ zconf_endhelp();
+ return T_HELPTEXT;
+ }
+ [ \t]*\n {
+ append_string("\n", 1);
+ }
+ [^ \t\n].* {
+ while (yyleng) {
+ if ((yytext[yyleng-1] != ' ') && (yytext[yyleng-1] != '\t'))
+ break;
+ yyleng--;
+ }
+ append_string(yytext, yyleng);
+ if (!first_ts)
+ first_ts = last_ts;
+ }
+ <<EOF>> {
+ zconf_endhelp();
+ return T_HELPTEXT;
+ }
+}
+
+<<EOF>> {
+ BEGIN(INITIAL);
+
+ if (prev_token != T_EOL && prev_token != T_HELPTEXT)
+ fprintf(stderr, "%s:%d:warning: no new line at end of file\n",
+ current_file->name, yylineno);
+
+ if (current_file) {
+ zconf_endfile();
+ return T_EOL;
+ }
+ fclose(yyin);
+ yyterminate();
+}
+
+%%
+
+/* second stage lexer */
+int yylex(void)
+{
+ int token;
+
+repeat:
+ token = yylex1();
+
+ if (prev_token == T_EOL || prev_token == T_HELPTEXT) {
+ if (token == T_EOL) {
+ /* Do not pass unneeded T_EOL to the parser. */
+ goto repeat;
+ } else {
+ /*
+ * For the parser, update file/lineno at the first token
+ * of each statement. Generally, \n is a statement
+ * terminator in Kconfig, but it is not always true
+ * because \n could be escaped by a backslash.
+ */
+ current_pos.file = current_file;
+ current_pos.lineno = yylineno;
+ }
+ }
+
+ if (prev_prev_token == T_EOL && prev_token == T_WORD &&
+ (token == T_EQUAL || token == T_COLON_EQUAL || token == T_PLUS_EQUAL))
+ BEGIN(ASSIGN_VAL);
+
+ prev_prev_token = prev_token;
+ prev_token = token;
+
+ return token;
+}
+
+static char *expand_token(const char *in, size_t n)
+{
+ char *out;
+ int c;
+ char c2;
+ const char *rest, *end;
+
+ new_string();
+ append_string(in, n);
+
+ /* get the whole line because we do not know the end of token. */
+ while ((c = input()) != EOF) {
+ if (c == '\n') {
+ unput(c);
+ break;
+ }
+ c2 = c;
+ append_string(&c2, 1);
+ }
+
+ rest = text;
+ out = expand_one_token(&rest);
+
+ /* push back unused characters to the input stream */
+ end = rest + strlen(rest);
+ while (end > rest)
+ unput(*--end);
+
+ free(text);
+
+ return out;
+}
+
+static void append_expanded_string(const char *str)
+{
+ const char *end;
+ char *res;
+
+ str++;
+
+ res = expand_dollar(&str);
+
+ /* push back unused characters to the input stream */
+ end = str + strlen(str);
+ while (end > str)
+ unput(*--end);
+
+ append_string(res, strlen(res));
+
+ free(res);
+}
+
+void zconf_starthelp(void)
+{
+ new_string();
+ last_ts = first_ts = 0;
+ BEGIN(HELP);
+}
+
+static void zconf_endhelp(void)
+{
+ yylval.string = text;
+ BEGIN(INITIAL);
+}
+
+
+/*
+ * Try to open specified file with following names:
+ * ./name
+ * $(srctree)/name
+ * The latter is used when srctree is separate from objtree
+ * when compiling the kernel.
+ * Return NULL if file is not found.
+ */
+FILE *zconf_fopen(const char *name)
+{
+ char *env, fullname[PATH_MAX+1];
+ FILE *f;
+
+ f = fopen(name, "r");
+ if (!f && name != NULL && name[0] != '/') {
+ env = getenv(SRCTREE);
+ if (env) {
+ snprintf(fullname, sizeof(fullname),
+ "%s/%s", env, name);
+ f = fopen(fullname, "r");
+ }
+ }
+ return f;
+}
+
+void zconf_initscan(const char *name)
+{
+ yyin = zconf_fopen(name);
+ if (!yyin) {
+ fprintf(stderr, "can't find file %s\n", name);
+ exit(1);
+ }
+
+ current_buf = xmalloc(sizeof(*current_buf));
+ memset(current_buf, 0, sizeof(*current_buf));
+
+ current_file = file_lookup(name);
+ yylineno = 1;
+}
+
+void zconf_nextfile(const char *name)
+{
+ struct file *iter;
+ struct file *file = file_lookup(name);
+ struct buffer *buf = xmalloc(sizeof(*buf));
+ memset(buf, 0, sizeof(*buf));
+
+ current_buf->state = YY_CURRENT_BUFFER;
+ yyin = zconf_fopen(file->name);
+ if (!yyin) {
+ fprintf(stderr, "%s:%d: can't open file \"%s\"\n",
+ zconf_curname(), zconf_lineno(), file->name);
+ exit(1);
+ }
+ yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE));
+ buf->parent = current_buf;
+ current_buf = buf;
+
+ current_file->lineno = yylineno;
+ file->parent = current_file;
+
+ for (iter = current_file; iter; iter = iter->parent) {
+ if (!strcmp(iter->name, file->name)) {
+ fprintf(stderr,
+ "Recursive inclusion detected.\n"
+ "Inclusion path:\n"
+ " current file : %s\n", file->name);
+ iter = file;
+ do {
+ iter = iter->parent;
+ fprintf(stderr, " included from: %s:%d\n",
+ iter->name, iter->lineno - 1);
+ } while (strcmp(iter->name, file->name));
+ exit(1);
+ }
+ }
+
+ yylineno = 1;
+ current_file = file;
+}
+
+static void zconf_endfile(void)
+{
+ struct buffer *parent;
+
+ current_file = current_file->parent;
+ if (current_file)
+ yylineno = current_file->lineno;
+
+ parent = current_buf->parent;
+ if (parent) {
+ fclose(yyin);
+ yy_delete_buffer(YY_CURRENT_BUFFER);
+ yy_switch_to_buffer(parent->state);
+ }
+ free(current_buf);
+ current_buf = parent;
+}
+
+int zconf_lineno(void)
+{
+ return current_pos.lineno;
+}
+
+const char *zconf_curname(void)
+{
+ return current_pos.file ? current_pos.file->name : "<none>";
+}
Index: Baikal/M1000/create-6.1.63-6.4.92-host-limits-patch/linux-m1-6.1.63-6.4.92-new/scripts/mod/modpost.c
===================================================================
--- Baikal/M1000/create-6.1.63-6.4.92-host-limits-patch/linux-m1-6.1.63-6.4.92-new/scripts/mod/modpost.c (nonexistent)
+++ Baikal/M1000/create-6.1.63-6.4.92-host-limits-patch/linux-m1-6.1.63-6.4.92-new/scripts/mod/modpost.c (revision 385)
@@ -0,0 +1,2371 @@
+/* Postprocess module symbol versions
+ *
+ * Copyright 2003 Kai Germaschewski
+ * Copyright 2002-2004 Rusty Russell, IBM Corporation
+ * Copyright 2006-2008 Sam Ravnborg
+ * Based in part on module-init-tools/depmod.c,file2alias
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ *
+ * Usage: modpost vmlinux module1.o module2.o ...
+ */
+
+#define _GNU_SOURCE
+#include <elf.h>
+#include <fnmatch.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <linux/limits.h>
+#include <stdbool.h>
+#include <errno.h>
+#include "modpost.h"
+#include "../../include/linux/license.h"
+
+/* Are we using CONFIG_MODVERSIONS? */
+static bool modversions;
+/* Is CONFIG_MODULE_SRCVERSION_ALL set? */
+static bool all_versions;
+/* If we are modposting external module set to 1 */
+static bool external_module;
+/* Only warn about unresolved symbols */
+static bool warn_unresolved;
+
+static int sec_mismatch_count;
+static bool sec_mismatch_warn_only = true;
+/* ignore missing files */
+static bool ignore_missing_files;
+/* If set to 1, only warn (instead of error) about missing ns imports */
+static bool allow_missing_ns_imports;
+
+static bool error_occurred;
+
+/*
+ * Cut off the warnings when there are too many. This typically occurs when
+ * vmlinux is missing. ('make modules' without building vmlinux.)
+ */
+#define MAX_UNRESOLVED_REPORTS 10
+static unsigned int nr_unresolved;
+
+/* In kernel, this size is defined in linux/module.h;
+ * here we use Elf_Addr instead of long for covering cross-compile
+ */
+
+#define MODULE_NAME_LEN (64 - sizeof(Elf_Addr))
+
+void __attribute__((format(printf, 2, 3)))
+modpost_log(enum loglevel loglevel, const char *fmt, ...)
+{
+ va_list arglist;
+
+ switch (loglevel) {
+ case LOG_WARN:
+ fprintf(stderr, "WARNING: ");
+ break;
+ case LOG_ERROR:
+ fprintf(stderr, "ERROR: ");
+ break;
+ case LOG_FATAL:
+ fprintf(stderr, "FATAL: ");
+ break;
+ default: /* invalid loglevel, ignore */
+ break;
+ }
+
+ fprintf(stderr, "modpost: ");
+
+ va_start(arglist, fmt);
+ vfprintf(stderr, fmt, arglist);
+ va_end(arglist);
+
+ if (loglevel == LOG_FATAL)
+ exit(1);
+ if (loglevel == LOG_ERROR)
+ error_occurred = true;
+}
+
+static inline bool strends(const char *str, const char *postfix)
+{
+ if (strlen(str) < strlen(postfix))
+ return false;
+
+ return strcmp(str + strlen(str) - strlen(postfix), postfix) == 0;
+}
+
+void *do_nofail(void *ptr, const char *expr)
+{
+ if (!ptr)
+ fatal("Memory allocation failure: %s.\n", expr);
+
+ return ptr;
+}
+
+char *read_text_file(const char *filename)
+{
+ struct stat st;
+ size_t nbytes;
+ int fd;
+ char *buf;
+
+ fd = open(filename, O_RDONLY);
+ if (fd < 0) {
+ perror(filename);
+ exit(1);
+ }
+
+ if (fstat(fd, &st) < 0) {
+ perror(filename);
+ exit(1);
+ }
+
+ buf = NOFAIL(malloc(st.st_size + 1));
+
+ nbytes = st.st_size;
+
+ while (nbytes) {
+ ssize_t bytes_read;
+
+ bytes_read = read(fd, buf, nbytes);
+ if (bytes_read < 0) {
+ perror(filename);
+ exit(1);
+ }
+
+ nbytes -= bytes_read;
+ }
+ buf[st.st_size] = '\0';
+
+ close(fd);
+
+ return buf;
+}
+
+char *get_line(char **stringp)
+{
+ char *orig = *stringp, *next;
+
+ /* do not return the unwanted extra line at EOF */
+ if (!orig || *orig == '\0')
+ return NULL;
+
+ /* don't use strsep here, it is not available everywhere */
+ next = strchr(orig, '\n');
+ if (next)
+ *next++ = '\0';
+
+ *stringp = next;
+
+ return orig;
+}
+
+/* A list of all modules we processed */
+LIST_HEAD(modules);
+
+static struct module *find_module(const char *modname)
+{
+ struct module *mod;
+
+ list_for_each_entry(mod, &modules, list) {
+ if (strcmp(mod->name, modname) == 0)
+ return mod;
+ }
+ return NULL;
+}
+
+static struct module *new_module(const char *name, size_t namelen)
+{
+ struct module *mod;
+
+ mod = NOFAIL(malloc(sizeof(*mod) + namelen + 1));
+ memset(mod, 0, sizeof(*mod));
+
+ INIT_LIST_HEAD(&mod->exported_symbols);
+ INIT_LIST_HEAD(&mod->unresolved_symbols);
+ INIT_LIST_HEAD(&mod->missing_namespaces);
+ INIT_LIST_HEAD(&mod->imported_namespaces);
+
+ memcpy(mod->name, name, namelen);
+ mod->name[namelen] = '\0';
+ mod->is_vmlinux = (strcmp(mod->name, "vmlinux") == 0);
+
+ /*
+ * Set mod->is_gpl_compatible to true by default. If MODULE_LICENSE()
+ * is missing, do not check the use for EXPORT_SYMBOL_GPL() becasue
+ * modpost will exit wiht error anyway.
+ */
+ mod->is_gpl_compatible = true;
+
+ list_add_tail(&mod->list, &modules);
+
+ return mod;
+}
+
+/* A hash of all exported symbols,
+ * struct symbol is also used for lists of unresolved symbols */
+
+#define SYMBOL_HASH_SIZE 1024
+
+struct symbol {
+ struct symbol *next;
+ struct list_head list; /* link to module::exported_symbols or module::unresolved_symbols */
+ struct module *module;
+ char *namespace;
+ unsigned int crc;
+ bool crc_valid;
+ bool weak;
+ bool is_gpl_only; /* exported by EXPORT_SYMBOL_GPL */
+ char name[];
+};
+
+static struct symbol *symbolhash[SYMBOL_HASH_SIZE];
+
+/* This is based on the hash algorithm from gdbm, via tdb */
+static inline unsigned int tdb_hash(const char *name)
+{
+ unsigned value; /* Used to compute the hash value. */
+ unsigned i; /* Used to cycle through random values. */
+
+ /* Set the initial value from the key size. */
+ for (value = 0x238F13AF * strlen(name), i = 0; name[i]; i++)
+ value = (value + (((unsigned char *)name)[i] << (i*5 % 24)));
+
+ return (1103515243 * value + 12345);
+}
+
+/**
+ * Allocate a new symbols for use in the hash of exported symbols or
+ * the list of unresolved symbols per module
+ **/
+static struct symbol *alloc_symbol(const char *name)
+{
+ struct symbol *s = NOFAIL(malloc(sizeof(*s) + strlen(name) + 1));
+
+ memset(s, 0, sizeof(*s));
+ strcpy(s->name, name);
+
+ return s;
+}
+
+/* For the hash of exported symbols */
+static void hash_add_symbol(struct symbol *sym)
+{
+ unsigned int hash;
+
+ hash = tdb_hash(sym->name) % SYMBOL_HASH_SIZE;
+ sym->next = symbolhash[hash];
+ symbolhash[hash] = sym;
+}
+
+static void sym_add_unresolved(const char *name, struct module *mod, bool weak)
+{
+ struct symbol *sym;
+
+ sym = alloc_symbol(name);
+ sym->weak = weak;
+
+ list_add_tail(&sym->list, &mod->unresolved_symbols);
+}
+
+static struct symbol *sym_find_with_module(const char *name, struct module *mod)
+{
+ struct symbol *s;
+
+ /* For our purposes, .foo matches foo. PPC64 needs this. */
+ if (name[0] == '.')
+ name++;
+
+ for (s = symbolhash[tdb_hash(name) % SYMBOL_HASH_SIZE]; s; s = s->next) {
+ if (strcmp(s->name, name) == 0 && (!mod || s->module == mod))
+ return s;
+ }
+ return NULL;
+}
+
+static struct symbol *find_symbol(const char *name)
+{
+ return sym_find_with_module(name, NULL);
+}
+
+struct namespace_list {
+ struct list_head list;
+ char namespace[];
+};
+
+static bool contains_namespace(struct list_head *head, const char *namespace)
+{
+ struct namespace_list *list;
+
+ list_for_each_entry(list, head, list) {
+ if (!strcmp(list->namespace, namespace))
+ return true;
+ }
+
+ return false;
+}
+
+static void add_namespace(struct list_head *head, const char *namespace)
+{
+ struct namespace_list *ns_entry;
+
+ if (!contains_namespace(head, namespace)) {
+ ns_entry = NOFAIL(malloc(sizeof(*ns_entry) +
+ strlen(namespace) + 1));
+ strcpy(ns_entry->namespace, namespace);
+ list_add_tail(&ns_entry->list, head);
+ }
+}
+
+static void *sym_get_data_by_offset(const struct elf_info *info,
+ unsigned int secindex, unsigned long offset)
+{
+ Elf_Shdr *sechdr = &info->sechdrs[secindex];
+
+ return (void *)info->hdr + sechdr->sh_offset + offset;
+}
+
+void *sym_get_data(const struct elf_info *info, const Elf_Sym *sym)
+{
+ return sym_get_data_by_offset(info, get_secindex(info, sym),
+ sym->st_value);
+}
+
+static const char *sech_name(const struct elf_info *info, Elf_Shdr *sechdr)
+{
+ return sym_get_data_by_offset(info, info->secindex_strings,
+ sechdr->sh_name);
+}
+
+static const char *sec_name(const struct elf_info *info, unsigned int secindex)
+{
+ /*
+ * If sym->st_shndx is a special section index, there is no
+ * corresponding section header.
+ * Return "" if the index is out of range of info->sechdrs[] array.
+ */
+ if (secindex >= info->num_sections)
+ return "";
+
+ return sech_name(info, &info->sechdrs[secindex]);
+}
+
+#define strstarts(str, prefix) (strncmp(str, prefix, strlen(prefix)) == 0)
+
+static void sym_update_namespace(const char *symname, const char *namespace)
+{
+ struct symbol *s = find_symbol(symname);
+
+ /*
+ * That symbol should have been created earlier and thus this is
+ * actually an assertion.
+ */
+ if (!s) {
+ error("Could not update namespace(%s) for symbol %s\n",
+ namespace, symname);
+ return;
+ }
+
+ free(s->namespace);
+ s->namespace = namespace[0] ? NOFAIL(strdup(namespace)) : NULL;
+}
+
+static struct symbol *sym_add_exported(const char *name, struct module *mod,
+ bool gpl_only)
+{
+ struct symbol *s = find_symbol(name);
+
+ if (s && (!external_module || s->module->is_vmlinux || s->module == mod)) {
+ error("%s: '%s' exported twice. Previous export was in %s%s\n",
+ mod->name, name, s->module->name,
+ s->module->is_vmlinux ? "" : ".ko");
+ }
+
+ s = alloc_symbol(name);
+ s->module = mod;
+ s->is_gpl_only = gpl_only;
+ list_add_tail(&s->list, &mod->exported_symbols);
+ hash_add_symbol(s);
+
+ return s;
+}
+
+static void sym_set_crc(struct symbol *sym, unsigned int crc)
+{
+ sym->crc = crc;
+ sym->crc_valid = true;
+}
+
+static void *grab_file(const char *filename, size_t *size)
+{
+ struct stat st;
+ void *map = MAP_FAILED;
+ int fd;
+
+ fd = open(filename, O_RDONLY);
+ if (fd < 0)
+ return NULL;
+ if (fstat(fd, &st))
+ goto failed;
+
+ *size = st.st_size;
+ map = mmap(NULL, *size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
+
+failed:
+ close(fd);
+ if (map == MAP_FAILED)
+ return NULL;
+ return map;
+}
+
+static void release_file(void *file, size_t size)
+{
+ munmap(file, size);
+}
+
+static int parse_elf(struct elf_info *info, const char *filename)
+{
+ unsigned int i;
+ Elf_Ehdr *hdr;
+ Elf_Shdr *sechdrs;
+ Elf_Sym *sym;
+ const char *secstrings;
+ unsigned int symtab_idx = ~0U, symtab_shndx_idx = ~0U;
+
+ hdr = grab_file(filename, &info->size);
+ if (!hdr) {
+ if (ignore_missing_files) {
+ fprintf(stderr, "%s: %s (ignored)\n", filename,
+ strerror(errno));
+ return 0;
+ }
+ perror(filename);
+ exit(1);
+ }
+ info->hdr = hdr;
+ if (info->size < sizeof(*hdr)) {
+ /* file too small, assume this is an empty .o file */
+ return 0;
+ }
+ /* Is this a valid ELF file? */
+ if ((hdr->e_ident[EI_MAG0] != ELFMAG0) ||
+ (hdr->e_ident[EI_MAG1] != ELFMAG1) ||
+ (hdr->e_ident[EI_MAG2] != ELFMAG2) ||
+ (hdr->e_ident[EI_MAG3] != ELFMAG3)) {
+ /* Not an ELF file - silently ignore it */
+ return 0;
+ }
+ /* Fix endianness in ELF header */
+ hdr->e_type = TO_NATIVE(hdr->e_type);
+ hdr->e_machine = TO_NATIVE(hdr->e_machine);
+ hdr->e_version = TO_NATIVE(hdr->e_version);
+ hdr->e_entry = TO_NATIVE(hdr->e_entry);
+ hdr->e_phoff = TO_NATIVE(hdr->e_phoff);
+ hdr->e_shoff = TO_NATIVE(hdr->e_shoff);
+ hdr->e_flags = TO_NATIVE(hdr->e_flags);
+ hdr->e_ehsize = TO_NATIVE(hdr->e_ehsize);
+ hdr->e_phentsize = TO_NATIVE(hdr->e_phentsize);
+ hdr->e_phnum = TO_NATIVE(hdr->e_phnum);
+ hdr->e_shentsize = TO_NATIVE(hdr->e_shentsize);
+ hdr->e_shnum = TO_NATIVE(hdr->e_shnum);
+ hdr->e_shstrndx = TO_NATIVE(hdr->e_shstrndx);
+ sechdrs = (void *)hdr + hdr->e_shoff;
+ info->sechdrs = sechdrs;
+
+ /* modpost only works for relocatable objects */
+ if (hdr->e_type != ET_REL)
+ fatal("%s: not relocatable object.", filename);
+
+ /* Check if file offset is correct */
+ if (hdr->e_shoff > info->size) {
+ fatal("section header offset=%lu in file '%s' is bigger than filesize=%zu\n",
+ (unsigned long)hdr->e_shoff, filename, info->size);
+ return 0;
+ }
+
+ if (hdr->e_shnum == SHN_UNDEF) {
+ /*
+ * There are more than 64k sections,
+ * read count from .sh_size.
+ */
+ info->num_sections = TO_NATIVE(sechdrs[0].sh_size);
+ }
+ else {
+ info->num_sections = hdr->e_shnum;
+ }
+ if (hdr->e_shstrndx == SHN_XINDEX) {
+ info->secindex_strings = TO_NATIVE(sechdrs[0].sh_link);
+ }
+ else {
+ info->secindex_strings = hdr->e_shstrndx;
+ }
+
+ /* Fix endianness in section headers */
+ for (i = 0; i < info->num_sections; i++) {
+ sechdrs[i].sh_name = TO_NATIVE(sechdrs[i].sh_name);
+ sechdrs[i].sh_type = TO_NATIVE(sechdrs[i].sh_type);
+ sechdrs[i].sh_flags = TO_NATIVE(sechdrs[i].sh_flags);
+ sechdrs[i].sh_addr = TO_NATIVE(sechdrs[i].sh_addr);
+ sechdrs[i].sh_offset = TO_NATIVE(sechdrs[i].sh_offset);
+ sechdrs[i].sh_size = TO_NATIVE(sechdrs[i].sh_size);
+ sechdrs[i].sh_link = TO_NATIVE(sechdrs[i].sh_link);
+ sechdrs[i].sh_info = TO_NATIVE(sechdrs[i].sh_info);
+ sechdrs[i].sh_addralign = TO_NATIVE(sechdrs[i].sh_addralign);
+ sechdrs[i].sh_entsize = TO_NATIVE(sechdrs[i].sh_entsize);
+ }
+ /* Find symbol table. */
+ secstrings = (void *)hdr + sechdrs[info->secindex_strings].sh_offset;
+ for (i = 1; i < info->num_sections; i++) {
+ const char *secname;
+ int nobits = sechdrs[i].sh_type == SHT_NOBITS;
+
+ if (!nobits && sechdrs[i].sh_offset > info->size) {
+ fatal("%s is truncated. sechdrs[i].sh_offset=%lu > "
+ "sizeof(*hrd)=%zu\n", filename,
+ (unsigned long)sechdrs[i].sh_offset,
+ sizeof(*hdr));
+ return 0;
+ }
+ secname = secstrings + sechdrs[i].sh_name;
+ if (strcmp(secname, ".modinfo") == 0) {
+ if (nobits)
+ fatal("%s has NOBITS .modinfo\n", filename);
+ info->modinfo = (void *)hdr + sechdrs[i].sh_offset;
+ info->modinfo_len = sechdrs[i].sh_size;
+ }
+
+ if (sechdrs[i].sh_type == SHT_SYMTAB) {
+ unsigned int sh_link_idx;
+ symtab_idx = i;
+ info->symtab_start = (void *)hdr +
+ sechdrs[i].sh_offset;
+ info->symtab_stop = (void *)hdr +
+ sechdrs[i].sh_offset + sechdrs[i].sh_size;
+ sh_link_idx = sechdrs[i].sh_link;
+ info->strtab = (void *)hdr +
+ sechdrs[sh_link_idx].sh_offset;
+ }
+
+ /* 32bit section no. table? ("more than 64k sections") */
+ if (sechdrs[i].sh_type == SHT_SYMTAB_SHNDX) {
+ symtab_shndx_idx = i;
+ info->symtab_shndx_start = (void *)hdr +
+ sechdrs[i].sh_offset;
+ info->symtab_shndx_stop = (void *)hdr +
+ sechdrs[i].sh_offset + sechdrs[i].sh_size;
+ }
+ }
+ if (!info->symtab_start)
+ fatal("%s has no symtab?\n", filename);
+
+ /* Fix endianness in symbols */
+ for (sym = info->symtab_start; sym < info->symtab_stop; sym++) {
+ sym->st_shndx = TO_NATIVE(sym->st_shndx);
+ sym->st_name = TO_NATIVE(sym->st_name);
+ sym->st_value = TO_NATIVE(sym->st_value);
+ sym->st_size = TO_NATIVE(sym->st_size);
+ }
+
+ if (symtab_shndx_idx != ~0U) {
+ Elf32_Word *p;
+ if (symtab_idx != sechdrs[symtab_shndx_idx].sh_link)
+ fatal("%s: SYMTAB_SHNDX has bad sh_link: %u!=%u\n",
+ filename, sechdrs[symtab_shndx_idx].sh_link,
+ symtab_idx);
+ /* Fix endianness */
+ for (p = info->symtab_shndx_start; p < info->symtab_shndx_stop;
+ p++)
+ *p = TO_NATIVE(*p);
+ }
+
+ return 1;
+}
+
+static void parse_elf_finish(struct elf_info *info)
+{
+ release_file(info->hdr, info->size);
+}
+
+static int ignore_undef_symbol(struct elf_info *info, const char *symname)
+{
+ /* ignore __this_module, it will be resolved shortly */
+ if (strcmp(symname, "__this_module") == 0)
+ return 1;
+ /* ignore global offset table */
+ if (strcmp(symname, "_GLOBAL_OFFSET_TABLE_") == 0)
+ return 1;
+ if (info->hdr->e_machine == EM_PPC)
+ /* Special register function linked on all modules during final link of .ko */
+ if (strstarts(symname, "_restgpr_") ||
+ strstarts(symname, "_savegpr_") ||
+ strstarts(symname, "_rest32gpr_") ||
+ strstarts(symname, "_save32gpr_") ||
+ strstarts(symname, "_restvr_") ||
+ strstarts(symname, "_savevr_"))
+ return 1;
+ if (info->hdr->e_machine == EM_PPC64)
+ /* Special register function linked on all modules during final link of .ko */
+ if (strstarts(symname, "_restgpr0_") ||
+ strstarts(symname, "_savegpr0_") ||
+ strstarts(symname, "_restvr_") ||
+ strstarts(symname, "_savevr_") ||
+ strcmp(symname, ".TOC.") == 0)
+ return 1;
+
+ if (info->hdr->e_machine == EM_S390)
+ /* Expoline thunks are linked on all kernel modules during final link of .ko */
+ if (strstarts(symname, "__s390_indirect_jump_r"))
+ return 1;
+ /* Do not ignore this symbol */
+ return 0;
+}
+
+static void handle_symbol(struct module *mod, struct elf_info *info,
+ const Elf_Sym *sym, const char *symname)
+{
+ switch (sym->st_shndx) {
+ case SHN_COMMON:
+ if (strstarts(symname, "__gnu_lto_")) {
+ /* Should warn here, but modpost runs before the linker */
+ } else
+ warn("\"%s\" [%s] is COMMON symbol\n", symname, mod->name);
+ break;
+ case SHN_UNDEF:
+ /* undefined symbol */
+ if (ELF_ST_BIND(sym->st_info) != STB_GLOBAL &&
+ ELF_ST_BIND(sym->st_info) != STB_WEAK)
+ break;
+ if (ignore_undef_symbol(info, symname))
+ break;
+ if (info->hdr->e_machine == EM_SPARC ||
+ info->hdr->e_machine == EM_SPARCV9) {
+ /* Ignore register directives. */
+ if (ELF_ST_TYPE(sym->st_info) == STT_SPARC_REGISTER)
+ break;
+ if (symname[0] == '.') {
+ char *munged = NOFAIL(strdup(symname));
+ munged[0] = '_';
+ munged[1] = toupper(munged[1]);
+ symname = munged;
+ }
+ }
+
+ sym_add_unresolved(symname, mod,
+ ELF_ST_BIND(sym->st_info) == STB_WEAK);
+ break;
+ default:
+ /* All exported symbols */
+ if (strstarts(symname, "__ksymtab_")) {
+ const char *name, *secname;
+
+ name = symname + strlen("__ksymtab_");
+ secname = sec_name(info, get_secindex(info, sym));
+
+ if (strstarts(secname, "___ksymtab_gpl+"))
+ sym_add_exported(name, mod, true);
+ else if (strstarts(secname, "___ksymtab+"))
+ sym_add_exported(name, mod, false);
+ }
+ if (strcmp(symname, "init_module") == 0)
+ mod->has_init = true;
+ if (strcmp(symname, "cleanup_module") == 0)
+ mod->has_cleanup = true;
+ break;
+ }
+}
+
+/**
+ * Parse tag=value strings from .modinfo section
+ **/
+static char *next_string(char *string, unsigned long *secsize)
+{
+ /* Skip non-zero chars */
+ while (string[0]) {
+ string++;
+ if ((*secsize)-- <= 1)
+ return NULL;
+ }
+
+ /* Skip any zero padding. */
+ while (!string[0]) {
+ string++;
+ if ((*secsize)-- <= 1)
+ return NULL;
+ }
+ return string;
+}
+
+static char *get_next_modinfo(struct elf_info *info, const char *tag,
+ char *prev)
+{
+ char *p;
+ unsigned int taglen = strlen(tag);
+ char *modinfo = info->modinfo;
+ unsigned long size = info->modinfo_len;
+
+ if (prev) {
+ size -= prev - modinfo;
+ modinfo = next_string(prev, &size);
+ }
+
+ for (p = modinfo; p; p = next_string(p, &size)) {
+ if (strncmp(p, tag, taglen) == 0 && p[taglen] == '=')
+ return p + taglen + 1;
+ }
+ return NULL;
+}
+
+static char *get_modinfo(struct elf_info *info, const char *tag)
+
+{
+ return get_next_modinfo(info, tag, NULL);
+}
+
+static const char *sym_name(struct elf_info *elf, Elf_Sym *sym)
+{
+ if (sym)
+ return elf->strtab + sym->st_name;
+ else
+ return "(unknown)";
+}
+
+/*
+ * Check whether the 'string' argument matches one of the 'patterns',
+ * an array of shell wildcard patterns (glob).
+ *
+ * Return true is there is a match.
+ */
+static bool match(const char *string, const char *const patterns[])
+{
+ const char *pattern;
+
+ while ((pattern = *patterns++)) {
+ if (!fnmatch(pattern, string, 0))
+ return true;
+ }
+
+ return false;
+}
+
+/* useful to pass patterns to match() directly */
+#define PATTERNS(...) \
+ ({ \
+ static const char *const patterns[] = {__VA_ARGS__, NULL}; \
+ patterns; \
+ })
+
+/* sections that we do not want to do full section mismatch check on */
+static const char *const section_white_list[] =
+{
+ ".comment*",
+ ".debug*",
+ ".zdebug*", /* Compressed debug sections. */
+ ".GCC.command.line", /* record-gcc-switches */
+ ".mdebug*", /* alpha, score, mips etc. */
+ ".pdr", /* alpha, score, mips etc. */
+ ".stab*",
+ ".note*",
+ ".got*",
+ ".toc*",
+ ".xt.prop", /* xtensa */
+ ".xt.lit", /* xtensa */
+ ".arcextmap*", /* arc */
+ ".gnu.linkonce.arcext*", /* arc : modules */
+ ".cmem*", /* EZchip */
+ ".fmt_slot*", /* EZchip */
+ ".gnu.lto*",
+ ".discard.*",
+ NULL
+};
+
+/*
+ * This is used to find sections missing the SHF_ALLOC flag.
+ * The cause of this is often a section specified in assembler
+ * without "ax" / "aw".
+ */
+static void check_section(const char *modname, struct elf_info *elf,
+ Elf_Shdr *sechdr)
+{
+ const char *sec = sech_name(elf, sechdr);
+
+ if (sechdr->sh_type == SHT_PROGBITS &&
+ !(sechdr->sh_flags & SHF_ALLOC) &&
+ !match(sec, section_white_list)) {
+ warn("%s (%s): unexpected non-allocatable section.\n"
+ "Did you forget to use \"ax\"/\"aw\" in a .S file?\n"
+ "Note that for example <linux/init.h> contains\n"
+ "section definitions for use in .S files.\n\n",
+ modname, sec);
+ }
+}
+
+
+
+#define ALL_INIT_DATA_SECTIONS \
+ ".init.setup", ".init.rodata", ".meminit.rodata", \
+ ".init.data", ".meminit.data"
+#define ALL_EXIT_DATA_SECTIONS \
+ ".exit.data", ".memexit.data"
+
+#define ALL_INIT_TEXT_SECTIONS \
+ ".init.text", ".meminit.text"
+#define ALL_EXIT_TEXT_SECTIONS \
+ ".exit.text", ".memexit.text"
+
+#define ALL_PCI_INIT_SECTIONS \
+ ".pci_fixup_early", ".pci_fixup_header", ".pci_fixup_final", \
+ ".pci_fixup_enable", ".pci_fixup_resume", \
+ ".pci_fixup_resume_early", ".pci_fixup_suspend"
+
+#define ALL_XXXINIT_SECTIONS MEM_INIT_SECTIONS
+#define ALL_XXXEXIT_SECTIONS MEM_EXIT_SECTIONS
+
+#define ALL_INIT_SECTIONS INIT_SECTIONS, ALL_XXXINIT_SECTIONS
+#define ALL_EXIT_SECTIONS EXIT_SECTIONS, ALL_XXXEXIT_SECTIONS
+
+#define DATA_SECTIONS ".data", ".data.rel"
+#define TEXT_SECTIONS ".text", ".text.unlikely", ".sched.text", \
+ ".kprobes.text", ".cpuidle.text", ".noinstr.text"
+#define OTHER_TEXT_SECTIONS ".ref.text", ".head.text", ".spinlock.text", \
+ ".fixup", ".entry.text", ".exception.text", ".text.*", \
+ ".coldtext", ".softirqentry.text"
+
+#define INIT_SECTIONS ".init.*"
+#define MEM_INIT_SECTIONS ".meminit.*"
+
+#define EXIT_SECTIONS ".exit.*"
+#define MEM_EXIT_SECTIONS ".memexit.*"
+
+#define ALL_TEXT_SECTIONS ALL_INIT_TEXT_SECTIONS, ALL_EXIT_TEXT_SECTIONS, \
+ TEXT_SECTIONS, OTHER_TEXT_SECTIONS
+
+/* init data sections */
+static const char *const init_data_sections[] =
+ { ALL_INIT_DATA_SECTIONS, NULL };
+
+/* all init sections */
+static const char *const init_sections[] = { ALL_INIT_SECTIONS, NULL };
+
+/* all text sections */
+static const char *const text_sections[] = { ALL_TEXT_SECTIONS, NULL };
+
+/* data section */
+static const char *const data_sections[] = { DATA_SECTIONS, NULL };
+
+static const char *const head_sections[] = { ".head.text*", NULL };
+static const char *const linker_symbols[] =
+ { "__init_begin", "_sinittext", "_einittext", NULL };
+static const char *const optim_symbols[] = { "*.constprop.*", NULL };
+
+enum mismatch {
+ TEXT_TO_ANY_INIT,
+ DATA_TO_ANY_INIT,
+ TEXT_TO_ANY_EXIT,
+ DATA_TO_ANY_EXIT,
+ XXXINIT_TO_SOME_INIT,
+ XXXEXIT_TO_SOME_EXIT,
+ ANY_INIT_TO_ANY_EXIT,
+ ANY_EXIT_TO_ANY_INIT,
+ EXPORT_TO_INIT_EXIT,
+ EXTABLE_TO_NON_TEXT,
+};
+
+/**
+ * Describe how to match sections on different criteria:
+ *
+ * @fromsec: Array of sections to be matched.
+ *
+ * @bad_tosec: Relocations applied to a section in @fromsec to a section in
+ * this array is forbidden (black-list). Can be empty.
+ *
+ * @good_tosec: Relocations applied to a section in @fromsec must be
+ * targeting sections in this array (white-list). Can be empty.
+ *
+ * @mismatch: Type of mismatch.
+ *
+ * @handler: Specific handler to call when a match is found. If NULL,
+ * default_mismatch_handler() will be called.
+ *
+ */
+struct sectioncheck {
+ const char *fromsec[20];
+ const char *bad_tosec[20];
+ const char *good_tosec[20];
+ enum mismatch mismatch;
+ void (*handler)(const char *modname, struct elf_info *elf,
+ const struct sectioncheck* const mismatch,
+ Elf_Rela *r, Elf_Sym *sym, const char *fromsec);
+
+};
+
+static void extable_mismatch_handler(const char *modname, struct elf_info *elf,
+ const struct sectioncheck* const mismatch,
+ Elf_Rela *r, Elf_Sym *sym,
+ const char *fromsec);
+
+static const struct sectioncheck sectioncheck[] = {
+/* Do not reference init/exit code/data from
+ * normal code and data
+ */
+{
+ .fromsec = { TEXT_SECTIONS, NULL },
+ .bad_tosec = { ALL_INIT_SECTIONS, NULL },
+ .mismatch = TEXT_TO_ANY_INIT,
+},
+{
+ .fromsec = { DATA_SECTIONS, NULL },
+ .bad_tosec = { ALL_XXXINIT_SECTIONS, NULL },
+ .mismatch = DATA_TO_ANY_INIT,
+},
+{
+ .fromsec = { DATA_SECTIONS, NULL },
+ .bad_tosec = { INIT_SECTIONS, NULL },
+ .mismatch = DATA_TO_ANY_INIT,
+},
+{
+ .fromsec = { TEXT_SECTIONS, NULL },
+ .bad_tosec = { ALL_EXIT_SECTIONS, NULL },
+ .mismatch = TEXT_TO_ANY_EXIT,
+},
+{
+ .fromsec = { DATA_SECTIONS, NULL },
+ .bad_tosec = { ALL_EXIT_SECTIONS, NULL },
+ .mismatch = DATA_TO_ANY_EXIT,
+},
+/* Do not reference init code/data from meminit code/data */
+{
+ .fromsec = { ALL_XXXINIT_SECTIONS, NULL },
+ .bad_tosec = { INIT_SECTIONS, NULL },
+ .mismatch = XXXINIT_TO_SOME_INIT,
+},
+/* Do not reference exit code/data from memexit code/data */
+{
+ .fromsec = { ALL_XXXEXIT_SECTIONS, NULL },
+ .bad_tosec = { EXIT_SECTIONS, NULL },
+ .mismatch = XXXEXIT_TO_SOME_EXIT,
+},
+/* Do not use exit code/data from init code */
+{
+ .fromsec = { ALL_INIT_SECTIONS, NULL },
+ .bad_tosec = { ALL_EXIT_SECTIONS, NULL },
+ .mismatch = ANY_INIT_TO_ANY_EXIT,
+},
+/* Do not use init code/data from exit code */
+{
+ .fromsec = { ALL_EXIT_SECTIONS, NULL },
+ .bad_tosec = { ALL_INIT_SECTIONS, NULL },
+ .mismatch = ANY_EXIT_TO_ANY_INIT,
+},
+{
+ .fromsec = { ALL_PCI_INIT_SECTIONS, NULL },
+ .bad_tosec = { INIT_SECTIONS, NULL },
+ .mismatch = ANY_INIT_TO_ANY_EXIT,
+},
+/* Do not export init/exit functions or data */
+{
+ .fromsec = { "___ksymtab*", NULL },
+ .bad_tosec = { INIT_SECTIONS, EXIT_SECTIONS, NULL },
+ .mismatch = EXPORT_TO_INIT_EXIT,
+},
+{
+ .fromsec = { "__ex_table", NULL },
+ /* If you're adding any new black-listed sections in here, consider
+ * adding a special 'printer' for them in scripts/check_extable.
+ */
+ .bad_tosec = { ".altinstr_replacement", NULL },
+ .good_tosec = {ALL_TEXT_SECTIONS , NULL},
+ .mismatch = EXTABLE_TO_NON_TEXT,
+ .handler = extable_mismatch_handler,
+}
+};
+
+static const struct sectioncheck *section_mismatch(
+ const char *fromsec, const char *tosec)
+{
+ int i;
+
+ /*
+ * The target section could be the SHT_NUL section when we're
+ * handling relocations to un-resolved symbols, trying to match it
+ * doesn't make much sense and causes build failures on parisc
+ * architectures.
+ */
+ if (*tosec == '\0')
+ return NULL;
+
+ for (i = 0; i < ARRAY_SIZE(sectioncheck); i++) {
+ const struct sectioncheck *check = §ioncheck[i];
+
+ if (match(fromsec, check->fromsec)) {
+ if (check->bad_tosec[0] && match(tosec, check->bad_tosec))
+ return check;
+ if (check->good_tosec[0] && !match(tosec, check->good_tosec))
+ return check;
+ }
+ }
+ return NULL;
+}
+
+/**
+ * Whitelist to allow certain references to pass with no warning.
+ *
+ * Pattern 1:
+ * If a module parameter is declared __initdata and permissions=0
+ * then this is legal despite the warning generated.
+ * We cannot see value of permissions here, so just ignore
+ * this pattern.
+ * The pattern is identified by:
+ * tosec = .init.data
+ * fromsec = .data*
+ * atsym =__param*
+ *
+ * Pattern 1a:
+ * module_param_call() ops can refer to __init set function if permissions=0
+ * The pattern is identified by:
+ * tosec = .init.text
+ * fromsec = .data*
+ * atsym = __param_ops_*
+ *
+ * Pattern 3:
+ * Whitelist all references from .head.text to any init section
+ *
+ * Pattern 4:
+ * Some symbols belong to init section but still it is ok to reference
+ * these from non-init sections as these symbols don't have any memory
+ * allocated for them and symbol address and value are same. So even
+ * if init section is freed, its ok to reference those symbols.
+ * For ex. symbols marking the init section boundaries.
+ * This pattern is identified by
+ * refsymname = __init_begin, _sinittext, _einittext
+ *
+ * Pattern 5:
+ * GCC may optimize static inlines when fed constant arg(s) resulting
+ * in functions like cpumask_empty() -- generating an associated symbol
+ * cpumask_empty.constprop.3 that appears in the audit. If the const that
+ * is passed in comes from __init, like say nmi_ipi_mask, we get a
+ * meaningless section warning. May need to add isra symbols too...
+ * This pattern is identified by
+ * tosec = init section
+ * fromsec = text section
+ * refsymname = *.constprop.*
+ *
+ * Pattern 6:
+ * Hide section mismatch warnings for ELF local symbols. The goal
+ * is to eliminate false positive modpost warnings caused by
+ * compiler-generated ELF local symbol names such as ".LANCHOR1".
+ * Autogenerated symbol names bypass modpost's "Pattern 2"
+ * whitelisting, which relies on pattern-matching against symbol
+ * names to work. (One situation where gcc can autogenerate ELF
+ * local symbols is when "-fsection-anchors" is used.)
+ **/
+static int secref_whitelist(const struct sectioncheck *mismatch,
+ const char *fromsec, const char *fromsym,
+ const char *tosec, const char *tosym)
+{
+ /* Check for pattern 1 */
+ if (match(tosec, init_data_sections) &&
+ match(fromsec, data_sections) &&
+ strstarts(fromsym, "__param"))
+ return 0;
+
+ /* Check for pattern 1a */
+ if (strcmp(tosec, ".init.text") == 0 &&
+ match(fromsec, data_sections) &&
+ strstarts(fromsym, "__param_ops_"))
+ return 0;
+
+ /* symbols in data sections that may refer to any init/exit sections */
+ if (match(fromsec, PATTERNS(DATA_SECTIONS)) &&
+ match(tosec, PATTERNS(ALL_INIT_SECTIONS, ALL_EXIT_SECTIONS)) &&
+ match(fromsym, PATTERNS("*_template", // scsi uses *_template a lot
+ "*_timer", // arm uses ops structures named _timer a lot
+ "*_sht", // scsi also used *_sht to some extent
+ "*_ops",
+ "*_probe",
+ "*_probe_one",
+ "*_console")))
+ return 0;
+
+ /* symbols in data sections that may refer to meminit/exit sections */
+ if (match(fromsec, PATTERNS(DATA_SECTIONS)) &&
+ match(tosec, PATTERNS(ALL_XXXINIT_SECTIONS, ALL_EXIT_SECTIONS)) &&
+ match(fromsym, PATTERNS("*driver")))
+ return 0;
+
+ /* Check for pattern 3 */
+ if (match(fromsec, head_sections) &&
+ match(tosec, init_sections))
+ return 0;
+
+ /* Check for pattern 4 */
+ if (match(tosym, linker_symbols))
+ return 0;
+
+ /* Check for pattern 5 */
+ if (match(fromsec, text_sections) &&
+ match(tosec, init_sections) &&
+ match(fromsym, optim_symbols))
+ return 0;
+
+ /* Check for pattern 6 */
+ if (strstarts(fromsym, ".L"))
+ return 0;
+
+ return 1;
+}
+
+static inline int is_arm_mapping_symbol(const char *str)
+{
+ return str[0] == '$' &&
+ (str[1] == 'a' || str[1] == 'd' || str[1] == 't' || str[1] == 'x')
+ && (str[2] == '\0' || str[2] == '.');
+}
+
+/*
+ * If there's no name there, ignore it; likewise, ignore it if it's
+ * one of the magic symbols emitted used by current ARM tools.
+ *
+ * Otherwise if find_symbols_between() returns those symbols, they'll
+ * fail the whitelist tests and cause lots of false alarms ... fixable
+ * only by merging __exit and __init sections into __text, bloating
+ * the kernel (which is especially evil on embedded platforms).
+ */
+static inline int is_valid_name(struct elf_info *elf, Elf_Sym *sym)
+{
+ const char *name = elf->strtab + sym->st_name;
+
+ if (!name || !strlen(name))
+ return 0;
+ return !is_arm_mapping_symbol(name);
+}
+
+/**
+ * Find symbol based on relocation record info.
+ * In some cases the symbol supplied is a valid symbol so
+ * return refsym. If st_name != 0 we assume this is a valid symbol.
+ * In other cases the symbol needs to be looked up in the symbol table
+ * based on section and address.
+ * **/
+static Elf_Sym *find_elf_symbol(struct elf_info *elf, Elf64_Sword addr,
+ Elf_Sym *relsym)
+{
+ Elf_Sym *sym;
+ Elf_Sym *near = NULL;
+ Elf64_Sword distance = 20;
+ Elf64_Sword d;
+ unsigned int relsym_secindex;
+
+ if (relsym->st_name != 0)
+ return relsym;
+
+ /*
+ * Strive to find a better symbol name, but the resulting name may not
+ * match the symbol referenced in the original code.
+ */
+ relsym_secindex = get_secindex(elf, relsym);
+ for (sym = elf->symtab_start; sym < elf->symtab_stop; sym++) {
+ if (get_secindex(elf, sym) != relsym_secindex)
+ continue;
+ if (ELF_ST_TYPE(sym->st_info) == STT_SECTION)
+ continue;
+ if (!is_valid_name(elf, sym))
+ continue;
+ if (sym->st_value == addr)
+ return sym;
+ /* Find a symbol nearby - addr are maybe negative */
+ d = sym->st_value - addr;
+ if (d < 0)
+ d = addr - sym->st_value;
+ if (d < distance) {
+ distance = d;
+ near = sym;
+ }
+ }
+ /* We need a close match */
+ if (distance < 20)
+ return near;
+ else
+ return NULL;
+}
+
+/*
+ * Find symbols before or equal addr and after addr - in the section sec.
+ * If we find two symbols with equal offset prefer one with a valid name.
+ * The ELF format may have a better way to detect what type of symbol
+ * it is, but this works for now.
+ **/
+static Elf_Sym *find_elf_symbol2(struct elf_info *elf, Elf_Addr addr,
+ const char *sec)
+{
+ Elf_Sym *sym;
+ Elf_Sym *near = NULL;
+ Elf_Addr distance = ~0;
+
+ for (sym = elf->symtab_start; sym < elf->symtab_stop; sym++) {
+ const char *symsec;
+
+ if (is_shndx_special(sym->st_shndx))
+ continue;
+ symsec = sec_name(elf, get_secindex(elf, sym));
+ if (strcmp(symsec, sec) != 0)
+ continue;
+ if (!is_valid_name(elf, sym))
+ continue;
+ if (sym->st_value <= addr && addr - sym->st_value <= distance) {
+ distance = addr - sym->st_value;
+ near = sym;
+ }
+ }
+ return near;
+}
+
+static int is_function(Elf_Sym *sym)
+{
+ if (sym)
+ return ELF_ST_TYPE(sym->st_info) == STT_FUNC;
+ else
+ return -1;
+}
+
+static inline void get_pretty_name(int is_func, const char** name, const char** name_p)
+{
+ switch (is_func) {
+ case 0: *name = "variable"; *name_p = ""; break;
+ case 1: *name = "function"; *name_p = "()"; break;
+ default: *name = "(unknown reference)"; *name_p = ""; break;
+ }
+}
+
+/*
+ * Print a warning about a section mismatch.
+ * Try to find symbols near it so user can find it.
+ * Check whitelist before warning - it may be a false positive.
+ */
+static void report_sec_mismatch(const char *modname,
+ const struct sectioncheck *mismatch,
+ const char *fromsec,
+ const char *fromsym,
+ const char *tosec, const char *tosym)
+{
+ sec_mismatch_count++;
+
+ switch (mismatch->mismatch) {
+ case TEXT_TO_ANY_INIT:
+ case DATA_TO_ANY_INIT:
+ case TEXT_TO_ANY_EXIT:
+ case DATA_TO_ANY_EXIT:
+ case XXXINIT_TO_SOME_INIT:
+ case XXXEXIT_TO_SOME_EXIT:
+ case ANY_INIT_TO_ANY_EXIT:
+ case ANY_EXIT_TO_ANY_INIT:
+ warn("%s: section mismatch in reference: %s (section: %s) -> %s (section: %s)\n",
+ modname, fromsym, fromsec, tosym, tosec);
+ break;
+ case EXPORT_TO_INIT_EXIT:
+ warn("%s: EXPORT_SYMBOL used for init/exit symbol: %s (section: %s)\n",
+ modname, tosym, tosec);
+ break;
+ case EXTABLE_TO_NON_TEXT:
+ fatal("There's a special handler for this mismatch type, we should never get here.\n");
+ break;
+ }
+}
+
+static void default_mismatch_handler(const char *modname, struct elf_info *elf,
+ const struct sectioncheck* const mismatch,
+ Elf_Rela *r, Elf_Sym *sym, const char *fromsec)
+{
+ const char *tosec;
+ Elf_Sym *to;
+ Elf_Sym *from;
+ const char *tosym;
+ const char *fromsym;
+
+ from = find_elf_symbol2(elf, r->r_offset, fromsec);
+ fromsym = sym_name(elf, from);
+
+ tosec = sec_name(elf, get_secindex(elf, sym));
+ to = find_elf_symbol(elf, r->r_addend, sym);
+ tosym = sym_name(elf, to);
+
+ /* check whitelist - we may ignore it */
+ if (secref_whitelist(mismatch,
+ fromsec, fromsym, tosec, tosym)) {
+ report_sec_mismatch(modname, mismatch,
+ fromsec, fromsym, tosec, tosym);
+ }
+}
+
+static int is_executable_section(struct elf_info* elf, unsigned int section_index)
+{
+ if (section_index >= elf->num_sections)
+ fatal("section_index is outside elf->num_sections!\n");
+
+ return ((elf->sechdrs[section_index].sh_flags & SHF_EXECINSTR) == SHF_EXECINSTR);
+}
+
+static void report_extable_warnings(const char* modname, struct elf_info* elf,
+ const struct sectioncheck* const mismatch,
+ Elf_Rela* r, Elf_Sym* sym,
+ const char* fromsec, const char* tosec)
+{
+ Elf_Sym* fromsym = find_elf_symbol2(elf, r->r_offset, fromsec);
+ const char* fromsym_name = sym_name(elf, fromsym);
+ Elf_Sym* tosym = find_elf_symbol(elf, r->r_addend, sym);
+ const char* tosym_name = sym_name(elf, tosym);
+ const char* from_pretty_name;
+ const char* from_pretty_name_p;
+ const char* to_pretty_name;
+ const char* to_pretty_name_p;
+
+ get_pretty_name(is_function(fromsym),
+ &from_pretty_name, &from_pretty_name_p);
+ get_pretty_name(is_function(tosym),
+ &to_pretty_name, &to_pretty_name_p);
+
+ warn("%s(%s+0x%lx): Section mismatch in reference"
+ " from the %s %s%s to the %s %s:%s%s\n",
+ modname, fromsec, (long)r->r_offset, from_pretty_name,
+ fromsym_name, from_pretty_name_p,
+ to_pretty_name, tosec, tosym_name, to_pretty_name_p);
+
+ if (!match(tosec, mismatch->bad_tosec) &&
+ is_executable_section(elf, get_secindex(elf, sym)))
+ fprintf(stderr,
+ "The relocation at %s+0x%lx references\n"
+ "section \"%s\" which is not in the list of\n"
+ "authorized sections. If you're adding a new section\n"
+ "and/or if this reference is valid, add \"%s\" to the\n"
+ "list of authorized sections to jump to on fault.\n"
+ "This can be achieved by adding \"%s\" to \n"
+ "OTHER_TEXT_SECTIONS in scripts/mod/modpost.c.\n",
+ fromsec, (long)r->r_offset, tosec, tosec, tosec);
+}
+
+static void extable_mismatch_handler(const char* modname, struct elf_info *elf,
+ const struct sectioncheck* const mismatch,
+ Elf_Rela* r, Elf_Sym* sym,
+ const char *fromsec)
+{
+ const char* tosec = sec_name(elf, get_secindex(elf, sym));
+
+ sec_mismatch_count++;
+
+ report_extable_warnings(modname, elf, mismatch, r, sym, fromsec, tosec);
+
+ if (match(tosec, mismatch->bad_tosec))
+ fatal("The relocation at %s+0x%lx references\n"
+ "section \"%s\" which is black-listed.\n"
+ "Something is seriously wrong and should be fixed.\n"
+ "You might get more information about where this is\n"
+ "coming from by using scripts/check_extable.sh %s\n",
+ fromsec, (long)r->r_offset, tosec, modname);
+ else if (!is_executable_section(elf, get_secindex(elf, sym)))
+ error("%s+0x%lx references non-executable section '%s'\n",
+ fromsec, (long)r->r_offset, tosec);
+}
+
+static void check_section_mismatch(const char *modname, struct elf_info *elf,
+ Elf_Rela *r, Elf_Sym *sym, const char *fromsec)
+{
+ const char *tosec = sec_name(elf, get_secindex(elf, sym));
+ const struct sectioncheck *mismatch = section_mismatch(fromsec, tosec);
+
+ if (mismatch) {
+ if (mismatch->handler)
+ mismatch->handler(modname, elf, mismatch,
+ r, sym, fromsec);
+ else
+ default_mismatch_handler(modname, elf, mismatch,
+ r, sym, fromsec);
+ }
+}
+
+static unsigned int *reloc_location(struct elf_info *elf,
+ Elf_Shdr *sechdr, Elf_Rela *r)
+{
+ return sym_get_data_by_offset(elf, sechdr->sh_info, r->r_offset);
+}
+
+static int addend_386_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r)
+{
+ unsigned int r_typ = ELF_R_TYPE(r->r_info);
+ unsigned int *location = reloc_location(elf, sechdr, r);
+
+ switch (r_typ) {
+ case R_386_32:
+ r->r_addend = TO_NATIVE(*location);
+ break;
+ case R_386_PC32:
+ r->r_addend = TO_NATIVE(*location) + 4;
+ break;
+ }
+ return 0;
+}
+
+#ifndef R_ARM_CALL
+#define R_ARM_CALL 28
+#endif
+#ifndef R_ARM_JUMP24
+#define R_ARM_JUMP24 29
+#endif
+
+#ifndef R_ARM_THM_CALL
+#define R_ARM_THM_CALL 10
+#endif
+#ifndef R_ARM_THM_JUMP24
+#define R_ARM_THM_JUMP24 30
+#endif
+#ifndef R_ARM_THM_JUMP19
+#define R_ARM_THM_JUMP19 51
+#endif
+
+static int32_t sign_extend32(int32_t value, int index)
+{
+ uint8_t shift = 31 - index;
+
+ return (int32_t)(value << shift) >> shift;
+}
+
+static int addend_arm_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r)
+{
+ unsigned int r_typ = ELF_R_TYPE(r->r_info);
+ Elf_Sym *sym = elf->symtab_start + ELF_R_SYM(r->r_info);
+ void *loc = reloc_location(elf, sechdr, r);
+ uint32_t inst;
+ int32_t offset;
+
+ switch (r_typ) {
+ case R_ARM_ABS32:
+ inst = TO_NATIVE(*(uint32_t *)loc);
+ r->r_addend = inst + sym->st_value;
+ break;
+ case R_ARM_PC24:
+ case R_ARM_CALL:
+ case R_ARM_JUMP24:
+ inst = TO_NATIVE(*(uint32_t *)loc);
+ offset = sign_extend32((inst & 0x00ffffff) << 2, 25);
+ r->r_addend = offset + sym->st_value + 8;
+ break;
+ case R_ARM_THM_CALL:
+ case R_ARM_THM_JUMP24:
+ case R_ARM_THM_JUMP19:
+ /* From ARM ABI: ((S + A) | T) - P */
+ r->r_addend = (int)(long)(elf->hdr +
+ sechdr->sh_offset +
+ (r->r_offset - sechdr->sh_addr));
+ break;
+ default:
+ return 1;
+ }
+ return 0;
+}
+
+static int addend_mips_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r)
+{
+ unsigned int r_typ = ELF_R_TYPE(r->r_info);
+ unsigned int *location = reloc_location(elf, sechdr, r);
+ unsigned int inst;
+
+ if (r_typ == R_MIPS_HI16)
+ return 1; /* skip this */
+ inst = TO_NATIVE(*location);
+ switch (r_typ) {
+ case R_MIPS_LO16:
+ r->r_addend = inst & 0xffff;
+ break;
+ case R_MIPS_26:
+ r->r_addend = (inst & 0x03ffffff) << 2;
+ break;
+ case R_MIPS_32:
+ r->r_addend = inst;
+ break;
+ }
+ return 0;
+}
+
+#ifndef EM_RISCV
+#define EM_RISCV 243
+#endif
+
+#ifndef R_RISCV_SUB32
+#define R_RISCV_SUB32 39
+#endif
+
+static void section_rela(const char *modname, struct elf_info *elf,
+ Elf_Shdr *sechdr)
+{
+ Elf_Sym *sym;
+ Elf_Rela *rela;
+ Elf_Rela r;
+ unsigned int r_sym;
+ const char *fromsec;
+
+ Elf_Rela *start = (void *)elf->hdr + sechdr->sh_offset;
+ Elf_Rela *stop = (void *)start + sechdr->sh_size;
+
+ fromsec = sec_name(elf, sechdr->sh_info);
+ /* if from section (name) is know good then skip it */
+ if (match(fromsec, section_white_list))
+ return;
+
+ for (rela = start; rela < stop; rela++) {
+ r.r_offset = TO_NATIVE(rela->r_offset);
+#if KERNEL_ELFCLASS == ELFCLASS64
+ if (elf->hdr->e_machine == EM_MIPS) {
+ unsigned int r_typ;
+ r_sym = ELF64_MIPS_R_SYM(rela->r_info);
+ r_sym = TO_NATIVE(r_sym);
+ r_typ = ELF64_MIPS_R_TYPE(rela->r_info);
+ r.r_info = ELF64_R_INFO(r_sym, r_typ);
+ } else {
+ r.r_info = TO_NATIVE(rela->r_info);
+ r_sym = ELF_R_SYM(r.r_info);
+ }
+#else
+ r.r_info = TO_NATIVE(rela->r_info);
+ r_sym = ELF_R_SYM(r.r_info);
+#endif
+ r.r_addend = TO_NATIVE(rela->r_addend);
+ switch (elf->hdr->e_machine) {
+ case EM_RISCV:
+ if (!strcmp("__ex_table", fromsec) &&
+ ELF_R_TYPE(r.r_info) == R_RISCV_SUB32)
+ continue;
+ break;
+ }
+ sym = elf->symtab_start + r_sym;
+ /* Skip special sections */
+ if (is_shndx_special(sym->st_shndx))
+ continue;
+ check_section_mismatch(modname, elf, &r, sym, fromsec);
+ }
+}
+
+static void section_rel(const char *modname, struct elf_info *elf,
+ Elf_Shdr *sechdr)
+{
+ Elf_Sym *sym;
+ Elf_Rel *rel;
+ Elf_Rela r;
+ unsigned int r_sym;
+ const char *fromsec;
+
+ Elf_Rel *start = (void *)elf->hdr + sechdr->sh_offset;
+ Elf_Rel *stop = (void *)start + sechdr->sh_size;
+
+ fromsec = sec_name(elf, sechdr->sh_info);
+ /* if from section (name) is know good then skip it */
+ if (match(fromsec, section_white_list))
+ return;
+
+ for (rel = start; rel < stop; rel++) {
+ r.r_offset = TO_NATIVE(rel->r_offset);
+#if KERNEL_ELFCLASS == ELFCLASS64
+ if (elf->hdr->e_machine == EM_MIPS) {
+ unsigned int r_typ;
+ r_sym = ELF64_MIPS_R_SYM(rel->r_info);
+ r_sym = TO_NATIVE(r_sym);
+ r_typ = ELF64_MIPS_R_TYPE(rel->r_info);
+ r.r_info = ELF64_R_INFO(r_sym, r_typ);
+ } else {
+ r.r_info = TO_NATIVE(rel->r_info);
+ r_sym = ELF_R_SYM(r.r_info);
+ }
+#else
+ r.r_info = TO_NATIVE(rel->r_info);
+ r_sym = ELF_R_SYM(r.r_info);
+#endif
+ r.r_addend = 0;
+ switch (elf->hdr->e_machine) {
+ case EM_386:
+ if (addend_386_rel(elf, sechdr, &r))
+ continue;
+ break;
+ case EM_ARM:
+ if (addend_arm_rel(elf, sechdr, &r))
+ continue;
+ break;
+ case EM_MIPS:
+ if (addend_mips_rel(elf, sechdr, &r))
+ continue;
+ break;
+ }
+ sym = elf->symtab_start + r_sym;
+ /* Skip special sections */
+ if (is_shndx_special(sym->st_shndx))
+ continue;
+ check_section_mismatch(modname, elf, &r, sym, fromsec);
+ }
+}
+
+/**
+ * A module includes a number of sections that are discarded
+ * either when loaded or when used as built-in.
+ * For loaded modules all functions marked __init and all data
+ * marked __initdata will be discarded when the module has been initialized.
+ * Likewise for modules used built-in the sections marked __exit
+ * are discarded because __exit marked function are supposed to be called
+ * only when a module is unloaded which never happens for built-in modules.
+ * The check_sec_ref() function traverses all relocation records
+ * to find all references to a section that reference a section that will
+ * be discarded and warns about it.
+ **/
+static void check_sec_ref(const char *modname, struct elf_info *elf)
+{
+ int i;
+ Elf_Shdr *sechdrs = elf->sechdrs;
+
+ /* Walk through all sections */
+ for (i = 0; i < elf->num_sections; i++) {
+ check_section(modname, elf, &elf->sechdrs[i]);
+ /* We want to process only relocation sections and not .init */
+ if (sechdrs[i].sh_type == SHT_RELA)
+ section_rela(modname, elf, &elf->sechdrs[i]);
+ else if (sechdrs[i].sh_type == SHT_REL)
+ section_rel(modname, elf, &elf->sechdrs[i]);
+ }
+}
+
+static char *remove_dot(char *s)
+{
+ size_t n = strcspn(s, ".");
+
+ if (n && s[n]) {
+ size_t m = strspn(s + n + 1, "0123456789");
+ if (m && (s[n + m + 1] == '.' || s[n + m + 1] == 0))
+ s[n] = 0;
+ }
+ return s;
+}
+
+/*
+ * The CRCs are recorded in .*.cmd files in the form of:
+ * #SYMVER <name> <crc>
+ */
+static void extract_crcs_for_object(const char *object, struct module *mod)
+{
+ char cmd_file[PATH_MAX];
+ char *buf, *p;
+ const char *base;
+ int dirlen, ret;
+
+ base = strrchr(object, '/');
+ if (base) {
+ base++;
+ dirlen = base - object;
+ } else {
+ dirlen = 0;
+ base = object;
+ }
+
+ ret = snprintf(cmd_file, sizeof(cmd_file), "%.*s.%s.cmd",
+ dirlen, object, base);
+ if (ret >= sizeof(cmd_file)) {
+ error("%s: too long path was truncated\n", cmd_file);
+ return;
+ }
+
+ buf = read_text_file(cmd_file);
+ p = buf;
+
+ while ((p = strstr(p, "\n#SYMVER "))) {
+ char *name;
+ size_t namelen;
+ unsigned int crc;
+ struct symbol *sym;
+
+ name = p + strlen("\n#SYMVER ");
+
+ p = strchr(name, ' ');
+ if (!p)
+ break;
+
+ namelen = p - name;
+ p++;
+
+ if (!isdigit(*p))
+ continue; /* skip this line */
+
+ crc = strtoul(p, &p, 0);
+ if (*p != '\n')
+ continue; /* skip this line */
+
+ name[namelen] = '\0';
+
+ /*
+ * sym_find_with_module() may return NULL here.
+ * It typically occurs when CONFIG_TRIM_UNUSED_KSYMS=y.
+ * Since commit e1327a127703, genksyms calculates CRCs of all
+ * symbols, including trimmed ones. Ignore orphan CRCs.
+ */
+ sym = sym_find_with_module(name, mod);
+ if (sym)
+ sym_set_crc(sym, crc);
+ }
+
+ free(buf);
+}
+
+/*
+ * The symbol versions (CRC) are recorded in the .*.cmd files.
+ * Parse them to retrieve CRCs for the current module.
+ */
+static void mod_set_crcs(struct module *mod)
+{
+ char objlist[PATH_MAX];
+ char *buf, *p, *obj;
+ int ret;
+
+ if (mod->is_vmlinux) {
+ strcpy(objlist, ".vmlinux.objs");
+ } else {
+ /* objects for a module are listed in the *.mod file. */
+ ret = snprintf(objlist, sizeof(objlist), "%s.mod", mod->name);
+ if (ret >= sizeof(objlist)) {
+ error("%s: too long path was truncated\n", objlist);
+ return;
+ }
+ }
+
+ buf = read_text_file(objlist);
+ p = buf;
+
+ while ((obj = strsep(&p, "\n")) && obj[0])
+ extract_crcs_for_object(obj, mod);
+
+ free(buf);
+}
+
+static void read_symbols(const char *modname)
+{
+ const char *symname;
+ char *version;
+ char *license;
+ char *namespace;
+ struct module *mod;
+ struct elf_info info = { };
+ Elf_Sym *sym;
+
+ if (!parse_elf(&info, modname))
+ return;
+
+ if (!strends(modname, ".o")) {
+ error("%s: filename must be suffixed with .o\n", modname);
+ return;
+ }
+
+ /* strip trailing .o */
+ mod = new_module(modname, strlen(modname) - strlen(".o"));
+
+ if (!mod->is_vmlinux) {
+ license = get_modinfo(&info, "license");
+ if (!license)
+ error("missing MODULE_LICENSE() in %s\n", modname);
+ while (license) {
+ if (!license_is_gpl_compatible(license)) {
+ mod->is_gpl_compatible = false;
+ break;
+ }
+ license = get_next_modinfo(&info, "license", license);
+ }
+
+ namespace = get_modinfo(&info, "import_ns");
+ while (namespace) {
+ add_namespace(&mod->imported_namespaces, namespace);
+ namespace = get_next_modinfo(&info, "import_ns",
+ namespace);
+ }
+ }
+
+ for (sym = info.symtab_start; sym < info.symtab_stop; sym++) {
+ symname = remove_dot(info.strtab + sym->st_name);
+
+ handle_symbol(mod, &info, sym, symname);
+ handle_moddevtable(mod, &info, sym, symname);
+ }
+
+ for (sym = info.symtab_start; sym < info.symtab_stop; sym++) {
+ symname = remove_dot(info.strtab + sym->st_name);
+
+ /* Apply symbol namespaces from __kstrtabns_<symbol> entries. */
+ if (strstarts(symname, "__kstrtabns_"))
+ sym_update_namespace(symname + strlen("__kstrtabns_"),
+ sym_get_data(&info, sym));
+ }
+
+ check_sec_ref(modname, &info);
+
+ if (!mod->is_vmlinux) {
+ version = get_modinfo(&info, "version");
+ if (version || all_versions)
+ get_src_version(mod->name, mod->srcversion,
+ sizeof(mod->srcversion) - 1);
+ }
+
+ parse_elf_finish(&info);
+
+ if (modversions) {
+ /*
+ * Our trick to get versioning for module struct etc. - it's
+ * never passed as an argument to an exported function, so
+ * the automatic versioning doesn't pick it up, but it's really
+ * important anyhow.
+ */
+ sym_add_unresolved("module_layout", mod, false);
+
+ mod_set_crcs(mod);
+ }
+}
+
+static void read_symbols_from_files(const char *filename)
+{
+ FILE *in = stdin;
+ char fname[PATH_MAX];
+
+ if (strcmp(filename, "-") != 0) {
+ in = fopen(filename, "r");
+ if (!in)
+ fatal("Can't open filenames file %s: %m", filename);
+ }
+
+ while (fgets(fname, PATH_MAX, in) != NULL) {
+ if (strends(fname, "\n"))
+ fname[strlen(fname)-1] = '\0';
+ read_symbols(fname);
+ }
+
+ if (in != stdin)
+ fclose(in);
+}
+
+#define SZ 500
+
+/* We first write the generated file into memory using the
+ * following helper, then compare to the file on disk and
+ * only update the later if anything changed */
+
+void __attribute__((format(printf, 2, 3))) buf_printf(struct buffer *buf,
+ const char *fmt, ...)
+{
+ char tmp[SZ];
+ int len;
+ va_list ap;
+
+ va_start(ap, fmt);
+ len = vsnprintf(tmp, SZ, fmt, ap);
+ buf_write(buf, tmp, len);
+ va_end(ap);
+}
+
+void buf_write(struct buffer *buf, const char *s, int len)
+{
+ if (buf->size - buf->pos < len) {
+ buf->size += len + SZ;
+ buf->p = NOFAIL(realloc(buf->p, buf->size));
+ }
+ strncpy(buf->p + buf->pos, s, len);
+ buf->pos += len;
+}
+
+static void check_exports(struct module *mod)
+{
+ struct symbol *s, *exp;
+
+ list_for_each_entry(s, &mod->unresolved_symbols, list) {
+ const char *basename;
+ exp = find_symbol(s->name);
+ if (!exp) {
+ if (!s->weak && nr_unresolved++ < MAX_UNRESOLVED_REPORTS)
+ modpost_log(warn_unresolved ? LOG_WARN : LOG_ERROR,
+ "\"%s\" [%s.ko] undefined!\n",
+ s->name, mod->name);
+ continue;
+ }
+ if (exp->module == mod) {
+ error("\"%s\" [%s.ko] was exported without definition\n",
+ s->name, mod->name);
+ continue;
+ }
+
+ s->module = exp->module;
+ s->crc_valid = exp->crc_valid;
+ s->crc = exp->crc;
+
+ basename = strrchr(mod->name, '/');
+ if (basename)
+ basename++;
+ else
+ basename = mod->name;
+
+ if (exp->namespace &&
+ !contains_namespace(&mod->imported_namespaces, exp->namespace)) {
+ modpost_log(allow_missing_ns_imports ? LOG_WARN : LOG_ERROR,
+ "module %s uses symbol %s from namespace %s, but does not import it.\n",
+ basename, exp->name, exp->namespace);
+ add_namespace(&mod->missing_namespaces, exp->namespace);
+ }
+
+ if (!mod->is_gpl_compatible && exp->is_gpl_only)
+ error("GPL-incompatible module %s.ko uses GPL-only symbol '%s'\n",
+ basename, exp->name);
+ }
+}
+
+static void check_modname_len(struct module *mod)
+{
+ const char *mod_name;
+
+ mod_name = strrchr(mod->name, '/');
+ if (mod_name == NULL)
+ mod_name = mod->name;
+ else
+ mod_name++;
+ if (strlen(mod_name) >= MODULE_NAME_LEN)
+ error("module name is too long [%s.ko]\n", mod->name);
+}
+
+/**
+ * Header for the generated file
+ **/
+static void add_header(struct buffer *b, struct module *mod)
+{
+ buf_printf(b, "#include <linux/module.h>\n");
+ /*
+ * Include build-salt.h after module.h in order to
+ * inherit the definitions.
+ */
+ buf_printf(b, "#define INCLUDE_VERMAGIC\n");
+ buf_printf(b, "#include <linux/build-salt.h>\n");
+ buf_printf(b, "#include <linux/elfnote-lto.h>\n");
+ buf_printf(b, "#include <linux/export-internal.h>\n");
+ buf_printf(b, "#include <linux/vermagic.h>\n");
+ buf_printf(b, "#include <linux/compiler.h>\n");
+ buf_printf(b, "\n");
+ buf_printf(b, "BUILD_SALT;\n");
+ buf_printf(b, "BUILD_LTO_INFO;\n");
+ buf_printf(b, "\n");
+ buf_printf(b, "MODULE_INFO(vermagic, VERMAGIC_STRING);\n");
+ buf_printf(b, "MODULE_INFO(name, KBUILD_MODNAME);\n");
+ buf_printf(b, "\n");
+ buf_printf(b, "__visible struct module __this_module\n");
+ buf_printf(b, "__section(\".gnu.linkonce.this_module\") = {\n");
+ buf_printf(b, "\t.name = KBUILD_MODNAME,\n");
+ if (mod->has_init)
+ buf_printf(b, "\t.init = init_module,\n");
+ if (mod->has_cleanup)
+ buf_printf(b, "#ifdef CONFIG_MODULE_UNLOAD\n"
+ "\t.exit = cleanup_module,\n"
+ "#endif\n");
+ buf_printf(b, "\t.arch = MODULE_ARCH_INIT,\n");
+ buf_printf(b, "};\n");
+
+ if (!external_module)
+ buf_printf(b, "\nMODULE_INFO(intree, \"Y\");\n");
+
+ buf_printf(b,
+ "\n"
+ "#ifdef CONFIG_RETPOLINE\n"
+ "MODULE_INFO(retpoline, \"Y\");\n"
+ "#endif\n");
+
+ if (strstarts(mod->name, "drivers/staging"))
+ buf_printf(b, "\nMODULE_INFO(staging, \"Y\");\n");
+
+ if (strstarts(mod->name, "tools/testing"))
+ buf_printf(b, "\nMODULE_INFO(test, \"Y\");\n");
+}
+
+static void add_exported_symbols(struct buffer *buf, struct module *mod)
+{
+ struct symbol *sym;
+
+ if (!modversions)
+ return;
+
+ /* record CRCs for exported symbols */
+ buf_printf(buf, "\n");
+ list_for_each_entry(sym, &mod->exported_symbols, list) {
+ if (!sym->crc_valid)
+ warn("EXPORT symbol \"%s\" [%s%s] version generation failed, symbol will not be versioned.\n"
+ "Is \"%s\" prototyped in <asm/asm-prototypes.h>?\n",
+ sym->name, mod->name, mod->is_vmlinux ? "" : ".ko",
+ sym->name);
+
+ buf_printf(buf, "SYMBOL_CRC(%s, 0x%08x, \"%s\");\n",
+ sym->name, sym->crc, sym->is_gpl_only ? "_gpl" : "");
+ }
+}
+
+/**
+ * Record CRCs for unresolved symbols
+ **/
+static void add_versions(struct buffer *b, struct module *mod)
+{
+ struct symbol *s;
+
+ if (!modversions)
+ return;
+
+ buf_printf(b, "\n");
+ buf_printf(b, "static const struct modversion_info ____versions[]\n");
+ buf_printf(b, "__used __section(\"__versions\") = {\n");
+
+ list_for_each_entry(s, &mod->unresolved_symbols, list) {
+ if (!s->module)
+ continue;
+ if (!s->crc_valid) {
+ warn("\"%s\" [%s.ko] has no CRC!\n",
+ s->name, mod->name);
+ continue;
+ }
+ if (strlen(s->name) >= MODULE_NAME_LEN) {
+ error("too long symbol \"%s\" [%s.ko]\n",
+ s->name, mod->name);
+ break;
+ }
+ buf_printf(b, "\t{ %#8x, \"%s\" },\n",
+ s->crc, s->name);
+ }
+
+ buf_printf(b, "};\n");
+}
+
+static void add_depends(struct buffer *b, struct module *mod)
+{
+ struct symbol *s;
+ int first = 1;
+
+ /* Clear ->seen flag of modules that own symbols needed by this. */
+ list_for_each_entry(s, &mod->unresolved_symbols, list) {
+ if (s->module)
+ s->module->seen = s->module->is_vmlinux;
+ }
+
+ buf_printf(b, "\n");
+ buf_printf(b, "MODULE_INFO(depends, \"");
+ list_for_each_entry(s, &mod->unresolved_symbols, list) {
+ const char *p;
+ if (!s->module)
+ continue;
+
+ if (s->module->seen)
+ continue;
+
+ s->module->seen = true;
+ p = strrchr(s->module->name, '/');
+ if (p)
+ p++;
+ else
+ p = s->module->name;
+ buf_printf(b, "%s%s", first ? "" : ",", p);
+ first = 0;
+ }
+ buf_printf(b, "\");\n");
+}
+
+static void add_srcversion(struct buffer *b, struct module *mod)
+{
+ if (mod->srcversion[0]) {
+ buf_printf(b, "\n");
+ buf_printf(b, "MODULE_INFO(srcversion, \"%s\");\n",
+ mod->srcversion);
+ }
+}
+
+static void write_buf(struct buffer *b, const char *fname)
+{
+ FILE *file;
+
+ if (error_occurred)
+ return;
+
+ file = fopen(fname, "w");
+ if (!file) {
+ perror(fname);
+ exit(1);
+ }
+ if (fwrite(b->p, 1, b->pos, file) != b->pos) {
+ perror(fname);
+ exit(1);
+ }
+ if (fclose(file) != 0) {
+ perror(fname);
+ exit(1);
+ }
+}
+
+static void write_if_changed(struct buffer *b, const char *fname)
+{
+ char *tmp;
+ FILE *file;
+ struct stat st;
+
+ file = fopen(fname, "r");
+ if (!file)
+ goto write;
+
+ if (fstat(fileno(file), &st) < 0)
+ goto close_write;
+
+ if (st.st_size != b->pos)
+ goto close_write;
+
+ tmp = NOFAIL(malloc(b->pos));
+ if (fread(tmp, 1, b->pos, file) != b->pos)
+ goto free_write;
+
+ if (memcmp(tmp, b->p, b->pos) != 0)
+ goto free_write;
+
+ free(tmp);
+ fclose(file);
+ return;
+
+ free_write:
+ free(tmp);
+ close_write:
+ fclose(file);
+ write:
+ write_buf(b, fname);
+}
+
+static void write_vmlinux_export_c_file(struct module *mod)
+{
+ struct buffer buf = { };
+
+ buf_printf(&buf,
+ "#include <linux/export-internal.h>\n");
+
+ add_exported_symbols(&buf, mod);
+ write_if_changed(&buf, ".vmlinux.export.c");
+ free(buf.p);
+}
+
+/* do sanity checks, and generate *.mod.c file */
+static void write_mod_c_file(struct module *mod)
+{
+ struct buffer buf = { };
+ char fname[PATH_MAX];
+ int ret;
+
+ check_modname_len(mod);
+ check_exports(mod);
+
+ add_header(&buf, mod);
+ add_exported_symbols(&buf, mod);
+ add_versions(&buf, mod);
+ add_depends(&buf, mod);
+ add_moddevtable(&buf, mod);
+ add_srcversion(&buf, mod);
+
+ ret = snprintf(fname, sizeof(fname), "%s.mod.c", mod->name);
+ if (ret >= sizeof(fname)) {
+ error("%s: too long path was truncated\n", fname);
+ goto free;
+ }
+
+ write_if_changed(&buf, fname);
+
+free:
+ free(buf.p);
+}
+
+/* parse Module.symvers file. line format:
+ * 0x12345678<tab>symbol<tab>module<tab>export<tab>namespace
+ **/
+static void read_dump(const char *fname)
+{
+ char *buf, *pos, *line;
+
+ buf = read_text_file(fname);
+ if (!buf)
+ /* No symbol versions, silently ignore */
+ return;
+
+ pos = buf;
+
+ while ((line = get_line(&pos))) {
+ char *symname, *namespace, *modname, *d, *export;
+ unsigned int crc;
+ struct module *mod;
+ struct symbol *s;
+ bool gpl_only;
+
+ if (!(symname = strchr(line, '\t')))
+ goto fail;
+ *symname++ = '\0';
+ if (!(modname = strchr(symname, '\t')))
+ goto fail;
+ *modname++ = '\0';
+ if (!(export = strchr(modname, '\t')))
+ goto fail;
+ *export++ = '\0';
+ if (!(namespace = strchr(export, '\t')))
+ goto fail;
+ *namespace++ = '\0';
+
+ crc = strtoul(line, &d, 16);
+ if (*symname == '\0' || *modname == '\0' || *d != '\0')
+ goto fail;
+
+ if (!strcmp(export, "EXPORT_SYMBOL_GPL")) {
+ gpl_only = true;
+ } else if (!strcmp(export, "EXPORT_SYMBOL")) {
+ gpl_only = false;
+ } else {
+ error("%s: unknown license %s. skip", symname, export);
+ continue;
+ }
+
+ mod = find_module(modname);
+ if (!mod) {
+ mod = new_module(modname, strlen(modname));
+ mod->from_dump = true;
+ }
+ s = sym_add_exported(symname, mod, gpl_only);
+ sym_set_crc(s, crc);
+ sym_update_namespace(symname, namespace);
+ }
+ free(buf);
+ return;
+fail:
+ free(buf);
+ fatal("parse error in symbol dump file\n");
+}
+
+static void write_dump(const char *fname)
+{
+ struct buffer buf = { };
+ struct module *mod;
+ struct symbol *sym;
+
+ list_for_each_entry(mod, &modules, list) {
+ if (mod->from_dump)
+ continue;
+ list_for_each_entry(sym, &mod->exported_symbols, list) {
+ buf_printf(&buf, "0x%08x\t%s\t%s\tEXPORT_SYMBOL%s\t%s\n",
+ sym->crc, sym->name, mod->name,
+ sym->is_gpl_only ? "_GPL" : "",
+ sym->namespace ?: "");
+ }
+ }
+ write_buf(&buf, fname);
+ free(buf.p);
+}
+
+static void write_namespace_deps_files(const char *fname)
+{
+ struct module *mod;
+ struct namespace_list *ns;
+ struct buffer ns_deps_buf = {};
+
+ list_for_each_entry(mod, &modules, list) {
+
+ if (mod->from_dump || list_empty(&mod->missing_namespaces))
+ continue;
+
+ buf_printf(&ns_deps_buf, "%s.ko:", mod->name);
+
+ list_for_each_entry(ns, &mod->missing_namespaces, list)
+ buf_printf(&ns_deps_buf, " %s", ns->namespace);
+
+ buf_printf(&ns_deps_buf, "\n");
+ }
+
+ write_if_changed(&ns_deps_buf, fname);
+ free(ns_deps_buf.p);
+}
+
+struct dump_list {
+ struct list_head list;
+ const char *file;
+};
+
+int main(int argc, char **argv)
+{
+ struct module *mod;
+ char *missing_namespace_deps = NULL;
+ char *dump_write = NULL, *files_source = NULL;
+ int opt;
+ LIST_HEAD(dump_lists);
+ struct dump_list *dl, *dl2;
+
+ while ((opt = getopt(argc, argv, "ei:mnT:o:awENd:")) != -1) {
+ switch (opt) {
+ case 'e':
+ external_module = true;
+ break;
+ case 'i':
+ dl = NOFAIL(malloc(sizeof(*dl)));
+ dl->file = optarg;
+ list_add_tail(&dl->list, &dump_lists);
+ break;
+ case 'm':
+ modversions = true;
+ break;
+ case 'n':
+ ignore_missing_files = true;
+ break;
+ case 'o':
+ dump_write = optarg;
+ break;
+ case 'a':
+ all_versions = true;
+ break;
+ case 'T':
+ files_source = optarg;
+ break;
+ case 'w':
+ warn_unresolved = true;
+ break;
+ case 'E':
+ sec_mismatch_warn_only = false;
+ break;
+ case 'N':
+ allow_missing_ns_imports = true;
+ break;
+ case 'd':
+ missing_namespace_deps = optarg;
+ break;
+ default:
+ exit(1);
+ }
+ }
+
+ list_for_each_entry_safe(dl, dl2, &dump_lists, list) {
+ read_dump(dl->file);
+ list_del(&dl->list);
+ free(dl);
+ }
+
+ while (optind < argc)
+ read_symbols(argv[optind++]);
+
+ if (files_source)
+ read_symbols_from_files(files_source);
+
+ list_for_each_entry(mod, &modules, list) {
+ if (mod->from_dump)
+ continue;
+
+ if (mod->is_vmlinux)
+ write_vmlinux_export_c_file(mod);
+ else
+ write_mod_c_file(mod);
+ }
+
+ if (missing_namespace_deps)
+ write_namespace_deps_files(missing_namespace_deps);
+
+ if (dump_write)
+ write_dump(dump_write);
+ if (sec_mismatch_count && !sec_mismatch_warn_only)
+ error("Section mismatches detected.\n"
+ "Set CONFIG_SECTION_MISMATCH_WARN_ONLY=y to allow them.\n");
+
+ if (nr_unresolved > MAX_UNRESOLVED_REPORTS)
+ warn("suppressed %u unresolved symbol warnings because there were too many)\n",
+ nr_unresolved - MAX_UNRESOLVED_REPORTS);
+
+ return error_occurred ? 1 : 0;
+}
Index: Baikal/M1000/create-6.1.63-6.4.92-host-limits-patch/linux-m1-6.1.63-6.4.92-new/scripts/mod/sumversion.c
===================================================================
--- Baikal/M1000/create-6.1.63-6.4.92-host-limits-patch/linux-m1-6.1.63-6.4.92-new/scripts/mod/sumversion.c (nonexistent)
+++ Baikal/M1000/create-6.1.63-6.4.92-host-limits-patch/linux-m1-6.1.63-6.4.92-new/scripts/mod/sumversion.c (revision 385)
@@ -0,0 +1,410 @@
+#include <netinet/in.h>
+#ifdef __sun__
+#include <inttypes.h>
+#else
+#include <stdint.h>
+#endif
+#include <ctype.h>
+#include <errno.h>
+#include <string.h>
+#include <linux/limits.h>
+#include "modpost.h"
+
+/*
+ * Stolen form Cryptographic API.
+ *
+ * MD4 Message Digest Algorithm (RFC1320).
+ *
+ * Implementation derived from Andrew Tridgell and Steve French's
+ * CIFS MD4 implementation, and the cryptoapi implementation
+ * originally based on the public domain implementation written
+ * by Colin Plumb in 1993.
+ *
+ * Copyright (c) Andrew Tridgell 1997-1998.
+ * Modified by Steve French (sfrench@us.ibm.com) 2002
+ * Copyright (c) Cryptoapi developers.
+ * Copyright (c) 2002 David S. Miller (davem@redhat.com)
+ * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+#define MD4_DIGEST_SIZE 16
+#define MD4_HMAC_BLOCK_SIZE 64
+#define MD4_BLOCK_WORDS 16
+#define MD4_HASH_WORDS 4
+
+struct md4_ctx {
+ uint32_t hash[MD4_HASH_WORDS];
+ uint32_t block[MD4_BLOCK_WORDS];
+ uint64_t byte_count;
+};
+
+static inline uint32_t lshift(uint32_t x, unsigned int s)
+{
+ x &= 0xFFFFFFFF;
+ return ((x << s) & 0xFFFFFFFF) | (x >> (32 - s));
+}
+
+static inline uint32_t F(uint32_t x, uint32_t y, uint32_t z)
+{
+ return (x & y) | ((~x) & z);
+}
+
+static inline uint32_t G(uint32_t x, uint32_t y, uint32_t z)
+{
+ return (x & y) | (x & z) | (y & z);
+}
+
+static inline uint32_t H(uint32_t x, uint32_t y, uint32_t z)
+{
+ return x ^ y ^ z;
+}
+
+#define ROUND1(a,b,c,d,k,s) (a = lshift(a + F(b,c,d) + k, s))
+#define ROUND2(a,b,c,d,k,s) (a = lshift(a + G(b,c,d) + k + (uint32_t)0x5A827999,s))
+#define ROUND3(a,b,c,d,k,s) (a = lshift(a + H(b,c,d) + k + (uint32_t)0x6ED9EBA1,s))
+
+/* XXX: this stuff can be optimized */
+static inline void le32_to_cpu_array(uint32_t *buf, unsigned int words)
+{
+ while (words--) {
+ *buf = ntohl(*buf);
+ buf++;
+ }
+}
+
+static inline void cpu_to_le32_array(uint32_t *buf, unsigned int words)
+{
+ while (words--) {
+ *buf = htonl(*buf);
+ buf++;
+ }
+}
+
+static void md4_transform(uint32_t *hash, uint32_t const *in)
+{
+ uint32_t a, b, c, d;
+
+ a = hash[0];
+ b = hash[1];
+ c = hash[2];
+ d = hash[3];
+
+ ROUND1(a, b, c, d, in[0], 3);
+ ROUND1(d, a, b, c, in[1], 7);
+ ROUND1(c, d, a, b, in[2], 11);
+ ROUND1(b, c, d, a, in[3], 19);
+ ROUND1(a, b, c, d, in[4], 3);
+ ROUND1(d, a, b, c, in[5], 7);
+ ROUND1(c, d, a, b, in[6], 11);
+ ROUND1(b, c, d, a, in[7], 19);
+ ROUND1(a, b, c, d, in[8], 3);
+ ROUND1(d, a, b, c, in[9], 7);
+ ROUND1(c, d, a, b, in[10], 11);
+ ROUND1(b, c, d, a, in[11], 19);
+ ROUND1(a, b, c, d, in[12], 3);
+ ROUND1(d, a, b, c, in[13], 7);
+ ROUND1(c, d, a, b, in[14], 11);
+ ROUND1(b, c, d, a, in[15], 19);
+
+ ROUND2(a, b, c, d,in[ 0], 3);
+ ROUND2(d, a, b, c, in[4], 5);
+ ROUND2(c, d, a, b, in[8], 9);
+ ROUND2(b, c, d, a, in[12], 13);
+ ROUND2(a, b, c, d, in[1], 3);
+ ROUND2(d, a, b, c, in[5], 5);
+ ROUND2(c, d, a, b, in[9], 9);
+ ROUND2(b, c, d, a, in[13], 13);
+ ROUND2(a, b, c, d, in[2], 3);
+ ROUND2(d, a, b, c, in[6], 5);
+ ROUND2(c, d, a, b, in[10], 9);
+ ROUND2(b, c, d, a, in[14], 13);
+ ROUND2(a, b, c, d, in[3], 3);
+ ROUND2(d, a, b, c, in[7], 5);
+ ROUND2(c, d, a, b, in[11], 9);
+ ROUND2(b, c, d, a, in[15], 13);
+
+ ROUND3(a, b, c, d,in[ 0], 3);
+ ROUND3(d, a, b, c, in[8], 9);
+ ROUND3(c, d, a, b, in[4], 11);
+ ROUND3(b, c, d, a, in[12], 15);
+ ROUND3(a, b, c, d, in[2], 3);
+ ROUND3(d, a, b, c, in[10], 9);
+ ROUND3(c, d, a, b, in[6], 11);
+ ROUND3(b, c, d, a, in[14], 15);
+ ROUND3(a, b, c, d, in[1], 3);
+ ROUND3(d, a, b, c, in[9], 9);
+ ROUND3(c, d, a, b, in[5], 11);
+ ROUND3(b, c, d, a, in[13], 15);
+ ROUND3(a, b, c, d, in[3], 3);
+ ROUND3(d, a, b, c, in[11], 9);
+ ROUND3(c, d, a, b, in[7], 11);
+ ROUND3(b, c, d, a, in[15], 15);
+
+ hash[0] += a;
+ hash[1] += b;
+ hash[2] += c;
+ hash[3] += d;
+}
+
+static inline void md4_transform_helper(struct md4_ctx *ctx)
+{
+ le32_to_cpu_array(ctx->block, sizeof(ctx->block) / sizeof(uint32_t));
+ md4_transform(ctx->hash, ctx->block);
+}
+
+static void md4_init(struct md4_ctx *mctx)
+{
+ mctx->hash[0] = 0x67452301;
+ mctx->hash[1] = 0xefcdab89;
+ mctx->hash[2] = 0x98badcfe;
+ mctx->hash[3] = 0x10325476;
+ mctx->byte_count = 0;
+}
+
+static void md4_update(struct md4_ctx *mctx,
+ const unsigned char *data, unsigned int len)
+{
+ const uint32_t avail = sizeof(mctx->block) - (mctx->byte_count & 0x3f);
+
+ mctx->byte_count += len;
+
+ if (avail > len) {
+ memcpy((char *)mctx->block + (sizeof(mctx->block) - avail),
+ data, len);
+ return;
+ }
+
+ memcpy((char *)mctx->block + (sizeof(mctx->block) - avail),
+ data, avail);
+
+ md4_transform_helper(mctx);
+ data += avail;
+ len -= avail;
+
+ while (len >= sizeof(mctx->block)) {
+ memcpy(mctx->block, data, sizeof(mctx->block));
+ md4_transform_helper(mctx);
+ data += sizeof(mctx->block);
+ len -= sizeof(mctx->block);
+ }
+
+ memcpy(mctx->block, data, len);
+}
+
+static void md4_final_ascii(struct md4_ctx *mctx, char *out, unsigned int len)
+{
+ const unsigned int offset = mctx->byte_count & 0x3f;
+ char *p = (char *)mctx->block + offset;
+ int padding = 56 - (offset + 1);
+
+ *p++ = 0x80;
+ if (padding < 0) {
+ memset(p, 0x00, padding + sizeof (uint64_t));
+ md4_transform_helper(mctx);
+ p = (char *)mctx->block;
+ padding = 56;
+ }
+
+ memset(p, 0, padding);
+ mctx->block[14] = mctx->byte_count << 3;
+ mctx->block[15] = mctx->byte_count >> 29;
+ le32_to_cpu_array(mctx->block, (sizeof(mctx->block) -
+ sizeof(uint64_t)) / sizeof(uint32_t));
+ md4_transform(mctx->hash, mctx->block);
+ cpu_to_le32_array(mctx->hash, sizeof(mctx->hash) / sizeof(uint32_t));
+
+ snprintf(out, len, "%08X%08X%08X%08X",
+ mctx->hash[0], mctx->hash[1], mctx->hash[2], mctx->hash[3]);
+}
+
+static inline void add_char(unsigned char c, struct md4_ctx *md)
+{
+ md4_update(md, &c, 1);
+}
+
+static int parse_string(const char *file, unsigned long len,
+ struct md4_ctx *md)
+{
+ unsigned long i;
+
+ add_char(file[0], md);
+ for (i = 1; i < len; i++) {
+ add_char(file[i], md);
+ if (file[i] == '"' && file[i-1] != '\\')
+ break;
+ }
+ return i;
+}
+
+static int parse_comment(const char *file, unsigned long len)
+{
+ unsigned long i;
+
+ for (i = 2; i < len; i++) {
+ if (file[i-1] == '*' && file[i] == '/')
+ break;
+ }
+ return i;
+}
+
+/* FIXME: Handle .s files differently (eg. # starts comments) --RR */
+static int parse_file(const char *fname, struct md4_ctx *md)
+{
+ char *file;
+ unsigned long i, len;
+
+ file = read_text_file(fname);
+ len = strlen(file);
+
+ for (i = 0; i < len; i++) {
+ /* Collapse and ignore \ and CR. */
+ if (file[i] == '\\' && (i+1 < len) && file[i+1] == '\n') {
+ i++;
+ continue;
+ }
+
+ /* Ignore whitespace */
+ if (isspace(file[i]))
+ continue;
+
+ /* Handle strings as whole units */
+ if (file[i] == '"') {
+ i += parse_string(file+i, len - i, md);
+ continue;
+ }
+
+ /* Comments: ignore */
+ if (file[i] == '/' && file[i+1] == '*') {
+ i += parse_comment(file+i, len - i);
+ continue;
+ }
+
+ add_char(file[i], md);
+ }
+ free(file);
+ return 1;
+}
+/* Check whether the file is a static library or not */
+static bool is_static_library(const char *objfile)
+{
+ int len = strlen(objfile);
+
+ return objfile[len - 2] == '.' && objfile[len - 1] == 'a';
+}
+
+/* We have dir/file.o. Open dir/.file.o.cmd, look for source_ and deps_ line
+ * to figure out source files. */
+static int parse_source_files(const char *objfile, struct md4_ctx *md)
+{
+ char *cmd, *file, *line, *dir, *pos;
+ const char *base;
+ int dirlen, ret = 0, check_files = 0;
+
+ cmd = NOFAIL(malloc(strlen(objfile) + sizeof("..cmd")));
+
+ base = strrchr(objfile, '/');
+ if (base) {
+ base++;
+ dirlen = base - objfile;
+ sprintf(cmd, "%.*s.%s.cmd", dirlen, objfile, base);
+ } else {
+ dirlen = 0;
+ sprintf(cmd, ".%s.cmd", objfile);
+ }
+ dir = NOFAIL(malloc(dirlen + 1));
+ strncpy(dir, objfile, dirlen);
+ dir[dirlen] = '\0';
+
+ file = read_text_file(cmd);
+
+ pos = file;
+
+ /* Sum all files in the same dir or subdirs. */
+ while ((line = get_line(&pos))) {
+ char* p = line;
+
+ if (strncmp(line, "source_", sizeof("source_")-1) == 0) {
+ p = strrchr(line, ' ');
+ if (!p) {
+ warn("malformed line: %s\n", line);
+ goto out_file;
+ }
+ p++;
+ if (!parse_file(p, md)) {
+ warn("could not open %s: %s\n",
+ p, strerror(errno));
+ goto out_file;
+ }
+ continue;
+ }
+ if (strncmp(line, "deps_", sizeof("deps_")-1) == 0) {
+ check_files = 1;
+ continue;
+ }
+ if (!check_files)
+ continue;
+
+ /* Continue until line does not end with '\' */
+ if ( *(p + strlen(p)-1) != '\\')
+ break;
+ /* Terminate line at first space, to get rid of final ' \' */
+ while (*p) {
+ if (isspace(*p)) {
+ *p = '\0';
+ break;
+ }
+ p++;
+ }
+
+ /* Check if this file is in same dir as objfile */
+ if ((strstr(line, dir)+strlen(dir)-1) == strrchr(line, '/')) {
+ if (!parse_file(line, md)) {
+ warn("could not open %s: %s\n",
+ line, strerror(errno));
+ goto out_file;
+ }
+
+ }
+
+ }
+
+ /* Everyone parsed OK */
+ ret = 1;
+out_file:
+ free(file);
+ free(dir);
+ free(cmd);
+ return ret;
+}
+
+/* Calc and record src checksum. */
+void get_src_version(const char *modname, char sum[], unsigned sumlen)
+{
+ char *buf;
+ struct md4_ctx md;
+ char *fname;
+ char filelist[PATH_MAX + 1];
+
+ /* objects for a module are listed in the first line of *.mod file. */
+ snprintf(filelist, sizeof(filelist), "%s.mod", modname);
+
+ buf = read_text_file(filelist);
+
+ md4_init(&md);
+ while ((fname = strsep(&buf, "\n"))) {
+ if (!*fname)
+ continue;
+ if (!(is_static_library(fname)) &&
+ !parse_source_files(fname, &md))
+ goto free;
+ }
+
+ md4_final_ascii(&md, sum, sumlen);
+free:
+ free(buf);
+}
Index: Baikal/M1000/create-6.1.63-6.4.92-host-limits-patch/linux-m1-6.1.63-6.4.92-new/tools/build/fixdep.c
===================================================================
--- Baikal/M1000/create-6.1.63-6.4.92-host-limits-patch/linux-m1-6.1.63-6.4.92-new/tools/build/fixdep.c (nonexistent)
+++ Baikal/M1000/create-6.1.63-6.4.92-host-limits-patch/linux-m1-6.1.63-6.4.92-new/tools/build/fixdep.c (revision 385)
@@ -0,0 +1,170 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * "Optimize" a list of dependencies as spit out by gcc -MD
+ * for the build framework.
+ *
+ * Original author:
+ * Copyright 2002 by Kai Germaschewski <kai.germaschewski@gmx.de>
+ *
+ * This code has been borrowed from kbuild's fixdep (scripts/basic/fixdep.c),
+ * Please check it for detailed explanation. This fixdep borow only the
+ * base transformation of dependecies without the CONFIG mangle.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <linux/limits.h>
+
+char *target;
+char *depfile;
+char *cmdline;
+
+static void usage(void)
+{
+ fprintf(stderr, "Usage: fixdep <depfile> <target> <cmdline>\n");
+ exit(1);
+}
+
+/*
+ * Print out the commandline prefixed with cmd_<target filename> :=
+ */
+static void print_cmdline(void)
+{
+ printf("cmd_%s := %s\n\n", target, cmdline);
+}
+
+/*
+ * Important: The below generated source_foo.o and deps_foo.o variable
+ * assignments are parsed not only by make, but also by the rather simple
+ * parser in scripts/mod/sumversion.c.
+ */
+static void parse_dep_file(void *map, size_t len)
+{
+ char *m = map;
+ char *end = m + len;
+ char *p;
+ char s[PATH_MAX];
+ int is_target, has_target = 0;
+ int saw_any_target = 0;
+ int is_first_dep = 0;
+
+ while (m < end) {
+ /* Skip any "white space" */
+ while (m < end && (*m == ' ' || *m == '\\' || *m == '\n'))
+ m++;
+ /* Find next "white space" */
+ p = m;
+ while (p < end && *p != ' ' && *p != '\\' && *p != '\n')
+ p++;
+ /* Is the token we found a target name? */
+ is_target = (*(p-1) == ':');
+ /* Don't write any target names into the dependency file */
+ if (is_target) {
+ /* The /next/ file is the first dependency */
+ is_first_dep = 1;
+ has_target = 1;
+ } else if (has_target) {
+ /* Save this token/filename */
+ memcpy(s, m, p-m);
+ s[p - m] = 0;
+
+ /*
+ * Do not list the source file as dependency,
+ * so that kbuild is not confused if a .c file
+ * is rewritten into .S or vice versa. Storing
+ * it in source_* is needed for modpost to
+ * compute srcversions.
+ */
+ if (is_first_dep) {
+ /*
+ * If processing the concatenation of
+ * multiple dependency files, only
+ * process the first target name, which
+ * will be the original source name,
+ * and ignore any other target names,
+ * which will be intermediate temporary
+ * files.
+ */
+ if (!saw_any_target) {
+ saw_any_target = 1;
+ printf("source_%s := %s\n\n",
+ target, s);
+ printf("deps_%s := \\\n",
+ target);
+ }
+ is_first_dep = 0;
+ } else
+ printf(" %s \\\n", s);
+ }
+ /*
+ * Start searching for next token immediately after the first
+ * "whitespace" character that follows this token.
+ */
+ m = p + 1;
+ }
+
+ if (!saw_any_target) {
+ fprintf(stderr, "fixdep: parse error; no targets found\n");
+ exit(1);
+ }
+
+ printf("\n%s: $(deps_%s)\n\n", target, target);
+ printf("$(deps_%s):\n", target);
+}
+
+static void print_deps(void)
+{
+ struct stat st;
+ int fd;
+ void *map;
+
+ fd = open(depfile, O_RDONLY);
+ if (fd < 0) {
+ fprintf(stderr, "fixdep: error opening depfile: ");
+ perror(depfile);
+ exit(2);
+ }
+ if (fstat(fd, &st) < 0) {
+ fprintf(stderr, "fixdep: error fstat'ing depfile: ");
+ perror(depfile);
+ exit(2);
+ }
+ if (st.st_size == 0) {
+ fprintf(stderr, "fixdep: %s is empty\n", depfile);
+ close(fd);
+ return;
+ }
+ map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+ if ((long) map == -1) {
+ perror("fixdep: mmap");
+ close(fd);
+ return;
+ }
+
+ parse_dep_file(map, st.st_size);
+
+ munmap(map, st.st_size);
+
+ close(fd);
+}
+
+int main(int argc, char **argv)
+{
+ if (argc != 4)
+ usage();
+
+ depfile = argv[1];
+ target = argv[2];
+ cmdline = argv[3];
+
+ print_cmdline();
+ print_deps();
+
+ return 0;
+}
Index: Baikal/M1000/create-6.1.63-6.4.92-host-limits-patch/linux-m1-6.1.63-6.4.92-new/usr/gen_init_cpio.c
===================================================================
--- Baikal/M1000/create-6.1.63-6.4.92-host-limits-patch/linux-m1-6.1.63-6.4.92-new/usr/gen_init_cpio.c (nonexistent)
+++ Baikal/M1000/create-6.1.63-6.4.92-host-limits-patch/linux-m1-6.1.63-6.4.92-new/usr/gen_init_cpio.c (revision 385)
@@ -0,0 +1,682 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <unistd.h>
+#include <time.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <ctype.h>
+#include <linux/limits.h>
+
+/*
+ * Original work by Jeff Garzik
+ *
+ * External file lists, symlink, pipe and fifo support by Thayne Harbaugh
+ * Hard link support by Luciano Rocha
+ */
+
+#define xstr(s) #s
+#define str(s) xstr(s)
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+
+static unsigned int offset;
+static unsigned int ino = 721;
+static time_t default_mtime;
+static bool do_csum = false;
+
+struct file_handler {
+ const char *type;
+ int (*handler)(const char *line);
+};
+
+static void push_string(const char *name)
+{
+ unsigned int name_len = strlen(name) + 1;
+
+ fputs(name, stdout);
+ putchar(0);
+ offset += name_len;
+}
+
+static void push_pad (void)
+{
+ while (offset & 3) {
+ putchar(0);
+ offset++;
+ }
+}
+
+static void push_rest(const char *name)
+{
+ unsigned int name_len = strlen(name) + 1;
+ unsigned int tmp_ofs;
+
+ fputs(name, stdout);
+ putchar(0);
+ offset += name_len;
+
+ tmp_ofs = name_len + 110;
+ while (tmp_ofs & 3) {
+ putchar(0);
+ offset++;
+ tmp_ofs++;
+ }
+}
+
+static void push_hdr(const char *s)
+{
+ fputs(s, stdout);
+ offset += 110;
+}
+
+static void cpio_trailer(void)
+{
+ char s[256];
+ const char name[] = "TRAILER!!!";
+
+ sprintf(s, "%s%08X%08X%08lX%08lX%08X%08lX"
+ "%08X%08X%08X%08X%08X%08X%08X",
+ do_csum ? "070702" : "070701", /* magic */
+ 0, /* ino */
+ 0, /* mode */
+ (long) 0, /* uid */
+ (long) 0, /* gid */
+ 1, /* nlink */
+ (long) 0, /* mtime */
+ 0, /* filesize */
+ 0, /* major */
+ 0, /* minor */
+ 0, /* rmajor */
+ 0, /* rminor */
+ (unsigned)strlen(name)+1, /* namesize */
+ 0); /* chksum */
+ push_hdr(s);
+ push_rest(name);
+
+ while (offset % 512) {
+ putchar(0);
+ offset++;
+ }
+}
+
+static int cpio_mkslink(const char *name, const char *target,
+ unsigned int mode, uid_t uid, gid_t gid)
+{
+ char s[256];
+
+ if (name[0] == '/')
+ name++;
+ sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
+ "%08X%08X%08X%08X%08X%08X%08X",
+ do_csum ? "070702" : "070701", /* magic */
+ ino++, /* ino */
+ S_IFLNK | mode, /* mode */
+ (long) uid, /* uid */
+ (long) gid, /* gid */
+ 1, /* nlink */
+ (long) default_mtime, /* mtime */
+ (unsigned)strlen(target)+1, /* filesize */
+ 3, /* major */
+ 1, /* minor */
+ 0, /* rmajor */
+ 0, /* rminor */
+ (unsigned)strlen(name) + 1,/* namesize */
+ 0); /* chksum */
+ push_hdr(s);
+ push_string(name);
+ push_pad();
+ push_string(target);
+ push_pad();
+ return 0;
+}
+
+static int cpio_mkslink_line(const char *line)
+{
+ char name[PATH_MAX + 1];
+ char target[PATH_MAX + 1];
+ unsigned int mode;
+ int uid;
+ int gid;
+ int rc = -1;
+
+ if (5 != sscanf(line, "%" str(PATH_MAX) "s %" str(PATH_MAX) "s %o %d %d", name, target, &mode, &uid, &gid)) {
+ fprintf(stderr, "Unrecognized dir format '%s'", line);
+ goto fail;
+ }
+ rc = cpio_mkslink(name, target, mode, uid, gid);
+ fail:
+ return rc;
+}
+
+static int cpio_mkgeneric(const char *name, unsigned int mode,
+ uid_t uid, gid_t gid)
+{
+ char s[256];
+
+ if (name[0] == '/')
+ name++;
+ sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
+ "%08X%08X%08X%08X%08X%08X%08X",
+ do_csum ? "070702" : "070701", /* magic */
+ ino++, /* ino */
+ mode, /* mode */
+ (long) uid, /* uid */
+ (long) gid, /* gid */
+ 2, /* nlink */
+ (long) default_mtime, /* mtime */
+ 0, /* filesize */
+ 3, /* major */
+ 1, /* minor */
+ 0, /* rmajor */
+ 0, /* rminor */
+ (unsigned)strlen(name) + 1,/* namesize */
+ 0); /* chksum */
+ push_hdr(s);
+ push_rest(name);
+ return 0;
+}
+
+enum generic_types {
+ GT_DIR,
+ GT_PIPE,
+ GT_SOCK
+};
+
+struct generic_type {
+ const char *type;
+ mode_t mode;
+};
+
+static const struct generic_type generic_type_table[] = {
+ [GT_DIR] = {
+ .type = "dir",
+ .mode = S_IFDIR
+ },
+ [GT_PIPE] = {
+ .type = "pipe",
+ .mode = S_IFIFO
+ },
+ [GT_SOCK] = {
+ .type = "sock",
+ .mode = S_IFSOCK
+ }
+};
+
+static int cpio_mkgeneric_line(const char *line, enum generic_types gt)
+{
+ char name[PATH_MAX + 1];
+ unsigned int mode;
+ int uid;
+ int gid;
+ int rc = -1;
+
+ if (4 != sscanf(line, "%" str(PATH_MAX) "s %o %d %d", name, &mode, &uid, &gid)) {
+ fprintf(stderr, "Unrecognized %s format '%s'",
+ line, generic_type_table[gt].type);
+ goto fail;
+ }
+ mode |= generic_type_table[gt].mode;
+ rc = cpio_mkgeneric(name, mode, uid, gid);
+ fail:
+ return rc;
+}
+
+static int cpio_mkdir_line(const char *line)
+{
+ return cpio_mkgeneric_line(line, GT_DIR);
+}
+
+static int cpio_mkpipe_line(const char *line)
+{
+ return cpio_mkgeneric_line(line, GT_PIPE);
+}
+
+static int cpio_mksock_line(const char *line)
+{
+ return cpio_mkgeneric_line(line, GT_SOCK);
+}
+
+static int cpio_mknod(const char *name, unsigned int mode,
+ uid_t uid, gid_t gid, char dev_type,
+ unsigned int maj, unsigned int min)
+{
+ char s[256];
+
+ if (dev_type == 'b')
+ mode |= S_IFBLK;
+ else
+ mode |= S_IFCHR;
+
+ if (name[0] == '/')
+ name++;
+ sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
+ "%08X%08X%08X%08X%08X%08X%08X",
+ do_csum ? "070702" : "070701", /* magic */
+ ino++, /* ino */
+ mode, /* mode */
+ (long) uid, /* uid */
+ (long) gid, /* gid */
+ 1, /* nlink */
+ (long) default_mtime, /* mtime */
+ 0, /* filesize */
+ 3, /* major */
+ 1, /* minor */
+ maj, /* rmajor */
+ min, /* rminor */
+ (unsigned)strlen(name) + 1,/* namesize */
+ 0); /* chksum */
+ push_hdr(s);
+ push_rest(name);
+ return 0;
+}
+
+static int cpio_mknod_line(const char *line)
+{
+ char name[PATH_MAX + 1];
+ unsigned int mode;
+ int uid;
+ int gid;
+ char dev_type;
+ unsigned int maj;
+ unsigned int min;
+ int rc = -1;
+
+ if (7 != sscanf(line, "%" str(PATH_MAX) "s %o %d %d %c %u %u",
+ name, &mode, &uid, &gid, &dev_type, &maj, &min)) {
+ fprintf(stderr, "Unrecognized nod format '%s'", line);
+ goto fail;
+ }
+ rc = cpio_mknod(name, mode, uid, gid, dev_type, maj, min);
+ fail:
+ return rc;
+}
+
+static int cpio_mkfile_csum(int fd, unsigned long size, uint32_t *csum)
+{
+ while (size) {
+ unsigned char filebuf[65536];
+ ssize_t this_read;
+ size_t i, this_size = MIN(size, sizeof(filebuf));
+
+ this_read = read(fd, filebuf, this_size);
+ if (this_read <= 0 || this_read > this_size)
+ return -1;
+
+ for (i = 0; i < this_read; i++)
+ *csum += filebuf[i];
+
+ size -= this_read;
+ }
+ /* seek back to the start for data segment I/O */
+ if (lseek(fd, 0, SEEK_SET) < 0)
+ return -1;
+
+ return 0;
+}
+
+static int cpio_mkfile(const char *name, const char *location,
+ unsigned int mode, uid_t uid, gid_t gid,
+ unsigned int nlinks)
+{
+ char s[256];
+ struct stat buf;
+ unsigned long size;
+ int file;
+ int retval;
+ int rc = -1;
+ int namesize;
+ unsigned int i;
+ uint32_t csum = 0;
+
+ mode |= S_IFREG;
+
+ file = open (location, O_RDONLY);
+ if (file < 0) {
+ fprintf (stderr, "File %s could not be opened for reading\n", location);
+ goto error;
+ }
+
+ retval = fstat(file, &buf);
+ if (retval) {
+ fprintf(stderr, "File %s could not be stat()'ed\n", location);
+ goto error;
+ }
+
+ if (buf.st_mtime > 0xffffffff) {
+ fprintf(stderr, "%s: Timestamp exceeds maximum cpio timestamp, clipping.\n",
+ location);
+ buf.st_mtime = 0xffffffff;
+ }
+
+ if (buf.st_size > 0xffffffff) {
+ fprintf(stderr, "%s: Size exceeds maximum cpio file size\n",
+ location);
+ goto error;
+ }
+
+ if (do_csum && cpio_mkfile_csum(file, buf.st_size, &csum) < 0) {
+ fprintf(stderr, "Failed to checksum file %s\n", location);
+ goto error;
+ }
+
+ size = 0;
+ for (i = 1; i <= nlinks; i++) {
+ /* data goes on last link */
+ if (i == nlinks)
+ size = buf.st_size;
+
+ if (name[0] == '/')
+ name++;
+ namesize = strlen(name) + 1;
+ sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
+ "%08lX%08X%08X%08X%08X%08X%08X",
+ do_csum ? "070702" : "070701", /* magic */
+ ino, /* ino */
+ mode, /* mode */
+ (long) uid, /* uid */
+ (long) gid, /* gid */
+ nlinks, /* nlink */
+ (long) buf.st_mtime, /* mtime */
+ size, /* filesize */
+ 3, /* major */
+ 1, /* minor */
+ 0, /* rmajor */
+ 0, /* rminor */
+ namesize, /* namesize */
+ size ? csum : 0); /* chksum */
+ push_hdr(s);
+ push_string(name);
+ push_pad();
+
+ while (size) {
+ unsigned char filebuf[65536];
+ ssize_t this_read;
+ size_t this_size = MIN(size, sizeof(filebuf));
+
+ this_read = read(file, filebuf, this_size);
+ if (this_read <= 0 || this_read > this_size) {
+ fprintf(stderr, "Can not read %s file\n", location);
+ goto error;
+ }
+
+ if (fwrite(filebuf, this_read, 1, stdout) != 1) {
+ fprintf(stderr, "writing filebuf failed\n");
+ goto error;
+ }
+ offset += this_read;
+ size -= this_read;
+ }
+ push_pad();
+
+ name += namesize;
+ }
+ ino++;
+ rc = 0;
+
+error:
+ if (file >= 0)
+ close(file);
+ return rc;
+}
+
+static char *cpio_replace_env(char *new_location)
+{
+ char expanded[PATH_MAX + 1];
+ char *start, *end, *var;
+
+ while ((start = strstr(new_location, "${")) &&
+ (end = strchr(start + 2, '}'))) {
+ *start = *end = 0;
+ var = getenv(start + 2);
+ snprintf(expanded, sizeof expanded, "%s%s%s",
+ new_location, var ? var : "", end + 1);
+ strcpy(new_location, expanded);
+ }
+
+ return new_location;
+}
+
+static int cpio_mkfile_line(const char *line)
+{
+ char name[PATH_MAX + 1];
+ char *dname = NULL; /* malloc'ed buffer for hard links */
+ char location[PATH_MAX + 1];
+ unsigned int mode;
+ int uid;
+ int gid;
+ int nlinks = 1;
+ int end = 0, dname_len = 0;
+ int rc = -1;
+
+ if (5 > sscanf(line, "%" str(PATH_MAX) "s %" str(PATH_MAX)
+ "s %o %d %d %n",
+ name, location, &mode, &uid, &gid, &end)) {
+ fprintf(stderr, "Unrecognized file format '%s'", line);
+ goto fail;
+ }
+ if (end && isgraph(line[end])) {
+ int len;
+ int nend;
+
+ dname = malloc(strlen(line));
+ if (!dname) {
+ fprintf (stderr, "out of memory (%d)\n", dname_len);
+ goto fail;
+ }
+
+ dname_len = strlen(name) + 1;
+ memcpy(dname, name, dname_len);
+
+ do {
+ nend = 0;
+ if (sscanf(line + end, "%" str(PATH_MAX) "s %n",
+ name, &nend) < 1)
+ break;
+ len = strlen(name) + 1;
+ memcpy(dname + dname_len, name, len);
+ dname_len += len;
+ nlinks++;
+ end += nend;
+ } while (isgraph(line[end]));
+ } else {
+ dname = name;
+ }
+ rc = cpio_mkfile(dname, cpio_replace_env(location),
+ mode, uid, gid, nlinks);
+ fail:
+ if (dname_len) free(dname);
+ return rc;
+}
+
+static void usage(const char *prog)
+{
+ fprintf(stderr, "Usage:\n"
+ "\t%s [-t <timestamp>] [-c] <cpio_list>\n"
+ "\n"
+ "<cpio_list> is a file containing newline separated entries that\n"
+ "describe the files to be included in the initramfs archive:\n"
+ "\n"
+ "# a comment\n"
+ "file <name> <location> <mode> <uid> <gid> [<hard links>]\n"
+ "dir <name> <mode> <uid> <gid>\n"
+ "nod <name> <mode> <uid> <gid> <dev_type> <maj> <min>\n"
+ "slink <name> <target> <mode> <uid> <gid>\n"
+ "pipe <name> <mode> <uid> <gid>\n"
+ "sock <name> <mode> <uid> <gid>\n"
+ "\n"
+ "<name> name of the file/dir/nod/etc in the archive\n"
+ "<location> location of the file in the current filesystem\n"
+ " expands shell variables quoted with ${}\n"
+ "<target> link target\n"
+ "<mode> mode/permissions of the file\n"
+ "<uid> user id (0=root)\n"
+ "<gid> group id (0=root)\n"
+ "<dev_type> device type (b=block, c=character)\n"
+ "<maj> major number of nod\n"
+ "<min> minor number of nod\n"
+ "<hard links> space separated list of other links to file\n"
+ "\n"
+ "example:\n"
+ "# A simple initramfs\n"
+ "dir /dev 0755 0 0\n"
+ "nod /dev/console 0600 0 0 c 5 1\n"
+ "dir /root 0700 0 0\n"
+ "dir /sbin 0755 0 0\n"
+ "file /sbin/kinit /usr/src/klibc/kinit/kinit 0755 0 0\n"
+ "\n"
+ "<timestamp> is time in seconds since Epoch that will be used\n"
+ "as mtime for symlinks, special files and directories. The default\n"
+ "is to use the current time for these entries.\n"
+ "-c: calculate and store 32-bit checksums for file data.\n",
+ prog);
+}
+
+static const struct file_handler file_handler_table[] = {
+ {
+ .type = "file",
+ .handler = cpio_mkfile_line,
+ }, {
+ .type = "nod",
+ .handler = cpio_mknod_line,
+ }, {
+ .type = "dir",
+ .handler = cpio_mkdir_line,
+ }, {
+ .type = "slink",
+ .handler = cpio_mkslink_line,
+ }, {
+ .type = "pipe",
+ .handler = cpio_mkpipe_line,
+ }, {
+ .type = "sock",
+ .handler = cpio_mksock_line,
+ }, {
+ .type = NULL,
+ .handler = NULL,
+ }
+};
+
+#define LINE_SIZE (2 * PATH_MAX + 50)
+
+int main (int argc, char *argv[])
+{
+ FILE *cpio_list;
+ char line[LINE_SIZE];
+ char *args, *type;
+ int ec = 0;
+ int line_nr = 0;
+ const char *filename;
+
+ default_mtime = time(NULL);
+ while (1) {
+ int opt = getopt(argc, argv, "t:ch");
+ char *invalid;
+
+ if (opt == -1)
+ break;
+ switch (opt) {
+ case 't':
+ default_mtime = strtol(optarg, &invalid, 10);
+ if (!*optarg || *invalid) {
+ fprintf(stderr, "Invalid timestamp: %s\n",
+ optarg);
+ usage(argv[0]);
+ exit(1);
+ }
+ break;
+ case 'c':
+ do_csum = true;
+ break;
+ case 'h':
+ case '?':
+ usage(argv[0]);
+ exit(opt == 'h' ? 0 : 1);
+ }
+ }
+
+ /*
+ * Timestamps after 2106-02-07 06:28:15 UTC have an ascii hex time_t
+ * representation that exceeds 8 chars and breaks the cpio header
+ * specification.
+ */
+ if (default_mtime > 0xffffffff) {
+ fprintf(stderr, "ERROR: Timestamp too large for cpio format\n");
+ exit(1);
+ }
+
+ if (argc - optind != 1) {
+ usage(argv[0]);
+ exit(1);
+ }
+ filename = argv[optind];
+ if (!strcmp(filename, "-"))
+ cpio_list = stdin;
+ else if (!(cpio_list = fopen(filename, "r"))) {
+ fprintf(stderr, "ERROR: unable to open '%s': %s\n\n",
+ filename, strerror(errno));
+ usage(argv[0]);
+ exit(1);
+ }
+
+ while (fgets(line, LINE_SIZE, cpio_list)) {
+ int type_idx;
+ size_t slen = strlen(line);
+
+ line_nr++;
+
+ if ('#' == *line) {
+ /* comment - skip to next line */
+ continue;
+ }
+
+ if (! (type = strtok(line, " \t"))) {
+ fprintf(stderr,
+ "ERROR: incorrect format, could not locate file type line %d: '%s'\n",
+ line_nr, line);
+ ec = -1;
+ break;
+ }
+
+ if ('\n' == *type) {
+ /* a blank line */
+ continue;
+ }
+
+ if (slen == strlen(type)) {
+ /* must be an empty line */
+ continue;
+ }
+
+ if (! (args = strtok(NULL, "\n"))) {
+ fprintf(stderr,
+ "ERROR: incorrect format, newline required line %d: '%s'\n",
+ line_nr, line);
+ ec = -1;
+ }
+
+ for (type_idx = 0; file_handler_table[type_idx].type; type_idx++) {
+ int rc;
+ if (! strcmp(line, file_handler_table[type_idx].type)) {
+ if ((rc = file_handler_table[type_idx].handler(args))) {
+ ec = rc;
+ fprintf(stderr, " line %d\n", line_nr);
+ }
+ break;
+ }
+ }
+
+ if (NULL == file_handler_table[type_idx].type) {
+ fprintf(stderr, "unknown file type line %d: '%s'\n",
+ line_nr, line);
+ }
+ }
+ if (ec == 0)
+ cpio_trailer();
+
+ exit(ec);
+}
Index: OrangePi/Makefile
===================================================================
--- OrangePi/Makefile (nonexistent)
+++ OrangePi/Makefile (revision 385)
@@ -0,0 +1,54 @@
+
+COMPONENT_TARGETS = $(HARDWARE_NOARCH)
+
+
+include ../../../build-system/constants.mk
+
+
+url = $(DOWNLOAD_SERVER)/sources/Linux/OrangePi
+
+versions = orangepi-5.10.110
+
+tarballs = $(addsuffix .tar.xz, $(addprefix linux-, $(versions)))
+sha1s = $(addsuffix .sha1sum, $(tarballs))
+
+patches = $(CURDIR)/patches/linux-orangepi-5.10.110-host-limits.patch
+
+.NOTPARALLEL: $(patches)
+
+
+BUILD_TARGETS = $(tarballs) $(sha1s) $(patches)
+
+
+include ../../../build-system/core.mk
+
+
+.PHONY: download_clean
+
+
+$(tarballs):
+ @echo -e "\n======= Downloading source tarballs =======" ; \
+ for tarball in $(tarballs) ; do \
+ echo "$(url)/$$tarball" | xargs -n 1 -P 100 wget $(WGET_OPTIONS) - & \
+ done ; wait
+
+$(sha1s): $(tarballs)
+ @for sha in $@ ; do \
+ echo -e "\n======= Downloading '$$sha' signature =======\n" ; \
+ echo "$(url)/$$sha" | xargs -n 1 -P 100 wget $(WGET_OPTIONS) - & wait %1 ; \
+ touch $$sha ; \
+ echo -e "\n======= Check the '$$sha' sha1sum =======\n" ; \
+ sha1sum --check $$sha ; ret="$$?" ; \
+ if [ "$$ret" == "1" ]; then \
+ echo -e "\n======= ERROR: Bad '$$sha' sha1sum =======\n" ; \
+ exit 1 ; \
+ fi ; \
+ done
+
+$(patches): $(sha1s)
+ @echo -e "\n======= Create Patches =======\n" ; \
+ ( cd create-5.10.110-host-limits-patch ; ./create.patch.sh ) ; \
+ echo -e "\n"
+
+download_clean:
+ @rm -f $(tarballs) $(sha1s) $(patches)
Index: OrangePi/create-5.10.110-host-limits-patch/create.patch.sh
===================================================================
--- OrangePi/create-5.10.110-host-limits-patch/create.patch.sh (nonexistent)
+++ OrangePi/create-5.10.110-host-limits-patch/create.patch.sh (revision 385)
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+VERSION=5.10.110
+
+tar --files-from=file.list -xJvf ../linux-orangepi-$VERSION.tar.xz
+mv linux-orangepi-$VERSION linux-orangepi-$VERSION-orig
+
+cp -rf ./linux-orangepi-$VERSION-new ./linux-orangepi-$VERSION
+
+diff --unified -Nr linux-orangepi-$VERSION-orig linux-orangepi-$VERSION > linux-orangepi-$VERSION-host-limits.patch
+
+mv linux-orangepi-$VERSION-host-limits.patch ../patches
+
+rm -rf ./linux-orangepi-$VERSION
+rm -rf ./linux-orangepi-$VERSION-orig
Property changes on: OrangePi/create-5.10.110-host-limits-patch/create.patch.sh
___________________________________________________________________
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: OrangePi/create-5.10.110-host-limits-patch/file.list
===================================================================
--- OrangePi/create-5.10.110-host-limits-patch/file.list (nonexistent)
+++ OrangePi/create-5.10.110-host-limits-patch/file.list (revision 385)
@@ -0,0 +1,7 @@
+linux-orangepi-5.10.110/scripts/kconfig/conf.c
+linux-orangepi-5.10.110/scripts/kconfig/confdata.c
+linux-orangepi-5.10.110/scripts/kconfig/lexer.l
+linux-orangepi-5.10.110/scripts/mod/modpost.c
+linux-orangepi-5.10.110/scripts/mod/sumversion.c
+linux-orangepi-5.10.110/tools/build/fixdep.c
+linux-orangepi-5.10.110/usr/gen_init_cpio.c
Index: OrangePi/create-5.10.110-host-limits-patch/linux-orangepi-5.10.110-new/scripts/kconfig/conf.c
===================================================================
--- OrangePi/create-5.10.110-host-limits-patch/linux-orangepi-5.10.110-new/scripts/kconfig/conf.c (nonexistent)
+++ OrangePi/create-5.10.110-host-limits-patch/linux-orangepi-5.10.110-new/scripts/kconfig/conf.c (revision 385)
@@ -0,0 +1,727 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ */
+
+#include <ctype.h>
+#include <linux/limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <errno.h>
+
+#include "lkc.h"
+
+static void conf(struct menu *menu);
+static void check_conf(struct menu *menu);
+
+enum input_mode {
+ oldaskconfig,
+ syncconfig,
+ oldconfig,
+ allnoconfig,
+ allyesconfig,
+ allmodconfig,
+ alldefconfig,
+ randconfig,
+ defconfig,
+ savedefconfig,
+ listnewconfig,
+ helpnewconfig,
+ olddefconfig,
+ yes2modconfig,
+ mod2yesconfig,
+};
+static enum input_mode input_mode = oldaskconfig;
+
+static int indent = 1;
+static int tty_stdio;
+static int sync_kconfig;
+static int conf_cnt;
+static char line[PATH_MAX];
+static struct menu *rootEntry;
+
+static void print_help(struct menu *menu)
+{
+ struct gstr help = str_new();
+
+ menu_get_ext_help(menu, &help);
+
+ printf("\n%s\n", str_get(&help));
+ str_free(&help);
+}
+
+static void strip(char *str)
+{
+ char *p = str;
+ int l;
+
+ while ((isspace(*p)))
+ p++;
+ l = strlen(p);
+ if (p != str)
+ memmove(str, p, l + 1);
+ if (!l)
+ return;
+ p = str + l - 1;
+ while ((isspace(*p)))
+ *p-- = 0;
+}
+
+/* Helper function to facilitate fgets() by Jean Sacren. */
+static void xfgets(char *str, int size, FILE *in)
+{
+ if (!fgets(str, size, in))
+ fprintf(stderr, "\nError in reading or end of file.\n");
+
+ if (!tty_stdio)
+ printf("%s", str);
+}
+
+static int conf_askvalue(struct symbol *sym, const char *def)
+{
+ enum symbol_type type = sym_get_type(sym);
+
+ if (!sym_has_value(sym))
+ printf("(NEW) ");
+
+ line[0] = '\n';
+ line[1] = 0;
+
+ if (!sym_is_changeable(sym)) {
+ printf("%s\n", def);
+ line[0] = '\n';
+ line[1] = 0;
+ return 0;
+ }
+
+ switch (input_mode) {
+ case oldconfig:
+ case syncconfig:
+ if (sym_has_value(sym)) {
+ printf("%s\n", def);
+ return 0;
+ }
+ /* fall through */
+ case oldaskconfig:
+ fflush(stdout);
+ xfgets(line, sizeof(line), stdin);
+ return 1;
+ default:
+ break;
+ }
+
+ switch (type) {
+ case S_INT:
+ case S_HEX:
+ case S_STRING:
+ printf("%s\n", def);
+ return 1;
+ default:
+ ;
+ }
+ printf("%s", line);
+ return 1;
+}
+
+static int conf_string(struct menu *menu)
+{
+ struct symbol *sym = menu->sym;
+ const char *def;
+
+ while (1) {
+ printf("%*s%s ", indent - 1, "", menu->prompt->text);
+ printf("(%s) ", sym->name);
+ def = sym_get_string_value(sym);
+ if (sym_get_string_value(sym))
+ printf("[%s] ", def);
+ if (!conf_askvalue(sym, def))
+ return 0;
+ switch (line[0]) {
+ case '\n':
+ break;
+ case '?':
+ /* print help */
+ if (line[1] == '\n') {
+ print_help(menu);
+ def = NULL;
+ break;
+ }
+ /* fall through */
+ default:
+ line[strlen(line)-1] = 0;
+ def = line;
+ }
+ if (def && sym_set_string_value(sym, def))
+ return 0;
+ }
+}
+
+static int conf_sym(struct menu *menu)
+{
+ struct symbol *sym = menu->sym;
+ tristate oldval, newval;
+
+ while (1) {
+ printf("%*s%s ", indent - 1, "", menu->prompt->text);
+ if (sym->name)
+ printf("(%s) ", sym->name);
+ putchar('[');
+ oldval = sym_get_tristate_value(sym);
+ switch (oldval) {
+ case no:
+ putchar('N');
+ break;
+ case mod:
+ putchar('M');
+ break;
+ case yes:
+ putchar('Y');
+ break;
+ }
+ if (oldval != no && sym_tristate_within_range(sym, no))
+ printf("/n");
+ if (oldval != mod && sym_tristate_within_range(sym, mod))
+ printf("/m");
+ if (oldval != yes && sym_tristate_within_range(sym, yes))
+ printf("/y");
+ printf("/?] ");
+ if (!conf_askvalue(sym, sym_get_string_value(sym)))
+ return 0;
+ strip(line);
+
+ switch (line[0]) {
+ case 'n':
+ case 'N':
+ newval = no;
+ if (!line[1] || !strcmp(&line[1], "o"))
+ break;
+ continue;
+ case 'm':
+ case 'M':
+ newval = mod;
+ if (!line[1])
+ break;
+ continue;
+ case 'y':
+ case 'Y':
+ newval = yes;
+ if (!line[1] || !strcmp(&line[1], "es"))
+ break;
+ continue;
+ case 0:
+ newval = oldval;
+ break;
+ case '?':
+ goto help;
+ default:
+ continue;
+ }
+ if (sym_set_tristate_value(sym, newval))
+ return 0;
+help:
+ print_help(menu);
+ }
+}
+
+static int conf_choice(struct menu *menu)
+{
+ struct symbol *sym, *def_sym;
+ struct menu *child;
+ bool is_new;
+
+ sym = menu->sym;
+ is_new = !sym_has_value(sym);
+ if (sym_is_changeable(sym)) {
+ conf_sym(menu);
+ sym_calc_value(sym);
+ switch (sym_get_tristate_value(sym)) {
+ case no:
+ return 1;
+ case mod:
+ return 0;
+ case yes:
+ break;
+ }
+ } else {
+ switch (sym_get_tristate_value(sym)) {
+ case no:
+ return 1;
+ case mod:
+ printf("%*s%s\n", indent - 1, "", menu_get_prompt(menu));
+ return 0;
+ case yes:
+ break;
+ }
+ }
+
+ while (1) {
+ int cnt, def;
+
+ printf("%*s%s\n", indent - 1, "", menu_get_prompt(menu));
+ def_sym = sym_get_choice_value(sym);
+ cnt = def = 0;
+ line[0] = 0;
+ for (child = menu->list; child; child = child->next) {
+ if (!menu_is_visible(child))
+ continue;
+ if (!child->sym) {
+ printf("%*c %s\n", indent, '*', menu_get_prompt(child));
+ continue;
+ }
+ cnt++;
+ if (child->sym == def_sym) {
+ def = cnt;
+ printf("%*c", indent, '>');
+ } else
+ printf("%*c", indent, ' ');
+ printf(" %d. %s", cnt, menu_get_prompt(child));
+ if (child->sym->name)
+ printf(" (%s)", child->sym->name);
+ if (!sym_has_value(child->sym))
+ printf(" (NEW)");
+ printf("\n");
+ }
+ printf("%*schoice", indent - 1, "");
+ if (cnt == 1) {
+ printf("[1]: 1\n");
+ goto conf_childs;
+ }
+ printf("[1-%d?]: ", cnt);
+ switch (input_mode) {
+ case oldconfig:
+ case syncconfig:
+ if (!is_new) {
+ cnt = def;
+ printf("%d\n", cnt);
+ break;
+ }
+ /* fall through */
+ case oldaskconfig:
+ fflush(stdout);
+ xfgets(line, sizeof(line), stdin);
+ strip(line);
+ if (line[0] == '?') {
+ print_help(menu);
+ continue;
+ }
+ if (!line[0])
+ cnt = def;
+ else if (isdigit(line[0]))
+ cnt = atoi(line);
+ else
+ continue;
+ break;
+ default:
+ break;
+ }
+
+ conf_childs:
+ for (child = menu->list; child; child = child->next) {
+ if (!child->sym || !menu_is_visible(child))
+ continue;
+ if (!--cnt)
+ break;
+ }
+ if (!child)
+ continue;
+ if (line[0] && line[strlen(line) - 1] == '?') {
+ print_help(child);
+ continue;
+ }
+ sym_set_choice_value(sym, child->sym);
+ for (child = child->list; child; child = child->next) {
+ indent += 2;
+ conf(child);
+ indent -= 2;
+ }
+ return 1;
+ }
+}
+
+static void conf(struct menu *menu)
+{
+ struct symbol *sym;
+ struct property *prop;
+ struct menu *child;
+
+ if (!menu_is_visible(menu))
+ return;
+
+ sym = menu->sym;
+ prop = menu->prompt;
+ if (prop) {
+ const char *prompt;
+
+ switch (prop->type) {
+ case P_MENU:
+ /*
+ * Except in oldaskconfig mode, we show only menus that
+ * contain new symbols.
+ */
+ if (input_mode != oldaskconfig && rootEntry != menu) {
+ check_conf(menu);
+ return;
+ }
+ /* fall through */
+ case P_COMMENT:
+ prompt = menu_get_prompt(menu);
+ if (prompt)
+ printf("%*c\n%*c %s\n%*c\n",
+ indent, '*',
+ indent, '*', prompt,
+ indent, '*');
+ default:
+ ;
+ }
+ }
+
+ if (!sym)
+ goto conf_childs;
+
+ if (sym_is_choice(sym)) {
+ conf_choice(menu);
+ if (sym->curr.tri != mod)
+ return;
+ goto conf_childs;
+ }
+
+ switch (sym->type) {
+ case S_INT:
+ case S_HEX:
+ case S_STRING:
+ conf_string(menu);
+ break;
+ default:
+ conf_sym(menu);
+ break;
+ }
+
+conf_childs:
+ if (sym)
+ indent += 2;
+ for (child = menu->list; child; child = child->next)
+ conf(child);
+ if (sym)
+ indent -= 2;
+}
+
+static void check_conf(struct menu *menu)
+{
+ struct symbol *sym;
+ struct menu *child;
+
+ if (!menu_is_visible(menu))
+ return;
+
+ sym = menu->sym;
+ if (sym && !sym_has_value(sym)) {
+ if (sym_is_changeable(sym) ||
+ (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)) {
+ if (input_mode == listnewconfig) {
+ if (sym->name) {
+ const char *str;
+
+ if (sym->type == S_STRING) {
+ str = sym_get_string_value(sym);
+ str = sym_escape_string_value(str);
+ printf("%s%s=%s\n", CONFIG_, sym->name, str);
+ free((void *)str);
+ } else {
+ str = sym_get_string_value(sym);
+ printf("%s%s=%s\n", CONFIG_, sym->name, str);
+ }
+ }
+ } else if (input_mode == helpnewconfig) {
+ printf("-----\n");
+ print_help(menu);
+ printf("-----\n");
+
+ } else {
+ if (!conf_cnt++)
+ printf("*\n* Restart config...\n*\n");
+ rootEntry = menu_get_parent_menu(menu);
+ conf(rootEntry);
+ }
+ }
+ }
+
+ for (child = menu->list; child; child = child->next)
+ check_conf(child);
+}
+
+static struct option long_opts[] = {
+ {"oldaskconfig", no_argument, NULL, oldaskconfig},
+ {"oldconfig", no_argument, NULL, oldconfig},
+ {"syncconfig", no_argument, NULL, syncconfig},
+ {"defconfig", required_argument, NULL, defconfig},
+ {"savedefconfig", required_argument, NULL, savedefconfig},
+ {"allnoconfig", no_argument, NULL, allnoconfig},
+ {"allyesconfig", no_argument, NULL, allyesconfig},
+ {"allmodconfig", no_argument, NULL, allmodconfig},
+ {"alldefconfig", no_argument, NULL, alldefconfig},
+ {"randconfig", no_argument, NULL, randconfig},
+ {"listnewconfig", no_argument, NULL, listnewconfig},
+ {"helpnewconfig", no_argument, NULL, helpnewconfig},
+ {"olddefconfig", no_argument, NULL, olddefconfig},
+ {"yes2modconfig", no_argument, NULL, yes2modconfig},
+ {"mod2yesconfig", no_argument, NULL, mod2yesconfig},
+ {NULL, 0, NULL, 0}
+};
+
+static void conf_usage(const char *progname)
+{
+
+ printf("Usage: %s [-s] [option] <kconfig-file>\n", progname);
+ printf("[option] is _one_ of the following:\n");
+ printf(" --listnewconfig List new options\n");
+ printf(" --helpnewconfig List new options and help text\n");
+ printf(" --oldaskconfig Start a new configuration using a line-oriented program\n");
+ printf(" --oldconfig Update a configuration using a provided .config as base\n");
+ printf(" --syncconfig Similar to oldconfig but generates configuration in\n"
+ " include/{generated/,config/}\n");
+ printf(" --olddefconfig Same as oldconfig but sets new symbols to their default value\n");
+ printf(" --defconfig <file> New config with default defined in <file>\n");
+ printf(" --savedefconfig <file> Save the minimal current configuration to <file>\n");
+ printf(" --allnoconfig New config where all options are answered with no\n");
+ printf(" --allyesconfig New config where all options are answered with yes\n");
+ printf(" --allmodconfig New config where all options are answered with mod\n");
+ printf(" --alldefconfig New config with all symbols set to default\n");
+ printf(" --randconfig New config with random answer to all options\n");
+ printf(" --yes2modconfig Change answers from yes to mod if possible\n");
+ printf(" --mod2yesconfig Change answers from mod to yes if possible\n");
+}
+
+int main(int ac, char **av)
+{
+ const char *progname = av[0];
+ int opt;
+ const char *name, *defconfig_file = NULL /* gcc uninit */;
+ int no_conf_write = 0;
+
+ tty_stdio = isatty(0) && isatty(1);
+
+ while ((opt = getopt_long(ac, av, "s", long_opts, NULL)) != -1) {
+ if (opt == 's') {
+ conf_set_message_callback(NULL);
+ continue;
+ }
+ input_mode = (enum input_mode)opt;
+ switch (opt) {
+ case syncconfig:
+ /*
+ * syncconfig is invoked during the build stage.
+ * Suppress distracting "configuration written to ..."
+ */
+ conf_set_message_callback(NULL);
+ sync_kconfig = 1;
+ break;
+ case defconfig:
+ case savedefconfig:
+ defconfig_file = optarg;
+ break;
+ case randconfig:
+ {
+ struct timeval now;
+ unsigned int seed;
+ char *seed_env;
+
+ /*
+ * Use microseconds derived seed,
+ * compensate for systems where it may be zero
+ */
+ gettimeofday(&now, NULL);
+ seed = (unsigned int)((now.tv_sec + 1) * (now.tv_usec + 1));
+
+ seed_env = getenv("KCONFIG_SEED");
+ if( seed_env && *seed_env ) {
+ char *endp;
+ int tmp = (int)strtol(seed_env, &endp, 0);
+ if (*endp == '\0') {
+ seed = tmp;
+ }
+ }
+ fprintf( stderr, "KCONFIG_SEED=0x%X\n", seed );
+ srand(seed);
+ break;
+ }
+ case oldaskconfig:
+ case oldconfig:
+ case allnoconfig:
+ case allyesconfig:
+ case allmodconfig:
+ case alldefconfig:
+ case listnewconfig:
+ case helpnewconfig:
+ case olddefconfig:
+ case yes2modconfig:
+ case mod2yesconfig:
+ break;
+ case '?':
+ conf_usage(progname);
+ exit(1);
+ break;
+ }
+ }
+ if (ac == optind) {
+ fprintf(stderr, "%s: Kconfig file missing\n", av[0]);
+ conf_usage(progname);
+ exit(1);
+ }
+ name = av[optind];
+ conf_parse(name);
+ //zconfdump(stdout);
+
+ switch (input_mode) {
+ case defconfig:
+ if (conf_read(defconfig_file)) {
+ fprintf(stderr,
+ "***\n"
+ "*** Can't find default configuration \"%s\"!\n"
+ "***\n",
+ defconfig_file);
+ exit(1);
+ }
+ break;
+ case savedefconfig:
+ case syncconfig:
+ case oldaskconfig:
+ case oldconfig:
+ case listnewconfig:
+ case helpnewconfig:
+ case olddefconfig:
+ case yes2modconfig:
+ case mod2yesconfig:
+ conf_read(NULL);
+ break;
+ case allnoconfig:
+ case allyesconfig:
+ case allmodconfig:
+ case alldefconfig:
+ case randconfig:
+ name = getenv("KCONFIG_ALLCONFIG");
+ if (!name)
+ break;
+ if ((strcmp(name, "") != 0) && (strcmp(name, "1") != 0)) {
+ if (conf_read_simple(name, S_DEF_USER)) {
+ fprintf(stderr,
+ "*** Can't read seed configuration \"%s\"!\n",
+ name);
+ exit(1);
+ }
+ break;
+ }
+ switch (input_mode) {
+ case allnoconfig: name = "allno.config"; break;
+ case allyesconfig: name = "allyes.config"; break;
+ case allmodconfig: name = "allmod.config"; break;
+ case alldefconfig: name = "alldef.config"; break;
+ case randconfig: name = "allrandom.config"; break;
+ default: break;
+ }
+ if (conf_read_simple(name, S_DEF_USER) &&
+ conf_read_simple("all.config", S_DEF_USER)) {
+ fprintf(stderr,
+ "*** KCONFIG_ALLCONFIG set, but no \"%s\" or \"all.config\" file found\n",
+ name);
+ exit(1);
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (sync_kconfig) {
+ name = getenv("KCONFIG_NOSILENTUPDATE");
+ if (name && *name) {
+ if (conf_get_changed()) {
+ fprintf(stderr,
+ "\n*** The configuration requires explicit update.\n\n");
+ return 1;
+ }
+ no_conf_write = 1;
+ }
+ }
+
+ switch (input_mode) {
+ case allnoconfig:
+ conf_set_all_new_symbols(def_no);
+ break;
+ case allyesconfig:
+ conf_set_all_new_symbols(def_yes);
+ break;
+ case allmodconfig:
+ conf_set_all_new_symbols(def_mod);
+ break;
+ case alldefconfig:
+ conf_set_all_new_symbols(def_default);
+ break;
+ case randconfig:
+ /* Really nothing to do in this loop */
+ while (conf_set_all_new_symbols(def_random)) ;
+ break;
+ case defconfig:
+ conf_set_all_new_symbols(def_default);
+ break;
+ case savedefconfig:
+ break;
+ case yes2modconfig:
+ conf_rewrite_mod_or_yes(def_y2m);
+ break;
+ case mod2yesconfig:
+ conf_rewrite_mod_or_yes(def_m2y);
+ break;
+ case oldaskconfig:
+ rootEntry = &rootmenu;
+ conf(&rootmenu);
+ input_mode = oldconfig;
+ /* fall through */
+ case oldconfig:
+ case listnewconfig:
+ case helpnewconfig:
+ case syncconfig:
+ /* Update until a loop caused no more changes */
+ do {
+ conf_cnt = 0;
+ check_conf(&rootmenu);
+ } while (conf_cnt);
+ break;
+ case olddefconfig:
+ default:
+ break;
+ }
+
+ if (input_mode == savedefconfig) {
+ if (conf_write_defconfig(defconfig_file)) {
+ fprintf(stderr, "n*** Error while saving defconfig to: %s\n\n",
+ defconfig_file);
+ return 1;
+ }
+ } else if (input_mode != listnewconfig && input_mode != helpnewconfig) {
+ if (!no_conf_write && conf_write(NULL)) {
+ fprintf(stderr, "\n*** Error during writing of the configuration.\n\n");
+ exit(1);
+ }
+
+ /*
+ * Create auto.conf if it does not exist.
+ * This prevents GNU Make 4.1 or older from emitting
+ * "include/config/auto.conf: No such file or directory"
+ * in the top-level Makefile
+ *
+ * syncconfig always creates or updates auto.conf because it is
+ * used during the build.
+ */
+ if (conf_write_autoconf(sync_kconfig) && sync_kconfig) {
+ fprintf(stderr,
+ "\n*** Error during sync of the configuration.\n\n");
+ return 1;
+ }
+ }
+ return 0;
+}
Index: OrangePi/create-5.10.110-host-limits-patch/linux-orangepi-5.10.110-new/scripts/kconfig/confdata.c
===================================================================
--- OrangePi/create-5.10.110-host-limits-patch/linux-orangepi-5.10.110-new/scripts/kconfig/confdata.c (nonexistent)
+++ OrangePi/create-5.10.110-host-limits-patch/linux-orangepi-5.10.110-new/scripts/kconfig/confdata.c (revision 385)
@@ -0,0 +1,1343 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ */
+
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <linux/limits.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "lkc.h"
+
+/* return true if 'path' exists, false otherwise */
+static bool is_present(const char *path)
+{
+ struct stat st;
+
+ return !stat(path, &st);
+}
+
+/* return true if 'path' exists and it is a directory, false otherwise */
+static bool is_dir(const char *path)
+{
+ struct stat st;
+
+ if (stat(path, &st))
+ return 0;
+
+ return S_ISDIR(st.st_mode);
+}
+
+/* return true if the given two files are the same, false otherwise */
+static bool is_same(const char *file1, const char *file2)
+{
+ int fd1, fd2;
+ struct stat st1, st2;
+ void *map1, *map2;
+ bool ret = false;
+
+ fd1 = open(file1, O_RDONLY);
+ if (fd1 < 0)
+ return ret;
+
+ fd2 = open(file2, O_RDONLY);
+ if (fd2 < 0)
+ goto close1;
+
+ ret = fstat(fd1, &st1);
+ if (ret)
+ goto close2;
+ ret = fstat(fd2, &st2);
+ if (ret)
+ goto close2;
+
+ if (st1.st_size != st2.st_size)
+ goto close2;
+
+ map1 = mmap(NULL, st1.st_size, PROT_READ, MAP_PRIVATE, fd1, 0);
+ if (map1 == MAP_FAILED)
+ goto close2;
+
+ map2 = mmap(NULL, st2.st_size, PROT_READ, MAP_PRIVATE, fd2, 0);
+ if (map2 == MAP_FAILED)
+ goto close2;
+
+ if (bcmp(map1, map2, st1.st_size))
+ goto close2;
+
+ ret = true;
+close2:
+ close(fd2);
+close1:
+ close(fd1);
+
+ return ret;
+}
+
+/*
+ * Create the parent directory of the given path.
+ *
+ * For example, if 'include/config/auto.conf' is given, create 'include/config'.
+ */
+static int make_parent_dir(const char *path)
+{
+ char tmp[PATH_MAX + 1];
+ char *p;
+
+ strncpy(tmp, path, sizeof(tmp));
+ tmp[sizeof(tmp) - 1] = 0;
+
+ /* Remove the base name. Just return if nothing is left */
+ p = strrchr(tmp, '/');
+ if (!p)
+ return 0;
+ *(p + 1) = 0;
+
+ /* Just in case it is an absolute path */
+ p = tmp;
+ while (*p == '/')
+ p++;
+
+ while ((p = strchr(p, '/'))) {
+ *p = 0;
+
+ /* skip if the directory exists */
+ if (!is_dir(tmp) && mkdir(tmp, 0755))
+ return -1;
+
+ *p = '/';
+ while (*p == '/')
+ p++;
+ }
+
+ return 0;
+}
+
+static char depfile_path[PATH_MAX];
+static size_t depfile_prefix_len;
+
+/* touch depfile for symbol 'name' */
+static int conf_touch_dep(const char *name)
+{
+ int fd, ret;
+ const char *s;
+ char *d, c;
+
+ /* check overflow: prefix + name + ".h" + '\0' must fit in buffer. */
+ if (depfile_prefix_len + strlen(name) + 3 > sizeof(depfile_path))
+ return -1;
+
+ d = depfile_path + depfile_prefix_len;
+ s = name;
+
+ while ((c = *s++))
+ *d++ = (c == '_') ? '/' : tolower(c);
+ strcpy(d, ".h");
+
+ /* Assume directory path already exists. */
+ fd = open(depfile_path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
+ if (fd == -1) {
+ if (errno != ENOENT)
+ return -1;
+
+ ret = make_parent_dir(depfile_path);
+ if (ret)
+ return ret;
+
+ /* Try it again. */
+ fd = open(depfile_path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
+ if (fd == -1)
+ return -1;
+ }
+ close(fd);
+
+ return 0;
+}
+
+struct conf_printer {
+ void (*print_symbol)(FILE *, struct symbol *, const char *, void *);
+ void (*print_comment)(FILE *, const char *, void *);
+};
+
+static void conf_warning(const char *fmt, ...)
+ __attribute__ ((format (printf, 1, 2)));
+
+static void conf_message(const char *fmt, ...)
+ __attribute__ ((format (printf, 1, 2)));
+
+static const char *conf_filename;
+static int conf_lineno, conf_warnings;
+
+static void conf_warning(const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ fprintf(stderr, "%s:%d:warning: ", conf_filename, conf_lineno);
+ vfprintf(stderr, fmt, ap);
+ fprintf(stderr, "\n");
+ va_end(ap);
+ conf_warnings++;
+}
+
+static void conf_default_message_callback(const char *s)
+{
+ printf("#\n# ");
+ printf("%s", s);
+ printf("\n#\n");
+}
+
+static void (*conf_message_callback)(const char *s) =
+ conf_default_message_callback;
+void conf_set_message_callback(void (*fn)(const char *s))
+{
+ conf_message_callback = fn;
+}
+
+static void conf_message(const char *fmt, ...)
+{
+ va_list ap;
+ char buf[4096];
+
+ if (!conf_message_callback)
+ return;
+
+ va_start(ap, fmt);
+
+ vsnprintf(buf, sizeof(buf), fmt, ap);
+ conf_message_callback(buf);
+ va_end(ap);
+}
+
+const char *conf_get_configname(void)
+{
+ char *name = getenv("KCONFIG_CONFIG");
+
+ return name ? name : ".config";
+}
+
+static const char *conf_get_autoconfig_name(void)
+{
+ char *name = getenv("KCONFIG_AUTOCONFIG");
+
+ return name ? name : "include/config/auto.conf";
+}
+
+static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p)
+{
+ char *p2;
+
+ switch (sym->type) {
+ case S_TRISTATE:
+ if (p[0] == 'm') {
+ sym->def[def].tri = mod;
+ sym->flags |= def_flags;
+ break;
+ }
+ /* fall through */
+ case S_BOOLEAN:
+ if (p[0] == 'y') {
+ sym->def[def].tri = yes;
+ sym->flags |= def_flags;
+ break;
+ }
+ if (p[0] == 'n') {
+ sym->def[def].tri = no;
+ sym->flags |= def_flags;
+ break;
+ }
+ if (def != S_DEF_AUTO)
+ conf_warning("symbol value '%s' invalid for %s",
+ p, sym->name);
+ return 1;
+ case S_STRING:
+ if (*p++ != '"')
+ break;
+ for (p2 = p; (p2 = strpbrk(p2, "\"\\")); p2++) {
+ if (*p2 == '"') {
+ *p2 = 0;
+ break;
+ }
+ memmove(p2, p2 + 1, strlen(p2));
+ }
+ if (!p2) {
+ if (def != S_DEF_AUTO)
+ conf_warning("invalid string found");
+ return 1;
+ }
+ /* fall through */
+ case S_INT:
+ case S_HEX:
+ if (sym_string_valid(sym, p)) {
+ sym->def[def].val = xstrdup(p);
+ sym->flags |= def_flags;
+ } else {
+ if (def != S_DEF_AUTO)
+ conf_warning("symbol value '%s' invalid for %s",
+ p, sym->name);
+ return 1;
+ }
+ break;
+ default:
+ ;
+ }
+ return 0;
+}
+
+#define LINE_GROWTH 16
+static int add_byte(int c, char **lineptr, size_t slen, size_t *n)
+{
+ char *nline;
+ size_t new_size = slen + 1;
+ if (new_size > *n) {
+ new_size += LINE_GROWTH - 1;
+ new_size *= 2;
+ nline = xrealloc(*lineptr, new_size);
+ if (!nline)
+ return -1;
+
+ *lineptr = nline;
+ *n = new_size;
+ }
+
+ (*lineptr)[slen] = c;
+
+ return 0;
+}
+
+static ssize_t compat_getline(char **lineptr, size_t *n, FILE *stream)
+{
+ char *line = *lineptr;
+ size_t slen = 0;
+
+ for (;;) {
+ int c = getc(stream);
+
+ switch (c) {
+ case '\n':
+ if (add_byte(c, &line, slen, n) < 0)
+ goto e_out;
+ slen++;
+ /* fall through */
+ case EOF:
+ if (add_byte('\0', &line, slen, n) < 0)
+ goto e_out;
+ *lineptr = line;
+ if (slen == 0)
+ return -1;
+ return slen;
+ default:
+ if (add_byte(c, &line, slen, n) < 0)
+ goto e_out;
+ slen++;
+ }
+ }
+
+e_out:
+ line[slen-1] = '\0';
+ *lineptr = line;
+ return -1;
+}
+
+int conf_read_simple(const char *name, int def)
+{
+ FILE *in = NULL;
+ char *line = NULL;
+ size_t line_asize = 0;
+ char *p, *p2;
+ struct symbol *sym;
+ int i, def_flags;
+
+ if (name) {
+ in = zconf_fopen(name);
+ } else {
+ struct property *prop;
+
+ name = conf_get_configname();
+ in = zconf_fopen(name);
+ if (in)
+ goto load;
+ sym_add_change_count(1);
+ if (!sym_defconfig_list)
+ return 1;
+
+ for_all_defaults(sym_defconfig_list, prop) {
+ if (expr_calc_value(prop->visible.expr) == no ||
+ prop->expr->type != E_SYMBOL)
+ continue;
+ sym_calc_value(prop->expr->left.sym);
+ name = sym_get_string_value(prop->expr->left.sym);
+ in = zconf_fopen(name);
+ if (in) {
+ conf_message("using defaults found in %s",
+ name);
+ goto load;
+ }
+ }
+ }
+ if (!in)
+ return 1;
+
+load:
+ conf_filename = name;
+ conf_lineno = 0;
+ conf_warnings = 0;
+
+ def_flags = SYMBOL_DEF << def;
+ for_all_symbols(i, sym) {
+ sym->flags |= SYMBOL_CHANGED;
+ sym->flags &= ~(def_flags|SYMBOL_VALID);
+ if (sym_is_choice(sym))
+ sym->flags |= def_flags;
+ switch (sym->type) {
+ case S_INT:
+ case S_HEX:
+ case S_STRING:
+ if (sym->def[def].val)
+ free(sym->def[def].val);
+ /* fall through */
+ default:
+ sym->def[def].val = NULL;
+ sym->def[def].tri = no;
+ }
+ }
+
+ while (compat_getline(&line, &line_asize, in) != -1) {
+ conf_lineno++;
+ sym = NULL;
+ if (line[0] == '#') {
+ if (memcmp(line + 2, CONFIG_, strlen(CONFIG_)))
+ continue;
+ p = strchr(line + 2 + strlen(CONFIG_), ' ');
+ if (!p)
+ continue;
+ *p++ = 0;
+ if (strncmp(p, "is not set", 10))
+ continue;
+ if (def == S_DEF_USER) {
+ sym = sym_find(line + 2 + strlen(CONFIG_));
+ if (!sym) {
+ sym_add_change_count(1);
+ continue;
+ }
+ } else {
+ sym = sym_lookup(line + 2 + strlen(CONFIG_), 0);
+ if (sym->type == S_UNKNOWN)
+ sym->type = S_BOOLEAN;
+ }
+ if (sym->flags & def_flags) {
+ conf_warning("override: reassigning to symbol %s", sym->name);
+ }
+ switch (sym->type) {
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ sym->def[def].tri = no;
+ sym->flags |= def_flags;
+ break;
+ default:
+ ;
+ }
+ } else if (memcmp(line, CONFIG_, strlen(CONFIG_)) == 0) {
+ p = strchr(line + strlen(CONFIG_), '=');
+ if (!p)
+ continue;
+ *p++ = 0;
+ p2 = strchr(p, '\n');
+ if (p2) {
+ *p2-- = 0;
+ if (*p2 == '\r')
+ *p2 = 0;
+ }
+
+ sym = sym_find(line + strlen(CONFIG_));
+ if (!sym) {
+ if (def == S_DEF_AUTO)
+ /*
+ * Reading from include/config/auto.conf
+ * If CONFIG_FOO previously existed in
+ * auto.conf but it is missing now,
+ * include/config/foo.h must be touched.
+ */
+ conf_touch_dep(line + strlen(CONFIG_));
+ else
+ sym_add_change_count(1);
+ continue;
+ }
+
+ if (sym->flags & def_flags) {
+ conf_warning("override: reassigning to symbol %s", sym->name);
+ }
+ if (conf_set_sym_val(sym, def, def_flags, p))
+ continue;
+ } else {
+ if (line[0] != '\r' && line[0] != '\n')
+ conf_warning("unexpected data: %.*s",
+ (int)strcspn(line, "\r\n"), line);
+
+ continue;
+ }
+
+ if (sym && sym_is_choice_value(sym)) {
+ struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym));
+ switch (sym->def[def].tri) {
+ case no:
+ break;
+ case mod:
+ if (cs->def[def].tri == yes) {
+ conf_warning("%s creates inconsistent choice state", sym->name);
+ cs->flags &= ~def_flags;
+ }
+ break;
+ case yes:
+ if (cs->def[def].tri != no)
+ conf_warning("override: %s changes choice state", sym->name);
+ cs->def[def].val = sym;
+ break;
+ }
+ cs->def[def].tri = EXPR_OR(cs->def[def].tri, sym->def[def].tri);
+ }
+ }
+ free(line);
+ fclose(in);
+ return 0;
+}
+
+int conf_read(const char *name)
+{
+ struct symbol *sym;
+ int conf_unsaved = 0;
+ int i;
+
+ sym_set_change_count(0);
+
+ if (conf_read_simple(name, S_DEF_USER)) {
+ sym_calc_value(modules_sym);
+ return 1;
+ }
+
+ sym_calc_value(modules_sym);
+
+ for_all_symbols(i, sym) {
+ sym_calc_value(sym);
+ if (sym_is_choice(sym) || (sym->flags & SYMBOL_NO_WRITE))
+ continue;
+ if (sym_has_value(sym) && (sym->flags & SYMBOL_WRITE)) {
+ /* check that calculated value agrees with saved value */
+ switch (sym->type) {
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ if (sym->def[S_DEF_USER].tri == sym_get_tristate_value(sym))
+ continue;
+ break;
+ default:
+ if (!strcmp(sym->curr.val, sym->def[S_DEF_USER].val))
+ continue;
+ break;
+ }
+ } else if (!sym_has_value(sym) && !(sym->flags & SYMBOL_WRITE))
+ /* no previous value and not saved */
+ continue;
+ conf_unsaved++;
+ /* maybe print value in verbose mode... */
+ }
+
+ for_all_symbols(i, sym) {
+ if (sym_has_value(sym) && !sym_is_choice_value(sym)) {
+ /* Reset values of generates values, so they'll appear
+ * as new, if they should become visible, but that
+ * doesn't quite work if the Kconfig and the saved
+ * configuration disagree.
+ */
+ if (sym->visible == no && !conf_unsaved)
+ sym->flags &= ~SYMBOL_DEF_USER;
+ switch (sym->type) {
+ case S_STRING:
+ case S_INT:
+ case S_HEX:
+ /* Reset a string value if it's out of range */
+ if (sym_string_within_range(sym, sym->def[S_DEF_USER].val))
+ break;
+ sym->flags &= ~(SYMBOL_VALID|SYMBOL_DEF_USER);
+ conf_unsaved++;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ sym_add_change_count(conf_warnings || conf_unsaved);
+
+ return 0;
+}
+
+/*
+ * Kconfig configuration printer
+ *
+ * This printer is used when generating the resulting configuration after
+ * kconfig invocation and `defconfig' files. Unset symbol might be omitted by
+ * passing a non-NULL argument to the printer.
+ *
+ */
+static void
+kconfig_print_symbol(FILE *fp, struct symbol *sym, const char *value, void *arg)
+{
+
+ switch (sym->type) {
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ if (*value == 'n') {
+ bool skip_unset = (arg != NULL);
+
+ if (!skip_unset)
+ fprintf(fp, "# %s%s is not set\n",
+ CONFIG_, sym->name);
+ return;
+ }
+ break;
+ default:
+ break;
+ }
+
+ fprintf(fp, "%s%s=%s\n", CONFIG_, sym->name, value);
+}
+
+static void
+kconfig_print_comment(FILE *fp, const char *value, void *arg)
+{
+ const char *p = value;
+ size_t l;
+
+ for (;;) {
+ l = strcspn(p, "\n");
+ fprintf(fp, "#");
+ if (l) {
+ fprintf(fp, " ");
+ xfwrite(p, l, 1, fp);
+ p += l;
+ }
+ fprintf(fp, "\n");
+ if (*p++ == '\0')
+ break;
+ }
+}
+
+static struct conf_printer kconfig_printer_cb =
+{
+ .print_symbol = kconfig_print_symbol,
+ .print_comment = kconfig_print_comment,
+};
+
+/*
+ * Header printer
+ *
+ * This printer is used when generating the `include/generated/autoconf.h' file.
+ */
+static void
+header_print_symbol(FILE *fp, struct symbol *sym, const char *value, void *arg)
+{
+
+ switch (sym->type) {
+ case S_BOOLEAN:
+ case S_TRISTATE: {
+ const char *suffix = "";
+
+ switch (*value) {
+ case 'n':
+ break;
+ case 'm':
+ suffix = "_MODULE";
+ /* fall through */
+ default:
+ fprintf(fp, "#define %s%s%s 1\n",
+ CONFIG_, sym->name, suffix);
+ }
+ break;
+ }
+ case S_HEX: {
+ const char *prefix = "";
+
+ if (value[0] != '0' || (value[1] != 'x' && value[1] != 'X'))
+ prefix = "0x";
+ fprintf(fp, "#define %s%s %s%s\n",
+ CONFIG_, sym->name, prefix, value);
+ break;
+ }
+ case S_STRING:
+ case S_INT:
+ fprintf(fp, "#define %s%s %s\n",
+ CONFIG_, sym->name, value);
+ break;
+ default:
+ break;
+ }
+
+}
+
+static void
+header_print_comment(FILE *fp, const char *value, void *arg)
+{
+ const char *p = value;
+ size_t l;
+
+ fprintf(fp, "/*\n");
+ for (;;) {
+ l = strcspn(p, "\n");
+ fprintf(fp, " *");
+ if (l) {
+ fprintf(fp, " ");
+ xfwrite(p, l, 1, fp);
+ p += l;
+ }
+ fprintf(fp, "\n");
+ if (*p++ == '\0')
+ break;
+ }
+ fprintf(fp, " */\n");
+}
+
+static struct conf_printer header_printer_cb =
+{
+ .print_symbol = header_print_symbol,
+ .print_comment = header_print_comment,
+};
+
+static void conf_write_symbol(FILE *fp, struct symbol *sym,
+ struct conf_printer *printer, void *printer_arg)
+{
+ const char *str;
+
+ switch (sym->type) {
+ case S_UNKNOWN:
+ break;
+ case S_STRING:
+ str = sym_get_string_value(sym);
+ str = sym_escape_string_value(str);
+ printer->print_symbol(fp, sym, str, printer_arg);
+ free((void *)str);
+ break;
+ default:
+ str = sym_get_string_value(sym);
+ printer->print_symbol(fp, sym, str, printer_arg);
+ }
+}
+
+static void
+conf_write_heading(FILE *fp, struct conf_printer *printer, void *printer_arg)
+{
+ char buf[256];
+
+ snprintf(buf, sizeof(buf),
+ "\n"
+ "Automatically generated file; DO NOT EDIT.\n"
+ "%s\n",
+ rootmenu.prompt->text);
+
+ printer->print_comment(fp, buf, printer_arg);
+}
+
+/*
+ * Write out a minimal config.
+ * All values that has default values are skipped as this is redundant.
+ */
+int conf_write_defconfig(const char *filename)
+{
+ struct symbol *sym;
+ struct menu *menu;
+ FILE *out;
+
+ out = fopen(filename, "w");
+ if (!out)
+ return 1;
+
+ sym_clear_all_valid();
+
+ /* Traverse all menus to find all relevant symbols */
+ menu = rootmenu.list;
+
+ while (menu != NULL)
+ {
+ sym = menu->sym;
+ if (sym == NULL) {
+ if (!menu_is_visible(menu))
+ goto next_menu;
+ } else if (!sym_is_choice(sym)) {
+ sym_calc_value(sym);
+ if (!(sym->flags & SYMBOL_WRITE))
+ goto next_menu;
+ sym->flags &= ~SYMBOL_WRITE;
+ /* If we cannot change the symbol - skip */
+ if (!sym_is_changeable(sym))
+ goto next_menu;
+ /* If symbol equals to default value - skip */
+ if (strcmp(sym_get_string_value(sym), sym_get_string_default(sym)) == 0)
+ goto next_menu;
+
+ /*
+ * If symbol is a choice value and equals to the
+ * default for a choice - skip.
+ * But only if value is bool and equal to "y" and
+ * choice is not "optional".
+ * (If choice is "optional" then all values can be "n")
+ */
+ if (sym_is_choice_value(sym)) {
+ struct symbol *cs;
+ struct symbol *ds;
+
+ cs = prop_get_symbol(sym_get_choice_prop(sym));
+ ds = sym_choice_default(cs);
+ if (!sym_is_optional(cs) && sym == ds) {
+ if ((sym->type == S_BOOLEAN) &&
+ sym_get_tristate_value(sym) == yes)
+ goto next_menu;
+ }
+ }
+ conf_write_symbol(out, sym, &kconfig_printer_cb, NULL);
+ }
+next_menu:
+ if (menu->list != NULL) {
+ menu = menu->list;
+ }
+ else if (menu->next != NULL) {
+ menu = menu->next;
+ } else {
+ while ((menu = menu->parent)) {
+ if (menu->next != NULL) {
+ menu = menu->next;
+ break;
+ }
+ }
+ }
+ }
+ fclose(out);
+ return 0;
+}
+
+int conf_write(const char *name)
+{
+ FILE *out;
+ struct symbol *sym;
+ struct menu *menu;
+ const char *str;
+ char tmpname[PATH_MAX + 1], oldname[PATH_MAX + 1];
+ char *env;
+ int i;
+ bool need_newline = false;
+
+ if (!name)
+ name = conf_get_configname();
+
+ if (!*name) {
+ fprintf(stderr, "config name is empty\n");
+ return -1;
+ }
+
+ if (is_dir(name)) {
+ fprintf(stderr, "%s: Is a directory\n", name);
+ return -1;
+ }
+
+ if (make_parent_dir(name))
+ return -1;
+
+ env = getenv("KCONFIG_OVERWRITECONFIG");
+ if (env && *env) {
+ *tmpname = 0;
+ out = fopen(name, "w");
+ } else {
+ snprintf(tmpname, sizeof(tmpname), "%s.%d.tmp",
+ name, (int)getpid());
+ out = fopen(tmpname, "w");
+ }
+ if (!out)
+ return 1;
+
+ conf_write_heading(out, &kconfig_printer_cb, NULL);
+
+ if (!conf_get_changed())
+ sym_clear_all_valid();
+
+ menu = rootmenu.list;
+ while (menu) {
+ sym = menu->sym;
+ if (!sym) {
+ if (!menu_is_visible(menu))
+ goto next;
+ str = menu_get_prompt(menu);
+ fprintf(out, "\n"
+ "#\n"
+ "# %s\n"
+ "#\n", str);
+ need_newline = false;
+ } else if (!(sym->flags & SYMBOL_CHOICE) &&
+ !(sym->flags & SYMBOL_WRITTEN)) {
+ sym_calc_value(sym);
+ if (!(sym->flags & SYMBOL_WRITE))
+ goto next;
+ if (need_newline) {
+ fprintf(out, "\n");
+ need_newline = false;
+ }
+ sym->flags |= SYMBOL_WRITTEN;
+ conf_write_symbol(out, sym, &kconfig_printer_cb, NULL);
+ }
+
+next:
+ if (menu->list) {
+ menu = menu->list;
+ continue;
+ }
+ if (menu->next)
+ menu = menu->next;
+ else while ((menu = menu->parent)) {
+ if (!menu->sym && menu_is_visible(menu) &&
+ menu != &rootmenu) {
+ str = menu_get_prompt(menu);
+ fprintf(out, "# end of %s\n", str);
+ need_newline = true;
+ }
+ if (menu->next) {
+ menu = menu->next;
+ break;
+ }
+ }
+ }
+ fclose(out);
+
+ for_all_symbols(i, sym)
+ sym->flags &= ~SYMBOL_WRITTEN;
+
+ if (*tmpname) {
+ if (is_same(name, tmpname)) {
+ conf_message("No change to %s", name);
+ unlink(tmpname);
+ sym_set_change_count(0);
+ return 0;
+ }
+
+ snprintf(oldname, sizeof(oldname), "%s.old", name);
+ rename(name, oldname);
+ if (rename(tmpname, name))
+ return 1;
+ }
+
+ conf_message("configuration written to %s", name);
+
+ sym_set_change_count(0);
+
+ return 0;
+}
+
+/* write a dependency file as used by kbuild to track dependencies */
+static int conf_write_dep(const char *name)
+{
+ struct file *file;
+ FILE *out;
+
+ out = fopen("..config.tmp", "w");
+ if (!out)
+ return 1;
+ fprintf(out, "deps_config := \\\n");
+ for (file = file_list; file; file = file->next) {
+ if (file->next)
+ fprintf(out, "\t%s \\\n", file->name);
+ else
+ fprintf(out, "\t%s\n", file->name);
+ }
+ fprintf(out, "\n%s: \\\n"
+ "\t$(deps_config)\n\n", conf_get_autoconfig_name());
+
+ env_write_dep(out, conf_get_autoconfig_name());
+
+ fprintf(out, "\n$(deps_config): ;\n");
+ fclose(out);
+
+ if (make_parent_dir(name))
+ return 1;
+ rename("..config.tmp", name);
+ return 0;
+}
+
+static int conf_touch_deps(void)
+{
+ const char *name, *tmp;
+ struct symbol *sym;
+ int res, i;
+
+ name = conf_get_autoconfig_name();
+ tmp = strrchr(name, '/');
+ depfile_prefix_len = tmp ? tmp - name + 1 : 0;
+ if (depfile_prefix_len + 1 > sizeof(depfile_path))
+ return -1;
+
+ strncpy(depfile_path, name, depfile_prefix_len);
+ depfile_path[depfile_prefix_len] = 0;
+
+ conf_read_simple(name, S_DEF_AUTO);
+ sym_calc_value(modules_sym);
+
+ for_all_symbols(i, sym) {
+ sym_calc_value(sym);
+ if ((sym->flags & SYMBOL_NO_WRITE) || !sym->name)
+ continue;
+ if (sym->flags & SYMBOL_WRITE) {
+ if (sym->flags & SYMBOL_DEF_AUTO) {
+ /*
+ * symbol has old and new value,
+ * so compare them...
+ */
+ switch (sym->type) {
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ if (sym_get_tristate_value(sym) ==
+ sym->def[S_DEF_AUTO].tri)
+ continue;
+ break;
+ case S_STRING:
+ case S_HEX:
+ case S_INT:
+ if (!strcmp(sym_get_string_value(sym),
+ sym->def[S_DEF_AUTO].val))
+ continue;
+ break;
+ default:
+ break;
+ }
+ } else {
+ /*
+ * If there is no old value, only 'no' (unset)
+ * is allowed as new value.
+ */
+ switch (sym->type) {
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ if (sym_get_tristate_value(sym) == no)
+ continue;
+ break;
+ default:
+ break;
+ }
+ }
+ } else if (!(sym->flags & SYMBOL_DEF_AUTO))
+ /* There is neither an old nor a new value. */
+ continue;
+ /* else
+ * There is an old value, but no new value ('no' (unset)
+ * isn't saved in auto.conf, so the old value is always
+ * different from 'no').
+ */
+
+ res = conf_touch_dep(sym->name);
+ if (res)
+ return res;
+ }
+
+ return 0;
+}
+
+int conf_write_autoconf(int overwrite)
+{
+ struct symbol *sym;
+ const char *name;
+ const char *autoconf_name = conf_get_autoconfig_name();
+ FILE *out, *out_h;
+ int i;
+
+ if (!overwrite && is_present(autoconf_name))
+ return 0;
+
+ conf_write_dep("include/config/auto.conf.cmd");
+
+ if (conf_touch_deps())
+ return 1;
+
+ out = fopen(".tmpconfig", "w");
+ if (!out)
+ return 1;
+
+ out_h = fopen(".tmpconfig.h", "w");
+ if (!out_h) {
+ fclose(out);
+ return 1;
+ }
+
+ conf_write_heading(out, &kconfig_printer_cb, NULL);
+ conf_write_heading(out_h, &header_printer_cb, NULL);
+
+ for_all_symbols(i, sym) {
+ sym_calc_value(sym);
+ if (!(sym->flags & SYMBOL_WRITE) || !sym->name)
+ continue;
+
+ /* write symbols to auto.conf and autoconf.h */
+ conf_write_symbol(out, sym, &kconfig_printer_cb, (void *)1);
+ conf_write_symbol(out_h, sym, &header_printer_cb, NULL);
+ }
+ fclose(out);
+ fclose(out_h);
+
+ name = getenv("KCONFIG_AUTOHEADER");
+ if (!name)
+ name = "include/generated/autoconf.h";
+ if (make_parent_dir(name))
+ return 1;
+ if (rename(".tmpconfig.h", name))
+ return 1;
+
+ if (make_parent_dir(autoconf_name))
+ return 1;
+ /*
+ * This must be the last step, kbuild has a dependency on auto.conf
+ * and this marks the successful completion of the previous steps.
+ */
+ if (rename(".tmpconfig", autoconf_name))
+ return 1;
+
+ return 0;
+}
+
+static int sym_change_count;
+static void (*conf_changed_callback)(void);
+
+void sym_set_change_count(int count)
+{
+ int _sym_change_count = sym_change_count;
+ sym_change_count = count;
+ if (conf_changed_callback &&
+ (bool)_sym_change_count != (bool)count)
+ conf_changed_callback();
+}
+
+void sym_add_change_count(int count)
+{
+ sym_set_change_count(count + sym_change_count);
+}
+
+bool conf_get_changed(void)
+{
+ return sym_change_count;
+}
+
+void conf_set_changed_callback(void (*fn)(void))
+{
+ conf_changed_callback = fn;
+}
+
+static bool randomize_choice_values(struct symbol *csym)
+{
+ struct property *prop;
+ struct symbol *sym;
+ struct expr *e;
+ int cnt, def;
+
+ /*
+ * If choice is mod then we may have more items selected
+ * and if no then no-one.
+ * In both cases stop.
+ */
+ if (csym->curr.tri != yes)
+ return false;
+
+ prop = sym_get_choice_prop(csym);
+
+ /* count entries in choice block */
+ cnt = 0;
+ expr_list_for_each_sym(prop->expr, e, sym)
+ cnt++;
+
+ /*
+ * find a random value and set it to yes,
+ * set the rest to no so we have only one set
+ */
+ def = (rand() % cnt);
+
+ cnt = 0;
+ expr_list_for_each_sym(prop->expr, e, sym) {
+ if (def == cnt++) {
+ sym->def[S_DEF_USER].tri = yes;
+ csym->def[S_DEF_USER].val = sym;
+ }
+ else {
+ sym->def[S_DEF_USER].tri = no;
+ }
+ sym->flags |= SYMBOL_DEF_USER;
+ /* clear VALID to get value calculated */
+ sym->flags &= ~SYMBOL_VALID;
+ }
+ csym->flags |= SYMBOL_DEF_USER;
+ /* clear VALID to get value calculated */
+ csym->flags &= ~(SYMBOL_VALID);
+
+ return true;
+}
+
+void set_all_choice_values(struct symbol *csym)
+{
+ struct property *prop;
+ struct symbol *sym;
+ struct expr *e;
+
+ prop = sym_get_choice_prop(csym);
+
+ /*
+ * Set all non-assinged choice values to no
+ */
+ expr_list_for_each_sym(prop->expr, e, sym) {
+ if (!sym_has_value(sym))
+ sym->def[S_DEF_USER].tri = no;
+ }
+ csym->flags |= SYMBOL_DEF_USER;
+ /* clear VALID to get value calculated */
+ csym->flags &= ~(SYMBOL_VALID | SYMBOL_NEED_SET_CHOICE_VALUES);
+}
+
+bool conf_set_all_new_symbols(enum conf_def_mode mode)
+{
+ struct symbol *sym, *csym;
+ int i, cnt, pby, pty, ptm; /* pby: probability of bool = y
+ * pty: probability of tristate = y
+ * ptm: probability of tristate = m
+ */
+
+ pby = 50; pty = ptm = 33; /* can't go as the default in switch-case
+ * below, otherwise gcc whines about
+ * -Wmaybe-uninitialized */
+ if (mode == def_random) {
+ int n, p[3];
+ char *env = getenv("KCONFIG_PROBABILITY");
+ n = 0;
+ while( env && *env ) {
+ char *endp;
+ int tmp = strtol( env, &endp, 10 );
+ if( tmp >= 0 && tmp <= 100 ) {
+ p[n++] = tmp;
+ } else {
+ errno = ERANGE;
+ perror( "KCONFIG_PROBABILITY" );
+ exit( 1 );
+ }
+ env = (*endp == ':') ? endp+1 : endp;
+ if( n >=3 ) {
+ break;
+ }
+ }
+ switch( n ) {
+ case 1:
+ pby = p[0]; ptm = pby/2; pty = pby-ptm;
+ break;
+ case 2:
+ pty = p[0]; ptm = p[1]; pby = pty + ptm;
+ break;
+ case 3:
+ pby = p[0]; pty = p[1]; ptm = p[2];
+ break;
+ }
+
+ if( pty+ptm > 100 ) {
+ errno = ERANGE;
+ perror( "KCONFIG_PROBABILITY" );
+ exit( 1 );
+ }
+ }
+ bool has_changed = false;
+
+ for_all_symbols(i, sym) {
+ if (sym_has_value(sym) || (sym->flags & SYMBOL_VALID))
+ continue;
+ switch (sym_get_type(sym)) {
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ has_changed = true;
+ switch (mode) {
+ case def_yes:
+ sym->def[S_DEF_USER].tri = yes;
+ break;
+ case def_mod:
+ sym->def[S_DEF_USER].tri = mod;
+ break;
+ case def_no:
+ if (sym->flags & SYMBOL_ALLNOCONFIG_Y)
+ sym->def[S_DEF_USER].tri = yes;
+ else
+ sym->def[S_DEF_USER].tri = no;
+ break;
+ case def_random:
+ sym->def[S_DEF_USER].tri = no;
+ cnt = rand() % 100;
+ if (sym->type == S_TRISTATE) {
+ if (cnt < pty)
+ sym->def[S_DEF_USER].tri = yes;
+ else if (cnt < (pty+ptm))
+ sym->def[S_DEF_USER].tri = mod;
+ } else if (cnt < pby)
+ sym->def[S_DEF_USER].tri = yes;
+ break;
+ default:
+ continue;
+ }
+ if (!(sym_is_choice(sym) && mode == def_random))
+ sym->flags |= SYMBOL_DEF_USER;
+ break;
+ default:
+ break;
+ }
+
+ }
+
+ sym_clear_all_valid();
+
+ /*
+ * We have different type of choice blocks.
+ * If curr.tri equals to mod then we can select several
+ * choice symbols in one block.
+ * In this case we do nothing.
+ * If curr.tri equals yes then only one symbol can be
+ * selected in a choice block and we set it to yes,
+ * and the rest to no.
+ */
+ if (mode != def_random) {
+ for_all_symbols(i, csym) {
+ if ((sym_is_choice(csym) && !sym_has_value(csym)) ||
+ sym_is_choice_value(csym))
+ csym->flags |= SYMBOL_NEED_SET_CHOICE_VALUES;
+ }
+ }
+
+ for_all_symbols(i, csym) {
+ if (sym_has_value(csym) || !sym_is_choice(csym))
+ continue;
+
+ sym_calc_value(csym);
+ if (mode == def_random)
+ has_changed |= randomize_choice_values(csym);
+ else {
+ set_all_choice_values(csym);
+ has_changed = true;
+ }
+ }
+
+ return has_changed;
+}
+
+void conf_rewrite_mod_or_yes(enum conf_def_mode mode)
+{
+ struct symbol *sym;
+ int i;
+ tristate old_val = (mode == def_y2m) ? yes : mod;
+ tristate new_val = (mode == def_y2m) ? mod : yes;
+
+ for_all_symbols(i, sym) {
+ if (sym_get_type(sym) == S_TRISTATE &&
+ sym->def[S_DEF_USER].tri == old_val)
+ sym->def[S_DEF_USER].tri = new_val;
+ }
+ sym_clear_all_valid();
+}
Index: OrangePi/create-5.10.110-host-limits-patch/linux-orangepi-5.10.110-new/scripts/kconfig/lexer.l
===================================================================
--- OrangePi/create-5.10.110-host-limits-patch/linux-orangepi-5.10.110-new/scripts/kconfig/lexer.l (nonexistent)
+++ OrangePi/create-5.10.110-host-limits-patch/linux-orangepi-5.10.110-new/scripts/kconfig/lexer.l (revision 385)
@@ -0,0 +1,471 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ */
+%option nostdinit noyywrap never-interactive full ecs
+%option 8bit nodefault yylineno
+%x ASSIGN_VAL HELP STRING
+%{
+
+#include <assert.h>
+#include <linux/limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "lkc.h"
+#include "parser.tab.h"
+
+#define YY_DECL static int yylex1(void)
+
+#define START_STRSIZE 16
+
+static struct {
+ struct file *file;
+ int lineno;
+} current_pos;
+
+static int prev_prev_token = T_EOL;
+static int prev_token = T_EOL;
+static char *text;
+static int text_size, text_asize;
+
+struct buffer {
+ struct buffer *parent;
+ YY_BUFFER_STATE state;
+};
+
+static struct buffer *current_buf;
+
+static int last_ts, first_ts;
+
+static char *expand_token(const char *in, size_t n);
+static void append_expanded_string(const char *in);
+static void zconf_endhelp(void);
+static void zconf_endfile(void);
+
+static void new_string(void)
+{
+ text = xmalloc(START_STRSIZE);
+ text_asize = START_STRSIZE;
+ text_size = 0;
+ *text = 0;
+}
+
+static void append_string(const char *str, int size)
+{
+ int new_size = text_size + size + 1;
+ if (new_size > text_asize) {
+ new_size += START_STRSIZE - 1;
+ new_size &= -START_STRSIZE;
+ text = xrealloc(text, new_size);
+ text_asize = new_size;
+ }
+ memcpy(text + text_size, str, size);
+ text_size += size;
+ text[text_size] = 0;
+}
+
+static void alloc_string(const char *str, int size)
+{
+ text = xmalloc(size + 1);
+ memcpy(text, str, size);
+ text[size] = 0;
+}
+
+static void warn_ignored_character(char chr)
+{
+ fprintf(stderr,
+ "%s:%d:warning: ignoring unsupported character '%c'\n",
+ current_file->name, yylineno, chr);
+}
+%}
+
+n [A-Za-z0-9_-]
+
+%%
+ int str = 0;
+ int ts, i;
+
+#.* /* ignore comment */
+[ \t]* /* whitespaces */
+\\\n /* escaped new line */
+\n return T_EOL;
+"allnoconfig_y" return T_ALLNOCONFIG_Y;
+"bool" return T_BOOL;
+"choice" return T_CHOICE;
+"comment" return T_COMMENT;
+"config" return T_CONFIG;
+"def_bool" return T_DEF_BOOL;
+"def_tristate" return T_DEF_TRISTATE;
+"default" return T_DEFAULT;
+"defconfig_list" return T_DEFCONFIG_LIST;
+"depends" return T_DEPENDS;
+"endchoice" return T_ENDCHOICE;
+"endif" return T_ENDIF;
+"endmenu" return T_ENDMENU;
+"help" return T_HELP;
+"hex" return T_HEX;
+"if" return T_IF;
+"imply" return T_IMPLY;
+"int" return T_INT;
+"mainmenu" return T_MAINMENU;
+"menu" return T_MENU;
+"menuconfig" return T_MENUCONFIG;
+"modules" return T_MODULES;
+"on" return T_ON;
+"option" return T_OPTION;
+"optional" return T_OPTIONAL;
+"prompt" return T_PROMPT;
+"range" return T_RANGE;
+"select" return T_SELECT;
+"source" return T_SOURCE;
+"string" return T_STRING;
+"tristate" return T_TRISTATE;
+"visible" return T_VISIBLE;
+"||" return T_OR;
+"&&" return T_AND;
+"=" return T_EQUAL;
+"!=" return T_UNEQUAL;
+"<" return T_LESS;
+"<=" return T_LESS_EQUAL;
+">" return T_GREATER;
+">=" return T_GREATER_EQUAL;
+"!" return T_NOT;
+"(" return T_OPEN_PAREN;
+")" return T_CLOSE_PAREN;
+":=" return T_COLON_EQUAL;
+"+=" return T_PLUS_EQUAL;
+\"|\' {
+ str = yytext[0];
+ new_string();
+ BEGIN(STRING);
+ }
+{n}+ {
+ alloc_string(yytext, yyleng);
+ yylval.string = text;
+ return T_WORD;
+ }
+({n}|$)+ {
+ /* this token includes at least one '$' */
+ yylval.string = expand_token(yytext, yyleng);
+ if (strlen(yylval.string))
+ return T_WORD;
+ free(yylval.string);
+ }
+. warn_ignored_character(*yytext);
+
+<ASSIGN_VAL>{
+ [^[:blank:]\n]+.* {
+ alloc_string(yytext, yyleng);
+ yylval.string = text;
+ return T_ASSIGN_VAL;
+ }
+ \n { BEGIN(INITIAL); return T_EOL; }
+ .
+}
+
+<STRING>{
+ "$".* append_expanded_string(yytext);
+ [^$'"\\\n]+ {
+ append_string(yytext, yyleng);
+ }
+ \\.? {
+ append_string(yytext + 1, yyleng - 1);
+ }
+ \'|\" {
+ if (str == yytext[0]) {
+ BEGIN(INITIAL);
+ yylval.string = text;
+ return T_WORD_QUOTE;
+ } else
+ append_string(yytext, 1);
+ }
+ \n {
+ fprintf(stderr,
+ "%s:%d:warning: multi-line strings not supported\n",
+ zconf_curname(), zconf_lineno());
+ unput('\n');
+ BEGIN(INITIAL);
+ yylval.string = text;
+ return T_WORD_QUOTE;
+ }
+ <<EOF>> {
+ BEGIN(INITIAL);
+ yylval.string = text;
+ return T_WORD_QUOTE;
+ }
+}
+
+<HELP>{
+ [ \t]+ {
+ ts = 0;
+ for (i = 0; i < yyleng; i++) {
+ if (yytext[i] == '\t')
+ ts = (ts & ~7) + 8;
+ else
+ ts++;
+ }
+ last_ts = ts;
+ if (first_ts) {
+ if (ts < first_ts) {
+ zconf_endhelp();
+ return T_HELPTEXT;
+ }
+ ts -= first_ts;
+ while (ts > 8) {
+ append_string(" ", 8);
+ ts -= 8;
+ }
+ append_string(" ", ts);
+ }
+ }
+ [ \t]*\n/[^ \t\n] {
+ zconf_endhelp();
+ return T_HELPTEXT;
+ }
+ [ \t]*\n {
+ append_string("\n", 1);
+ }
+ [^ \t\n].* {
+ while (yyleng) {
+ if ((yytext[yyleng-1] != ' ') && (yytext[yyleng-1] != '\t'))
+ break;
+ yyleng--;
+ }
+ append_string(yytext, yyleng);
+ if (!first_ts)
+ first_ts = last_ts;
+ }
+ <<EOF>> {
+ zconf_endhelp();
+ return T_HELPTEXT;
+ }
+}
+
+<<EOF>> {
+ BEGIN(INITIAL);
+
+ if (prev_token != T_EOL && prev_token != T_HELPTEXT)
+ fprintf(stderr, "%s:%d:warning: no new line at end of file\n",
+ current_file->name, yylineno);
+
+ if (current_file) {
+ zconf_endfile();
+ return T_EOL;
+ }
+ fclose(yyin);
+ yyterminate();
+}
+
+%%
+
+/* second stage lexer */
+int yylex(void)
+{
+ int token;
+
+repeat:
+ token = yylex1();
+
+ if (prev_token == T_EOL || prev_token == T_HELPTEXT) {
+ if (token == T_EOL) {
+ /* Do not pass unneeded T_EOL to the parser. */
+ goto repeat;
+ } else {
+ /*
+ * For the parser, update file/lineno at the first token
+ * of each statement. Generally, \n is a statement
+ * terminator in Kconfig, but it is not always true
+ * because \n could be escaped by a backslash.
+ */
+ current_pos.file = current_file;
+ current_pos.lineno = yylineno;
+ }
+ }
+
+ if (prev_prev_token == T_EOL && prev_token == T_WORD &&
+ (token == T_EQUAL || token == T_COLON_EQUAL || token == T_PLUS_EQUAL))
+ BEGIN(ASSIGN_VAL);
+
+ prev_prev_token = prev_token;
+ prev_token = token;
+
+ return token;
+}
+
+static char *expand_token(const char *in, size_t n)
+{
+ char *out;
+ int c;
+ char c2;
+ const char *rest, *end;
+
+ new_string();
+ append_string(in, n);
+
+ /* get the whole line because we do not know the end of token. */
+ while ((c = input()) != EOF) {
+ if (c == '\n') {
+ unput(c);
+ break;
+ }
+ c2 = c;
+ append_string(&c2, 1);
+ }
+
+ rest = text;
+ out = expand_one_token(&rest);
+
+ /* push back unused characters to the input stream */
+ end = rest + strlen(rest);
+ while (end > rest)
+ unput(*--end);
+
+ free(text);
+
+ return out;
+}
+
+static void append_expanded_string(const char *str)
+{
+ const char *end;
+ char *res;
+
+ str++;
+
+ res = expand_dollar(&str);
+
+ /* push back unused characters to the input stream */
+ end = str + strlen(str);
+ while (end > str)
+ unput(*--end);
+
+ append_string(res, strlen(res));
+
+ free(res);
+}
+
+void zconf_starthelp(void)
+{
+ new_string();
+ last_ts = first_ts = 0;
+ BEGIN(HELP);
+}
+
+static void zconf_endhelp(void)
+{
+ yylval.string = text;
+ BEGIN(INITIAL);
+}
+
+
+/*
+ * Try to open specified file with following names:
+ * ./name
+ * $(srctree)/name
+ * The latter is used when srctree is separate from objtree
+ * when compiling the kernel.
+ * Return NULL if file is not found.
+ */
+FILE *zconf_fopen(const char *name)
+{
+ char *env, fullname[PATH_MAX+1];
+ FILE *f;
+
+ f = fopen(name, "r");
+ if (!f && name != NULL && name[0] != '/') {
+ env = getenv(SRCTREE);
+ if (env) {
+ snprintf(fullname, sizeof(fullname),
+ "%s/%s", env, name);
+ f = fopen(fullname, "r");
+ }
+ }
+ return f;
+}
+
+void zconf_initscan(const char *name)
+{
+ yyin = zconf_fopen(name);
+ if (!yyin) {
+ fprintf(stderr, "can't find file %s\n", name);
+ exit(1);
+ }
+
+ current_buf = xmalloc(sizeof(*current_buf));
+ memset(current_buf, 0, sizeof(*current_buf));
+
+ current_file = file_lookup(name);
+ yylineno = 1;
+}
+
+void zconf_nextfile(const char *name)
+{
+ struct file *iter;
+ struct file *file = file_lookup(name);
+ struct buffer *buf = xmalloc(sizeof(*buf));
+ memset(buf, 0, sizeof(*buf));
+
+ current_buf->state = YY_CURRENT_BUFFER;
+ yyin = zconf_fopen(file->name);
+ if (!yyin) {
+ fprintf(stderr, "%s:%d: can't open file \"%s\"\n",
+ zconf_curname(), zconf_lineno(), file->name);
+ exit(1);
+ }
+ yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE));
+ buf->parent = current_buf;
+ current_buf = buf;
+
+ current_file->lineno = yylineno;
+ file->parent = current_file;
+
+ for (iter = current_file; iter; iter = iter->parent) {
+ if (!strcmp(iter->name, file->name)) {
+ fprintf(stderr,
+ "Recursive inclusion detected.\n"
+ "Inclusion path:\n"
+ " current file : %s\n", file->name);
+ iter = file;
+ do {
+ iter = iter->parent;
+ fprintf(stderr, " included from: %s:%d\n",
+ iter->name, iter->lineno - 1);
+ } while (strcmp(iter->name, file->name));
+ exit(1);
+ }
+ }
+
+ yylineno = 1;
+ current_file = file;
+}
+
+static void zconf_endfile(void)
+{
+ struct buffer *parent;
+
+ current_file = current_file->parent;
+ if (current_file)
+ yylineno = current_file->lineno;
+
+ parent = current_buf->parent;
+ if (parent) {
+ fclose(yyin);
+ yy_delete_buffer(YY_CURRENT_BUFFER);
+ yy_switch_to_buffer(parent->state);
+ }
+ free(current_buf);
+ current_buf = parent;
+}
+
+int zconf_lineno(void)
+{
+ return current_pos.lineno;
+}
+
+const char *zconf_curname(void)
+{
+ return current_pos.file ? current_pos.file->name : "<none>";
+}
Index: OrangePi/create-5.10.110-host-limits-patch/linux-orangepi-5.10.110-new/scripts/mod/modpost.c
===================================================================
--- OrangePi/create-5.10.110-host-limits-patch/linux-orangepi-5.10.110-new/scripts/mod/modpost.c (nonexistent)
+++ OrangePi/create-5.10.110-host-limits-patch/linux-orangepi-5.10.110-new/scripts/mod/modpost.c (revision 385)
@@ -0,0 +1,2664 @@
+/* Postprocess module symbol versions
+ *
+ * Copyright 2003 Kai Germaschewski
+ * Copyright 2002-2004 Rusty Russell, IBM Corporation
+ * Copyright 2006-2008 Sam Ravnborg
+ * Based in part on module-init-tools/depmod.c,file2alias
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ *
+ * Usage: modpost vmlinux module1.o module2.o ...
+ */
+
+#define _GNU_SOURCE
+#include <elf.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <linux/limits.h>
+#include <errno.h>
+#include "modpost.h"
+#include "../../include/linux/license.h"
+
+/* Are we using CONFIG_MODVERSIONS? */
+static int modversions = 0;
+/* Warn about undefined symbols? (do so if we have vmlinux) */
+static int have_vmlinux = 0;
+/* Is CONFIG_MODULE_SRCVERSION_ALL set? */
+static int all_versions = 0;
+/* If we are modposting external module set to 1 */
+static int external_module = 0;
+#define MODULE_SCMVERSION_SIZE 64
+static char module_scmversion[MODULE_SCMVERSION_SIZE];
+/* Only warn about unresolved symbols */
+static int warn_unresolved = 0;
+/* How a symbol is exported */
+static int sec_mismatch_count = 0;
+static int sec_mismatch_warn_only = true;
+/* ignore missing files */
+static int ignore_missing_files;
+/* If set to 1, only warn (instead of error) about missing ns imports */
+static int allow_missing_ns_imports;
+
+static bool error_occurred;
+
+enum export {
+ export_plain, export_unused, export_gpl,
+ export_unused_gpl, export_gpl_future, export_unknown
+};
+
+/* In kernel, this size is defined in linux/module.h;
+ * here we use Elf_Addr instead of long for covering cross-compile
+ */
+
+#define MODULE_NAME_LEN (64 - sizeof(Elf_Addr))
+
+void __attribute__((format(printf, 2, 3)))
+modpost_log(enum loglevel loglevel, const char *fmt, ...)
+{
+ va_list arglist;
+
+ switch (loglevel) {
+ case LOG_WARN:
+ fprintf(stderr, "WARNING: ");
+ break;
+ case LOG_ERROR:
+ fprintf(stderr, "ERROR: ");
+ break;
+ case LOG_FATAL:
+ fprintf(stderr, "FATAL: ");
+ break;
+ default: /* invalid loglevel, ignore */
+ break;
+ }
+
+ fprintf(stderr, "modpost: ");
+
+ va_start(arglist, fmt);
+ vfprintf(stderr, fmt, arglist);
+ va_end(arglist);
+
+ if (loglevel == LOG_FATAL)
+ exit(1);
+ if (loglevel == LOG_ERROR)
+ error_occurred = true;
+}
+
+void *do_nofail(void *ptr, const char *expr)
+{
+ if (!ptr)
+ fatal("Memory allocation failure: %s.\n", expr);
+
+ return ptr;
+}
+
+char *read_text_file(const char *filename)
+{
+ struct stat st;
+ size_t nbytes;
+ int fd;
+ char *buf;
+
+ fd = open(filename, O_RDONLY);
+ if (fd < 0) {
+ perror(filename);
+ exit(1);
+ }
+
+ if (fstat(fd, &st) < 0) {
+ perror(filename);
+ exit(1);
+ }
+
+ buf = NOFAIL(malloc(st.st_size + 1));
+
+ nbytes = st.st_size;
+
+ while (nbytes) {
+ ssize_t bytes_read;
+
+ bytes_read = read(fd, buf, nbytes);
+ if (bytes_read < 0) {
+ perror(filename);
+ exit(1);
+ }
+
+ nbytes -= bytes_read;
+ }
+ buf[st.st_size] = '\0';
+
+ close(fd);
+
+ return buf;
+}
+
+char *get_line(char **stringp)
+{
+ char *orig = *stringp, *next;
+
+ /* do not return the unwanted extra line at EOF */
+ if (!orig || *orig == '\0')
+ return NULL;
+
+ /* don't use strsep here, it is not available everywhere */
+ next = strchr(orig, '\n');
+ if (next)
+ *next++ = '\0';
+
+ *stringp = next;
+
+ return orig;
+}
+
+/* A list of all modules we processed */
+static struct module *modules;
+
+static struct module *find_module(const char *modname)
+{
+ struct module *mod;
+
+ for (mod = modules; mod; mod = mod->next)
+ if (strcmp(mod->name, modname) == 0)
+ break;
+ return mod;
+}
+
+static struct module *new_module(const char *modname)
+{
+ struct module *mod;
+
+ mod = NOFAIL(malloc(sizeof(*mod) + strlen(modname) + 1));
+ memset(mod, 0, sizeof(*mod));
+
+ /* add to list */
+ strcpy(mod->name, modname);
+ mod->is_vmlinux = (strcmp(modname, "vmlinux") == 0);
+ mod->gpl_compatible = -1;
+ mod->next = modules;
+ modules = mod;
+
+ if (mod->is_vmlinux)
+ have_vmlinux = 1;
+
+ return mod;
+}
+
+/* A hash of all exported symbols,
+ * struct symbol is also used for lists of unresolved symbols */
+
+#define SYMBOL_HASH_SIZE 1024
+
+struct symbol {
+ struct symbol *next;
+ struct module *module;
+ unsigned int crc;
+ int crc_valid;
+ char *namespace;
+ unsigned int weak:1;
+ unsigned int is_static:1; /* 1 if symbol is not global */
+ enum export export; /* Type of export */
+ char name[];
+};
+
+static struct symbol *symbolhash[SYMBOL_HASH_SIZE];
+
+/* This is based on the hash agorithm from gdbm, via tdb */
+static inline unsigned int tdb_hash(const char *name)
+{
+ unsigned value; /* Used to compute the hash value. */
+ unsigned i; /* Used to cycle through random values. */
+
+ /* Set the initial value from the key size. */
+ for (value = 0x238F13AF * strlen(name), i = 0; name[i]; i++)
+ value = (value + (((unsigned char *)name)[i] << (i*5 % 24)));
+
+ return (1103515243 * value + 12345);
+}
+
+/**
+ * Allocate a new symbols for use in the hash of exported symbols or
+ * the list of unresolved symbols per module
+ **/
+static struct symbol *alloc_symbol(const char *name, unsigned int weak,
+ struct symbol *next)
+{
+ struct symbol *s = NOFAIL(malloc(sizeof(*s) + strlen(name) + 1));
+
+ memset(s, 0, sizeof(*s));
+ strcpy(s->name, name);
+ s->weak = weak;
+ s->next = next;
+ s->is_static = 1;
+ return s;
+}
+
+/* For the hash of exported symbols */
+static struct symbol *new_symbol(const char *name, struct module *module,
+ enum export export)
+{
+ unsigned int hash;
+
+ hash = tdb_hash(name) % SYMBOL_HASH_SIZE;
+ symbolhash[hash] = alloc_symbol(name, 0, symbolhash[hash]);
+
+ return symbolhash[hash];
+}
+
+static struct symbol *find_symbol(const char *name)
+{
+ struct symbol *s;
+
+ /* For our purposes, .foo matches foo. PPC64 needs this. */
+ if (name[0] == '.')
+ name++;
+
+ for (s = symbolhash[tdb_hash(name) % SYMBOL_HASH_SIZE]; s; s = s->next) {
+ if (strcmp(s->name, name) == 0)
+ return s;
+ }
+ return NULL;
+}
+
+static bool contains_namespace(struct namespace_list *list,
+ const char *namespace)
+{
+ for (; list; list = list->next)
+ if (!strcmp(list->namespace, namespace))
+ return true;
+
+ return false;
+}
+
+static void add_namespace(struct namespace_list **list, const char *namespace)
+{
+ struct namespace_list *ns_entry;
+
+ if (!contains_namespace(*list, namespace)) {
+ ns_entry = NOFAIL(malloc(sizeof(struct namespace_list) +
+ strlen(namespace) + 1));
+ strcpy(ns_entry->namespace, namespace);
+ ns_entry->next = *list;
+ *list = ns_entry;
+ }
+}
+
+static bool module_imports_namespace(struct module *module,
+ const char *namespace)
+{
+ return contains_namespace(module->imported_namespaces, namespace);
+}
+
+static const struct {
+ const char *str;
+ enum export export;
+} export_list[] = {
+ { .str = "EXPORT_SYMBOL", .export = export_plain },
+ { .str = "EXPORT_UNUSED_SYMBOL", .export = export_unused },
+ { .str = "EXPORT_SYMBOL_GPL", .export = export_gpl },
+ { .str = "EXPORT_UNUSED_SYMBOL_GPL", .export = export_unused_gpl },
+ { .str = "EXPORT_SYMBOL_GPL_FUTURE", .export = export_gpl_future },
+ { .str = "(unknown)", .export = export_unknown },
+};
+
+
+static const char *export_str(enum export ex)
+{
+ return export_list[ex].str;
+}
+
+static enum export export_no(const char *s)
+{
+ int i;
+
+ if (!s)
+ return export_unknown;
+ for (i = 0; export_list[i].export != export_unknown; i++) {
+ if (strcmp(export_list[i].str, s) == 0)
+ return export_list[i].export;
+ }
+ return export_unknown;
+}
+
+static void *sym_get_data_by_offset(const struct elf_info *info,
+ unsigned int secindex, unsigned long offset)
+{
+ Elf_Shdr *sechdr = &info->sechdrs[secindex];
+
+ if (info->hdr->e_type != ET_REL)
+ offset -= sechdr->sh_addr;
+
+ return (void *)info->hdr + sechdr->sh_offset + offset;
+}
+
+static void *sym_get_data(const struct elf_info *info, const Elf_Sym *sym)
+{
+ return sym_get_data_by_offset(info, get_secindex(info, sym),
+ sym->st_value);
+}
+
+static const char *sech_name(const struct elf_info *info, Elf_Shdr *sechdr)
+{
+ return sym_get_data_by_offset(info, info->secindex_strings,
+ sechdr->sh_name);
+}
+
+static const char *sec_name(const struct elf_info *info, int secindex)
+{
+ return sech_name(info, &info->sechdrs[secindex]);
+}
+
+#define strstarts(str, prefix) (strncmp(str, prefix, strlen(prefix)) == 0)
+
+static enum export export_from_secname(struct elf_info *elf, unsigned int sec)
+{
+ const char *secname = sec_name(elf, sec);
+
+ if (strstarts(secname, "___ksymtab+"))
+ return export_plain;
+ else if (strstarts(secname, "___ksymtab_unused+"))
+ return export_unused;
+ else if (strstarts(secname, "___ksymtab_gpl+"))
+ return export_gpl;
+ else if (strstarts(secname, "___ksymtab_unused_gpl+"))
+ return export_unused_gpl;
+ else if (strstarts(secname, "___ksymtab_gpl_future+"))
+ return export_gpl_future;
+ else
+ return export_unknown;
+}
+
+static enum export export_from_sec(struct elf_info *elf, unsigned int sec)
+{
+ if (sec == elf->export_sec)
+ return export_plain;
+ else if (sec == elf->export_unused_sec)
+ return export_unused;
+ else if (sec == elf->export_gpl_sec)
+ return export_gpl;
+ else if (sec == elf->export_unused_gpl_sec)
+ return export_unused_gpl;
+ else if (sec == elf->export_gpl_future_sec)
+ return export_gpl_future;
+ else
+ return export_unknown;
+}
+
+static const char *namespace_from_kstrtabns(const struct elf_info *info,
+ const Elf_Sym *sym)
+{
+ const char *value = sym_get_data(info, sym);
+ return value[0] ? value : NULL;
+}
+
+static void sym_update_namespace(const char *symname, const char *namespace)
+{
+ struct symbol *s = find_symbol(symname);
+
+ /*
+ * That symbol should have been created earlier and thus this is
+ * actually an assertion.
+ */
+ if (!s) {
+ error("Could not update namespace(%s) for symbol %s\n",
+ namespace, symname);
+ return;
+ }
+
+ free(s->namespace);
+ s->namespace =
+ namespace && namespace[0] ? NOFAIL(strdup(namespace)) : NULL;
+}
+
+/**
+ * Add an exported symbol - it may have already been added without a
+ * CRC, in this case just update the CRC
+ **/
+static struct symbol *sym_add_exported(const char *name, struct module *mod,
+ enum export export)
+{
+ struct symbol *s = find_symbol(name);
+
+ if (!s) {
+ s = new_symbol(name, mod, export);
+ } else if (!external_module || s->module->is_vmlinux ||
+ s->module == mod) {
+ fatal("%s: '%s' exported twice. Previous export was in %s%s\n",
+ mod->name, name, s->module->name,
+ s->module->is_vmlinux ? "" : ".ko");
+ }
+
+ s->module = mod;
+ s->export = export;
+ return s;
+}
+
+static void sym_set_crc(const char *name, unsigned int crc)
+{
+ struct symbol *s = find_symbol(name);
+
+ /*
+ * Ignore stand-alone __crc_*, which might be auto-generated symbols
+ * such as __*_veneer in ARM ELF.
+ */
+ if (!s)
+ return;
+
+ s->crc = crc;
+ s->crc_valid = 1;
+}
+
+static void *grab_file(const char *filename, size_t *size)
+{
+ struct stat st;
+ void *map = MAP_FAILED;
+ int fd;
+
+ fd = open(filename, O_RDONLY);
+ if (fd < 0)
+ return NULL;
+ if (fstat(fd, &st))
+ goto failed;
+
+ *size = st.st_size;
+ map = mmap(NULL, *size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
+
+failed:
+ close(fd);
+ if (map == MAP_FAILED)
+ return NULL;
+ return map;
+}
+
+static void release_file(void *file, size_t size)
+{
+ munmap(file, size);
+}
+
+static int parse_elf(struct elf_info *info, const char *filename)
+{
+ unsigned int i;
+ Elf_Ehdr *hdr;
+ Elf_Shdr *sechdrs;
+ Elf_Sym *sym;
+ const char *secstrings;
+ unsigned int symtab_idx = ~0U, symtab_shndx_idx = ~0U;
+
+ hdr = grab_file(filename, &info->size);
+ if (!hdr) {
+ if (ignore_missing_files) {
+ fprintf(stderr, "%s: %s (ignored)\n", filename,
+ strerror(errno));
+ return 0;
+ }
+ perror(filename);
+ exit(1);
+ }
+ info->hdr = hdr;
+ if (info->size < sizeof(*hdr)) {
+ /* file too small, assume this is an empty .o file */
+ return 0;
+ }
+ /* Is this a valid ELF file? */
+ if ((hdr->e_ident[EI_MAG0] != ELFMAG0) ||
+ (hdr->e_ident[EI_MAG1] != ELFMAG1) ||
+ (hdr->e_ident[EI_MAG2] != ELFMAG2) ||
+ (hdr->e_ident[EI_MAG3] != ELFMAG3)) {
+ /* Not an ELF file - silently ignore it */
+ return 0;
+ }
+ /* Fix endianness in ELF header */
+ hdr->e_type = TO_NATIVE(hdr->e_type);
+ hdr->e_machine = TO_NATIVE(hdr->e_machine);
+ hdr->e_version = TO_NATIVE(hdr->e_version);
+ hdr->e_entry = TO_NATIVE(hdr->e_entry);
+ hdr->e_phoff = TO_NATIVE(hdr->e_phoff);
+ hdr->e_shoff = TO_NATIVE(hdr->e_shoff);
+ hdr->e_flags = TO_NATIVE(hdr->e_flags);
+ hdr->e_ehsize = TO_NATIVE(hdr->e_ehsize);
+ hdr->e_phentsize = TO_NATIVE(hdr->e_phentsize);
+ hdr->e_phnum = TO_NATIVE(hdr->e_phnum);
+ hdr->e_shentsize = TO_NATIVE(hdr->e_shentsize);
+ hdr->e_shnum = TO_NATIVE(hdr->e_shnum);
+ hdr->e_shstrndx = TO_NATIVE(hdr->e_shstrndx);
+ sechdrs = (void *)hdr + hdr->e_shoff;
+ info->sechdrs = sechdrs;
+
+ /* Check if file offset is correct */
+ if (hdr->e_shoff > info->size) {
+ fatal("section header offset=%lu in file '%s' is bigger than filesize=%zu\n",
+ (unsigned long)hdr->e_shoff, filename, info->size);
+ return 0;
+ }
+
+ if (hdr->e_shnum == SHN_UNDEF) {
+ /*
+ * There are more than 64k sections,
+ * read count from .sh_size.
+ */
+ info->num_sections = TO_NATIVE(sechdrs[0].sh_size);
+ }
+ else {
+ info->num_sections = hdr->e_shnum;
+ }
+ if (hdr->e_shstrndx == SHN_XINDEX) {
+ info->secindex_strings = TO_NATIVE(sechdrs[0].sh_link);
+ }
+ else {
+ info->secindex_strings = hdr->e_shstrndx;
+ }
+
+ /* Fix endianness in section headers */
+ for (i = 0; i < info->num_sections; i++) {
+ sechdrs[i].sh_name = TO_NATIVE(sechdrs[i].sh_name);
+ sechdrs[i].sh_type = TO_NATIVE(sechdrs[i].sh_type);
+ sechdrs[i].sh_flags = TO_NATIVE(sechdrs[i].sh_flags);
+ sechdrs[i].sh_addr = TO_NATIVE(sechdrs[i].sh_addr);
+ sechdrs[i].sh_offset = TO_NATIVE(sechdrs[i].sh_offset);
+ sechdrs[i].sh_size = TO_NATIVE(sechdrs[i].sh_size);
+ sechdrs[i].sh_link = TO_NATIVE(sechdrs[i].sh_link);
+ sechdrs[i].sh_info = TO_NATIVE(sechdrs[i].sh_info);
+ sechdrs[i].sh_addralign = TO_NATIVE(sechdrs[i].sh_addralign);
+ sechdrs[i].sh_entsize = TO_NATIVE(sechdrs[i].sh_entsize);
+ }
+ /* Find symbol table. */
+ secstrings = (void *)hdr + sechdrs[info->secindex_strings].sh_offset;
+ for (i = 1; i < info->num_sections; i++) {
+ const char *secname;
+ int nobits = sechdrs[i].sh_type == SHT_NOBITS;
+
+ if (!nobits && sechdrs[i].sh_offset > info->size) {
+ fatal("%s is truncated. sechdrs[i].sh_offset=%lu > "
+ "sizeof(*hrd)=%zu\n", filename,
+ (unsigned long)sechdrs[i].sh_offset,
+ sizeof(*hdr));
+ return 0;
+ }
+ secname = secstrings + sechdrs[i].sh_name;
+ if (strcmp(secname, ".modinfo") == 0) {
+ if (nobits)
+ fatal("%s has NOBITS .modinfo\n", filename);
+ info->modinfo = (void *)hdr + sechdrs[i].sh_offset;
+ info->modinfo_len = sechdrs[i].sh_size;
+ } else if (strcmp(secname, "__ksymtab") == 0)
+ info->export_sec = i;
+ else if (strcmp(secname, "__ksymtab_unused") == 0)
+ info->export_unused_sec = i;
+ else if (strcmp(secname, "__ksymtab_gpl") == 0)
+ info->export_gpl_sec = i;
+ else if (strcmp(secname, "__ksymtab_unused_gpl") == 0)
+ info->export_unused_gpl_sec = i;
+ else if (strcmp(secname, "__ksymtab_gpl_future") == 0)
+ info->export_gpl_future_sec = i;
+
+ if (sechdrs[i].sh_type == SHT_SYMTAB) {
+ unsigned int sh_link_idx;
+ symtab_idx = i;
+ info->symtab_start = (void *)hdr +
+ sechdrs[i].sh_offset;
+ info->symtab_stop = (void *)hdr +
+ sechdrs[i].sh_offset + sechdrs[i].sh_size;
+ sh_link_idx = sechdrs[i].sh_link;
+ info->strtab = (void *)hdr +
+ sechdrs[sh_link_idx].sh_offset;
+ }
+
+ /* 32bit section no. table? ("more than 64k sections") */
+ if (sechdrs[i].sh_type == SHT_SYMTAB_SHNDX) {
+ symtab_shndx_idx = i;
+ info->symtab_shndx_start = (void *)hdr +
+ sechdrs[i].sh_offset;
+ info->symtab_shndx_stop = (void *)hdr +
+ sechdrs[i].sh_offset + sechdrs[i].sh_size;
+ }
+ }
+ if (!info->symtab_start)
+ fatal("%s has no symtab?\n", filename);
+
+ /* Fix endianness in symbols */
+ for (sym = info->symtab_start; sym < info->symtab_stop; sym++) {
+ sym->st_shndx = TO_NATIVE(sym->st_shndx);
+ sym->st_name = TO_NATIVE(sym->st_name);
+ sym->st_value = TO_NATIVE(sym->st_value);
+ sym->st_size = TO_NATIVE(sym->st_size);
+ }
+
+ if (symtab_shndx_idx != ~0U) {
+ Elf32_Word *p;
+ if (symtab_idx != sechdrs[symtab_shndx_idx].sh_link)
+ fatal("%s: SYMTAB_SHNDX has bad sh_link: %u!=%u\n",
+ filename, sechdrs[symtab_shndx_idx].sh_link,
+ symtab_idx);
+ /* Fix endianness */
+ for (p = info->symtab_shndx_start; p < info->symtab_shndx_stop;
+ p++)
+ *p = TO_NATIVE(*p);
+ }
+
+ return 1;
+}
+
+static void parse_elf_finish(struct elf_info *info)
+{
+ release_file(info->hdr, info->size);
+}
+
+static int ignore_undef_symbol(struct elf_info *info, const char *symname)
+{
+ /* ignore __this_module, it will be resolved shortly */
+ if (strcmp(symname, "__this_module") == 0)
+ return 1;
+ /* ignore global offset table */
+ if (strcmp(symname, "_GLOBAL_OFFSET_TABLE_") == 0)
+ return 1;
+ if (info->hdr->e_machine == EM_PPC)
+ /* Special register function linked on all modules during final link of .ko */
+ if (strstarts(symname, "_restgpr_") ||
+ strstarts(symname, "_savegpr_") ||
+ strstarts(symname, "_rest32gpr_") ||
+ strstarts(symname, "_save32gpr_") ||
+ strstarts(symname, "_restvr_") ||
+ strstarts(symname, "_savevr_"))
+ return 1;
+ if (info->hdr->e_machine == EM_PPC64)
+ /* Special register function linked on all modules during final link of .ko */
+ if (strstarts(symname, "_restgpr0_") ||
+ strstarts(symname, "_savegpr0_") ||
+ strstarts(symname, "_restvr_") ||
+ strstarts(symname, "_savevr_") ||
+ strcmp(symname, ".TOC.") == 0)
+ return 1;
+ /* Do not ignore this symbol */
+ return 0;
+}
+
+static void handle_modversion(const struct module *mod,
+ const struct elf_info *info,
+ const Elf_Sym *sym, const char *symname)
+{
+ unsigned int crc;
+
+ if (sym->st_shndx == SHN_UNDEF) {
+ warn("EXPORT symbol \"%s\" [%s%s] version generation failed, symbol will not be versioned.\n",
+ symname, mod->name, mod->is_vmlinux ? "" : ".ko");
+ return;
+ }
+
+ if (sym->st_shndx == SHN_ABS) {
+ crc = sym->st_value;
+ } else {
+ unsigned int *crcp;
+
+ /* symbol points to the CRC in the ELF object */
+ crcp = sym_get_data(info, sym);
+ crc = TO_NATIVE(*crcp);
+ }
+ sym_set_crc(symname, crc);
+}
+
+static void handle_symbol(struct module *mod, struct elf_info *info,
+ const Elf_Sym *sym, const char *symname)
+{
+ enum export export;
+ const char *name;
+
+ if (strstarts(symname, "__ksymtab"))
+ export = export_from_secname(info, get_secindex(info, sym));
+ else
+ export = export_from_sec(info, get_secindex(info, sym));
+
+ switch (sym->st_shndx) {
+ case SHN_COMMON:
+ if (strstarts(symname, "__gnu_lto_")) {
+ /* Should warn here, but modpost runs before the linker */
+ } else
+ warn("\"%s\" [%s] is COMMON symbol\n", symname, mod->name);
+ break;
+ case SHN_UNDEF:
+ /* undefined symbol */
+ if (ELF_ST_BIND(sym->st_info) != STB_GLOBAL &&
+ ELF_ST_BIND(sym->st_info) != STB_WEAK)
+ break;
+ if (ignore_undef_symbol(info, symname))
+ break;
+ if (info->hdr->e_machine == EM_SPARC ||
+ info->hdr->e_machine == EM_SPARCV9) {
+ /* Ignore register directives. */
+ if (ELF_ST_TYPE(sym->st_info) == STT_SPARC_REGISTER)
+ break;
+ if (symname[0] == '.') {
+ char *munged = NOFAIL(strdup(symname));
+ munged[0] = '_';
+ munged[1] = toupper(munged[1]);
+ symname = munged;
+ }
+ }
+
+ mod->unres = alloc_symbol(symname,
+ ELF_ST_BIND(sym->st_info) == STB_WEAK,
+ mod->unres);
+ break;
+ default:
+ /* All exported symbols */
+ if (strstarts(symname, "__ksymtab_")) {
+ name = symname + strlen("__ksymtab_");
+ sym_add_exported(name, mod, export);
+ }
+ if (strcmp(symname, "init_module") == 0)
+ mod->has_init = 1;
+ if (strcmp(symname, "cleanup_module") == 0)
+ mod->has_cleanup = 1;
+ break;
+ }
+}
+
+/**
+ * Parse tag=value strings from .modinfo section
+ **/
+static char *next_string(char *string, unsigned long *secsize)
+{
+ /* Skip non-zero chars */
+ while (string[0]) {
+ string++;
+ if ((*secsize)-- <= 1)
+ return NULL;
+ }
+
+ /* Skip any zero padding. */
+ while (!string[0]) {
+ string++;
+ if ((*secsize)-- <= 1)
+ return NULL;
+ }
+ return string;
+}
+
+static char *get_next_modinfo(struct elf_info *info, const char *tag,
+ char *prev)
+{
+ char *p;
+ unsigned int taglen = strlen(tag);
+ char *modinfo = info->modinfo;
+ unsigned long size = info->modinfo_len;
+
+ if (prev) {
+ size -= prev - modinfo;
+ modinfo = next_string(prev, &size);
+ }
+
+ for (p = modinfo; p; p = next_string(p, &size)) {
+ if (strncmp(p, tag, taglen) == 0 && p[taglen] == '=')
+ return p + taglen + 1;
+ }
+ return NULL;
+}
+
+static char *get_modinfo(struct elf_info *info, const char *tag)
+
+{
+ return get_next_modinfo(info, tag, NULL);
+}
+
+/**
+ * Test if string s ends in string sub
+ * return 0 if match
+ **/
+static int strrcmp(const char *s, const char *sub)
+{
+ int slen, sublen;
+
+ if (!s || !sub)
+ return 1;
+
+ slen = strlen(s);
+ sublen = strlen(sub);
+
+ if ((slen == 0) || (sublen == 0))
+ return 1;
+
+ if (sublen > slen)
+ return 1;
+
+ return memcmp(s + slen - sublen, sub, sublen);
+}
+
+static const char *sym_name(struct elf_info *elf, Elf_Sym *sym)
+{
+ if (sym)
+ return elf->strtab + sym->st_name;
+ else
+ return "(unknown)";
+}
+
+/* The pattern is an array of simple patterns.
+ * "foo" will match an exact string equal to "foo"
+ * "*foo" will match a string that ends with "foo"
+ * "foo*" will match a string that begins with "foo"
+ * "*foo*" will match a string that contains "foo"
+ */
+static int match(const char *sym, const char * const pat[])
+{
+ const char *p;
+ while (*pat) {
+ p = *pat++;
+ const char *endp = p + strlen(p) - 1;
+
+ /* "*foo*" */
+ if (*p == '*' && *endp == '*') {
+ char *bare = NOFAIL(strndup(p + 1, strlen(p) - 2));
+ char *here = strstr(sym, bare);
+
+ free(bare);
+ if (here != NULL)
+ return 1;
+ }
+ /* "*foo" */
+ else if (*p == '*') {
+ if (strrcmp(sym, p + 1) == 0)
+ return 1;
+ }
+ /* "foo*" */
+ else if (*endp == '*') {
+ if (strncmp(sym, p, strlen(p) - 1) == 0)
+ return 1;
+ }
+ /* no wildcards */
+ else {
+ if (strcmp(p, sym) == 0)
+ return 1;
+ }
+ }
+ /* no match */
+ return 0;
+}
+
+/* sections that we do not want to do full section mismatch check on */
+static const char *const section_white_list[] =
+{
+ ".comment*",
+ ".debug*",
+ ".cranges", /* sh64 */
+ ".zdebug*", /* Compressed debug sections. */
+ ".GCC.command.line", /* record-gcc-switches */
+ ".mdebug*", /* alpha, score, mips etc. */
+ ".pdr", /* alpha, score, mips etc. */
+ ".stab*",
+ ".note*",
+ ".got*",
+ ".toc*",
+ ".xt.prop", /* xtensa */
+ ".xt.lit", /* xtensa */
+ ".arcextmap*", /* arc */
+ ".gnu.linkonce.arcext*", /* arc : modules */
+ ".cmem*", /* EZchip */
+ ".fmt_slot*", /* EZchip */
+ ".gnu.lto*",
+ ".discard.*",
+ NULL
+};
+
+/*
+ * This is used to find sections missing the SHF_ALLOC flag.
+ * The cause of this is often a section specified in assembler
+ * without "ax" / "aw".
+ */
+static void check_section(const char *modname, struct elf_info *elf,
+ Elf_Shdr *sechdr)
+{
+ const char *sec = sech_name(elf, sechdr);
+
+ if (sechdr->sh_type == SHT_PROGBITS &&
+ !(sechdr->sh_flags & SHF_ALLOC) &&
+ !match(sec, section_white_list)) {
+ warn("%s (%s): unexpected non-allocatable section.\n"
+ "Did you forget to use \"ax\"/\"aw\" in a .S file?\n"
+ "Note that for example <linux/init.h> contains\n"
+ "section definitions for use in .S files.\n\n",
+ modname, sec);
+ }
+}
+
+
+
+#define ALL_INIT_DATA_SECTIONS \
+ ".init.setup", ".init.rodata", ".meminit.rodata", \
+ ".init.data", ".meminit.data"
+#define ALL_EXIT_DATA_SECTIONS \
+ ".exit.data", ".memexit.data"
+
+#define ALL_INIT_TEXT_SECTIONS \
+ ".init.text", ".meminit.text"
+#define ALL_EXIT_TEXT_SECTIONS \
+ ".exit.text", ".memexit.text"
+
+#define ALL_PCI_INIT_SECTIONS \
+ ".pci_fixup_early", ".pci_fixup_header", ".pci_fixup_final", \
+ ".pci_fixup_enable", ".pci_fixup_resume", \
+ ".pci_fixup_resume_early", ".pci_fixup_suspend"
+
+#define ALL_XXXINIT_SECTIONS MEM_INIT_SECTIONS
+#define ALL_XXXEXIT_SECTIONS MEM_EXIT_SECTIONS
+
+#define ALL_INIT_SECTIONS INIT_SECTIONS, ALL_XXXINIT_SECTIONS
+#define ALL_EXIT_SECTIONS EXIT_SECTIONS, ALL_XXXEXIT_SECTIONS
+
+#define DATA_SECTIONS ".data", ".data.rel"
+#define TEXT_SECTIONS ".text", ".text.unlikely", ".sched.text", \
+ ".kprobes.text", ".cpuidle.text", ".noinstr.text"
+#define OTHER_TEXT_SECTIONS ".ref.text", ".head.text", ".spinlock.text", \
+ ".fixup", ".entry.text", ".exception.text", ".text.*", \
+ ".coldtext"
+
+#define INIT_SECTIONS ".init.*"
+#define MEM_INIT_SECTIONS ".meminit.*"
+
+#define EXIT_SECTIONS ".exit.*"
+#define MEM_EXIT_SECTIONS ".memexit.*"
+
+#define ALL_TEXT_SECTIONS ALL_INIT_TEXT_SECTIONS, ALL_EXIT_TEXT_SECTIONS, \
+ TEXT_SECTIONS, OTHER_TEXT_SECTIONS
+
+/* init data sections */
+static const char *const init_data_sections[] =
+ { ALL_INIT_DATA_SECTIONS, NULL };
+
+/* all init sections */
+static const char *const init_sections[] = { ALL_INIT_SECTIONS, NULL };
+
+/* All init and exit sections (code + data) */
+static const char *const init_exit_sections[] =
+ {ALL_INIT_SECTIONS, ALL_EXIT_SECTIONS, NULL };
+
+/* all text sections */
+static const char *const text_sections[] = { ALL_TEXT_SECTIONS, NULL };
+
+/* data section */
+static const char *const data_sections[] = { DATA_SECTIONS, NULL };
+
+
+/* symbols in .data that may refer to init/exit sections */
+#define DEFAULT_SYMBOL_WHITE_LIST \
+ "*driver", \
+ "*_template", /* scsi uses *_template a lot */ \
+ "*_timer", /* arm uses ops structures named _timer a lot */ \
+ "*_sht", /* scsi also used *_sht to some extent */ \
+ "*_ops", \
+ "*_probe", \
+ "*_probe_one", \
+ "*_console"
+
+static const char *const head_sections[] = { ".head.text*", NULL };
+static const char *const linker_symbols[] =
+ { "__init_begin", "_sinittext", "_einittext", NULL };
+static const char *const optim_symbols[] = { "*.constprop.*", NULL };
+
+enum mismatch {
+ TEXT_TO_ANY_INIT,
+ DATA_TO_ANY_INIT,
+ TEXT_TO_ANY_EXIT,
+ DATA_TO_ANY_EXIT,
+ XXXINIT_TO_SOME_INIT,
+ XXXEXIT_TO_SOME_EXIT,
+ ANY_INIT_TO_ANY_EXIT,
+ ANY_EXIT_TO_ANY_INIT,
+ EXPORT_TO_INIT_EXIT,
+ EXTABLE_TO_NON_TEXT,
+};
+
+/**
+ * Describe how to match sections on different criterias:
+ *
+ * @fromsec: Array of sections to be matched.
+ *
+ * @bad_tosec: Relocations applied to a section in @fromsec to a section in
+ * this array is forbidden (black-list). Can be empty.
+ *
+ * @good_tosec: Relocations applied to a section in @fromsec must be
+ * targetting sections in this array (white-list). Can be empty.
+ *
+ * @mismatch: Type of mismatch.
+ *
+ * @symbol_white_list: Do not match a relocation to a symbol in this list
+ * even if it is targetting a section in @bad_to_sec.
+ *
+ * @handler: Specific handler to call when a match is found. If NULL,
+ * default_mismatch_handler() will be called.
+ *
+ */
+struct sectioncheck {
+ const char *fromsec[20];
+ const char *bad_tosec[20];
+ const char *good_tosec[20];
+ enum mismatch mismatch;
+ const char *symbol_white_list[20];
+ void (*handler)(const char *modname, struct elf_info *elf,
+ const struct sectioncheck* const mismatch,
+ Elf_Rela *r, Elf_Sym *sym, const char *fromsec);
+
+};
+
+static void extable_mismatch_handler(const char *modname, struct elf_info *elf,
+ const struct sectioncheck* const mismatch,
+ Elf_Rela *r, Elf_Sym *sym,
+ const char *fromsec);
+
+static const struct sectioncheck sectioncheck[] = {
+/* Do not reference init/exit code/data from
+ * normal code and data
+ */
+{
+ .fromsec = { TEXT_SECTIONS, NULL },
+ .bad_tosec = { ALL_INIT_SECTIONS, NULL },
+ .mismatch = TEXT_TO_ANY_INIT,
+ .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
+},
+{
+ .fromsec = { DATA_SECTIONS, NULL },
+ .bad_tosec = { ALL_XXXINIT_SECTIONS, NULL },
+ .mismatch = DATA_TO_ANY_INIT,
+ .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
+},
+{
+ .fromsec = { DATA_SECTIONS, NULL },
+ .bad_tosec = { INIT_SECTIONS, NULL },
+ .mismatch = DATA_TO_ANY_INIT,
+ .symbol_white_list = {
+ "*_template", "*_timer", "*_sht", "*_ops",
+ "*_probe", "*_probe_one", "*_console", NULL
+ },
+},
+{
+ .fromsec = { TEXT_SECTIONS, NULL },
+ .bad_tosec = { ALL_EXIT_SECTIONS, NULL },
+ .mismatch = TEXT_TO_ANY_EXIT,
+ .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
+},
+{
+ .fromsec = { DATA_SECTIONS, NULL },
+ .bad_tosec = { ALL_EXIT_SECTIONS, NULL },
+ .mismatch = DATA_TO_ANY_EXIT,
+ .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
+},
+/* Do not reference init code/data from meminit code/data */
+{
+ .fromsec = { ALL_XXXINIT_SECTIONS, NULL },
+ .bad_tosec = { INIT_SECTIONS, NULL },
+ .mismatch = XXXINIT_TO_SOME_INIT,
+ .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
+},
+/* Do not reference exit code/data from memexit code/data */
+{
+ .fromsec = { ALL_XXXEXIT_SECTIONS, NULL },
+ .bad_tosec = { EXIT_SECTIONS, NULL },
+ .mismatch = XXXEXIT_TO_SOME_EXIT,
+ .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
+},
+/* Do not use exit code/data from init code */
+{
+ .fromsec = { ALL_INIT_SECTIONS, NULL },
+ .bad_tosec = { ALL_EXIT_SECTIONS, NULL },
+ .mismatch = ANY_INIT_TO_ANY_EXIT,
+ .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
+},
+/* Do not use init code/data from exit code */
+{
+ .fromsec = { ALL_EXIT_SECTIONS, NULL },
+ .bad_tosec = { ALL_INIT_SECTIONS, NULL },
+ .mismatch = ANY_EXIT_TO_ANY_INIT,
+ .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
+},
+{
+ .fromsec = { ALL_PCI_INIT_SECTIONS, NULL },
+ .bad_tosec = { INIT_SECTIONS, NULL },
+ .mismatch = ANY_INIT_TO_ANY_EXIT,
+ .symbol_white_list = { NULL },
+},
+/* Do not export init/exit functions or data */
+{
+ .fromsec = { "__ksymtab*", NULL },
+ .bad_tosec = { INIT_SECTIONS, EXIT_SECTIONS, NULL },
+ .mismatch = EXPORT_TO_INIT_EXIT,
+ .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
+},
+{
+ .fromsec = { "__ex_table", NULL },
+ /* If you're adding any new black-listed sections in here, consider
+ * adding a special 'printer' for them in scripts/check_extable.
+ */
+ .bad_tosec = { ".altinstr_replacement", NULL },
+ .good_tosec = {ALL_TEXT_SECTIONS , NULL},
+ .mismatch = EXTABLE_TO_NON_TEXT,
+ .handler = extable_mismatch_handler,
+}
+};
+
+static const struct sectioncheck *section_mismatch(
+ const char *fromsec, const char *tosec)
+{
+ int i;
+ int elems = sizeof(sectioncheck) / sizeof(struct sectioncheck);
+ const struct sectioncheck *check = §ioncheck[0];
+
+ /*
+ * The target section could be the SHT_NUL section when we're
+ * handling relocations to un-resolved symbols, trying to match it
+ * doesn't make much sense and causes build failures on parisc
+ * architectures.
+ */
+ if (*tosec == '\0')
+ return NULL;
+
+ for (i = 0; i < elems; i++) {
+ if (match(fromsec, check->fromsec)) {
+ if (check->bad_tosec[0] && match(tosec, check->bad_tosec))
+ return check;
+ if (check->good_tosec[0] && !match(tosec, check->good_tosec))
+ return check;
+ }
+ check++;
+ }
+ return NULL;
+}
+
+/**
+ * Whitelist to allow certain references to pass with no warning.
+ *
+ * Pattern 1:
+ * If a module parameter is declared __initdata and permissions=0
+ * then this is legal despite the warning generated.
+ * We cannot see value of permissions here, so just ignore
+ * this pattern.
+ * The pattern is identified by:
+ * tosec = .init.data
+ * fromsec = .data*
+ * atsym =__param*
+ *
+ * Pattern 1a:
+ * module_param_call() ops can refer to __init set function if permissions=0
+ * The pattern is identified by:
+ * tosec = .init.text
+ * fromsec = .data*
+ * atsym = __param_ops_*
+ *
+ * Pattern 2:
+ * Many drivers utilise a *driver container with references to
+ * add, remove, probe functions etc.
+ * the pattern is identified by:
+ * tosec = init or exit section
+ * fromsec = data section
+ * atsym = *driver, *_template, *_sht, *_ops, *_probe,
+ * *probe_one, *_console, *_timer
+ *
+ * Pattern 3:
+ * Whitelist all references from .head.text to any init section
+ *
+ * Pattern 4:
+ * Some symbols belong to init section but still it is ok to reference
+ * these from non-init sections as these symbols don't have any memory
+ * allocated for them and symbol address and value are same. So even
+ * if init section is freed, its ok to reference those symbols.
+ * For ex. symbols marking the init section boundaries.
+ * This pattern is identified by
+ * refsymname = __init_begin, _sinittext, _einittext
+ *
+ * Pattern 5:
+ * GCC may optimize static inlines when fed constant arg(s) resulting
+ * in functions like cpumask_empty() -- generating an associated symbol
+ * cpumask_empty.constprop.3 that appears in the audit. If the const that
+ * is passed in comes from __init, like say nmi_ipi_mask, we get a
+ * meaningless section warning. May need to add isra symbols too...
+ * This pattern is identified by
+ * tosec = init section
+ * fromsec = text section
+ * refsymname = *.constprop.*
+ *
+ * Pattern 6:
+ * Hide section mismatch warnings for ELF local symbols. The goal
+ * is to eliminate false positive modpost warnings caused by
+ * compiler-generated ELF local symbol names such as ".LANCHOR1".
+ * Autogenerated symbol names bypass modpost's "Pattern 2"
+ * whitelisting, which relies on pattern-matching against symbol
+ * names to work. (One situation where gcc can autogenerate ELF
+ * local symbols is when "-fsection-anchors" is used.)
+ **/
+static int secref_whitelist(const struct sectioncheck *mismatch,
+ const char *fromsec, const char *fromsym,
+ const char *tosec, const char *tosym)
+{
+ /* Check for pattern 1 */
+ if (match(tosec, init_data_sections) &&
+ match(fromsec, data_sections) &&
+ strstarts(fromsym, "__param"))
+ return 0;
+
+ /* Check for pattern 1a */
+ if (strcmp(tosec, ".init.text") == 0 &&
+ match(fromsec, data_sections) &&
+ strstarts(fromsym, "__param_ops_"))
+ return 0;
+
+ /* Check for pattern 2 */
+ if (match(tosec, init_exit_sections) &&
+ match(fromsec, data_sections) &&
+ match(fromsym, mismatch->symbol_white_list))
+ return 0;
+
+ /* Check for pattern 3 */
+ if (match(fromsec, head_sections) &&
+ match(tosec, init_sections))
+ return 0;
+
+ /* Check for pattern 4 */
+ if (match(tosym, linker_symbols))
+ return 0;
+
+ /* Check for pattern 5 */
+ if (match(fromsec, text_sections) &&
+ match(tosec, init_sections) &&
+ match(fromsym, optim_symbols))
+ return 0;
+
+ /* Check for pattern 6 */
+ if (strstarts(fromsym, ".L"))
+ return 0;
+
+ return 1;
+}
+
+static inline int is_arm_mapping_symbol(const char *str)
+{
+ return str[0] == '$' && strchr("axtd", str[1])
+ && (str[2] == '\0' || str[2] == '.');
+}
+
+/*
+ * If there's no name there, ignore it; likewise, ignore it if it's
+ * one of the magic symbols emitted used by current ARM tools.
+ *
+ * Otherwise if find_symbols_between() returns those symbols, they'll
+ * fail the whitelist tests and cause lots of false alarms ... fixable
+ * only by merging __exit and __init sections into __text, bloating
+ * the kernel (which is especially evil on embedded platforms).
+ */
+static inline int is_valid_name(struct elf_info *elf, Elf_Sym *sym)
+{
+ const char *name = elf->strtab + sym->st_name;
+
+ if (!name || !strlen(name))
+ return 0;
+ return !is_arm_mapping_symbol(name);
+}
+
+/**
+ * Find symbol based on relocation record info.
+ * In some cases the symbol supplied is a valid symbol so
+ * return refsym. If st_name != 0 we assume this is a valid symbol.
+ * In other cases the symbol needs to be looked up in the symbol table
+ * based on section and address.
+ * **/
+static Elf_Sym *find_elf_symbol(struct elf_info *elf, Elf64_Sword addr,
+ Elf_Sym *relsym)
+{
+ Elf_Sym *sym;
+ Elf_Sym *near = NULL;
+ Elf64_Sword distance = 20;
+ Elf64_Sword d;
+ unsigned int relsym_secindex;
+
+ if (relsym->st_name != 0)
+ return relsym;
+
+ relsym_secindex = get_secindex(elf, relsym);
+ for (sym = elf->symtab_start; sym < elf->symtab_stop; sym++) {
+ if (get_secindex(elf, sym) != relsym_secindex)
+ continue;
+ if (ELF_ST_TYPE(sym->st_info) == STT_SECTION)
+ continue;
+ if (!is_valid_name(elf, sym))
+ continue;
+ if (sym->st_value == addr)
+ return sym;
+ /* Find a symbol nearby - addr are maybe negative */
+ d = sym->st_value - addr;
+ if (d < 0)
+ d = addr - sym->st_value;
+ if (d < distance) {
+ distance = d;
+ near = sym;
+ }
+ }
+ /* We need a close match */
+ if (distance < 20)
+ return near;
+ else
+ return NULL;
+}
+
+/*
+ * Find symbols before or equal addr and after addr - in the section sec.
+ * If we find two symbols with equal offset prefer one with a valid name.
+ * The ELF format may have a better way to detect what type of symbol
+ * it is, but this works for now.
+ **/
+static Elf_Sym *find_elf_symbol2(struct elf_info *elf, Elf_Addr addr,
+ const char *sec)
+{
+ Elf_Sym *sym;
+ Elf_Sym *near = NULL;
+ Elf_Addr distance = ~0;
+
+ for (sym = elf->symtab_start; sym < elf->symtab_stop; sym++) {
+ const char *symsec;
+
+ if (is_shndx_special(sym->st_shndx))
+ continue;
+ symsec = sec_name(elf, get_secindex(elf, sym));
+ if (strcmp(symsec, sec) != 0)
+ continue;
+ if (!is_valid_name(elf, sym))
+ continue;
+ if (sym->st_value <= addr) {
+ if ((addr - sym->st_value) < distance) {
+ distance = addr - sym->st_value;
+ near = sym;
+ } else if ((addr - sym->st_value) == distance) {
+ near = sym;
+ }
+ }
+ }
+ return near;
+}
+
+/*
+ * Convert a section name to the function/data attribute
+ * .init.text => __init
+ * .memexitconst => __memconst
+ * etc.
+ *
+ * The memory of returned value has been allocated on a heap. The user of this
+ * method should free it after usage.
+*/
+static char *sec2annotation(const char *s)
+{
+ if (match(s, init_exit_sections)) {
+ char *p = NOFAIL(malloc(20));
+ char *r = p;
+
+ *p++ = '_';
+ *p++ = '_';
+ if (*s == '.')
+ s++;
+ while (*s && *s != '.')
+ *p++ = *s++;
+ *p = '\0';
+ if (*s == '.')
+ s++;
+ if (strstr(s, "rodata") != NULL)
+ strcat(p, "const ");
+ else if (strstr(s, "data") != NULL)
+ strcat(p, "data ");
+ else
+ strcat(p, " ");
+ return r;
+ } else {
+ return NOFAIL(strdup(""));
+ }
+}
+
+static int is_function(Elf_Sym *sym)
+{
+ if (sym)
+ return ELF_ST_TYPE(sym->st_info) == STT_FUNC;
+ else
+ return -1;
+}
+
+static void print_section_list(const char * const list[20])
+{
+ const char *const *s = list;
+
+ while (*s) {
+ fprintf(stderr, "%s", *s);
+ s++;
+ if (*s)
+ fprintf(stderr, ", ");
+ }
+ fprintf(stderr, "\n");
+}
+
+static inline void get_pretty_name(int is_func, const char** name, const char** name_p)
+{
+ switch (is_func) {
+ case 0: *name = "variable"; *name_p = ""; break;
+ case 1: *name = "function"; *name_p = "()"; break;
+ default: *name = "(unknown reference)"; *name_p = ""; break;
+ }
+}
+
+/*
+ * Print a warning about a section mismatch.
+ * Try to find symbols near it so user can find it.
+ * Check whitelist before warning - it may be a false positive.
+ */
+static void report_sec_mismatch(const char *modname,
+ const struct sectioncheck *mismatch,
+ const char *fromsec,
+ unsigned long long fromaddr,
+ const char *fromsym,
+ int from_is_func,
+ const char *tosec, const char *tosym,
+ int to_is_func)
+{
+ const char *from, *from_p;
+ const char *to, *to_p;
+ char *prl_from;
+ char *prl_to;
+
+ sec_mismatch_count++;
+
+ get_pretty_name(from_is_func, &from, &from_p);
+ get_pretty_name(to_is_func, &to, &to_p);
+
+ warn("%s(%s+0x%llx): Section mismatch in reference from the %s %s%s "
+ "to the %s %s:%s%s\n",
+ modname, fromsec, fromaddr, from, fromsym, from_p, to, tosec,
+ tosym, to_p);
+
+ switch (mismatch->mismatch) {
+ case TEXT_TO_ANY_INIT:
+ prl_from = sec2annotation(fromsec);
+ prl_to = sec2annotation(tosec);
+ fprintf(stderr,
+ "The function %s%s() references\n"
+ "the %s %s%s%s.\n"
+ "This is often because %s lacks a %s\n"
+ "annotation or the annotation of %s is wrong.\n",
+ prl_from, fromsym,
+ to, prl_to, tosym, to_p,
+ fromsym, prl_to, tosym);
+ free(prl_from);
+ free(prl_to);
+ break;
+ case DATA_TO_ANY_INIT: {
+ prl_to = sec2annotation(tosec);
+ fprintf(stderr,
+ "The variable %s references\n"
+ "the %s %s%s%s\n"
+ "If the reference is valid then annotate the\n"
+ "variable with __init* or __refdata (see linux/init.h) "
+ "or name the variable:\n",
+ fromsym, to, prl_to, tosym, to_p);
+ print_section_list(mismatch->symbol_white_list);
+ free(prl_to);
+ break;
+ }
+ case TEXT_TO_ANY_EXIT:
+ prl_to = sec2annotation(tosec);
+ fprintf(stderr,
+ "The function %s() references a %s in an exit section.\n"
+ "Often the %s %s%s has valid usage outside the exit section\n"
+ "and the fix is to remove the %sannotation of %s.\n",
+ fromsym, to, to, tosym, to_p, prl_to, tosym);
+ free(prl_to);
+ break;
+ case DATA_TO_ANY_EXIT: {
+ prl_to = sec2annotation(tosec);
+ fprintf(stderr,
+ "The variable %s references\n"
+ "the %s %s%s%s\n"
+ "If the reference is valid then annotate the\n"
+ "variable with __exit* (see linux/init.h) or "
+ "name the variable:\n",
+ fromsym, to, prl_to, tosym, to_p);
+ print_section_list(mismatch->symbol_white_list);
+ free(prl_to);
+ break;
+ }
+ case XXXINIT_TO_SOME_INIT:
+ case XXXEXIT_TO_SOME_EXIT:
+ prl_from = sec2annotation(fromsec);
+ prl_to = sec2annotation(tosec);
+ fprintf(stderr,
+ "The %s %s%s%s references\n"
+ "a %s %s%s%s.\n"
+ "If %s is only used by %s then\n"
+ "annotate %s with a matching annotation.\n",
+ from, prl_from, fromsym, from_p,
+ to, prl_to, tosym, to_p,
+ tosym, fromsym, tosym);
+ free(prl_from);
+ free(prl_to);
+ break;
+ case ANY_INIT_TO_ANY_EXIT:
+ prl_from = sec2annotation(fromsec);
+ prl_to = sec2annotation(tosec);
+ fprintf(stderr,
+ "The %s %s%s%s references\n"
+ "a %s %s%s%s.\n"
+ "This is often seen when error handling "
+ "in the init function\n"
+ "uses functionality in the exit path.\n"
+ "The fix is often to remove the %sannotation of\n"
+ "%s%s so it may be used outside an exit section.\n",
+ from, prl_from, fromsym, from_p,
+ to, prl_to, tosym, to_p,
+ prl_to, tosym, to_p);
+ free(prl_from);
+ free(prl_to);
+ break;
+ case ANY_EXIT_TO_ANY_INIT:
+ prl_from = sec2annotation(fromsec);
+ prl_to = sec2annotation(tosec);
+ fprintf(stderr,
+ "The %s %s%s%s references\n"
+ "a %s %s%s%s.\n"
+ "This is often seen when error handling "
+ "in the exit function\n"
+ "uses functionality in the init path.\n"
+ "The fix is often to remove the %sannotation of\n"
+ "%s%s so it may be used outside an init section.\n",
+ from, prl_from, fromsym, from_p,
+ to, prl_to, tosym, to_p,
+ prl_to, tosym, to_p);
+ free(prl_from);
+ free(prl_to);
+ break;
+ case EXPORT_TO_INIT_EXIT:
+ prl_to = sec2annotation(tosec);
+ fprintf(stderr,
+ "The symbol %s is exported and annotated %s\n"
+ "Fix this by removing the %sannotation of %s "
+ "or drop the export.\n",
+ tosym, prl_to, prl_to, tosym);
+ free(prl_to);
+ break;
+ case EXTABLE_TO_NON_TEXT:
+ fatal("There's a special handler for this mismatch type, "
+ "we should never get here.");
+ break;
+ }
+ fprintf(stderr, "\n");
+}
+
+static void default_mismatch_handler(const char *modname, struct elf_info *elf,
+ const struct sectioncheck* const mismatch,
+ Elf_Rela *r, Elf_Sym *sym, const char *fromsec)
+{
+ const char *tosec;
+ Elf_Sym *to;
+ Elf_Sym *from;
+ const char *tosym;
+ const char *fromsym;
+
+ from = find_elf_symbol2(elf, r->r_offset, fromsec);
+ fromsym = sym_name(elf, from);
+
+ if (strstarts(fromsym, "reference___initcall"))
+ return;
+
+ tosec = sec_name(elf, get_secindex(elf, sym));
+ to = find_elf_symbol(elf, r->r_addend, sym);
+ tosym = sym_name(elf, to);
+
+ /* check whitelist - we may ignore it */
+ if (secref_whitelist(mismatch,
+ fromsec, fromsym, tosec, tosym)) {
+ report_sec_mismatch(modname, mismatch,
+ fromsec, r->r_offset, fromsym,
+ is_function(from), tosec, tosym,
+ is_function(to));
+ }
+}
+
+static int is_executable_section(struct elf_info* elf, unsigned int section_index)
+{
+ if (section_index > elf->num_sections)
+ fatal("section_index is outside elf->num_sections!\n");
+
+ return ((elf->sechdrs[section_index].sh_flags & SHF_EXECINSTR) == SHF_EXECINSTR);
+}
+
+/*
+ * We rely on a gross hack in section_rel[a]() calling find_extable_entry_size()
+ * to know the sizeof(struct exception_table_entry) for the target architecture.
+ */
+static unsigned int extable_entry_size = 0;
+static void find_extable_entry_size(const char* const sec, const Elf_Rela* r)
+{
+ /*
+ * If we're currently checking the second relocation within __ex_table,
+ * that relocation offset tells us the offsetof(struct
+ * exception_table_entry, fixup) which is equal to sizeof(struct
+ * exception_table_entry) divided by two. We use that to our advantage
+ * since there's no portable way to get that size as every architecture
+ * seems to go with different sized types. Not pretty but better than
+ * hard-coding the size for every architecture..
+ */
+ if (!extable_entry_size)
+ extable_entry_size = r->r_offset * 2;
+}
+
+static inline bool is_extable_fault_address(Elf_Rela *r)
+{
+ /*
+ * extable_entry_size is only discovered after we've handled the
+ * _second_ relocation in __ex_table, so only abort when we're not
+ * handling the first reloc and extable_entry_size is zero.
+ */
+ if (r->r_offset && extable_entry_size == 0)
+ fatal("extable_entry size hasn't been discovered!\n");
+
+ return ((r->r_offset == 0) ||
+ (r->r_offset % extable_entry_size == 0));
+}
+
+#define is_second_extable_reloc(Start, Cur, Sec) \
+ (((Cur) == (Start) + 1) && (strcmp("__ex_table", (Sec)) == 0))
+
+static void report_extable_warnings(const char* modname, struct elf_info* elf,
+ const struct sectioncheck* const mismatch,
+ Elf_Rela* r, Elf_Sym* sym,
+ const char* fromsec, const char* tosec)
+{
+ Elf_Sym* fromsym = find_elf_symbol2(elf, r->r_offset, fromsec);
+ const char* fromsym_name = sym_name(elf, fromsym);
+ Elf_Sym* tosym = find_elf_symbol(elf, r->r_addend, sym);
+ const char* tosym_name = sym_name(elf, tosym);
+ const char* from_pretty_name;
+ const char* from_pretty_name_p;
+ const char* to_pretty_name;
+ const char* to_pretty_name_p;
+
+ get_pretty_name(is_function(fromsym),
+ &from_pretty_name, &from_pretty_name_p);
+ get_pretty_name(is_function(tosym),
+ &to_pretty_name, &to_pretty_name_p);
+
+ warn("%s(%s+0x%lx): Section mismatch in reference"
+ " from the %s %s%s to the %s %s:%s%s\n",
+ modname, fromsec, (long)r->r_offset, from_pretty_name,
+ fromsym_name, from_pretty_name_p,
+ to_pretty_name, tosec, tosym_name, to_pretty_name_p);
+
+ if (!match(tosec, mismatch->bad_tosec) &&
+ is_executable_section(elf, get_secindex(elf, sym)))
+ fprintf(stderr,
+ "The relocation at %s+0x%lx references\n"
+ "section \"%s\" which is not in the list of\n"
+ "authorized sections. If you're adding a new section\n"
+ "and/or if this reference is valid, add \"%s\" to the\n"
+ "list of authorized sections to jump to on fault.\n"
+ "This can be achieved by adding \"%s\" to \n"
+ "OTHER_TEXT_SECTIONS in scripts/mod/modpost.c.\n",
+ fromsec, (long)r->r_offset, tosec, tosec, tosec);
+}
+
+static void extable_mismatch_handler(const char* modname, struct elf_info *elf,
+ const struct sectioncheck* const mismatch,
+ Elf_Rela* r, Elf_Sym* sym,
+ const char *fromsec)
+{
+ const char* tosec = sec_name(elf, get_secindex(elf, sym));
+
+ sec_mismatch_count++;
+
+ report_extable_warnings(modname, elf, mismatch, r, sym, fromsec, tosec);
+
+ if (match(tosec, mismatch->bad_tosec))
+ fatal("The relocation at %s+0x%lx references\n"
+ "section \"%s\" which is black-listed.\n"
+ "Something is seriously wrong and should be fixed.\n"
+ "You might get more information about where this is\n"
+ "coming from by using scripts/check_extable.sh %s\n",
+ fromsec, (long)r->r_offset, tosec, modname);
+ else if (!is_executable_section(elf, get_secindex(elf, sym))) {
+ if (is_extable_fault_address(r))
+ fatal("The relocation at %s+0x%lx references\n"
+ "section \"%s\" which is not executable, IOW\n"
+ "it is not possible for the kernel to fault\n"
+ "at that address. Something is seriously wrong\n"
+ "and should be fixed.\n",
+ fromsec, (long)r->r_offset, tosec);
+ else
+ fatal("The relocation at %s+0x%lx references\n"
+ "section \"%s\" which is not executable, IOW\n"
+ "the kernel will fault if it ever tries to\n"
+ "jump to it. Something is seriously wrong\n"
+ "and should be fixed.\n",
+ fromsec, (long)r->r_offset, tosec);
+ }
+}
+
+static void check_section_mismatch(const char *modname, struct elf_info *elf,
+ Elf_Rela *r, Elf_Sym *sym, const char *fromsec)
+{
+ const char *tosec = sec_name(elf, get_secindex(elf, sym));
+ const struct sectioncheck *mismatch = section_mismatch(fromsec, tosec);
+
+ if (mismatch) {
+ if (mismatch->handler)
+ mismatch->handler(modname, elf, mismatch,
+ r, sym, fromsec);
+ else
+ default_mismatch_handler(modname, elf, mismatch,
+ r, sym, fromsec);
+ }
+}
+
+static unsigned int *reloc_location(struct elf_info *elf,
+ Elf_Shdr *sechdr, Elf_Rela *r)
+{
+ return sym_get_data_by_offset(elf, sechdr->sh_info, r->r_offset);
+}
+
+static int addend_386_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r)
+{
+ unsigned int r_typ = ELF_R_TYPE(r->r_info);
+ unsigned int *location = reloc_location(elf, sechdr, r);
+
+ switch (r_typ) {
+ case R_386_32:
+ r->r_addend = TO_NATIVE(*location);
+ break;
+ case R_386_PC32:
+ r->r_addend = TO_NATIVE(*location) + 4;
+ /* For CONFIG_RELOCATABLE=y */
+ if (elf->hdr->e_type == ET_EXEC)
+ r->r_addend += r->r_offset;
+ break;
+ }
+ return 0;
+}
+
+#ifndef R_ARM_CALL
+#define R_ARM_CALL 28
+#endif
+#ifndef R_ARM_JUMP24
+#define R_ARM_JUMP24 29
+#endif
+
+#ifndef R_ARM_THM_CALL
+#define R_ARM_THM_CALL 10
+#endif
+#ifndef R_ARM_THM_JUMP24
+#define R_ARM_THM_JUMP24 30
+#endif
+#ifndef R_ARM_THM_JUMP19
+#define R_ARM_THM_JUMP19 51
+#endif
+
+static int addend_arm_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r)
+{
+ unsigned int r_typ = ELF_R_TYPE(r->r_info);
+
+ switch (r_typ) {
+ case R_ARM_ABS32:
+ /* From ARM ABI: (S + A) | T */
+ r->r_addend = (int)(long)
+ (elf->symtab_start + ELF_R_SYM(r->r_info));
+ break;
+ case R_ARM_PC24:
+ case R_ARM_CALL:
+ case R_ARM_JUMP24:
+ case R_ARM_THM_CALL:
+ case R_ARM_THM_JUMP24:
+ case R_ARM_THM_JUMP19:
+ /* From ARM ABI: ((S + A) | T) - P */
+ r->r_addend = (int)(long)(elf->hdr +
+ sechdr->sh_offset +
+ (r->r_offset - sechdr->sh_addr));
+ break;
+ default:
+ return 1;
+ }
+ return 0;
+}
+
+static int addend_mips_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r)
+{
+ unsigned int r_typ = ELF_R_TYPE(r->r_info);
+ unsigned int *location = reloc_location(elf, sechdr, r);
+ unsigned int inst;
+
+ if (r_typ == R_MIPS_HI16)
+ return 1; /* skip this */
+ inst = TO_NATIVE(*location);
+ switch (r_typ) {
+ case R_MIPS_LO16:
+ r->r_addend = inst & 0xffff;
+ break;
+ case R_MIPS_26:
+ r->r_addend = (inst & 0x03ffffff) << 2;
+ break;
+ case R_MIPS_32:
+ r->r_addend = inst;
+ break;
+ }
+ return 0;
+}
+
+static void section_rela(const char *modname, struct elf_info *elf,
+ Elf_Shdr *sechdr)
+{
+ Elf_Sym *sym;
+ Elf_Rela *rela;
+ Elf_Rela r;
+ unsigned int r_sym;
+ const char *fromsec;
+
+ Elf_Rela *start = (void *)elf->hdr + sechdr->sh_offset;
+ Elf_Rela *stop = (void *)start + sechdr->sh_size;
+
+ fromsec = sech_name(elf, sechdr);
+ fromsec += strlen(".rela");
+ /* if from section (name) is know good then skip it */
+ if (match(fromsec, section_white_list))
+ return;
+
+ for (rela = start; rela < stop; rela++) {
+ r.r_offset = TO_NATIVE(rela->r_offset);
+#if KERNEL_ELFCLASS == ELFCLASS64
+ if (elf->hdr->e_machine == EM_MIPS) {
+ unsigned int r_typ;
+ r_sym = ELF64_MIPS_R_SYM(rela->r_info);
+ r_sym = TO_NATIVE(r_sym);
+ r_typ = ELF64_MIPS_R_TYPE(rela->r_info);
+ r.r_info = ELF64_R_INFO(r_sym, r_typ);
+ } else {
+ r.r_info = TO_NATIVE(rela->r_info);
+ r_sym = ELF_R_SYM(r.r_info);
+ }
+#else
+ r.r_info = TO_NATIVE(rela->r_info);
+ r_sym = ELF_R_SYM(r.r_info);
+#endif
+ r.r_addend = TO_NATIVE(rela->r_addend);
+ sym = elf->symtab_start + r_sym;
+ /* Skip special sections */
+ if (is_shndx_special(sym->st_shndx))
+ continue;
+ if (is_second_extable_reloc(start, rela, fromsec))
+ find_extable_entry_size(fromsec, &r);
+ check_section_mismatch(modname, elf, &r, sym, fromsec);
+ }
+}
+
+static void section_rel(const char *modname, struct elf_info *elf,
+ Elf_Shdr *sechdr)
+{
+ Elf_Sym *sym;
+ Elf_Rel *rel;
+ Elf_Rela r;
+ unsigned int r_sym;
+ const char *fromsec;
+
+ Elf_Rel *start = (void *)elf->hdr + sechdr->sh_offset;
+ Elf_Rel *stop = (void *)start + sechdr->sh_size;
+
+ fromsec = sech_name(elf, sechdr);
+ fromsec += strlen(".rel");
+ /* if from section (name) is know good then skip it */
+ if (match(fromsec, section_white_list))
+ return;
+
+ for (rel = start; rel < stop; rel++) {
+ r.r_offset = TO_NATIVE(rel->r_offset);
+#if KERNEL_ELFCLASS == ELFCLASS64
+ if (elf->hdr->e_machine == EM_MIPS) {
+ unsigned int r_typ;
+ r_sym = ELF64_MIPS_R_SYM(rel->r_info);
+ r_sym = TO_NATIVE(r_sym);
+ r_typ = ELF64_MIPS_R_TYPE(rel->r_info);
+ r.r_info = ELF64_R_INFO(r_sym, r_typ);
+ } else {
+ r.r_info = TO_NATIVE(rel->r_info);
+ r_sym = ELF_R_SYM(r.r_info);
+ }
+#else
+ r.r_info = TO_NATIVE(rel->r_info);
+ r_sym = ELF_R_SYM(r.r_info);
+#endif
+ r.r_addend = 0;
+ switch (elf->hdr->e_machine) {
+ case EM_386:
+ if (addend_386_rel(elf, sechdr, &r))
+ continue;
+ break;
+ case EM_ARM:
+ if (addend_arm_rel(elf, sechdr, &r))
+ continue;
+ break;
+ case EM_MIPS:
+ if (addend_mips_rel(elf, sechdr, &r))
+ continue;
+ break;
+ }
+ sym = elf->symtab_start + r_sym;
+ /* Skip special sections */
+ if (is_shndx_special(sym->st_shndx))
+ continue;
+ if (is_second_extable_reloc(start, rel, fromsec))
+ find_extable_entry_size(fromsec, &r);
+ check_section_mismatch(modname, elf, &r, sym, fromsec);
+ }
+}
+
+/**
+ * A module includes a number of sections that are discarded
+ * either when loaded or when used as built-in.
+ * For loaded modules all functions marked __init and all data
+ * marked __initdata will be discarded when the module has been initialized.
+ * Likewise for modules used built-in the sections marked __exit
+ * are discarded because __exit marked function are supposed to be called
+ * only when a module is unloaded which never happens for built-in modules.
+ * The check_sec_ref() function traverses all relocation records
+ * to find all references to a section that reference a section that will
+ * be discarded and warns about it.
+ **/
+static void check_sec_ref(struct module *mod, const char *modname,
+ struct elf_info *elf)
+{
+ int i;
+ Elf_Shdr *sechdrs = elf->sechdrs;
+
+ /* Walk through all sections */
+ for (i = 0; i < elf->num_sections; i++) {
+ check_section(modname, elf, &elf->sechdrs[i]);
+ /* We want to process only relocation sections and not .init */
+ if (sechdrs[i].sh_type == SHT_RELA)
+ section_rela(modname, elf, &elf->sechdrs[i]);
+ else if (sechdrs[i].sh_type == SHT_REL)
+ section_rel(modname, elf, &elf->sechdrs[i]);
+ }
+}
+
+static char *remove_dot(char *s)
+{
+ size_t n = strcspn(s, ".");
+
+ if (n && s[n]) {
+ size_t m = strspn(s + n + 1, "0123456789");
+ if (m && (s[n + m] == '.' || s[n + m] == 0))
+ s[n] = 0;
+
+ /* strip trailing .lto */
+ if (strends(s, ".lto"))
+ s[strlen(s) - 4] = '\0';
+ }
+ return s;
+}
+
+static void read_symbols(const char *modname)
+{
+ const char *symname;
+ char *version;
+ char *license;
+ char *namespace;
+ struct module *mod;
+ struct elf_info info = { };
+ Elf_Sym *sym;
+
+ if (!parse_elf(&info, modname))
+ return;
+
+ {
+ char *tmp;
+
+ /* strip trailing .o */
+ tmp = NOFAIL(strdup(modname));
+ tmp[strlen(tmp) - 2] = '\0';
+ /* strip trailing .lto */
+ if (strends(tmp, ".lto"))
+ tmp[strlen(tmp) - 4] = '\0';
+ mod = new_module(tmp);
+ free(tmp);
+ }
+
+ if (!mod->is_vmlinux) {
+ license = get_modinfo(&info, "license");
+ if (!license)
+ error("missing MODULE_LICENSE() in %s\n", modname);
+ while (license) {
+ if (license_is_gpl_compatible(license))
+ mod->gpl_compatible = 1;
+ else {
+ mod->gpl_compatible = 0;
+ break;
+ }
+ license = get_next_modinfo(&info, "license", license);
+ }
+
+ namespace = get_modinfo(&info, "import_ns");
+ while (namespace) {
+ add_namespace(&mod->imported_namespaces, namespace);
+ namespace = get_next_modinfo(&info, "import_ns",
+ namespace);
+ }
+ }
+
+ for (sym = info.symtab_start; sym < info.symtab_stop; sym++) {
+ symname = remove_dot(info.strtab + sym->st_name);
+
+ handle_symbol(mod, &info, sym, symname);
+ handle_moddevtable(mod, &info, sym, symname);
+ }
+
+ for (sym = info.symtab_start; sym < info.symtab_stop; sym++) {
+ symname = remove_dot(info.strtab + sym->st_name);
+
+ /* Apply symbol namespaces from __kstrtabns_<symbol> entries. */
+ if (strstarts(symname, "__kstrtabns_"))
+ sym_update_namespace(symname + strlen("__kstrtabns_"),
+ namespace_from_kstrtabns(&info,
+ sym));
+
+ if (strstarts(symname, "__crc_"))
+ handle_modversion(mod, &info, sym,
+ symname + strlen("__crc_"));
+ }
+
+ // check for static EXPORT_SYMBOL_* functions && global vars
+ for (sym = info.symtab_start; sym < info.symtab_stop; sym++) {
+ unsigned char bind = ELF_ST_BIND(sym->st_info);
+
+ if (bind == STB_GLOBAL || bind == STB_WEAK) {
+ struct symbol *s =
+ find_symbol(remove_dot(info.strtab +
+ sym->st_name));
+
+ if (s)
+ s->is_static = 0;
+ }
+ }
+
+ check_sec_ref(mod, modname, &info);
+
+ if (!mod->is_vmlinux) {
+ version = get_modinfo(&info, "version");
+ if (version || all_versions)
+ get_src_version(modname, mod->srcversion,
+ sizeof(mod->srcversion) - 1);
+ }
+
+ parse_elf_finish(&info);
+
+ /* Our trick to get versioning for module struct etc. - it's
+ * never passed as an argument to an exported function, so
+ * the automatic versioning doesn't pick it up, but it's really
+ * important anyhow */
+ if (modversions)
+ mod->unres = alloc_symbol("module_layout", 0, mod->unres);
+}
+
+static void read_symbols_from_files(const char *filename)
+{
+ FILE *in = stdin;
+ char fname[PATH_MAX];
+
+ if (strcmp(filename, "-") != 0) {
+ in = fopen(filename, "r");
+ if (!in)
+ fatal("Can't open filenames file %s: %m", filename);
+ }
+
+ while (fgets(fname, PATH_MAX, in) != NULL) {
+ if (strends(fname, "\n"))
+ fname[strlen(fname)-1] = '\0';
+ read_symbols(fname);
+ }
+
+ if (in != stdin)
+ fclose(in);
+}
+
+#define SZ 500
+
+/* We first write the generated file into memory using the
+ * following helper, then compare to the file on disk and
+ * only update the later if anything changed */
+
+void __attribute__((format(printf, 2, 3))) buf_printf(struct buffer *buf,
+ const char *fmt, ...)
+{
+ char tmp[SZ];
+ int len;
+ va_list ap;
+
+ va_start(ap, fmt);
+ len = vsnprintf(tmp, SZ, fmt, ap);
+ buf_write(buf, tmp, len);
+ va_end(ap);
+}
+
+void buf_write(struct buffer *buf, const char *s, int len)
+{
+ if (buf->size - buf->pos < len) {
+ buf->size += len + SZ;
+ buf->p = NOFAIL(realloc(buf->p, buf->size));
+ }
+ strncpy(buf->p + buf->pos, s, len);
+ buf->pos += len;
+}
+
+static void check_for_gpl_usage(enum export exp, const char *m, const char *s)
+{
+ switch (exp) {
+ case export_gpl:
+ error("GPL-incompatible module %s.ko uses GPL-only symbol '%s'\n",
+ m, s);
+ break;
+ case export_unused_gpl:
+ error("GPL-incompatible module %s.ko uses GPL-only symbol marked UNUSED '%s'\n",
+ m, s);
+ break;
+ case export_gpl_future:
+ warn("GPL-incompatible module %s.ko uses future GPL-only symbol '%s'\n",
+ m, s);
+ break;
+ case export_plain:
+ case export_unused:
+ case export_unknown:
+ /* ignore */
+ break;
+ }
+}
+
+static void check_for_unused(enum export exp, const char *m, const char *s)
+{
+ switch (exp) {
+ case export_unused:
+ case export_unused_gpl:
+ warn("module %s.ko uses symbol '%s' marked UNUSED\n",
+ m, s);
+ break;
+ default:
+ /* ignore */
+ break;
+ }
+}
+
+static void check_exports(struct module *mod)
+{
+ struct symbol *s, *exp;
+
+ for (s = mod->unres; s; s = s->next) {
+ const char *basename;
+ exp = find_symbol(s->name);
+ if (!exp || exp->module == mod) {
+ if (have_vmlinux && !s->weak)
+ modpost_log(warn_unresolved ? LOG_WARN : LOG_ERROR,
+ "\"%s\" [%s.ko] undefined!\n",
+ s->name, mod->name);
+ continue;
+ }
+ basename = strrchr(mod->name, '/');
+ if (basename)
+ basename++;
+ else
+ basename = mod->name;
+
+ if (exp->namespace &&
+ !module_imports_namespace(mod, exp->namespace)) {
+ modpost_log(allow_missing_ns_imports ? LOG_WARN : LOG_ERROR,
+ "module %s uses symbol %s from namespace %s, but does not import it.\n",
+ basename, exp->name, exp->namespace);
+ add_namespace(&mod->missing_namespaces, exp->namespace);
+ }
+
+ if (!mod->gpl_compatible)
+ check_for_gpl_usage(exp->export, basename, exp->name);
+ check_for_unused(exp->export, basename, exp->name);
+ }
+}
+
+static void check_modname_len(struct module *mod)
+{
+ const char *mod_name;
+
+ mod_name = strrchr(mod->name, '/');
+ if (mod_name == NULL)
+ mod_name = mod->name;
+ else
+ mod_name++;
+ if (strlen(mod_name) >= MODULE_NAME_LEN)
+ error("module name is too long [%s.ko]\n", mod->name);
+}
+
+/**
+ * Header for the generated file
+ **/
+static void add_header(struct buffer *b, struct module *mod)
+{
+ buf_printf(b, "#include <linux/module.h>\n");
+ /*
+ * Include build-salt.h after module.h in order to
+ * inherit the definitions.
+ */
+ buf_printf(b, "#define INCLUDE_VERMAGIC\n");
+ buf_printf(b, "#include <linux/build-salt.h>\n");
+ buf_printf(b, "#include <linux/vermagic.h>\n");
+ buf_printf(b, "#include <linux/compiler.h>\n");
+ buf_printf(b, "\n");
+ buf_printf(b, "BUILD_SALT;\n");
+ buf_printf(b, "\n");
+ buf_printf(b, "MODULE_INFO(vermagic, VERMAGIC_STRING);\n");
+ buf_printf(b, "MODULE_INFO(name, KBUILD_MODNAME);\n");
+ buf_printf(b, "\n");
+ buf_printf(b, "__visible struct module __this_module\n");
+ buf_printf(b, "__section(\".gnu.linkonce.this_module\") = {\n");
+ buf_printf(b, "\t.name = KBUILD_MODNAME,\n");
+ if (mod->has_init)
+ buf_printf(b, "\t.init = init_module,\n");
+ if (mod->has_cleanup)
+ buf_printf(b, "#ifdef CONFIG_MODULE_UNLOAD\n"
+ "\t.exit = cleanup_module,\n"
+ "#endif\n");
+ buf_printf(b, "\t.arch = MODULE_ARCH_INIT,\n");
+ buf_printf(b, "};\n");
+}
+
+static void add_intree_flag(struct buffer *b, int is_intree)
+{
+ if (is_intree)
+ buf_printf(b, "\nMODULE_INFO(intree, \"Y\");\n");
+}
+
+/**
+ * add_scmversion() - Adds the MODULE_INFO macro for the scmversion.
+ * @b: Buffer to append to.
+ *
+ * This function fills in the module attribute `scmversion` for the kernel
+ * module. This is useful for determining a given module's SCM version on
+ * device via /sys/modules/<module>/scmversion and/or using the modinfo tool.
+ */
+static void add_scmversion(struct buffer *b)
+{
+ if (module_scmversion[0] != '\0')
+ buf_printf(b, "\nMODULE_INFO(scmversion, \"%s\");\n", module_scmversion);
+}
+
+/* Cannot check for assembler */
+static void add_retpoline(struct buffer *b)
+{
+ buf_printf(b, "\n#ifdef CONFIG_RETPOLINE\n");
+ buf_printf(b, "MODULE_INFO(retpoline, \"Y\");\n");
+ buf_printf(b, "#endif\n");
+}
+
+static void add_staging_flag(struct buffer *b, const char *name)
+{
+ if (strstarts(name, "drivers/staging"))
+ buf_printf(b, "\nMODULE_INFO(staging, \"Y\");\n");
+}
+
+/**
+ * Record CRCs for unresolved symbols
+ **/
+static void add_versions(struct buffer *b, struct module *mod)
+{
+ struct symbol *s, *exp;
+
+ for (s = mod->unres; s; s = s->next) {
+ exp = find_symbol(s->name);
+ if (!exp || exp->module == mod)
+ continue;
+ s->module = exp->module;
+ s->crc_valid = exp->crc_valid;
+ s->crc = exp->crc;
+ }
+
+ if (!modversions)
+ return;
+
+ buf_printf(b, "\n");
+ buf_printf(b, "static const struct modversion_info ____versions[]\n");
+ buf_printf(b, "__used __section(\"__versions\") = {\n");
+
+ for (s = mod->unres; s; s = s->next) {
+ if (!s->module)
+ continue;
+ if (!s->crc_valid) {
+ warn("\"%s\" [%s.ko] has no CRC!\n",
+ s->name, mod->name);
+ continue;
+ }
+ if (strlen(s->name) >= MODULE_NAME_LEN) {
+ error("too long symbol \"%s\" [%s.ko]\n",
+ s->name, mod->name);
+ break;
+ }
+ buf_printf(b, "\t{ %#8x, \"%s\" },\n",
+ s->crc, s->name);
+ }
+
+ buf_printf(b, "};\n");
+}
+
+static void add_depends(struct buffer *b, struct module *mod)
+{
+ struct symbol *s;
+ int first = 1;
+
+ /* Clear ->seen flag of modules that own symbols needed by this. */
+ for (s = mod->unres; s; s = s->next)
+ if (s->module)
+ s->module->seen = s->module->is_vmlinux;
+
+ buf_printf(b, "\n");
+ buf_printf(b, "MODULE_INFO(depends, \"");
+ for (s = mod->unres; s; s = s->next) {
+ const char *p;
+ if (!s->module)
+ continue;
+
+ if (s->module->seen)
+ continue;
+
+ s->module->seen = 1;
+ p = strrchr(s->module->name, '/');
+ if (p)
+ p++;
+ else
+ p = s->module->name;
+ buf_printf(b, "%s%s", first ? "" : ",", p);
+ first = 0;
+ }
+ buf_printf(b, "\");\n");
+}
+
+static void add_srcversion(struct buffer *b, struct module *mod)
+{
+ if (mod->srcversion[0]) {
+ buf_printf(b, "\n");
+ buf_printf(b, "MODULE_INFO(srcversion, \"%s\");\n",
+ mod->srcversion);
+ }
+}
+
+static void write_buf(struct buffer *b, const char *fname)
+{
+ FILE *file;
+
+ file = fopen(fname, "w");
+ if (!file) {
+ perror(fname);
+ exit(1);
+ }
+ if (fwrite(b->p, 1, b->pos, file) != b->pos) {
+ perror(fname);
+ exit(1);
+ }
+ if (fclose(file) != 0) {
+ perror(fname);
+ exit(1);
+ }
+}
+
+static void write_if_changed(struct buffer *b, const char *fname)
+{
+ char *tmp;
+ FILE *file;
+ struct stat st;
+
+ file = fopen(fname, "r");
+ if (!file)
+ goto write;
+
+ if (fstat(fileno(file), &st) < 0)
+ goto close_write;
+
+ if (st.st_size != b->pos)
+ goto close_write;
+
+ tmp = NOFAIL(malloc(b->pos));
+ if (fread(tmp, 1, b->pos, file) != b->pos)
+ goto free_write;
+
+ if (memcmp(tmp, b->p, b->pos) != 0)
+ goto free_write;
+
+ free(tmp);
+ fclose(file);
+ return;
+
+ free_write:
+ free(tmp);
+ close_write:
+ fclose(file);
+ write:
+ write_buf(b, fname);
+}
+
+/* parse Module.symvers file. line format:
+ * 0x12345678<tab>symbol<tab>module<tab>export<tab>namespace
+ **/
+static void read_dump(const char *fname)
+{
+ char *buf, *pos, *line;
+
+ buf = read_text_file(fname);
+ if (!buf)
+ /* No symbol versions, silently ignore */
+ return;
+
+ pos = buf;
+
+ while ((line = get_line(&pos))) {
+ char *symname, *namespace, *modname, *d, *export;
+ unsigned int crc;
+ struct module *mod;
+ struct symbol *s;
+
+ if (!(symname = strchr(line, '\t')))
+ goto fail;
+ *symname++ = '\0';
+ if (!(modname = strchr(symname, '\t')))
+ goto fail;
+ *modname++ = '\0';
+ if (!(export = strchr(modname, '\t')))
+ goto fail;
+ *export++ = '\0';
+ if (!(namespace = strchr(export, '\t')))
+ goto fail;
+ *namespace++ = '\0';
+
+ crc = strtoul(line, &d, 16);
+ if (*symname == '\0' || *modname == '\0' || *d != '\0')
+ goto fail;
+ mod = find_module(modname);
+ if (!mod) {
+ mod = new_module(modname);
+ mod->from_dump = 1;
+ }
+ s = sym_add_exported(symname, mod, export_no(export));
+ s->is_static = 0;
+ sym_set_crc(symname, crc);
+ sym_update_namespace(symname, namespace);
+ }
+ free(buf);
+ return;
+fail:
+ free(buf);
+ fatal("parse error in symbol dump file\n");
+}
+
+static void write_dump(const char *fname)
+{
+ struct buffer buf = { };
+ struct symbol *symbol;
+ const char *namespace;
+ int n;
+
+ for (n = 0; n < SYMBOL_HASH_SIZE ; n++) {
+ symbol = symbolhash[n];
+ while (symbol) {
+ if (!symbol->module->from_dump) {
+ namespace = symbol->namespace;
+ buf_printf(&buf, "0x%08x\t%s\t%s\t%s\t%s\n",
+ symbol->crc, symbol->name,
+ symbol->module->name,
+ export_str(symbol->export),
+ namespace ? namespace : "");
+ }
+ symbol = symbol->next;
+ }
+ }
+ write_buf(&buf, fname);
+ free(buf.p);
+}
+
+static void write_namespace_deps_files(const char *fname)
+{
+ struct module *mod;
+ struct namespace_list *ns;
+ struct buffer ns_deps_buf = {};
+
+ for (mod = modules; mod; mod = mod->next) {
+
+ if (mod->from_dump || !mod->missing_namespaces)
+ continue;
+
+ buf_printf(&ns_deps_buf, "%s.ko:", mod->name);
+
+ for (ns = mod->missing_namespaces; ns; ns = ns->next)
+ buf_printf(&ns_deps_buf, " %s", ns->namespace);
+
+ buf_printf(&ns_deps_buf, "\n");
+ }
+
+ write_if_changed(&ns_deps_buf, fname);
+ free(ns_deps_buf.p);
+}
+
+struct dump_list {
+ struct dump_list *next;
+ const char *file;
+};
+
+int main(int argc, char **argv)
+{
+ struct module *mod;
+ struct buffer buf = { };
+ char *missing_namespace_deps = NULL;
+ char *dump_write = NULL, *files_source = NULL;
+ int opt;
+ int n;
+ struct dump_list *dump_read_start = NULL;
+ struct dump_list **dump_read_iter = &dump_read_start;
+
+ while ((opt = getopt(argc, argv, "ei:mnT:o:awENd:v:")) != -1) {
+ switch (opt) {
+ case 'e':
+ external_module = 1;
+ break;
+ case 'i':
+ *dump_read_iter =
+ NOFAIL(calloc(1, sizeof(**dump_read_iter)));
+ (*dump_read_iter)->file = optarg;
+ dump_read_iter = &(*dump_read_iter)->next;
+ break;
+ case 'm':
+ modversions = 1;
+ break;
+ case 'n':
+ ignore_missing_files = 1;
+ break;
+ case 'o':
+ dump_write = optarg;
+ break;
+ case 'a':
+ all_versions = 1;
+ break;
+ case 'T':
+ files_source = optarg;
+ break;
+ case 'w':
+ warn_unresolved = 1;
+ break;
+ case 'E':
+ sec_mismatch_warn_only = false;
+ break;
+ case 'N':
+ allow_missing_ns_imports = 1;
+ break;
+ case 'd':
+ missing_namespace_deps = optarg;
+ break;
+ case 'v':
+ strncpy(module_scmversion, optarg, sizeof(module_scmversion) - 1);
+ break;
+ default:
+ exit(1);
+ }
+ }
+
+ while (dump_read_start) {
+ struct dump_list *tmp;
+
+ read_dump(dump_read_start->file);
+ tmp = dump_read_start->next;
+ free(dump_read_start);
+ dump_read_start = tmp;
+ }
+
+ while (optind < argc)
+ read_symbols(argv[optind++]);
+
+ if (files_source)
+ read_symbols_from_files(files_source);
+
+ /*
+ * When there's no vmlinux, don't print warnings about
+ * unresolved symbols (since there'll be too many ;)
+ */
+ if (!have_vmlinux)
+ warn("Symbol info of vmlinux is missing. Unresolved symbol check will be entirely skipped.\n");
+
+ for (mod = modules; mod; mod = mod->next) {
+ char fname[PATH_MAX];
+
+ if (mod->is_vmlinux || mod->from_dump)
+ continue;
+
+ buf.pos = 0;
+
+ check_modname_len(mod);
+ check_exports(mod);
+
+ add_header(&buf, mod);
+ add_intree_flag(&buf, !external_module);
+ add_retpoline(&buf);
+ add_staging_flag(&buf, mod->name);
+ add_versions(&buf, mod);
+ add_depends(&buf, mod);
+ add_moddevtable(&buf, mod);
+ add_srcversion(&buf, mod);
+ add_scmversion(&buf);
+
+ sprintf(fname, "%s.mod.c", mod->name);
+ write_if_changed(&buf, fname);
+ }
+
+ if (missing_namespace_deps)
+ write_namespace_deps_files(missing_namespace_deps);
+
+ if (dump_write)
+ write_dump(dump_write);
+ if (sec_mismatch_count && !sec_mismatch_warn_only)
+ error("Section mismatches detected.\n"
+ "Set CONFIG_SECTION_MISMATCH_WARN_ONLY=y to allow them.\n");
+ for (n = 0; n < SYMBOL_HASH_SIZE; n++) {
+ struct symbol *s;
+
+ for (s = symbolhash[n]; s; s = s->next) {
+ if (s->is_static)
+ error("\"%s\" [%s] is a static %s\n",
+ s->name, s->module->name,
+ export_str(s->export));
+ }
+ }
+
+ free(buf.p);
+
+ return error_occurred ? 1 : 0;
+}
Index: OrangePi/create-5.10.110-host-limits-patch/linux-orangepi-5.10.110-new/scripts/mod/sumversion.c
===================================================================
--- OrangePi/create-5.10.110-host-limits-patch/linux-orangepi-5.10.110-new/scripts/mod/sumversion.c (nonexistent)
+++ OrangePi/create-5.10.110-host-limits-patch/linux-orangepi-5.10.110-new/scripts/mod/sumversion.c (revision 385)
@@ -0,0 +1,424 @@
+#include <netinet/in.h>
+#ifdef __sun__
+#include <inttypes.h>
+#else
+#include <stdint.h>
+#endif
+#include <ctype.h>
+#include <errno.h>
+#include <string.h>
+#include <linux/limits.h>
+#include "modpost.h"
+
+/*
+ * Stolen form Cryptographic API.
+ *
+ * MD4 Message Digest Algorithm (RFC1320).
+ *
+ * Implementation derived from Andrew Tridgell and Steve French's
+ * CIFS MD4 implementation, and the cryptoapi implementation
+ * originally based on the public domain implementation written
+ * by Colin Plumb in 1993.
+ *
+ * Copyright (c) Andrew Tridgell 1997-1998.
+ * Modified by Steve French (sfrench@us.ibm.com) 2002
+ * Copyright (c) Cryptoapi developers.
+ * Copyright (c) 2002 David S. Miller (davem@redhat.com)
+ * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+#define MD4_DIGEST_SIZE 16
+#define MD4_HMAC_BLOCK_SIZE 64
+#define MD4_BLOCK_WORDS 16
+#define MD4_HASH_WORDS 4
+
+struct md4_ctx {
+ uint32_t hash[MD4_HASH_WORDS];
+ uint32_t block[MD4_BLOCK_WORDS];
+ uint64_t byte_count;
+};
+
+static inline uint32_t lshift(uint32_t x, unsigned int s)
+{
+ x &= 0xFFFFFFFF;
+ return ((x << s) & 0xFFFFFFFF) | (x >> (32 - s));
+}
+
+static inline uint32_t F(uint32_t x, uint32_t y, uint32_t z)
+{
+ return (x & y) | ((~x) & z);
+}
+
+static inline uint32_t G(uint32_t x, uint32_t y, uint32_t z)
+{
+ return (x & y) | (x & z) | (y & z);
+}
+
+static inline uint32_t H(uint32_t x, uint32_t y, uint32_t z)
+{
+ return x ^ y ^ z;
+}
+
+#define ROUND1(a,b,c,d,k,s) (a = lshift(a + F(b,c,d) + k, s))
+#define ROUND2(a,b,c,d,k,s) (a = lshift(a + G(b,c,d) + k + (uint32_t)0x5A827999,s))
+#define ROUND3(a,b,c,d,k,s) (a = lshift(a + H(b,c,d) + k + (uint32_t)0x6ED9EBA1,s))
+
+/* XXX: this stuff can be optimized */
+static inline void le32_to_cpu_array(uint32_t *buf, unsigned int words)
+{
+ while (words--) {
+ *buf = ntohl(*buf);
+ buf++;
+ }
+}
+
+static inline void cpu_to_le32_array(uint32_t *buf, unsigned int words)
+{
+ while (words--) {
+ *buf = htonl(*buf);
+ buf++;
+ }
+}
+
+static void md4_transform(uint32_t *hash, uint32_t const *in)
+{
+ uint32_t a, b, c, d;
+
+ a = hash[0];
+ b = hash[1];
+ c = hash[2];
+ d = hash[3];
+
+ ROUND1(a, b, c, d, in[0], 3);
+ ROUND1(d, a, b, c, in[1], 7);
+ ROUND1(c, d, a, b, in[2], 11);
+ ROUND1(b, c, d, a, in[3], 19);
+ ROUND1(a, b, c, d, in[4], 3);
+ ROUND1(d, a, b, c, in[5], 7);
+ ROUND1(c, d, a, b, in[6], 11);
+ ROUND1(b, c, d, a, in[7], 19);
+ ROUND1(a, b, c, d, in[8], 3);
+ ROUND1(d, a, b, c, in[9], 7);
+ ROUND1(c, d, a, b, in[10], 11);
+ ROUND1(b, c, d, a, in[11], 19);
+ ROUND1(a, b, c, d, in[12], 3);
+ ROUND1(d, a, b, c, in[13], 7);
+ ROUND1(c, d, a, b, in[14], 11);
+ ROUND1(b, c, d, a, in[15], 19);
+
+ ROUND2(a, b, c, d,in[ 0], 3);
+ ROUND2(d, a, b, c, in[4], 5);
+ ROUND2(c, d, a, b, in[8], 9);
+ ROUND2(b, c, d, a, in[12], 13);
+ ROUND2(a, b, c, d, in[1], 3);
+ ROUND2(d, a, b, c, in[5], 5);
+ ROUND2(c, d, a, b, in[9], 9);
+ ROUND2(b, c, d, a, in[13], 13);
+ ROUND2(a, b, c, d, in[2], 3);
+ ROUND2(d, a, b, c, in[6], 5);
+ ROUND2(c, d, a, b, in[10], 9);
+ ROUND2(b, c, d, a, in[14], 13);
+ ROUND2(a, b, c, d, in[3], 3);
+ ROUND2(d, a, b, c, in[7], 5);
+ ROUND2(c, d, a, b, in[11], 9);
+ ROUND2(b, c, d, a, in[15], 13);
+
+ ROUND3(a, b, c, d,in[ 0], 3);
+ ROUND3(d, a, b, c, in[8], 9);
+ ROUND3(c, d, a, b, in[4], 11);
+ ROUND3(b, c, d, a, in[12], 15);
+ ROUND3(a, b, c, d, in[2], 3);
+ ROUND3(d, a, b, c, in[10], 9);
+ ROUND3(c, d, a, b, in[6], 11);
+ ROUND3(b, c, d, a, in[14], 15);
+ ROUND3(a, b, c, d, in[1], 3);
+ ROUND3(d, a, b, c, in[9], 9);
+ ROUND3(c, d, a, b, in[5], 11);
+ ROUND3(b, c, d, a, in[13], 15);
+ ROUND3(a, b, c, d, in[3], 3);
+ ROUND3(d, a, b, c, in[11], 9);
+ ROUND3(c, d, a, b, in[7], 11);
+ ROUND3(b, c, d, a, in[15], 15);
+
+ hash[0] += a;
+ hash[1] += b;
+ hash[2] += c;
+ hash[3] += d;
+}
+
+static inline void md4_transform_helper(struct md4_ctx *ctx)
+{
+ le32_to_cpu_array(ctx->block, sizeof(ctx->block) / sizeof(uint32_t));
+ md4_transform(ctx->hash, ctx->block);
+}
+
+static void md4_init(struct md4_ctx *mctx)
+{
+ mctx->hash[0] = 0x67452301;
+ mctx->hash[1] = 0xefcdab89;
+ mctx->hash[2] = 0x98badcfe;
+ mctx->hash[3] = 0x10325476;
+ mctx->byte_count = 0;
+}
+
+static void md4_update(struct md4_ctx *mctx,
+ const unsigned char *data, unsigned int len)
+{
+ const uint32_t avail = sizeof(mctx->block) - (mctx->byte_count & 0x3f);
+
+ mctx->byte_count += len;
+
+ if (avail > len) {
+ memcpy((char *)mctx->block + (sizeof(mctx->block) - avail),
+ data, len);
+ return;
+ }
+
+ memcpy((char *)mctx->block + (sizeof(mctx->block) - avail),
+ data, avail);
+
+ md4_transform_helper(mctx);
+ data += avail;
+ len -= avail;
+
+ while (len >= sizeof(mctx->block)) {
+ memcpy(mctx->block, data, sizeof(mctx->block));
+ md4_transform_helper(mctx);
+ data += sizeof(mctx->block);
+ len -= sizeof(mctx->block);
+ }
+
+ memcpy(mctx->block, data, len);
+}
+
+static void md4_final_ascii(struct md4_ctx *mctx, char *out, unsigned int len)
+{
+ const unsigned int offset = mctx->byte_count & 0x3f;
+ char *p = (char *)mctx->block + offset;
+ int padding = 56 - (offset + 1);
+
+ *p++ = 0x80;
+ if (padding < 0) {
+ memset(p, 0x00, padding + sizeof (uint64_t));
+ md4_transform_helper(mctx);
+ p = (char *)mctx->block;
+ padding = 56;
+ }
+
+ memset(p, 0, padding);
+ mctx->block[14] = mctx->byte_count << 3;
+ mctx->block[15] = mctx->byte_count >> 29;
+ le32_to_cpu_array(mctx->block, (sizeof(mctx->block) -
+ sizeof(uint64_t)) / sizeof(uint32_t));
+ md4_transform(mctx->hash, mctx->block);
+ cpu_to_le32_array(mctx->hash, sizeof(mctx->hash) / sizeof(uint32_t));
+
+ snprintf(out, len, "%08X%08X%08X%08X",
+ mctx->hash[0], mctx->hash[1], mctx->hash[2], mctx->hash[3]);
+}
+
+static inline void add_char(unsigned char c, struct md4_ctx *md)
+{
+ md4_update(md, &c, 1);
+}
+
+static int parse_string(const char *file, unsigned long len,
+ struct md4_ctx *md)
+{
+ unsigned long i;
+
+ add_char(file[0], md);
+ for (i = 1; i < len; i++) {
+ add_char(file[i], md);
+ if (file[i] == '"' && file[i-1] != '\\')
+ break;
+ }
+ return i;
+}
+
+static int parse_comment(const char *file, unsigned long len)
+{
+ unsigned long i;
+
+ for (i = 2; i < len; i++) {
+ if (file[i-1] == '*' && file[i] == '/')
+ break;
+ }
+ return i;
+}
+
+/* FIXME: Handle .s files differently (eg. # starts comments) --RR */
+static int parse_file(const char *fname, struct md4_ctx *md)
+{
+ char *file;
+ unsigned long i, len;
+
+ file = read_text_file(fname);
+ len = strlen(file);
+
+ for (i = 0; i < len; i++) {
+ /* Collapse and ignore \ and CR. */
+ if (file[i] == '\\' && (i+1 < len) && file[i+1] == '\n') {
+ i++;
+ continue;
+ }
+
+ /* Ignore whitespace */
+ if (isspace(file[i]))
+ continue;
+
+ /* Handle strings as whole units */
+ if (file[i] == '"') {
+ i += parse_string(file+i, len - i, md);
+ continue;
+ }
+
+ /* Comments: ignore */
+ if (file[i] == '/' && file[i+1] == '*') {
+ i += parse_comment(file+i, len - i);
+ continue;
+ }
+
+ add_char(file[i], md);
+ }
+ free(file);
+ return 1;
+}
+/* Check whether the file is a static library or not */
+static int is_static_library(const char *objfile)
+{
+ int len = strlen(objfile);
+ if (objfile[len - 2] == '.' && objfile[len - 1] == 'a')
+ return 1;
+ else
+ return 0;
+}
+
+/* We have dir/file.o. Open dir/.file.o.cmd, look for source_ and deps_ line
+ * to figure out source files. */
+static int parse_source_files(const char *objfile, struct md4_ctx *md)
+{
+ char *cmd, *file, *line, *dir, *pos;
+ const char *base;
+ int dirlen, ret = 0, check_files = 0;
+
+ cmd = NOFAIL(malloc(strlen(objfile) + sizeof("..cmd")));
+
+ base = strrchr(objfile, '/');
+ if (base) {
+ base++;
+ dirlen = base - objfile;
+ sprintf(cmd, "%.*s.%s.cmd", dirlen, objfile, base);
+ } else {
+ dirlen = 0;
+ sprintf(cmd, ".%s.cmd", objfile);
+ }
+ dir = NOFAIL(malloc(dirlen + 1));
+ strncpy(dir, objfile, dirlen);
+ dir[dirlen] = '\0';
+
+ file = read_text_file(cmd);
+
+ pos = file;
+
+ /* Sum all files in the same dir or subdirs. */
+ while ((line = get_line(&pos))) {
+ char* p = line;
+
+ if (strncmp(line, "source_", sizeof("source_")-1) == 0) {
+ p = strrchr(line, ' ');
+ if (!p) {
+ warn("malformed line: %s\n", line);
+ goto out_file;
+ }
+ p++;
+ if (!parse_file(p, md)) {
+ warn("could not open %s: %s\n",
+ p, strerror(errno));
+ goto out_file;
+ }
+ continue;
+ }
+ if (strncmp(line, "deps_", sizeof("deps_")-1) == 0) {
+ check_files = 1;
+ continue;
+ }
+ if (!check_files)
+ continue;
+
+ /* Continue until line does not end with '\' */
+ if ( *(p + strlen(p)-1) != '\\')
+ break;
+ /* Terminate line at first space, to get rid of final ' \' */
+ while (*p) {
+ if (isspace(*p)) {
+ *p = '\0';
+ break;
+ }
+ p++;
+ }
+
+ /* Check if this file is in same dir as objfile */
+ if ((strstr(line, dir)+strlen(dir)-1) == strrchr(line, '/')) {
+ if (!parse_file(line, md)) {
+ warn("could not open %s: %s\n",
+ line, strerror(errno));
+ goto out_file;
+ }
+
+ }
+
+ }
+
+ /* Everyone parsed OK */
+ ret = 1;
+out_file:
+ free(file);
+ free(dir);
+ free(cmd);
+ return ret;
+}
+
+/* Calc and record src checksum. */
+void get_src_version(const char *modname, char sum[], unsigned sumlen)
+{
+ char *buf, *pos, *firstline;
+ struct md4_ctx md;
+ char *fname;
+ char filelist[PATH_MAX + 1];
+ int postfix_len = 1;
+
+ if (strends(modname, ".lto.o"))
+ postfix_len = 5;
+
+ /* objects for a module are listed in the first line of *.mod file. */
+ snprintf(filelist, sizeof(filelist), "%.*smod",
+ (int)strlen(modname) - postfix_len, modname);
+
+ buf = read_text_file(filelist);
+
+ pos = buf;
+ firstline = get_line(&pos);
+ if (!firstline) {
+ warn("bad ending versions file for %s\n", modname);
+ goto free;
+ }
+
+ md4_init(&md);
+ while ((fname = strsep(&firstline, " "))) {
+ if (!*fname)
+ continue;
+ if (!(is_static_library(fname)) &&
+ !parse_source_files(fname, &md))
+ goto free;
+ }
+
+ md4_final_ascii(&md, sum, sumlen);
+free:
+ free(buf);
+}
Index: OrangePi/create-5.10.110-host-limits-patch/linux-orangepi-5.10.110-new/tools/build/fixdep.c
===================================================================
--- OrangePi/create-5.10.110-host-limits-patch/linux-orangepi-5.10.110-new/tools/build/fixdep.c (nonexistent)
+++ OrangePi/create-5.10.110-host-limits-patch/linux-orangepi-5.10.110-new/tools/build/fixdep.c (revision 385)
@@ -0,0 +1,170 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * "Optimize" a list of dependencies as spit out by gcc -MD
+ * for the build framework.
+ *
+ * Original author:
+ * Copyright 2002 by Kai Germaschewski <kai.germaschewski@gmx.de>
+ *
+ * This code has been borrowed from kbuild's fixdep (scripts/basic/fixdep.c),
+ * Please check it for detailed explanation. This fixdep borow only the
+ * base transformation of dependecies without the CONFIG mangle.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <linux/limits.h>
+
+char *target;
+char *depfile;
+char *cmdline;
+
+static void usage(void)
+{
+ fprintf(stderr, "Usage: fixdep <depfile> <target> <cmdline>\n");
+ exit(1);
+}
+
+/*
+ * Print out the commandline prefixed with cmd_<target filename> :=
+ */
+static void print_cmdline(void)
+{
+ printf("cmd_%s := %s\n\n", target, cmdline);
+}
+
+/*
+ * Important: The below generated source_foo.o and deps_foo.o variable
+ * assignments are parsed not only by make, but also by the rather simple
+ * parser in scripts/mod/sumversion.c.
+ */
+static void parse_dep_file(void *map, size_t len)
+{
+ char *m = map;
+ char *end = m + len;
+ char *p;
+ char s[PATH_MAX];
+ int is_target, has_target = 0;
+ int saw_any_target = 0;
+ int is_first_dep = 0;
+
+ while (m < end) {
+ /* Skip any "white space" */
+ while (m < end && (*m == ' ' || *m == '\\' || *m == '\n'))
+ m++;
+ /* Find next "white space" */
+ p = m;
+ while (p < end && *p != ' ' && *p != '\\' && *p != '\n')
+ p++;
+ /* Is the token we found a target name? */
+ is_target = (*(p-1) == ':');
+ /* Don't write any target names into the dependency file */
+ if (is_target) {
+ /* The /next/ file is the first dependency */
+ is_first_dep = 1;
+ has_target = 1;
+ } else if (has_target) {
+ /* Save this token/filename */
+ memcpy(s, m, p-m);
+ s[p - m] = 0;
+
+ /*
+ * Do not list the source file as dependency,
+ * so that kbuild is not confused if a .c file
+ * is rewritten into .S or vice versa. Storing
+ * it in source_* is needed for modpost to
+ * compute srcversions.
+ */
+ if (is_first_dep) {
+ /*
+ * If processing the concatenation of
+ * multiple dependency files, only
+ * process the first target name, which
+ * will be the original source name,
+ * and ignore any other target names,
+ * which will be intermediate temporary
+ * files.
+ */
+ if (!saw_any_target) {
+ saw_any_target = 1;
+ printf("source_%s := %s\n\n",
+ target, s);
+ printf("deps_%s := \\\n",
+ target);
+ }
+ is_first_dep = 0;
+ } else
+ printf(" %s \\\n", s);
+ }
+ /*
+ * Start searching for next token immediately after the first
+ * "whitespace" character that follows this token.
+ */
+ m = p + 1;
+ }
+
+ if (!saw_any_target) {
+ fprintf(stderr, "fixdep: parse error; no targets found\n");
+ exit(1);
+ }
+
+ printf("\n%s: $(deps_%s)\n\n", target, target);
+ printf("$(deps_%s):\n", target);
+}
+
+static void print_deps(void)
+{
+ struct stat st;
+ int fd;
+ void *map;
+
+ fd = open(depfile, O_RDONLY);
+ if (fd < 0) {
+ fprintf(stderr, "fixdep: error opening depfile: ");
+ perror(depfile);
+ exit(2);
+ }
+ if (fstat(fd, &st) < 0) {
+ fprintf(stderr, "fixdep: error fstat'ing depfile: ");
+ perror(depfile);
+ exit(2);
+ }
+ if (st.st_size == 0) {
+ fprintf(stderr, "fixdep: %s is empty\n", depfile);
+ close(fd);
+ return;
+ }
+ map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+ if ((long) map == -1) {
+ perror("fixdep: mmap");
+ close(fd);
+ return;
+ }
+
+ parse_dep_file(map, st.st_size);
+
+ munmap(map, st.st_size);
+
+ close(fd);
+}
+
+int main(int argc, char **argv)
+{
+ if (argc != 4)
+ usage();
+
+ depfile = argv[1];
+ target = argv[2];
+ cmdline = argv[3];
+
+ print_cmdline();
+ print_deps();
+
+ return 0;
+}
Index: OrangePi/create-5.10.110-host-limits-patch/linux-orangepi-5.10.110-new/usr/gen_init_cpio.c
===================================================================
--- OrangePi/create-5.10.110-host-limits-patch/linux-orangepi-5.10.110-new/usr/gen_init_cpio.c (nonexistent)
+++ OrangePi/create-5.10.110-host-limits-patch/linux-orangepi-5.10.110-new/usr/gen_init_cpio.c (revision 385)
@@ -0,0 +1,624 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <unistd.h>
+#include <time.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <ctype.h>
+#include <linux/limits.h>
+
+/*
+ * Original work by Jeff Garzik
+ *
+ * External file lists, symlink, pipe and fifo support by Thayne Harbaugh
+ * Hard link support by Luciano Rocha
+ */
+
+#define xstr(s) #s
+#define str(s) xstr(s)
+
+static unsigned int offset;
+static unsigned int ino = 721;
+static time_t default_mtime;
+
+struct file_handler {
+ const char *type;
+ int (*handler)(const char *line);
+};
+
+static void push_string(const char *name)
+{
+ unsigned int name_len = strlen(name) + 1;
+
+ fputs(name, stdout);
+ putchar(0);
+ offset += name_len;
+}
+
+static void push_pad (void)
+{
+ while (offset & 3) {
+ putchar(0);
+ offset++;
+ }
+}
+
+static void push_rest(const char *name)
+{
+ unsigned int name_len = strlen(name) + 1;
+ unsigned int tmp_ofs;
+
+ fputs(name, stdout);
+ putchar(0);
+ offset += name_len;
+
+ tmp_ofs = name_len + 110;
+ while (tmp_ofs & 3) {
+ putchar(0);
+ offset++;
+ tmp_ofs++;
+ }
+}
+
+static void push_hdr(const char *s)
+{
+ fputs(s, stdout);
+ offset += 110;
+}
+
+static void cpio_trailer(void)
+{
+ char s[256];
+ const char name[] = "TRAILER!!!";
+
+ sprintf(s, "%s%08X%08X%08lX%08lX%08X%08lX"
+ "%08X%08X%08X%08X%08X%08X%08X",
+ "070701", /* magic */
+ 0, /* ino */
+ 0, /* mode */
+ (long) 0, /* uid */
+ (long) 0, /* gid */
+ 1, /* nlink */
+ (long) 0, /* mtime */
+ 0, /* filesize */
+ 0, /* major */
+ 0, /* minor */
+ 0, /* rmajor */
+ 0, /* rminor */
+ (unsigned)strlen(name)+1, /* namesize */
+ 0); /* chksum */
+ push_hdr(s);
+ push_rest(name);
+
+ while (offset % 512) {
+ putchar(0);
+ offset++;
+ }
+}
+
+static int cpio_mkslink(const char *name, const char *target,
+ unsigned int mode, uid_t uid, gid_t gid)
+{
+ char s[256];
+
+ if (name[0] == '/')
+ name++;
+ sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
+ "%08X%08X%08X%08X%08X%08X%08X",
+ "070701", /* magic */
+ ino++, /* ino */
+ S_IFLNK | mode, /* mode */
+ (long) uid, /* uid */
+ (long) gid, /* gid */
+ 1, /* nlink */
+ (long) default_mtime, /* mtime */
+ (unsigned)strlen(target)+1, /* filesize */
+ 3, /* major */
+ 1, /* minor */
+ 0, /* rmajor */
+ 0, /* rminor */
+ (unsigned)strlen(name) + 1,/* namesize */
+ 0); /* chksum */
+ push_hdr(s);
+ push_string(name);
+ push_pad();
+ push_string(target);
+ push_pad();
+ return 0;
+}
+
+static int cpio_mkslink_line(const char *line)
+{
+ char name[PATH_MAX + 1];
+ char target[PATH_MAX + 1];
+ unsigned int mode;
+ int uid;
+ int gid;
+ int rc = -1;
+
+ if (5 != sscanf(line, "%" str(PATH_MAX) "s %" str(PATH_MAX) "s %o %d %d", name, target, &mode, &uid, &gid)) {
+ fprintf(stderr, "Unrecognized dir format '%s'", line);
+ goto fail;
+ }
+ rc = cpio_mkslink(name, target, mode, uid, gid);
+ fail:
+ return rc;
+}
+
+static int cpio_mkgeneric(const char *name, unsigned int mode,
+ uid_t uid, gid_t gid)
+{
+ char s[256];
+
+ if (name[0] == '/')
+ name++;
+ sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
+ "%08X%08X%08X%08X%08X%08X%08X",
+ "070701", /* magic */
+ ino++, /* ino */
+ mode, /* mode */
+ (long) uid, /* uid */
+ (long) gid, /* gid */
+ 2, /* nlink */
+ (long) default_mtime, /* mtime */
+ 0, /* filesize */
+ 3, /* major */
+ 1, /* minor */
+ 0, /* rmajor */
+ 0, /* rminor */
+ (unsigned)strlen(name) + 1,/* namesize */
+ 0); /* chksum */
+ push_hdr(s);
+ push_rest(name);
+ return 0;
+}
+
+enum generic_types {
+ GT_DIR,
+ GT_PIPE,
+ GT_SOCK
+};
+
+struct generic_type {
+ const char *type;
+ mode_t mode;
+};
+
+static struct generic_type generic_type_table[] = {
+ [GT_DIR] = {
+ .type = "dir",
+ .mode = S_IFDIR
+ },
+ [GT_PIPE] = {
+ .type = "pipe",
+ .mode = S_IFIFO
+ },
+ [GT_SOCK] = {
+ .type = "sock",
+ .mode = S_IFSOCK
+ }
+};
+
+static int cpio_mkgeneric_line(const char *line, enum generic_types gt)
+{
+ char name[PATH_MAX + 1];
+ unsigned int mode;
+ int uid;
+ int gid;
+ int rc = -1;
+
+ if (4 != sscanf(line, "%" str(PATH_MAX) "s %o %d %d", name, &mode, &uid, &gid)) {
+ fprintf(stderr, "Unrecognized %s format '%s'",
+ line, generic_type_table[gt].type);
+ goto fail;
+ }
+ mode |= generic_type_table[gt].mode;
+ rc = cpio_mkgeneric(name, mode, uid, gid);
+ fail:
+ return rc;
+}
+
+static int cpio_mkdir_line(const char *line)
+{
+ return cpio_mkgeneric_line(line, GT_DIR);
+}
+
+static int cpio_mkpipe_line(const char *line)
+{
+ return cpio_mkgeneric_line(line, GT_PIPE);
+}
+
+static int cpio_mksock_line(const char *line)
+{
+ return cpio_mkgeneric_line(line, GT_SOCK);
+}
+
+static int cpio_mknod(const char *name, unsigned int mode,
+ uid_t uid, gid_t gid, char dev_type,
+ unsigned int maj, unsigned int min)
+{
+ char s[256];
+
+ if (dev_type == 'b')
+ mode |= S_IFBLK;
+ else
+ mode |= S_IFCHR;
+
+ if (name[0] == '/')
+ name++;
+ sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
+ "%08X%08X%08X%08X%08X%08X%08X",
+ "070701", /* magic */
+ ino++, /* ino */
+ mode, /* mode */
+ (long) uid, /* uid */
+ (long) gid, /* gid */
+ 1, /* nlink */
+ (long) default_mtime, /* mtime */
+ 0, /* filesize */
+ 3, /* major */
+ 1, /* minor */
+ maj, /* rmajor */
+ min, /* rminor */
+ (unsigned)strlen(name) + 1,/* namesize */
+ 0); /* chksum */
+ push_hdr(s);
+ push_rest(name);
+ return 0;
+}
+
+static int cpio_mknod_line(const char *line)
+{
+ char name[PATH_MAX + 1];
+ unsigned int mode;
+ int uid;
+ int gid;
+ char dev_type;
+ unsigned int maj;
+ unsigned int min;
+ int rc = -1;
+
+ if (7 != sscanf(line, "%" str(PATH_MAX) "s %o %d %d %c %u %u",
+ name, &mode, &uid, &gid, &dev_type, &maj, &min)) {
+ fprintf(stderr, "Unrecognized nod format '%s'", line);
+ goto fail;
+ }
+ rc = cpio_mknod(name, mode, uid, gid, dev_type, maj, min);
+ fail:
+ return rc;
+}
+
+static int cpio_mkfile(const char *name, const char *location,
+ unsigned int mode, uid_t uid, gid_t gid,
+ unsigned int nlinks)
+{
+ char s[256];
+ char *filebuf = NULL;
+ struct stat buf;
+ long size;
+ int file = -1;
+ int retval;
+ int rc = -1;
+ int namesize;
+ unsigned int i;
+
+ mode |= S_IFREG;
+
+ file = open (location, O_RDONLY);
+ if (file < 0) {
+ fprintf (stderr, "File %s could not be opened for reading\n", location);
+ goto error;
+ }
+
+ retval = fstat(file, &buf);
+ if (retval) {
+ fprintf(stderr, "File %s could not be stat()'ed\n", location);
+ goto error;
+ }
+
+ filebuf = malloc(buf.st_size);
+ if (!filebuf) {
+ fprintf (stderr, "out of memory\n");
+ goto error;
+ }
+
+ retval = read (file, filebuf, buf.st_size);
+ if (retval < 0) {
+ fprintf (stderr, "Can not read %s file\n", location);
+ goto error;
+ }
+
+ size = 0;
+ for (i = 1; i <= nlinks; i++) {
+ /* data goes on last link */
+ if (i == nlinks) size = buf.st_size;
+
+ if (name[0] == '/')
+ name++;
+ namesize = strlen(name) + 1;
+ sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
+ "%08lX%08X%08X%08X%08X%08X%08X",
+ "070701", /* magic */
+ ino, /* ino */
+ mode, /* mode */
+ (long) uid, /* uid */
+ (long) gid, /* gid */
+ nlinks, /* nlink */
+ (long) buf.st_mtime, /* mtime */
+ size, /* filesize */
+ 3, /* major */
+ 1, /* minor */
+ 0, /* rmajor */
+ 0, /* rminor */
+ namesize, /* namesize */
+ 0); /* chksum */
+ push_hdr(s);
+ push_string(name);
+ push_pad();
+
+ if (size) {
+ if (fwrite(filebuf, size, 1, stdout) != 1) {
+ fprintf(stderr, "writing filebuf failed\n");
+ goto error;
+ }
+ offset += size;
+ push_pad();
+ }
+
+ name += namesize;
+ }
+ ino++;
+ rc = 0;
+
+error:
+ if (filebuf) free(filebuf);
+ if (file >= 0) close(file);
+ return rc;
+}
+
+static char *cpio_replace_env(char *new_location)
+{
+ char expanded[PATH_MAX + 1];
+ char *start, *end, *var;
+
+ while ((start = strstr(new_location, "${")) &&
+ (end = strchr(start + 2, '}'))) {
+ *start = *end = 0;
+ var = getenv(start + 2);
+ snprintf(expanded, sizeof expanded, "%s%s%s",
+ new_location, var ? var : "", end + 1);
+ strcpy(new_location, expanded);
+ }
+
+ return new_location;
+}
+
+static int cpio_mkfile_line(const char *line)
+{
+ char name[PATH_MAX + 1];
+ char *dname = NULL; /* malloc'ed buffer for hard links */
+ char location[PATH_MAX + 1];
+ unsigned int mode;
+ int uid;
+ int gid;
+ int nlinks = 1;
+ int end = 0, dname_len = 0;
+ int rc = -1;
+
+ if (5 > sscanf(line, "%" str(PATH_MAX) "s %" str(PATH_MAX)
+ "s %o %d %d %n",
+ name, location, &mode, &uid, &gid, &end)) {
+ fprintf(stderr, "Unrecognized file format '%s'", line);
+ goto fail;
+ }
+ if (end && isgraph(line[end])) {
+ int len;
+ int nend;
+
+ dname = malloc(strlen(line));
+ if (!dname) {
+ fprintf (stderr, "out of memory (%d)\n", dname_len);
+ goto fail;
+ }
+
+ dname_len = strlen(name) + 1;
+ memcpy(dname, name, dname_len);
+
+ do {
+ nend = 0;
+ if (sscanf(line + end, "%" str(PATH_MAX) "s %n",
+ name, &nend) < 1)
+ break;
+ len = strlen(name) + 1;
+ memcpy(dname + dname_len, name, len);
+ dname_len += len;
+ nlinks++;
+ end += nend;
+ } while (isgraph(line[end]));
+ } else {
+ dname = name;
+ }
+ rc = cpio_mkfile(dname, cpio_replace_env(location),
+ mode, uid, gid, nlinks);
+ fail:
+ if (dname_len) free(dname);
+ return rc;
+}
+
+static void usage(const char *prog)
+{
+ fprintf(stderr, "Usage:\n"
+ "\t%s [-t <timestamp>] <cpio_list>\n"
+ "\n"
+ "<cpio_list> is a file containing newline separated entries that\n"
+ "describe the files to be included in the initramfs archive:\n"
+ "\n"
+ "# a comment\n"
+ "file <name> <location> <mode> <uid> <gid> [<hard links>]\n"
+ "dir <name> <mode> <uid> <gid>\n"
+ "nod <name> <mode> <uid> <gid> <dev_type> <maj> <min>\n"
+ "slink <name> <target> <mode> <uid> <gid>\n"
+ "pipe <name> <mode> <uid> <gid>\n"
+ "sock <name> <mode> <uid> <gid>\n"
+ "\n"
+ "<name> name of the file/dir/nod/etc in the archive\n"
+ "<location> location of the file in the current filesystem\n"
+ " expands shell variables quoted with ${}\n"
+ "<target> link target\n"
+ "<mode> mode/permissions of the file\n"
+ "<uid> user id (0=root)\n"
+ "<gid> group id (0=root)\n"
+ "<dev_type> device type (b=block, c=character)\n"
+ "<maj> major number of nod\n"
+ "<min> minor number of nod\n"
+ "<hard links> space separated list of other links to file\n"
+ "\n"
+ "example:\n"
+ "# A simple initramfs\n"
+ "dir /dev 0755 0 0\n"
+ "nod /dev/console 0600 0 0 c 5 1\n"
+ "dir /root 0700 0 0\n"
+ "dir /sbin 0755 0 0\n"
+ "file /sbin/kinit /usr/src/klibc/kinit/kinit 0755 0 0\n"
+ "\n"
+ "<timestamp> is time in seconds since Epoch that will be used\n"
+ "as mtime for symlinks, special files and directories. The default\n"
+ "is to use the current time for these entries.\n",
+ prog);
+}
+
+struct file_handler file_handler_table[] = {
+ {
+ .type = "file",
+ .handler = cpio_mkfile_line,
+ }, {
+ .type = "nod",
+ .handler = cpio_mknod_line,
+ }, {
+ .type = "dir",
+ .handler = cpio_mkdir_line,
+ }, {
+ .type = "slink",
+ .handler = cpio_mkslink_line,
+ }, {
+ .type = "pipe",
+ .handler = cpio_mkpipe_line,
+ }, {
+ .type = "sock",
+ .handler = cpio_mksock_line,
+ }, {
+ .type = NULL,
+ .handler = NULL,
+ }
+};
+
+#define LINE_SIZE (2 * PATH_MAX + 50)
+
+int main (int argc, char *argv[])
+{
+ FILE *cpio_list;
+ char line[LINE_SIZE];
+ char *args, *type;
+ int ec = 0;
+ int line_nr = 0;
+ const char *filename;
+
+ default_mtime = time(NULL);
+ while (1) {
+ int opt = getopt(argc, argv, "t:h");
+ char *invalid;
+
+ if (opt == -1)
+ break;
+ switch (opt) {
+ case 't':
+ default_mtime = strtol(optarg, &invalid, 10);
+ if (!*optarg || *invalid) {
+ fprintf(stderr, "Invalid timestamp: %s\n",
+ optarg);
+ usage(argv[0]);
+ exit(1);
+ }
+ break;
+ case 'h':
+ case '?':
+ usage(argv[0]);
+ exit(opt == 'h' ? 0 : 1);
+ }
+ }
+
+ if (argc - optind != 1) {
+ usage(argv[0]);
+ exit(1);
+ }
+ filename = argv[optind];
+ if (!strcmp(filename, "-"))
+ cpio_list = stdin;
+ else if (!(cpio_list = fopen(filename, "r"))) {
+ fprintf(stderr, "ERROR: unable to open '%s': %s\n\n",
+ filename, strerror(errno));
+ usage(argv[0]);
+ exit(1);
+ }
+
+ while (fgets(line, LINE_SIZE, cpio_list)) {
+ int type_idx;
+ size_t slen = strlen(line);
+
+ line_nr++;
+
+ if ('#' == *line) {
+ /* comment - skip to next line */
+ continue;
+ }
+
+ if (! (type = strtok(line, " \t"))) {
+ fprintf(stderr,
+ "ERROR: incorrect format, could not locate file type line %d: '%s'\n",
+ line_nr, line);
+ ec = -1;
+ break;
+ }
+
+ if ('\n' == *type) {
+ /* a blank line */
+ continue;
+ }
+
+ if (slen == strlen(type)) {
+ /* must be an empty line */
+ continue;
+ }
+
+ if (! (args = strtok(NULL, "\n"))) {
+ fprintf(stderr,
+ "ERROR: incorrect format, newline required line %d: '%s'\n",
+ line_nr, line);
+ ec = -1;
+ }
+
+ for (type_idx = 0; file_handler_table[type_idx].type; type_idx++) {
+ int rc;
+ if (! strcmp(line, file_handler_table[type_idx].type)) {
+ if ((rc = file_handler_table[type_idx].handler(args))) {
+ ec = rc;
+ fprintf(stderr, " line %d\n", line_nr);
+ }
+ break;
+ }
+ }
+
+ if (NULL == file_handler_table[type_idx].type) {
+ fprintf(stderr, "unknown file type line %d: '%s'\n",
+ line_nr, line);
+ }
+ }
+ if (ec == 0)
+ cpio_trailer();
+
+ exit(ec);
+}
Index: OrangePi/patches/README
===================================================================
--- OrangePi/patches/README (nonexistent)
+++ OrangePi/patches/README (revision 385)
@@ -0,0 +1,6 @@
+
+/* begin *
+
+ TODO: Leave some comment here.
+
+ * end */
Index: OrangePi/patches
===================================================================
--- OrangePi/patches (nonexistent)
+++ OrangePi/patches (revision 385)
Property changes on: OrangePi/patches
___________________________________________________________________
Added: svn:ignore
## -0,0 +1,74 ##
+
+# install dir
+dist
+
+# Target build dirs
+.a1x-newlib
+.a2x-newlib
+.at91sam7s-newlib
+
+.build-machine
+
+.a1x-glibc
+.a2x-glibc
+.h3-glibc
+.h5-glibc
+.i586-glibc
+.i686-glibc
+.imx6-glibc
+.jz47xx-glibc
+.makefile
+.am335x-glibc
+.omap543x-glibc
+.p5600-glibc
+.power8-glibc
+.power8le-glibc
+.power9-glibc
+.power9le-glibc
+.m1000-glibc
+.riscv64-glibc
+.rk328x-glibc
+.rk33xx-glibc
+.rk339x-glibc
+.rk358x-glibc
+.s8xx-glibc
+.s9xx-glibc
+.x86_64-glibc
+
+# Hidden files (each file)
+.makefile
+.dist
+.rootfs
+
+# src & hw requires
+.src_requires
+.src_requires_depend
+.requires
+.requires_depend
+
+# Tarballs
+*.gz
+*.bz2
+*.lz
+*.xz
+*.tgz
+*.txz
+
+# Signatures
+*.asc
+*.sig
+*.sign
+*.sha1sum
+
+# Patches
+*.patch
+
+# Descriptions
+*.dsc
+*.txt
+
+# Default linux config files
+*.defconfig
+
+# backup copies
+*~
Index: OrangePi
===================================================================
--- OrangePi (nonexistent)
+++ OrangePi (revision 385)
Property changes on: OrangePi
___________________________________________________________________
Added: svn:ignore
## -0,0 +1,74 ##
+
+# install dir
+dist
+
+# Target build dirs
+.a1x-newlib
+.a2x-newlib
+.at91sam7s-newlib
+
+.build-machine
+
+.a1x-glibc
+.a2x-glibc
+.h3-glibc
+.h5-glibc
+.i586-glibc
+.i686-glibc
+.imx6-glibc
+.jz47xx-glibc
+.makefile
+.am335x-glibc
+.omap543x-glibc
+.p5600-glibc
+.power8-glibc
+.power8le-glibc
+.power9-glibc
+.power9le-glibc
+.m1000-glibc
+.riscv64-glibc
+.rk328x-glibc
+.rk33xx-glibc
+.rk339x-glibc
+.rk358x-glibc
+.s8xx-glibc
+.s9xx-glibc
+.x86_64-glibc
+
+# Hidden files (each file)
+.makefile
+.dist
+.rootfs
+
+# src & hw requires
+.src_requires
+.src_requires_depend
+.requires
+.requires_depend
+
+# Tarballs
+*.gz
+*.bz2
+*.lz
+*.xz
+*.tgz
+*.txz
+
+# Signatures
+*.asc
+*.sig
+*.sign
+*.sha1sum
+
+# Patches
+*.patch
+
+# Descriptions
+*.dsc
+*.txt
+
+# Default linux config files
+*.defconfig
+
+# backup copies
+*~
Index: StarFive/Makefile
===================================================================
--- StarFive/Makefile (nonexistent)
+++ StarFive/Makefile (revision 385)
@@ -0,0 +1,54 @@
+
+COMPONENT_TARGETS = $(HARDWARE_NOARCH)
+
+
+include ../../../build-system/constants.mk
+
+
+url = $(DOWNLOAD_SERVER)/sources/Linux/StarFive
+
+versions = starfive-6.1.31-3.8.2
+
+tarballs = $(addsuffix .tar.xz, $(addprefix linux-, $(versions)))
+sha1s = $(addsuffix .sha1sum, $(tarballs))
+
+patches = $(CURDIR)/patches/linux-starfive-6.1.31-3.8.2-host-limits.patch
+
+.NOTPARALLEL: $(patches)
+
+
+BUILD_TARGETS = $(tarballs) $(sha1s) $(patches)
+
+
+include ../../../build-system/core.mk
+
+
+.PHONY: download_clean
+
+
+$(tarballs):
+ @echo -e "\n======= Downloading source tarballs =======" ; \
+ for tarball in $(tarballs) ; do \
+ echo "$(url)/$$tarball" | xargs -n 1 -P 100 wget $(WGET_OPTIONS) - & \
+ done ; wait
+
+$(sha1s): $(tarballs)
+ @for sha in $@ ; do \
+ echo -e "\n======= Downloading '$$sha' signature =======\n" ; \
+ echo "$(url)/$$sha" | xargs -n 1 -P 100 wget $(WGET_OPTIONS) - & wait %1 ; \
+ touch $$sha ; \
+ echo -e "\n======= Check the '$$sha' sha1sum =======\n" ; \
+ sha1sum --check $$sha ; ret="$$?" ; \
+ if [ "$$ret" == "1" ]; then \
+ echo -e "\n======= ERROR: Bad '$$sha' sha1sum =======\n" ; \
+ exit 1 ; \
+ fi ; \
+ done
+
+$(patches): $(sha1s)
+ @echo -e "\n======= Create Patches =======\n" ; \
+ ( cd create-6.1.31-3.8.2-host-limits-patch ; ./create.patch.sh ) ; \
+ echo -e "\n"
+
+download_clean:
+ @rm -f $(tarballs) $(sha1s) $(patches)
Index: StarFive/create-6.1.31-3.8.2-host-limits-patch/create.patch.sh
===================================================================
--- StarFive/create-6.1.31-3.8.2-host-limits-patch/create.patch.sh (nonexistent)
+++ StarFive/create-6.1.31-3.8.2-host-limits-patch/create.patch.sh (revision 385)
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+VERSION=6.1.31-3.8.2
+
+tar --files-from=file.list -xJvf ../linux-starfive-$VERSION.tar.xz
+mv linux-starfive-$VERSION linux-starfive-$VERSION-orig
+
+cp -rf ./linux-starfive-$VERSION-new ./linux-starfive-$VERSION
+
+diff --unified -Nr linux-starfive-$VERSION-orig linux-starfive-$VERSION > linux-starfive-$VERSION-host-limits.patch
+
+mv linux-starfive-$VERSION-host-limits.patch ../patches
+
+rm -rf ./linux-starfive-$VERSION
+rm -rf ./linux-starfive-$VERSION-orig
Property changes on: StarFive/create-6.1.31-3.8.2-host-limits-patch/create.patch.sh
___________________________________________________________________
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: StarFive/create-6.1.31-3.8.2-host-limits-patch/file.list
===================================================================
--- StarFive/create-6.1.31-3.8.2-host-limits-patch/file.list (nonexistent)
+++ StarFive/create-6.1.31-3.8.2-host-limits-patch/file.list (revision 385)
@@ -0,0 +1,7 @@
+linux-starfive-6.1.31-3.8.2/scripts/kconfig/conf.c
+linux-starfive-6.1.31-3.8.2/scripts/kconfig/confdata.c
+linux-starfive-6.1.31-3.8.2/scripts/kconfig/lexer.l
+linux-starfive-6.1.31-3.8.2/scripts/mod/modpost.c
+linux-starfive-6.1.31-3.8.2/scripts/mod/sumversion.c
+linux-starfive-6.1.31-3.8.2/tools/build/fixdep.c
+linux-starfive-6.1.31-3.8.2/usr/gen_init_cpio.c
Index: StarFive/create-6.1.31-3.8.2-host-limits-patch/linux-starfive-6.1.31-3.8.2-new/scripts/kconfig/conf.c
===================================================================
--- StarFive/create-6.1.31-3.8.2-host-limits-patch/linux-starfive-6.1.31-3.8.2-new/scripts/kconfig/conf.c (nonexistent)
+++ StarFive/create-6.1.31-3.8.2-host-limits-patch/linux-starfive-6.1.31-3.8.2-new/scripts/kconfig/conf.c (revision 385)
@@ -0,0 +1,921 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ */
+
+#include <ctype.h>
+#include <linux/limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <sys/time.h>
+#include <errno.h>
+
+#include "lkc.h"
+
+static void conf(struct menu *menu);
+static void check_conf(struct menu *menu);
+
+enum input_mode {
+ oldaskconfig,
+ syncconfig,
+ oldconfig,
+ allnoconfig,
+ allyesconfig,
+ allmodconfig,
+ alldefconfig,
+ randconfig,
+ defconfig,
+ savedefconfig,
+ listnewconfig,
+ helpnewconfig,
+ olddefconfig,
+ yes2modconfig,
+ mod2yesconfig,
+ mod2noconfig,
+};
+static enum input_mode input_mode = oldaskconfig;
+static int input_mode_opt;
+static int indent = 1;
+static int tty_stdio;
+static int sync_kconfig;
+static int conf_cnt;
+static char line[PATH_MAX];
+static struct menu *rootEntry;
+
+static void print_help(struct menu *menu)
+{
+ struct gstr help = str_new();
+
+ menu_get_ext_help(menu, &help);
+
+ printf("\n%s\n", str_get(&help));
+ str_free(&help);
+}
+
+static void strip(char *str)
+{
+ char *p = str;
+ int l;
+
+ while ((isspace(*p)))
+ p++;
+ l = strlen(p);
+ if (p != str)
+ memmove(str, p, l + 1);
+ if (!l)
+ return;
+ p = str + l - 1;
+ while ((isspace(*p)))
+ *p-- = 0;
+}
+
+/* Helper function to facilitate fgets() by Jean Sacren. */
+static void xfgets(char *str, int size, FILE *in)
+{
+ if (!fgets(str, size, in))
+ fprintf(stderr, "\nError in reading or end of file.\n");
+
+ if (!tty_stdio)
+ printf("%s", str);
+}
+
+static void set_randconfig_seed(void)
+{
+ unsigned int seed;
+ char *env;
+ bool seed_set = false;
+
+ env = getenv("KCONFIG_SEED");
+ if (env && *env) {
+ char *endp;
+
+ seed = strtol(env, &endp, 0);
+ if (*endp == '\0')
+ seed_set = true;
+ }
+
+ if (!seed_set) {
+ struct timeval now;
+
+ /*
+ * Use microseconds derived seed, compensate for systems where it may
+ * be zero.
+ */
+ gettimeofday(&now, NULL);
+ seed = (now.tv_sec + 1) * (now.tv_usec + 1);
+ }
+
+ printf("KCONFIG_SEED=0x%X\n", seed);
+ srand(seed);
+}
+
+static bool randomize_choice_values(struct symbol *csym)
+{
+ struct property *prop;
+ struct symbol *sym;
+ struct expr *e;
+ int cnt, def;
+
+ /*
+ * If choice is mod then we may have more items selected
+ * and if no then no-one.
+ * In both cases stop.
+ */
+ if (csym->curr.tri != yes)
+ return false;
+
+ prop = sym_get_choice_prop(csym);
+
+ /* count entries in choice block */
+ cnt = 0;
+ expr_list_for_each_sym(prop->expr, e, sym)
+ cnt++;
+
+ /*
+ * find a random value and set it to yes,
+ * set the rest to no so we have only one set
+ */
+ def = rand() % cnt;
+
+ cnt = 0;
+ expr_list_for_each_sym(prop->expr, e, sym) {
+ if (def == cnt++) {
+ sym->def[S_DEF_USER].tri = yes;
+ csym->def[S_DEF_USER].val = sym;
+ } else {
+ sym->def[S_DEF_USER].tri = no;
+ }
+ sym->flags |= SYMBOL_DEF_USER;
+ /* clear VALID to get value calculated */
+ sym->flags &= ~SYMBOL_VALID;
+ }
+ csym->flags |= SYMBOL_DEF_USER;
+ /* clear VALID to get value calculated */
+ csym->flags &= ~SYMBOL_VALID;
+
+ return true;
+}
+
+enum conf_def_mode {
+ def_default,
+ def_yes,
+ def_mod,
+ def_no,
+ def_random
+};
+
+static bool conf_set_all_new_symbols(enum conf_def_mode mode)
+{
+ struct symbol *sym, *csym;
+ int i, cnt;
+ /*
+ * can't go as the default in switch-case below, otherwise gcc whines
+ * about -Wmaybe-uninitialized
+ */
+ int pby = 50; /* probability of bool = y */
+ int pty = 33; /* probability of tristate = y */
+ int ptm = 33; /* probability of tristate = m */
+ bool has_changed = false;
+
+ if (mode == def_random) {
+ int n, p[3];
+ char *env = getenv("KCONFIG_PROBABILITY");
+
+ n = 0;
+ while (env && *env) {
+ char *endp;
+ int tmp = strtol(env, &endp, 10);
+
+ if (tmp >= 0 && tmp <= 100) {
+ p[n++] = tmp;
+ } else {
+ errno = ERANGE;
+ perror("KCONFIG_PROBABILITY");
+ exit(1);
+ }
+ env = (*endp == ':') ? endp + 1 : endp;
+ if (n >= 3)
+ break;
+ }
+ switch (n) {
+ case 1:
+ pby = p[0];
+ ptm = pby / 2;
+ pty = pby - ptm;
+ break;
+ case 2:
+ pty = p[0];
+ ptm = p[1];
+ pby = pty + ptm;
+ break;
+ case 3:
+ pby = p[0];
+ pty = p[1];
+ ptm = p[2];
+ break;
+ }
+
+ if (pty + ptm > 100) {
+ errno = ERANGE;
+ perror("KCONFIG_PROBABILITY");
+ exit(1);
+ }
+ }
+
+ for_all_symbols(i, sym) {
+ if (sym_has_value(sym) || sym->flags & SYMBOL_VALID)
+ continue;
+ switch (sym_get_type(sym)) {
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ has_changed = true;
+ switch (mode) {
+ case def_yes:
+ sym->def[S_DEF_USER].tri = yes;
+ break;
+ case def_mod:
+ sym->def[S_DEF_USER].tri = mod;
+ break;
+ case def_no:
+ sym->def[S_DEF_USER].tri = no;
+ break;
+ case def_random:
+ sym->def[S_DEF_USER].tri = no;
+ cnt = rand() % 100;
+ if (sym->type == S_TRISTATE) {
+ if (cnt < pty)
+ sym->def[S_DEF_USER].tri = yes;
+ else if (cnt < pty + ptm)
+ sym->def[S_DEF_USER].tri = mod;
+ } else if (cnt < pby)
+ sym->def[S_DEF_USER].tri = yes;
+ break;
+ default:
+ continue;
+ }
+ if (!(sym_is_choice(sym) && mode == def_random))
+ sym->flags |= SYMBOL_DEF_USER;
+ break;
+ default:
+ break;
+ }
+
+ }
+
+ sym_clear_all_valid();
+
+ /*
+ * We have different type of choice blocks.
+ * If curr.tri equals to mod then we can select several
+ * choice symbols in one block.
+ * In this case we do nothing.
+ * If curr.tri equals yes then only one symbol can be
+ * selected in a choice block and we set it to yes,
+ * and the rest to no.
+ */
+ if (mode != def_random) {
+ for_all_symbols(i, csym) {
+ if ((sym_is_choice(csym) && !sym_has_value(csym)) ||
+ sym_is_choice_value(csym))
+ csym->flags |= SYMBOL_NEED_SET_CHOICE_VALUES;
+ }
+ }
+
+ for_all_symbols(i, csym) {
+ if (sym_has_value(csym) || !sym_is_choice(csym))
+ continue;
+
+ sym_calc_value(csym);
+ if (mode == def_random)
+ has_changed |= randomize_choice_values(csym);
+ else {
+ set_all_choice_values(csym);
+ has_changed = true;
+ }
+ }
+
+ return has_changed;
+}
+
+static void conf_rewrite_tristates(tristate old_val, tristate new_val)
+{
+ struct symbol *sym;
+ int i;
+
+ for_all_symbols(i, sym) {
+ if (sym_get_type(sym) == S_TRISTATE &&
+ sym->def[S_DEF_USER].tri == old_val)
+ sym->def[S_DEF_USER].tri = new_val;
+ }
+ sym_clear_all_valid();
+}
+
+static int conf_askvalue(struct symbol *sym, const char *def)
+{
+ if (!sym_has_value(sym))
+ printf("(NEW) ");
+
+ line[0] = '\n';
+ line[1] = 0;
+
+ if (!sym_is_changeable(sym)) {
+ printf("%s\n", def);
+ line[0] = '\n';
+ line[1] = 0;
+ return 0;
+ }
+
+ switch (input_mode) {
+ case oldconfig:
+ case syncconfig:
+ if (sym_has_value(sym)) {
+ printf("%s\n", def);
+ return 0;
+ }
+ /* fall through */
+ default:
+ fflush(stdout);
+ xfgets(line, sizeof(line), stdin);
+ break;
+ }
+
+ return 1;
+}
+
+static int conf_string(struct menu *menu)
+{
+ struct symbol *sym = menu->sym;
+ const char *def;
+
+ while (1) {
+ printf("%*s%s ", indent - 1, "", menu->prompt->text);
+ printf("(%s) ", sym->name);
+ def = sym_get_string_value(sym);
+ if (def)
+ printf("[%s] ", def);
+ if (!conf_askvalue(sym, def))
+ return 0;
+ switch (line[0]) {
+ case '\n':
+ break;
+ case '?':
+ /* print help */
+ if (line[1] == '\n') {
+ print_help(menu);
+ def = NULL;
+ break;
+ }
+ /* fall through */
+ default:
+ line[strlen(line)-1] = 0;
+ def = line;
+ }
+ if (def && sym_set_string_value(sym, def))
+ return 0;
+ }
+}
+
+static int conf_sym(struct menu *menu)
+{
+ struct symbol *sym = menu->sym;
+ tristate oldval, newval;
+
+ while (1) {
+ printf("%*s%s ", indent - 1, "", menu->prompt->text);
+ if (sym->name)
+ printf("(%s) ", sym->name);
+ putchar('[');
+ oldval = sym_get_tristate_value(sym);
+ switch (oldval) {
+ case no:
+ putchar('N');
+ break;
+ case mod:
+ putchar('M');
+ break;
+ case yes:
+ putchar('Y');
+ break;
+ }
+ if (oldval != no && sym_tristate_within_range(sym, no))
+ printf("/n");
+ if (oldval != mod && sym_tristate_within_range(sym, mod))
+ printf("/m");
+ if (oldval != yes && sym_tristate_within_range(sym, yes))
+ printf("/y");
+ printf("/?] ");
+ if (!conf_askvalue(sym, sym_get_string_value(sym)))
+ return 0;
+ strip(line);
+
+ switch (line[0]) {
+ case 'n':
+ case 'N':
+ newval = no;
+ if (!line[1] || !strcmp(&line[1], "o"))
+ break;
+ continue;
+ case 'm':
+ case 'M':
+ newval = mod;
+ if (!line[1])
+ break;
+ continue;
+ case 'y':
+ case 'Y':
+ newval = yes;
+ if (!line[1] || !strcmp(&line[1], "es"))
+ break;
+ continue;
+ case 0:
+ newval = oldval;
+ break;
+ case '?':
+ goto help;
+ default:
+ continue;
+ }
+ if (sym_set_tristate_value(sym, newval))
+ return 0;
+help:
+ print_help(menu);
+ }
+}
+
+static int conf_choice(struct menu *menu)
+{
+ struct symbol *sym, *def_sym;
+ struct menu *child;
+ bool is_new;
+
+ sym = menu->sym;
+ is_new = !sym_has_value(sym);
+ if (sym_is_changeable(sym)) {
+ conf_sym(menu);
+ sym_calc_value(sym);
+ switch (sym_get_tristate_value(sym)) {
+ case no:
+ return 1;
+ case mod:
+ return 0;
+ case yes:
+ break;
+ }
+ } else {
+ switch (sym_get_tristate_value(sym)) {
+ case no:
+ return 1;
+ case mod:
+ printf("%*s%s\n", indent - 1, "", menu_get_prompt(menu));
+ return 0;
+ case yes:
+ break;
+ }
+ }
+
+ while (1) {
+ int cnt, def;
+
+ printf("%*s%s\n", indent - 1, "", menu_get_prompt(menu));
+ def_sym = sym_get_choice_value(sym);
+ cnt = def = 0;
+ line[0] = 0;
+ for (child = menu->list; child; child = child->next) {
+ if (!menu_is_visible(child))
+ continue;
+ if (!child->sym) {
+ printf("%*c %s\n", indent, '*', menu_get_prompt(child));
+ continue;
+ }
+ cnt++;
+ if (child->sym == def_sym) {
+ def = cnt;
+ printf("%*c", indent, '>');
+ } else
+ printf("%*c", indent, ' ');
+ printf(" %d. %s", cnt, menu_get_prompt(child));
+ if (child->sym->name)
+ printf(" (%s)", child->sym->name);
+ if (!sym_has_value(child->sym))
+ printf(" (NEW)");
+ printf("\n");
+ }
+ printf("%*schoice", indent - 1, "");
+ if (cnt == 1) {
+ printf("[1]: 1\n");
+ goto conf_childs;
+ }
+ printf("[1-%d?]: ", cnt);
+ switch (input_mode) {
+ case oldconfig:
+ case syncconfig:
+ if (!is_new) {
+ cnt = def;
+ printf("%d\n", cnt);
+ break;
+ }
+ /* fall through */
+ case oldaskconfig:
+ fflush(stdout);
+ xfgets(line, sizeof(line), stdin);
+ strip(line);
+ if (line[0] == '?') {
+ print_help(menu);
+ continue;
+ }
+ if (!line[0])
+ cnt = def;
+ else if (isdigit(line[0]))
+ cnt = atoi(line);
+ else
+ continue;
+ break;
+ default:
+ break;
+ }
+
+ conf_childs:
+ for (child = menu->list; child; child = child->next) {
+ if (!child->sym || !menu_is_visible(child))
+ continue;
+ if (!--cnt)
+ break;
+ }
+ if (!child)
+ continue;
+ if (line[0] && line[strlen(line) - 1] == '?') {
+ print_help(child);
+ continue;
+ }
+ sym_set_tristate_value(child->sym, yes);
+ for (child = child->list; child; child = child->next) {
+ indent += 2;
+ conf(child);
+ indent -= 2;
+ }
+ return 1;
+ }
+}
+
+static void conf(struct menu *menu)
+{
+ struct symbol *sym;
+ struct property *prop;
+ struct menu *child;
+
+ if (!menu_is_visible(menu))
+ return;
+
+ sym = menu->sym;
+ prop = menu->prompt;
+ if (prop) {
+ const char *prompt;
+
+ switch (prop->type) {
+ case P_MENU:
+ /*
+ * Except in oldaskconfig mode, we show only menus that
+ * contain new symbols.
+ */
+ if (input_mode != oldaskconfig && rootEntry != menu) {
+ check_conf(menu);
+ return;
+ }
+ /* fall through */
+ case P_COMMENT:
+ prompt = menu_get_prompt(menu);
+ if (prompt)
+ printf("%*c\n%*c %s\n%*c\n",
+ indent, '*',
+ indent, '*', prompt,
+ indent, '*');
+ default:
+ ;
+ }
+ }
+
+ if (!sym)
+ goto conf_childs;
+
+ if (sym_is_choice(sym)) {
+ conf_choice(menu);
+ if (sym->curr.tri != mod)
+ return;
+ goto conf_childs;
+ }
+
+ switch (sym->type) {
+ case S_INT:
+ case S_HEX:
+ case S_STRING:
+ conf_string(menu);
+ break;
+ default:
+ conf_sym(menu);
+ break;
+ }
+
+conf_childs:
+ if (sym)
+ indent += 2;
+ for (child = menu->list; child; child = child->next)
+ conf(child);
+ if (sym)
+ indent -= 2;
+}
+
+static void check_conf(struct menu *menu)
+{
+ struct symbol *sym;
+ struct menu *child;
+
+ if (!menu_is_visible(menu))
+ return;
+
+ sym = menu->sym;
+ if (sym && !sym_has_value(sym) &&
+ (sym_is_changeable(sym) ||
+ (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes))) {
+
+ switch (input_mode) {
+ case listnewconfig:
+ if (sym->name)
+ print_symbol_for_listconfig(sym);
+ break;
+ case helpnewconfig:
+ printf("-----\n");
+ print_help(menu);
+ printf("-----\n");
+ break;
+ default:
+ if (!conf_cnt++)
+ printf("*\n* Restart config...\n*\n");
+ rootEntry = menu_get_parent_menu(menu);
+ conf(rootEntry);
+ break;
+ }
+ }
+
+ for (child = menu->list; child; child = child->next)
+ check_conf(child);
+}
+
+static const struct option long_opts[] = {
+ {"help", no_argument, NULL, 'h'},
+ {"silent", no_argument, NULL, 's'},
+ {"oldaskconfig", no_argument, &input_mode_opt, oldaskconfig},
+ {"oldconfig", no_argument, &input_mode_opt, oldconfig},
+ {"syncconfig", no_argument, &input_mode_opt, syncconfig},
+ {"defconfig", required_argument, &input_mode_opt, defconfig},
+ {"savedefconfig", required_argument, &input_mode_opt, savedefconfig},
+ {"allnoconfig", no_argument, &input_mode_opt, allnoconfig},
+ {"allyesconfig", no_argument, &input_mode_opt, allyesconfig},
+ {"allmodconfig", no_argument, &input_mode_opt, allmodconfig},
+ {"alldefconfig", no_argument, &input_mode_opt, alldefconfig},
+ {"randconfig", no_argument, &input_mode_opt, randconfig},
+ {"listnewconfig", no_argument, &input_mode_opt, listnewconfig},
+ {"helpnewconfig", no_argument, &input_mode_opt, helpnewconfig},
+ {"olddefconfig", no_argument, &input_mode_opt, olddefconfig},
+ {"yes2modconfig", no_argument, &input_mode_opt, yes2modconfig},
+ {"mod2yesconfig", no_argument, &input_mode_opt, mod2yesconfig},
+ {"mod2noconfig", no_argument, &input_mode_opt, mod2noconfig},
+ {NULL, 0, NULL, 0}
+};
+
+static void conf_usage(const char *progname)
+{
+ printf("Usage: %s [options] <kconfig-file>\n", progname);
+ printf("\n");
+ printf("Generic options:\n");
+ printf(" -h, --help Print this message and exit.\n");
+ printf(" -s, --silent Do not print log.\n");
+ printf("\n");
+ printf("Mode options:\n");
+ printf(" --listnewconfig List new options\n");
+ printf(" --helpnewconfig List new options and help text\n");
+ printf(" --oldaskconfig Start a new configuration using a line-oriented program\n");
+ printf(" --oldconfig Update a configuration using a provided .config as base\n");
+ printf(" --syncconfig Similar to oldconfig but generates configuration in\n"
+ " include/{generated/,config/}\n");
+ printf(" --olddefconfig Same as oldconfig but sets new symbols to their default value\n");
+ printf(" --defconfig <file> New config with default defined in <file>\n");
+ printf(" --savedefconfig <file> Save the minimal current configuration to <file>\n");
+ printf(" --allnoconfig New config where all options are answered with no\n");
+ printf(" --allyesconfig New config where all options are answered with yes\n");
+ printf(" --allmodconfig New config where all options are answered with mod\n");
+ printf(" --alldefconfig New config with all symbols set to default\n");
+ printf(" --randconfig New config with random answer to all options\n");
+ printf(" --yes2modconfig Change answers from yes to mod if possible\n");
+ printf(" --mod2yesconfig Change answers from mod to yes if possible\n");
+ printf(" --mod2noconfig Change answers from mod to no if possible\n");
+ printf(" (If none of the above is given, --oldaskconfig is the default)\n");
+}
+
+int main(int ac, char **av)
+{
+ const char *progname = av[0];
+ int opt;
+ const char *name, *defconfig_file = NULL /* gcc uninit */;
+ int no_conf_write = 0;
+
+ tty_stdio = isatty(0) && isatty(1);
+
+ while ((opt = getopt_long(ac, av, "hs", long_opts, NULL)) != -1) {
+ switch (opt) {
+ case 'h':
+ conf_usage(progname);
+ exit(1);
+ break;
+ case 's':
+ conf_set_message_callback(NULL);
+ break;
+ case 0:
+ input_mode = input_mode_opt;
+ switch (input_mode) {
+ case syncconfig:
+ /*
+ * syncconfig is invoked during the build stage.
+ * Suppress distracting
+ * "configuration written to ..."
+ */
+ conf_set_message_callback(NULL);
+ sync_kconfig = 1;
+ break;
+ case defconfig:
+ case savedefconfig:
+ defconfig_file = optarg;
+ break;
+ case randconfig:
+ set_randconfig_seed();
+ break;
+ default:
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ if (ac == optind) {
+ fprintf(stderr, "%s: Kconfig file missing\n", av[0]);
+ conf_usage(progname);
+ exit(1);
+ }
+ conf_parse(av[optind]);
+ //zconfdump(stdout);
+
+ switch (input_mode) {
+ case defconfig:
+ if (conf_read(defconfig_file)) {
+ fprintf(stderr,
+ "***\n"
+ "*** Can't find default configuration \"%s\"!\n"
+ "***\n",
+ defconfig_file);
+ exit(1);
+ }
+ break;
+ case savedefconfig:
+ case syncconfig:
+ case oldaskconfig:
+ case oldconfig:
+ case listnewconfig:
+ case helpnewconfig:
+ case olddefconfig:
+ case yes2modconfig:
+ case mod2yesconfig:
+ case mod2noconfig:
+ conf_read(NULL);
+ break;
+ case allnoconfig:
+ case allyesconfig:
+ case allmodconfig:
+ case alldefconfig:
+ case randconfig:
+ name = getenv("KCONFIG_ALLCONFIG");
+ if (!name)
+ break;
+ if ((strcmp(name, "") != 0) && (strcmp(name, "1") != 0)) {
+ if (conf_read_simple(name, S_DEF_USER)) {
+ fprintf(stderr,
+ "*** Can't read seed configuration \"%s\"!\n",
+ name);
+ exit(1);
+ }
+ break;
+ }
+ switch (input_mode) {
+ case allnoconfig: name = "allno.config"; break;
+ case allyesconfig: name = "allyes.config"; break;
+ case allmodconfig: name = "allmod.config"; break;
+ case alldefconfig: name = "alldef.config"; break;
+ case randconfig: name = "allrandom.config"; break;
+ default: break;
+ }
+ if (conf_read_simple(name, S_DEF_USER) &&
+ conf_read_simple("all.config", S_DEF_USER)) {
+ fprintf(stderr,
+ "*** KCONFIG_ALLCONFIG set, but no \"%s\" or \"all.config\" file found\n",
+ name);
+ exit(1);
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (sync_kconfig) {
+ name = getenv("KCONFIG_NOSILENTUPDATE");
+ if (name && *name) {
+ if (conf_get_changed()) {
+ fprintf(stderr,
+ "\n*** The configuration requires explicit update.\n\n");
+ return 1;
+ }
+ no_conf_write = 1;
+ }
+ }
+
+ switch (input_mode) {
+ case allnoconfig:
+ conf_set_all_new_symbols(def_no);
+ break;
+ case allyesconfig:
+ conf_set_all_new_symbols(def_yes);
+ break;
+ case allmodconfig:
+ conf_set_all_new_symbols(def_mod);
+ break;
+ case alldefconfig:
+ conf_set_all_new_symbols(def_default);
+ break;
+ case randconfig:
+ /* Really nothing to do in this loop */
+ while (conf_set_all_new_symbols(def_random)) ;
+ break;
+ case defconfig:
+ conf_set_all_new_symbols(def_default);
+ break;
+ case savedefconfig:
+ break;
+ case yes2modconfig:
+ conf_rewrite_tristates(yes, mod);
+ break;
+ case mod2yesconfig:
+ conf_rewrite_tristates(mod, yes);
+ break;
+ case mod2noconfig:
+ conf_rewrite_tristates(mod, no);
+ break;
+ case oldaskconfig:
+ rootEntry = &rootmenu;
+ conf(&rootmenu);
+ input_mode = oldconfig;
+ /* fall through */
+ case oldconfig:
+ case listnewconfig:
+ case helpnewconfig:
+ case syncconfig:
+ /* Update until a loop caused no more changes */
+ do {
+ conf_cnt = 0;
+ check_conf(&rootmenu);
+ } while (conf_cnt);
+ break;
+ case olddefconfig:
+ default:
+ break;
+ }
+
+ if (input_mode == savedefconfig) {
+ if (conf_write_defconfig(defconfig_file)) {
+ fprintf(stderr, "n*** Error while saving defconfig to: %s\n\n",
+ defconfig_file);
+ return 1;
+ }
+ } else if (input_mode != listnewconfig && input_mode != helpnewconfig) {
+ if (!no_conf_write && conf_write(NULL)) {
+ fprintf(stderr, "\n*** Error during writing of the configuration.\n\n");
+ exit(1);
+ }
+
+ /*
+ * Create auto.conf if it does not exist.
+ * This prevents GNU Make 4.1 or older from emitting
+ * "include/config/auto.conf: No such file or directory"
+ * in the top-level Makefile
+ *
+ * syncconfig always creates or updates auto.conf because it is
+ * used during the build.
+ */
+ if (conf_write_autoconf(sync_kconfig) && sync_kconfig) {
+ fprintf(stderr,
+ "\n*** Error during sync of the configuration.\n\n");
+ return 1;
+ }
+ }
+ return 0;
+}
Index: StarFive/create-6.1.31-3.8.2-host-limits-patch/linux-starfive-6.1.31-3.8.2-new/scripts/kconfig/confdata.c
===================================================================
--- StarFive/create-6.1.31-3.8.2-host-limits-patch/linux-starfive-6.1.31-3.8.2-new/scripts/kconfig/confdata.c (nonexistent)
+++ StarFive/create-6.1.31-3.8.2-host-limits-patch/linux-starfive-6.1.31-3.8.2-new/scripts/kconfig/confdata.c (revision 385)
@@ -0,0 +1,1265 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ */
+
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <linux/limits.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "lkc.h"
+
+/* return true if 'path' exists, false otherwise */
+static bool is_present(const char *path)
+{
+ struct stat st;
+
+ return !stat(path, &st);
+}
+
+/* return true if 'path' exists and it is a directory, false otherwise */
+static bool is_dir(const char *path)
+{
+ struct stat st;
+
+ if (stat(path, &st))
+ return false;
+
+ return S_ISDIR(st.st_mode);
+}
+
+/* return true if the given two files are the same, false otherwise */
+static bool is_same(const char *file1, const char *file2)
+{
+ int fd1, fd2;
+ struct stat st1, st2;
+ void *map1, *map2;
+ bool ret = false;
+
+ fd1 = open(file1, O_RDONLY);
+ if (fd1 < 0)
+ return ret;
+
+ fd2 = open(file2, O_RDONLY);
+ if (fd2 < 0)
+ goto close1;
+
+ ret = fstat(fd1, &st1);
+ if (ret)
+ goto close2;
+ ret = fstat(fd2, &st2);
+ if (ret)
+ goto close2;
+
+ if (st1.st_size != st2.st_size)
+ goto close2;
+
+ map1 = mmap(NULL, st1.st_size, PROT_READ, MAP_PRIVATE, fd1, 0);
+ if (map1 == MAP_FAILED)
+ goto close2;
+
+ map2 = mmap(NULL, st2.st_size, PROT_READ, MAP_PRIVATE, fd2, 0);
+ if (map2 == MAP_FAILED)
+ goto close2;
+
+ if (bcmp(map1, map2, st1.st_size))
+ goto close2;
+
+ ret = true;
+close2:
+ close(fd2);
+close1:
+ close(fd1);
+
+ return ret;
+}
+
+/*
+ * Create the parent directory of the given path.
+ *
+ * For example, if 'include/config/auto.conf' is given, create 'include/config'.
+ */
+static int make_parent_dir(const char *path)
+{
+ char tmp[PATH_MAX + 1];
+ char *p;
+
+ strncpy(tmp, path, sizeof(tmp));
+ tmp[sizeof(tmp) - 1] = 0;
+
+ /* Remove the base name. Just return if nothing is left */
+ p = strrchr(tmp, '/');
+ if (!p)
+ return 0;
+ *(p + 1) = 0;
+
+ /* Just in case it is an absolute path */
+ p = tmp;
+ while (*p == '/')
+ p++;
+
+ while ((p = strchr(p, '/'))) {
+ *p = 0;
+
+ /* skip if the directory exists */
+ if (!is_dir(tmp) && mkdir(tmp, 0755))
+ return -1;
+
+ *p = '/';
+ while (*p == '/')
+ p++;
+ }
+
+ return 0;
+}
+
+static char depfile_path[PATH_MAX];
+static size_t depfile_prefix_len;
+
+/* touch depfile for symbol 'name' */
+static int conf_touch_dep(const char *name)
+{
+ int fd;
+
+ /* check overflow: prefix + name + '\0' must fit in buffer. */
+ if (depfile_prefix_len + strlen(name) + 1 > sizeof(depfile_path))
+ return -1;
+
+ strcpy(depfile_path + depfile_prefix_len, name);
+
+ fd = open(depfile_path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
+ if (fd == -1)
+ return -1;
+ close(fd);
+
+ return 0;
+}
+
+static void conf_warning(const char *fmt, ...)
+ __attribute__ ((format (printf, 1, 2)));
+
+static void conf_message(const char *fmt, ...)
+ __attribute__ ((format (printf, 1, 2)));
+
+static const char *conf_filename;
+static int conf_lineno, conf_warnings;
+
+static void conf_warning(const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ fprintf(stderr, "%s:%d:warning: ", conf_filename, conf_lineno);
+ vfprintf(stderr, fmt, ap);
+ fprintf(stderr, "\n");
+ va_end(ap);
+ conf_warnings++;
+}
+
+static void conf_default_message_callback(const char *s)
+{
+ printf("#\n# ");
+ printf("%s", s);
+ printf("\n#\n");
+}
+
+static void (*conf_message_callback)(const char *s) =
+ conf_default_message_callback;
+void conf_set_message_callback(void (*fn)(const char *s))
+{
+ conf_message_callback = fn;
+}
+
+static void conf_message(const char *fmt, ...)
+{
+ va_list ap;
+ char buf[4096];
+
+ if (!conf_message_callback)
+ return;
+
+ va_start(ap, fmt);
+
+ vsnprintf(buf, sizeof(buf), fmt, ap);
+ conf_message_callback(buf);
+ va_end(ap);
+}
+
+const char *conf_get_configname(void)
+{
+ char *name = getenv("KCONFIG_CONFIG");
+
+ return name ? name : ".config";
+}
+
+static const char *conf_get_autoconfig_name(void)
+{
+ char *name = getenv("KCONFIG_AUTOCONFIG");
+
+ return name ? name : "include/config/auto.conf";
+}
+
+static const char *conf_get_autoheader_name(void)
+{
+ char *name = getenv("KCONFIG_AUTOHEADER");
+
+ return name ? name : "include/generated/autoconf.h";
+}
+
+static const char *conf_get_rustccfg_name(void)
+{
+ char *name = getenv("KCONFIG_RUSTCCFG");
+
+ return name ? name : "include/generated/rustc_cfg";
+}
+
+static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p)
+{
+ char *p2;
+
+ switch (sym->type) {
+ case S_TRISTATE:
+ if (p[0] == 'm') {
+ sym->def[def].tri = mod;
+ sym->flags |= def_flags;
+ break;
+ }
+ /* fall through */
+ case S_BOOLEAN:
+ if (p[0] == 'y') {
+ sym->def[def].tri = yes;
+ sym->flags |= def_flags;
+ break;
+ }
+ if (p[0] == 'n') {
+ sym->def[def].tri = no;
+ sym->flags |= def_flags;
+ break;
+ }
+ if (def != S_DEF_AUTO)
+ conf_warning("symbol value '%s' invalid for %s",
+ p, sym->name);
+ return 1;
+ case S_STRING:
+ /* No escaping for S_DEF_AUTO (include/config/auto.conf) */
+ if (def != S_DEF_AUTO) {
+ if (*p++ != '"')
+ break;
+ for (p2 = p; (p2 = strpbrk(p2, "\"\\")); p2++) {
+ if (*p2 == '"') {
+ *p2 = 0;
+ break;
+ }
+ memmove(p2, p2 + 1, strlen(p2));
+ }
+ if (!p2) {
+ conf_warning("invalid string found");
+ return 1;
+ }
+ }
+ /* fall through */
+ case S_INT:
+ case S_HEX:
+ if (sym_string_valid(sym, p)) {
+ sym->def[def].val = xstrdup(p);
+ sym->flags |= def_flags;
+ } else {
+ if (def != S_DEF_AUTO)
+ conf_warning("symbol value '%s' invalid for %s",
+ p, sym->name);
+ return 1;
+ }
+ break;
+ default:
+ ;
+ }
+ return 0;
+}
+
+#define LINE_GROWTH 16
+static int add_byte(int c, char **lineptr, size_t slen, size_t *n)
+{
+ char *nline;
+ size_t new_size = slen + 1;
+ if (new_size > *n) {
+ new_size += LINE_GROWTH - 1;
+ new_size *= 2;
+ nline = xrealloc(*lineptr, new_size);
+ if (!nline)
+ return -1;
+
+ *lineptr = nline;
+ *n = new_size;
+ }
+
+ (*lineptr)[slen] = c;
+
+ return 0;
+}
+
+static ssize_t compat_getline(char **lineptr, size_t *n, FILE *stream)
+{
+ char *line = *lineptr;
+ size_t slen = 0;
+
+ for (;;) {
+ int c = getc(stream);
+
+ switch (c) {
+ case '\n':
+ if (add_byte(c, &line, slen, n) < 0)
+ goto e_out;
+ slen++;
+ /* fall through */
+ case EOF:
+ if (add_byte('\0', &line, slen, n) < 0)
+ goto e_out;
+ *lineptr = line;
+ if (slen == 0)
+ return -1;
+ return slen;
+ default:
+ if (add_byte(c, &line, slen, n) < 0)
+ goto e_out;
+ slen++;
+ }
+ }
+
+e_out:
+ line[slen-1] = '\0';
+ *lineptr = line;
+ return -1;
+}
+
+int conf_read_simple(const char *name, int def)
+{
+ FILE *in = NULL;
+ char *line = NULL;
+ size_t line_asize = 0;
+ char *p, *p2;
+ struct symbol *sym;
+ int i, def_flags;
+
+ if (name) {
+ in = zconf_fopen(name);
+ } else {
+ char *env;
+
+ name = conf_get_configname();
+ in = zconf_fopen(name);
+ if (in)
+ goto load;
+ conf_set_changed(true);
+
+ env = getenv("KCONFIG_DEFCONFIG_LIST");
+ if (!env)
+ return 1;
+
+ while (1) {
+ bool is_last;
+
+ while (isspace(*env))
+ env++;
+
+ if (!*env)
+ break;
+
+ p = env;
+ while (*p && !isspace(*p))
+ p++;
+
+ is_last = (*p == '\0');
+
+ *p = '\0';
+
+ in = zconf_fopen(env);
+ if (in) {
+ conf_message("using defaults found in %s",
+ env);
+ goto load;
+ }
+
+ if (is_last)
+ break;
+
+ env = p + 1;
+ }
+ }
+ if (!in)
+ return 1;
+
+load:
+ conf_filename = name;
+ conf_lineno = 0;
+ conf_warnings = 0;
+
+ def_flags = SYMBOL_DEF << def;
+ for_all_symbols(i, sym) {
+ sym->flags |= SYMBOL_CHANGED;
+ sym->flags &= ~(def_flags|SYMBOL_VALID);
+ if (sym_is_choice(sym))
+ sym->flags |= def_flags;
+ switch (sym->type) {
+ case S_INT:
+ case S_HEX:
+ case S_STRING:
+ if (sym->def[def].val)
+ free(sym->def[def].val);
+ /* fall through */
+ default:
+ sym->def[def].val = NULL;
+ sym->def[def].tri = no;
+ }
+ }
+
+ while (compat_getline(&line, &line_asize, in) != -1) {
+ conf_lineno++;
+ sym = NULL;
+ if (line[0] == '#') {
+ if (memcmp(line + 2, CONFIG_, strlen(CONFIG_)))
+ continue;
+ p = strchr(line + 2 + strlen(CONFIG_), ' ');
+ if (!p)
+ continue;
+ *p++ = 0;
+ if (strncmp(p, "is not set", 10))
+ continue;
+ if (def == S_DEF_USER) {
+ sym = sym_find(line + 2 + strlen(CONFIG_));
+ if (!sym) {
+ conf_set_changed(true);
+ continue;
+ }
+ } else {
+ sym = sym_lookup(line + 2 + strlen(CONFIG_), 0);
+ if (sym->type == S_UNKNOWN)
+ sym->type = S_BOOLEAN;
+ }
+ if (sym->flags & def_flags) {
+ conf_warning("override: reassigning to symbol %s", sym->name);
+ }
+ switch (sym->type) {
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ sym->def[def].tri = no;
+ sym->flags |= def_flags;
+ break;
+ default:
+ ;
+ }
+ } else if (memcmp(line, CONFIG_, strlen(CONFIG_)) == 0) {
+ p = strchr(line + strlen(CONFIG_), '=');
+ if (!p)
+ continue;
+ *p++ = 0;
+ p2 = strchr(p, '\n');
+ if (p2) {
+ *p2-- = 0;
+ if (*p2 == '\r')
+ *p2 = 0;
+ }
+
+ sym = sym_find(line + strlen(CONFIG_));
+ if (!sym) {
+ if (def == S_DEF_AUTO)
+ /*
+ * Reading from include/config/auto.conf
+ * If CONFIG_FOO previously existed in
+ * auto.conf but it is missing now,
+ * include/config/FOO must be touched.
+ */
+ conf_touch_dep(line + strlen(CONFIG_));
+ else
+ conf_set_changed(true);
+ continue;
+ }
+
+ if (sym->flags & def_flags) {
+ conf_warning("override: reassigning to symbol %s", sym->name);
+ }
+ if (conf_set_sym_val(sym, def, def_flags, p))
+ continue;
+ } else {
+ if (line[0] != '\r' && line[0] != '\n')
+ conf_warning("unexpected data: %.*s",
+ (int)strcspn(line, "\r\n"), line);
+
+ continue;
+ }
+
+ if (sym && sym_is_choice_value(sym)) {
+ struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym));
+ switch (sym->def[def].tri) {
+ case no:
+ break;
+ case mod:
+ if (cs->def[def].tri == yes) {
+ conf_warning("%s creates inconsistent choice state", sym->name);
+ cs->flags &= ~def_flags;
+ }
+ break;
+ case yes:
+ if (cs->def[def].tri != no)
+ conf_warning("override: %s changes choice state", sym->name);
+ cs->def[def].val = sym;
+ break;
+ }
+ cs->def[def].tri = EXPR_OR(cs->def[def].tri, sym->def[def].tri);
+ }
+ }
+ free(line);
+ fclose(in);
+ return 0;
+}
+
+int conf_read(const char *name)
+{
+ struct symbol *sym;
+ int conf_unsaved = 0;
+ int i;
+
+ conf_set_changed(false);
+
+ if (conf_read_simple(name, S_DEF_USER)) {
+ sym_calc_value(modules_sym);
+ return 1;
+ }
+
+ sym_calc_value(modules_sym);
+
+ for_all_symbols(i, sym) {
+ sym_calc_value(sym);
+ if (sym_is_choice(sym) || (sym->flags & SYMBOL_NO_WRITE))
+ continue;
+ if (sym_has_value(sym) && (sym->flags & SYMBOL_WRITE)) {
+ /* check that calculated value agrees with saved value */
+ switch (sym->type) {
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ if (sym->def[S_DEF_USER].tri == sym_get_tristate_value(sym))
+ continue;
+ break;
+ default:
+ if (!strcmp(sym->curr.val, sym->def[S_DEF_USER].val))
+ continue;
+ break;
+ }
+ } else if (!sym_has_value(sym) && !(sym->flags & SYMBOL_WRITE))
+ /* no previous value and not saved */
+ continue;
+ conf_unsaved++;
+ /* maybe print value in verbose mode... */
+ }
+
+ for_all_symbols(i, sym) {
+ if (sym_has_value(sym) && !sym_is_choice_value(sym)) {
+ /* Reset values of generates values, so they'll appear
+ * as new, if they should become visible, but that
+ * doesn't quite work if the Kconfig and the saved
+ * configuration disagree.
+ */
+ if (sym->visible == no && !conf_unsaved)
+ sym->flags &= ~SYMBOL_DEF_USER;
+ switch (sym->type) {
+ case S_STRING:
+ case S_INT:
+ case S_HEX:
+ /* Reset a string value if it's out of range */
+ if (sym_string_within_range(sym, sym->def[S_DEF_USER].val))
+ break;
+ sym->flags &= ~(SYMBOL_VALID|SYMBOL_DEF_USER);
+ conf_unsaved++;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ if (conf_warnings || conf_unsaved)
+ conf_set_changed(true);
+
+ return 0;
+}
+
+struct comment_style {
+ const char *decoration;
+ const char *prefix;
+ const char *postfix;
+};
+
+static const struct comment_style comment_style_pound = {
+ .decoration = "#",
+ .prefix = "#",
+ .postfix = "#",
+};
+
+static const struct comment_style comment_style_c = {
+ .decoration = " *",
+ .prefix = "/*",
+ .postfix = " */",
+};
+
+static void conf_write_heading(FILE *fp, const struct comment_style *cs)
+{
+ if (!cs)
+ return;
+
+ fprintf(fp, "%s\n", cs->prefix);
+
+ fprintf(fp, "%s Automatically generated file; DO NOT EDIT.\n",
+ cs->decoration);
+
+ fprintf(fp, "%s %s\n", cs->decoration, rootmenu.prompt->text);
+
+ fprintf(fp, "%s\n", cs->postfix);
+}
+
+/* The returned pointer must be freed on the caller side */
+static char *escape_string_value(const char *in)
+{
+ const char *p;
+ char *out;
+ size_t len;
+
+ len = strlen(in) + strlen("\"\"") + 1;
+
+ p = in;
+ while (1) {
+ p += strcspn(p, "\"\\");
+
+ if (p[0] == '\0')
+ break;
+
+ len++;
+ p++;
+ }
+
+ out = xmalloc(len);
+ out[0] = '\0';
+
+ strcat(out, "\"");
+
+ p = in;
+ while (1) {
+ len = strcspn(p, "\"\\");
+ strncat(out, p, len);
+ p += len;
+
+ if (p[0] == '\0')
+ break;
+
+ strcat(out, "\\");
+ strncat(out, p++, 1);
+ }
+
+ strcat(out, "\"");
+
+ return out;
+}
+
+enum output_n { OUTPUT_N, OUTPUT_N_AS_UNSET, OUTPUT_N_NONE };
+
+static void __print_symbol(FILE *fp, struct symbol *sym, enum output_n output_n,
+ bool escape_string)
+{
+ const char *val;
+ char *escaped = NULL;
+
+ if (sym->type == S_UNKNOWN)
+ return;
+
+ val = sym_get_string_value(sym);
+
+ if ((sym->type == S_BOOLEAN || sym->type == S_TRISTATE) &&
+ output_n != OUTPUT_N && *val == 'n') {
+ if (output_n == OUTPUT_N_AS_UNSET)
+ fprintf(fp, "# %s%s is not set\n", CONFIG_, sym->name);
+ return;
+ }
+
+ if (sym->type == S_STRING && escape_string) {
+ escaped = escape_string_value(val);
+ val = escaped;
+ }
+
+ fprintf(fp, "%s%s=%s\n", CONFIG_, sym->name, val);
+
+ free(escaped);
+}
+
+static void print_symbol_for_dotconfig(FILE *fp, struct symbol *sym)
+{
+ __print_symbol(fp, sym, OUTPUT_N_AS_UNSET, true);
+}
+
+static void print_symbol_for_autoconf(FILE *fp, struct symbol *sym)
+{
+ __print_symbol(fp, sym, OUTPUT_N_NONE, false);
+}
+
+void print_symbol_for_listconfig(struct symbol *sym)
+{
+ __print_symbol(stdout, sym, OUTPUT_N, true);
+}
+
+static void print_symbol_for_c(FILE *fp, struct symbol *sym)
+{
+ const char *val;
+ const char *sym_suffix = "";
+ const char *val_prefix = "";
+ char *escaped = NULL;
+
+ if (sym->type == S_UNKNOWN)
+ return;
+
+ val = sym_get_string_value(sym);
+
+ switch (sym->type) {
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ switch (*val) {
+ case 'n':
+ return;
+ case 'm':
+ sym_suffix = "_MODULE";
+ /* fall through */
+ default:
+ val = "1";
+ }
+ break;
+ case S_HEX:
+ if (val[0] != '0' || (val[1] != 'x' && val[1] != 'X'))
+ val_prefix = "0x";
+ break;
+ case S_STRING:
+ escaped = escape_string_value(val);
+ val = escaped;
+ default:
+ break;
+ }
+
+ fprintf(fp, "#define %s%s%s %s%s\n", CONFIG_, sym->name, sym_suffix,
+ val_prefix, val);
+
+ free(escaped);
+}
+
+static void print_symbol_for_rustccfg(FILE *fp, struct symbol *sym)
+{
+ const char *val;
+ const char *val_prefix = "";
+ char *val_prefixed = NULL;
+ size_t val_prefixed_len;
+ char *escaped = NULL;
+
+ if (sym->type == S_UNKNOWN)
+ return;
+
+ val = sym_get_string_value(sym);
+
+ switch (sym->type) {
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ /*
+ * We do not care about disabled ones, i.e. no need for
+ * what otherwise are "comments" in other printers.
+ */
+ if (*val == 'n')
+ return;
+
+ /*
+ * To have similar functionality to the C macro `IS_ENABLED()`
+ * we provide an empty `--cfg CONFIG_X` here in both `y`
+ * and `m` cases.
+ *
+ * Then, the common `fprintf()` below will also give us
+ * a `--cfg CONFIG_X="y"` or `--cfg CONFIG_X="m"`, which can
+ * be used as the equivalent of `IS_BUILTIN()`/`IS_MODULE()`.
+ */
+ fprintf(fp, "--cfg=%s%s\n", CONFIG_, sym->name);
+ break;
+ case S_HEX:
+ if (val[0] != '0' || (val[1] != 'x' && val[1] != 'X'))
+ val_prefix = "0x";
+ break;
+ default:
+ break;
+ }
+
+ if (strlen(val_prefix) > 0) {
+ val_prefixed_len = strlen(val) + strlen(val_prefix) + 1;
+ val_prefixed = xmalloc(val_prefixed_len);
+ snprintf(val_prefixed, val_prefixed_len, "%s%s", val_prefix, val);
+ val = val_prefixed;
+ }
+
+ /* All values get escaped: the `--cfg` option only takes strings */
+ escaped = escape_string_value(val);
+ val = escaped;
+
+ fprintf(fp, "--cfg=%s%s=%s\n", CONFIG_, sym->name, val);
+
+ free(escaped);
+ free(val_prefixed);
+}
+
+/*
+ * Write out a minimal config.
+ * All values that has default values are skipped as this is redundant.
+ */
+int conf_write_defconfig(const char *filename)
+{
+ struct symbol *sym;
+ struct menu *menu;
+ FILE *out;
+
+ out = fopen(filename, "w");
+ if (!out)
+ return 1;
+
+ sym_clear_all_valid();
+
+ /* Traverse all menus to find all relevant symbols */
+ menu = rootmenu.list;
+
+ while (menu != NULL)
+ {
+ sym = menu->sym;
+ if (sym == NULL) {
+ if (!menu_is_visible(menu))
+ goto next_menu;
+ } else if (!sym_is_choice(sym)) {
+ sym_calc_value(sym);
+ if (!(sym->flags & SYMBOL_WRITE))
+ goto next_menu;
+ sym->flags &= ~SYMBOL_WRITE;
+ /* If we cannot change the symbol - skip */
+ if (!sym_is_changeable(sym))
+ goto next_menu;
+ /* If symbol equals to default value - skip */
+ if (strcmp(sym_get_string_value(sym), sym_get_string_default(sym)) == 0)
+ goto next_menu;
+
+ /*
+ * If symbol is a choice value and equals to the
+ * default for a choice - skip.
+ * But only if value is bool and equal to "y" and
+ * choice is not "optional".
+ * (If choice is "optional" then all values can be "n")
+ */
+ if (sym_is_choice_value(sym)) {
+ struct symbol *cs;
+ struct symbol *ds;
+
+ cs = prop_get_symbol(sym_get_choice_prop(sym));
+ ds = sym_choice_default(cs);
+ if (!sym_is_optional(cs) && sym == ds) {
+ if ((sym->type == S_BOOLEAN) &&
+ sym_get_tristate_value(sym) == yes)
+ goto next_menu;
+ }
+ }
+ print_symbol_for_dotconfig(out, sym);
+ }
+next_menu:
+ if (menu->list != NULL) {
+ menu = menu->list;
+ }
+ else if (menu->next != NULL) {
+ menu = menu->next;
+ } else {
+ while ((menu = menu->parent)) {
+ if (menu->next != NULL) {
+ menu = menu->next;
+ break;
+ }
+ }
+ }
+ }
+ fclose(out);
+ return 0;
+}
+
+int conf_write(const char *name)
+{
+ FILE *out;
+ struct symbol *sym;
+ struct menu *menu;
+ const char *str;
+ char tmpname[PATH_MAX + 1], oldname[PATH_MAX + 1];
+ char *env;
+ int i;
+ bool need_newline = false;
+
+ if (!name)
+ name = conf_get_configname();
+
+ if (!*name) {
+ fprintf(stderr, "config name is empty\n");
+ return -1;
+ }
+
+ if (is_dir(name)) {
+ fprintf(stderr, "%s: Is a directory\n", name);
+ return -1;
+ }
+
+ if (make_parent_dir(name))
+ return -1;
+
+ env = getenv("KCONFIG_OVERWRITECONFIG");
+ if (env && *env) {
+ *tmpname = 0;
+ out = fopen(name, "w");
+ } else {
+ snprintf(tmpname, sizeof(tmpname), "%s.%d.tmp",
+ name, (int)getpid());
+ out = fopen(tmpname, "w");
+ }
+ if (!out)
+ return 1;
+
+ conf_write_heading(out, &comment_style_pound);
+
+ if (!conf_get_changed())
+ sym_clear_all_valid();
+
+ menu = rootmenu.list;
+ while (menu) {
+ sym = menu->sym;
+ if (!sym) {
+ if (!menu_is_visible(menu))
+ goto next;
+ str = menu_get_prompt(menu);
+ fprintf(out, "\n"
+ "#\n"
+ "# %s\n"
+ "#\n", str);
+ need_newline = false;
+ } else if (!(sym->flags & SYMBOL_CHOICE) &&
+ !(sym->flags & SYMBOL_WRITTEN)) {
+ sym_calc_value(sym);
+ if (!(sym->flags & SYMBOL_WRITE))
+ goto next;
+ if (need_newline) {
+ fprintf(out, "\n");
+ need_newline = false;
+ }
+ sym->flags |= SYMBOL_WRITTEN;
+ print_symbol_for_dotconfig(out, sym);
+ }
+
+next:
+ if (menu->list) {
+ menu = menu->list;
+ continue;
+ }
+
+end_check:
+ if (!menu->sym && menu_is_visible(menu) && menu != &rootmenu &&
+ menu->prompt->type == P_MENU) {
+ fprintf(out, "# end of %s\n", menu_get_prompt(menu));
+ need_newline = true;
+ }
+
+ if (menu->next) {
+ menu = menu->next;
+ } else {
+ menu = menu->parent;
+ if (menu)
+ goto end_check;
+ }
+ }
+ fclose(out);
+
+ for_all_symbols(i, sym)
+ sym->flags &= ~SYMBOL_WRITTEN;
+
+ if (*tmpname) {
+ if (is_same(name, tmpname)) {
+ conf_message("No change to %s", name);
+ unlink(tmpname);
+ conf_set_changed(false);
+ return 0;
+ }
+
+ snprintf(oldname, sizeof(oldname), "%s.old", name);
+ rename(name, oldname);
+ if (rename(tmpname, name))
+ return 1;
+ }
+
+ conf_message("configuration written to %s", name);
+
+ conf_set_changed(false);
+
+ return 0;
+}
+
+/* write a dependency file as used by kbuild to track dependencies */
+static int conf_write_autoconf_cmd(const char *autoconf_name)
+{
+ char name[PATH_MAX], tmp[PATH_MAX];
+ struct file *file;
+ FILE *out;
+ int ret;
+
+ ret = snprintf(name, sizeof(name), "%s.cmd", autoconf_name);
+ if (ret >= sizeof(name)) /* check truncation */
+ return -1;
+
+ if (make_parent_dir(name))
+ return -1;
+
+ ret = snprintf(tmp, sizeof(tmp), "%s.cmd.tmp", autoconf_name);
+ if (ret >= sizeof(tmp)) /* check truncation */
+ return -1;
+
+ out = fopen(tmp, "w");
+ if (!out) {
+ perror("fopen");
+ return -1;
+ }
+
+ fprintf(out, "deps_config := \\\n");
+ for (file = file_list; file; file = file->next)
+ fprintf(out, "\t%s \\\n", file->name);
+
+ fprintf(out, "\n%s: $(deps_config)\n\n", autoconf_name);
+
+ env_write_dep(out, autoconf_name);
+
+ fprintf(out, "\n$(deps_config): ;\n");
+
+ fflush(out);
+ ret = ferror(out); /* error check for all fprintf() calls */
+ fclose(out);
+ if (ret)
+ return -1;
+
+ if (rename(tmp, name)) {
+ perror("rename");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int conf_touch_deps(void)
+{
+ const char *name, *tmp;
+ struct symbol *sym;
+ int res, i;
+
+ name = conf_get_autoconfig_name();
+ tmp = strrchr(name, '/');
+ depfile_prefix_len = tmp ? tmp - name + 1 : 0;
+ if (depfile_prefix_len + 1 > sizeof(depfile_path))
+ return -1;
+
+ strncpy(depfile_path, name, depfile_prefix_len);
+ depfile_path[depfile_prefix_len] = 0;
+
+ conf_read_simple(name, S_DEF_AUTO);
+ sym_calc_value(modules_sym);
+
+ for_all_symbols(i, sym) {
+ sym_calc_value(sym);
+ if ((sym->flags & SYMBOL_NO_WRITE) || !sym->name)
+ continue;
+ if (sym->flags & SYMBOL_WRITE) {
+ if (sym->flags & SYMBOL_DEF_AUTO) {
+ /*
+ * symbol has old and new value,
+ * so compare them...
+ */
+ switch (sym->type) {
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ if (sym_get_tristate_value(sym) ==
+ sym->def[S_DEF_AUTO].tri)
+ continue;
+ break;
+ case S_STRING:
+ case S_HEX:
+ case S_INT:
+ if (!strcmp(sym_get_string_value(sym),
+ sym->def[S_DEF_AUTO].val))
+ continue;
+ break;
+ default:
+ break;
+ }
+ } else {
+ /*
+ * If there is no old value, only 'no' (unset)
+ * is allowed as new value.
+ */
+ switch (sym->type) {
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ if (sym_get_tristate_value(sym) == no)
+ continue;
+ break;
+ default:
+ break;
+ }
+ }
+ } else if (!(sym->flags & SYMBOL_DEF_AUTO))
+ /* There is neither an old nor a new value. */
+ continue;
+ /* else
+ * There is an old value, but no new value ('no' (unset)
+ * isn't saved in auto.conf, so the old value is always
+ * different from 'no').
+ */
+
+ res = conf_touch_dep(sym->name);
+ if (res)
+ return res;
+ }
+
+ return 0;
+}
+
+static int __conf_write_autoconf(const char *filename,
+ void (*print_symbol)(FILE *, struct symbol *),
+ const struct comment_style *comment_style)
+{
+ char tmp[PATH_MAX];
+ FILE *file;
+ struct symbol *sym;
+ int ret, i;
+
+ if (make_parent_dir(filename))
+ return -1;
+
+ ret = snprintf(tmp, sizeof(tmp), "%s.tmp", filename);
+ if (ret >= sizeof(tmp)) /* check truncation */
+ return -1;
+
+ file = fopen(tmp, "w");
+ if (!file) {
+ perror("fopen");
+ return -1;
+ }
+
+ conf_write_heading(file, comment_style);
+
+ for_all_symbols(i, sym)
+ if ((sym->flags & SYMBOL_WRITE) && sym->name)
+ print_symbol(file, sym);
+
+ fflush(file);
+ /* check possible errors in conf_write_heading() and print_symbol() */
+ ret = ferror(file);
+ fclose(file);
+ if (ret)
+ return -1;
+
+ if (rename(tmp, filename)) {
+ perror("rename");
+ return -1;
+ }
+
+ return 0;
+}
+
+int conf_write_autoconf(int overwrite)
+{
+ struct symbol *sym;
+ const char *autoconf_name = conf_get_autoconfig_name();
+ int ret, i;
+
+ if (!overwrite && is_present(autoconf_name))
+ return 0;
+
+ ret = conf_write_autoconf_cmd(autoconf_name);
+ if (ret)
+ return -1;
+
+ if (conf_touch_deps())
+ return 1;
+
+ for_all_symbols(i, sym)
+ sym_calc_value(sym);
+
+ ret = __conf_write_autoconf(conf_get_autoheader_name(),
+ print_symbol_for_c,
+ &comment_style_c);
+ if (ret)
+ return ret;
+
+ ret = __conf_write_autoconf(conf_get_rustccfg_name(),
+ print_symbol_for_rustccfg,
+ NULL);
+ if (ret)
+ return ret;
+
+ /*
+ * Create include/config/auto.conf. This must be the last step because
+ * Kbuild has a dependency on auto.conf and this marks the successful
+ * completion of the previous steps.
+ */
+ ret = __conf_write_autoconf(conf_get_autoconfig_name(),
+ print_symbol_for_autoconf,
+ &comment_style_pound);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static bool conf_changed;
+static void (*conf_changed_callback)(void);
+
+void conf_set_changed(bool val)
+{
+ bool changed = conf_changed != val;
+
+ conf_changed = val;
+
+ if (conf_changed_callback && changed)
+ conf_changed_callback();
+}
+
+bool conf_get_changed(void)
+{
+ return conf_changed;
+}
+
+void conf_set_changed_callback(void (*fn)(void))
+{
+ conf_changed_callback = fn;
+}
+
+void set_all_choice_values(struct symbol *csym)
+{
+ struct property *prop;
+ struct symbol *sym;
+ struct expr *e;
+
+ prop = sym_get_choice_prop(csym);
+
+ /*
+ * Set all non-assinged choice values to no
+ */
+ expr_list_for_each_sym(prop->expr, e, sym) {
+ if (!sym_has_value(sym))
+ sym->def[S_DEF_USER].tri = no;
+ }
+ csym->flags |= SYMBOL_DEF_USER;
+ /* clear VALID to get value calculated */
+ csym->flags &= ~(SYMBOL_VALID | SYMBOL_NEED_SET_CHOICE_VALUES);
+}
Index: StarFive/create-6.1.31-3.8.2-host-limits-patch/linux-starfive-6.1.31-3.8.2-new/scripts/kconfig/lexer.l
===================================================================
--- StarFive/create-6.1.31-3.8.2-host-limits-patch/linux-starfive-6.1.31-3.8.2-new/scripts/kconfig/lexer.l (nonexistent)
+++ StarFive/create-6.1.31-3.8.2-host-limits-patch/linux-starfive-6.1.31-3.8.2-new/scripts/kconfig/lexer.l (revision 385)
@@ -0,0 +1,468 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ */
+%option nostdinit noyywrap never-interactive full ecs
+%option 8bit nodefault yylineno
+%x ASSIGN_VAL HELP STRING
+%{
+
+#include <assert.h>
+#include <linux/limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "lkc.h"
+#include "parser.tab.h"
+
+#define YY_DECL static int yylex1(void)
+
+#define START_STRSIZE 16
+
+static struct {
+ struct file *file;
+ int lineno;
+} current_pos;
+
+static int prev_prev_token = T_EOL;
+static int prev_token = T_EOL;
+static char *text;
+static int text_size, text_asize;
+
+struct buffer {
+ struct buffer *parent;
+ YY_BUFFER_STATE state;
+};
+
+static struct buffer *current_buf;
+
+static int last_ts, first_ts;
+
+static char *expand_token(const char *in, size_t n);
+static void append_expanded_string(const char *in);
+static void zconf_endhelp(void);
+static void zconf_endfile(void);
+
+static void new_string(void)
+{
+ text = xmalloc(START_STRSIZE);
+ text_asize = START_STRSIZE;
+ text_size = 0;
+ *text = 0;
+}
+
+static void append_string(const char *str, int size)
+{
+ int new_size = text_size + size + 1;
+ if (new_size > text_asize) {
+ new_size += START_STRSIZE - 1;
+ new_size &= -START_STRSIZE;
+ text = xrealloc(text, new_size);
+ text_asize = new_size;
+ }
+ memcpy(text + text_size, str, size);
+ text_size += size;
+ text[text_size] = 0;
+}
+
+static void alloc_string(const char *str, int size)
+{
+ text = xmalloc(size + 1);
+ memcpy(text, str, size);
+ text[size] = 0;
+}
+
+static void warn_ignored_character(char chr)
+{
+ fprintf(stderr,
+ "%s:%d:warning: ignoring unsupported character '%c'\n",
+ current_file->name, yylineno, chr);
+}
+%}
+
+n [A-Za-z0-9_-]
+
+%%
+ char open_quote = 0;
+
+#.* /* ignore comment */
+[ \t]* /* whitespaces */
+\\\n /* escaped new line */
+\n return T_EOL;
+"bool" return T_BOOL;
+"choice" return T_CHOICE;
+"comment" return T_COMMENT;
+"config" return T_CONFIG;
+"def_bool" return T_DEF_BOOL;
+"def_tristate" return T_DEF_TRISTATE;
+"default" return T_DEFAULT;
+"depends" return T_DEPENDS;
+"endchoice" return T_ENDCHOICE;
+"endif" return T_ENDIF;
+"endmenu" return T_ENDMENU;
+"help" return T_HELP;
+"hex" return T_HEX;
+"if" return T_IF;
+"imply" return T_IMPLY;
+"int" return T_INT;
+"mainmenu" return T_MAINMENU;
+"menu" return T_MENU;
+"menuconfig" return T_MENUCONFIG;
+"modules" return T_MODULES;
+"on" return T_ON;
+"optional" return T_OPTIONAL;
+"prompt" return T_PROMPT;
+"range" return T_RANGE;
+"select" return T_SELECT;
+"source" return T_SOURCE;
+"string" return T_STRING;
+"tristate" return T_TRISTATE;
+"visible" return T_VISIBLE;
+"||" return T_OR;
+"&&" return T_AND;
+"=" return T_EQUAL;
+"!=" return T_UNEQUAL;
+"<" return T_LESS;
+"<=" return T_LESS_EQUAL;
+">" return T_GREATER;
+">=" return T_GREATER_EQUAL;
+"!" return T_NOT;
+"(" return T_OPEN_PAREN;
+")" return T_CLOSE_PAREN;
+":=" return T_COLON_EQUAL;
+"+=" return T_PLUS_EQUAL;
+\"|\' {
+ open_quote = yytext[0];
+ new_string();
+ BEGIN(STRING);
+ }
+{n}+ {
+ alloc_string(yytext, yyleng);
+ yylval.string = text;
+ return T_WORD;
+ }
+({n}|$)+ {
+ /* this token includes at least one '$' */
+ yylval.string = expand_token(yytext, yyleng);
+ if (strlen(yylval.string))
+ return T_WORD;
+ free(yylval.string);
+ }
+. warn_ignored_character(*yytext);
+
+<ASSIGN_VAL>{
+ [^[:blank:]\n]+.* {
+ alloc_string(yytext, yyleng);
+ yylval.string = text;
+ return T_ASSIGN_VAL;
+ }
+ \n { BEGIN(INITIAL); return T_EOL; }
+ .
+}
+
+<STRING>{
+ "$".* append_expanded_string(yytext);
+ [^$'"\\\n]+ {
+ append_string(yytext, yyleng);
+ }
+ \\.? {
+ append_string(yytext + 1, yyleng - 1);
+ }
+ \'|\" {
+ if (open_quote == yytext[0]) {
+ BEGIN(INITIAL);
+ yylval.string = text;
+ return T_WORD_QUOTE;
+ } else
+ append_string(yytext, 1);
+ }
+ \n {
+ fprintf(stderr,
+ "%s:%d:warning: multi-line strings not supported\n",
+ zconf_curname(), zconf_lineno());
+ unput('\n');
+ BEGIN(INITIAL);
+ yylval.string = text;
+ return T_WORD_QUOTE;
+ }
+ <<EOF>> {
+ BEGIN(INITIAL);
+ yylval.string = text;
+ return T_WORD_QUOTE;
+ }
+}
+
+<HELP>{
+ [ \t]+ {
+ int ts, i;
+
+ ts = 0;
+ for (i = 0; i < yyleng; i++) {
+ if (yytext[i] == '\t')
+ ts = (ts & ~7) + 8;
+ else
+ ts++;
+ }
+ last_ts = ts;
+ if (first_ts) {
+ if (ts < first_ts) {
+ zconf_endhelp();
+ return T_HELPTEXT;
+ }
+ ts -= first_ts;
+ while (ts > 8) {
+ append_string(" ", 8);
+ ts -= 8;
+ }
+ append_string(" ", ts);
+ }
+ }
+ [ \t]*\n/[^ \t\n] {
+ zconf_endhelp();
+ return T_HELPTEXT;
+ }
+ [ \t]*\n {
+ append_string("\n", 1);
+ }
+ [^ \t\n].* {
+ while (yyleng) {
+ if ((yytext[yyleng-1] != ' ') && (yytext[yyleng-1] != '\t'))
+ break;
+ yyleng--;
+ }
+ append_string(yytext, yyleng);
+ if (!first_ts)
+ first_ts = last_ts;
+ }
+ <<EOF>> {
+ zconf_endhelp();
+ return T_HELPTEXT;
+ }
+}
+
+<<EOF>> {
+ BEGIN(INITIAL);
+
+ if (prev_token != T_EOL && prev_token != T_HELPTEXT)
+ fprintf(stderr, "%s:%d:warning: no new line at end of file\n",
+ current_file->name, yylineno);
+
+ if (current_file) {
+ zconf_endfile();
+ return T_EOL;
+ }
+ fclose(yyin);
+ yyterminate();
+}
+
+%%
+
+/* second stage lexer */
+int yylex(void)
+{
+ int token;
+
+repeat:
+ token = yylex1();
+
+ if (prev_token == T_EOL || prev_token == T_HELPTEXT) {
+ if (token == T_EOL) {
+ /* Do not pass unneeded T_EOL to the parser. */
+ goto repeat;
+ } else {
+ /*
+ * For the parser, update file/lineno at the first token
+ * of each statement. Generally, \n is a statement
+ * terminator in Kconfig, but it is not always true
+ * because \n could be escaped by a backslash.
+ */
+ current_pos.file = current_file;
+ current_pos.lineno = yylineno;
+ }
+ }
+
+ if (prev_prev_token == T_EOL && prev_token == T_WORD &&
+ (token == T_EQUAL || token == T_COLON_EQUAL || token == T_PLUS_EQUAL))
+ BEGIN(ASSIGN_VAL);
+
+ prev_prev_token = prev_token;
+ prev_token = token;
+
+ return token;
+}
+
+static char *expand_token(const char *in, size_t n)
+{
+ char *out;
+ int c;
+ char c2;
+ const char *rest, *end;
+
+ new_string();
+ append_string(in, n);
+
+ /* get the whole line because we do not know the end of token. */
+ while ((c = input()) != EOF) {
+ if (c == '\n') {
+ unput(c);
+ break;
+ }
+ c2 = c;
+ append_string(&c2, 1);
+ }
+
+ rest = text;
+ out = expand_one_token(&rest);
+
+ /* push back unused characters to the input stream */
+ end = rest + strlen(rest);
+ while (end > rest)
+ unput(*--end);
+
+ free(text);
+
+ return out;
+}
+
+static void append_expanded_string(const char *str)
+{
+ const char *end;
+ char *res;
+
+ str++;
+
+ res = expand_dollar(&str);
+
+ /* push back unused characters to the input stream */
+ end = str + strlen(str);
+ while (end > str)
+ unput(*--end);
+
+ append_string(res, strlen(res));
+
+ free(res);
+}
+
+void zconf_starthelp(void)
+{
+ new_string();
+ last_ts = first_ts = 0;
+ BEGIN(HELP);
+}
+
+static void zconf_endhelp(void)
+{
+ yylval.string = text;
+ BEGIN(INITIAL);
+}
+
+
+/*
+ * Try to open specified file with following names:
+ * ./name
+ * $(srctree)/name
+ * The latter is used when srctree is separate from objtree
+ * when compiling the kernel.
+ * Return NULL if file is not found.
+ */
+FILE *zconf_fopen(const char *name)
+{
+ char *env, fullname[PATH_MAX+1];
+ FILE *f;
+
+ f = fopen(name, "r");
+ if (!f && name != NULL && name[0] != '/') {
+ env = getenv(SRCTREE);
+ if (env) {
+ snprintf(fullname, sizeof(fullname),
+ "%s/%s", env, name);
+ f = fopen(fullname, "r");
+ }
+ }
+ return f;
+}
+
+void zconf_initscan(const char *name)
+{
+ yyin = zconf_fopen(name);
+ if (!yyin) {
+ fprintf(stderr, "can't find file %s\n", name);
+ exit(1);
+ }
+
+ current_buf = xmalloc(sizeof(*current_buf));
+ memset(current_buf, 0, sizeof(*current_buf));
+
+ current_file = file_lookup(name);
+ yylineno = 1;
+}
+
+void zconf_nextfile(const char *name)
+{
+ struct file *iter;
+ struct file *file = file_lookup(name);
+ struct buffer *buf = xmalloc(sizeof(*buf));
+ memset(buf, 0, sizeof(*buf));
+
+ current_buf->state = YY_CURRENT_BUFFER;
+ yyin = zconf_fopen(file->name);
+ if (!yyin) {
+ fprintf(stderr, "%s:%d: can't open file \"%s\"\n",
+ zconf_curname(), zconf_lineno(), file->name);
+ exit(1);
+ }
+ yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE));
+ buf->parent = current_buf;
+ current_buf = buf;
+
+ current_file->lineno = yylineno;
+ file->parent = current_file;
+
+ for (iter = current_file; iter; iter = iter->parent) {
+ if (!strcmp(iter->name, file->name)) {
+ fprintf(stderr,
+ "Recursive inclusion detected.\n"
+ "Inclusion path:\n"
+ " current file : %s\n", file->name);
+ iter = file;
+ do {
+ iter = iter->parent;
+ fprintf(stderr, " included from: %s:%d\n",
+ iter->name, iter->lineno - 1);
+ } while (strcmp(iter->name, file->name));
+ exit(1);
+ }
+ }
+
+ yylineno = 1;
+ current_file = file;
+}
+
+static void zconf_endfile(void)
+{
+ struct buffer *parent;
+
+ current_file = current_file->parent;
+ if (current_file)
+ yylineno = current_file->lineno;
+
+ parent = current_buf->parent;
+ if (parent) {
+ fclose(yyin);
+ yy_delete_buffer(YY_CURRENT_BUFFER);
+ yy_switch_to_buffer(parent->state);
+ }
+ free(current_buf);
+ current_buf = parent;
+}
+
+int zconf_lineno(void)
+{
+ return current_pos.lineno;
+}
+
+const char *zconf_curname(void)
+{
+ return current_pos.file ? current_pos.file->name : "<none>";
+}
Index: StarFive/create-6.1.31-3.8.2-host-limits-patch/linux-starfive-6.1.31-3.8.2-new/scripts/mod/modpost.c
===================================================================
--- StarFive/create-6.1.31-3.8.2-host-limits-patch/linux-starfive-6.1.31-3.8.2-new/scripts/mod/modpost.c (nonexistent)
+++ StarFive/create-6.1.31-3.8.2-host-limits-patch/linux-starfive-6.1.31-3.8.2-new/scripts/mod/modpost.c (revision 385)
@@ -0,0 +1,2407 @@
+/* Postprocess module symbol versions
+ *
+ * Copyright 2003 Kai Germaschewski
+ * Copyright 2002-2004 Rusty Russell, IBM Corporation
+ * Copyright 2006-2008 Sam Ravnborg
+ * Based in part on module-init-tools/depmod.c,file2alias
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ *
+ * Usage: modpost vmlinux module1.o module2.o ...
+ */
+
+#define _GNU_SOURCE
+#include <elf.h>
+#include <fnmatch.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <linux/limits.h>
+#include <stdbool.h>
+#include <errno.h>
+#include "modpost.h"
+#include "../../include/linux/license.h"
+
+/* Are we using CONFIG_MODVERSIONS? */
+static bool modversions;
+/* Is CONFIG_MODULE_SRCVERSION_ALL set? */
+static bool all_versions;
+/* If we are modposting external module set to 1 */
+static bool external_module;
+/* Only warn about unresolved symbols */
+static bool warn_unresolved;
+
+static int sec_mismatch_count;
+static bool sec_mismatch_warn_only = true;
+/* ignore missing files */
+static bool ignore_missing_files;
+/* If set to 1, only warn (instead of error) about missing ns imports */
+static bool allow_missing_ns_imports;
+
+static bool error_occurred;
+
+/*
+ * Cut off the warnings when there are too many. This typically occurs when
+ * vmlinux is missing. ('make modules' without building vmlinux.)
+ */
+#define MAX_UNRESOLVED_REPORTS 10
+static unsigned int nr_unresolved;
+
+/* In kernel, this size is defined in linux/module.h;
+ * here we use Elf_Addr instead of long for covering cross-compile
+ */
+
+#define MODULE_NAME_LEN (64 - sizeof(Elf_Addr))
+
+void __attribute__((format(printf, 2, 3)))
+modpost_log(enum loglevel loglevel, const char *fmt, ...)
+{
+ va_list arglist;
+
+ switch (loglevel) {
+ case LOG_WARN:
+ fprintf(stderr, "WARNING: ");
+ break;
+ case LOG_ERROR:
+ fprintf(stderr, "ERROR: ");
+ break;
+ case LOG_FATAL:
+ fprintf(stderr, "FATAL: ");
+ break;
+ default: /* invalid loglevel, ignore */
+ break;
+ }
+
+ fprintf(stderr, "modpost: ");
+
+ va_start(arglist, fmt);
+ vfprintf(stderr, fmt, arglist);
+ va_end(arglist);
+
+ if (loglevel == LOG_FATAL)
+ exit(1);
+ if (loglevel == LOG_ERROR)
+ error_occurred = true;
+}
+
+static inline bool strends(const char *str, const char *postfix)
+{
+ if (strlen(str) < strlen(postfix))
+ return false;
+
+ return strcmp(str + strlen(str) - strlen(postfix), postfix) == 0;
+}
+
+void *do_nofail(void *ptr, const char *expr)
+{
+ if (!ptr)
+ fatal("Memory allocation failure: %s.\n", expr);
+
+ return ptr;
+}
+
+char *read_text_file(const char *filename)
+{
+ struct stat st;
+ size_t nbytes;
+ int fd;
+ char *buf;
+
+ fd = open(filename, O_RDONLY);
+ if (fd < 0) {
+ perror(filename);
+ exit(1);
+ }
+
+ if (fstat(fd, &st) < 0) {
+ perror(filename);
+ exit(1);
+ }
+
+ buf = NOFAIL(malloc(st.st_size + 1));
+
+ nbytes = st.st_size;
+
+ while (nbytes) {
+ ssize_t bytes_read;
+
+ bytes_read = read(fd, buf, nbytes);
+ if (bytes_read < 0) {
+ perror(filename);
+ exit(1);
+ }
+
+ nbytes -= bytes_read;
+ }
+ buf[st.st_size] = '\0';
+
+ close(fd);
+
+ return buf;
+}
+
+char *get_line(char **stringp)
+{
+ char *orig = *stringp, *next;
+
+ /* do not return the unwanted extra line at EOF */
+ if (!orig || *orig == '\0')
+ return NULL;
+
+ /* don't use strsep here, it is not available everywhere */
+ next = strchr(orig, '\n');
+ if (next)
+ *next++ = '\0';
+
+ *stringp = next;
+
+ return orig;
+}
+
+/* A list of all modules we processed */
+LIST_HEAD(modules);
+
+static struct module *find_module(const char *modname)
+{
+ struct module *mod;
+
+ list_for_each_entry(mod, &modules, list) {
+ if (strcmp(mod->name, modname) == 0)
+ return mod;
+ }
+ return NULL;
+}
+
+static struct module *new_module(const char *name, size_t namelen)
+{
+ struct module *mod;
+
+ mod = NOFAIL(malloc(sizeof(*mod) + namelen + 1));
+ memset(mod, 0, sizeof(*mod));
+
+ INIT_LIST_HEAD(&mod->exported_symbols);
+ INIT_LIST_HEAD(&mod->unresolved_symbols);
+ INIT_LIST_HEAD(&mod->missing_namespaces);
+ INIT_LIST_HEAD(&mod->imported_namespaces);
+
+ memcpy(mod->name, name, namelen);
+ mod->name[namelen] = '\0';
+ mod->is_vmlinux = (strcmp(mod->name, "vmlinux") == 0);
+
+ /*
+ * Set mod->is_gpl_compatible to true by default. If MODULE_LICENSE()
+ * is missing, do not check the use for EXPORT_SYMBOL_GPL() becasue
+ * modpost will exit wiht error anyway.
+ */
+ mod->is_gpl_compatible = true;
+
+ list_add_tail(&mod->list, &modules);
+
+ return mod;
+}
+
+/* A hash of all exported symbols,
+ * struct symbol is also used for lists of unresolved symbols */
+
+#define SYMBOL_HASH_SIZE 1024
+
+struct symbol {
+ struct symbol *next;
+ struct list_head list; /* link to module::exported_symbols or module::unresolved_symbols */
+ struct module *module;
+ char *namespace;
+ unsigned int crc;
+ bool crc_valid;
+ bool weak;
+ bool is_gpl_only; /* exported by EXPORT_SYMBOL_GPL */
+ char name[];
+};
+
+static struct symbol *symbolhash[SYMBOL_HASH_SIZE];
+
+/* This is based on the hash algorithm from gdbm, via tdb */
+static inline unsigned int tdb_hash(const char *name)
+{
+ unsigned value; /* Used to compute the hash value. */
+ unsigned i; /* Used to cycle through random values. */
+
+ /* Set the initial value from the key size. */
+ for (value = 0x238F13AF * strlen(name), i = 0; name[i]; i++)
+ value = (value + (((unsigned char *)name)[i] << (i*5 % 24)));
+
+ return (1103515243 * value + 12345);
+}
+
+/**
+ * Allocate a new symbols for use in the hash of exported symbols or
+ * the list of unresolved symbols per module
+ **/
+static struct symbol *alloc_symbol(const char *name)
+{
+ struct symbol *s = NOFAIL(malloc(sizeof(*s) + strlen(name) + 1));
+
+ memset(s, 0, sizeof(*s));
+ strcpy(s->name, name);
+
+ return s;
+}
+
+/* For the hash of exported symbols */
+static void hash_add_symbol(struct symbol *sym)
+{
+ unsigned int hash;
+
+ hash = tdb_hash(sym->name) % SYMBOL_HASH_SIZE;
+ sym->next = symbolhash[hash];
+ symbolhash[hash] = sym;
+}
+
+static void sym_add_unresolved(const char *name, struct module *mod, bool weak)
+{
+ struct symbol *sym;
+
+ sym = alloc_symbol(name);
+ sym->weak = weak;
+
+ list_add_tail(&sym->list, &mod->unresolved_symbols);
+}
+
+static struct symbol *sym_find_with_module(const char *name, struct module *mod)
+{
+ struct symbol *s;
+
+ /* For our purposes, .foo matches foo. PPC64 needs this. */
+ if (name[0] == '.')
+ name++;
+
+ for (s = symbolhash[tdb_hash(name) % SYMBOL_HASH_SIZE]; s; s = s->next) {
+ if (strcmp(s->name, name) == 0 && (!mod || s->module == mod))
+ return s;
+ }
+ return NULL;
+}
+
+static struct symbol *find_symbol(const char *name)
+{
+ return sym_find_with_module(name, NULL);
+}
+
+struct namespace_list {
+ struct list_head list;
+ char namespace[];
+};
+
+static bool contains_namespace(struct list_head *head, const char *namespace)
+{
+ struct namespace_list *list;
+
+ list_for_each_entry(list, head, list) {
+ if (!strcmp(list->namespace, namespace))
+ return true;
+ }
+
+ return false;
+}
+
+static void add_namespace(struct list_head *head, const char *namespace)
+{
+ struct namespace_list *ns_entry;
+
+ if (!contains_namespace(head, namespace)) {
+ ns_entry = NOFAIL(malloc(sizeof(*ns_entry) +
+ strlen(namespace) + 1));
+ strcpy(ns_entry->namespace, namespace);
+ list_add_tail(&ns_entry->list, head);
+ }
+}
+
+static void *sym_get_data_by_offset(const struct elf_info *info,
+ unsigned int secindex, unsigned long offset)
+{
+ Elf_Shdr *sechdr = &info->sechdrs[secindex];
+
+ return (void *)info->hdr + sechdr->sh_offset + offset;
+}
+
+void *sym_get_data(const struct elf_info *info, const Elf_Sym *sym)
+{
+ return sym_get_data_by_offset(info, get_secindex(info, sym),
+ sym->st_value);
+}
+
+static const char *sech_name(const struct elf_info *info, Elf_Shdr *sechdr)
+{
+ return sym_get_data_by_offset(info, info->secindex_strings,
+ sechdr->sh_name);
+}
+
+static const char *sec_name(const struct elf_info *info, unsigned int secindex)
+{
+ /*
+ * If sym->st_shndx is a special section index, there is no
+ * corresponding section header.
+ * Return "" if the index is out of range of info->sechdrs[] array.
+ */
+ if (secindex >= info->num_sections)
+ return "";
+
+ return sech_name(info, &info->sechdrs[secindex]);
+}
+
+#define strstarts(str, prefix) (strncmp(str, prefix, strlen(prefix)) == 0)
+
+static void sym_update_namespace(const char *symname, const char *namespace)
+{
+ struct symbol *s = find_symbol(symname);
+
+ /*
+ * That symbol should have been created earlier and thus this is
+ * actually an assertion.
+ */
+ if (!s) {
+ error("Could not update namespace(%s) for symbol %s\n",
+ namespace, symname);
+ return;
+ }
+
+ free(s->namespace);
+ s->namespace = namespace[0] ? NOFAIL(strdup(namespace)) : NULL;
+}
+
+static struct symbol *sym_add_exported(const char *name, struct module *mod,
+ bool gpl_only)
+{
+ struct symbol *s = find_symbol(name);
+
+ if (s && (!external_module || s->module->is_vmlinux || s->module == mod)) {
+ error("%s: '%s' exported twice. Previous export was in %s%s\n",
+ mod->name, name, s->module->name,
+ s->module->is_vmlinux ? "" : ".ko");
+ }
+
+ s = alloc_symbol(name);
+ s->module = mod;
+ s->is_gpl_only = gpl_only;
+ list_add_tail(&s->list, &mod->exported_symbols);
+ hash_add_symbol(s);
+
+ return s;
+}
+
+static void sym_set_crc(struct symbol *sym, unsigned int crc)
+{
+ sym->crc = crc;
+ sym->crc_valid = true;
+}
+
+static void *grab_file(const char *filename, size_t *size)
+{
+ struct stat st;
+ void *map = MAP_FAILED;
+ int fd;
+
+ fd = open(filename, O_RDONLY);
+ if (fd < 0)
+ return NULL;
+ if (fstat(fd, &st))
+ goto failed;
+
+ *size = st.st_size;
+ map = mmap(NULL, *size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
+
+failed:
+ close(fd);
+ if (map == MAP_FAILED)
+ return NULL;
+ return map;
+}
+
+static void release_file(void *file, size_t size)
+{
+ munmap(file, size);
+}
+
+static int parse_elf(struct elf_info *info, const char *filename)
+{
+ unsigned int i;
+ Elf_Ehdr *hdr;
+ Elf_Shdr *sechdrs;
+ Elf_Sym *sym;
+ const char *secstrings;
+ unsigned int symtab_idx = ~0U, symtab_shndx_idx = ~0U;
+
+ hdr = grab_file(filename, &info->size);
+ if (!hdr) {
+ if (ignore_missing_files) {
+ fprintf(stderr, "%s: %s (ignored)\n", filename,
+ strerror(errno));
+ return 0;
+ }
+ perror(filename);
+ exit(1);
+ }
+ info->hdr = hdr;
+ if (info->size < sizeof(*hdr)) {
+ /* file too small, assume this is an empty .o file */
+ return 0;
+ }
+ /* Is this a valid ELF file? */
+ if ((hdr->e_ident[EI_MAG0] != ELFMAG0) ||
+ (hdr->e_ident[EI_MAG1] != ELFMAG1) ||
+ (hdr->e_ident[EI_MAG2] != ELFMAG2) ||
+ (hdr->e_ident[EI_MAG3] != ELFMAG3)) {
+ /* Not an ELF file - silently ignore it */
+ return 0;
+ }
+ /* Fix endianness in ELF header */
+ hdr->e_type = TO_NATIVE(hdr->e_type);
+ hdr->e_machine = TO_NATIVE(hdr->e_machine);
+ hdr->e_version = TO_NATIVE(hdr->e_version);
+ hdr->e_entry = TO_NATIVE(hdr->e_entry);
+ hdr->e_phoff = TO_NATIVE(hdr->e_phoff);
+ hdr->e_shoff = TO_NATIVE(hdr->e_shoff);
+ hdr->e_flags = TO_NATIVE(hdr->e_flags);
+ hdr->e_ehsize = TO_NATIVE(hdr->e_ehsize);
+ hdr->e_phentsize = TO_NATIVE(hdr->e_phentsize);
+ hdr->e_phnum = TO_NATIVE(hdr->e_phnum);
+ hdr->e_shentsize = TO_NATIVE(hdr->e_shentsize);
+ hdr->e_shnum = TO_NATIVE(hdr->e_shnum);
+ hdr->e_shstrndx = TO_NATIVE(hdr->e_shstrndx);
+ sechdrs = (void *)hdr + hdr->e_shoff;
+ info->sechdrs = sechdrs;
+
+ /* modpost only works for relocatable objects */
+ if (hdr->e_type != ET_REL)
+ fatal("%s: not relocatable object.", filename);
+
+ /* Check if file offset is correct */
+ if (hdr->e_shoff > info->size) {
+ fatal("section header offset=%lu in file '%s' is bigger than filesize=%zu\n",
+ (unsigned long)hdr->e_shoff, filename, info->size);
+ return 0;
+ }
+
+ if (hdr->e_shnum == SHN_UNDEF) {
+ /*
+ * There are more than 64k sections,
+ * read count from .sh_size.
+ */
+ info->num_sections = TO_NATIVE(sechdrs[0].sh_size);
+ }
+ else {
+ info->num_sections = hdr->e_shnum;
+ }
+ if (hdr->e_shstrndx == SHN_XINDEX) {
+ info->secindex_strings = TO_NATIVE(sechdrs[0].sh_link);
+ }
+ else {
+ info->secindex_strings = hdr->e_shstrndx;
+ }
+
+ /* Fix endianness in section headers */
+ for (i = 0; i < info->num_sections; i++) {
+ sechdrs[i].sh_name = TO_NATIVE(sechdrs[i].sh_name);
+ sechdrs[i].sh_type = TO_NATIVE(sechdrs[i].sh_type);
+ sechdrs[i].sh_flags = TO_NATIVE(sechdrs[i].sh_flags);
+ sechdrs[i].sh_addr = TO_NATIVE(sechdrs[i].sh_addr);
+ sechdrs[i].sh_offset = TO_NATIVE(sechdrs[i].sh_offset);
+ sechdrs[i].sh_size = TO_NATIVE(sechdrs[i].sh_size);
+ sechdrs[i].sh_link = TO_NATIVE(sechdrs[i].sh_link);
+ sechdrs[i].sh_info = TO_NATIVE(sechdrs[i].sh_info);
+ sechdrs[i].sh_addralign = TO_NATIVE(sechdrs[i].sh_addralign);
+ sechdrs[i].sh_entsize = TO_NATIVE(sechdrs[i].sh_entsize);
+ }
+ /* Find symbol table. */
+ secstrings = (void *)hdr + sechdrs[info->secindex_strings].sh_offset;
+ for (i = 1; i < info->num_sections; i++) {
+ const char *secname;
+ int nobits = sechdrs[i].sh_type == SHT_NOBITS;
+
+ if (!nobits && sechdrs[i].sh_offset > info->size) {
+ fatal("%s is truncated. sechdrs[i].sh_offset=%lu > "
+ "sizeof(*hrd)=%zu\n", filename,
+ (unsigned long)sechdrs[i].sh_offset,
+ sizeof(*hdr));
+ return 0;
+ }
+ secname = secstrings + sechdrs[i].sh_name;
+ if (strcmp(secname, ".modinfo") == 0) {
+ if (nobits)
+ fatal("%s has NOBITS .modinfo\n", filename);
+ info->modinfo = (void *)hdr + sechdrs[i].sh_offset;
+ info->modinfo_len = sechdrs[i].sh_size;
+ }
+
+ if (sechdrs[i].sh_type == SHT_SYMTAB) {
+ unsigned int sh_link_idx;
+ symtab_idx = i;
+ info->symtab_start = (void *)hdr +
+ sechdrs[i].sh_offset;
+ info->symtab_stop = (void *)hdr +
+ sechdrs[i].sh_offset + sechdrs[i].sh_size;
+ sh_link_idx = sechdrs[i].sh_link;
+ info->strtab = (void *)hdr +
+ sechdrs[sh_link_idx].sh_offset;
+ }
+
+ /* 32bit section no. table? ("more than 64k sections") */
+ if (sechdrs[i].sh_type == SHT_SYMTAB_SHNDX) {
+ symtab_shndx_idx = i;
+ info->symtab_shndx_start = (void *)hdr +
+ sechdrs[i].sh_offset;
+ info->symtab_shndx_stop = (void *)hdr +
+ sechdrs[i].sh_offset + sechdrs[i].sh_size;
+ }
+ }
+ if (!info->symtab_start)
+ fatal("%s has no symtab?\n", filename);
+
+ /* Fix endianness in symbols */
+ for (sym = info->symtab_start; sym < info->symtab_stop; sym++) {
+ sym->st_shndx = TO_NATIVE(sym->st_shndx);
+ sym->st_name = TO_NATIVE(sym->st_name);
+ sym->st_value = TO_NATIVE(sym->st_value);
+ sym->st_size = TO_NATIVE(sym->st_size);
+ }
+
+ if (symtab_shndx_idx != ~0U) {
+ Elf32_Word *p;
+ if (symtab_idx != sechdrs[symtab_shndx_idx].sh_link)
+ fatal("%s: SYMTAB_SHNDX has bad sh_link: %u!=%u\n",
+ filename, sechdrs[symtab_shndx_idx].sh_link,
+ symtab_idx);
+ /* Fix endianness */
+ for (p = info->symtab_shndx_start; p < info->symtab_shndx_stop;
+ p++)
+ *p = TO_NATIVE(*p);
+ }
+
+ return 1;
+}
+
+static void parse_elf_finish(struct elf_info *info)
+{
+ release_file(info->hdr, info->size);
+}
+
+static int ignore_undef_symbol(struct elf_info *info, const char *symname)
+{
+ /* ignore __this_module, it will be resolved shortly */
+ if (strcmp(symname, "__this_module") == 0)
+ return 1;
+ /* ignore global offset table */
+ if (strcmp(symname, "_GLOBAL_OFFSET_TABLE_") == 0)
+ return 1;
+ if (info->hdr->e_machine == EM_PPC)
+ /* Special register function linked on all modules during final link of .ko */
+ if (strstarts(symname, "_restgpr_") ||
+ strstarts(symname, "_savegpr_") ||
+ strstarts(symname, "_rest32gpr_") ||
+ strstarts(symname, "_save32gpr_") ||
+ strstarts(symname, "_restvr_") ||
+ strstarts(symname, "_savevr_"))
+ return 1;
+ if (info->hdr->e_machine == EM_PPC64)
+ /* Special register function linked on all modules during final link of .ko */
+ if (strstarts(symname, "_restgpr0_") ||
+ strstarts(symname, "_savegpr0_") ||
+ strstarts(symname, "_restvr_") ||
+ strstarts(symname, "_savevr_") ||
+ strcmp(symname, ".TOC.") == 0)
+ return 1;
+
+ if (info->hdr->e_machine == EM_S390)
+ /* Expoline thunks are linked on all kernel modules during final link of .ko */
+ if (strstarts(symname, "__s390_indirect_jump_r"))
+ return 1;
+ /* Do not ignore this symbol */
+ return 0;
+}
+
+static void handle_symbol(struct module *mod, struct elf_info *info,
+ const Elf_Sym *sym, const char *symname)
+{
+ switch (sym->st_shndx) {
+ case SHN_COMMON:
+ if (strstarts(symname, "__gnu_lto_")) {
+ /* Should warn here, but modpost runs before the linker */
+ } else
+ warn("\"%s\" [%s] is COMMON symbol\n", symname, mod->name);
+ break;
+ case SHN_UNDEF:
+ /* undefined symbol */
+ if (ELF_ST_BIND(sym->st_info) != STB_GLOBAL &&
+ ELF_ST_BIND(sym->st_info) != STB_WEAK)
+ break;
+ if (ignore_undef_symbol(info, symname))
+ break;
+ if (info->hdr->e_machine == EM_SPARC ||
+ info->hdr->e_machine == EM_SPARCV9) {
+ /* Ignore register directives. */
+ if (ELF_ST_TYPE(sym->st_info) == STT_SPARC_REGISTER)
+ break;
+ if (symname[0] == '.') {
+ char *munged = NOFAIL(strdup(symname));
+ munged[0] = '_';
+ munged[1] = toupper(munged[1]);
+ symname = munged;
+ }
+ }
+
+ sym_add_unresolved(symname, mod,
+ ELF_ST_BIND(sym->st_info) == STB_WEAK);
+ break;
+ default:
+ /* All exported symbols */
+ if (strstarts(symname, "__ksymtab_")) {
+ const char *name, *secname;
+
+ name = symname + strlen("__ksymtab_");
+ secname = sec_name(info, get_secindex(info, sym));
+
+ if (strstarts(secname, "___ksymtab_gpl+"))
+ sym_add_exported(name, mod, true);
+ else if (strstarts(secname, "___ksymtab+"))
+ sym_add_exported(name, mod, false);
+ }
+ if (strcmp(symname, "init_module") == 0)
+ mod->has_init = true;
+ if (strcmp(symname, "cleanup_module") == 0)
+ mod->has_cleanup = true;
+ break;
+ }
+}
+
+/**
+ * Parse tag=value strings from .modinfo section
+ **/
+static char *next_string(char *string, unsigned long *secsize)
+{
+ /* Skip non-zero chars */
+ while (string[0]) {
+ string++;
+ if ((*secsize)-- <= 1)
+ return NULL;
+ }
+
+ /* Skip any zero padding. */
+ while (!string[0]) {
+ string++;
+ if ((*secsize)-- <= 1)
+ return NULL;
+ }
+ return string;
+}
+
+static char *get_next_modinfo(struct elf_info *info, const char *tag,
+ char *prev)
+{
+ char *p;
+ unsigned int taglen = strlen(tag);
+ char *modinfo = info->modinfo;
+ unsigned long size = info->modinfo_len;
+
+ if (prev) {
+ size -= prev - modinfo;
+ modinfo = next_string(prev, &size);
+ }
+
+ for (p = modinfo; p; p = next_string(p, &size)) {
+ if (strncmp(p, tag, taglen) == 0 && p[taglen] == '=')
+ return p + taglen + 1;
+ }
+ return NULL;
+}
+
+static char *get_modinfo(struct elf_info *info, const char *tag)
+
+{
+ return get_next_modinfo(info, tag, NULL);
+}
+
+static const char *sym_name(struct elf_info *elf, Elf_Sym *sym)
+{
+ if (sym)
+ return elf->strtab + sym->st_name;
+ else
+ return "(unknown)";
+}
+
+/*
+ * Check whether the 'string' argument matches one of the 'patterns',
+ * an array of shell wildcard patterns (glob).
+ *
+ * Return true is there is a match.
+ */
+static bool match(const char *string, const char *const patterns[])
+{
+ const char *pattern;
+
+ while ((pattern = *patterns++)) {
+ if (!fnmatch(pattern, string, 0))
+ return true;
+ }
+
+ return false;
+}
+
+/* useful to pass patterns to match() directly */
+#define PATTERNS(...) \
+ ({ \
+ static const char *const patterns[] = {__VA_ARGS__, NULL}; \
+ patterns; \
+ })
+
+/* sections that we do not want to do full section mismatch check on */
+static const char *const section_white_list[] =
+{
+ ".comment*",
+ ".debug*",
+ ".zdebug*", /* Compressed debug sections. */
+ ".GCC.command.line", /* record-gcc-switches */
+ ".mdebug*", /* alpha, score, mips etc. */
+ ".pdr", /* alpha, score, mips etc. */
+ ".stab*",
+ ".note*",
+ ".got*",
+ ".toc*",
+ ".xt.prop", /* xtensa */
+ ".xt.lit", /* xtensa */
+ ".arcextmap*", /* arc */
+ ".gnu.linkonce.arcext*", /* arc : modules */
+ ".cmem*", /* EZchip */
+ ".fmt_slot*", /* EZchip */
+ ".gnu.lto*",
+ ".discard.*",
+ NULL
+};
+
+/*
+ * This is used to find sections missing the SHF_ALLOC flag.
+ * The cause of this is often a section specified in assembler
+ * without "ax" / "aw".
+ */
+static void check_section(const char *modname, struct elf_info *elf,
+ Elf_Shdr *sechdr)
+{
+ const char *sec = sech_name(elf, sechdr);
+
+ if (sechdr->sh_type == SHT_PROGBITS &&
+ !(sechdr->sh_flags & SHF_ALLOC) &&
+ !match(sec, section_white_list)) {
+ warn("%s (%s): unexpected non-allocatable section.\n"
+ "Did you forget to use \"ax\"/\"aw\" in a .S file?\n"
+ "Note that for example <linux/init.h> contains\n"
+ "section definitions for use in .S files.\n\n",
+ modname, sec);
+ }
+}
+
+
+
+#define ALL_INIT_DATA_SECTIONS \
+ ".init.setup", ".init.rodata", ".meminit.rodata", \
+ ".init.data", ".meminit.data"
+#define ALL_EXIT_DATA_SECTIONS \
+ ".exit.data", ".memexit.data"
+
+#define ALL_INIT_TEXT_SECTIONS \
+ ".init.text", ".meminit.text"
+#define ALL_EXIT_TEXT_SECTIONS \
+ ".exit.text", ".memexit.text"
+
+#define ALL_PCI_INIT_SECTIONS \
+ ".pci_fixup_early", ".pci_fixup_header", ".pci_fixup_final", \
+ ".pci_fixup_enable", ".pci_fixup_resume", \
+ ".pci_fixup_resume_early", ".pci_fixup_suspend"
+
+#define ALL_XXXINIT_SECTIONS MEM_INIT_SECTIONS
+#define ALL_XXXEXIT_SECTIONS MEM_EXIT_SECTIONS
+
+#define ALL_INIT_SECTIONS INIT_SECTIONS, ALL_XXXINIT_SECTIONS
+#define ALL_EXIT_SECTIONS EXIT_SECTIONS, ALL_XXXEXIT_SECTIONS
+
+#define DATA_SECTIONS ".data", ".data.rel"
+#define TEXT_SECTIONS ".text", ".text.unlikely", ".sched.text", \
+ ".kprobes.text", ".cpuidle.text", ".noinstr.text"
+#define OTHER_TEXT_SECTIONS ".ref.text", ".head.text", ".spinlock.text", \
+ ".fixup", ".entry.text", ".exception.text", ".text.*", \
+ ".coldtext", ".softirqentry.text"
+
+#define INIT_SECTIONS ".init.*"
+#define MEM_INIT_SECTIONS ".meminit.*"
+
+#define EXIT_SECTIONS ".exit.*"
+#define MEM_EXIT_SECTIONS ".memexit.*"
+
+#define ALL_TEXT_SECTIONS ALL_INIT_TEXT_SECTIONS, ALL_EXIT_TEXT_SECTIONS, \
+ TEXT_SECTIONS, OTHER_TEXT_SECTIONS
+
+/* init data sections */
+static const char *const init_data_sections[] =
+ { ALL_INIT_DATA_SECTIONS, NULL };
+
+/* all init sections */
+static const char *const init_sections[] = { ALL_INIT_SECTIONS, NULL };
+
+/* all text sections */
+static const char *const text_sections[] = { ALL_TEXT_SECTIONS, NULL };
+
+/* data section */
+static const char *const data_sections[] = { DATA_SECTIONS, NULL };
+
+static const char *const head_sections[] = { ".head.text*", NULL };
+static const char *const linker_symbols[] =
+ { "__init_begin", "_sinittext", "_einittext", NULL };
+static const char *const optim_symbols[] = { "*.constprop.*", NULL };
+
+enum mismatch {
+ TEXT_TO_ANY_INIT,
+ DATA_TO_ANY_INIT,
+ TEXT_TO_ANY_EXIT,
+ DATA_TO_ANY_EXIT,
+ XXXINIT_TO_SOME_INIT,
+ XXXEXIT_TO_SOME_EXIT,
+ ANY_INIT_TO_ANY_EXIT,
+ ANY_EXIT_TO_ANY_INIT,
+ EXPORT_TO_INIT_EXIT,
+ EXTABLE_TO_NON_TEXT,
+};
+
+/**
+ * Describe how to match sections on different criteria:
+ *
+ * @fromsec: Array of sections to be matched.
+ *
+ * @bad_tosec: Relocations applied to a section in @fromsec to a section in
+ * this array is forbidden (black-list). Can be empty.
+ *
+ * @good_tosec: Relocations applied to a section in @fromsec must be
+ * targeting sections in this array (white-list). Can be empty.
+ *
+ * @mismatch: Type of mismatch.
+ *
+ * @handler: Specific handler to call when a match is found. If NULL,
+ * default_mismatch_handler() will be called.
+ *
+ */
+struct sectioncheck {
+ const char *fromsec[20];
+ const char *bad_tosec[20];
+ const char *good_tosec[20];
+ enum mismatch mismatch;
+ void (*handler)(const char *modname, struct elf_info *elf,
+ const struct sectioncheck* const mismatch,
+ Elf_Rela *r, Elf_Sym *sym, const char *fromsec);
+
+};
+
+static void extable_mismatch_handler(const char *modname, struct elf_info *elf,
+ const struct sectioncheck* const mismatch,
+ Elf_Rela *r, Elf_Sym *sym,
+ const char *fromsec);
+
+static const struct sectioncheck sectioncheck[] = {
+/* Do not reference init/exit code/data from
+ * normal code and data
+ */
+{
+ .fromsec = { TEXT_SECTIONS, NULL },
+ .bad_tosec = { ALL_INIT_SECTIONS, NULL },
+ .mismatch = TEXT_TO_ANY_INIT,
+},
+{
+ .fromsec = { DATA_SECTIONS, NULL },
+ .bad_tosec = { ALL_XXXINIT_SECTIONS, NULL },
+ .mismatch = DATA_TO_ANY_INIT,
+},
+{
+ .fromsec = { DATA_SECTIONS, NULL },
+ .bad_tosec = { INIT_SECTIONS, NULL },
+ .mismatch = DATA_TO_ANY_INIT,
+},
+{
+ .fromsec = { TEXT_SECTIONS, NULL },
+ .bad_tosec = { ALL_EXIT_SECTIONS, NULL },
+ .mismatch = TEXT_TO_ANY_EXIT,
+},
+{
+ .fromsec = { DATA_SECTIONS, NULL },
+ .bad_tosec = { ALL_EXIT_SECTIONS, NULL },
+ .mismatch = DATA_TO_ANY_EXIT,
+},
+/* Do not reference init code/data from meminit code/data */
+{
+ .fromsec = { ALL_XXXINIT_SECTIONS, NULL },
+ .bad_tosec = { INIT_SECTIONS, NULL },
+ .mismatch = XXXINIT_TO_SOME_INIT,
+},
+/* Do not reference exit code/data from memexit code/data */
+{
+ .fromsec = { ALL_XXXEXIT_SECTIONS, NULL },
+ .bad_tosec = { EXIT_SECTIONS, NULL },
+ .mismatch = XXXEXIT_TO_SOME_EXIT,
+},
+/* Do not use exit code/data from init code */
+{
+ .fromsec = { ALL_INIT_SECTIONS, NULL },
+ .bad_tosec = { ALL_EXIT_SECTIONS, NULL },
+ .mismatch = ANY_INIT_TO_ANY_EXIT,
+},
+/* Do not use init code/data from exit code */
+{
+ .fromsec = { ALL_EXIT_SECTIONS, NULL },
+ .bad_tosec = { ALL_INIT_SECTIONS, NULL },
+ .mismatch = ANY_EXIT_TO_ANY_INIT,
+},
+{
+ .fromsec = { ALL_PCI_INIT_SECTIONS, NULL },
+ .bad_tosec = { INIT_SECTIONS, NULL },
+ .mismatch = ANY_INIT_TO_ANY_EXIT,
+},
+/* Do not export init/exit functions or data */
+{
+ .fromsec = { "___ksymtab*", NULL },
+ .bad_tosec = { INIT_SECTIONS, EXIT_SECTIONS, NULL },
+ .mismatch = EXPORT_TO_INIT_EXIT,
+},
+{
+ .fromsec = { "__ex_table", NULL },
+ /* If you're adding any new black-listed sections in here, consider
+ * adding a special 'printer' for them in scripts/check_extable.
+ */
+ .bad_tosec = { ".altinstr_replacement", NULL },
+ .good_tosec = {ALL_TEXT_SECTIONS , NULL},
+ .mismatch = EXTABLE_TO_NON_TEXT,
+ .handler = extable_mismatch_handler,
+}
+};
+
+static const struct sectioncheck *section_mismatch(
+ const char *fromsec, const char *tosec)
+{
+ int i;
+
+ /*
+ * The target section could be the SHT_NUL section when we're
+ * handling relocations to un-resolved symbols, trying to match it
+ * doesn't make much sense and causes build failures on parisc
+ * architectures.
+ */
+ if (*tosec == '\0')
+ return NULL;
+
+ for (i = 0; i < ARRAY_SIZE(sectioncheck); i++) {
+ const struct sectioncheck *check = §ioncheck[i];
+
+ if (match(fromsec, check->fromsec)) {
+ if (check->bad_tosec[0] && match(tosec, check->bad_tosec))
+ return check;
+ if (check->good_tosec[0] && !match(tosec, check->good_tosec))
+ return check;
+ }
+ }
+ return NULL;
+}
+
+/**
+ * Whitelist to allow certain references to pass with no warning.
+ *
+ * Pattern 1:
+ * If a module parameter is declared __initdata and permissions=0
+ * then this is legal despite the warning generated.
+ * We cannot see value of permissions here, so just ignore
+ * this pattern.
+ * The pattern is identified by:
+ * tosec = .init.data
+ * fromsec = .data*
+ * atsym =__param*
+ *
+ * Pattern 1a:
+ * module_param_call() ops can refer to __init set function if permissions=0
+ * The pattern is identified by:
+ * tosec = .init.text
+ * fromsec = .data*
+ * atsym = __param_ops_*
+ *
+ * Pattern 3:
+ * Whitelist all references from .head.text to any init section
+ *
+ * Pattern 4:
+ * Some symbols belong to init section but still it is ok to reference
+ * these from non-init sections as these symbols don't have any memory
+ * allocated for them and symbol address and value are same. So even
+ * if init section is freed, its ok to reference those symbols.
+ * For ex. symbols marking the init section boundaries.
+ * This pattern is identified by
+ * refsymname = __init_begin, _sinittext, _einittext
+ *
+ * Pattern 5:
+ * GCC may optimize static inlines when fed constant arg(s) resulting
+ * in functions like cpumask_empty() -- generating an associated symbol
+ * cpumask_empty.constprop.3 that appears in the audit. If the const that
+ * is passed in comes from __init, like say nmi_ipi_mask, we get a
+ * meaningless section warning. May need to add isra symbols too...
+ * This pattern is identified by
+ * tosec = init section
+ * fromsec = text section
+ * refsymname = *.constprop.*
+ *
+ * Pattern 6:
+ * Hide section mismatch warnings for ELF local symbols. The goal
+ * is to eliminate false positive modpost warnings caused by
+ * compiler-generated ELF local symbol names such as ".LANCHOR1".
+ * Autogenerated symbol names bypass modpost's "Pattern 2"
+ * whitelisting, which relies on pattern-matching against symbol
+ * names to work. (One situation where gcc can autogenerate ELF
+ * local symbols is when "-fsection-anchors" is used.)
+ **/
+static int secref_whitelist(const struct sectioncheck *mismatch,
+ const char *fromsec, const char *fromsym,
+ const char *tosec, const char *tosym)
+{
+ /* Check for pattern 1 */
+ if (match(tosec, init_data_sections) &&
+ match(fromsec, data_sections) &&
+ strstarts(fromsym, "__param"))
+ return 0;
+
+ /* Check for pattern 1a */
+ if (strcmp(tosec, ".init.text") == 0 &&
+ match(fromsec, data_sections) &&
+ strstarts(fromsym, "__param_ops_"))
+ return 0;
+
+ /* symbols in data sections that may refer to any init/exit sections */
+ if (match(fromsec, PATTERNS(DATA_SECTIONS)) &&
+ match(tosec, PATTERNS(ALL_INIT_SECTIONS, ALL_EXIT_SECTIONS)) &&
+ match(fromsym, PATTERNS("*_template", // scsi uses *_template a lot
+ "*_timer", // arm uses ops structures named _timer a lot
+ "*_sht", // scsi also used *_sht to some extent
+ "*_ops",
+ "*_probe",
+ "*_probe_one",
+ "*_console")))
+ return 0;
+
+ /* symbols in data sections that may refer to meminit/exit sections */
+ if (match(fromsec, PATTERNS(DATA_SECTIONS)) &&
+ match(tosec, PATTERNS(ALL_XXXINIT_SECTIONS, ALL_EXIT_SECTIONS)) &&
+ match(fromsym, PATTERNS("*driver")))
+ return 0;
+
+ /* Check for pattern 3 */
+ if (match(fromsec, head_sections) &&
+ match(tosec, init_sections))
+ return 0;
+
+ /* Check for pattern 4 */
+ if (match(tosym, linker_symbols))
+ return 0;
+
+ /* Check for pattern 5 */
+ if (match(fromsec, text_sections) &&
+ match(tosec, init_sections) &&
+ match(fromsym, optim_symbols))
+ return 0;
+
+ /* Check for pattern 6 */
+ if (strstarts(fromsym, ".L"))
+ return 0;
+
+ return 1;
+}
+
+static inline int is_arm_mapping_symbol(const char *str)
+{
+ return str[0] == '$' &&
+ (str[1] == 'a' || str[1] == 'd' || str[1] == 't' || str[1] == 'x')
+ && (str[2] == '\0' || str[2] == '.');
+}
+
+/*
+ * If there's no name there, ignore it; likewise, ignore it if it's
+ * one of the magic symbols emitted used by current ARM tools.
+ *
+ * Otherwise if find_symbols_between() returns those symbols, they'll
+ * fail the whitelist tests and cause lots of false alarms ... fixable
+ * only by merging __exit and __init sections into __text, bloating
+ * the kernel (which is especially evil on embedded platforms).
+ */
+static inline int is_valid_name(struct elf_info *elf, Elf_Sym *sym)
+{
+ const char *name = elf->strtab + sym->st_name;
+
+ if (!name || !strlen(name))
+ return 0;
+ return !is_arm_mapping_symbol(name);
+}
+
+/**
+ * Find symbol based on relocation record info.
+ * In some cases the symbol supplied is a valid symbol so
+ * return refsym. If st_name != 0 we assume this is a valid symbol.
+ * In other cases the symbol needs to be looked up in the symbol table
+ * based on section and address.
+ * **/
+static Elf_Sym *find_elf_symbol(struct elf_info *elf, Elf64_Sword addr,
+ Elf_Sym *relsym)
+{
+ Elf_Sym *sym;
+ Elf_Sym *near = NULL;
+ Elf64_Sword distance = 20;
+ Elf64_Sword d;
+ unsigned int relsym_secindex;
+
+ if (relsym->st_name != 0)
+ return relsym;
+
+ relsym_secindex = get_secindex(elf, relsym);
+ for (sym = elf->symtab_start; sym < elf->symtab_stop; sym++) {
+ if (get_secindex(elf, sym) != relsym_secindex)
+ continue;
+ if (ELF_ST_TYPE(sym->st_info) == STT_SECTION)
+ continue;
+ if (!is_valid_name(elf, sym))
+ continue;
+ if (sym->st_value == addr)
+ return sym;
+ /* Find a symbol nearby - addr are maybe negative */
+ d = sym->st_value - addr;
+ if (d < 0)
+ d = addr - sym->st_value;
+ if (d < distance) {
+ distance = d;
+ near = sym;
+ }
+ }
+ /* We need a close match */
+ if (distance < 20)
+ return near;
+ else
+ return NULL;
+}
+
+/*
+ * Find symbols before or equal addr and after addr - in the section sec.
+ * If we find two symbols with equal offset prefer one with a valid name.
+ * The ELF format may have a better way to detect what type of symbol
+ * it is, but this works for now.
+ **/
+static Elf_Sym *find_elf_symbol2(struct elf_info *elf, Elf_Addr addr,
+ const char *sec)
+{
+ Elf_Sym *sym;
+ Elf_Sym *near = NULL;
+ Elf_Addr distance = ~0;
+
+ for (sym = elf->symtab_start; sym < elf->symtab_stop; sym++) {
+ const char *symsec;
+
+ if (is_shndx_special(sym->st_shndx))
+ continue;
+ symsec = sec_name(elf, get_secindex(elf, sym));
+ if (strcmp(symsec, sec) != 0)
+ continue;
+ if (!is_valid_name(elf, sym))
+ continue;
+ if (sym->st_value <= addr && addr - sym->st_value <= distance) {
+ distance = addr - sym->st_value;
+ near = sym;
+ }
+ }
+ return near;
+}
+
+static int is_function(Elf_Sym *sym)
+{
+ if (sym)
+ return ELF_ST_TYPE(sym->st_info) == STT_FUNC;
+ else
+ return -1;
+}
+
+static inline void get_pretty_name(int is_func, const char** name, const char** name_p)
+{
+ switch (is_func) {
+ case 0: *name = "variable"; *name_p = ""; break;
+ case 1: *name = "function"; *name_p = "()"; break;
+ default: *name = "(unknown reference)"; *name_p = ""; break;
+ }
+}
+
+/*
+ * Print a warning about a section mismatch.
+ * Try to find symbols near it so user can find it.
+ * Check whitelist before warning - it may be a false positive.
+ */
+static void report_sec_mismatch(const char *modname,
+ const struct sectioncheck *mismatch,
+ const char *fromsec,
+ const char *fromsym,
+ const char *tosec, const char *tosym)
+{
+ sec_mismatch_count++;
+
+ switch (mismatch->mismatch) {
+ case TEXT_TO_ANY_INIT:
+ case DATA_TO_ANY_INIT:
+ case TEXT_TO_ANY_EXIT:
+ case DATA_TO_ANY_EXIT:
+ case XXXINIT_TO_SOME_INIT:
+ case XXXEXIT_TO_SOME_EXIT:
+ case ANY_INIT_TO_ANY_EXIT:
+ case ANY_EXIT_TO_ANY_INIT:
+ warn("%s: section mismatch in reference: %s (section: %s) -> %s (section: %s)\n",
+ modname, fromsym, fromsec, tosym, tosec);
+ break;
+ case EXPORT_TO_INIT_EXIT:
+ warn("%s: EXPORT_SYMBOL used for init/exit symbol: %s (section: %s)\n",
+ modname, tosym, tosec);
+ break;
+ case EXTABLE_TO_NON_TEXT:
+ fatal("There's a special handler for this mismatch type, we should never get here.\n");
+ break;
+ }
+}
+
+static void default_mismatch_handler(const char *modname, struct elf_info *elf,
+ const struct sectioncheck* const mismatch,
+ Elf_Rela *r, Elf_Sym *sym, const char *fromsec)
+{
+ const char *tosec;
+ Elf_Sym *to;
+ Elf_Sym *from;
+ const char *tosym;
+ const char *fromsym;
+
+ from = find_elf_symbol2(elf, r->r_offset, fromsec);
+ fromsym = sym_name(elf, from);
+
+ tosec = sec_name(elf, get_secindex(elf, sym));
+ to = find_elf_symbol(elf, r->r_addend, sym);
+ tosym = sym_name(elf, to);
+
+ /* check whitelist - we may ignore it */
+ if (secref_whitelist(mismatch,
+ fromsec, fromsym, tosec, tosym)) {
+ report_sec_mismatch(modname, mismatch,
+ fromsec, fromsym, tosec, tosym);
+ }
+}
+
+static int is_executable_section(struct elf_info* elf, unsigned int section_index)
+{
+ if (section_index > elf->num_sections)
+ fatal("section_index is outside elf->num_sections!\n");
+
+ return ((elf->sechdrs[section_index].sh_flags & SHF_EXECINSTR) == SHF_EXECINSTR);
+}
+
+/*
+ * We rely on a gross hack in section_rel[a]() calling find_extable_entry_size()
+ * to know the sizeof(struct exception_table_entry) for the target architecture.
+ */
+static unsigned int extable_entry_size = 0;
+static void find_extable_entry_size(const char* const sec, const Elf_Rela* r)
+{
+ /*
+ * If we're currently checking the second relocation within __ex_table,
+ * that relocation offset tells us the offsetof(struct
+ * exception_table_entry, fixup) which is equal to sizeof(struct
+ * exception_table_entry) divided by two. We use that to our advantage
+ * since there's no portable way to get that size as every architecture
+ * seems to go with different sized types. Not pretty but better than
+ * hard-coding the size for every architecture..
+ */
+ if (!extable_entry_size)
+ extable_entry_size = r->r_offset * 2;
+}
+
+static inline bool is_extable_fault_address(Elf_Rela *r)
+{
+ /*
+ * extable_entry_size is only discovered after we've handled the
+ * _second_ relocation in __ex_table, so only abort when we're not
+ * handling the first reloc and extable_entry_size is zero.
+ */
+ if (r->r_offset && extable_entry_size == 0)
+ fatal("extable_entry size hasn't been discovered!\n");
+
+ return ((r->r_offset == 0) ||
+ (r->r_offset % extable_entry_size == 0));
+}
+
+#define is_second_extable_reloc(Start, Cur, Sec) \
+ (((Cur) == (Start) + 1) && (strcmp("__ex_table", (Sec)) == 0))
+
+static void report_extable_warnings(const char* modname, struct elf_info* elf,
+ const struct sectioncheck* const mismatch,
+ Elf_Rela* r, Elf_Sym* sym,
+ const char* fromsec, const char* tosec)
+{
+ Elf_Sym* fromsym = find_elf_symbol2(elf, r->r_offset, fromsec);
+ const char* fromsym_name = sym_name(elf, fromsym);
+ Elf_Sym* tosym = find_elf_symbol(elf, r->r_addend, sym);
+ const char* tosym_name = sym_name(elf, tosym);
+ const char* from_pretty_name;
+ const char* from_pretty_name_p;
+ const char* to_pretty_name;
+ const char* to_pretty_name_p;
+
+ get_pretty_name(is_function(fromsym),
+ &from_pretty_name, &from_pretty_name_p);
+ get_pretty_name(is_function(tosym),
+ &to_pretty_name, &to_pretty_name_p);
+
+ warn("%s(%s+0x%lx): Section mismatch in reference"
+ " from the %s %s%s to the %s %s:%s%s\n",
+ modname, fromsec, (long)r->r_offset, from_pretty_name,
+ fromsym_name, from_pretty_name_p,
+ to_pretty_name, tosec, tosym_name, to_pretty_name_p);
+
+ if (!match(tosec, mismatch->bad_tosec) &&
+ is_executable_section(elf, get_secindex(elf, sym)))
+ fprintf(stderr,
+ "The relocation at %s+0x%lx references\n"
+ "section \"%s\" which is not in the list of\n"
+ "authorized sections. If you're adding a new section\n"
+ "and/or if this reference is valid, add \"%s\" to the\n"
+ "list of authorized sections to jump to on fault.\n"
+ "This can be achieved by adding \"%s\" to \n"
+ "OTHER_TEXT_SECTIONS in scripts/mod/modpost.c.\n",
+ fromsec, (long)r->r_offset, tosec, tosec, tosec);
+}
+
+static void extable_mismatch_handler(const char* modname, struct elf_info *elf,
+ const struct sectioncheck* const mismatch,
+ Elf_Rela* r, Elf_Sym* sym,
+ const char *fromsec)
+{
+ const char* tosec = sec_name(elf, get_secindex(elf, sym));
+
+ sec_mismatch_count++;
+
+ report_extable_warnings(modname, elf, mismatch, r, sym, fromsec, tosec);
+
+ if (match(tosec, mismatch->bad_tosec))
+ fatal("The relocation at %s+0x%lx references\n"
+ "section \"%s\" which is black-listed.\n"
+ "Something is seriously wrong and should be fixed.\n"
+ "You might get more information about where this is\n"
+ "coming from by using scripts/check_extable.sh %s\n",
+ fromsec, (long)r->r_offset, tosec, modname);
+ else if (!is_executable_section(elf, get_secindex(elf, sym))) {
+ if (is_extable_fault_address(r))
+ fatal("The relocation at %s+0x%lx references\n"
+ "section \"%s\" which is not executable, IOW\n"
+ "it is not possible for the kernel to fault\n"
+ "at that address. Something is seriously wrong\n"
+ "and should be fixed.\n",
+ fromsec, (long)r->r_offset, tosec);
+ else
+ fatal("The relocation at %s+0x%lx references\n"
+ "section \"%s\" which is not executable, IOW\n"
+ "the kernel will fault if it ever tries to\n"
+ "jump to it. Something is seriously wrong\n"
+ "and should be fixed.\n",
+ fromsec, (long)r->r_offset, tosec);
+ }
+}
+
+static void check_section_mismatch(const char *modname, struct elf_info *elf,
+ Elf_Rela *r, Elf_Sym *sym, const char *fromsec)
+{
+ const char *tosec = sec_name(elf, get_secindex(elf, sym));
+ const struct sectioncheck *mismatch = section_mismatch(fromsec, tosec);
+
+ if (mismatch) {
+ if (mismatch->handler)
+ mismatch->handler(modname, elf, mismatch,
+ r, sym, fromsec);
+ else
+ default_mismatch_handler(modname, elf, mismatch,
+ r, sym, fromsec);
+ }
+}
+
+static unsigned int *reloc_location(struct elf_info *elf,
+ Elf_Shdr *sechdr, Elf_Rela *r)
+{
+ return sym_get_data_by_offset(elf, sechdr->sh_info, r->r_offset);
+}
+
+static int addend_386_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r)
+{
+ unsigned int r_typ = ELF_R_TYPE(r->r_info);
+ unsigned int *location = reloc_location(elf, sechdr, r);
+
+ switch (r_typ) {
+ case R_386_32:
+ r->r_addend = TO_NATIVE(*location);
+ break;
+ case R_386_PC32:
+ r->r_addend = TO_NATIVE(*location) + 4;
+ break;
+ }
+ return 0;
+}
+
+#ifndef R_ARM_CALL
+#define R_ARM_CALL 28
+#endif
+#ifndef R_ARM_JUMP24
+#define R_ARM_JUMP24 29
+#endif
+
+#ifndef R_ARM_THM_CALL
+#define R_ARM_THM_CALL 10
+#endif
+#ifndef R_ARM_THM_JUMP24
+#define R_ARM_THM_JUMP24 30
+#endif
+#ifndef R_ARM_THM_JUMP19
+#define R_ARM_THM_JUMP19 51
+#endif
+
+static int addend_arm_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r)
+{
+ unsigned int r_typ = ELF_R_TYPE(r->r_info);
+
+ switch (r_typ) {
+ case R_ARM_ABS32:
+ /* From ARM ABI: (S + A) | T */
+ r->r_addend = (int)(long)
+ (elf->symtab_start + ELF_R_SYM(r->r_info));
+ break;
+ case R_ARM_PC24:
+ case R_ARM_CALL:
+ case R_ARM_JUMP24:
+ case R_ARM_THM_CALL:
+ case R_ARM_THM_JUMP24:
+ case R_ARM_THM_JUMP19:
+ /* From ARM ABI: ((S + A) | T) - P */
+ r->r_addend = (int)(long)(elf->hdr +
+ sechdr->sh_offset +
+ (r->r_offset - sechdr->sh_addr));
+ break;
+ default:
+ return 1;
+ }
+ return 0;
+}
+
+static int addend_mips_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r)
+{
+ unsigned int r_typ = ELF_R_TYPE(r->r_info);
+ unsigned int *location = reloc_location(elf, sechdr, r);
+ unsigned int inst;
+
+ if (r_typ == R_MIPS_HI16)
+ return 1; /* skip this */
+ inst = TO_NATIVE(*location);
+ switch (r_typ) {
+ case R_MIPS_LO16:
+ r->r_addend = inst & 0xffff;
+ break;
+ case R_MIPS_26:
+ r->r_addend = (inst & 0x03ffffff) << 2;
+ break;
+ case R_MIPS_32:
+ r->r_addend = inst;
+ break;
+ }
+ return 0;
+}
+
+#ifndef EM_RISCV
+#define EM_RISCV 243
+#endif
+
+#ifndef R_RISCV_SUB32
+#define R_RISCV_SUB32 39
+#endif
+
+static void section_rela(const char *modname, struct elf_info *elf,
+ Elf_Shdr *sechdr)
+{
+ Elf_Sym *sym;
+ Elf_Rela *rela;
+ Elf_Rela r;
+ unsigned int r_sym;
+ const char *fromsec;
+
+ Elf_Rela *start = (void *)elf->hdr + sechdr->sh_offset;
+ Elf_Rela *stop = (void *)start + sechdr->sh_size;
+
+ fromsec = sec_name(elf, sechdr->sh_info);
+ /* if from section (name) is know good then skip it */
+ if (match(fromsec, section_white_list))
+ return;
+
+ for (rela = start; rela < stop; rela++) {
+ r.r_offset = TO_NATIVE(rela->r_offset);
+#if KERNEL_ELFCLASS == ELFCLASS64
+ if (elf->hdr->e_machine == EM_MIPS) {
+ unsigned int r_typ;
+ r_sym = ELF64_MIPS_R_SYM(rela->r_info);
+ r_sym = TO_NATIVE(r_sym);
+ r_typ = ELF64_MIPS_R_TYPE(rela->r_info);
+ r.r_info = ELF64_R_INFO(r_sym, r_typ);
+ } else {
+ r.r_info = TO_NATIVE(rela->r_info);
+ r_sym = ELF_R_SYM(r.r_info);
+ }
+#else
+ r.r_info = TO_NATIVE(rela->r_info);
+ r_sym = ELF_R_SYM(r.r_info);
+#endif
+ r.r_addend = TO_NATIVE(rela->r_addend);
+ switch (elf->hdr->e_machine) {
+ case EM_RISCV:
+ if (!strcmp("__ex_table", fromsec) &&
+ ELF_R_TYPE(r.r_info) == R_RISCV_SUB32)
+ continue;
+ break;
+ }
+ sym = elf->symtab_start + r_sym;
+ /* Skip special sections */
+ if (is_shndx_special(sym->st_shndx))
+ continue;
+ if (is_second_extable_reloc(start, rela, fromsec))
+ find_extable_entry_size(fromsec, &r);
+ check_section_mismatch(modname, elf, &r, sym, fromsec);
+ }
+}
+
+static void section_rel(const char *modname, struct elf_info *elf,
+ Elf_Shdr *sechdr)
+{
+ Elf_Sym *sym;
+ Elf_Rel *rel;
+ Elf_Rela r;
+ unsigned int r_sym;
+ const char *fromsec;
+
+ Elf_Rel *start = (void *)elf->hdr + sechdr->sh_offset;
+ Elf_Rel *stop = (void *)start + sechdr->sh_size;
+
+ fromsec = sec_name(elf, sechdr->sh_info);
+ /* if from section (name) is know good then skip it */
+ if (match(fromsec, section_white_list))
+ return;
+
+ for (rel = start; rel < stop; rel++) {
+ r.r_offset = TO_NATIVE(rel->r_offset);
+#if KERNEL_ELFCLASS == ELFCLASS64
+ if (elf->hdr->e_machine == EM_MIPS) {
+ unsigned int r_typ;
+ r_sym = ELF64_MIPS_R_SYM(rel->r_info);
+ r_sym = TO_NATIVE(r_sym);
+ r_typ = ELF64_MIPS_R_TYPE(rel->r_info);
+ r.r_info = ELF64_R_INFO(r_sym, r_typ);
+ } else {
+ r.r_info = TO_NATIVE(rel->r_info);
+ r_sym = ELF_R_SYM(r.r_info);
+ }
+#else
+ r.r_info = TO_NATIVE(rel->r_info);
+ r_sym = ELF_R_SYM(r.r_info);
+#endif
+ r.r_addend = 0;
+ switch (elf->hdr->e_machine) {
+ case EM_386:
+ if (addend_386_rel(elf, sechdr, &r))
+ continue;
+ break;
+ case EM_ARM:
+ if (addend_arm_rel(elf, sechdr, &r))
+ continue;
+ break;
+ case EM_MIPS:
+ if (addend_mips_rel(elf, sechdr, &r))
+ continue;
+ break;
+ }
+ sym = elf->symtab_start + r_sym;
+ /* Skip special sections */
+ if (is_shndx_special(sym->st_shndx))
+ continue;
+ if (is_second_extable_reloc(start, rel, fromsec))
+ find_extable_entry_size(fromsec, &r);
+ check_section_mismatch(modname, elf, &r, sym, fromsec);
+ }
+}
+
+/**
+ * A module includes a number of sections that are discarded
+ * either when loaded or when used as built-in.
+ * For loaded modules all functions marked __init and all data
+ * marked __initdata will be discarded when the module has been initialized.
+ * Likewise for modules used built-in the sections marked __exit
+ * are discarded because __exit marked function are supposed to be called
+ * only when a module is unloaded which never happens for built-in modules.
+ * The check_sec_ref() function traverses all relocation records
+ * to find all references to a section that reference a section that will
+ * be discarded and warns about it.
+ **/
+static void check_sec_ref(const char *modname, struct elf_info *elf)
+{
+ int i;
+ Elf_Shdr *sechdrs = elf->sechdrs;
+
+ /* Walk through all sections */
+ for (i = 0; i < elf->num_sections; i++) {
+ check_section(modname, elf, &elf->sechdrs[i]);
+ /* We want to process only relocation sections and not .init */
+ if (sechdrs[i].sh_type == SHT_RELA)
+ section_rela(modname, elf, &elf->sechdrs[i]);
+ else if (sechdrs[i].sh_type == SHT_REL)
+ section_rel(modname, elf, &elf->sechdrs[i]);
+ }
+}
+
+static char *remove_dot(char *s)
+{
+ size_t n = strcspn(s, ".");
+
+ if (n && s[n]) {
+ size_t m = strspn(s + n + 1, "0123456789");
+ if (m && (s[n + m + 1] == '.' || s[n + m + 1] == 0))
+ s[n] = 0;
+ }
+ return s;
+}
+
+/*
+ * The CRCs are recorded in .*.cmd files in the form of:
+ * #SYMVER <name> <crc>
+ */
+static void extract_crcs_for_object(const char *object, struct module *mod)
+{
+ char cmd_file[PATH_MAX];
+ char *buf, *p;
+ const char *base;
+ int dirlen, ret;
+
+ base = strrchr(object, '/');
+ if (base) {
+ base++;
+ dirlen = base - object;
+ } else {
+ dirlen = 0;
+ base = object;
+ }
+
+ ret = snprintf(cmd_file, sizeof(cmd_file), "%.*s.%s.cmd",
+ dirlen, object, base);
+ if (ret >= sizeof(cmd_file)) {
+ error("%s: too long path was truncated\n", cmd_file);
+ return;
+ }
+
+ buf = read_text_file(cmd_file);
+ p = buf;
+
+ while ((p = strstr(p, "\n#SYMVER "))) {
+ char *name;
+ size_t namelen;
+ unsigned int crc;
+ struct symbol *sym;
+
+ name = p + strlen("\n#SYMVER ");
+
+ p = strchr(name, ' ');
+ if (!p)
+ break;
+
+ namelen = p - name;
+ p++;
+
+ if (!isdigit(*p))
+ continue; /* skip this line */
+
+ crc = strtoul(p, &p, 0);
+ if (*p != '\n')
+ continue; /* skip this line */
+
+ name[namelen] = '\0';
+
+ /*
+ * sym_find_with_module() may return NULL here.
+ * It typically occurs when CONFIG_TRIM_UNUSED_KSYMS=y.
+ * Since commit e1327a127703, genksyms calculates CRCs of all
+ * symbols, including trimmed ones. Ignore orphan CRCs.
+ */
+ sym = sym_find_with_module(name, mod);
+ if (sym)
+ sym_set_crc(sym, crc);
+ }
+
+ free(buf);
+}
+
+/*
+ * The symbol versions (CRC) are recorded in the .*.cmd files.
+ * Parse them to retrieve CRCs for the current module.
+ */
+static void mod_set_crcs(struct module *mod)
+{
+ char objlist[PATH_MAX];
+ char *buf, *p, *obj;
+ int ret;
+
+ if (mod->is_vmlinux) {
+ strcpy(objlist, ".vmlinux.objs");
+ } else {
+ /* objects for a module are listed in the *.mod file. */
+ ret = snprintf(objlist, sizeof(objlist), "%s.mod", mod->name);
+ if (ret >= sizeof(objlist)) {
+ error("%s: too long path was truncated\n", objlist);
+ return;
+ }
+ }
+
+ buf = read_text_file(objlist);
+ p = buf;
+
+ while ((obj = strsep(&p, "\n")) && obj[0])
+ extract_crcs_for_object(obj, mod);
+
+ free(buf);
+}
+
+static void read_symbols(const char *modname)
+{
+ const char *symname;
+ char *version;
+ char *license;
+ char *namespace;
+ struct module *mod;
+ struct elf_info info = { };
+ Elf_Sym *sym;
+
+ if (!parse_elf(&info, modname))
+ return;
+
+ if (!strends(modname, ".o")) {
+ error("%s: filename must be suffixed with .o\n", modname);
+ return;
+ }
+
+ /* strip trailing .o */
+ mod = new_module(modname, strlen(modname) - strlen(".o"));
+
+ if (!mod->is_vmlinux) {
+ license = get_modinfo(&info, "license");
+ if (!license)
+ error("missing MODULE_LICENSE() in %s\n", modname);
+ while (license) {
+ if (!license_is_gpl_compatible(license)) {
+ mod->is_gpl_compatible = false;
+ break;
+ }
+ license = get_next_modinfo(&info, "license", license);
+ }
+
+ namespace = get_modinfo(&info, "import_ns");
+ while (namespace) {
+ add_namespace(&mod->imported_namespaces, namespace);
+ namespace = get_next_modinfo(&info, "import_ns",
+ namespace);
+ }
+ }
+
+ for (sym = info.symtab_start; sym < info.symtab_stop; sym++) {
+ symname = remove_dot(info.strtab + sym->st_name);
+
+ handle_symbol(mod, &info, sym, symname);
+ handle_moddevtable(mod, &info, sym, symname);
+ }
+
+ for (sym = info.symtab_start; sym < info.symtab_stop; sym++) {
+ symname = remove_dot(info.strtab + sym->st_name);
+
+ /* Apply symbol namespaces from __kstrtabns_<symbol> entries. */
+ if (strstarts(symname, "__kstrtabns_"))
+ sym_update_namespace(symname + strlen("__kstrtabns_"),
+ sym_get_data(&info, sym));
+ }
+
+ check_sec_ref(modname, &info);
+
+ if (!mod->is_vmlinux) {
+ version = get_modinfo(&info, "version");
+ if (version || all_versions)
+ get_src_version(mod->name, mod->srcversion,
+ sizeof(mod->srcversion) - 1);
+ }
+
+ parse_elf_finish(&info);
+
+ if (modversions) {
+ /*
+ * Our trick to get versioning for module struct etc. - it's
+ * never passed as an argument to an exported function, so
+ * the automatic versioning doesn't pick it up, but it's really
+ * important anyhow.
+ */
+ sym_add_unresolved("module_layout", mod, false);
+
+ mod_set_crcs(mod);
+ }
+}
+
+static void read_symbols_from_files(const char *filename)
+{
+ FILE *in = stdin;
+ char fname[PATH_MAX];
+
+ if (strcmp(filename, "-") != 0) {
+ in = fopen(filename, "r");
+ if (!in)
+ fatal("Can't open filenames file %s: %m", filename);
+ }
+
+ while (fgets(fname, PATH_MAX, in) != NULL) {
+ if (strends(fname, "\n"))
+ fname[strlen(fname)-1] = '\0';
+ read_symbols(fname);
+ }
+
+ if (in != stdin)
+ fclose(in);
+}
+
+#define SZ 500
+
+/* We first write the generated file into memory using the
+ * following helper, then compare to the file on disk and
+ * only update the later if anything changed */
+
+void __attribute__((format(printf, 2, 3))) buf_printf(struct buffer *buf,
+ const char *fmt, ...)
+{
+ char tmp[SZ];
+ int len;
+ va_list ap;
+
+ va_start(ap, fmt);
+ len = vsnprintf(tmp, SZ, fmt, ap);
+ buf_write(buf, tmp, len);
+ va_end(ap);
+}
+
+void buf_write(struct buffer *buf, const char *s, int len)
+{
+ if (buf->size - buf->pos < len) {
+ buf->size += len + SZ;
+ buf->p = NOFAIL(realloc(buf->p, buf->size));
+ }
+ strncpy(buf->p + buf->pos, s, len);
+ buf->pos += len;
+}
+
+static void check_exports(struct module *mod)
+{
+ struct symbol *s, *exp;
+
+ list_for_each_entry(s, &mod->unresolved_symbols, list) {
+ const char *basename;
+ exp = find_symbol(s->name);
+ if (!exp) {
+ if (!s->weak && nr_unresolved++ < MAX_UNRESOLVED_REPORTS)
+ modpost_log(warn_unresolved ? LOG_WARN : LOG_ERROR,
+ "\"%s\" [%s.ko] undefined!\n",
+ s->name, mod->name);
+ continue;
+ }
+ if (exp->module == mod) {
+ error("\"%s\" [%s.ko] was exported without definition\n",
+ s->name, mod->name);
+ continue;
+ }
+
+ s->module = exp->module;
+ s->crc_valid = exp->crc_valid;
+ s->crc = exp->crc;
+
+ basename = strrchr(mod->name, '/');
+ if (basename)
+ basename++;
+ else
+ basename = mod->name;
+
+ if (exp->namespace &&
+ !contains_namespace(&mod->imported_namespaces, exp->namespace)) {
+ modpost_log(allow_missing_ns_imports ? LOG_WARN : LOG_ERROR,
+ "module %s uses symbol %s from namespace %s, but does not import it.\n",
+ basename, exp->name, exp->namespace);
+ add_namespace(&mod->missing_namespaces, exp->namespace);
+ }
+
+ if (!mod->is_gpl_compatible && exp->is_gpl_only)
+ error("GPL-incompatible module %s.ko uses GPL-only symbol '%s'\n",
+ basename, exp->name);
+ }
+}
+
+static void check_modname_len(struct module *mod)
+{
+ const char *mod_name;
+
+ mod_name = strrchr(mod->name, '/');
+ if (mod_name == NULL)
+ mod_name = mod->name;
+ else
+ mod_name++;
+ if (strlen(mod_name) >= MODULE_NAME_LEN)
+ error("module name is too long [%s.ko]\n", mod->name);
+}
+
+/**
+ * Header for the generated file
+ **/
+static void add_header(struct buffer *b, struct module *mod)
+{
+ buf_printf(b, "#include <linux/module.h>\n");
+ /*
+ * Include build-salt.h after module.h in order to
+ * inherit the definitions.
+ */
+ buf_printf(b, "#define INCLUDE_VERMAGIC\n");
+ buf_printf(b, "#include <linux/build-salt.h>\n");
+ buf_printf(b, "#include <linux/elfnote-lto.h>\n");
+ buf_printf(b, "#include <linux/export-internal.h>\n");
+ buf_printf(b, "#include <linux/vermagic.h>\n");
+ buf_printf(b, "#include <linux/compiler.h>\n");
+ buf_printf(b, "\n");
+ buf_printf(b, "BUILD_SALT;\n");
+ buf_printf(b, "BUILD_LTO_INFO;\n");
+ buf_printf(b, "\n");
+ buf_printf(b, "MODULE_INFO(vermagic, VERMAGIC_STRING);\n");
+ buf_printf(b, "MODULE_INFO(name, KBUILD_MODNAME);\n");
+ buf_printf(b, "\n");
+ buf_printf(b, "__visible struct module __this_module\n");
+ buf_printf(b, "__section(\".gnu.linkonce.this_module\") = {\n");
+ buf_printf(b, "\t.name = KBUILD_MODNAME,\n");
+ if (mod->has_init)
+ buf_printf(b, "\t.init = init_module,\n");
+ if (mod->has_cleanup)
+ buf_printf(b, "#ifdef CONFIG_MODULE_UNLOAD\n"
+ "\t.exit = cleanup_module,\n"
+ "#endif\n");
+ buf_printf(b, "\t.arch = MODULE_ARCH_INIT,\n");
+ buf_printf(b, "};\n");
+
+ if (!external_module)
+ buf_printf(b, "\nMODULE_INFO(intree, \"Y\");\n");
+
+ buf_printf(b,
+ "\n"
+ "#ifdef CONFIG_RETPOLINE\n"
+ "MODULE_INFO(retpoline, \"Y\");\n"
+ "#endif\n");
+
+ if (strstarts(mod->name, "drivers/staging"))
+ buf_printf(b, "\nMODULE_INFO(staging, \"Y\");\n");
+
+ if (strstarts(mod->name, "tools/testing"))
+ buf_printf(b, "\nMODULE_INFO(test, \"Y\");\n");
+}
+
+static void add_exported_symbols(struct buffer *buf, struct module *mod)
+{
+ struct symbol *sym;
+
+ if (!modversions)
+ return;
+
+ /* record CRCs for exported symbols */
+ buf_printf(buf, "\n");
+ list_for_each_entry(sym, &mod->exported_symbols, list) {
+ if (!sym->crc_valid)
+ warn("EXPORT symbol \"%s\" [%s%s] version generation failed, symbol will not be versioned.\n"
+ "Is \"%s\" prototyped in <asm/asm-prototypes.h>?\n",
+ sym->name, mod->name, mod->is_vmlinux ? "" : ".ko",
+ sym->name);
+
+ buf_printf(buf, "SYMBOL_CRC(%s, 0x%08x, \"%s\");\n",
+ sym->name, sym->crc, sym->is_gpl_only ? "_gpl" : "");
+ }
+}
+
+/**
+ * Record CRCs for unresolved symbols
+ **/
+static void add_versions(struct buffer *b, struct module *mod)
+{
+ struct symbol *s;
+
+ if (!modversions)
+ return;
+
+ buf_printf(b, "\n");
+ buf_printf(b, "static const struct modversion_info ____versions[]\n");
+ buf_printf(b, "__used __section(\"__versions\") = {\n");
+
+ list_for_each_entry(s, &mod->unresolved_symbols, list) {
+ if (!s->module)
+ continue;
+ if (!s->crc_valid) {
+ warn("\"%s\" [%s.ko] has no CRC!\n",
+ s->name, mod->name);
+ continue;
+ }
+ if (strlen(s->name) >= MODULE_NAME_LEN) {
+ error("too long symbol \"%s\" [%s.ko]\n",
+ s->name, mod->name);
+ break;
+ }
+ buf_printf(b, "\t{ %#8x, \"%s\" },\n",
+ s->crc, s->name);
+ }
+
+ buf_printf(b, "};\n");
+}
+
+static void add_depends(struct buffer *b, struct module *mod)
+{
+ struct symbol *s;
+ int first = 1;
+
+ /* Clear ->seen flag of modules that own symbols needed by this. */
+ list_for_each_entry(s, &mod->unresolved_symbols, list) {
+ if (s->module)
+ s->module->seen = s->module->is_vmlinux;
+ }
+
+ buf_printf(b, "\n");
+ buf_printf(b, "MODULE_INFO(depends, \"");
+ list_for_each_entry(s, &mod->unresolved_symbols, list) {
+ const char *p;
+ if (!s->module)
+ continue;
+
+ if (s->module->seen)
+ continue;
+
+ s->module->seen = true;
+ p = strrchr(s->module->name, '/');
+ if (p)
+ p++;
+ else
+ p = s->module->name;
+ buf_printf(b, "%s%s", first ? "" : ",", p);
+ first = 0;
+ }
+ buf_printf(b, "\");\n");
+}
+
+static void add_srcversion(struct buffer *b, struct module *mod)
+{
+ if (mod->srcversion[0]) {
+ buf_printf(b, "\n");
+ buf_printf(b, "MODULE_INFO(srcversion, \"%s\");\n",
+ mod->srcversion);
+ }
+}
+
+static void write_buf(struct buffer *b, const char *fname)
+{
+ FILE *file;
+
+ if (error_occurred)
+ return;
+
+ file = fopen(fname, "w");
+ if (!file) {
+ perror(fname);
+ exit(1);
+ }
+ if (fwrite(b->p, 1, b->pos, file) != b->pos) {
+ perror(fname);
+ exit(1);
+ }
+ if (fclose(file) != 0) {
+ perror(fname);
+ exit(1);
+ }
+}
+
+static void write_if_changed(struct buffer *b, const char *fname)
+{
+ char *tmp;
+ FILE *file;
+ struct stat st;
+
+ file = fopen(fname, "r");
+ if (!file)
+ goto write;
+
+ if (fstat(fileno(file), &st) < 0)
+ goto close_write;
+
+ if (st.st_size != b->pos)
+ goto close_write;
+
+ tmp = NOFAIL(malloc(b->pos));
+ if (fread(tmp, 1, b->pos, file) != b->pos)
+ goto free_write;
+
+ if (memcmp(tmp, b->p, b->pos) != 0)
+ goto free_write;
+
+ free(tmp);
+ fclose(file);
+ return;
+
+ free_write:
+ free(tmp);
+ close_write:
+ fclose(file);
+ write:
+ write_buf(b, fname);
+}
+
+static void write_vmlinux_export_c_file(struct module *mod)
+{
+ struct buffer buf = { };
+
+ buf_printf(&buf,
+ "#include <linux/export-internal.h>\n");
+
+ add_exported_symbols(&buf, mod);
+ write_if_changed(&buf, ".vmlinux.export.c");
+ free(buf.p);
+}
+
+/* do sanity checks, and generate *.mod.c file */
+static void write_mod_c_file(struct module *mod)
+{
+ struct buffer buf = { };
+ char fname[PATH_MAX];
+ int ret;
+
+ check_modname_len(mod);
+ check_exports(mod);
+
+ add_header(&buf, mod);
+ add_exported_symbols(&buf, mod);
+ add_versions(&buf, mod);
+ add_depends(&buf, mod);
+ add_moddevtable(&buf, mod);
+ add_srcversion(&buf, mod);
+
+ ret = snprintf(fname, sizeof(fname), "%s.mod.c", mod->name);
+ if (ret >= sizeof(fname)) {
+ error("%s: too long path was truncated\n", fname);
+ goto free;
+ }
+
+ write_if_changed(&buf, fname);
+
+free:
+ free(buf.p);
+}
+
+/* parse Module.symvers file. line format:
+ * 0x12345678<tab>symbol<tab>module<tab>export<tab>namespace
+ **/
+static void read_dump(const char *fname)
+{
+ char *buf, *pos, *line;
+
+ buf = read_text_file(fname);
+ if (!buf)
+ /* No symbol versions, silently ignore */
+ return;
+
+ pos = buf;
+
+ while ((line = get_line(&pos))) {
+ char *symname, *namespace, *modname, *d, *export;
+ unsigned int crc;
+ struct module *mod;
+ struct symbol *s;
+ bool gpl_only;
+
+ if (!(symname = strchr(line, '\t')))
+ goto fail;
+ *symname++ = '\0';
+ if (!(modname = strchr(symname, '\t')))
+ goto fail;
+ *modname++ = '\0';
+ if (!(export = strchr(modname, '\t')))
+ goto fail;
+ *export++ = '\0';
+ if (!(namespace = strchr(export, '\t')))
+ goto fail;
+ *namespace++ = '\0';
+
+ crc = strtoul(line, &d, 16);
+ if (*symname == '\0' || *modname == '\0' || *d != '\0')
+ goto fail;
+
+ if (!strcmp(export, "EXPORT_SYMBOL_GPL")) {
+ gpl_only = true;
+ } else if (!strcmp(export, "EXPORT_SYMBOL")) {
+ gpl_only = false;
+ } else {
+ error("%s: unknown license %s. skip", symname, export);
+ continue;
+ }
+
+ mod = find_module(modname);
+ if (!mod) {
+ mod = new_module(modname, strlen(modname));
+ mod->from_dump = true;
+ }
+ s = sym_add_exported(symname, mod, gpl_only);
+ sym_set_crc(s, crc);
+ sym_update_namespace(symname, namespace);
+ }
+ free(buf);
+ return;
+fail:
+ free(buf);
+ fatal("parse error in symbol dump file\n");
+}
+
+static void write_dump(const char *fname)
+{
+ struct buffer buf = { };
+ struct module *mod;
+ struct symbol *sym;
+
+ list_for_each_entry(mod, &modules, list) {
+ if (mod->from_dump)
+ continue;
+ list_for_each_entry(sym, &mod->exported_symbols, list) {
+ buf_printf(&buf, "0x%08x\t%s\t%s\tEXPORT_SYMBOL%s\t%s\n",
+ sym->crc, sym->name, mod->name,
+ sym->is_gpl_only ? "_GPL" : "",
+ sym->namespace ?: "");
+ }
+ }
+ write_buf(&buf, fname);
+ free(buf.p);
+}
+
+static void write_namespace_deps_files(const char *fname)
+{
+ struct module *mod;
+ struct namespace_list *ns;
+ struct buffer ns_deps_buf = {};
+
+ list_for_each_entry(mod, &modules, list) {
+
+ if (mod->from_dump || list_empty(&mod->missing_namespaces))
+ continue;
+
+ buf_printf(&ns_deps_buf, "%s.ko:", mod->name);
+
+ list_for_each_entry(ns, &mod->missing_namespaces, list)
+ buf_printf(&ns_deps_buf, " %s", ns->namespace);
+
+ buf_printf(&ns_deps_buf, "\n");
+ }
+
+ write_if_changed(&ns_deps_buf, fname);
+ free(ns_deps_buf.p);
+}
+
+struct dump_list {
+ struct list_head list;
+ const char *file;
+};
+
+int main(int argc, char **argv)
+{
+ struct module *mod;
+ char *missing_namespace_deps = NULL;
+ char *dump_write = NULL, *files_source = NULL;
+ int opt;
+ LIST_HEAD(dump_lists);
+ struct dump_list *dl, *dl2;
+
+ while ((opt = getopt(argc, argv, "ei:mnT:o:awENd:")) != -1) {
+ switch (opt) {
+ case 'e':
+ external_module = true;
+ break;
+ case 'i':
+ dl = NOFAIL(malloc(sizeof(*dl)));
+ dl->file = optarg;
+ list_add_tail(&dl->list, &dump_lists);
+ break;
+ case 'm':
+ modversions = true;
+ break;
+ case 'n':
+ ignore_missing_files = true;
+ break;
+ case 'o':
+ dump_write = optarg;
+ break;
+ case 'a':
+ all_versions = true;
+ break;
+ case 'T':
+ files_source = optarg;
+ break;
+ case 'w':
+ warn_unresolved = true;
+ break;
+ case 'E':
+ sec_mismatch_warn_only = false;
+ break;
+ case 'N':
+ allow_missing_ns_imports = true;
+ break;
+ case 'd':
+ missing_namespace_deps = optarg;
+ break;
+ default:
+ exit(1);
+ }
+ }
+
+ list_for_each_entry_safe(dl, dl2, &dump_lists, list) {
+ read_dump(dl->file);
+ list_del(&dl->list);
+ free(dl);
+ }
+
+ while (optind < argc)
+ read_symbols(argv[optind++]);
+
+ if (files_source)
+ read_symbols_from_files(files_source);
+
+ list_for_each_entry(mod, &modules, list) {
+ if (mod->from_dump)
+ continue;
+
+ if (mod->is_vmlinux)
+ write_vmlinux_export_c_file(mod);
+ else
+ write_mod_c_file(mod);
+ }
+
+ if (missing_namespace_deps)
+ write_namespace_deps_files(missing_namespace_deps);
+
+ if (dump_write)
+ write_dump(dump_write);
+ if (sec_mismatch_count && !sec_mismatch_warn_only)
+ error("Section mismatches detected.\n"
+ "Set CONFIG_SECTION_MISMATCH_WARN_ONLY=y to allow them.\n");
+
+ if (nr_unresolved > MAX_UNRESOLVED_REPORTS)
+ warn("suppressed %u unresolved symbol warnings because there were too many)\n",
+ nr_unresolved - MAX_UNRESOLVED_REPORTS);
+
+ return error_occurred ? 1 : 0;
+}
Index: StarFive/create-6.1.31-3.8.2-host-limits-patch/linux-starfive-6.1.31-3.8.2-new/scripts/mod/sumversion.c
===================================================================
--- StarFive/create-6.1.31-3.8.2-host-limits-patch/linux-starfive-6.1.31-3.8.2-new/scripts/mod/sumversion.c (nonexistent)
+++ StarFive/create-6.1.31-3.8.2-host-limits-patch/linux-starfive-6.1.31-3.8.2-new/scripts/mod/sumversion.c (revision 385)
@@ -0,0 +1,410 @@
+#include <netinet/in.h>
+#ifdef __sun__
+#include <inttypes.h>
+#else
+#include <stdint.h>
+#endif
+#include <ctype.h>
+#include <errno.h>
+#include <string.h>
+#include <linux/limits.h>
+#include "modpost.h"
+
+/*
+ * Stolen form Cryptographic API.
+ *
+ * MD4 Message Digest Algorithm (RFC1320).
+ *
+ * Implementation derived from Andrew Tridgell and Steve French's
+ * CIFS MD4 implementation, and the cryptoapi implementation
+ * originally based on the public domain implementation written
+ * by Colin Plumb in 1993.
+ *
+ * Copyright (c) Andrew Tridgell 1997-1998.
+ * Modified by Steve French (sfrench@us.ibm.com) 2002
+ * Copyright (c) Cryptoapi developers.
+ * Copyright (c) 2002 David S. Miller (davem@redhat.com)
+ * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+#define MD4_DIGEST_SIZE 16
+#define MD4_HMAC_BLOCK_SIZE 64
+#define MD4_BLOCK_WORDS 16
+#define MD4_HASH_WORDS 4
+
+struct md4_ctx {
+ uint32_t hash[MD4_HASH_WORDS];
+ uint32_t block[MD4_BLOCK_WORDS];
+ uint64_t byte_count;
+};
+
+static inline uint32_t lshift(uint32_t x, unsigned int s)
+{
+ x &= 0xFFFFFFFF;
+ return ((x << s) & 0xFFFFFFFF) | (x >> (32 - s));
+}
+
+static inline uint32_t F(uint32_t x, uint32_t y, uint32_t z)
+{
+ return (x & y) | ((~x) & z);
+}
+
+static inline uint32_t G(uint32_t x, uint32_t y, uint32_t z)
+{
+ return (x & y) | (x & z) | (y & z);
+}
+
+static inline uint32_t H(uint32_t x, uint32_t y, uint32_t z)
+{
+ return x ^ y ^ z;
+}
+
+#define ROUND1(a,b,c,d,k,s) (a = lshift(a + F(b,c,d) + k, s))
+#define ROUND2(a,b,c,d,k,s) (a = lshift(a + G(b,c,d) + k + (uint32_t)0x5A827999,s))
+#define ROUND3(a,b,c,d,k,s) (a = lshift(a + H(b,c,d) + k + (uint32_t)0x6ED9EBA1,s))
+
+/* XXX: this stuff can be optimized */
+static inline void le32_to_cpu_array(uint32_t *buf, unsigned int words)
+{
+ while (words--) {
+ *buf = ntohl(*buf);
+ buf++;
+ }
+}
+
+static inline void cpu_to_le32_array(uint32_t *buf, unsigned int words)
+{
+ while (words--) {
+ *buf = htonl(*buf);
+ buf++;
+ }
+}
+
+static void md4_transform(uint32_t *hash, uint32_t const *in)
+{
+ uint32_t a, b, c, d;
+
+ a = hash[0];
+ b = hash[1];
+ c = hash[2];
+ d = hash[3];
+
+ ROUND1(a, b, c, d, in[0], 3);
+ ROUND1(d, a, b, c, in[1], 7);
+ ROUND1(c, d, a, b, in[2], 11);
+ ROUND1(b, c, d, a, in[3], 19);
+ ROUND1(a, b, c, d, in[4], 3);
+ ROUND1(d, a, b, c, in[5], 7);
+ ROUND1(c, d, a, b, in[6], 11);
+ ROUND1(b, c, d, a, in[7], 19);
+ ROUND1(a, b, c, d, in[8], 3);
+ ROUND1(d, a, b, c, in[9], 7);
+ ROUND1(c, d, a, b, in[10], 11);
+ ROUND1(b, c, d, a, in[11], 19);
+ ROUND1(a, b, c, d, in[12], 3);
+ ROUND1(d, a, b, c, in[13], 7);
+ ROUND1(c, d, a, b, in[14], 11);
+ ROUND1(b, c, d, a, in[15], 19);
+
+ ROUND2(a, b, c, d,in[ 0], 3);
+ ROUND2(d, a, b, c, in[4], 5);
+ ROUND2(c, d, a, b, in[8], 9);
+ ROUND2(b, c, d, a, in[12], 13);
+ ROUND2(a, b, c, d, in[1], 3);
+ ROUND2(d, a, b, c, in[5], 5);
+ ROUND2(c, d, a, b, in[9], 9);
+ ROUND2(b, c, d, a, in[13], 13);
+ ROUND2(a, b, c, d, in[2], 3);
+ ROUND2(d, a, b, c, in[6], 5);
+ ROUND2(c, d, a, b, in[10], 9);
+ ROUND2(b, c, d, a, in[14], 13);
+ ROUND2(a, b, c, d, in[3], 3);
+ ROUND2(d, a, b, c, in[7], 5);
+ ROUND2(c, d, a, b, in[11], 9);
+ ROUND2(b, c, d, a, in[15], 13);
+
+ ROUND3(a, b, c, d,in[ 0], 3);
+ ROUND3(d, a, b, c, in[8], 9);
+ ROUND3(c, d, a, b, in[4], 11);
+ ROUND3(b, c, d, a, in[12], 15);
+ ROUND3(a, b, c, d, in[2], 3);
+ ROUND3(d, a, b, c, in[10], 9);
+ ROUND3(c, d, a, b, in[6], 11);
+ ROUND3(b, c, d, a, in[14], 15);
+ ROUND3(a, b, c, d, in[1], 3);
+ ROUND3(d, a, b, c, in[9], 9);
+ ROUND3(c, d, a, b, in[5], 11);
+ ROUND3(b, c, d, a, in[13], 15);
+ ROUND3(a, b, c, d, in[3], 3);
+ ROUND3(d, a, b, c, in[11], 9);
+ ROUND3(c, d, a, b, in[7], 11);
+ ROUND3(b, c, d, a, in[15], 15);
+
+ hash[0] += a;
+ hash[1] += b;
+ hash[2] += c;
+ hash[3] += d;
+}
+
+static inline void md4_transform_helper(struct md4_ctx *ctx)
+{
+ le32_to_cpu_array(ctx->block, sizeof(ctx->block) / sizeof(uint32_t));
+ md4_transform(ctx->hash, ctx->block);
+}
+
+static void md4_init(struct md4_ctx *mctx)
+{
+ mctx->hash[0] = 0x67452301;
+ mctx->hash[1] = 0xefcdab89;
+ mctx->hash[2] = 0x98badcfe;
+ mctx->hash[3] = 0x10325476;
+ mctx->byte_count = 0;
+}
+
+static void md4_update(struct md4_ctx *mctx,
+ const unsigned char *data, unsigned int len)
+{
+ const uint32_t avail = sizeof(mctx->block) - (mctx->byte_count & 0x3f);
+
+ mctx->byte_count += len;
+
+ if (avail > len) {
+ memcpy((char *)mctx->block + (sizeof(mctx->block) - avail),
+ data, len);
+ return;
+ }
+
+ memcpy((char *)mctx->block + (sizeof(mctx->block) - avail),
+ data, avail);
+
+ md4_transform_helper(mctx);
+ data += avail;
+ len -= avail;
+
+ while (len >= sizeof(mctx->block)) {
+ memcpy(mctx->block, data, sizeof(mctx->block));
+ md4_transform_helper(mctx);
+ data += sizeof(mctx->block);
+ len -= sizeof(mctx->block);
+ }
+
+ memcpy(mctx->block, data, len);
+}
+
+static void md4_final_ascii(struct md4_ctx *mctx, char *out, unsigned int len)
+{
+ const unsigned int offset = mctx->byte_count & 0x3f;
+ char *p = (char *)mctx->block + offset;
+ int padding = 56 - (offset + 1);
+
+ *p++ = 0x80;
+ if (padding < 0) {
+ memset(p, 0x00, padding + sizeof (uint64_t));
+ md4_transform_helper(mctx);
+ p = (char *)mctx->block;
+ padding = 56;
+ }
+
+ memset(p, 0, padding);
+ mctx->block[14] = mctx->byte_count << 3;
+ mctx->block[15] = mctx->byte_count >> 29;
+ le32_to_cpu_array(mctx->block, (sizeof(mctx->block) -
+ sizeof(uint64_t)) / sizeof(uint32_t));
+ md4_transform(mctx->hash, mctx->block);
+ cpu_to_le32_array(mctx->hash, sizeof(mctx->hash) / sizeof(uint32_t));
+
+ snprintf(out, len, "%08X%08X%08X%08X",
+ mctx->hash[0], mctx->hash[1], mctx->hash[2], mctx->hash[3]);
+}
+
+static inline void add_char(unsigned char c, struct md4_ctx *md)
+{
+ md4_update(md, &c, 1);
+}
+
+static int parse_string(const char *file, unsigned long len,
+ struct md4_ctx *md)
+{
+ unsigned long i;
+
+ add_char(file[0], md);
+ for (i = 1; i < len; i++) {
+ add_char(file[i], md);
+ if (file[i] == '"' && file[i-1] != '\\')
+ break;
+ }
+ return i;
+}
+
+static int parse_comment(const char *file, unsigned long len)
+{
+ unsigned long i;
+
+ for (i = 2; i < len; i++) {
+ if (file[i-1] == '*' && file[i] == '/')
+ break;
+ }
+ return i;
+}
+
+/* FIXME: Handle .s files differently (eg. # starts comments) --RR */
+static int parse_file(const char *fname, struct md4_ctx *md)
+{
+ char *file;
+ unsigned long i, len;
+
+ file = read_text_file(fname);
+ len = strlen(file);
+
+ for (i = 0; i < len; i++) {
+ /* Collapse and ignore \ and CR. */
+ if (file[i] == '\\' && (i+1 < len) && file[i+1] == '\n') {
+ i++;
+ continue;
+ }
+
+ /* Ignore whitespace */
+ if (isspace(file[i]))
+ continue;
+
+ /* Handle strings as whole units */
+ if (file[i] == '"') {
+ i += parse_string(file+i, len - i, md);
+ continue;
+ }
+
+ /* Comments: ignore */
+ if (file[i] == '/' && file[i+1] == '*') {
+ i += parse_comment(file+i, len - i);
+ continue;
+ }
+
+ add_char(file[i], md);
+ }
+ free(file);
+ return 1;
+}
+/* Check whether the file is a static library or not */
+static bool is_static_library(const char *objfile)
+{
+ int len = strlen(objfile);
+
+ return objfile[len - 2] == '.' && objfile[len - 1] == 'a';
+}
+
+/* We have dir/file.o. Open dir/.file.o.cmd, look for source_ and deps_ line
+ * to figure out source files. */
+static int parse_source_files(const char *objfile, struct md4_ctx *md)
+{
+ char *cmd, *file, *line, *dir, *pos;
+ const char *base;
+ int dirlen, ret = 0, check_files = 0;
+
+ cmd = NOFAIL(malloc(strlen(objfile) + sizeof("..cmd")));
+
+ base = strrchr(objfile, '/');
+ if (base) {
+ base++;
+ dirlen = base - objfile;
+ sprintf(cmd, "%.*s.%s.cmd", dirlen, objfile, base);
+ } else {
+ dirlen = 0;
+ sprintf(cmd, ".%s.cmd", objfile);
+ }
+ dir = NOFAIL(malloc(dirlen + 1));
+ strncpy(dir, objfile, dirlen);
+ dir[dirlen] = '\0';
+
+ file = read_text_file(cmd);
+
+ pos = file;
+
+ /* Sum all files in the same dir or subdirs. */
+ while ((line = get_line(&pos))) {
+ char* p = line;
+
+ if (strncmp(line, "source_", sizeof("source_")-1) == 0) {
+ p = strrchr(line, ' ');
+ if (!p) {
+ warn("malformed line: %s\n", line);
+ goto out_file;
+ }
+ p++;
+ if (!parse_file(p, md)) {
+ warn("could not open %s: %s\n",
+ p, strerror(errno));
+ goto out_file;
+ }
+ continue;
+ }
+ if (strncmp(line, "deps_", sizeof("deps_")-1) == 0) {
+ check_files = 1;
+ continue;
+ }
+ if (!check_files)
+ continue;
+
+ /* Continue until line does not end with '\' */
+ if ( *(p + strlen(p)-1) != '\\')
+ break;
+ /* Terminate line at first space, to get rid of final ' \' */
+ while (*p) {
+ if (isspace(*p)) {
+ *p = '\0';
+ break;
+ }
+ p++;
+ }
+
+ /* Check if this file is in same dir as objfile */
+ if ((strstr(line, dir)+strlen(dir)-1) == strrchr(line, '/')) {
+ if (!parse_file(line, md)) {
+ warn("could not open %s: %s\n",
+ line, strerror(errno));
+ goto out_file;
+ }
+
+ }
+
+ }
+
+ /* Everyone parsed OK */
+ ret = 1;
+out_file:
+ free(file);
+ free(dir);
+ free(cmd);
+ return ret;
+}
+
+/* Calc and record src checksum. */
+void get_src_version(const char *modname, char sum[], unsigned sumlen)
+{
+ char *buf;
+ struct md4_ctx md;
+ char *fname;
+ char filelist[PATH_MAX + 1];
+
+ /* objects for a module are listed in the first line of *.mod file. */
+ snprintf(filelist, sizeof(filelist), "%s.mod", modname);
+
+ buf = read_text_file(filelist);
+
+ md4_init(&md);
+ while ((fname = strsep(&buf, "\n"))) {
+ if (!*fname)
+ continue;
+ if (!(is_static_library(fname)) &&
+ !parse_source_files(fname, &md))
+ goto free;
+ }
+
+ md4_final_ascii(&md, sum, sumlen);
+free:
+ free(buf);
+}
Index: StarFive/create-6.1.31-3.8.2-host-limits-patch/linux-starfive-6.1.31-3.8.2-new/tools/build/fixdep.c
===================================================================
--- StarFive/create-6.1.31-3.8.2-host-limits-patch/linux-starfive-6.1.31-3.8.2-new/tools/build/fixdep.c (nonexistent)
+++ StarFive/create-6.1.31-3.8.2-host-limits-patch/linux-starfive-6.1.31-3.8.2-new/tools/build/fixdep.c (revision 385)
@@ -0,0 +1,170 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * "Optimize" a list of dependencies as spit out by gcc -MD
+ * for the build framework.
+ *
+ * Original author:
+ * Copyright 2002 by Kai Germaschewski <kai.germaschewski@gmx.de>
+ *
+ * This code has been borrowed from kbuild's fixdep (scripts/basic/fixdep.c),
+ * Please check it for detailed explanation. This fixdep borow only the
+ * base transformation of dependecies without the CONFIG mangle.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <linux/limits.h>
+
+char *target;
+char *depfile;
+char *cmdline;
+
+static void usage(void)
+{
+ fprintf(stderr, "Usage: fixdep <depfile> <target> <cmdline>\n");
+ exit(1);
+}
+
+/*
+ * Print out the commandline prefixed with cmd_<target filename> :=
+ */
+static void print_cmdline(void)
+{
+ printf("cmd_%s := %s\n\n", target, cmdline);
+}
+
+/*
+ * Important: The below generated source_foo.o and deps_foo.o variable
+ * assignments are parsed not only by make, but also by the rather simple
+ * parser in scripts/mod/sumversion.c.
+ */
+static void parse_dep_file(void *map, size_t len)
+{
+ char *m = map;
+ char *end = m + len;
+ char *p;
+ char s[PATH_MAX];
+ int is_target, has_target = 0;
+ int saw_any_target = 0;
+ int is_first_dep = 0;
+
+ while (m < end) {
+ /* Skip any "white space" */
+ while (m < end && (*m == ' ' || *m == '\\' || *m == '\n'))
+ m++;
+ /* Find next "white space" */
+ p = m;
+ while (p < end && *p != ' ' && *p != '\\' && *p != '\n')
+ p++;
+ /* Is the token we found a target name? */
+ is_target = (*(p-1) == ':');
+ /* Don't write any target names into the dependency file */
+ if (is_target) {
+ /* The /next/ file is the first dependency */
+ is_first_dep = 1;
+ has_target = 1;
+ } else if (has_target) {
+ /* Save this token/filename */
+ memcpy(s, m, p-m);
+ s[p - m] = 0;
+
+ /*
+ * Do not list the source file as dependency,
+ * so that kbuild is not confused if a .c file
+ * is rewritten into .S or vice versa. Storing
+ * it in source_* is needed for modpost to
+ * compute srcversions.
+ */
+ if (is_first_dep) {
+ /*
+ * If processing the concatenation of
+ * multiple dependency files, only
+ * process the first target name, which
+ * will be the original source name,
+ * and ignore any other target names,
+ * which will be intermediate temporary
+ * files.
+ */
+ if (!saw_any_target) {
+ saw_any_target = 1;
+ printf("source_%s := %s\n\n",
+ target, s);
+ printf("deps_%s := \\\n",
+ target);
+ }
+ is_first_dep = 0;
+ } else
+ printf(" %s \\\n", s);
+ }
+ /*
+ * Start searching for next token immediately after the first
+ * "whitespace" character that follows this token.
+ */
+ m = p + 1;
+ }
+
+ if (!saw_any_target) {
+ fprintf(stderr, "fixdep: parse error; no targets found\n");
+ exit(1);
+ }
+
+ printf("\n%s: $(deps_%s)\n\n", target, target);
+ printf("$(deps_%s):\n", target);
+}
+
+static void print_deps(void)
+{
+ struct stat st;
+ int fd;
+ void *map;
+
+ fd = open(depfile, O_RDONLY);
+ if (fd < 0) {
+ fprintf(stderr, "fixdep: error opening depfile: ");
+ perror(depfile);
+ exit(2);
+ }
+ if (fstat(fd, &st) < 0) {
+ fprintf(stderr, "fixdep: error fstat'ing depfile: ");
+ perror(depfile);
+ exit(2);
+ }
+ if (st.st_size == 0) {
+ fprintf(stderr, "fixdep: %s is empty\n", depfile);
+ close(fd);
+ return;
+ }
+ map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+ if ((long) map == -1) {
+ perror("fixdep: mmap");
+ close(fd);
+ return;
+ }
+
+ parse_dep_file(map, st.st_size);
+
+ munmap(map, st.st_size);
+
+ close(fd);
+}
+
+int main(int argc, char **argv)
+{
+ if (argc != 4)
+ usage();
+
+ depfile = argv[1];
+ target = argv[2];
+ cmdline = argv[3];
+
+ print_cmdline();
+ print_deps();
+
+ return 0;
+}
Index: StarFive/create-6.1.31-3.8.2-host-limits-patch/linux-starfive-6.1.31-3.8.2-new/usr/gen_init_cpio.c
===================================================================
--- StarFive/create-6.1.31-3.8.2-host-limits-patch/linux-starfive-6.1.31-3.8.2-new/usr/gen_init_cpio.c (nonexistent)
+++ StarFive/create-6.1.31-3.8.2-host-limits-patch/linux-starfive-6.1.31-3.8.2-new/usr/gen_init_cpio.c (revision 385)
@@ -0,0 +1,682 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <unistd.h>
+#include <time.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <ctype.h>
+#include <linux/limits.h>
+
+/*
+ * Original work by Jeff Garzik
+ *
+ * External file lists, symlink, pipe and fifo support by Thayne Harbaugh
+ * Hard link support by Luciano Rocha
+ */
+
+#define xstr(s) #s
+#define str(s) xstr(s)
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+
+static unsigned int offset;
+static unsigned int ino = 721;
+static time_t default_mtime;
+static bool do_csum = false;
+
+struct file_handler {
+ const char *type;
+ int (*handler)(const char *line);
+};
+
+static void push_string(const char *name)
+{
+ unsigned int name_len = strlen(name) + 1;
+
+ fputs(name, stdout);
+ putchar(0);
+ offset += name_len;
+}
+
+static void push_pad (void)
+{
+ while (offset & 3) {
+ putchar(0);
+ offset++;
+ }
+}
+
+static void push_rest(const char *name)
+{
+ unsigned int name_len = strlen(name) + 1;
+ unsigned int tmp_ofs;
+
+ fputs(name, stdout);
+ putchar(0);
+ offset += name_len;
+
+ tmp_ofs = name_len + 110;
+ while (tmp_ofs & 3) {
+ putchar(0);
+ offset++;
+ tmp_ofs++;
+ }
+}
+
+static void push_hdr(const char *s)
+{
+ fputs(s, stdout);
+ offset += 110;
+}
+
+static void cpio_trailer(void)
+{
+ char s[256];
+ const char name[] = "TRAILER!!!";
+
+ sprintf(s, "%s%08X%08X%08lX%08lX%08X%08lX"
+ "%08X%08X%08X%08X%08X%08X%08X",
+ do_csum ? "070702" : "070701", /* magic */
+ 0, /* ino */
+ 0, /* mode */
+ (long) 0, /* uid */
+ (long) 0, /* gid */
+ 1, /* nlink */
+ (long) 0, /* mtime */
+ 0, /* filesize */
+ 0, /* major */
+ 0, /* minor */
+ 0, /* rmajor */
+ 0, /* rminor */
+ (unsigned)strlen(name)+1, /* namesize */
+ 0); /* chksum */
+ push_hdr(s);
+ push_rest(name);
+
+ while (offset % 512) {
+ putchar(0);
+ offset++;
+ }
+}
+
+static int cpio_mkslink(const char *name, const char *target,
+ unsigned int mode, uid_t uid, gid_t gid)
+{
+ char s[256];
+
+ if (name[0] == '/')
+ name++;
+ sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
+ "%08X%08X%08X%08X%08X%08X%08X",
+ do_csum ? "070702" : "070701", /* magic */
+ ino++, /* ino */
+ S_IFLNK | mode, /* mode */
+ (long) uid, /* uid */
+ (long) gid, /* gid */
+ 1, /* nlink */
+ (long) default_mtime, /* mtime */
+ (unsigned)strlen(target)+1, /* filesize */
+ 3, /* major */
+ 1, /* minor */
+ 0, /* rmajor */
+ 0, /* rminor */
+ (unsigned)strlen(name) + 1,/* namesize */
+ 0); /* chksum */
+ push_hdr(s);
+ push_string(name);
+ push_pad();
+ push_string(target);
+ push_pad();
+ return 0;
+}
+
+static int cpio_mkslink_line(const char *line)
+{
+ char name[PATH_MAX + 1];
+ char target[PATH_MAX + 1];
+ unsigned int mode;
+ int uid;
+ int gid;
+ int rc = -1;
+
+ if (5 != sscanf(line, "%" str(PATH_MAX) "s %" str(PATH_MAX) "s %o %d %d", name, target, &mode, &uid, &gid)) {
+ fprintf(stderr, "Unrecognized dir format '%s'", line);
+ goto fail;
+ }
+ rc = cpio_mkslink(name, target, mode, uid, gid);
+ fail:
+ return rc;
+}
+
+static int cpio_mkgeneric(const char *name, unsigned int mode,
+ uid_t uid, gid_t gid)
+{
+ char s[256];
+
+ if (name[0] == '/')
+ name++;
+ sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
+ "%08X%08X%08X%08X%08X%08X%08X",
+ do_csum ? "070702" : "070701", /* magic */
+ ino++, /* ino */
+ mode, /* mode */
+ (long) uid, /* uid */
+ (long) gid, /* gid */
+ 2, /* nlink */
+ (long) default_mtime, /* mtime */
+ 0, /* filesize */
+ 3, /* major */
+ 1, /* minor */
+ 0, /* rmajor */
+ 0, /* rminor */
+ (unsigned)strlen(name) + 1,/* namesize */
+ 0); /* chksum */
+ push_hdr(s);
+ push_rest(name);
+ return 0;
+}
+
+enum generic_types {
+ GT_DIR,
+ GT_PIPE,
+ GT_SOCK
+};
+
+struct generic_type {
+ const char *type;
+ mode_t mode;
+};
+
+static const struct generic_type generic_type_table[] = {
+ [GT_DIR] = {
+ .type = "dir",
+ .mode = S_IFDIR
+ },
+ [GT_PIPE] = {
+ .type = "pipe",
+ .mode = S_IFIFO
+ },
+ [GT_SOCK] = {
+ .type = "sock",
+ .mode = S_IFSOCK
+ }
+};
+
+static int cpio_mkgeneric_line(const char *line, enum generic_types gt)
+{
+ char name[PATH_MAX + 1];
+ unsigned int mode;
+ int uid;
+ int gid;
+ int rc = -1;
+
+ if (4 != sscanf(line, "%" str(PATH_MAX) "s %o %d %d", name, &mode, &uid, &gid)) {
+ fprintf(stderr, "Unrecognized %s format '%s'",
+ line, generic_type_table[gt].type);
+ goto fail;
+ }
+ mode |= generic_type_table[gt].mode;
+ rc = cpio_mkgeneric(name, mode, uid, gid);
+ fail:
+ return rc;
+}
+
+static int cpio_mkdir_line(const char *line)
+{
+ return cpio_mkgeneric_line(line, GT_DIR);
+}
+
+static int cpio_mkpipe_line(const char *line)
+{
+ return cpio_mkgeneric_line(line, GT_PIPE);
+}
+
+static int cpio_mksock_line(const char *line)
+{
+ return cpio_mkgeneric_line(line, GT_SOCK);
+}
+
+static int cpio_mknod(const char *name, unsigned int mode,
+ uid_t uid, gid_t gid, char dev_type,
+ unsigned int maj, unsigned int min)
+{
+ char s[256];
+
+ if (dev_type == 'b')
+ mode |= S_IFBLK;
+ else
+ mode |= S_IFCHR;
+
+ if (name[0] == '/')
+ name++;
+ sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
+ "%08X%08X%08X%08X%08X%08X%08X",
+ do_csum ? "070702" : "070701", /* magic */
+ ino++, /* ino */
+ mode, /* mode */
+ (long) uid, /* uid */
+ (long) gid, /* gid */
+ 1, /* nlink */
+ (long) default_mtime, /* mtime */
+ 0, /* filesize */
+ 3, /* major */
+ 1, /* minor */
+ maj, /* rmajor */
+ min, /* rminor */
+ (unsigned)strlen(name) + 1,/* namesize */
+ 0); /* chksum */
+ push_hdr(s);
+ push_rest(name);
+ return 0;
+}
+
+static int cpio_mknod_line(const char *line)
+{
+ char name[PATH_MAX + 1];
+ unsigned int mode;
+ int uid;
+ int gid;
+ char dev_type;
+ unsigned int maj;
+ unsigned int min;
+ int rc = -1;
+
+ if (7 != sscanf(line, "%" str(PATH_MAX) "s %o %d %d %c %u %u",
+ name, &mode, &uid, &gid, &dev_type, &maj, &min)) {
+ fprintf(stderr, "Unrecognized nod format '%s'", line);
+ goto fail;
+ }
+ rc = cpio_mknod(name, mode, uid, gid, dev_type, maj, min);
+ fail:
+ return rc;
+}
+
+static int cpio_mkfile_csum(int fd, unsigned long size, uint32_t *csum)
+{
+ while (size) {
+ unsigned char filebuf[65536];
+ ssize_t this_read;
+ size_t i, this_size = MIN(size, sizeof(filebuf));
+
+ this_read = read(fd, filebuf, this_size);
+ if (this_read <= 0 || this_read > this_size)
+ return -1;
+
+ for (i = 0; i < this_read; i++)
+ *csum += filebuf[i];
+
+ size -= this_read;
+ }
+ /* seek back to the start for data segment I/O */
+ if (lseek(fd, 0, SEEK_SET) < 0)
+ return -1;
+
+ return 0;
+}
+
+static int cpio_mkfile(const char *name, const char *location,
+ unsigned int mode, uid_t uid, gid_t gid,
+ unsigned int nlinks)
+{
+ char s[256];
+ struct stat buf;
+ unsigned long size;
+ int file;
+ int retval;
+ int rc = -1;
+ int namesize;
+ unsigned int i;
+ uint32_t csum = 0;
+
+ mode |= S_IFREG;
+
+ file = open (location, O_RDONLY);
+ if (file < 0) {
+ fprintf (stderr, "File %s could not be opened for reading\n", location);
+ goto error;
+ }
+
+ retval = fstat(file, &buf);
+ if (retval) {
+ fprintf(stderr, "File %s could not be stat()'ed\n", location);
+ goto error;
+ }
+
+ if (buf.st_mtime > 0xffffffff) {
+ fprintf(stderr, "%s: Timestamp exceeds maximum cpio timestamp, clipping.\n",
+ location);
+ buf.st_mtime = 0xffffffff;
+ }
+
+ if (buf.st_size > 0xffffffff) {
+ fprintf(stderr, "%s: Size exceeds maximum cpio file size\n",
+ location);
+ goto error;
+ }
+
+ if (do_csum && cpio_mkfile_csum(file, buf.st_size, &csum) < 0) {
+ fprintf(stderr, "Failed to checksum file %s\n", location);
+ goto error;
+ }
+
+ size = 0;
+ for (i = 1; i <= nlinks; i++) {
+ /* data goes on last link */
+ if (i == nlinks)
+ size = buf.st_size;
+
+ if (name[0] == '/')
+ name++;
+ namesize = strlen(name) + 1;
+ sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
+ "%08lX%08X%08X%08X%08X%08X%08X",
+ do_csum ? "070702" : "070701", /* magic */
+ ino, /* ino */
+ mode, /* mode */
+ (long) uid, /* uid */
+ (long) gid, /* gid */
+ nlinks, /* nlink */
+ (long) buf.st_mtime, /* mtime */
+ size, /* filesize */
+ 3, /* major */
+ 1, /* minor */
+ 0, /* rmajor */
+ 0, /* rminor */
+ namesize, /* namesize */
+ size ? csum : 0); /* chksum */
+ push_hdr(s);
+ push_string(name);
+ push_pad();
+
+ while (size) {
+ unsigned char filebuf[65536];
+ ssize_t this_read;
+ size_t this_size = MIN(size, sizeof(filebuf));
+
+ this_read = read(file, filebuf, this_size);
+ if (this_read <= 0 || this_read > this_size) {
+ fprintf(stderr, "Can not read %s file\n", location);
+ goto error;
+ }
+
+ if (fwrite(filebuf, this_read, 1, stdout) != 1) {
+ fprintf(stderr, "writing filebuf failed\n");
+ goto error;
+ }
+ offset += this_read;
+ size -= this_read;
+ }
+ push_pad();
+
+ name += namesize;
+ }
+ ino++;
+ rc = 0;
+
+error:
+ if (file >= 0)
+ close(file);
+ return rc;
+}
+
+static char *cpio_replace_env(char *new_location)
+{
+ char expanded[PATH_MAX + 1];
+ char *start, *end, *var;
+
+ while ((start = strstr(new_location, "${")) &&
+ (end = strchr(start + 2, '}'))) {
+ *start = *end = 0;
+ var = getenv(start + 2);
+ snprintf(expanded, sizeof expanded, "%s%s%s",
+ new_location, var ? var : "", end + 1);
+ strcpy(new_location, expanded);
+ }
+
+ return new_location;
+}
+
+static int cpio_mkfile_line(const char *line)
+{
+ char name[PATH_MAX + 1];
+ char *dname = NULL; /* malloc'ed buffer for hard links */
+ char location[PATH_MAX + 1];
+ unsigned int mode;
+ int uid;
+ int gid;
+ int nlinks = 1;
+ int end = 0, dname_len = 0;
+ int rc = -1;
+
+ if (5 > sscanf(line, "%" str(PATH_MAX) "s %" str(PATH_MAX)
+ "s %o %d %d %n",
+ name, location, &mode, &uid, &gid, &end)) {
+ fprintf(stderr, "Unrecognized file format '%s'", line);
+ goto fail;
+ }
+ if (end && isgraph(line[end])) {
+ int len;
+ int nend;
+
+ dname = malloc(strlen(line));
+ if (!dname) {
+ fprintf (stderr, "out of memory (%d)\n", dname_len);
+ goto fail;
+ }
+
+ dname_len = strlen(name) + 1;
+ memcpy(dname, name, dname_len);
+
+ do {
+ nend = 0;
+ if (sscanf(line + end, "%" str(PATH_MAX) "s %n",
+ name, &nend) < 1)
+ break;
+ len = strlen(name) + 1;
+ memcpy(dname + dname_len, name, len);
+ dname_len += len;
+ nlinks++;
+ end += nend;
+ } while (isgraph(line[end]));
+ } else {
+ dname = name;
+ }
+ rc = cpio_mkfile(dname, cpio_replace_env(location),
+ mode, uid, gid, nlinks);
+ fail:
+ if (dname_len) free(dname);
+ return rc;
+}
+
+static void usage(const char *prog)
+{
+ fprintf(stderr, "Usage:\n"
+ "\t%s [-t <timestamp>] [-c] <cpio_list>\n"
+ "\n"
+ "<cpio_list> is a file containing newline separated entries that\n"
+ "describe the files to be included in the initramfs archive:\n"
+ "\n"
+ "# a comment\n"
+ "file <name> <location> <mode> <uid> <gid> [<hard links>]\n"
+ "dir <name> <mode> <uid> <gid>\n"
+ "nod <name> <mode> <uid> <gid> <dev_type> <maj> <min>\n"
+ "slink <name> <target> <mode> <uid> <gid>\n"
+ "pipe <name> <mode> <uid> <gid>\n"
+ "sock <name> <mode> <uid> <gid>\n"
+ "\n"
+ "<name> name of the file/dir/nod/etc in the archive\n"
+ "<location> location of the file in the current filesystem\n"
+ " expands shell variables quoted with ${}\n"
+ "<target> link target\n"
+ "<mode> mode/permissions of the file\n"
+ "<uid> user id (0=root)\n"
+ "<gid> group id (0=root)\n"
+ "<dev_type> device type (b=block, c=character)\n"
+ "<maj> major number of nod\n"
+ "<min> minor number of nod\n"
+ "<hard links> space separated list of other links to file\n"
+ "\n"
+ "example:\n"
+ "# A simple initramfs\n"
+ "dir /dev 0755 0 0\n"
+ "nod /dev/console 0600 0 0 c 5 1\n"
+ "dir /root 0700 0 0\n"
+ "dir /sbin 0755 0 0\n"
+ "file /sbin/kinit /usr/src/klibc/kinit/kinit 0755 0 0\n"
+ "\n"
+ "<timestamp> is time in seconds since Epoch that will be used\n"
+ "as mtime for symlinks, special files and directories. The default\n"
+ "is to use the current time for these entries.\n"
+ "-c: calculate and store 32-bit checksums for file data.\n",
+ prog);
+}
+
+static const struct file_handler file_handler_table[] = {
+ {
+ .type = "file",
+ .handler = cpio_mkfile_line,
+ }, {
+ .type = "nod",
+ .handler = cpio_mknod_line,
+ }, {
+ .type = "dir",
+ .handler = cpio_mkdir_line,
+ }, {
+ .type = "slink",
+ .handler = cpio_mkslink_line,
+ }, {
+ .type = "pipe",
+ .handler = cpio_mkpipe_line,
+ }, {
+ .type = "sock",
+ .handler = cpio_mksock_line,
+ }, {
+ .type = NULL,
+ .handler = NULL,
+ }
+};
+
+#define LINE_SIZE (2 * PATH_MAX + 50)
+
+int main (int argc, char *argv[])
+{
+ FILE *cpio_list;
+ char line[LINE_SIZE];
+ char *args, *type;
+ int ec = 0;
+ int line_nr = 0;
+ const char *filename;
+
+ default_mtime = time(NULL);
+ while (1) {
+ int opt = getopt(argc, argv, "t:ch");
+ char *invalid;
+
+ if (opt == -1)
+ break;
+ switch (opt) {
+ case 't':
+ default_mtime = strtol(optarg, &invalid, 10);
+ if (!*optarg || *invalid) {
+ fprintf(stderr, "Invalid timestamp: %s\n",
+ optarg);
+ usage(argv[0]);
+ exit(1);
+ }
+ break;
+ case 'c':
+ do_csum = true;
+ break;
+ case 'h':
+ case '?':
+ usage(argv[0]);
+ exit(opt == 'h' ? 0 : 1);
+ }
+ }
+
+ /*
+ * Timestamps after 2106-02-07 06:28:15 UTC have an ascii hex time_t
+ * representation that exceeds 8 chars and breaks the cpio header
+ * specification.
+ */
+ if (default_mtime > 0xffffffff) {
+ fprintf(stderr, "ERROR: Timestamp too large for cpio format\n");
+ exit(1);
+ }
+
+ if (argc - optind != 1) {
+ usage(argv[0]);
+ exit(1);
+ }
+ filename = argv[optind];
+ if (!strcmp(filename, "-"))
+ cpio_list = stdin;
+ else if (!(cpio_list = fopen(filename, "r"))) {
+ fprintf(stderr, "ERROR: unable to open '%s': %s\n\n",
+ filename, strerror(errno));
+ usage(argv[0]);
+ exit(1);
+ }
+
+ while (fgets(line, LINE_SIZE, cpio_list)) {
+ int type_idx;
+ size_t slen = strlen(line);
+
+ line_nr++;
+
+ if ('#' == *line) {
+ /* comment - skip to next line */
+ continue;
+ }
+
+ if (! (type = strtok(line, " \t"))) {
+ fprintf(stderr,
+ "ERROR: incorrect format, could not locate file type line %d: '%s'\n",
+ line_nr, line);
+ ec = -1;
+ break;
+ }
+
+ if ('\n' == *type) {
+ /* a blank line */
+ continue;
+ }
+
+ if (slen == strlen(type)) {
+ /* must be an empty line */
+ continue;
+ }
+
+ if (! (args = strtok(NULL, "\n"))) {
+ fprintf(stderr,
+ "ERROR: incorrect format, newline required line %d: '%s'\n",
+ line_nr, line);
+ ec = -1;
+ }
+
+ for (type_idx = 0; file_handler_table[type_idx].type; type_idx++) {
+ int rc;
+ if (! strcmp(line, file_handler_table[type_idx].type)) {
+ if ((rc = file_handler_table[type_idx].handler(args))) {
+ ec = rc;
+ fprintf(stderr, " line %d\n", line_nr);
+ }
+ break;
+ }
+ }
+
+ if (NULL == file_handler_table[type_idx].type) {
+ fprintf(stderr, "unknown file type line %d: '%s'\n",
+ line_nr, line);
+ }
+ }
+ if (ec == 0)
+ cpio_trailer();
+
+ exit(ec);
+}
Index: StarFive/patches/README
===================================================================
--- StarFive/patches/README (nonexistent)
+++ StarFive/patches/README (revision 385)
@@ -0,0 +1,6 @@
+
+/* begin *
+
+ TODO: Leave some comment here.
+
+ * end */
Index: StarFive/patches
===================================================================
--- StarFive/patches (nonexistent)
+++ StarFive/patches (revision 385)
Property changes on: StarFive/patches
___________________________________________________________________
Added: svn:ignore
## -0,0 +1,74 ##
+
+# install dir
+dist
+
+# Target build dirs
+.a1x-newlib
+.a2x-newlib
+.at91sam7s-newlib
+
+.build-machine
+
+.a1x-glibc
+.a2x-glibc
+.h3-glibc
+.h5-glibc
+.i586-glibc
+.i686-glibc
+.imx6-glibc
+.jz47xx-glibc
+.makefile
+.am335x-glibc
+.omap543x-glibc
+.p5600-glibc
+.power8-glibc
+.power8le-glibc
+.power9-glibc
+.power9le-glibc
+.m1000-glibc
+.riscv64-glibc
+.rk328x-glibc
+.rk33xx-glibc
+.rk339x-glibc
+.rk358x-glibc
+.s8xx-glibc
+.s9xx-glibc
+.x86_64-glibc
+
+# Hidden files (each file)
+.makefile
+.dist
+.rootfs
+
+# src & hw requires
+.src_requires
+.src_requires_depend
+.requires
+.requires_depend
+
+# Tarballs
+*.gz
+*.bz2
+*.lz
+*.xz
+*.tgz
+*.txz
+
+# Signatures
+*.asc
+*.sig
+*.sign
+*.sha1sum
+
+# Patches
+*.patch
+
+# Descriptions
+*.dsc
+*.txt
+
+# Default linux config files
+*.defconfig
+
+# backup copies
+*~
Index: StarFive
===================================================================
--- StarFive (nonexistent)
+++ StarFive (revision 385)
Property changes on: StarFive
___________________________________________________________________
Added: svn:ignore
## -0,0 +1,74 ##
+
+# install dir
+dist
+
+# Target build dirs
+.a1x-newlib
+.a2x-newlib
+.at91sam7s-newlib
+
+.build-machine
+
+.a1x-glibc
+.a2x-glibc
+.h3-glibc
+.h5-glibc
+.i586-glibc
+.i686-glibc
+.imx6-glibc
+.jz47xx-glibc
+.makefile
+.am335x-glibc
+.omap543x-glibc
+.p5600-glibc
+.power8-glibc
+.power8le-glibc
+.power9-glibc
+.power9le-glibc
+.m1000-glibc
+.riscv64-glibc
+.rk328x-glibc
+.rk33xx-glibc
+.rk339x-glibc
+.rk358x-glibc
+.s8xx-glibc
+.s9xx-glibc
+.x86_64-glibc
+
+# Hidden files (each file)
+.makefile
+.dist
+.rootfs
+
+# src & hw requires
+.src_requires
+.src_requires_depend
+.requires
+.requires_depend
+
+# Tarballs
+*.gz
+*.bz2
+*.lz
+*.xz
+*.tgz
+*.txz
+
+# Signatures
+*.asc
+*.sig
+*.sign
+*.sha1sum
+
+# Patches
+*.patch
+
+# Descriptions
+*.dsc
+*.txt
+
+# Default linux config files
+*.defconfig
+
+# backup copies
+*~
Index: v6.x/create-6.0.7-host-limits-patch/file.list
===================================================================
--- v6.x/create-6.0.7-host-limits-patch/file.list (revision 384)
+++ v6.x/create-6.0.7-host-limits-patch/file.list (nonexistent)
@@ -1,7 +0,0 @@
-linux-6.0.7/scripts/kconfig/conf.c
-linux-6.0.7/scripts/kconfig/confdata.c
-linux-6.0.7/scripts/kconfig/lexer.l
-linux-6.0.7/scripts/mod/modpost.c
-linux-6.0.7/scripts/mod/sumversion.c
-linux-6.0.7/tools/build/fixdep.c
-linux-6.0.7/usr/gen_init_cpio.c
Index: v6.x/create-6.0.7-host-limits-patch/create.patch.sh
===================================================================
--- v6.x/create-6.0.7-host-limits-patch/create.patch.sh (revision 384)
+++ v6.x/create-6.0.7-host-limits-patch/create.patch.sh (nonexistent)
@@ -1,15 +0,0 @@
-#!/bin/sh
-
-VERSION=6.0.7
-
-tar --files-from=file.list -xJvf ../linux-$VERSION.tar.xz
-mv linux-$VERSION linux-$VERSION-orig
-
-cp -rf ./linux-$VERSION-new ./linux-$VERSION
-
-diff --unified -Nr linux-$VERSION-orig linux-$VERSION > linux-$VERSION-host-limits.patch
-
-mv linux-$VERSION-host-limits.patch ../patches
-
-rm -rf ./linux-$VERSION
-rm -rf ./linux-$VERSION-orig
Property changes on: v6.x/create-6.0.7-host-limits-patch/create.patch.sh
___________________________________________________________________
Deleted: svn:executable
## -1 +0,0 ##
-*
\ No newline at end of property
Index: v6.x/create-6.0.7-host-limits-patch/linux-6.0.7-new/scripts/mod/modpost.c
===================================================================
--- v6.x/create-6.0.7-host-limits-patch/linux-6.0.7-new/scripts/mod/modpost.c (revision 384)
+++ v6.x/create-6.0.7-host-limits-patch/linux-6.0.7-new/scripts/mod/modpost.c (nonexistent)
@@ -1,2407 +0,0 @@
-/* Postprocess module symbol versions
- *
- * Copyright 2003 Kai Germaschewski
- * Copyright 2002-2004 Rusty Russell, IBM Corporation
- * Copyright 2006-2008 Sam Ravnborg
- * Based in part on module-init-tools/depmod.c,file2alias
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- * Usage: modpost vmlinux module1.o module2.o ...
- */
-
-#define _GNU_SOURCE
-#include <elf.h>
-#include <fnmatch.h>
-#include <stdio.h>
-#include <ctype.h>
-#include <string.h>
-#include <linux/limits.h>
-#include <stdbool.h>
-#include <errno.h>
-#include "modpost.h"
-#include "../../include/linux/license.h"
-
-/* Are we using CONFIG_MODVERSIONS? */
-static bool modversions;
-/* Is CONFIG_MODULE_SRCVERSION_ALL set? */
-static bool all_versions;
-/* If we are modposting external module set to 1 */
-static bool external_module;
-/* Only warn about unresolved symbols */
-static bool warn_unresolved;
-
-static int sec_mismatch_count;
-static bool sec_mismatch_warn_only = true;
-/* ignore missing files */
-static bool ignore_missing_files;
-/* If set to 1, only warn (instead of error) about missing ns imports */
-static bool allow_missing_ns_imports;
-
-static bool error_occurred;
-
-/*
- * Cut off the warnings when there are too many. This typically occurs when
- * vmlinux is missing. ('make modules' without building vmlinux.)
- */
-#define MAX_UNRESOLVED_REPORTS 10
-static unsigned int nr_unresolved;
-
-/* In kernel, this size is defined in linux/module.h;
- * here we use Elf_Addr instead of long for covering cross-compile
- */
-
-#define MODULE_NAME_LEN (64 - sizeof(Elf_Addr))
-
-void __attribute__((format(printf, 2, 3)))
-modpost_log(enum loglevel loglevel, const char *fmt, ...)
-{
- va_list arglist;
-
- switch (loglevel) {
- case LOG_WARN:
- fprintf(stderr, "WARNING: ");
- break;
- case LOG_ERROR:
- fprintf(stderr, "ERROR: ");
- break;
- case LOG_FATAL:
- fprintf(stderr, "FATAL: ");
- break;
- default: /* invalid loglevel, ignore */
- break;
- }
-
- fprintf(stderr, "modpost: ");
-
- va_start(arglist, fmt);
- vfprintf(stderr, fmt, arglist);
- va_end(arglist);
-
- if (loglevel == LOG_FATAL)
- exit(1);
- if (loglevel == LOG_ERROR)
- error_occurred = true;
-}
-
-static inline bool strends(const char *str, const char *postfix)
-{
- if (strlen(str) < strlen(postfix))
- return false;
-
- return strcmp(str + strlen(str) - strlen(postfix), postfix) == 0;
-}
-
-void *do_nofail(void *ptr, const char *expr)
-{
- if (!ptr)
- fatal("Memory allocation failure: %s.\n", expr);
-
- return ptr;
-}
-
-char *read_text_file(const char *filename)
-{
- struct stat st;
- size_t nbytes;
- int fd;
- char *buf;
-
- fd = open(filename, O_RDONLY);
- if (fd < 0) {
- perror(filename);
- exit(1);
- }
-
- if (fstat(fd, &st) < 0) {
- perror(filename);
- exit(1);
- }
-
- buf = NOFAIL(malloc(st.st_size + 1));
-
- nbytes = st.st_size;
-
- while (nbytes) {
- ssize_t bytes_read;
-
- bytes_read = read(fd, buf, nbytes);
- if (bytes_read < 0) {
- perror(filename);
- exit(1);
- }
-
- nbytes -= bytes_read;
- }
- buf[st.st_size] = '\0';
-
- close(fd);
-
- return buf;
-}
-
-char *get_line(char **stringp)
-{
- char *orig = *stringp, *next;
-
- /* do not return the unwanted extra line at EOF */
- if (!orig || *orig == '\0')
- return NULL;
-
- /* don't use strsep here, it is not available everywhere */
- next = strchr(orig, '\n');
- if (next)
- *next++ = '\0';
-
- *stringp = next;
-
- return orig;
-}
-
-/* A list of all modules we processed */
-LIST_HEAD(modules);
-
-static struct module *find_module(const char *modname)
-{
- struct module *mod;
-
- list_for_each_entry(mod, &modules, list) {
- if (strcmp(mod->name, modname) == 0)
- return mod;
- }
- return NULL;
-}
-
-static struct module *new_module(const char *name, size_t namelen)
-{
- struct module *mod;
-
- mod = NOFAIL(malloc(sizeof(*mod) + namelen + 1));
- memset(mod, 0, sizeof(*mod));
-
- INIT_LIST_HEAD(&mod->exported_symbols);
- INIT_LIST_HEAD(&mod->unresolved_symbols);
- INIT_LIST_HEAD(&mod->missing_namespaces);
- INIT_LIST_HEAD(&mod->imported_namespaces);
-
- memcpy(mod->name, name, namelen);
- mod->name[namelen] = '\0';
- mod->is_vmlinux = (strcmp(mod->name, "vmlinux") == 0);
-
- /*
- * Set mod->is_gpl_compatible to true by default. If MODULE_LICENSE()
- * is missing, do not check the use for EXPORT_SYMBOL_GPL() becasue
- * modpost will exit wiht error anyway.
- */
- mod->is_gpl_compatible = true;
-
- list_add_tail(&mod->list, &modules);
-
- return mod;
-}
-
-/* A hash of all exported symbols,
- * struct symbol is also used for lists of unresolved symbols */
-
-#define SYMBOL_HASH_SIZE 1024
-
-struct symbol {
- struct symbol *next;
- struct list_head list; /* link to module::exported_symbols or module::unresolved_symbols */
- struct module *module;
- char *namespace;
- unsigned int crc;
- bool crc_valid;
- bool weak;
- bool is_gpl_only; /* exported by EXPORT_SYMBOL_GPL */
- char name[];
-};
-
-static struct symbol *symbolhash[SYMBOL_HASH_SIZE];
-
-/* This is based on the hash algorithm from gdbm, via tdb */
-static inline unsigned int tdb_hash(const char *name)
-{
- unsigned value; /* Used to compute the hash value. */
- unsigned i; /* Used to cycle through random values. */
-
- /* Set the initial value from the key size. */
- for (value = 0x238F13AF * strlen(name), i = 0; name[i]; i++)
- value = (value + (((unsigned char *)name)[i] << (i*5 % 24)));
-
- return (1103515243 * value + 12345);
-}
-
-/**
- * Allocate a new symbols for use in the hash of exported symbols or
- * the list of unresolved symbols per module
- **/
-static struct symbol *alloc_symbol(const char *name)
-{
- struct symbol *s = NOFAIL(malloc(sizeof(*s) + strlen(name) + 1));
-
- memset(s, 0, sizeof(*s));
- strcpy(s->name, name);
-
- return s;
-}
-
-/* For the hash of exported symbols */
-static void hash_add_symbol(struct symbol *sym)
-{
- unsigned int hash;
-
- hash = tdb_hash(sym->name) % SYMBOL_HASH_SIZE;
- sym->next = symbolhash[hash];
- symbolhash[hash] = sym;
-}
-
-static void sym_add_unresolved(const char *name, struct module *mod, bool weak)
-{
- struct symbol *sym;
-
- sym = alloc_symbol(name);
- sym->weak = weak;
-
- list_add_tail(&sym->list, &mod->unresolved_symbols);
-}
-
-static struct symbol *sym_find_with_module(const char *name, struct module *mod)
-{
- struct symbol *s;
-
- /* For our purposes, .foo matches foo. PPC64 needs this. */
- if (name[0] == '.')
- name++;
-
- for (s = symbolhash[tdb_hash(name) % SYMBOL_HASH_SIZE]; s; s = s->next) {
- if (strcmp(s->name, name) == 0 && (!mod || s->module == mod))
- return s;
- }
- return NULL;
-}
-
-static struct symbol *find_symbol(const char *name)
-{
- return sym_find_with_module(name, NULL);
-}
-
-struct namespace_list {
- struct list_head list;
- char namespace[];
-};
-
-static bool contains_namespace(struct list_head *head, const char *namespace)
-{
- struct namespace_list *list;
-
- list_for_each_entry(list, head, list) {
- if (!strcmp(list->namespace, namespace))
- return true;
- }
-
- return false;
-}
-
-static void add_namespace(struct list_head *head, const char *namespace)
-{
- struct namespace_list *ns_entry;
-
- if (!contains_namespace(head, namespace)) {
- ns_entry = NOFAIL(malloc(sizeof(*ns_entry) +
- strlen(namespace) + 1));
- strcpy(ns_entry->namespace, namespace);
- list_add_tail(&ns_entry->list, head);
- }
-}
-
-static void *sym_get_data_by_offset(const struct elf_info *info,
- unsigned int secindex, unsigned long offset)
-{
- Elf_Shdr *sechdr = &info->sechdrs[secindex];
-
- return (void *)info->hdr + sechdr->sh_offset + offset;
-}
-
-void *sym_get_data(const struct elf_info *info, const Elf_Sym *sym)
-{
- return sym_get_data_by_offset(info, get_secindex(info, sym),
- sym->st_value);
-}
-
-static const char *sech_name(const struct elf_info *info, Elf_Shdr *sechdr)
-{
- return sym_get_data_by_offset(info, info->secindex_strings,
- sechdr->sh_name);
-}
-
-static const char *sec_name(const struct elf_info *info, unsigned int secindex)
-{
- /*
- * If sym->st_shndx is a special section index, there is no
- * corresponding section header.
- * Return "" if the index is out of range of info->sechdrs[] array.
- */
- if (secindex >= info->num_sections)
- return "";
-
- return sech_name(info, &info->sechdrs[secindex]);
-}
-
-#define strstarts(str, prefix) (strncmp(str, prefix, strlen(prefix)) == 0)
-
-static void sym_update_namespace(const char *symname, const char *namespace)
-{
- struct symbol *s = find_symbol(symname);
-
- /*
- * That symbol should have been created earlier and thus this is
- * actually an assertion.
- */
- if (!s) {
- error("Could not update namespace(%s) for symbol %s\n",
- namespace, symname);
- return;
- }
-
- free(s->namespace);
- s->namespace = namespace[0] ? NOFAIL(strdup(namespace)) : NULL;
-}
-
-static struct symbol *sym_add_exported(const char *name, struct module *mod,
- bool gpl_only)
-{
- struct symbol *s = find_symbol(name);
-
- if (s && (!external_module || s->module->is_vmlinux || s->module == mod)) {
- error("%s: '%s' exported twice. Previous export was in %s%s\n",
- mod->name, name, s->module->name,
- s->module->is_vmlinux ? "" : ".ko");
- }
-
- s = alloc_symbol(name);
- s->module = mod;
- s->is_gpl_only = gpl_only;
- list_add_tail(&s->list, &mod->exported_symbols);
- hash_add_symbol(s);
-
- return s;
-}
-
-static void sym_set_crc(struct symbol *sym, unsigned int crc)
-{
- sym->crc = crc;
- sym->crc_valid = true;
-}
-
-static void *grab_file(const char *filename, size_t *size)
-{
- struct stat st;
- void *map = MAP_FAILED;
- int fd;
-
- fd = open(filename, O_RDONLY);
- if (fd < 0)
- return NULL;
- if (fstat(fd, &st))
- goto failed;
-
- *size = st.st_size;
- map = mmap(NULL, *size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
-
-failed:
- close(fd);
- if (map == MAP_FAILED)
- return NULL;
- return map;
-}
-
-static void release_file(void *file, size_t size)
-{
- munmap(file, size);
-}
-
-static int parse_elf(struct elf_info *info, const char *filename)
-{
- unsigned int i;
- Elf_Ehdr *hdr;
- Elf_Shdr *sechdrs;
- Elf_Sym *sym;
- const char *secstrings;
- unsigned int symtab_idx = ~0U, symtab_shndx_idx = ~0U;
-
- hdr = grab_file(filename, &info->size);
- if (!hdr) {
- if (ignore_missing_files) {
- fprintf(stderr, "%s: %s (ignored)\n", filename,
- strerror(errno));
- return 0;
- }
- perror(filename);
- exit(1);
- }
- info->hdr = hdr;
- if (info->size < sizeof(*hdr)) {
- /* file too small, assume this is an empty .o file */
- return 0;
- }
- /* Is this a valid ELF file? */
- if ((hdr->e_ident[EI_MAG0] != ELFMAG0) ||
- (hdr->e_ident[EI_MAG1] != ELFMAG1) ||
- (hdr->e_ident[EI_MAG2] != ELFMAG2) ||
- (hdr->e_ident[EI_MAG3] != ELFMAG3)) {
- /* Not an ELF file - silently ignore it */
- return 0;
- }
- /* Fix endianness in ELF header */
- hdr->e_type = TO_NATIVE(hdr->e_type);
- hdr->e_machine = TO_NATIVE(hdr->e_machine);
- hdr->e_version = TO_NATIVE(hdr->e_version);
- hdr->e_entry = TO_NATIVE(hdr->e_entry);
- hdr->e_phoff = TO_NATIVE(hdr->e_phoff);
- hdr->e_shoff = TO_NATIVE(hdr->e_shoff);
- hdr->e_flags = TO_NATIVE(hdr->e_flags);
- hdr->e_ehsize = TO_NATIVE(hdr->e_ehsize);
- hdr->e_phentsize = TO_NATIVE(hdr->e_phentsize);
- hdr->e_phnum = TO_NATIVE(hdr->e_phnum);
- hdr->e_shentsize = TO_NATIVE(hdr->e_shentsize);
- hdr->e_shnum = TO_NATIVE(hdr->e_shnum);
- hdr->e_shstrndx = TO_NATIVE(hdr->e_shstrndx);
- sechdrs = (void *)hdr + hdr->e_shoff;
- info->sechdrs = sechdrs;
-
- /* modpost only works for relocatable objects */
- if (hdr->e_type != ET_REL)
- fatal("%s: not relocatable object.", filename);
-
- /* Check if file offset is correct */
- if (hdr->e_shoff > info->size) {
- fatal("section header offset=%lu in file '%s' is bigger than filesize=%zu\n",
- (unsigned long)hdr->e_shoff, filename, info->size);
- return 0;
- }
-
- if (hdr->e_shnum == SHN_UNDEF) {
- /*
- * There are more than 64k sections,
- * read count from .sh_size.
- */
- info->num_sections = TO_NATIVE(sechdrs[0].sh_size);
- }
- else {
- info->num_sections = hdr->e_shnum;
- }
- if (hdr->e_shstrndx == SHN_XINDEX) {
- info->secindex_strings = TO_NATIVE(sechdrs[0].sh_link);
- }
- else {
- info->secindex_strings = hdr->e_shstrndx;
- }
-
- /* Fix endianness in section headers */
- for (i = 0; i < info->num_sections; i++) {
- sechdrs[i].sh_name = TO_NATIVE(sechdrs[i].sh_name);
- sechdrs[i].sh_type = TO_NATIVE(sechdrs[i].sh_type);
- sechdrs[i].sh_flags = TO_NATIVE(sechdrs[i].sh_flags);
- sechdrs[i].sh_addr = TO_NATIVE(sechdrs[i].sh_addr);
- sechdrs[i].sh_offset = TO_NATIVE(sechdrs[i].sh_offset);
- sechdrs[i].sh_size = TO_NATIVE(sechdrs[i].sh_size);
- sechdrs[i].sh_link = TO_NATIVE(sechdrs[i].sh_link);
- sechdrs[i].sh_info = TO_NATIVE(sechdrs[i].sh_info);
- sechdrs[i].sh_addralign = TO_NATIVE(sechdrs[i].sh_addralign);
- sechdrs[i].sh_entsize = TO_NATIVE(sechdrs[i].sh_entsize);
- }
- /* Find symbol table. */
- secstrings = (void *)hdr + sechdrs[info->secindex_strings].sh_offset;
- for (i = 1; i < info->num_sections; i++) {
- const char *secname;
- int nobits = sechdrs[i].sh_type == SHT_NOBITS;
-
- if (!nobits && sechdrs[i].sh_offset > info->size) {
- fatal("%s is truncated. sechdrs[i].sh_offset=%lu > "
- "sizeof(*hrd)=%zu\n", filename,
- (unsigned long)sechdrs[i].sh_offset,
- sizeof(*hdr));
- return 0;
- }
- secname = secstrings + sechdrs[i].sh_name;
- if (strcmp(secname, ".modinfo") == 0) {
- if (nobits)
- fatal("%s has NOBITS .modinfo\n", filename);
- info->modinfo = (void *)hdr + sechdrs[i].sh_offset;
- info->modinfo_len = sechdrs[i].sh_size;
- }
-
- if (sechdrs[i].sh_type == SHT_SYMTAB) {
- unsigned int sh_link_idx;
- symtab_idx = i;
- info->symtab_start = (void *)hdr +
- sechdrs[i].sh_offset;
- info->symtab_stop = (void *)hdr +
- sechdrs[i].sh_offset + sechdrs[i].sh_size;
- sh_link_idx = sechdrs[i].sh_link;
- info->strtab = (void *)hdr +
- sechdrs[sh_link_idx].sh_offset;
- }
-
- /* 32bit section no. table? ("more than 64k sections") */
- if (sechdrs[i].sh_type == SHT_SYMTAB_SHNDX) {
- symtab_shndx_idx = i;
- info->symtab_shndx_start = (void *)hdr +
- sechdrs[i].sh_offset;
- info->symtab_shndx_stop = (void *)hdr +
- sechdrs[i].sh_offset + sechdrs[i].sh_size;
- }
- }
- if (!info->symtab_start)
- fatal("%s has no symtab?\n", filename);
-
- /* Fix endianness in symbols */
- for (sym = info->symtab_start; sym < info->symtab_stop; sym++) {
- sym->st_shndx = TO_NATIVE(sym->st_shndx);
- sym->st_name = TO_NATIVE(sym->st_name);
- sym->st_value = TO_NATIVE(sym->st_value);
- sym->st_size = TO_NATIVE(sym->st_size);
- }
-
- if (symtab_shndx_idx != ~0U) {
- Elf32_Word *p;
- if (symtab_idx != sechdrs[symtab_shndx_idx].sh_link)
- fatal("%s: SYMTAB_SHNDX has bad sh_link: %u!=%u\n",
- filename, sechdrs[symtab_shndx_idx].sh_link,
- symtab_idx);
- /* Fix endianness */
- for (p = info->symtab_shndx_start; p < info->symtab_shndx_stop;
- p++)
- *p = TO_NATIVE(*p);
- }
-
- return 1;
-}
-
-static void parse_elf_finish(struct elf_info *info)
-{
- release_file(info->hdr, info->size);
-}
-
-static int ignore_undef_symbol(struct elf_info *info, const char *symname)
-{
- /* ignore __this_module, it will be resolved shortly */
- if (strcmp(symname, "__this_module") == 0)
- return 1;
- /* ignore global offset table */
- if (strcmp(symname, "_GLOBAL_OFFSET_TABLE_") == 0)
- return 1;
- if (info->hdr->e_machine == EM_PPC)
- /* Special register function linked on all modules during final link of .ko */
- if (strstarts(symname, "_restgpr_") ||
- strstarts(symname, "_savegpr_") ||
- strstarts(symname, "_rest32gpr_") ||
- strstarts(symname, "_save32gpr_") ||
- strstarts(symname, "_restvr_") ||
- strstarts(symname, "_savevr_"))
- return 1;
- if (info->hdr->e_machine == EM_PPC64)
- /* Special register function linked on all modules during final link of .ko */
- if (strstarts(symname, "_restgpr0_") ||
- strstarts(symname, "_savegpr0_") ||
- strstarts(symname, "_restvr_") ||
- strstarts(symname, "_savevr_") ||
- strcmp(symname, ".TOC.") == 0)
- return 1;
-
- if (info->hdr->e_machine == EM_S390)
- /* Expoline thunks are linked on all kernel modules during final link of .ko */
- if (strstarts(symname, "__s390_indirect_jump_r"))
- return 1;
- /* Do not ignore this symbol */
- return 0;
-}
-
-static void handle_symbol(struct module *mod, struct elf_info *info,
- const Elf_Sym *sym, const char *symname)
-{
- switch (sym->st_shndx) {
- case SHN_COMMON:
- if (strstarts(symname, "__gnu_lto_")) {
- /* Should warn here, but modpost runs before the linker */
- } else
- warn("\"%s\" [%s] is COMMON symbol\n", symname, mod->name);
- break;
- case SHN_UNDEF:
- /* undefined symbol */
- if (ELF_ST_BIND(sym->st_info) != STB_GLOBAL &&
- ELF_ST_BIND(sym->st_info) != STB_WEAK)
- break;
- if (ignore_undef_symbol(info, symname))
- break;
- if (info->hdr->e_machine == EM_SPARC ||
- info->hdr->e_machine == EM_SPARCV9) {
- /* Ignore register directives. */
- if (ELF_ST_TYPE(sym->st_info) == STT_SPARC_REGISTER)
- break;
- if (symname[0] == '.') {
- char *munged = NOFAIL(strdup(symname));
- munged[0] = '_';
- munged[1] = toupper(munged[1]);
- symname = munged;
- }
- }
-
- sym_add_unresolved(symname, mod,
- ELF_ST_BIND(sym->st_info) == STB_WEAK);
- break;
- default:
- /* All exported symbols */
- if (strstarts(symname, "__ksymtab_")) {
- const char *name, *secname;
-
- name = symname + strlen("__ksymtab_");
- secname = sec_name(info, get_secindex(info, sym));
-
- if (strstarts(secname, "___ksymtab_gpl+"))
- sym_add_exported(name, mod, true);
- else if (strstarts(secname, "___ksymtab+"))
- sym_add_exported(name, mod, false);
- }
- if (strcmp(symname, "init_module") == 0)
- mod->has_init = true;
- if (strcmp(symname, "cleanup_module") == 0)
- mod->has_cleanup = true;
- break;
- }
-}
-
-/**
- * Parse tag=value strings from .modinfo section
- **/
-static char *next_string(char *string, unsigned long *secsize)
-{
- /* Skip non-zero chars */
- while (string[0]) {
- string++;
- if ((*secsize)-- <= 1)
- return NULL;
- }
-
- /* Skip any zero padding. */
- while (!string[0]) {
- string++;
- if ((*secsize)-- <= 1)
- return NULL;
- }
- return string;
-}
-
-static char *get_next_modinfo(struct elf_info *info, const char *tag,
- char *prev)
-{
- char *p;
- unsigned int taglen = strlen(tag);
- char *modinfo = info->modinfo;
- unsigned long size = info->modinfo_len;
-
- if (prev) {
- size -= prev - modinfo;
- modinfo = next_string(prev, &size);
- }
-
- for (p = modinfo; p; p = next_string(p, &size)) {
- if (strncmp(p, tag, taglen) == 0 && p[taglen] == '=')
- return p + taglen + 1;
- }
- return NULL;
-}
-
-static char *get_modinfo(struct elf_info *info, const char *tag)
-
-{
- return get_next_modinfo(info, tag, NULL);
-}
-
-static const char *sym_name(struct elf_info *elf, Elf_Sym *sym)
-{
- if (sym)
- return elf->strtab + sym->st_name;
- else
- return "(unknown)";
-}
-
-/*
- * Check whether the 'string' argument matches one of the 'patterns',
- * an array of shell wildcard patterns (glob).
- *
- * Return true is there is a match.
- */
-static bool match(const char *string, const char *const patterns[])
-{
- const char *pattern;
-
- while ((pattern = *patterns++)) {
- if (!fnmatch(pattern, string, 0))
- return true;
- }
-
- return false;
-}
-
-/* useful to pass patterns to match() directly */
-#define PATTERNS(...) \
- ({ \
- static const char *const patterns[] = {__VA_ARGS__, NULL}; \
- patterns; \
- })
-
-/* sections that we do not want to do full section mismatch check on */
-static const char *const section_white_list[] =
-{
- ".comment*",
- ".debug*",
- ".zdebug*", /* Compressed debug sections. */
- ".GCC.command.line", /* record-gcc-switches */
- ".mdebug*", /* alpha, score, mips etc. */
- ".pdr", /* alpha, score, mips etc. */
- ".stab*",
- ".note*",
- ".got*",
- ".toc*",
- ".xt.prop", /* xtensa */
- ".xt.lit", /* xtensa */
- ".arcextmap*", /* arc */
- ".gnu.linkonce.arcext*", /* arc : modules */
- ".cmem*", /* EZchip */
- ".fmt_slot*", /* EZchip */
- ".gnu.lto*",
- ".discard.*",
- NULL
-};
-
-/*
- * This is used to find sections missing the SHF_ALLOC flag.
- * The cause of this is often a section specified in assembler
- * without "ax" / "aw".
- */
-static void check_section(const char *modname, struct elf_info *elf,
- Elf_Shdr *sechdr)
-{
- const char *sec = sech_name(elf, sechdr);
-
- if (sechdr->sh_type == SHT_PROGBITS &&
- !(sechdr->sh_flags & SHF_ALLOC) &&
- !match(sec, section_white_list)) {
- warn("%s (%s): unexpected non-allocatable section.\n"
- "Did you forget to use \"ax\"/\"aw\" in a .S file?\n"
- "Note that for example <linux/init.h> contains\n"
- "section definitions for use in .S files.\n\n",
- modname, sec);
- }
-}
-
-
-
-#define ALL_INIT_DATA_SECTIONS \
- ".init.setup", ".init.rodata", ".meminit.rodata", \
- ".init.data", ".meminit.data"
-#define ALL_EXIT_DATA_SECTIONS \
- ".exit.data", ".memexit.data"
-
-#define ALL_INIT_TEXT_SECTIONS \
- ".init.text", ".meminit.text"
-#define ALL_EXIT_TEXT_SECTIONS \
- ".exit.text", ".memexit.text"
-
-#define ALL_PCI_INIT_SECTIONS \
- ".pci_fixup_early", ".pci_fixup_header", ".pci_fixup_final", \
- ".pci_fixup_enable", ".pci_fixup_resume", \
- ".pci_fixup_resume_early", ".pci_fixup_suspend"
-
-#define ALL_XXXINIT_SECTIONS MEM_INIT_SECTIONS
-#define ALL_XXXEXIT_SECTIONS MEM_EXIT_SECTIONS
-
-#define ALL_INIT_SECTIONS INIT_SECTIONS, ALL_XXXINIT_SECTIONS
-#define ALL_EXIT_SECTIONS EXIT_SECTIONS, ALL_XXXEXIT_SECTIONS
-
-#define DATA_SECTIONS ".data", ".data.rel"
-#define TEXT_SECTIONS ".text", ".text.unlikely", ".sched.text", \
- ".kprobes.text", ".cpuidle.text", ".noinstr.text"
-#define OTHER_TEXT_SECTIONS ".ref.text", ".head.text", ".spinlock.text", \
- ".fixup", ".entry.text", ".exception.text", ".text.*", \
- ".coldtext", ".softirqentry.text"
-
-#define INIT_SECTIONS ".init.*"
-#define MEM_INIT_SECTIONS ".meminit.*"
-
-#define EXIT_SECTIONS ".exit.*"
-#define MEM_EXIT_SECTIONS ".memexit.*"
-
-#define ALL_TEXT_SECTIONS ALL_INIT_TEXT_SECTIONS, ALL_EXIT_TEXT_SECTIONS, \
- TEXT_SECTIONS, OTHER_TEXT_SECTIONS
-
-/* init data sections */
-static const char *const init_data_sections[] =
- { ALL_INIT_DATA_SECTIONS, NULL };
-
-/* all init sections */
-static const char *const init_sections[] = { ALL_INIT_SECTIONS, NULL };
-
-/* all text sections */
-static const char *const text_sections[] = { ALL_TEXT_SECTIONS, NULL };
-
-/* data section */
-static const char *const data_sections[] = { DATA_SECTIONS, NULL };
-
-static const char *const head_sections[] = { ".head.text*", NULL };
-static const char *const linker_symbols[] =
- { "__init_begin", "_sinittext", "_einittext", NULL };
-static const char *const optim_symbols[] = { "*.constprop.*", NULL };
-
-enum mismatch {
- TEXT_TO_ANY_INIT,
- DATA_TO_ANY_INIT,
- TEXT_TO_ANY_EXIT,
- DATA_TO_ANY_EXIT,
- XXXINIT_TO_SOME_INIT,
- XXXEXIT_TO_SOME_EXIT,
- ANY_INIT_TO_ANY_EXIT,
- ANY_EXIT_TO_ANY_INIT,
- EXPORT_TO_INIT_EXIT,
- EXTABLE_TO_NON_TEXT,
-};
-
-/**
- * Describe how to match sections on different criteria:
- *
- * @fromsec: Array of sections to be matched.
- *
- * @bad_tosec: Relocations applied to a section in @fromsec to a section in
- * this array is forbidden (black-list). Can be empty.
- *
- * @good_tosec: Relocations applied to a section in @fromsec must be
- * targeting sections in this array (white-list). Can be empty.
- *
- * @mismatch: Type of mismatch.
- *
- * @handler: Specific handler to call when a match is found. If NULL,
- * default_mismatch_handler() will be called.
- *
- */
-struct sectioncheck {
- const char *fromsec[20];
- const char *bad_tosec[20];
- const char *good_tosec[20];
- enum mismatch mismatch;
- void (*handler)(const char *modname, struct elf_info *elf,
- const struct sectioncheck* const mismatch,
- Elf_Rela *r, Elf_Sym *sym, const char *fromsec);
-
-};
-
-static void extable_mismatch_handler(const char *modname, struct elf_info *elf,
- const struct sectioncheck* const mismatch,
- Elf_Rela *r, Elf_Sym *sym,
- const char *fromsec);
-
-static const struct sectioncheck sectioncheck[] = {
-/* Do not reference init/exit code/data from
- * normal code and data
- */
-{
- .fromsec = { TEXT_SECTIONS, NULL },
- .bad_tosec = { ALL_INIT_SECTIONS, NULL },
- .mismatch = TEXT_TO_ANY_INIT,
-},
-{
- .fromsec = { DATA_SECTIONS, NULL },
- .bad_tosec = { ALL_XXXINIT_SECTIONS, NULL },
- .mismatch = DATA_TO_ANY_INIT,
-},
-{
- .fromsec = { DATA_SECTIONS, NULL },
- .bad_tosec = { INIT_SECTIONS, NULL },
- .mismatch = DATA_TO_ANY_INIT,
-},
-{
- .fromsec = { TEXT_SECTIONS, NULL },
- .bad_tosec = { ALL_EXIT_SECTIONS, NULL },
- .mismatch = TEXT_TO_ANY_EXIT,
-},
-{
- .fromsec = { DATA_SECTIONS, NULL },
- .bad_tosec = { ALL_EXIT_SECTIONS, NULL },
- .mismatch = DATA_TO_ANY_EXIT,
-},
-/* Do not reference init code/data from meminit code/data */
-{
- .fromsec = { ALL_XXXINIT_SECTIONS, NULL },
- .bad_tosec = { INIT_SECTIONS, NULL },
- .mismatch = XXXINIT_TO_SOME_INIT,
-},
-/* Do not reference exit code/data from memexit code/data */
-{
- .fromsec = { ALL_XXXEXIT_SECTIONS, NULL },
- .bad_tosec = { EXIT_SECTIONS, NULL },
- .mismatch = XXXEXIT_TO_SOME_EXIT,
-},
-/* Do not use exit code/data from init code */
-{
- .fromsec = { ALL_INIT_SECTIONS, NULL },
- .bad_tosec = { ALL_EXIT_SECTIONS, NULL },
- .mismatch = ANY_INIT_TO_ANY_EXIT,
-},
-/* Do not use init code/data from exit code */
-{
- .fromsec = { ALL_EXIT_SECTIONS, NULL },
- .bad_tosec = { ALL_INIT_SECTIONS, NULL },
- .mismatch = ANY_EXIT_TO_ANY_INIT,
-},
-{
- .fromsec = { ALL_PCI_INIT_SECTIONS, NULL },
- .bad_tosec = { INIT_SECTIONS, NULL },
- .mismatch = ANY_INIT_TO_ANY_EXIT,
-},
-/* Do not export init/exit functions or data */
-{
- .fromsec = { "___ksymtab*", NULL },
- .bad_tosec = { INIT_SECTIONS, EXIT_SECTIONS, NULL },
- .mismatch = EXPORT_TO_INIT_EXIT,
-},
-{
- .fromsec = { "__ex_table", NULL },
- /* If you're adding any new black-listed sections in here, consider
- * adding a special 'printer' for them in scripts/check_extable.
- */
- .bad_tosec = { ".altinstr_replacement", NULL },
- .good_tosec = {ALL_TEXT_SECTIONS , NULL},
- .mismatch = EXTABLE_TO_NON_TEXT,
- .handler = extable_mismatch_handler,
-}
-};
-
-static const struct sectioncheck *section_mismatch(
- const char *fromsec, const char *tosec)
-{
- int i;
-
- /*
- * The target section could be the SHT_NUL section when we're
- * handling relocations to un-resolved symbols, trying to match it
- * doesn't make much sense and causes build failures on parisc
- * architectures.
- */
- if (*tosec == '\0')
- return NULL;
-
- for (i = 0; i < ARRAY_SIZE(sectioncheck); i++) {
- const struct sectioncheck *check = §ioncheck[i];
-
- if (match(fromsec, check->fromsec)) {
- if (check->bad_tosec[0] && match(tosec, check->bad_tosec))
- return check;
- if (check->good_tosec[0] && !match(tosec, check->good_tosec))
- return check;
- }
- }
- return NULL;
-}
-
-/**
- * Whitelist to allow certain references to pass with no warning.
- *
- * Pattern 1:
- * If a module parameter is declared __initdata and permissions=0
- * then this is legal despite the warning generated.
- * We cannot see value of permissions here, so just ignore
- * this pattern.
- * The pattern is identified by:
- * tosec = .init.data
- * fromsec = .data*
- * atsym =__param*
- *
- * Pattern 1a:
- * module_param_call() ops can refer to __init set function if permissions=0
- * The pattern is identified by:
- * tosec = .init.text
- * fromsec = .data*
- * atsym = __param_ops_*
- *
- * Pattern 3:
- * Whitelist all references from .head.text to any init section
- *
- * Pattern 4:
- * Some symbols belong to init section but still it is ok to reference
- * these from non-init sections as these symbols don't have any memory
- * allocated for them and symbol address and value are same. So even
- * if init section is freed, its ok to reference those symbols.
- * For ex. symbols marking the init section boundaries.
- * This pattern is identified by
- * refsymname = __init_begin, _sinittext, _einittext
- *
- * Pattern 5:
- * GCC may optimize static inlines when fed constant arg(s) resulting
- * in functions like cpumask_empty() -- generating an associated symbol
- * cpumask_empty.constprop.3 that appears in the audit. If the const that
- * is passed in comes from __init, like say nmi_ipi_mask, we get a
- * meaningless section warning. May need to add isra symbols too...
- * This pattern is identified by
- * tosec = init section
- * fromsec = text section
- * refsymname = *.constprop.*
- *
- * Pattern 6:
- * Hide section mismatch warnings for ELF local symbols. The goal
- * is to eliminate false positive modpost warnings caused by
- * compiler-generated ELF local symbol names such as ".LANCHOR1".
- * Autogenerated symbol names bypass modpost's "Pattern 2"
- * whitelisting, which relies on pattern-matching against symbol
- * names to work. (One situation where gcc can autogenerate ELF
- * local symbols is when "-fsection-anchors" is used.)
- **/
-static int secref_whitelist(const struct sectioncheck *mismatch,
- const char *fromsec, const char *fromsym,
- const char *tosec, const char *tosym)
-{
- /* Check for pattern 1 */
- if (match(tosec, init_data_sections) &&
- match(fromsec, data_sections) &&
- strstarts(fromsym, "__param"))
- return 0;
-
- /* Check for pattern 1a */
- if (strcmp(tosec, ".init.text") == 0 &&
- match(fromsec, data_sections) &&
- strstarts(fromsym, "__param_ops_"))
- return 0;
-
- /* symbols in data sections that may refer to any init/exit sections */
- if (match(fromsec, PATTERNS(DATA_SECTIONS)) &&
- match(tosec, PATTERNS(ALL_INIT_SECTIONS, ALL_EXIT_SECTIONS)) &&
- match(fromsym, PATTERNS("*_template", // scsi uses *_template a lot
- "*_timer", // arm uses ops structures named _timer a lot
- "*_sht", // scsi also used *_sht to some extent
- "*_ops",
- "*_probe",
- "*_probe_one",
- "*_console")))
- return 0;
-
- /* symbols in data sections that may refer to meminit/exit sections */
- if (match(fromsec, PATTERNS(DATA_SECTIONS)) &&
- match(tosec, PATTERNS(ALL_XXXINIT_SECTIONS, ALL_EXIT_SECTIONS)) &&
- match(fromsym, PATTERNS("*driver")))
- return 0;
-
- /* Check for pattern 3 */
- if (match(fromsec, head_sections) &&
- match(tosec, init_sections))
- return 0;
-
- /* Check for pattern 4 */
- if (match(tosym, linker_symbols))
- return 0;
-
- /* Check for pattern 5 */
- if (match(fromsec, text_sections) &&
- match(tosec, init_sections) &&
- match(fromsym, optim_symbols))
- return 0;
-
- /* Check for pattern 6 */
- if (strstarts(fromsym, ".L"))
- return 0;
-
- return 1;
-}
-
-static inline int is_arm_mapping_symbol(const char *str)
-{
- return str[0] == '$' &&
- (str[1] == 'a' || str[1] == 'd' || str[1] == 't' || str[1] == 'x')
- && (str[2] == '\0' || str[2] == '.');
-}
-
-/*
- * If there's no name there, ignore it; likewise, ignore it if it's
- * one of the magic symbols emitted used by current ARM tools.
- *
- * Otherwise if find_symbols_between() returns those symbols, they'll
- * fail the whitelist tests and cause lots of false alarms ... fixable
- * only by merging __exit and __init sections into __text, bloating
- * the kernel (which is especially evil on embedded platforms).
- */
-static inline int is_valid_name(struct elf_info *elf, Elf_Sym *sym)
-{
- const char *name = elf->strtab + sym->st_name;
-
- if (!name || !strlen(name))
- return 0;
- return !is_arm_mapping_symbol(name);
-}
-
-/**
- * Find symbol based on relocation record info.
- * In some cases the symbol supplied is a valid symbol so
- * return refsym. If st_name != 0 we assume this is a valid symbol.
- * In other cases the symbol needs to be looked up in the symbol table
- * based on section and address.
- * **/
-static Elf_Sym *find_elf_symbol(struct elf_info *elf, Elf64_Sword addr,
- Elf_Sym *relsym)
-{
- Elf_Sym *sym;
- Elf_Sym *near = NULL;
- Elf64_Sword distance = 20;
- Elf64_Sword d;
- unsigned int relsym_secindex;
-
- if (relsym->st_name != 0)
- return relsym;
-
- relsym_secindex = get_secindex(elf, relsym);
- for (sym = elf->symtab_start; sym < elf->symtab_stop; sym++) {
- if (get_secindex(elf, sym) != relsym_secindex)
- continue;
- if (ELF_ST_TYPE(sym->st_info) == STT_SECTION)
- continue;
- if (!is_valid_name(elf, sym))
- continue;
- if (sym->st_value == addr)
- return sym;
- /* Find a symbol nearby - addr are maybe negative */
- d = sym->st_value - addr;
- if (d < 0)
- d = addr - sym->st_value;
- if (d < distance) {
- distance = d;
- near = sym;
- }
- }
- /* We need a close match */
- if (distance < 20)
- return near;
- else
- return NULL;
-}
-
-/*
- * Find symbols before or equal addr and after addr - in the section sec.
- * If we find two symbols with equal offset prefer one with a valid name.
- * The ELF format may have a better way to detect what type of symbol
- * it is, but this works for now.
- **/
-static Elf_Sym *find_elf_symbol2(struct elf_info *elf, Elf_Addr addr,
- const char *sec)
-{
- Elf_Sym *sym;
- Elf_Sym *near = NULL;
- Elf_Addr distance = ~0;
-
- for (sym = elf->symtab_start; sym < elf->symtab_stop; sym++) {
- const char *symsec;
-
- if (is_shndx_special(sym->st_shndx))
- continue;
- symsec = sec_name(elf, get_secindex(elf, sym));
- if (strcmp(symsec, sec) != 0)
- continue;
- if (!is_valid_name(elf, sym))
- continue;
- if (sym->st_value <= addr && addr - sym->st_value <= distance) {
- distance = addr - sym->st_value;
- near = sym;
- }
- }
- return near;
-}
-
-static int is_function(Elf_Sym *sym)
-{
- if (sym)
- return ELF_ST_TYPE(sym->st_info) == STT_FUNC;
- else
- return -1;
-}
-
-static inline void get_pretty_name(int is_func, const char** name, const char** name_p)
-{
- switch (is_func) {
- case 0: *name = "variable"; *name_p = ""; break;
- case 1: *name = "function"; *name_p = "()"; break;
- default: *name = "(unknown reference)"; *name_p = ""; break;
- }
-}
-
-/*
- * Print a warning about a section mismatch.
- * Try to find symbols near it so user can find it.
- * Check whitelist before warning - it may be a false positive.
- */
-static void report_sec_mismatch(const char *modname,
- const struct sectioncheck *mismatch,
- const char *fromsec,
- const char *fromsym,
- const char *tosec, const char *tosym)
-{
- sec_mismatch_count++;
-
- switch (mismatch->mismatch) {
- case TEXT_TO_ANY_INIT:
- case DATA_TO_ANY_INIT:
- case TEXT_TO_ANY_EXIT:
- case DATA_TO_ANY_EXIT:
- case XXXINIT_TO_SOME_INIT:
- case XXXEXIT_TO_SOME_EXIT:
- case ANY_INIT_TO_ANY_EXIT:
- case ANY_EXIT_TO_ANY_INIT:
- warn("%s: section mismatch in reference: %s (section: %s) -> %s (section: %s)\n",
- modname, fromsym, fromsec, tosym, tosec);
- break;
- case EXPORT_TO_INIT_EXIT:
- warn("%s: EXPORT_SYMBOL used for init/exit symbol: %s (section: %s)\n",
- modname, tosym, tosec);
- break;
- case EXTABLE_TO_NON_TEXT:
- fatal("There's a special handler for this mismatch type, we should never get here.\n");
- break;
- }
-}
-
-static void default_mismatch_handler(const char *modname, struct elf_info *elf,
- const struct sectioncheck* const mismatch,
- Elf_Rela *r, Elf_Sym *sym, const char *fromsec)
-{
- const char *tosec;
- Elf_Sym *to;
- Elf_Sym *from;
- const char *tosym;
- const char *fromsym;
-
- from = find_elf_symbol2(elf, r->r_offset, fromsec);
- fromsym = sym_name(elf, from);
-
- tosec = sec_name(elf, get_secindex(elf, sym));
- to = find_elf_symbol(elf, r->r_addend, sym);
- tosym = sym_name(elf, to);
-
- /* check whitelist - we may ignore it */
- if (secref_whitelist(mismatch,
- fromsec, fromsym, tosec, tosym)) {
- report_sec_mismatch(modname, mismatch,
- fromsec, fromsym, tosec, tosym);
- }
-}
-
-static int is_executable_section(struct elf_info* elf, unsigned int section_index)
-{
- if (section_index > elf->num_sections)
- fatal("section_index is outside elf->num_sections!\n");
-
- return ((elf->sechdrs[section_index].sh_flags & SHF_EXECINSTR) == SHF_EXECINSTR);
-}
-
-/*
- * We rely on a gross hack in section_rel[a]() calling find_extable_entry_size()
- * to know the sizeof(struct exception_table_entry) for the target architecture.
- */
-static unsigned int extable_entry_size = 0;
-static void find_extable_entry_size(const char* const sec, const Elf_Rela* r)
-{
- /*
- * If we're currently checking the second relocation within __ex_table,
- * that relocation offset tells us the offsetof(struct
- * exception_table_entry, fixup) which is equal to sizeof(struct
- * exception_table_entry) divided by two. We use that to our advantage
- * since there's no portable way to get that size as every architecture
- * seems to go with different sized types. Not pretty but better than
- * hard-coding the size for every architecture..
- */
- if (!extable_entry_size)
- extable_entry_size = r->r_offset * 2;
-}
-
-static inline bool is_extable_fault_address(Elf_Rela *r)
-{
- /*
- * extable_entry_size is only discovered after we've handled the
- * _second_ relocation in __ex_table, so only abort when we're not
- * handling the first reloc and extable_entry_size is zero.
- */
- if (r->r_offset && extable_entry_size == 0)
- fatal("extable_entry size hasn't been discovered!\n");
-
- return ((r->r_offset == 0) ||
- (r->r_offset % extable_entry_size == 0));
-}
-
-#define is_second_extable_reloc(Start, Cur, Sec) \
- (((Cur) == (Start) + 1) && (strcmp("__ex_table", (Sec)) == 0))
-
-static void report_extable_warnings(const char* modname, struct elf_info* elf,
- const struct sectioncheck* const mismatch,
- Elf_Rela* r, Elf_Sym* sym,
- const char* fromsec, const char* tosec)
-{
- Elf_Sym* fromsym = find_elf_symbol2(elf, r->r_offset, fromsec);
- const char* fromsym_name = sym_name(elf, fromsym);
- Elf_Sym* tosym = find_elf_symbol(elf, r->r_addend, sym);
- const char* tosym_name = sym_name(elf, tosym);
- const char* from_pretty_name;
- const char* from_pretty_name_p;
- const char* to_pretty_name;
- const char* to_pretty_name_p;
-
- get_pretty_name(is_function(fromsym),
- &from_pretty_name, &from_pretty_name_p);
- get_pretty_name(is_function(tosym),
- &to_pretty_name, &to_pretty_name_p);
-
- warn("%s(%s+0x%lx): Section mismatch in reference"
- " from the %s %s%s to the %s %s:%s%s\n",
- modname, fromsec, (long)r->r_offset, from_pretty_name,
- fromsym_name, from_pretty_name_p,
- to_pretty_name, tosec, tosym_name, to_pretty_name_p);
-
- if (!match(tosec, mismatch->bad_tosec) &&
- is_executable_section(elf, get_secindex(elf, sym)))
- fprintf(stderr,
- "The relocation at %s+0x%lx references\n"
- "section \"%s\" which is not in the list of\n"
- "authorized sections. If you're adding a new section\n"
- "and/or if this reference is valid, add \"%s\" to the\n"
- "list of authorized sections to jump to on fault.\n"
- "This can be achieved by adding \"%s\" to \n"
- "OTHER_TEXT_SECTIONS in scripts/mod/modpost.c.\n",
- fromsec, (long)r->r_offset, tosec, tosec, tosec);
-}
-
-static void extable_mismatch_handler(const char* modname, struct elf_info *elf,
- const struct sectioncheck* const mismatch,
- Elf_Rela* r, Elf_Sym* sym,
- const char *fromsec)
-{
- const char* tosec = sec_name(elf, get_secindex(elf, sym));
-
- sec_mismatch_count++;
-
- report_extable_warnings(modname, elf, mismatch, r, sym, fromsec, tosec);
-
- if (match(tosec, mismatch->bad_tosec))
- fatal("The relocation at %s+0x%lx references\n"
- "section \"%s\" which is black-listed.\n"
- "Something is seriously wrong and should be fixed.\n"
- "You might get more information about where this is\n"
- "coming from by using scripts/check_extable.sh %s\n",
- fromsec, (long)r->r_offset, tosec, modname);
- else if (!is_executable_section(elf, get_secindex(elf, sym))) {
- if (is_extable_fault_address(r))
- fatal("The relocation at %s+0x%lx references\n"
- "section \"%s\" which is not executable, IOW\n"
- "it is not possible for the kernel to fault\n"
- "at that address. Something is seriously wrong\n"
- "and should be fixed.\n",
- fromsec, (long)r->r_offset, tosec);
- else
- fatal("The relocation at %s+0x%lx references\n"
- "section \"%s\" which is not executable, IOW\n"
- "the kernel will fault if it ever tries to\n"
- "jump to it. Something is seriously wrong\n"
- "and should be fixed.\n",
- fromsec, (long)r->r_offset, tosec);
- }
-}
-
-static void check_section_mismatch(const char *modname, struct elf_info *elf,
- Elf_Rela *r, Elf_Sym *sym, const char *fromsec)
-{
- const char *tosec = sec_name(elf, get_secindex(elf, sym));
- const struct sectioncheck *mismatch = section_mismatch(fromsec, tosec);
-
- if (mismatch) {
- if (mismatch->handler)
- mismatch->handler(modname, elf, mismatch,
- r, sym, fromsec);
- else
- default_mismatch_handler(modname, elf, mismatch,
- r, sym, fromsec);
- }
-}
-
-static unsigned int *reloc_location(struct elf_info *elf,
- Elf_Shdr *sechdr, Elf_Rela *r)
-{
- return sym_get_data_by_offset(elf, sechdr->sh_info, r->r_offset);
-}
-
-static int addend_386_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r)
-{
- unsigned int r_typ = ELF_R_TYPE(r->r_info);
- unsigned int *location = reloc_location(elf, sechdr, r);
-
- switch (r_typ) {
- case R_386_32:
- r->r_addend = TO_NATIVE(*location);
- break;
- case R_386_PC32:
- r->r_addend = TO_NATIVE(*location) + 4;
- break;
- }
- return 0;
-}
-
-#ifndef R_ARM_CALL
-#define R_ARM_CALL 28
-#endif
-#ifndef R_ARM_JUMP24
-#define R_ARM_JUMP24 29
-#endif
-
-#ifndef R_ARM_THM_CALL
-#define R_ARM_THM_CALL 10
-#endif
-#ifndef R_ARM_THM_JUMP24
-#define R_ARM_THM_JUMP24 30
-#endif
-#ifndef R_ARM_THM_JUMP19
-#define R_ARM_THM_JUMP19 51
-#endif
-
-static int addend_arm_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r)
-{
- unsigned int r_typ = ELF_R_TYPE(r->r_info);
-
- switch (r_typ) {
- case R_ARM_ABS32:
- /* From ARM ABI: (S + A) | T */
- r->r_addend = (int)(long)
- (elf->symtab_start + ELF_R_SYM(r->r_info));
- break;
- case R_ARM_PC24:
- case R_ARM_CALL:
- case R_ARM_JUMP24:
- case R_ARM_THM_CALL:
- case R_ARM_THM_JUMP24:
- case R_ARM_THM_JUMP19:
- /* From ARM ABI: ((S + A) | T) - P */
- r->r_addend = (int)(long)(elf->hdr +
- sechdr->sh_offset +
- (r->r_offset - sechdr->sh_addr));
- break;
- default:
- return 1;
- }
- return 0;
-}
-
-static int addend_mips_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r)
-{
- unsigned int r_typ = ELF_R_TYPE(r->r_info);
- unsigned int *location = reloc_location(elf, sechdr, r);
- unsigned int inst;
-
- if (r_typ == R_MIPS_HI16)
- return 1; /* skip this */
- inst = TO_NATIVE(*location);
- switch (r_typ) {
- case R_MIPS_LO16:
- r->r_addend = inst & 0xffff;
- break;
- case R_MIPS_26:
- r->r_addend = (inst & 0x03ffffff) << 2;
- break;
- case R_MIPS_32:
- r->r_addend = inst;
- break;
- }
- return 0;
-}
-
-#ifndef EM_RISCV
-#define EM_RISCV 243
-#endif
-
-#ifndef R_RISCV_SUB32
-#define R_RISCV_SUB32 39
-#endif
-
-static void section_rela(const char *modname, struct elf_info *elf,
- Elf_Shdr *sechdr)
-{
- Elf_Sym *sym;
- Elf_Rela *rela;
- Elf_Rela r;
- unsigned int r_sym;
- const char *fromsec;
-
- Elf_Rela *start = (void *)elf->hdr + sechdr->sh_offset;
- Elf_Rela *stop = (void *)start + sechdr->sh_size;
-
- fromsec = sec_name(elf, sechdr->sh_info);
- /* if from section (name) is know good then skip it */
- if (match(fromsec, section_white_list))
- return;
-
- for (rela = start; rela < stop; rela++) {
- r.r_offset = TO_NATIVE(rela->r_offset);
-#if KERNEL_ELFCLASS == ELFCLASS64
- if (elf->hdr->e_machine == EM_MIPS) {
- unsigned int r_typ;
- r_sym = ELF64_MIPS_R_SYM(rela->r_info);
- r_sym = TO_NATIVE(r_sym);
- r_typ = ELF64_MIPS_R_TYPE(rela->r_info);
- r.r_info = ELF64_R_INFO(r_sym, r_typ);
- } else {
- r.r_info = TO_NATIVE(rela->r_info);
- r_sym = ELF_R_SYM(r.r_info);
- }
-#else
- r.r_info = TO_NATIVE(rela->r_info);
- r_sym = ELF_R_SYM(r.r_info);
-#endif
- r.r_addend = TO_NATIVE(rela->r_addend);
- switch (elf->hdr->e_machine) {
- case EM_RISCV:
- if (!strcmp("__ex_table", fromsec) &&
- ELF_R_TYPE(r.r_info) == R_RISCV_SUB32)
- continue;
- break;
- }
- sym = elf->symtab_start + r_sym;
- /* Skip special sections */
- if (is_shndx_special(sym->st_shndx))
- continue;
- if (is_second_extable_reloc(start, rela, fromsec))
- find_extable_entry_size(fromsec, &r);
- check_section_mismatch(modname, elf, &r, sym, fromsec);
- }
-}
-
-static void section_rel(const char *modname, struct elf_info *elf,
- Elf_Shdr *sechdr)
-{
- Elf_Sym *sym;
- Elf_Rel *rel;
- Elf_Rela r;
- unsigned int r_sym;
- const char *fromsec;
-
- Elf_Rel *start = (void *)elf->hdr + sechdr->sh_offset;
- Elf_Rel *stop = (void *)start + sechdr->sh_size;
-
- fromsec = sec_name(elf, sechdr->sh_info);
- /* if from section (name) is know good then skip it */
- if (match(fromsec, section_white_list))
- return;
-
- for (rel = start; rel < stop; rel++) {
- r.r_offset = TO_NATIVE(rel->r_offset);
-#if KERNEL_ELFCLASS == ELFCLASS64
- if (elf->hdr->e_machine == EM_MIPS) {
- unsigned int r_typ;
- r_sym = ELF64_MIPS_R_SYM(rel->r_info);
- r_sym = TO_NATIVE(r_sym);
- r_typ = ELF64_MIPS_R_TYPE(rel->r_info);
- r.r_info = ELF64_R_INFO(r_sym, r_typ);
- } else {
- r.r_info = TO_NATIVE(rel->r_info);
- r_sym = ELF_R_SYM(r.r_info);
- }
-#else
- r.r_info = TO_NATIVE(rel->r_info);
- r_sym = ELF_R_SYM(r.r_info);
-#endif
- r.r_addend = 0;
- switch (elf->hdr->e_machine) {
- case EM_386:
- if (addend_386_rel(elf, sechdr, &r))
- continue;
- break;
- case EM_ARM:
- if (addend_arm_rel(elf, sechdr, &r))
- continue;
- break;
- case EM_MIPS:
- if (addend_mips_rel(elf, sechdr, &r))
- continue;
- break;
- }
- sym = elf->symtab_start + r_sym;
- /* Skip special sections */
- if (is_shndx_special(sym->st_shndx))
- continue;
- if (is_second_extable_reloc(start, rel, fromsec))
- find_extable_entry_size(fromsec, &r);
- check_section_mismatch(modname, elf, &r, sym, fromsec);
- }
-}
-
-/**
- * A module includes a number of sections that are discarded
- * either when loaded or when used as built-in.
- * For loaded modules all functions marked __init and all data
- * marked __initdata will be discarded when the module has been initialized.
- * Likewise for modules used built-in the sections marked __exit
- * are discarded because __exit marked function are supposed to be called
- * only when a module is unloaded which never happens for built-in modules.
- * The check_sec_ref() function traverses all relocation records
- * to find all references to a section that reference a section that will
- * be discarded and warns about it.
- **/
-static void check_sec_ref(const char *modname, struct elf_info *elf)
-{
- int i;
- Elf_Shdr *sechdrs = elf->sechdrs;
-
- /* Walk through all sections */
- for (i = 0; i < elf->num_sections; i++) {
- check_section(modname, elf, &elf->sechdrs[i]);
- /* We want to process only relocation sections and not .init */
- if (sechdrs[i].sh_type == SHT_RELA)
- section_rela(modname, elf, &elf->sechdrs[i]);
- else if (sechdrs[i].sh_type == SHT_REL)
- section_rel(modname, elf, &elf->sechdrs[i]);
- }
-}
-
-static char *remove_dot(char *s)
-{
- size_t n = strcspn(s, ".");
-
- if (n && s[n]) {
- size_t m = strspn(s + n + 1, "0123456789");
- if (m && (s[n + m + 1] == '.' || s[n + m + 1] == 0))
- s[n] = 0;
- }
- return s;
-}
-
-/*
- * The CRCs are recorded in .*.cmd files in the form of:
- * #SYMVER <name> <crc>
- */
-static void extract_crcs_for_object(const char *object, struct module *mod)
-{
- char cmd_file[PATH_MAX];
- char *buf, *p;
- const char *base;
- int dirlen, ret;
-
- base = strrchr(object, '/');
- if (base) {
- base++;
- dirlen = base - object;
- } else {
- dirlen = 0;
- base = object;
- }
-
- ret = snprintf(cmd_file, sizeof(cmd_file), "%.*s.%s.cmd",
- dirlen, object, base);
- if (ret >= sizeof(cmd_file)) {
- error("%s: too long path was truncated\n", cmd_file);
- return;
- }
-
- buf = read_text_file(cmd_file);
- p = buf;
-
- while ((p = strstr(p, "\n#SYMVER "))) {
- char *name;
- size_t namelen;
- unsigned int crc;
- struct symbol *sym;
-
- name = p + strlen("\n#SYMVER ");
-
- p = strchr(name, ' ');
- if (!p)
- break;
-
- namelen = p - name;
- p++;
-
- if (!isdigit(*p))
- continue; /* skip this line */
-
- crc = strtol(p, &p, 0);
- if (*p != '\n')
- continue; /* skip this line */
-
- name[namelen] = '\0';
-
- /*
- * sym_find_with_module() may return NULL here.
- * It typically occurs when CONFIG_TRIM_UNUSED_KSYMS=y.
- * Since commit e1327a127703, genksyms calculates CRCs of all
- * symbols, including trimmed ones. Ignore orphan CRCs.
- */
- sym = sym_find_with_module(name, mod);
- if (sym)
- sym_set_crc(sym, crc);
- }
-
- free(buf);
-}
-
-/*
- * The symbol versions (CRC) are recorded in the .*.cmd files.
- * Parse them to retrieve CRCs for the current module.
- */
-static void mod_set_crcs(struct module *mod)
-{
- char objlist[PATH_MAX];
- char *buf, *p, *obj;
- int ret;
-
- if (mod->is_vmlinux) {
- strcpy(objlist, ".vmlinux.objs");
- } else {
- /* objects for a module are listed in the *.mod file. */
- ret = snprintf(objlist, sizeof(objlist), "%s.mod", mod->name);
- if (ret >= sizeof(objlist)) {
- error("%s: too long path was truncated\n", objlist);
- return;
- }
- }
-
- buf = read_text_file(objlist);
- p = buf;
-
- while ((obj = strsep(&p, "\n")) && obj[0])
- extract_crcs_for_object(obj, mod);
-
- free(buf);
-}
-
-static void read_symbols(const char *modname)
-{
- const char *symname;
- char *version;
- char *license;
- char *namespace;
- struct module *mod;
- struct elf_info info = { };
- Elf_Sym *sym;
-
- if (!parse_elf(&info, modname))
- return;
-
- if (!strends(modname, ".o")) {
- error("%s: filename must be suffixed with .o\n", modname);
- return;
- }
-
- /* strip trailing .o */
- mod = new_module(modname, strlen(modname) - strlen(".o"));
-
- if (!mod->is_vmlinux) {
- license = get_modinfo(&info, "license");
- if (!license)
- error("missing MODULE_LICENSE() in %s\n", modname);
- while (license) {
- if (!license_is_gpl_compatible(license)) {
- mod->is_gpl_compatible = false;
- break;
- }
- license = get_next_modinfo(&info, "license", license);
- }
-
- namespace = get_modinfo(&info, "import_ns");
- while (namespace) {
- add_namespace(&mod->imported_namespaces, namespace);
- namespace = get_next_modinfo(&info, "import_ns",
- namespace);
- }
- }
-
- for (sym = info.symtab_start; sym < info.symtab_stop; sym++) {
- symname = remove_dot(info.strtab + sym->st_name);
-
- handle_symbol(mod, &info, sym, symname);
- handle_moddevtable(mod, &info, sym, symname);
- }
-
- for (sym = info.symtab_start; sym < info.symtab_stop; sym++) {
- symname = remove_dot(info.strtab + sym->st_name);
-
- /* Apply symbol namespaces from __kstrtabns_<symbol> entries. */
- if (strstarts(symname, "__kstrtabns_"))
- sym_update_namespace(symname + strlen("__kstrtabns_"),
- sym_get_data(&info, sym));
- }
-
- check_sec_ref(modname, &info);
-
- if (!mod->is_vmlinux) {
- version = get_modinfo(&info, "version");
- if (version || all_versions)
- get_src_version(mod->name, mod->srcversion,
- sizeof(mod->srcversion) - 1);
- }
-
- parse_elf_finish(&info);
-
- if (modversions) {
- /*
- * Our trick to get versioning for module struct etc. - it's
- * never passed as an argument to an exported function, so
- * the automatic versioning doesn't pick it up, but it's really
- * important anyhow.
- */
- sym_add_unresolved("module_layout", mod, false);
-
- mod_set_crcs(mod);
- }
-}
-
-static void read_symbols_from_files(const char *filename)
-{
- FILE *in = stdin;
- char fname[PATH_MAX];
-
- if (strcmp(filename, "-") != 0) {
- in = fopen(filename, "r");
- if (!in)
- fatal("Can't open filenames file %s: %m", filename);
- }
-
- while (fgets(fname, PATH_MAX, in) != NULL) {
- if (strends(fname, "\n"))
- fname[strlen(fname)-1] = '\0';
- read_symbols(fname);
- }
-
- if (in != stdin)
- fclose(in);
-}
-
-#define SZ 500
-
-/* We first write the generated file into memory using the
- * following helper, then compare to the file on disk and
- * only update the later if anything changed */
-
-void __attribute__((format(printf, 2, 3))) buf_printf(struct buffer *buf,
- const char *fmt, ...)
-{
- char tmp[SZ];
- int len;
- va_list ap;
-
- va_start(ap, fmt);
- len = vsnprintf(tmp, SZ, fmt, ap);
- buf_write(buf, tmp, len);
- va_end(ap);
-}
-
-void buf_write(struct buffer *buf, const char *s, int len)
-{
- if (buf->size - buf->pos < len) {
- buf->size += len + SZ;
- buf->p = NOFAIL(realloc(buf->p, buf->size));
- }
- strncpy(buf->p + buf->pos, s, len);
- buf->pos += len;
-}
-
-static void check_exports(struct module *mod)
-{
- struct symbol *s, *exp;
-
- list_for_each_entry(s, &mod->unresolved_symbols, list) {
- const char *basename;
- exp = find_symbol(s->name);
- if (!exp) {
- if (!s->weak && nr_unresolved++ < MAX_UNRESOLVED_REPORTS)
- modpost_log(warn_unresolved ? LOG_WARN : LOG_ERROR,
- "\"%s\" [%s.ko] undefined!\n",
- s->name, mod->name);
- continue;
- }
- if (exp->module == mod) {
- error("\"%s\" [%s.ko] was exported without definition\n",
- s->name, mod->name);
- continue;
- }
-
- s->module = exp->module;
- s->crc_valid = exp->crc_valid;
- s->crc = exp->crc;
-
- basename = strrchr(mod->name, '/');
- if (basename)
- basename++;
- else
- basename = mod->name;
-
- if (exp->namespace &&
- !contains_namespace(&mod->imported_namespaces, exp->namespace)) {
- modpost_log(allow_missing_ns_imports ? LOG_WARN : LOG_ERROR,
- "module %s uses symbol %s from namespace %s, but does not import it.\n",
- basename, exp->name, exp->namespace);
- add_namespace(&mod->missing_namespaces, exp->namespace);
- }
-
- if (!mod->is_gpl_compatible && exp->is_gpl_only)
- error("GPL-incompatible module %s.ko uses GPL-only symbol '%s'\n",
- basename, exp->name);
- }
-}
-
-static void check_modname_len(struct module *mod)
-{
- const char *mod_name;
-
- mod_name = strrchr(mod->name, '/');
- if (mod_name == NULL)
- mod_name = mod->name;
- else
- mod_name++;
- if (strlen(mod_name) >= MODULE_NAME_LEN)
- error("module name is too long [%s.ko]\n", mod->name);
-}
-
-/**
- * Header for the generated file
- **/
-static void add_header(struct buffer *b, struct module *mod)
-{
- buf_printf(b, "#include <linux/module.h>\n");
- /*
- * Include build-salt.h after module.h in order to
- * inherit the definitions.
- */
- buf_printf(b, "#define INCLUDE_VERMAGIC\n");
- buf_printf(b, "#include <linux/build-salt.h>\n");
- buf_printf(b, "#include <linux/elfnote-lto.h>\n");
- buf_printf(b, "#include <linux/export-internal.h>\n");
- buf_printf(b, "#include <linux/vermagic.h>\n");
- buf_printf(b, "#include <linux/compiler.h>\n");
- buf_printf(b, "\n");
- buf_printf(b, "BUILD_SALT;\n");
- buf_printf(b, "BUILD_LTO_INFO;\n");
- buf_printf(b, "\n");
- buf_printf(b, "MODULE_INFO(vermagic, VERMAGIC_STRING);\n");
- buf_printf(b, "MODULE_INFO(name, KBUILD_MODNAME);\n");
- buf_printf(b, "\n");
- buf_printf(b, "__visible struct module __this_module\n");
- buf_printf(b, "__section(\".gnu.linkonce.this_module\") = {\n");
- buf_printf(b, "\t.name = KBUILD_MODNAME,\n");
- if (mod->has_init)
- buf_printf(b, "\t.init = init_module,\n");
- if (mod->has_cleanup)
- buf_printf(b, "#ifdef CONFIG_MODULE_UNLOAD\n"
- "\t.exit = cleanup_module,\n"
- "#endif\n");
- buf_printf(b, "\t.arch = MODULE_ARCH_INIT,\n");
- buf_printf(b, "};\n");
-
- if (!external_module)
- buf_printf(b, "\nMODULE_INFO(intree, \"Y\");\n");
-
- buf_printf(b,
- "\n"
- "#ifdef CONFIG_RETPOLINE\n"
- "MODULE_INFO(retpoline, \"Y\");\n"
- "#endif\n");
-
- if (strstarts(mod->name, "drivers/staging"))
- buf_printf(b, "\nMODULE_INFO(staging, \"Y\");\n");
-
- if (strstarts(mod->name, "tools/testing"))
- buf_printf(b, "\nMODULE_INFO(test, \"Y\");\n");
-}
-
-static void add_exported_symbols(struct buffer *buf, struct module *mod)
-{
- struct symbol *sym;
-
- if (!modversions)
- return;
-
- /* record CRCs for exported symbols */
- buf_printf(buf, "\n");
- list_for_each_entry(sym, &mod->exported_symbols, list) {
- if (!sym->crc_valid)
- warn("EXPORT symbol \"%s\" [%s%s] version generation failed, symbol will not be versioned.\n"
- "Is \"%s\" prototyped in <asm/asm-prototypes.h>?\n",
- sym->name, mod->name, mod->is_vmlinux ? "" : ".ko",
- sym->name);
-
- buf_printf(buf, "SYMBOL_CRC(%s, 0x%08x, \"%s\");\n",
- sym->name, sym->crc, sym->is_gpl_only ? "_gpl" : "");
- }
-}
-
-/**
- * Record CRCs for unresolved symbols
- **/
-static void add_versions(struct buffer *b, struct module *mod)
-{
- struct symbol *s;
-
- if (!modversions)
- return;
-
- buf_printf(b, "\n");
- buf_printf(b, "static const struct modversion_info ____versions[]\n");
- buf_printf(b, "__used __section(\"__versions\") = {\n");
-
- list_for_each_entry(s, &mod->unresolved_symbols, list) {
- if (!s->module)
- continue;
- if (!s->crc_valid) {
- warn("\"%s\" [%s.ko] has no CRC!\n",
- s->name, mod->name);
- continue;
- }
- if (strlen(s->name) >= MODULE_NAME_LEN) {
- error("too long symbol \"%s\" [%s.ko]\n",
- s->name, mod->name);
- break;
- }
- buf_printf(b, "\t{ %#8x, \"%s\" },\n",
- s->crc, s->name);
- }
-
- buf_printf(b, "};\n");
-}
-
-static void add_depends(struct buffer *b, struct module *mod)
-{
- struct symbol *s;
- int first = 1;
-
- /* Clear ->seen flag of modules that own symbols needed by this. */
- list_for_each_entry(s, &mod->unresolved_symbols, list) {
- if (s->module)
- s->module->seen = s->module->is_vmlinux;
- }
-
- buf_printf(b, "\n");
- buf_printf(b, "MODULE_INFO(depends, \"");
- list_for_each_entry(s, &mod->unresolved_symbols, list) {
- const char *p;
- if (!s->module)
- continue;
-
- if (s->module->seen)
- continue;
-
- s->module->seen = true;
- p = strrchr(s->module->name, '/');
- if (p)
- p++;
- else
- p = s->module->name;
- buf_printf(b, "%s%s", first ? "" : ",", p);
- first = 0;
- }
- buf_printf(b, "\");\n");
-}
-
-static void add_srcversion(struct buffer *b, struct module *mod)
-{
- if (mod->srcversion[0]) {
- buf_printf(b, "\n");
- buf_printf(b, "MODULE_INFO(srcversion, \"%s\");\n",
- mod->srcversion);
- }
-}
-
-static void write_buf(struct buffer *b, const char *fname)
-{
- FILE *file;
-
- if (error_occurred)
- return;
-
- file = fopen(fname, "w");
- if (!file) {
- perror(fname);
- exit(1);
- }
- if (fwrite(b->p, 1, b->pos, file) != b->pos) {
- perror(fname);
- exit(1);
- }
- if (fclose(file) != 0) {
- perror(fname);
- exit(1);
- }
-}
-
-static void write_if_changed(struct buffer *b, const char *fname)
-{
- char *tmp;
- FILE *file;
- struct stat st;
-
- file = fopen(fname, "r");
- if (!file)
- goto write;
-
- if (fstat(fileno(file), &st) < 0)
- goto close_write;
-
- if (st.st_size != b->pos)
- goto close_write;
-
- tmp = NOFAIL(malloc(b->pos));
- if (fread(tmp, 1, b->pos, file) != b->pos)
- goto free_write;
-
- if (memcmp(tmp, b->p, b->pos) != 0)
- goto free_write;
-
- free(tmp);
- fclose(file);
- return;
-
- free_write:
- free(tmp);
- close_write:
- fclose(file);
- write:
- write_buf(b, fname);
-}
-
-static void write_vmlinux_export_c_file(struct module *mod)
-{
- struct buffer buf = { };
-
- buf_printf(&buf,
- "#include <linux/export-internal.h>\n");
-
- add_exported_symbols(&buf, mod);
- write_if_changed(&buf, ".vmlinux.export.c");
- free(buf.p);
-}
-
-/* do sanity checks, and generate *.mod.c file */
-static void write_mod_c_file(struct module *mod)
-{
- struct buffer buf = { };
- char fname[PATH_MAX];
- int ret;
-
- check_modname_len(mod);
- check_exports(mod);
-
- add_header(&buf, mod);
- add_exported_symbols(&buf, mod);
- add_versions(&buf, mod);
- add_depends(&buf, mod);
- add_moddevtable(&buf, mod);
- add_srcversion(&buf, mod);
-
- ret = snprintf(fname, sizeof(fname), "%s.mod.c", mod->name);
- if (ret >= sizeof(fname)) {
- error("%s: too long path was truncated\n", fname);
- goto free;
- }
-
- write_if_changed(&buf, fname);
-
-free:
- free(buf.p);
-}
-
-/* parse Module.symvers file. line format:
- * 0x12345678<tab>symbol<tab>module<tab>export<tab>namespace
- **/
-static void read_dump(const char *fname)
-{
- char *buf, *pos, *line;
-
- buf = read_text_file(fname);
- if (!buf)
- /* No symbol versions, silently ignore */
- return;
-
- pos = buf;
-
- while ((line = get_line(&pos))) {
- char *symname, *namespace, *modname, *d, *export;
- unsigned int crc;
- struct module *mod;
- struct symbol *s;
- bool gpl_only;
-
- if (!(symname = strchr(line, '\t')))
- goto fail;
- *symname++ = '\0';
- if (!(modname = strchr(symname, '\t')))
- goto fail;
- *modname++ = '\0';
- if (!(export = strchr(modname, '\t')))
- goto fail;
- *export++ = '\0';
- if (!(namespace = strchr(export, '\t')))
- goto fail;
- *namespace++ = '\0';
-
- crc = strtoul(line, &d, 16);
- if (*symname == '\0' || *modname == '\0' || *d != '\0')
- goto fail;
-
- if (!strcmp(export, "EXPORT_SYMBOL_GPL")) {
- gpl_only = true;
- } else if (!strcmp(export, "EXPORT_SYMBOL")) {
- gpl_only = false;
- } else {
- error("%s: unknown license %s. skip", symname, export);
- continue;
- }
-
- mod = find_module(modname);
- if (!mod) {
- mod = new_module(modname, strlen(modname));
- mod->from_dump = true;
- }
- s = sym_add_exported(symname, mod, gpl_only);
- sym_set_crc(s, crc);
- sym_update_namespace(symname, namespace);
- }
- free(buf);
- return;
-fail:
- free(buf);
- fatal("parse error in symbol dump file\n");
-}
-
-static void write_dump(const char *fname)
-{
- struct buffer buf = { };
- struct module *mod;
- struct symbol *sym;
-
- list_for_each_entry(mod, &modules, list) {
- if (mod->from_dump)
- continue;
- list_for_each_entry(sym, &mod->exported_symbols, list) {
- buf_printf(&buf, "0x%08x\t%s\t%s\tEXPORT_SYMBOL%s\t%s\n",
- sym->crc, sym->name, mod->name,
- sym->is_gpl_only ? "_GPL" : "",
- sym->namespace ?: "");
- }
- }
- write_buf(&buf, fname);
- free(buf.p);
-}
-
-static void write_namespace_deps_files(const char *fname)
-{
- struct module *mod;
- struct namespace_list *ns;
- struct buffer ns_deps_buf = {};
-
- list_for_each_entry(mod, &modules, list) {
-
- if (mod->from_dump || list_empty(&mod->missing_namespaces))
- continue;
-
- buf_printf(&ns_deps_buf, "%s.ko:", mod->name);
-
- list_for_each_entry(ns, &mod->missing_namespaces, list)
- buf_printf(&ns_deps_buf, " %s", ns->namespace);
-
- buf_printf(&ns_deps_buf, "\n");
- }
-
- write_if_changed(&ns_deps_buf, fname);
- free(ns_deps_buf.p);
-}
-
-struct dump_list {
- struct list_head list;
- const char *file;
-};
-
-int main(int argc, char **argv)
-{
- struct module *mod;
- char *missing_namespace_deps = NULL;
- char *dump_write = NULL, *files_source = NULL;
- int opt;
- LIST_HEAD(dump_lists);
- struct dump_list *dl, *dl2;
-
- while ((opt = getopt(argc, argv, "ei:mnT:o:awENd:")) != -1) {
- switch (opt) {
- case 'e':
- external_module = true;
- break;
- case 'i':
- dl = NOFAIL(malloc(sizeof(*dl)));
- dl->file = optarg;
- list_add_tail(&dl->list, &dump_lists);
- break;
- case 'm':
- modversions = true;
- break;
- case 'n':
- ignore_missing_files = true;
- break;
- case 'o':
- dump_write = optarg;
- break;
- case 'a':
- all_versions = true;
- break;
- case 'T':
- files_source = optarg;
- break;
- case 'w':
- warn_unresolved = true;
- break;
- case 'E':
- sec_mismatch_warn_only = false;
- break;
- case 'N':
- allow_missing_ns_imports = true;
- break;
- case 'd':
- missing_namespace_deps = optarg;
- break;
- default:
- exit(1);
- }
- }
-
- list_for_each_entry_safe(dl, dl2, &dump_lists, list) {
- read_dump(dl->file);
- list_del(&dl->list);
- free(dl);
- }
-
- while (optind < argc)
- read_symbols(argv[optind++]);
-
- if (files_source)
- read_symbols_from_files(files_source);
-
- list_for_each_entry(mod, &modules, list) {
- if (mod->from_dump)
- continue;
-
- if (mod->is_vmlinux)
- write_vmlinux_export_c_file(mod);
- else
- write_mod_c_file(mod);
- }
-
- if (missing_namespace_deps)
- write_namespace_deps_files(missing_namespace_deps);
-
- if (dump_write)
- write_dump(dump_write);
- if (sec_mismatch_count && !sec_mismatch_warn_only)
- error("Section mismatches detected.\n"
- "Set CONFIG_SECTION_MISMATCH_WARN_ONLY=y to allow them.\n");
-
- if (nr_unresolved > MAX_UNRESOLVED_REPORTS)
- warn("suppressed %u unresolved symbol warnings because there were too many)\n",
- nr_unresolved - MAX_UNRESOLVED_REPORTS);
-
- return error_occurred ? 1 : 0;
-}
Index: v6.x/create-6.0.7-host-limits-patch/linux-6.0.7-new/scripts/mod/sumversion.c
===================================================================
--- v6.x/create-6.0.7-host-limits-patch/linux-6.0.7-new/scripts/mod/sumversion.c (revision 384)
+++ v6.x/create-6.0.7-host-limits-patch/linux-6.0.7-new/scripts/mod/sumversion.c (nonexistent)
@@ -1,410 +0,0 @@
-#include <netinet/in.h>
-#ifdef __sun__
-#include <inttypes.h>
-#else
-#include <stdint.h>
-#endif
-#include <ctype.h>
-#include <errno.h>
-#include <string.h>
-#include <linux/limits.h>
-#include "modpost.h"
-
-/*
- * Stolen form Cryptographic API.
- *
- * MD4 Message Digest Algorithm (RFC1320).
- *
- * Implementation derived from Andrew Tridgell and Steve French's
- * CIFS MD4 implementation, and the cryptoapi implementation
- * originally based on the public domain implementation written
- * by Colin Plumb in 1993.
- *
- * Copyright (c) Andrew Tridgell 1997-1998.
- * Modified by Steve French (sfrench@us.ibm.com) 2002
- * Copyright (c) Cryptoapi developers.
- * Copyright (c) 2002 David S. Miller (davem@redhat.com)
- * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- */
-#define MD4_DIGEST_SIZE 16
-#define MD4_HMAC_BLOCK_SIZE 64
-#define MD4_BLOCK_WORDS 16
-#define MD4_HASH_WORDS 4
-
-struct md4_ctx {
- uint32_t hash[MD4_HASH_WORDS];
- uint32_t block[MD4_BLOCK_WORDS];
- uint64_t byte_count;
-};
-
-static inline uint32_t lshift(uint32_t x, unsigned int s)
-{
- x &= 0xFFFFFFFF;
- return ((x << s) & 0xFFFFFFFF) | (x >> (32 - s));
-}
-
-static inline uint32_t F(uint32_t x, uint32_t y, uint32_t z)
-{
- return (x & y) | ((~x) & z);
-}
-
-static inline uint32_t G(uint32_t x, uint32_t y, uint32_t z)
-{
- return (x & y) | (x & z) | (y & z);
-}
-
-static inline uint32_t H(uint32_t x, uint32_t y, uint32_t z)
-{
- return x ^ y ^ z;
-}
-
-#define ROUND1(a,b,c,d,k,s) (a = lshift(a + F(b,c,d) + k, s))
-#define ROUND2(a,b,c,d,k,s) (a = lshift(a + G(b,c,d) + k + (uint32_t)0x5A827999,s))
-#define ROUND3(a,b,c,d,k,s) (a = lshift(a + H(b,c,d) + k + (uint32_t)0x6ED9EBA1,s))
-
-/* XXX: this stuff can be optimized */
-static inline void le32_to_cpu_array(uint32_t *buf, unsigned int words)
-{
- while (words--) {
- *buf = ntohl(*buf);
- buf++;
- }
-}
-
-static inline void cpu_to_le32_array(uint32_t *buf, unsigned int words)
-{
- while (words--) {
- *buf = htonl(*buf);
- buf++;
- }
-}
-
-static void md4_transform(uint32_t *hash, uint32_t const *in)
-{
- uint32_t a, b, c, d;
-
- a = hash[0];
- b = hash[1];
- c = hash[2];
- d = hash[3];
-
- ROUND1(a, b, c, d, in[0], 3);
- ROUND1(d, a, b, c, in[1], 7);
- ROUND1(c, d, a, b, in[2], 11);
- ROUND1(b, c, d, a, in[3], 19);
- ROUND1(a, b, c, d, in[4], 3);
- ROUND1(d, a, b, c, in[5], 7);
- ROUND1(c, d, a, b, in[6], 11);
- ROUND1(b, c, d, a, in[7], 19);
- ROUND1(a, b, c, d, in[8], 3);
- ROUND1(d, a, b, c, in[9], 7);
- ROUND1(c, d, a, b, in[10], 11);
- ROUND1(b, c, d, a, in[11], 19);
- ROUND1(a, b, c, d, in[12], 3);
- ROUND1(d, a, b, c, in[13], 7);
- ROUND1(c, d, a, b, in[14], 11);
- ROUND1(b, c, d, a, in[15], 19);
-
- ROUND2(a, b, c, d,in[ 0], 3);
- ROUND2(d, a, b, c, in[4], 5);
- ROUND2(c, d, a, b, in[8], 9);
- ROUND2(b, c, d, a, in[12], 13);
- ROUND2(a, b, c, d, in[1], 3);
- ROUND2(d, a, b, c, in[5], 5);
- ROUND2(c, d, a, b, in[9], 9);
- ROUND2(b, c, d, a, in[13], 13);
- ROUND2(a, b, c, d, in[2], 3);
- ROUND2(d, a, b, c, in[6], 5);
- ROUND2(c, d, a, b, in[10], 9);
- ROUND2(b, c, d, a, in[14], 13);
- ROUND2(a, b, c, d, in[3], 3);
- ROUND2(d, a, b, c, in[7], 5);
- ROUND2(c, d, a, b, in[11], 9);
- ROUND2(b, c, d, a, in[15], 13);
-
- ROUND3(a, b, c, d,in[ 0], 3);
- ROUND3(d, a, b, c, in[8], 9);
- ROUND3(c, d, a, b, in[4], 11);
- ROUND3(b, c, d, a, in[12], 15);
- ROUND3(a, b, c, d, in[2], 3);
- ROUND3(d, a, b, c, in[10], 9);
- ROUND3(c, d, a, b, in[6], 11);
- ROUND3(b, c, d, a, in[14], 15);
- ROUND3(a, b, c, d, in[1], 3);
- ROUND3(d, a, b, c, in[9], 9);
- ROUND3(c, d, a, b, in[5], 11);
- ROUND3(b, c, d, a, in[13], 15);
- ROUND3(a, b, c, d, in[3], 3);
- ROUND3(d, a, b, c, in[11], 9);
- ROUND3(c, d, a, b, in[7], 11);
- ROUND3(b, c, d, a, in[15], 15);
-
- hash[0] += a;
- hash[1] += b;
- hash[2] += c;
- hash[3] += d;
-}
-
-static inline void md4_transform_helper(struct md4_ctx *ctx)
-{
- le32_to_cpu_array(ctx->block, sizeof(ctx->block) / sizeof(uint32_t));
- md4_transform(ctx->hash, ctx->block);
-}
-
-static void md4_init(struct md4_ctx *mctx)
-{
- mctx->hash[0] = 0x67452301;
- mctx->hash[1] = 0xefcdab89;
- mctx->hash[2] = 0x98badcfe;
- mctx->hash[3] = 0x10325476;
- mctx->byte_count = 0;
-}
-
-static void md4_update(struct md4_ctx *mctx,
- const unsigned char *data, unsigned int len)
-{
- const uint32_t avail = sizeof(mctx->block) - (mctx->byte_count & 0x3f);
-
- mctx->byte_count += len;
-
- if (avail > len) {
- memcpy((char *)mctx->block + (sizeof(mctx->block) - avail),
- data, len);
- return;
- }
-
- memcpy((char *)mctx->block + (sizeof(mctx->block) - avail),
- data, avail);
-
- md4_transform_helper(mctx);
- data += avail;
- len -= avail;
-
- while (len >= sizeof(mctx->block)) {
- memcpy(mctx->block, data, sizeof(mctx->block));
- md4_transform_helper(mctx);
- data += sizeof(mctx->block);
- len -= sizeof(mctx->block);
- }
-
- memcpy(mctx->block, data, len);
-}
-
-static void md4_final_ascii(struct md4_ctx *mctx, char *out, unsigned int len)
-{
- const unsigned int offset = mctx->byte_count & 0x3f;
- char *p = (char *)mctx->block + offset;
- int padding = 56 - (offset + 1);
-
- *p++ = 0x80;
- if (padding < 0) {
- memset(p, 0x00, padding + sizeof (uint64_t));
- md4_transform_helper(mctx);
- p = (char *)mctx->block;
- padding = 56;
- }
-
- memset(p, 0, padding);
- mctx->block[14] = mctx->byte_count << 3;
- mctx->block[15] = mctx->byte_count >> 29;
- le32_to_cpu_array(mctx->block, (sizeof(mctx->block) -
- sizeof(uint64_t)) / sizeof(uint32_t));
- md4_transform(mctx->hash, mctx->block);
- cpu_to_le32_array(mctx->hash, sizeof(mctx->hash) / sizeof(uint32_t));
-
- snprintf(out, len, "%08X%08X%08X%08X",
- mctx->hash[0], mctx->hash[1], mctx->hash[2], mctx->hash[3]);
-}
-
-static inline void add_char(unsigned char c, struct md4_ctx *md)
-{
- md4_update(md, &c, 1);
-}
-
-static int parse_string(const char *file, unsigned long len,
- struct md4_ctx *md)
-{
- unsigned long i;
-
- add_char(file[0], md);
- for (i = 1; i < len; i++) {
- add_char(file[i], md);
- if (file[i] == '"' && file[i-1] != '\\')
- break;
- }
- return i;
-}
-
-static int parse_comment(const char *file, unsigned long len)
-{
- unsigned long i;
-
- for (i = 2; i < len; i++) {
- if (file[i-1] == '*' && file[i] == '/')
- break;
- }
- return i;
-}
-
-/* FIXME: Handle .s files differently (eg. # starts comments) --RR */
-static int parse_file(const char *fname, struct md4_ctx *md)
-{
- char *file;
- unsigned long i, len;
-
- file = read_text_file(fname);
- len = strlen(file);
-
- for (i = 0; i < len; i++) {
- /* Collapse and ignore \ and CR. */
- if (file[i] == '\\' && (i+1 < len) && file[i+1] == '\n') {
- i++;
- continue;
- }
-
- /* Ignore whitespace */
- if (isspace(file[i]))
- continue;
-
- /* Handle strings as whole units */
- if (file[i] == '"') {
- i += parse_string(file+i, len - i, md);
- continue;
- }
-
- /* Comments: ignore */
- if (file[i] == '/' && file[i+1] == '*') {
- i += parse_comment(file+i, len - i);
- continue;
- }
-
- add_char(file[i], md);
- }
- free(file);
- return 1;
-}
-/* Check whether the file is a static library or not */
-static bool is_static_library(const char *objfile)
-{
- int len = strlen(objfile);
-
- return objfile[len - 2] == '.' && objfile[len - 1] == 'a';
-}
-
-/* We have dir/file.o. Open dir/.file.o.cmd, look for source_ and deps_ line
- * to figure out source files. */
-static int parse_source_files(const char *objfile, struct md4_ctx *md)
-{
- char *cmd, *file, *line, *dir, *pos;
- const char *base;
- int dirlen, ret = 0, check_files = 0;
-
- cmd = NOFAIL(malloc(strlen(objfile) + sizeof("..cmd")));
-
- base = strrchr(objfile, '/');
- if (base) {
- base++;
- dirlen = base - objfile;
- sprintf(cmd, "%.*s.%s.cmd", dirlen, objfile, base);
- } else {
- dirlen = 0;
- sprintf(cmd, ".%s.cmd", objfile);
- }
- dir = NOFAIL(malloc(dirlen + 1));
- strncpy(dir, objfile, dirlen);
- dir[dirlen] = '\0';
-
- file = read_text_file(cmd);
-
- pos = file;
-
- /* Sum all files in the same dir or subdirs. */
- while ((line = get_line(&pos))) {
- char* p = line;
-
- if (strncmp(line, "source_", sizeof("source_")-1) == 0) {
- p = strrchr(line, ' ');
- if (!p) {
- warn("malformed line: %s\n", line);
- goto out_file;
- }
- p++;
- if (!parse_file(p, md)) {
- warn("could not open %s: %s\n",
- p, strerror(errno));
- goto out_file;
- }
- continue;
- }
- if (strncmp(line, "deps_", sizeof("deps_")-1) == 0) {
- check_files = 1;
- continue;
- }
- if (!check_files)
- continue;
-
- /* Continue until line does not end with '\' */
- if ( *(p + strlen(p)-1) != '\\')
- break;
- /* Terminate line at first space, to get rid of final ' \' */
- while (*p) {
- if (isspace(*p)) {
- *p = '\0';
- break;
- }
- p++;
- }
-
- /* Check if this file is in same dir as objfile */
- if ((strstr(line, dir)+strlen(dir)-1) == strrchr(line, '/')) {
- if (!parse_file(line, md)) {
- warn("could not open %s: %s\n",
- line, strerror(errno));
- goto out_file;
- }
-
- }
-
- }
-
- /* Everyone parsed OK */
- ret = 1;
-out_file:
- free(file);
- free(dir);
- free(cmd);
- return ret;
-}
-
-/* Calc and record src checksum. */
-void get_src_version(const char *modname, char sum[], unsigned sumlen)
-{
- char *buf;
- struct md4_ctx md;
- char *fname;
- char filelist[PATH_MAX + 1];
-
- /* objects for a module are listed in the first line of *.mod file. */
- snprintf(filelist, sizeof(filelist), "%s.mod", modname);
-
- buf = read_text_file(filelist);
-
- md4_init(&md);
- while ((fname = strsep(&buf, "\n"))) {
- if (!*fname)
- continue;
- if (!(is_static_library(fname)) &&
- !parse_source_files(fname, &md))
- goto free;
- }
-
- md4_final_ascii(&md, sum, sumlen);
-free:
- free(buf);
-}
Index: v6.x/create-6.0.7-host-limits-patch/linux-6.0.7-new/scripts/mod
===================================================================
--- v6.x/create-6.0.7-host-limits-patch/linux-6.0.7-new/scripts/mod (revision 384)
+++ v6.x/create-6.0.7-host-limits-patch/linux-6.0.7-new/scripts/mod (nonexistent)
Property changes on: v6.x/create-6.0.7-host-limits-patch/linux-6.0.7-new/scripts/mod
___________________________________________________________________
Deleted: svn:ignore
## -1,73 +0,0 ##
-
-# install dir
-dist
-
-# Target build dirs
-.a1x-newlib
-.a2x-newlib
-.at91sam7s-newlib
-
-.build-machine
-
-.a1x-glibc
-.a2x-glibc
-.h3-glibc
-.h5-glibc
-.i586-glibc
-.i686-glibc
-.imx6-glibc
-.jz47xx-glibc
-.makefile
-.am335x-glibc
-.omap543x-glibc
-.p5600-glibc
-.power8-glibc
-.power8le-glibc
-.power9-glibc
-.power9le-glibc
-.m1000-glibc
-.riscv64-glibc
-.rk328x-glibc
-.rk33xx-glibc
-.rk339x-glibc
-.s8xx-glibc
-.s9xx-glibc
-.x86_64-glibc
-
-# Hidden files (each file)
-.makefile
-.dist
-.rootfs
-
-# src & hw requires
-.src_requires
-.src_requires_depend
-.requires
-.requires_depend
-
-# Tarballs
-*.gz
-*.bz2
-*.lz
-*.xz
-*.tgz
-*.txz
-
-# Signatures
-*.asc
-*.sig
-*.sign
-*.sha1sum
-
-# Patches
-*.patch
-
-# Descriptions
-*.dsc
-*.txt
-
-# Default linux config files
-*.defconfig
-
-# backup copies
-*~
Index: v6.x/create-6.0.7-host-limits-patch/linux-6.0.7-new/scripts/kconfig/lexer.l
===================================================================
--- v6.x/create-6.0.7-host-limits-patch/linux-6.0.7-new/scripts/kconfig/lexer.l (revision 384)
+++ v6.x/create-6.0.7-host-limits-patch/linux-6.0.7-new/scripts/kconfig/lexer.l (nonexistent)
@@ -1,468 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
- */
-%option nostdinit noyywrap never-interactive full ecs
-%option 8bit nodefault yylineno
-%x ASSIGN_VAL HELP STRING
-%{
-
-#include <assert.h>
-#include <linux/limits.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "lkc.h"
-#include "parser.tab.h"
-
-#define YY_DECL static int yylex1(void)
-
-#define START_STRSIZE 16
-
-static struct {
- struct file *file;
- int lineno;
-} current_pos;
-
-static int prev_prev_token = T_EOL;
-static int prev_token = T_EOL;
-static char *text;
-static int text_size, text_asize;
-
-struct buffer {
- struct buffer *parent;
- YY_BUFFER_STATE state;
-};
-
-static struct buffer *current_buf;
-
-static int last_ts, first_ts;
-
-static char *expand_token(const char *in, size_t n);
-static void append_expanded_string(const char *in);
-static void zconf_endhelp(void);
-static void zconf_endfile(void);
-
-static void new_string(void)
-{
- text = xmalloc(START_STRSIZE);
- text_asize = START_STRSIZE;
- text_size = 0;
- *text = 0;
-}
-
-static void append_string(const char *str, int size)
-{
- int new_size = text_size + size + 1;
- if (new_size > text_asize) {
- new_size += START_STRSIZE - 1;
- new_size &= -START_STRSIZE;
- text = xrealloc(text, new_size);
- text_asize = new_size;
- }
- memcpy(text + text_size, str, size);
- text_size += size;
- text[text_size] = 0;
-}
-
-static void alloc_string(const char *str, int size)
-{
- text = xmalloc(size + 1);
- memcpy(text, str, size);
- text[size] = 0;
-}
-
-static void warn_ignored_character(char chr)
-{
- fprintf(stderr,
- "%s:%d:warning: ignoring unsupported character '%c'\n",
- current_file->name, yylineno, chr);
-}
-%}
-
-n [A-Za-z0-9_-]
-
-%%
- char open_quote = 0;
-
-#.* /* ignore comment */
-[ \t]* /* whitespaces */
-\\\n /* escaped new line */
-\n return T_EOL;
-"bool" return T_BOOL;
-"choice" return T_CHOICE;
-"comment" return T_COMMENT;
-"config" return T_CONFIG;
-"def_bool" return T_DEF_BOOL;
-"def_tristate" return T_DEF_TRISTATE;
-"default" return T_DEFAULT;
-"depends" return T_DEPENDS;
-"endchoice" return T_ENDCHOICE;
-"endif" return T_ENDIF;
-"endmenu" return T_ENDMENU;
-"help" return T_HELP;
-"hex" return T_HEX;
-"if" return T_IF;
-"imply" return T_IMPLY;
-"int" return T_INT;
-"mainmenu" return T_MAINMENU;
-"menu" return T_MENU;
-"menuconfig" return T_MENUCONFIG;
-"modules" return T_MODULES;
-"on" return T_ON;
-"optional" return T_OPTIONAL;
-"prompt" return T_PROMPT;
-"range" return T_RANGE;
-"select" return T_SELECT;
-"source" return T_SOURCE;
-"string" return T_STRING;
-"tristate" return T_TRISTATE;
-"visible" return T_VISIBLE;
-"||" return T_OR;
-"&&" return T_AND;
-"=" return T_EQUAL;
-"!=" return T_UNEQUAL;
-"<" return T_LESS;
-"<=" return T_LESS_EQUAL;
-">" return T_GREATER;
-">=" return T_GREATER_EQUAL;
-"!" return T_NOT;
-"(" return T_OPEN_PAREN;
-")" return T_CLOSE_PAREN;
-":=" return T_COLON_EQUAL;
-"+=" return T_PLUS_EQUAL;
-\"|\' {
- open_quote = yytext[0];
- new_string();
- BEGIN(STRING);
- }
-{n}+ {
- alloc_string(yytext, yyleng);
- yylval.string = text;
- return T_WORD;
- }
-({n}|$)+ {
- /* this token includes at least one '$' */
- yylval.string = expand_token(yytext, yyleng);
- if (strlen(yylval.string))
- return T_WORD;
- free(yylval.string);
- }
-. warn_ignored_character(*yytext);
-
-<ASSIGN_VAL>{
- [^[:blank:]\n]+.* {
- alloc_string(yytext, yyleng);
- yylval.string = text;
- return T_ASSIGN_VAL;
- }
- \n { BEGIN(INITIAL); return T_EOL; }
- .
-}
-
-<STRING>{
- "$".* append_expanded_string(yytext);
- [^$'"\\\n]+ {
- append_string(yytext, yyleng);
- }
- \\.? {
- append_string(yytext + 1, yyleng - 1);
- }
- \'|\" {
- if (open_quote == yytext[0]) {
- BEGIN(INITIAL);
- yylval.string = text;
- return T_WORD_QUOTE;
- } else
- append_string(yytext, 1);
- }
- \n {
- fprintf(stderr,
- "%s:%d:warning: multi-line strings not supported\n",
- zconf_curname(), zconf_lineno());
- unput('\n');
- BEGIN(INITIAL);
- yylval.string = text;
- return T_WORD_QUOTE;
- }
- <<EOF>> {
- BEGIN(INITIAL);
- yylval.string = text;
- return T_WORD_QUOTE;
- }
-}
-
-<HELP>{
- [ \t]+ {
- int ts, i;
-
- ts = 0;
- for (i = 0; i < yyleng; i++) {
- if (yytext[i] == '\t')
- ts = (ts & ~7) + 8;
- else
- ts++;
- }
- last_ts = ts;
- if (first_ts) {
- if (ts < first_ts) {
- zconf_endhelp();
- return T_HELPTEXT;
- }
- ts -= first_ts;
- while (ts > 8) {
- append_string(" ", 8);
- ts -= 8;
- }
- append_string(" ", ts);
- }
- }
- [ \t]*\n/[^ \t\n] {
- zconf_endhelp();
- return T_HELPTEXT;
- }
- [ \t]*\n {
- append_string("\n", 1);
- }
- [^ \t\n].* {
- while (yyleng) {
- if ((yytext[yyleng-1] != ' ') && (yytext[yyleng-1] != '\t'))
- break;
- yyleng--;
- }
- append_string(yytext, yyleng);
- if (!first_ts)
- first_ts = last_ts;
- }
- <<EOF>> {
- zconf_endhelp();
- return T_HELPTEXT;
- }
-}
-
-<<EOF>> {
- BEGIN(INITIAL);
-
- if (prev_token != T_EOL && prev_token != T_HELPTEXT)
- fprintf(stderr, "%s:%d:warning: no new line at end of file\n",
- current_file->name, yylineno);
-
- if (current_file) {
- zconf_endfile();
- return T_EOL;
- }
- fclose(yyin);
- yyterminate();
-}
-
-%%
-
-/* second stage lexer */
-int yylex(void)
-{
- int token;
-
-repeat:
- token = yylex1();
-
- if (prev_token == T_EOL || prev_token == T_HELPTEXT) {
- if (token == T_EOL) {
- /* Do not pass unneeded T_EOL to the parser. */
- goto repeat;
- } else {
- /*
- * For the parser, update file/lineno at the first token
- * of each statement. Generally, \n is a statement
- * terminator in Kconfig, but it is not always true
- * because \n could be escaped by a backslash.
- */
- current_pos.file = current_file;
- current_pos.lineno = yylineno;
- }
- }
-
- if (prev_prev_token == T_EOL && prev_token == T_WORD &&
- (token == T_EQUAL || token == T_COLON_EQUAL || token == T_PLUS_EQUAL))
- BEGIN(ASSIGN_VAL);
-
- prev_prev_token = prev_token;
- prev_token = token;
-
- return token;
-}
-
-static char *expand_token(const char *in, size_t n)
-{
- char *out;
- int c;
- char c2;
- const char *rest, *end;
-
- new_string();
- append_string(in, n);
-
- /* get the whole line because we do not know the end of token. */
- while ((c = input()) != EOF) {
- if (c == '\n') {
- unput(c);
- break;
- }
- c2 = c;
- append_string(&c2, 1);
- }
-
- rest = text;
- out = expand_one_token(&rest);
-
- /* push back unused characters to the input stream */
- end = rest + strlen(rest);
- while (end > rest)
- unput(*--end);
-
- free(text);
-
- return out;
-}
-
-static void append_expanded_string(const char *str)
-{
- const char *end;
- char *res;
-
- str++;
-
- res = expand_dollar(&str);
-
- /* push back unused characters to the input stream */
- end = str + strlen(str);
- while (end > str)
- unput(*--end);
-
- append_string(res, strlen(res));
-
- free(res);
-}
-
-void zconf_starthelp(void)
-{
- new_string();
- last_ts = first_ts = 0;
- BEGIN(HELP);
-}
-
-static void zconf_endhelp(void)
-{
- yylval.string = text;
- BEGIN(INITIAL);
-}
-
-
-/*
- * Try to open specified file with following names:
- * ./name
- * $(srctree)/name
- * The latter is used when srctree is separate from objtree
- * when compiling the kernel.
- * Return NULL if file is not found.
- */
-FILE *zconf_fopen(const char *name)
-{
- char *env, fullname[PATH_MAX+1];
- FILE *f;
-
- f = fopen(name, "r");
- if (!f && name != NULL && name[0] != '/') {
- env = getenv(SRCTREE);
- if (env) {
- snprintf(fullname, sizeof(fullname),
- "%s/%s", env, name);
- f = fopen(fullname, "r");
- }
- }
- return f;
-}
-
-void zconf_initscan(const char *name)
-{
- yyin = zconf_fopen(name);
- if (!yyin) {
- fprintf(stderr, "can't find file %s\n", name);
- exit(1);
- }
-
- current_buf = xmalloc(sizeof(*current_buf));
- memset(current_buf, 0, sizeof(*current_buf));
-
- current_file = file_lookup(name);
- yylineno = 1;
-}
-
-void zconf_nextfile(const char *name)
-{
- struct file *iter;
- struct file *file = file_lookup(name);
- struct buffer *buf = xmalloc(sizeof(*buf));
- memset(buf, 0, sizeof(*buf));
-
- current_buf->state = YY_CURRENT_BUFFER;
- yyin = zconf_fopen(file->name);
- if (!yyin) {
- fprintf(stderr, "%s:%d: can't open file \"%s\"\n",
- zconf_curname(), zconf_lineno(), file->name);
- exit(1);
- }
- yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE));
- buf->parent = current_buf;
- current_buf = buf;
-
- current_file->lineno = yylineno;
- file->parent = current_file;
-
- for (iter = current_file; iter; iter = iter->parent) {
- if (!strcmp(iter->name, file->name)) {
- fprintf(stderr,
- "Recursive inclusion detected.\n"
- "Inclusion path:\n"
- " current file : %s\n", file->name);
- iter = file;
- do {
- iter = iter->parent;
- fprintf(stderr, " included from: %s:%d\n",
- iter->name, iter->lineno - 1);
- } while (strcmp(iter->name, file->name));
- exit(1);
- }
- }
-
- yylineno = 1;
- current_file = file;
-}
-
-static void zconf_endfile(void)
-{
- struct buffer *parent;
-
- current_file = current_file->parent;
- if (current_file)
- yylineno = current_file->lineno;
-
- parent = current_buf->parent;
- if (parent) {
- fclose(yyin);
- yy_delete_buffer(YY_CURRENT_BUFFER);
- yy_switch_to_buffer(parent->state);
- }
- free(current_buf);
- current_buf = parent;
-}
-
-int zconf_lineno(void)
-{
- return current_pos.lineno;
-}
-
-const char *zconf_curname(void)
-{
- return current_pos.file ? current_pos.file->name : "<none>";
-}
Index: v6.x/create-6.0.7-host-limits-patch/linux-6.0.7-new/scripts/kconfig/confdata.c
===================================================================
--- v6.x/create-6.0.7-host-limits-patch/linux-6.0.7-new/scripts/kconfig/confdata.c (revision 384)
+++ v6.x/create-6.0.7-host-limits-patch/linux-6.0.7-new/scripts/kconfig/confdata.c (nonexistent)
@@ -1,1188 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
- */
-
-#include <sys/mman.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <ctype.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <linux/limits.h>
-#include <stdarg.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <unistd.h>
-
-#include "lkc.h"
-
-/* return true if 'path' exists, false otherwise */
-static bool is_present(const char *path)
-{
- struct stat st;
-
- return !stat(path, &st);
-}
-
-/* return true if 'path' exists and it is a directory, false otherwise */
-static bool is_dir(const char *path)
-{
- struct stat st;
-
- if (stat(path, &st))
- return false;
-
- return S_ISDIR(st.st_mode);
-}
-
-/* return true if the given two files are the same, false otherwise */
-static bool is_same(const char *file1, const char *file2)
-{
- int fd1, fd2;
- struct stat st1, st2;
- void *map1, *map2;
- bool ret = false;
-
- fd1 = open(file1, O_RDONLY);
- if (fd1 < 0)
- return ret;
-
- fd2 = open(file2, O_RDONLY);
- if (fd2 < 0)
- goto close1;
-
- ret = fstat(fd1, &st1);
- if (ret)
- goto close2;
- ret = fstat(fd2, &st2);
- if (ret)
- goto close2;
-
- if (st1.st_size != st2.st_size)
- goto close2;
-
- map1 = mmap(NULL, st1.st_size, PROT_READ, MAP_PRIVATE, fd1, 0);
- if (map1 == MAP_FAILED)
- goto close2;
-
- map2 = mmap(NULL, st2.st_size, PROT_READ, MAP_PRIVATE, fd2, 0);
- if (map2 == MAP_FAILED)
- goto close2;
-
- if (bcmp(map1, map2, st1.st_size))
- goto close2;
-
- ret = true;
-close2:
- close(fd2);
-close1:
- close(fd1);
-
- return ret;
-}
-
-/*
- * Create the parent directory of the given path.
- *
- * For example, if 'include/config/auto.conf' is given, create 'include/config'.
- */
-static int make_parent_dir(const char *path)
-{
- char tmp[PATH_MAX + 1];
- char *p;
-
- strncpy(tmp, path, sizeof(tmp));
- tmp[sizeof(tmp) - 1] = 0;
-
- /* Remove the base name. Just return if nothing is left */
- p = strrchr(tmp, '/');
- if (!p)
- return 0;
- *(p + 1) = 0;
-
- /* Just in case it is an absolute path */
- p = tmp;
- while (*p == '/')
- p++;
-
- while ((p = strchr(p, '/'))) {
- *p = 0;
-
- /* skip if the directory exists */
- if (!is_dir(tmp) && mkdir(tmp, 0755))
- return -1;
-
- *p = '/';
- while (*p == '/')
- p++;
- }
-
- return 0;
-}
-
-static char depfile_path[PATH_MAX];
-static size_t depfile_prefix_len;
-
-/* touch depfile for symbol 'name' */
-static int conf_touch_dep(const char *name)
-{
- int fd;
-
- /* check overflow: prefix + name + '\0' must fit in buffer. */
- if (depfile_prefix_len + strlen(name) + 1 > sizeof(depfile_path))
- return -1;
-
- strcpy(depfile_path + depfile_prefix_len, name);
-
- fd = open(depfile_path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
- if (fd == -1)
- return -1;
- close(fd);
-
- return 0;
-}
-
-static void conf_warning(const char *fmt, ...)
- __attribute__ ((format (printf, 1, 2)));
-
-static void conf_message(const char *fmt, ...)
- __attribute__ ((format (printf, 1, 2)));
-
-static const char *conf_filename;
-static int conf_lineno, conf_warnings;
-
-static void conf_warning(const char *fmt, ...)
-{
- va_list ap;
- va_start(ap, fmt);
- fprintf(stderr, "%s:%d:warning: ", conf_filename, conf_lineno);
- vfprintf(stderr, fmt, ap);
- fprintf(stderr, "\n");
- va_end(ap);
- conf_warnings++;
-}
-
-static void conf_default_message_callback(const char *s)
-{
- printf("#\n# ");
- printf("%s", s);
- printf("\n#\n");
-}
-
-static void (*conf_message_callback)(const char *s) =
- conf_default_message_callback;
-void conf_set_message_callback(void (*fn)(const char *s))
-{
- conf_message_callback = fn;
-}
-
-static void conf_message(const char *fmt, ...)
-{
- va_list ap;
- char buf[4096];
-
- if (!conf_message_callback)
- return;
-
- va_start(ap, fmt);
-
- vsnprintf(buf, sizeof(buf), fmt, ap);
- conf_message_callback(buf);
- va_end(ap);
-}
-
-const char *conf_get_configname(void)
-{
- char *name = getenv("KCONFIG_CONFIG");
-
- return name ? name : ".config";
-}
-
-static const char *conf_get_autoconfig_name(void)
-{
- char *name = getenv("KCONFIG_AUTOCONFIG");
-
- return name ? name : "include/config/auto.conf";
-}
-
-static const char *conf_get_autoheader_name(void)
-{
- char *name = getenv("KCONFIG_AUTOHEADER");
-
- return name ? name : "include/generated/autoconf.h";
-}
-
-static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p)
-{
- char *p2;
-
- switch (sym->type) {
- case S_TRISTATE:
- if (p[0] == 'm') {
- sym->def[def].tri = mod;
- sym->flags |= def_flags;
- break;
- }
- /* fall through */
- case S_BOOLEAN:
- if (p[0] == 'y') {
- sym->def[def].tri = yes;
- sym->flags |= def_flags;
- break;
- }
- if (p[0] == 'n') {
- sym->def[def].tri = no;
- sym->flags |= def_flags;
- break;
- }
- if (def != S_DEF_AUTO)
- conf_warning("symbol value '%s' invalid for %s",
- p, sym->name);
- return 1;
- case S_STRING:
- /* No escaping for S_DEF_AUTO (include/config/auto.conf) */
- if (def != S_DEF_AUTO) {
- if (*p++ != '"')
- break;
- for (p2 = p; (p2 = strpbrk(p2, "\"\\")); p2++) {
- if (*p2 == '"') {
- *p2 = 0;
- break;
- }
- memmove(p2, p2 + 1, strlen(p2));
- }
- if (!p2) {
- conf_warning("invalid string found");
- return 1;
- }
- }
- /* fall through */
- case S_INT:
- case S_HEX:
- if (sym_string_valid(sym, p)) {
- sym->def[def].val = xstrdup(p);
- sym->flags |= def_flags;
- } else {
- if (def != S_DEF_AUTO)
- conf_warning("symbol value '%s' invalid for %s",
- p, sym->name);
- return 1;
- }
- break;
- default:
- ;
- }
- return 0;
-}
-
-#define LINE_GROWTH 16
-static int add_byte(int c, char **lineptr, size_t slen, size_t *n)
-{
- char *nline;
- size_t new_size = slen + 1;
- if (new_size > *n) {
- new_size += LINE_GROWTH - 1;
- new_size *= 2;
- nline = xrealloc(*lineptr, new_size);
- if (!nline)
- return -1;
-
- *lineptr = nline;
- *n = new_size;
- }
-
- (*lineptr)[slen] = c;
-
- return 0;
-}
-
-static ssize_t compat_getline(char **lineptr, size_t *n, FILE *stream)
-{
- char *line = *lineptr;
- size_t slen = 0;
-
- for (;;) {
- int c = getc(stream);
-
- switch (c) {
- case '\n':
- if (add_byte(c, &line, slen, n) < 0)
- goto e_out;
- slen++;
- /* fall through */
- case EOF:
- if (add_byte('\0', &line, slen, n) < 0)
- goto e_out;
- *lineptr = line;
- if (slen == 0)
- return -1;
- return slen;
- default:
- if (add_byte(c, &line, slen, n) < 0)
- goto e_out;
- slen++;
- }
- }
-
-e_out:
- line[slen-1] = '\0';
- *lineptr = line;
- return -1;
-}
-
-int conf_read_simple(const char *name, int def)
-{
- FILE *in = NULL;
- char *line = NULL;
- size_t line_asize = 0;
- char *p, *p2;
- struct symbol *sym;
- int i, def_flags;
-
- if (name) {
- in = zconf_fopen(name);
- } else {
- char *env;
-
- name = conf_get_configname();
- in = zconf_fopen(name);
- if (in)
- goto load;
- conf_set_changed(true);
-
- env = getenv("KCONFIG_DEFCONFIG_LIST");
- if (!env)
- return 1;
-
- while (1) {
- bool is_last;
-
- while (isspace(*env))
- env++;
-
- if (!*env)
- break;
-
- p = env;
- while (*p && !isspace(*p))
- p++;
-
- is_last = (*p == '\0');
-
- *p = '\0';
-
- in = zconf_fopen(env);
- if (in) {
- conf_message("using defaults found in %s",
- env);
- goto load;
- }
-
- if (is_last)
- break;
-
- env = p + 1;
- }
- }
- if (!in)
- return 1;
-
-load:
- conf_filename = name;
- conf_lineno = 0;
- conf_warnings = 0;
-
- def_flags = SYMBOL_DEF << def;
- for_all_symbols(i, sym) {
- sym->flags |= SYMBOL_CHANGED;
- sym->flags &= ~(def_flags|SYMBOL_VALID);
- if (sym_is_choice(sym))
- sym->flags |= def_flags;
- switch (sym->type) {
- case S_INT:
- case S_HEX:
- case S_STRING:
- if (sym->def[def].val)
- free(sym->def[def].val);
- /* fall through */
- default:
- sym->def[def].val = NULL;
- sym->def[def].tri = no;
- }
- }
-
- while (compat_getline(&line, &line_asize, in) != -1) {
- conf_lineno++;
- sym = NULL;
- if (line[0] == '#') {
- if (memcmp(line + 2, CONFIG_, strlen(CONFIG_)))
- continue;
- p = strchr(line + 2 + strlen(CONFIG_), ' ');
- if (!p)
- continue;
- *p++ = 0;
- if (strncmp(p, "is not set", 10))
- continue;
- if (def == S_DEF_USER) {
- sym = sym_find(line + 2 + strlen(CONFIG_));
- if (!sym) {
- conf_set_changed(true);
- continue;
- }
- } else {
- sym = sym_lookup(line + 2 + strlen(CONFIG_), 0);
- if (sym->type == S_UNKNOWN)
- sym->type = S_BOOLEAN;
- }
- if (sym->flags & def_flags) {
- conf_warning("override: reassigning to symbol %s", sym->name);
- }
- switch (sym->type) {
- case S_BOOLEAN:
- case S_TRISTATE:
- sym->def[def].tri = no;
- sym->flags |= def_flags;
- break;
- default:
- ;
- }
- } else if (memcmp(line, CONFIG_, strlen(CONFIG_)) == 0) {
- p = strchr(line + strlen(CONFIG_), '=');
- if (!p)
- continue;
- *p++ = 0;
- p2 = strchr(p, '\n');
- if (p2) {
- *p2-- = 0;
- if (*p2 == '\r')
- *p2 = 0;
- }
-
- sym = sym_find(line + strlen(CONFIG_));
- if (!sym) {
- if (def == S_DEF_AUTO)
- /*
- * Reading from include/config/auto.conf
- * If CONFIG_FOO previously existed in
- * auto.conf but it is missing now,
- * include/config/FOO must be touched.
- */
- conf_touch_dep(line + strlen(CONFIG_));
- else
- conf_set_changed(true);
- continue;
- }
-
- if (sym->flags & def_flags) {
- conf_warning("override: reassigning to symbol %s", sym->name);
- }
- if (conf_set_sym_val(sym, def, def_flags, p))
- continue;
- } else {
- if (line[0] != '\r' && line[0] != '\n')
- conf_warning("unexpected data: %.*s",
- (int)strcspn(line, "\r\n"), line);
-
- continue;
- }
-
- if (sym && sym_is_choice_value(sym)) {
- struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym));
- switch (sym->def[def].tri) {
- case no:
- break;
- case mod:
- if (cs->def[def].tri == yes) {
- conf_warning("%s creates inconsistent choice state", sym->name);
- cs->flags &= ~def_flags;
- }
- break;
- case yes:
- if (cs->def[def].tri != no)
- conf_warning("override: %s changes choice state", sym->name);
- cs->def[def].val = sym;
- break;
- }
- cs->def[def].tri = EXPR_OR(cs->def[def].tri, sym->def[def].tri);
- }
- }
- free(line);
- fclose(in);
- return 0;
-}
-
-int conf_read(const char *name)
-{
- struct symbol *sym;
- int conf_unsaved = 0;
- int i;
-
- conf_set_changed(false);
-
- if (conf_read_simple(name, S_DEF_USER)) {
- sym_calc_value(modules_sym);
- return 1;
- }
-
- sym_calc_value(modules_sym);
-
- for_all_symbols(i, sym) {
- sym_calc_value(sym);
- if (sym_is_choice(sym) || (sym->flags & SYMBOL_NO_WRITE))
- continue;
- if (sym_has_value(sym) && (sym->flags & SYMBOL_WRITE)) {
- /* check that calculated value agrees with saved value */
- switch (sym->type) {
- case S_BOOLEAN:
- case S_TRISTATE:
- if (sym->def[S_DEF_USER].tri == sym_get_tristate_value(sym))
- continue;
- break;
- default:
- if (!strcmp(sym->curr.val, sym->def[S_DEF_USER].val))
- continue;
- break;
- }
- } else if (!sym_has_value(sym) && !(sym->flags & SYMBOL_WRITE))
- /* no previous value and not saved */
- continue;
- conf_unsaved++;
- /* maybe print value in verbose mode... */
- }
-
- for_all_symbols(i, sym) {
- if (sym_has_value(sym) && !sym_is_choice_value(sym)) {
- /* Reset values of generates values, so they'll appear
- * as new, if they should become visible, but that
- * doesn't quite work if the Kconfig and the saved
- * configuration disagree.
- */
- if (sym->visible == no && !conf_unsaved)
- sym->flags &= ~SYMBOL_DEF_USER;
- switch (sym->type) {
- case S_STRING:
- case S_INT:
- case S_HEX:
- /* Reset a string value if it's out of range */
- if (sym_string_within_range(sym, sym->def[S_DEF_USER].val))
- break;
- sym->flags &= ~(SYMBOL_VALID|SYMBOL_DEF_USER);
- conf_unsaved++;
- break;
- default:
- break;
- }
- }
- }
-
- if (conf_warnings || conf_unsaved)
- conf_set_changed(true);
-
- return 0;
-}
-
-struct comment_style {
- const char *decoration;
- const char *prefix;
- const char *postfix;
-};
-
-static const struct comment_style comment_style_pound = {
- .decoration = "#",
- .prefix = "#",
- .postfix = "#",
-};
-
-static const struct comment_style comment_style_c = {
- .decoration = " *",
- .prefix = "/*",
- .postfix = " */",
-};
-
-static void conf_write_heading(FILE *fp, const struct comment_style *cs)
-{
- fprintf(fp, "%s\n", cs->prefix);
-
- fprintf(fp, "%s Automatically generated file; DO NOT EDIT.\n",
- cs->decoration);
-
- fprintf(fp, "%s %s\n", cs->decoration, rootmenu.prompt->text);
-
- fprintf(fp, "%s\n", cs->postfix);
-}
-
-/* The returned pointer must be freed on the caller side */
-static char *escape_string_value(const char *in)
-{
- const char *p;
- char *out;
- size_t len;
-
- len = strlen(in) + strlen("\"\"") + 1;
-
- p = in;
- while (1) {
- p += strcspn(p, "\"\\");
-
- if (p[0] == '\0')
- break;
-
- len++;
- p++;
- }
-
- out = xmalloc(len);
- out[0] = '\0';
-
- strcat(out, "\"");
-
- p = in;
- while (1) {
- len = strcspn(p, "\"\\");
- strncat(out, p, len);
- p += len;
-
- if (p[0] == '\0')
- break;
-
- strcat(out, "\\");
- strncat(out, p++, 1);
- }
-
- strcat(out, "\"");
-
- return out;
-}
-
-enum output_n { OUTPUT_N, OUTPUT_N_AS_UNSET, OUTPUT_N_NONE };
-
-static void __print_symbol(FILE *fp, struct symbol *sym, enum output_n output_n,
- bool escape_string)
-{
- const char *val;
- char *escaped = NULL;
-
- if (sym->type == S_UNKNOWN)
- return;
-
- val = sym_get_string_value(sym);
-
- if ((sym->type == S_BOOLEAN || sym->type == S_TRISTATE) &&
- output_n != OUTPUT_N && *val == 'n') {
- if (output_n == OUTPUT_N_AS_UNSET)
- fprintf(fp, "# %s%s is not set\n", CONFIG_, sym->name);
- return;
- }
-
- if (sym->type == S_STRING && escape_string) {
- escaped = escape_string_value(val);
- val = escaped;
- }
-
- fprintf(fp, "%s%s=%s\n", CONFIG_, sym->name, val);
-
- free(escaped);
-}
-
-static void print_symbol_for_dotconfig(FILE *fp, struct symbol *sym)
-{
- __print_symbol(fp, sym, OUTPUT_N_AS_UNSET, true);
-}
-
-static void print_symbol_for_autoconf(FILE *fp, struct symbol *sym)
-{
- __print_symbol(fp, sym, OUTPUT_N_NONE, false);
-}
-
-void print_symbol_for_listconfig(struct symbol *sym)
-{
- __print_symbol(stdout, sym, OUTPUT_N, true);
-}
-
-static void print_symbol_for_c(FILE *fp, struct symbol *sym)
-{
- const char *val;
- const char *sym_suffix = "";
- const char *val_prefix = "";
- char *escaped = NULL;
-
- if (sym->type == S_UNKNOWN)
- return;
-
- val = sym_get_string_value(sym);
-
- switch (sym->type) {
- case S_BOOLEAN:
- case S_TRISTATE:
- switch (*val) {
- case 'n':
- return;
- case 'm':
- sym_suffix = "_MODULE";
- /* fall through */
- default:
- val = "1";
- }
- break;
- case S_HEX:
- if (val[0] != '0' || (val[1] != 'x' && val[1] != 'X'))
- val_prefix = "0x";
- break;
- case S_STRING:
- escaped = escape_string_value(val);
- val = escaped;
- default:
- break;
- }
-
- fprintf(fp, "#define %s%s%s %s%s\n", CONFIG_, sym->name, sym_suffix,
- val_prefix, val);
-
- free(escaped);
-}
-
-/*
- * Write out a minimal config.
- * All values that has default values are skipped as this is redundant.
- */
-int conf_write_defconfig(const char *filename)
-{
- struct symbol *sym;
- struct menu *menu;
- FILE *out;
-
- out = fopen(filename, "w");
- if (!out)
- return 1;
-
- sym_clear_all_valid();
-
- /* Traverse all menus to find all relevant symbols */
- menu = rootmenu.list;
-
- while (menu != NULL)
- {
- sym = menu->sym;
- if (sym == NULL) {
- if (!menu_is_visible(menu))
- goto next_menu;
- } else if (!sym_is_choice(sym)) {
- sym_calc_value(sym);
- if (!(sym->flags & SYMBOL_WRITE))
- goto next_menu;
- sym->flags &= ~SYMBOL_WRITE;
- /* If we cannot change the symbol - skip */
- if (!sym_is_changeable(sym))
- goto next_menu;
- /* If symbol equals to default value - skip */
- if (strcmp(sym_get_string_value(sym), sym_get_string_default(sym)) == 0)
- goto next_menu;
-
- /*
- * If symbol is a choice value and equals to the
- * default for a choice - skip.
- * But only if value is bool and equal to "y" and
- * choice is not "optional".
- * (If choice is "optional" then all values can be "n")
- */
- if (sym_is_choice_value(sym)) {
- struct symbol *cs;
- struct symbol *ds;
-
- cs = prop_get_symbol(sym_get_choice_prop(sym));
- ds = sym_choice_default(cs);
- if (!sym_is_optional(cs) && sym == ds) {
- if ((sym->type == S_BOOLEAN) &&
- sym_get_tristate_value(sym) == yes)
- goto next_menu;
- }
- }
- print_symbol_for_dotconfig(out, sym);
- }
-next_menu:
- if (menu->list != NULL) {
- menu = menu->list;
- }
- else if (menu->next != NULL) {
- menu = menu->next;
- } else {
- while ((menu = menu->parent)) {
- if (menu->next != NULL) {
- menu = menu->next;
- break;
- }
- }
- }
- }
- fclose(out);
- return 0;
-}
-
-int conf_write(const char *name)
-{
- FILE *out;
- struct symbol *sym;
- struct menu *menu;
- const char *str;
- char tmpname[PATH_MAX + 1], oldname[PATH_MAX + 1];
- char *env;
- int i;
- bool need_newline = false;
-
- if (!name)
- name = conf_get_configname();
-
- if (!*name) {
- fprintf(stderr, "config name is empty\n");
- return -1;
- }
-
- if (is_dir(name)) {
- fprintf(stderr, "%s: Is a directory\n", name);
- return -1;
- }
-
- if (make_parent_dir(name))
- return -1;
-
- env = getenv("KCONFIG_OVERWRITECONFIG");
- if (env && *env) {
- *tmpname = 0;
- out = fopen(name, "w");
- } else {
- snprintf(tmpname, sizeof(tmpname), "%s.%d.tmp",
- name, (int)getpid());
- out = fopen(tmpname, "w");
- }
- if (!out)
- return 1;
-
- conf_write_heading(out, &comment_style_pound);
-
- if (!conf_get_changed())
- sym_clear_all_valid();
-
- menu = rootmenu.list;
- while (menu) {
- sym = menu->sym;
- if (!sym) {
- if (!menu_is_visible(menu))
- goto next;
- str = menu_get_prompt(menu);
- fprintf(out, "\n"
- "#\n"
- "# %s\n"
- "#\n", str);
- need_newline = false;
- } else if (!(sym->flags & SYMBOL_CHOICE) &&
- !(sym->flags & SYMBOL_WRITTEN)) {
- sym_calc_value(sym);
- if (!(sym->flags & SYMBOL_WRITE))
- goto next;
- if (need_newline) {
- fprintf(out, "\n");
- need_newline = false;
- }
- sym->flags |= SYMBOL_WRITTEN;
- print_symbol_for_dotconfig(out, sym);
- }
-
-next:
- if (menu->list) {
- menu = menu->list;
- continue;
- }
-
-end_check:
- if (!menu->sym && menu_is_visible(menu) && menu != &rootmenu &&
- menu->prompt->type == P_MENU) {
- fprintf(out, "# end of %s\n", menu_get_prompt(menu));
- need_newline = true;
- }
-
- if (menu->next) {
- menu = menu->next;
- } else {
- menu = menu->parent;
- if (menu)
- goto end_check;
- }
- }
- fclose(out);
-
- for_all_symbols(i, sym)
- sym->flags &= ~SYMBOL_WRITTEN;
-
- if (*tmpname) {
- if (is_same(name, tmpname)) {
- conf_message("No change to %s", name);
- unlink(tmpname);
- conf_set_changed(false);
- return 0;
- }
-
- snprintf(oldname, sizeof(oldname), "%s.old", name);
- rename(name, oldname);
- if (rename(tmpname, name))
- return 1;
- }
-
- conf_message("configuration written to %s", name);
-
- conf_set_changed(false);
-
- return 0;
-}
-
-/* write a dependency file as used by kbuild to track dependencies */
-static int conf_write_autoconf_cmd(const char *autoconf_name)
-{
- char name[PATH_MAX], tmp[PATH_MAX];
- struct file *file;
- FILE *out;
- int ret;
-
- ret = snprintf(name, sizeof(name), "%s.cmd", autoconf_name);
- if (ret >= sizeof(name)) /* check truncation */
- return -1;
-
- if (make_parent_dir(name))
- return -1;
-
- ret = snprintf(tmp, sizeof(tmp), "%s.cmd.tmp", autoconf_name);
- if (ret >= sizeof(tmp)) /* check truncation */
- return -1;
-
- out = fopen(tmp, "w");
- if (!out) {
- perror("fopen");
- return -1;
- }
-
- fprintf(out, "deps_config := \\\n");
- for (file = file_list; file; file = file->next)
- fprintf(out, "\t%s \\\n", file->name);
-
- fprintf(out, "\n%s: $(deps_config)\n\n", autoconf_name);
-
- env_write_dep(out, autoconf_name);
-
- fprintf(out, "\n$(deps_config): ;\n");
-
- fflush(out);
- ret = ferror(out); /* error check for all fprintf() calls */
- fclose(out);
- if (ret)
- return -1;
-
- if (rename(tmp, name)) {
- perror("rename");
- return -1;
- }
-
- return 0;
-}
-
-static int conf_touch_deps(void)
-{
- const char *name, *tmp;
- struct symbol *sym;
- int res, i;
-
- name = conf_get_autoconfig_name();
- tmp = strrchr(name, '/');
- depfile_prefix_len = tmp ? tmp - name + 1 : 0;
- if (depfile_prefix_len + 1 > sizeof(depfile_path))
- return -1;
-
- strncpy(depfile_path, name, depfile_prefix_len);
- depfile_path[depfile_prefix_len] = 0;
-
- conf_read_simple(name, S_DEF_AUTO);
- sym_calc_value(modules_sym);
-
- for_all_symbols(i, sym) {
- sym_calc_value(sym);
- if ((sym->flags & SYMBOL_NO_WRITE) || !sym->name)
- continue;
- if (sym->flags & SYMBOL_WRITE) {
- if (sym->flags & SYMBOL_DEF_AUTO) {
- /*
- * symbol has old and new value,
- * so compare them...
- */
- switch (sym->type) {
- case S_BOOLEAN:
- case S_TRISTATE:
- if (sym_get_tristate_value(sym) ==
- sym->def[S_DEF_AUTO].tri)
- continue;
- break;
- case S_STRING:
- case S_HEX:
- case S_INT:
- if (!strcmp(sym_get_string_value(sym),
- sym->def[S_DEF_AUTO].val))
- continue;
- break;
- default:
- break;
- }
- } else {
- /*
- * If there is no old value, only 'no' (unset)
- * is allowed as new value.
- */
- switch (sym->type) {
- case S_BOOLEAN:
- case S_TRISTATE:
- if (sym_get_tristate_value(sym) == no)
- continue;
- break;
- default:
- break;
- }
- }
- } else if (!(sym->flags & SYMBOL_DEF_AUTO))
- /* There is neither an old nor a new value. */
- continue;
- /* else
- * There is an old value, but no new value ('no' (unset)
- * isn't saved in auto.conf, so the old value is always
- * different from 'no').
- */
-
- res = conf_touch_dep(sym->name);
- if (res)
- return res;
- }
-
- return 0;
-}
-
-static int __conf_write_autoconf(const char *filename,
- void (*print_symbol)(FILE *, struct symbol *),
- const struct comment_style *comment_style)
-{
- char tmp[PATH_MAX];
- FILE *file;
- struct symbol *sym;
- int ret, i;
-
- if (make_parent_dir(filename))
- return -1;
-
- ret = snprintf(tmp, sizeof(tmp), "%s.tmp", filename);
- if (ret >= sizeof(tmp)) /* check truncation */
- return -1;
-
- file = fopen(tmp, "w");
- if (!file) {
- perror("fopen");
- return -1;
- }
-
- conf_write_heading(file, comment_style);
-
- for_all_symbols(i, sym)
- if ((sym->flags & SYMBOL_WRITE) && sym->name)
- print_symbol(file, sym);
-
- fflush(file);
- /* check possible errors in conf_write_heading() and print_symbol() */
- ret = ferror(file);
- fclose(file);
- if (ret)
- return -1;
-
- if (rename(tmp, filename)) {
- perror("rename");
- return -1;
- }
-
- return 0;
-}
-
-int conf_write_autoconf(int overwrite)
-{
- struct symbol *sym;
- const char *autoconf_name = conf_get_autoconfig_name();
- int ret, i;
-
- if (!overwrite && is_present(autoconf_name))
- return 0;
-
- ret = conf_write_autoconf_cmd(autoconf_name);
- if (ret)
- return -1;
-
- if (conf_touch_deps())
- return 1;
-
- for_all_symbols(i, sym)
- sym_calc_value(sym);
-
- ret = __conf_write_autoconf(conf_get_autoheader_name(),
- print_symbol_for_c,
- &comment_style_c);
- if (ret)
- return ret;
-
- /*
- * Create include/config/auto.conf. This must be the last step because
- * Kbuild has a dependency on auto.conf and this marks the successful
- * completion of the previous steps.
- */
- ret = __conf_write_autoconf(conf_get_autoconfig_name(),
- print_symbol_for_autoconf,
- &comment_style_pound);
- if (ret)
- return ret;
-
- return 0;
-}
-
-static bool conf_changed;
-static void (*conf_changed_callback)(void);
-
-void conf_set_changed(bool val)
-{
- if (conf_changed_callback && conf_changed != val)
- conf_changed_callback();
-
- conf_changed = val;
-}
-
-bool conf_get_changed(void)
-{
- return conf_changed;
-}
-
-void conf_set_changed_callback(void (*fn)(void))
-{
- conf_changed_callback = fn;
-}
-
-void set_all_choice_values(struct symbol *csym)
-{
- struct property *prop;
- struct symbol *sym;
- struct expr *e;
-
- prop = sym_get_choice_prop(csym);
-
- /*
- * Set all non-assinged choice values to no
- */
- expr_list_for_each_sym(prop->expr, e, sym) {
- if (!sym_has_value(sym))
- sym->def[S_DEF_USER].tri = no;
- }
- csym->flags |= SYMBOL_DEF_USER;
- /* clear VALID to get value calculated */
- csym->flags &= ~(SYMBOL_VALID | SYMBOL_NEED_SET_CHOICE_VALUES);
-}
Index: v6.x/create-6.0.7-host-limits-patch/linux-6.0.7-new/scripts/kconfig/conf.c
===================================================================
--- v6.x/create-6.0.7-host-limits-patch/linux-6.0.7-new/scripts/kconfig/conf.c (revision 384)
+++ v6.x/create-6.0.7-host-limits-patch/linux-6.0.7-new/scripts/kconfig/conf.c (nonexistent)
@@ -1,921 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
- */
-
-#include <ctype.h>
-#include <linux/limits.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <unistd.h>
-#include <getopt.h>
-#include <sys/time.h>
-#include <errno.h>
-
-#include "lkc.h"
-
-static void conf(struct menu *menu);
-static void check_conf(struct menu *menu);
-
-enum input_mode {
- oldaskconfig,
- syncconfig,
- oldconfig,
- allnoconfig,
- allyesconfig,
- allmodconfig,
- alldefconfig,
- randconfig,
- defconfig,
- savedefconfig,
- listnewconfig,
- helpnewconfig,
- olddefconfig,
- yes2modconfig,
- mod2yesconfig,
- mod2noconfig,
-};
-static enum input_mode input_mode = oldaskconfig;
-static int input_mode_opt;
-static int indent = 1;
-static int tty_stdio;
-static int sync_kconfig;
-static int conf_cnt;
-static char line[PATH_MAX];
-static struct menu *rootEntry;
-
-static void print_help(struct menu *menu)
-{
- struct gstr help = str_new();
-
- menu_get_ext_help(menu, &help);
-
- printf("\n%s\n", str_get(&help));
- str_free(&help);
-}
-
-static void strip(char *str)
-{
- char *p = str;
- int l;
-
- while ((isspace(*p)))
- p++;
- l = strlen(p);
- if (p != str)
- memmove(str, p, l + 1);
- if (!l)
- return;
- p = str + l - 1;
- while ((isspace(*p)))
- *p-- = 0;
-}
-
-/* Helper function to facilitate fgets() by Jean Sacren. */
-static void xfgets(char *str, int size, FILE *in)
-{
- if (!fgets(str, size, in))
- fprintf(stderr, "\nError in reading or end of file.\n");
-
- if (!tty_stdio)
- printf("%s", str);
-}
-
-static void set_randconfig_seed(void)
-{
- unsigned int seed;
- char *env;
- bool seed_set = false;
-
- env = getenv("KCONFIG_SEED");
- if (env && *env) {
- char *endp;
-
- seed = strtol(env, &endp, 0);
- if (*endp == '\0')
- seed_set = true;
- }
-
- if (!seed_set) {
- struct timeval now;
-
- /*
- * Use microseconds derived seed, compensate for systems where it may
- * be zero.
- */
- gettimeofday(&now, NULL);
- seed = (now.tv_sec + 1) * (now.tv_usec + 1);
- }
-
- printf("KCONFIG_SEED=0x%X\n", seed);
- srand(seed);
-}
-
-static bool randomize_choice_values(struct symbol *csym)
-{
- struct property *prop;
- struct symbol *sym;
- struct expr *e;
- int cnt, def;
-
- /*
- * If choice is mod then we may have more items selected
- * and if no then no-one.
- * In both cases stop.
- */
- if (csym->curr.tri != yes)
- return false;
-
- prop = sym_get_choice_prop(csym);
-
- /* count entries in choice block */
- cnt = 0;
- expr_list_for_each_sym(prop->expr, e, sym)
- cnt++;
-
- /*
- * find a random value and set it to yes,
- * set the rest to no so we have only one set
- */
- def = rand() % cnt;
-
- cnt = 0;
- expr_list_for_each_sym(prop->expr, e, sym) {
- if (def == cnt++) {
- sym->def[S_DEF_USER].tri = yes;
- csym->def[S_DEF_USER].val = sym;
- } else {
- sym->def[S_DEF_USER].tri = no;
- }
- sym->flags |= SYMBOL_DEF_USER;
- /* clear VALID to get value calculated */
- sym->flags &= ~SYMBOL_VALID;
- }
- csym->flags |= SYMBOL_DEF_USER;
- /* clear VALID to get value calculated */
- csym->flags &= ~SYMBOL_VALID;
-
- return true;
-}
-
-enum conf_def_mode {
- def_default,
- def_yes,
- def_mod,
- def_no,
- def_random
-};
-
-static bool conf_set_all_new_symbols(enum conf_def_mode mode)
-{
- struct symbol *sym, *csym;
- int i, cnt;
- /*
- * can't go as the default in switch-case below, otherwise gcc whines
- * about -Wmaybe-uninitialized
- */
- int pby = 50; /* probability of bool = y */
- int pty = 33; /* probability of tristate = y */
- int ptm = 33; /* probability of tristate = m */
- bool has_changed = false;
-
- if (mode == def_random) {
- int n, p[3];
- char *env = getenv("KCONFIG_PROBABILITY");
-
- n = 0;
- while (env && *env) {
- char *endp;
- int tmp = strtol(env, &endp, 10);
-
- if (tmp >= 0 && tmp <= 100) {
- p[n++] = tmp;
- } else {
- errno = ERANGE;
- perror("KCONFIG_PROBABILITY");
- exit(1);
- }
- env = (*endp == ':') ? endp + 1 : endp;
- if (n >= 3)
- break;
- }
- switch (n) {
- case 1:
- pby = p[0];
- ptm = pby / 2;
- pty = pby - ptm;
- break;
- case 2:
- pty = p[0];
- ptm = p[1];
- pby = pty + ptm;
- break;
- case 3:
- pby = p[0];
- pty = p[1];
- ptm = p[2];
- break;
- }
-
- if (pty + ptm > 100) {
- errno = ERANGE;
- perror("KCONFIG_PROBABILITY");
- exit(1);
- }
- }
-
- for_all_symbols(i, sym) {
- if (sym_has_value(sym) || sym->flags & SYMBOL_VALID)
- continue;
- switch (sym_get_type(sym)) {
- case S_BOOLEAN:
- case S_TRISTATE:
- has_changed = true;
- switch (mode) {
- case def_yes:
- sym->def[S_DEF_USER].tri = yes;
- break;
- case def_mod:
- sym->def[S_DEF_USER].tri = mod;
- break;
- case def_no:
- sym->def[S_DEF_USER].tri = no;
- break;
- case def_random:
- sym->def[S_DEF_USER].tri = no;
- cnt = rand() % 100;
- if (sym->type == S_TRISTATE) {
- if (cnt < pty)
- sym->def[S_DEF_USER].tri = yes;
- else if (cnt < pty + ptm)
- sym->def[S_DEF_USER].tri = mod;
- } else if (cnt < pby)
- sym->def[S_DEF_USER].tri = yes;
- break;
- default:
- continue;
- }
- if (!(sym_is_choice(sym) && mode == def_random))
- sym->flags |= SYMBOL_DEF_USER;
- break;
- default:
- break;
- }
-
- }
-
- sym_clear_all_valid();
-
- /*
- * We have different type of choice blocks.
- * If curr.tri equals to mod then we can select several
- * choice symbols in one block.
- * In this case we do nothing.
- * If curr.tri equals yes then only one symbol can be
- * selected in a choice block and we set it to yes,
- * and the rest to no.
- */
- if (mode != def_random) {
- for_all_symbols(i, csym) {
- if ((sym_is_choice(csym) && !sym_has_value(csym)) ||
- sym_is_choice_value(csym))
- csym->flags |= SYMBOL_NEED_SET_CHOICE_VALUES;
- }
- }
-
- for_all_symbols(i, csym) {
- if (sym_has_value(csym) || !sym_is_choice(csym))
- continue;
-
- sym_calc_value(csym);
- if (mode == def_random)
- has_changed |= randomize_choice_values(csym);
- else {
- set_all_choice_values(csym);
- has_changed = true;
- }
- }
-
- return has_changed;
-}
-
-static void conf_rewrite_tristates(tristate old_val, tristate new_val)
-{
- struct symbol *sym;
- int i;
-
- for_all_symbols(i, sym) {
- if (sym_get_type(sym) == S_TRISTATE &&
- sym->def[S_DEF_USER].tri == old_val)
- sym->def[S_DEF_USER].tri = new_val;
- }
- sym_clear_all_valid();
-}
-
-static int conf_askvalue(struct symbol *sym, const char *def)
-{
- if (!sym_has_value(sym))
- printf("(NEW) ");
-
- line[0] = '\n';
- line[1] = 0;
-
- if (!sym_is_changeable(sym)) {
- printf("%s\n", def);
- line[0] = '\n';
- line[1] = 0;
- return 0;
- }
-
- switch (input_mode) {
- case oldconfig:
- case syncconfig:
- if (sym_has_value(sym)) {
- printf("%s\n", def);
- return 0;
- }
- /* fall through */
- default:
- fflush(stdout);
- xfgets(line, sizeof(line), stdin);
- break;
- }
-
- return 1;
-}
-
-static int conf_string(struct menu *menu)
-{
- struct symbol *sym = menu->sym;
- const char *def;
-
- while (1) {
- printf("%*s%s ", indent - 1, "", menu->prompt->text);
- printf("(%s) ", sym->name);
- def = sym_get_string_value(sym);
- if (def)
- printf("[%s] ", def);
- if (!conf_askvalue(sym, def))
- return 0;
- switch (line[0]) {
- case '\n':
- break;
- case '?':
- /* print help */
- if (line[1] == '\n') {
- print_help(menu);
- def = NULL;
- break;
- }
- /* fall through */
- default:
- line[strlen(line)-1] = 0;
- def = line;
- }
- if (def && sym_set_string_value(sym, def))
- return 0;
- }
-}
-
-static int conf_sym(struct menu *menu)
-{
- struct symbol *sym = menu->sym;
- tristate oldval, newval;
-
- while (1) {
- printf("%*s%s ", indent - 1, "", menu->prompt->text);
- if (sym->name)
- printf("(%s) ", sym->name);
- putchar('[');
- oldval = sym_get_tristate_value(sym);
- switch (oldval) {
- case no:
- putchar('N');
- break;
- case mod:
- putchar('M');
- break;
- case yes:
- putchar('Y');
- break;
- }
- if (oldval != no && sym_tristate_within_range(sym, no))
- printf("/n");
- if (oldval != mod && sym_tristate_within_range(sym, mod))
- printf("/m");
- if (oldval != yes && sym_tristate_within_range(sym, yes))
- printf("/y");
- printf("/?] ");
- if (!conf_askvalue(sym, sym_get_string_value(sym)))
- return 0;
- strip(line);
-
- switch (line[0]) {
- case 'n':
- case 'N':
- newval = no;
- if (!line[1] || !strcmp(&line[1], "o"))
- break;
- continue;
- case 'm':
- case 'M':
- newval = mod;
- if (!line[1])
- break;
- continue;
- case 'y':
- case 'Y':
- newval = yes;
- if (!line[1] || !strcmp(&line[1], "es"))
- break;
- continue;
- case 0:
- newval = oldval;
- break;
- case '?':
- goto help;
- default:
- continue;
- }
- if (sym_set_tristate_value(sym, newval))
- return 0;
-help:
- print_help(menu);
- }
-}
-
-static int conf_choice(struct menu *menu)
-{
- struct symbol *sym, *def_sym;
- struct menu *child;
- bool is_new;
-
- sym = menu->sym;
- is_new = !sym_has_value(sym);
- if (sym_is_changeable(sym)) {
- conf_sym(menu);
- sym_calc_value(sym);
- switch (sym_get_tristate_value(sym)) {
- case no:
- return 1;
- case mod:
- return 0;
- case yes:
- break;
- }
- } else {
- switch (sym_get_tristate_value(sym)) {
- case no:
- return 1;
- case mod:
- printf("%*s%s\n", indent - 1, "", menu_get_prompt(menu));
- return 0;
- case yes:
- break;
- }
- }
-
- while (1) {
- int cnt, def;
-
- printf("%*s%s\n", indent - 1, "", menu_get_prompt(menu));
- def_sym = sym_get_choice_value(sym);
- cnt = def = 0;
- line[0] = 0;
- for (child = menu->list; child; child = child->next) {
- if (!menu_is_visible(child))
- continue;
- if (!child->sym) {
- printf("%*c %s\n", indent, '*', menu_get_prompt(child));
- continue;
- }
- cnt++;
- if (child->sym == def_sym) {
- def = cnt;
- printf("%*c", indent, '>');
- } else
- printf("%*c", indent, ' ');
- printf(" %d. %s", cnt, menu_get_prompt(child));
- if (child->sym->name)
- printf(" (%s)", child->sym->name);
- if (!sym_has_value(child->sym))
- printf(" (NEW)");
- printf("\n");
- }
- printf("%*schoice", indent - 1, "");
- if (cnt == 1) {
- printf("[1]: 1\n");
- goto conf_childs;
- }
- printf("[1-%d?]: ", cnt);
- switch (input_mode) {
- case oldconfig:
- case syncconfig:
- if (!is_new) {
- cnt = def;
- printf("%d\n", cnt);
- break;
- }
- /* fall through */
- case oldaskconfig:
- fflush(stdout);
- xfgets(line, sizeof(line), stdin);
- strip(line);
- if (line[0] == '?') {
- print_help(menu);
- continue;
- }
- if (!line[0])
- cnt = def;
- else if (isdigit(line[0]))
- cnt = atoi(line);
- else
- continue;
- break;
- default:
- break;
- }
-
- conf_childs:
- for (child = menu->list; child; child = child->next) {
- if (!child->sym || !menu_is_visible(child))
- continue;
- if (!--cnt)
- break;
- }
- if (!child)
- continue;
- if (line[0] && line[strlen(line) - 1] == '?') {
- print_help(child);
- continue;
- }
- sym_set_choice_value(sym, child->sym);
- for (child = child->list; child; child = child->next) {
- indent += 2;
- conf(child);
- indent -= 2;
- }
- return 1;
- }
-}
-
-static void conf(struct menu *menu)
-{
- struct symbol *sym;
- struct property *prop;
- struct menu *child;
-
- if (!menu_is_visible(menu))
- return;
-
- sym = menu->sym;
- prop = menu->prompt;
- if (prop) {
- const char *prompt;
-
- switch (prop->type) {
- case P_MENU:
- /*
- * Except in oldaskconfig mode, we show only menus that
- * contain new symbols.
- */
- if (input_mode != oldaskconfig && rootEntry != menu) {
- check_conf(menu);
- return;
- }
- /* fall through */
- case P_COMMENT:
- prompt = menu_get_prompt(menu);
- if (prompt)
- printf("%*c\n%*c %s\n%*c\n",
- indent, '*',
- indent, '*', prompt,
- indent, '*');
- default:
- ;
- }
- }
-
- if (!sym)
- goto conf_childs;
-
- if (sym_is_choice(sym)) {
- conf_choice(menu);
- if (sym->curr.tri != mod)
- return;
- goto conf_childs;
- }
-
- switch (sym->type) {
- case S_INT:
- case S_HEX:
- case S_STRING:
- conf_string(menu);
- break;
- default:
- conf_sym(menu);
- break;
- }
-
-conf_childs:
- if (sym)
- indent += 2;
- for (child = menu->list; child; child = child->next)
- conf(child);
- if (sym)
- indent -= 2;
-}
-
-static void check_conf(struct menu *menu)
-{
- struct symbol *sym;
- struct menu *child;
-
- if (!menu_is_visible(menu))
- return;
-
- sym = menu->sym;
- if (sym && !sym_has_value(sym) &&
- (sym_is_changeable(sym) ||
- (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes))) {
-
- switch (input_mode) {
- case listnewconfig:
- if (sym->name)
- print_symbol_for_listconfig(sym);
- break;
- case helpnewconfig:
- printf("-----\n");
- print_help(menu);
- printf("-----\n");
- break;
- default:
- if (!conf_cnt++)
- printf("*\n* Restart config...\n*\n");
- rootEntry = menu_get_parent_menu(menu);
- conf(rootEntry);
- break;
- }
- }
-
- for (child = menu->list; child; child = child->next)
- check_conf(child);
-}
-
-static const struct option long_opts[] = {
- {"help", no_argument, NULL, 'h'},
- {"silent", no_argument, NULL, 's'},
- {"oldaskconfig", no_argument, &input_mode_opt, oldaskconfig},
- {"oldconfig", no_argument, &input_mode_opt, oldconfig},
- {"syncconfig", no_argument, &input_mode_opt, syncconfig},
- {"defconfig", required_argument, &input_mode_opt, defconfig},
- {"savedefconfig", required_argument, &input_mode_opt, savedefconfig},
- {"allnoconfig", no_argument, &input_mode_opt, allnoconfig},
- {"allyesconfig", no_argument, &input_mode_opt, allyesconfig},
- {"allmodconfig", no_argument, &input_mode_opt, allmodconfig},
- {"alldefconfig", no_argument, &input_mode_opt, alldefconfig},
- {"randconfig", no_argument, &input_mode_opt, randconfig},
- {"listnewconfig", no_argument, &input_mode_opt, listnewconfig},
- {"helpnewconfig", no_argument, &input_mode_opt, helpnewconfig},
- {"olddefconfig", no_argument, &input_mode_opt, olddefconfig},
- {"yes2modconfig", no_argument, &input_mode_opt, yes2modconfig},
- {"mod2yesconfig", no_argument, &input_mode_opt, mod2yesconfig},
- {"mod2noconfig", no_argument, &input_mode_opt, mod2noconfig},
- {NULL, 0, NULL, 0}
-};
-
-static void conf_usage(const char *progname)
-{
- printf("Usage: %s [options] <kconfig-file>\n", progname);
- printf("\n");
- printf("Generic options:\n");
- printf(" -h, --help Print this message and exit.\n");
- printf(" -s, --silent Do not print log.\n");
- printf("\n");
- printf("Mode options:\n");
- printf(" --listnewconfig List new options\n");
- printf(" --helpnewconfig List new options and help text\n");
- printf(" --oldaskconfig Start a new configuration using a line-oriented program\n");
- printf(" --oldconfig Update a configuration using a provided .config as base\n");
- printf(" --syncconfig Similar to oldconfig but generates configuration in\n"
- " include/{generated/,config/}\n");
- printf(" --olddefconfig Same as oldconfig but sets new symbols to their default value\n");
- printf(" --defconfig <file> New config with default defined in <file>\n");
- printf(" --savedefconfig <file> Save the minimal current configuration to <file>\n");
- printf(" --allnoconfig New config where all options are answered with no\n");
- printf(" --allyesconfig New config where all options are answered with yes\n");
- printf(" --allmodconfig New config where all options are answered with mod\n");
- printf(" --alldefconfig New config with all symbols set to default\n");
- printf(" --randconfig New config with random answer to all options\n");
- printf(" --yes2modconfig Change answers from yes to mod if possible\n");
- printf(" --mod2yesconfig Change answers from mod to yes if possible\n");
- printf(" --mod2noconfig Change answers from mod to no if possible\n");
- printf(" (If none of the above is given, --oldaskconfig is the default)\n");
-}
-
-int main(int ac, char **av)
-{
- const char *progname = av[0];
- int opt;
- const char *name, *defconfig_file = NULL /* gcc uninit */;
- int no_conf_write = 0;
-
- tty_stdio = isatty(0) && isatty(1);
-
- while ((opt = getopt_long(ac, av, "hs", long_opts, NULL)) != -1) {
- switch (opt) {
- case 'h':
- conf_usage(progname);
- exit(1);
- break;
- case 's':
- conf_set_message_callback(NULL);
- break;
- case 0:
- input_mode = input_mode_opt;
- switch (input_mode) {
- case syncconfig:
- /*
- * syncconfig is invoked during the build stage.
- * Suppress distracting
- * "configuration written to ..."
- */
- conf_set_message_callback(NULL);
- sync_kconfig = 1;
- break;
- case defconfig:
- case savedefconfig:
- defconfig_file = optarg;
- break;
- case randconfig:
- set_randconfig_seed();
- break;
- default:
- break;
- }
- default:
- break;
- }
- }
- if (ac == optind) {
- fprintf(stderr, "%s: Kconfig file missing\n", av[0]);
- conf_usage(progname);
- exit(1);
- }
- conf_parse(av[optind]);
- //zconfdump(stdout);
-
- switch (input_mode) {
- case defconfig:
- if (conf_read(defconfig_file)) {
- fprintf(stderr,
- "***\n"
- "*** Can't find default configuration \"%s\"!\n"
- "***\n",
- defconfig_file);
- exit(1);
- }
- break;
- case savedefconfig:
- case syncconfig:
- case oldaskconfig:
- case oldconfig:
- case listnewconfig:
- case helpnewconfig:
- case olddefconfig:
- case yes2modconfig:
- case mod2yesconfig:
- case mod2noconfig:
- conf_read(NULL);
- break;
- case allnoconfig:
- case allyesconfig:
- case allmodconfig:
- case alldefconfig:
- case randconfig:
- name = getenv("KCONFIG_ALLCONFIG");
- if (!name)
- break;
- if ((strcmp(name, "") != 0) && (strcmp(name, "1") != 0)) {
- if (conf_read_simple(name, S_DEF_USER)) {
- fprintf(stderr,
- "*** Can't read seed configuration \"%s\"!\n",
- name);
- exit(1);
- }
- break;
- }
- switch (input_mode) {
- case allnoconfig: name = "allno.config"; break;
- case allyesconfig: name = "allyes.config"; break;
- case allmodconfig: name = "allmod.config"; break;
- case alldefconfig: name = "alldef.config"; break;
- case randconfig: name = "allrandom.config"; break;
- default: break;
- }
- if (conf_read_simple(name, S_DEF_USER) &&
- conf_read_simple("all.config", S_DEF_USER)) {
- fprintf(stderr,
- "*** KCONFIG_ALLCONFIG set, but no \"%s\" or \"all.config\" file found\n",
- name);
- exit(1);
- }
- break;
- default:
- break;
- }
-
- if (sync_kconfig) {
- name = getenv("KCONFIG_NOSILENTUPDATE");
- if (name && *name) {
- if (conf_get_changed()) {
- fprintf(stderr,
- "\n*** The configuration requires explicit update.\n\n");
- return 1;
- }
- no_conf_write = 1;
- }
- }
-
- switch (input_mode) {
- case allnoconfig:
- conf_set_all_new_symbols(def_no);
- break;
- case allyesconfig:
- conf_set_all_new_symbols(def_yes);
- break;
- case allmodconfig:
- conf_set_all_new_symbols(def_mod);
- break;
- case alldefconfig:
- conf_set_all_new_symbols(def_default);
- break;
- case randconfig:
- /* Really nothing to do in this loop */
- while (conf_set_all_new_symbols(def_random)) ;
- break;
- case defconfig:
- conf_set_all_new_symbols(def_default);
- break;
- case savedefconfig:
- break;
- case yes2modconfig:
- conf_rewrite_tristates(yes, mod);
- break;
- case mod2yesconfig:
- conf_rewrite_tristates(mod, yes);
- break;
- case mod2noconfig:
- conf_rewrite_tristates(mod, no);
- break;
- case oldaskconfig:
- rootEntry = &rootmenu;
- conf(&rootmenu);
- input_mode = oldconfig;
- /* fall through */
- case oldconfig:
- case listnewconfig:
- case helpnewconfig:
- case syncconfig:
- /* Update until a loop caused no more changes */
- do {
- conf_cnt = 0;
- check_conf(&rootmenu);
- } while (conf_cnt);
- break;
- case olddefconfig:
- default:
- break;
- }
-
- if (input_mode == savedefconfig) {
- if (conf_write_defconfig(defconfig_file)) {
- fprintf(stderr, "n*** Error while saving defconfig to: %s\n\n",
- defconfig_file);
- return 1;
- }
- } else if (input_mode != listnewconfig && input_mode != helpnewconfig) {
- if (!no_conf_write && conf_write(NULL)) {
- fprintf(stderr, "\n*** Error during writing of the configuration.\n\n");
- exit(1);
- }
-
- /*
- * Create auto.conf if it does not exist.
- * This prevents GNU Make 4.1 or older from emitting
- * "include/config/auto.conf: No such file or directory"
- * in the top-level Makefile
- *
- * syncconfig always creates or updates auto.conf because it is
- * used during the build.
- */
- if (conf_write_autoconf(sync_kconfig) && sync_kconfig) {
- fprintf(stderr,
- "\n*** Error during sync of the configuration.\n\n");
- return 1;
- }
- }
- return 0;
-}
Index: v6.x/create-6.0.7-host-limits-patch/linux-6.0.7-new/scripts/kconfig
===================================================================
--- v6.x/create-6.0.7-host-limits-patch/linux-6.0.7-new/scripts/kconfig (revision 384)
+++ v6.x/create-6.0.7-host-limits-patch/linux-6.0.7-new/scripts/kconfig (nonexistent)
Property changes on: v6.x/create-6.0.7-host-limits-patch/linux-6.0.7-new/scripts/kconfig
___________________________________________________________________
Deleted: svn:ignore
## -1,73 +0,0 ##
-
-# install dir
-dist
-
-# Target build dirs
-.a1x-newlib
-.a2x-newlib
-.at91sam7s-newlib
-
-.build-machine
-
-.a1x-glibc
-.a2x-glibc
-.h3-glibc
-.h5-glibc
-.i586-glibc
-.i686-glibc
-.imx6-glibc
-.jz47xx-glibc
-.makefile
-.am335x-glibc
-.omap543x-glibc
-.p5600-glibc
-.power8-glibc
-.power8le-glibc
-.power9-glibc
-.power9le-glibc
-.m1000-glibc
-.riscv64-glibc
-.rk328x-glibc
-.rk33xx-glibc
-.rk339x-glibc
-.s8xx-glibc
-.s9xx-glibc
-.x86_64-glibc
-
-# Hidden files (each file)
-.makefile
-.dist
-.rootfs
-
-# src & hw requires
-.src_requires
-.src_requires_depend
-.requires
-.requires_depend
-
-# Tarballs
-*.gz
-*.bz2
-*.lz
-*.xz
-*.tgz
-*.txz
-
-# Signatures
-*.asc
-*.sig
-*.sign
-*.sha1sum
-
-# Patches
-*.patch
-
-# Descriptions
-*.dsc
-*.txt
-
-# Default linux config files
-*.defconfig
-
-# backup copies
-*~
Index: v6.x/create-6.0.7-host-limits-patch/linux-6.0.7-new/scripts
===================================================================
--- v6.x/create-6.0.7-host-limits-patch/linux-6.0.7-new/scripts (revision 384)
+++ v6.x/create-6.0.7-host-limits-patch/linux-6.0.7-new/scripts (nonexistent)
Property changes on: v6.x/create-6.0.7-host-limits-patch/linux-6.0.7-new/scripts
___________________________________________________________________
Deleted: svn:ignore
## -1,73 +0,0 ##
-
-# install dir
-dist
-
-# Target build dirs
-.a1x-newlib
-.a2x-newlib
-.at91sam7s-newlib
-
-.build-machine
-
-.a1x-glibc
-.a2x-glibc
-.h3-glibc
-.h5-glibc
-.i586-glibc
-.i686-glibc
-.imx6-glibc
-.jz47xx-glibc
-.makefile
-.am335x-glibc
-.omap543x-glibc
-.p5600-glibc
-.power8-glibc
-.power8le-glibc
-.power9-glibc
-.power9le-glibc
-.m1000-glibc
-.riscv64-glibc
-.rk328x-glibc
-.rk33xx-glibc
-.rk339x-glibc
-.s8xx-glibc
-.s9xx-glibc
-.x86_64-glibc
-
-# Hidden files (each file)
-.makefile
-.dist
-.rootfs
-
-# src & hw requires
-.src_requires
-.src_requires_depend
-.requires
-.requires_depend
-
-# Tarballs
-*.gz
-*.bz2
-*.lz
-*.xz
-*.tgz
-*.txz
-
-# Signatures
-*.asc
-*.sig
-*.sign
-*.sha1sum
-
-# Patches
-*.patch
-
-# Descriptions
-*.dsc
-*.txt
-
-# Default linux config files
-*.defconfig
-
-# backup copies
-*~
Index: v6.x/create-6.0.7-host-limits-patch/linux-6.0.7-new/usr/gen_init_cpio.c
===================================================================
--- v6.x/create-6.0.7-host-limits-patch/linux-6.0.7-new/usr/gen_init_cpio.c (revision 384)
+++ v6.x/create-6.0.7-host-limits-patch/linux-6.0.7-new/usr/gen_init_cpio.c (nonexistent)
@@ -1,682 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <stdbool.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <string.h>
-#include <unistd.h>
-#include <time.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <ctype.h>
-#include <linux/limits.h>
-
-/*
- * Original work by Jeff Garzik
- *
- * External file lists, symlink, pipe and fifo support by Thayne Harbaugh
- * Hard link support by Luciano Rocha
- */
-
-#define xstr(s) #s
-#define str(s) xstr(s)
-#define MIN(a, b) ((a) < (b) ? (a) : (b))
-
-static unsigned int offset;
-static unsigned int ino = 721;
-static time_t default_mtime;
-static bool do_csum = false;
-
-struct file_handler {
- const char *type;
- int (*handler)(const char *line);
-};
-
-static void push_string(const char *name)
-{
- unsigned int name_len = strlen(name) + 1;
-
- fputs(name, stdout);
- putchar(0);
- offset += name_len;
-}
-
-static void push_pad (void)
-{
- while (offset & 3) {
- putchar(0);
- offset++;
- }
-}
-
-static void push_rest(const char *name)
-{
- unsigned int name_len = strlen(name) + 1;
- unsigned int tmp_ofs;
-
- fputs(name, stdout);
- putchar(0);
- offset += name_len;
-
- tmp_ofs = name_len + 110;
- while (tmp_ofs & 3) {
- putchar(0);
- offset++;
- tmp_ofs++;
- }
-}
-
-static void push_hdr(const char *s)
-{
- fputs(s, stdout);
- offset += 110;
-}
-
-static void cpio_trailer(void)
-{
- char s[256];
- const char name[] = "TRAILER!!!";
-
- sprintf(s, "%s%08X%08X%08lX%08lX%08X%08lX"
- "%08X%08X%08X%08X%08X%08X%08X",
- do_csum ? "070702" : "070701", /* magic */
- 0, /* ino */
- 0, /* mode */
- (long) 0, /* uid */
- (long) 0, /* gid */
- 1, /* nlink */
- (long) 0, /* mtime */
- 0, /* filesize */
- 0, /* major */
- 0, /* minor */
- 0, /* rmajor */
- 0, /* rminor */
- (unsigned)strlen(name)+1, /* namesize */
- 0); /* chksum */
- push_hdr(s);
- push_rest(name);
-
- while (offset % 512) {
- putchar(0);
- offset++;
- }
-}
-
-static int cpio_mkslink(const char *name, const char *target,
- unsigned int mode, uid_t uid, gid_t gid)
-{
- char s[256];
-
- if (name[0] == '/')
- name++;
- sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
- "%08X%08X%08X%08X%08X%08X%08X",
- do_csum ? "070702" : "070701", /* magic */
- ino++, /* ino */
- S_IFLNK | mode, /* mode */
- (long) uid, /* uid */
- (long) gid, /* gid */
- 1, /* nlink */
- (long) default_mtime, /* mtime */
- (unsigned)strlen(target)+1, /* filesize */
- 3, /* major */
- 1, /* minor */
- 0, /* rmajor */
- 0, /* rminor */
- (unsigned)strlen(name) + 1,/* namesize */
- 0); /* chksum */
- push_hdr(s);
- push_string(name);
- push_pad();
- push_string(target);
- push_pad();
- return 0;
-}
-
-static int cpio_mkslink_line(const char *line)
-{
- char name[PATH_MAX + 1];
- char target[PATH_MAX + 1];
- unsigned int mode;
- int uid;
- int gid;
- int rc = -1;
-
- if (5 != sscanf(line, "%" str(PATH_MAX) "s %" str(PATH_MAX) "s %o %d %d", name, target, &mode, &uid, &gid)) {
- fprintf(stderr, "Unrecognized dir format '%s'", line);
- goto fail;
- }
- rc = cpio_mkslink(name, target, mode, uid, gid);
- fail:
- return rc;
-}
-
-static int cpio_mkgeneric(const char *name, unsigned int mode,
- uid_t uid, gid_t gid)
-{
- char s[256];
-
- if (name[0] == '/')
- name++;
- sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
- "%08X%08X%08X%08X%08X%08X%08X",
- do_csum ? "070702" : "070701", /* magic */
- ino++, /* ino */
- mode, /* mode */
- (long) uid, /* uid */
- (long) gid, /* gid */
- 2, /* nlink */
- (long) default_mtime, /* mtime */
- 0, /* filesize */
- 3, /* major */
- 1, /* minor */
- 0, /* rmajor */
- 0, /* rminor */
- (unsigned)strlen(name) + 1,/* namesize */
- 0); /* chksum */
- push_hdr(s);
- push_rest(name);
- return 0;
-}
-
-enum generic_types {
- GT_DIR,
- GT_PIPE,
- GT_SOCK
-};
-
-struct generic_type {
- const char *type;
- mode_t mode;
-};
-
-static const struct generic_type generic_type_table[] = {
- [GT_DIR] = {
- .type = "dir",
- .mode = S_IFDIR
- },
- [GT_PIPE] = {
- .type = "pipe",
- .mode = S_IFIFO
- },
- [GT_SOCK] = {
- .type = "sock",
- .mode = S_IFSOCK
- }
-};
-
-static int cpio_mkgeneric_line(const char *line, enum generic_types gt)
-{
- char name[PATH_MAX + 1];
- unsigned int mode;
- int uid;
- int gid;
- int rc = -1;
-
- if (4 != sscanf(line, "%" str(PATH_MAX) "s %o %d %d", name, &mode, &uid, &gid)) {
- fprintf(stderr, "Unrecognized %s format '%s'",
- line, generic_type_table[gt].type);
- goto fail;
- }
- mode |= generic_type_table[gt].mode;
- rc = cpio_mkgeneric(name, mode, uid, gid);
- fail:
- return rc;
-}
-
-static int cpio_mkdir_line(const char *line)
-{
- return cpio_mkgeneric_line(line, GT_DIR);
-}
-
-static int cpio_mkpipe_line(const char *line)
-{
- return cpio_mkgeneric_line(line, GT_PIPE);
-}
-
-static int cpio_mksock_line(const char *line)
-{
- return cpio_mkgeneric_line(line, GT_SOCK);
-}
-
-static int cpio_mknod(const char *name, unsigned int mode,
- uid_t uid, gid_t gid, char dev_type,
- unsigned int maj, unsigned int min)
-{
- char s[256];
-
- if (dev_type == 'b')
- mode |= S_IFBLK;
- else
- mode |= S_IFCHR;
-
- if (name[0] == '/')
- name++;
- sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
- "%08X%08X%08X%08X%08X%08X%08X",
- do_csum ? "070702" : "070701", /* magic */
- ino++, /* ino */
- mode, /* mode */
- (long) uid, /* uid */
- (long) gid, /* gid */
- 1, /* nlink */
- (long) default_mtime, /* mtime */
- 0, /* filesize */
- 3, /* major */
- 1, /* minor */
- maj, /* rmajor */
- min, /* rminor */
- (unsigned)strlen(name) + 1,/* namesize */
- 0); /* chksum */
- push_hdr(s);
- push_rest(name);
- return 0;
-}
-
-static int cpio_mknod_line(const char *line)
-{
- char name[PATH_MAX + 1];
- unsigned int mode;
- int uid;
- int gid;
- char dev_type;
- unsigned int maj;
- unsigned int min;
- int rc = -1;
-
- if (7 != sscanf(line, "%" str(PATH_MAX) "s %o %d %d %c %u %u",
- name, &mode, &uid, &gid, &dev_type, &maj, &min)) {
- fprintf(stderr, "Unrecognized nod format '%s'", line);
- goto fail;
- }
- rc = cpio_mknod(name, mode, uid, gid, dev_type, maj, min);
- fail:
- return rc;
-}
-
-static int cpio_mkfile_csum(int fd, unsigned long size, uint32_t *csum)
-{
- while (size) {
- unsigned char filebuf[65536];
- ssize_t this_read;
- size_t i, this_size = MIN(size, sizeof(filebuf));
-
- this_read = read(fd, filebuf, this_size);
- if (this_read <= 0 || this_read > this_size)
- return -1;
-
- for (i = 0; i < this_read; i++)
- *csum += filebuf[i];
-
- size -= this_read;
- }
- /* seek back to the start for data segment I/O */
- if (lseek(fd, 0, SEEK_SET) < 0)
- return -1;
-
- return 0;
-}
-
-static int cpio_mkfile(const char *name, const char *location,
- unsigned int mode, uid_t uid, gid_t gid,
- unsigned int nlinks)
-{
- char s[256];
- struct stat buf;
- unsigned long size;
- int file = -1;
- int retval;
- int rc = -1;
- int namesize;
- unsigned int i;
- uint32_t csum = 0;
-
- mode |= S_IFREG;
-
- file = open (location, O_RDONLY);
- if (file < 0) {
- fprintf (stderr, "File %s could not be opened for reading\n", location);
- goto error;
- }
-
- retval = fstat(file, &buf);
- if (retval) {
- fprintf(stderr, "File %s could not be stat()'ed\n", location);
- goto error;
- }
-
- if (buf.st_mtime > 0xffffffff) {
- fprintf(stderr, "%s: Timestamp exceeds maximum cpio timestamp, clipping.\n",
- location);
- buf.st_mtime = 0xffffffff;
- }
-
- if (buf.st_size > 0xffffffff) {
- fprintf(stderr, "%s: Size exceeds maximum cpio file size\n",
- location);
- goto error;
- }
-
- if (do_csum && cpio_mkfile_csum(file, buf.st_size, &csum) < 0) {
- fprintf(stderr, "Failed to checksum file %s\n", location);
- goto error;
- }
-
- size = 0;
- for (i = 1; i <= nlinks; i++) {
- /* data goes on last link */
- if (i == nlinks)
- size = buf.st_size;
-
- if (name[0] == '/')
- name++;
- namesize = strlen(name) + 1;
- sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
- "%08lX%08X%08X%08X%08X%08X%08X",
- do_csum ? "070702" : "070701", /* magic */
- ino, /* ino */
- mode, /* mode */
- (long) uid, /* uid */
- (long) gid, /* gid */
- nlinks, /* nlink */
- (long) buf.st_mtime, /* mtime */
- size, /* filesize */
- 3, /* major */
- 1, /* minor */
- 0, /* rmajor */
- 0, /* rminor */
- namesize, /* namesize */
- size ? csum : 0); /* chksum */
- push_hdr(s);
- push_string(name);
- push_pad();
-
- while (size) {
- unsigned char filebuf[65536];
- ssize_t this_read;
- size_t this_size = MIN(size, sizeof(filebuf));
-
- this_read = read(file, filebuf, this_size);
- if (this_read <= 0 || this_read > this_size) {
- fprintf(stderr, "Can not read %s file\n", location);
- goto error;
- }
-
- if (fwrite(filebuf, this_read, 1, stdout) != 1) {
- fprintf(stderr, "writing filebuf failed\n");
- goto error;
- }
- offset += this_read;
- size -= this_read;
- }
- push_pad();
-
- name += namesize;
- }
- ino++;
- rc = 0;
-
-error:
- if (file >= 0)
- close(file);
- return rc;
-}
-
-static char *cpio_replace_env(char *new_location)
-{
- char expanded[PATH_MAX + 1];
- char *start, *end, *var;
-
- while ((start = strstr(new_location, "${")) &&
- (end = strchr(start + 2, '}'))) {
- *start = *end = 0;
- var = getenv(start + 2);
- snprintf(expanded, sizeof expanded, "%s%s%s",
- new_location, var ? var : "", end + 1);
- strcpy(new_location, expanded);
- }
-
- return new_location;
-}
-
-static int cpio_mkfile_line(const char *line)
-{
- char name[PATH_MAX + 1];
- char *dname = NULL; /* malloc'ed buffer for hard links */
- char location[PATH_MAX + 1];
- unsigned int mode;
- int uid;
- int gid;
- int nlinks = 1;
- int end = 0, dname_len = 0;
- int rc = -1;
-
- if (5 > sscanf(line, "%" str(PATH_MAX) "s %" str(PATH_MAX)
- "s %o %d %d %n",
- name, location, &mode, &uid, &gid, &end)) {
- fprintf(stderr, "Unrecognized file format '%s'", line);
- goto fail;
- }
- if (end && isgraph(line[end])) {
- int len;
- int nend;
-
- dname = malloc(strlen(line));
- if (!dname) {
- fprintf (stderr, "out of memory (%d)\n", dname_len);
- goto fail;
- }
-
- dname_len = strlen(name) + 1;
- memcpy(dname, name, dname_len);
-
- do {
- nend = 0;
- if (sscanf(line + end, "%" str(PATH_MAX) "s %n",
- name, &nend) < 1)
- break;
- len = strlen(name) + 1;
- memcpy(dname + dname_len, name, len);
- dname_len += len;
- nlinks++;
- end += nend;
- } while (isgraph(line[end]));
- } else {
- dname = name;
- }
- rc = cpio_mkfile(dname, cpio_replace_env(location),
- mode, uid, gid, nlinks);
- fail:
- if (dname_len) free(dname);
- return rc;
-}
-
-static void usage(const char *prog)
-{
- fprintf(stderr, "Usage:\n"
- "\t%s [-t <timestamp>] [-c] <cpio_list>\n"
- "\n"
- "<cpio_list> is a file containing newline separated entries that\n"
- "describe the files to be included in the initramfs archive:\n"
- "\n"
- "# a comment\n"
- "file <name> <location> <mode> <uid> <gid> [<hard links>]\n"
- "dir <name> <mode> <uid> <gid>\n"
- "nod <name> <mode> <uid> <gid> <dev_type> <maj> <min>\n"
- "slink <name> <target> <mode> <uid> <gid>\n"
- "pipe <name> <mode> <uid> <gid>\n"
- "sock <name> <mode> <uid> <gid>\n"
- "\n"
- "<name> name of the file/dir/nod/etc in the archive\n"
- "<location> location of the file in the current filesystem\n"
- " expands shell variables quoted with ${}\n"
- "<target> link target\n"
- "<mode> mode/permissions of the file\n"
- "<uid> user id (0=root)\n"
- "<gid> group id (0=root)\n"
- "<dev_type> device type (b=block, c=character)\n"
- "<maj> major number of nod\n"
- "<min> minor number of nod\n"
- "<hard links> space separated list of other links to file\n"
- "\n"
- "example:\n"
- "# A simple initramfs\n"
- "dir /dev 0755 0 0\n"
- "nod /dev/console 0600 0 0 c 5 1\n"
- "dir /root 0700 0 0\n"
- "dir /sbin 0755 0 0\n"
- "file /sbin/kinit /usr/src/klibc/kinit/kinit 0755 0 0\n"
- "\n"
- "<timestamp> is time in seconds since Epoch that will be used\n"
- "as mtime for symlinks, special files and directories. The default\n"
- "is to use the current time for these entries.\n"
- "-c: calculate and store 32-bit checksums for file data.\n",
- prog);
-}
-
-static const struct file_handler file_handler_table[] = {
- {
- .type = "file",
- .handler = cpio_mkfile_line,
- }, {
- .type = "nod",
- .handler = cpio_mknod_line,
- }, {
- .type = "dir",
- .handler = cpio_mkdir_line,
- }, {
- .type = "slink",
- .handler = cpio_mkslink_line,
- }, {
- .type = "pipe",
- .handler = cpio_mkpipe_line,
- }, {
- .type = "sock",
- .handler = cpio_mksock_line,
- }, {
- .type = NULL,
- .handler = NULL,
- }
-};
-
-#define LINE_SIZE (2 * PATH_MAX + 50)
-
-int main (int argc, char *argv[])
-{
- FILE *cpio_list;
- char line[LINE_SIZE];
- char *args, *type;
- int ec = 0;
- int line_nr = 0;
- const char *filename;
-
- default_mtime = time(NULL);
- while (1) {
- int opt = getopt(argc, argv, "t:ch");
- char *invalid;
-
- if (opt == -1)
- break;
- switch (opt) {
- case 't':
- default_mtime = strtol(optarg, &invalid, 10);
- if (!*optarg || *invalid) {
- fprintf(stderr, "Invalid timestamp: %s\n",
- optarg);
- usage(argv[0]);
- exit(1);
- }
- break;
- case 'c':
- do_csum = true;
- break;
- case 'h':
- case '?':
- usage(argv[0]);
- exit(opt == 'h' ? 0 : 1);
- }
- }
-
- /*
- * Timestamps after 2106-02-07 06:28:15 UTC have an ascii hex time_t
- * representation that exceeds 8 chars and breaks the cpio header
- * specification.
- */
- if (default_mtime > 0xffffffff) {
- fprintf(stderr, "ERROR: Timestamp too large for cpio format\n");
- exit(1);
- }
-
- if (argc - optind != 1) {
- usage(argv[0]);
- exit(1);
- }
- filename = argv[optind];
- if (!strcmp(filename, "-"))
- cpio_list = stdin;
- else if (!(cpio_list = fopen(filename, "r"))) {
- fprintf(stderr, "ERROR: unable to open '%s': %s\n\n",
- filename, strerror(errno));
- usage(argv[0]);
- exit(1);
- }
-
- while (fgets(line, LINE_SIZE, cpio_list)) {
- int type_idx;
- size_t slen = strlen(line);
-
- line_nr++;
-
- if ('#' == *line) {
- /* comment - skip to next line */
- continue;
- }
-
- if (! (type = strtok(line, " \t"))) {
- fprintf(stderr,
- "ERROR: incorrect format, could not locate file type line %d: '%s'\n",
- line_nr, line);
- ec = -1;
- break;
- }
-
- if ('\n' == *type) {
- /* a blank line */
- continue;
- }
-
- if (slen == strlen(type)) {
- /* must be an empty line */
- continue;
- }
-
- if (! (args = strtok(NULL, "\n"))) {
- fprintf(stderr,
- "ERROR: incorrect format, newline required line %d: '%s'\n",
- line_nr, line);
- ec = -1;
- }
-
- for (type_idx = 0; file_handler_table[type_idx].type; type_idx++) {
- int rc;
- if (! strcmp(line, file_handler_table[type_idx].type)) {
- if ((rc = file_handler_table[type_idx].handler(args))) {
- ec = rc;
- fprintf(stderr, " line %d\n", line_nr);
- }
- break;
- }
- }
-
- if (NULL == file_handler_table[type_idx].type) {
- fprintf(stderr, "unknown file type line %d: '%s'\n",
- line_nr, line);
- }
- }
- if (ec == 0)
- cpio_trailer();
-
- exit(ec);
-}
Index: v6.x/create-6.0.7-host-limits-patch/linux-6.0.7-new/usr
===================================================================
--- v6.x/create-6.0.7-host-limits-patch/linux-6.0.7-new/usr (revision 384)
+++ v6.x/create-6.0.7-host-limits-patch/linux-6.0.7-new/usr (nonexistent)
Property changes on: v6.x/create-6.0.7-host-limits-patch/linux-6.0.7-new/usr
___________________________________________________________________
Deleted: svn:ignore
## -1,73 +0,0 ##
-
-# install dir
-dist
-
-# Target build dirs
-.a1x-newlib
-.a2x-newlib
-.at91sam7s-newlib
-
-.build-machine
-
-.a1x-glibc
-.a2x-glibc
-.h3-glibc
-.h5-glibc
-.i586-glibc
-.i686-glibc
-.imx6-glibc
-.jz47xx-glibc
-.makefile
-.am335x-glibc
-.omap543x-glibc
-.p5600-glibc
-.power8-glibc
-.power8le-glibc
-.power9-glibc
-.power9le-glibc
-.m1000-glibc
-.riscv64-glibc
-.rk328x-glibc
-.rk33xx-glibc
-.rk339x-glibc
-.s8xx-glibc
-.s9xx-glibc
-.x86_64-glibc
-
-# Hidden files (each file)
-.makefile
-.dist
-.rootfs
-
-# src & hw requires
-.src_requires
-.src_requires_depend
-.requires
-.requires_depend
-
-# Tarballs
-*.gz
-*.bz2
-*.lz
-*.xz
-*.tgz
-*.txz
-
-# Signatures
-*.asc
-*.sig
-*.sign
-*.sha1sum
-
-# Patches
-*.patch
-
-# Descriptions
-*.dsc
-*.txt
-
-# Default linux config files
-*.defconfig
-
-# backup copies
-*~
Index: v6.x/create-6.0.7-host-limits-patch/linux-6.0.7-new/tools/build/fixdep.c
===================================================================
--- v6.x/create-6.0.7-host-limits-patch/linux-6.0.7-new/tools/build/fixdep.c (revision 384)
+++ v6.x/create-6.0.7-host-limits-patch/linux-6.0.7-new/tools/build/fixdep.c (nonexistent)
@@ -1,170 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * "Optimize" a list of dependencies as spit out by gcc -MD
- * for the build framework.
- *
- * Original author:
- * Copyright 2002 by Kai Germaschewski <kai.germaschewski@gmx.de>
- *
- * This code has been borrowed from kbuild's fixdep (scripts/basic/fixdep.c),
- * Please check it for detailed explanation. This fixdep borow only the
- * base transformation of dependecies without the CONFIG mangle.
- */
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/mman.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <string.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <linux/limits.h>
-
-char *target;
-char *depfile;
-char *cmdline;
-
-static void usage(void)
-{
- fprintf(stderr, "Usage: fixdep <depfile> <target> <cmdline>\n");
- exit(1);
-}
-
-/*
- * Print out the commandline prefixed with cmd_<target filename> :=
- */
-static void print_cmdline(void)
-{
- printf("cmd_%s := %s\n\n", target, cmdline);
-}
-
-/*
- * Important: The below generated source_foo.o and deps_foo.o variable
- * assignments are parsed not only by make, but also by the rather simple
- * parser in scripts/mod/sumversion.c.
- */
-static void parse_dep_file(void *map, size_t len)
-{
- char *m = map;
- char *end = m + len;
- char *p;
- char s[PATH_MAX];
- int is_target, has_target = 0;
- int saw_any_target = 0;
- int is_first_dep = 0;
-
- while (m < end) {
- /* Skip any "white space" */
- while (m < end && (*m == ' ' || *m == '\\' || *m == '\n'))
- m++;
- /* Find next "white space" */
- p = m;
- while (p < end && *p != ' ' && *p != '\\' && *p != '\n')
- p++;
- /* Is the token we found a target name? */
- is_target = (*(p-1) == ':');
- /* Don't write any target names into the dependency file */
- if (is_target) {
- /* The /next/ file is the first dependency */
- is_first_dep = 1;
- has_target = 1;
- } else if (has_target) {
- /* Save this token/filename */
- memcpy(s, m, p-m);
- s[p - m] = 0;
-
- /*
- * Do not list the source file as dependency,
- * so that kbuild is not confused if a .c file
- * is rewritten into .S or vice versa. Storing
- * it in source_* is needed for modpost to
- * compute srcversions.
- */
- if (is_first_dep) {
- /*
- * If processing the concatenation of
- * multiple dependency files, only
- * process the first target name, which
- * will be the original source name,
- * and ignore any other target names,
- * which will be intermediate temporary
- * files.
- */
- if (!saw_any_target) {
- saw_any_target = 1;
- printf("source_%s := %s\n\n",
- target, s);
- printf("deps_%s := \\\n",
- target);
- }
- is_first_dep = 0;
- } else
- printf(" %s \\\n", s);
- }
- /*
- * Start searching for next token immediately after the first
- * "whitespace" character that follows this token.
- */
- m = p + 1;
- }
-
- if (!saw_any_target) {
- fprintf(stderr, "fixdep: parse error; no targets found\n");
- exit(1);
- }
-
- printf("\n%s: $(deps_%s)\n\n", target, target);
- printf("$(deps_%s):\n", target);
-}
-
-static void print_deps(void)
-{
- struct stat st;
- int fd;
- void *map;
-
- fd = open(depfile, O_RDONLY);
- if (fd < 0) {
- fprintf(stderr, "fixdep: error opening depfile: ");
- perror(depfile);
- exit(2);
- }
- if (fstat(fd, &st) < 0) {
- fprintf(stderr, "fixdep: error fstat'ing depfile: ");
- perror(depfile);
- exit(2);
- }
- if (st.st_size == 0) {
- fprintf(stderr, "fixdep: %s is empty\n", depfile);
- close(fd);
- return;
- }
- map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
- if ((long) map == -1) {
- perror("fixdep: mmap");
- close(fd);
- return;
- }
-
- parse_dep_file(map, st.st_size);
-
- munmap(map, st.st_size);
-
- close(fd);
-}
-
-int main(int argc, char **argv)
-{
- if (argc != 4)
- usage();
-
- depfile = argv[1];
- target = argv[2];
- cmdline = argv[3];
-
- print_cmdline();
- print_deps();
-
- return 0;
-}
Index: v6.x/create-6.0.7-host-limits-patch/linux-6.0.7-new/tools/build
===================================================================
--- v6.x/create-6.0.7-host-limits-patch/linux-6.0.7-new/tools/build (revision 384)
+++ v6.x/create-6.0.7-host-limits-patch/linux-6.0.7-new/tools/build (nonexistent)
Property changes on: v6.x/create-6.0.7-host-limits-patch/linux-6.0.7-new/tools/build
___________________________________________________________________
Deleted: svn:ignore
## -1,73 +0,0 ##
-
-# install dir
-dist
-
-# Target build dirs
-.a1x-newlib
-.a2x-newlib
-.at91sam7s-newlib
-
-.build-machine
-
-.a1x-glibc
-.a2x-glibc
-.h3-glibc
-.h5-glibc
-.i586-glibc
-.i686-glibc
-.imx6-glibc
-.jz47xx-glibc
-.makefile
-.am335x-glibc
-.omap543x-glibc
-.p5600-glibc
-.power8-glibc
-.power8le-glibc
-.power9-glibc
-.power9le-glibc
-.m1000-glibc
-.riscv64-glibc
-.rk328x-glibc
-.rk33xx-glibc
-.rk339x-glibc
-.s8xx-glibc
-.s9xx-glibc
-.x86_64-glibc
-
-# Hidden files (each file)
-.makefile
-.dist
-.rootfs
-
-# src & hw requires
-.src_requires
-.src_requires_depend
-.requires
-.requires_depend
-
-# Tarballs
-*.gz
-*.bz2
-*.lz
-*.xz
-*.tgz
-*.txz
-
-# Signatures
-*.asc
-*.sig
-*.sign
-*.sha1sum
-
-# Patches
-*.patch
-
-# Descriptions
-*.dsc
-*.txt
-
-# Default linux config files
-*.defconfig
-
-# backup copies
-*~
Index: v6.x/create-6.0.7-host-limits-patch/linux-6.0.7-new/tools
===================================================================
--- v6.x/create-6.0.7-host-limits-patch/linux-6.0.7-new/tools (revision 384)
+++ v6.x/create-6.0.7-host-limits-patch/linux-6.0.7-new/tools (nonexistent)
Property changes on: v6.x/create-6.0.7-host-limits-patch/linux-6.0.7-new/tools
___________________________________________________________________
Deleted: svn:ignore
## -1,73 +0,0 ##
-
-# install dir
-dist
-
-# Target build dirs
-.a1x-newlib
-.a2x-newlib
-.at91sam7s-newlib
-
-.build-machine
-
-.a1x-glibc
-.a2x-glibc
-.h3-glibc
-.h5-glibc
-.i586-glibc
-.i686-glibc
-.imx6-glibc
-.jz47xx-glibc
-.makefile
-.am335x-glibc
-.omap543x-glibc
-.p5600-glibc
-.power8-glibc
-.power8le-glibc
-.power9-glibc
-.power9le-glibc
-.m1000-glibc
-.riscv64-glibc
-.rk328x-glibc
-.rk33xx-glibc
-.rk339x-glibc
-.s8xx-glibc
-.s9xx-glibc
-.x86_64-glibc
-
-# Hidden files (each file)
-.makefile
-.dist
-.rootfs
-
-# src & hw requires
-.src_requires
-.src_requires_depend
-.requires
-.requires_depend
-
-# Tarballs
-*.gz
-*.bz2
-*.lz
-*.xz
-*.tgz
-*.txz
-
-# Signatures
-*.asc
-*.sig
-*.sign
-*.sha1sum
-
-# Patches
-*.patch
-
-# Descriptions
-*.dsc
-*.txt
-
-# Default linux config files
-*.defconfig
-
-# backup copies
-*~
Index: v6.x/create-6.0.7-host-limits-patch/linux-6.0.7-new
===================================================================
--- v6.x/create-6.0.7-host-limits-patch/linux-6.0.7-new (revision 384)
+++ v6.x/create-6.0.7-host-limits-patch/linux-6.0.7-new (nonexistent)
Property changes on: v6.x/create-6.0.7-host-limits-patch/linux-6.0.7-new
___________________________________________________________________
Deleted: svn:ignore
## -1,73 +0,0 ##
-
-# install dir
-dist
-
-# Target build dirs
-.a1x-newlib
-.a2x-newlib
-.at91sam7s-newlib
-
-.build-machine
-
-.a1x-glibc
-.a2x-glibc
-.h3-glibc
-.h5-glibc
-.i586-glibc
-.i686-glibc
-.imx6-glibc
-.jz47xx-glibc
-.makefile
-.am335x-glibc
-.omap543x-glibc
-.p5600-glibc
-.power8-glibc
-.power8le-glibc
-.power9-glibc
-.power9le-glibc
-.m1000-glibc
-.riscv64-glibc
-.rk328x-glibc
-.rk33xx-glibc
-.rk339x-glibc
-.s8xx-glibc
-.s9xx-glibc
-.x86_64-glibc
-
-# Hidden files (each file)
-.makefile
-.dist
-.rootfs
-
-# src & hw requires
-.src_requires
-.src_requires_depend
-.requires
-.requires_depend
-
-# Tarballs
-*.gz
-*.bz2
-*.lz
-*.xz
-*.tgz
-*.txz
-
-# Signatures
-*.asc
-*.sig
-*.sign
-*.sha1sum
-
-# Patches
-*.patch
-
-# Descriptions
-*.dsc
-*.txt
-
-# Default linux config files
-*.defconfig
-
-# backup copies
-*~
Index: v6.x/create-6.0.7-host-limits-patch
===================================================================
--- v6.x/create-6.0.7-host-limits-patch (revision 384)
+++ v6.x/create-6.0.7-host-limits-patch (nonexistent)
Property changes on: v6.x/create-6.0.7-host-limits-patch
___________________________________________________________________
Deleted: svn:ignore
## -1,73 +0,0 ##
-
-# install dir
-dist
-
-# Target build dirs
-.a1x-newlib
-.a2x-newlib
-.at91sam7s-newlib
-
-.build-machine
-
-.a1x-glibc
-.a2x-glibc
-.h3-glibc
-.h5-glibc
-.i586-glibc
-.i686-glibc
-.imx6-glibc
-.jz47xx-glibc
-.makefile
-.am335x-glibc
-.omap543x-glibc
-.p5600-glibc
-.power8-glibc
-.power8le-glibc
-.power9-glibc
-.power9le-glibc
-.m1000-glibc
-.riscv64-glibc
-.rk328x-glibc
-.rk33xx-glibc
-.rk339x-glibc
-.s8xx-glibc
-.s9xx-glibc
-.x86_64-glibc
-
-# Hidden files (each file)
-.makefile
-.dist
-.rootfs
-
-# src & hw requires
-.src_requires
-.src_requires_depend
-.requires
-.requires_depend
-
-# Tarballs
-*.gz
-*.bz2
-*.lz
-*.xz
-*.tgz
-*.txz
-
-# Signatures
-*.asc
-*.sig
-*.sign
-*.sha1sum
-
-# Patches
-*.patch
-
-# Descriptions
-*.dsc
-*.txt
-
-# Default linux config files
-*.defconfig
-
-# backup copies
-*~
Index: v6.x/create-6.0.7-leez-p710-spi-patch/file.list
===================================================================
--- v6.x/create-6.0.7-leez-p710-spi-patch/file.list (revision 384)
+++ v6.x/create-6.0.7-leez-p710-spi-patch/file.list (nonexistent)
@@ -1 +0,0 @@
-linux-6.0.7/arch/arm64/boot/dts/rockchip/rk3399-leez-p710.dts
Index: v6.x/create-6.0.7-leez-p710-spi-patch/create.patch.sh
===================================================================
--- v6.x/create-6.0.7-leez-p710-spi-patch/create.patch.sh (revision 384)
+++ v6.x/create-6.0.7-leez-p710-spi-patch/create.patch.sh (nonexistent)
@@ -1,15 +0,0 @@
-#!/bin/sh
-
-VERSION=6.0.7
-
-tar --files-from=file.list -xJvf ../linux-$VERSION.tar.xz
-mv linux-$VERSION linux-$VERSION-orig
-
-cp -rf ./linux-$VERSION-new ./linux-$VERSION
-
-diff --unified -Nr linux-$VERSION-orig linux-$VERSION > linux-$VERSION-leez-p710-spi.patch
-
-mv linux-$VERSION-leez-p710-spi.patch ../patches
-
-rm -rf ./linux-$VERSION
-rm -rf ./linux-$VERSION-orig
Property changes on: v6.x/create-6.0.7-leez-p710-spi-patch/create.patch.sh
___________________________________________________________________
Deleted: svn:executable
## -1 +0,0 ##
-*
\ No newline at end of property
Index: v6.x/create-6.0.7-leez-p710-spi-patch/linux-6.0.7-new/arch/arm64/boot/dts/rockchip/rk3399-leez-p710.dts
===================================================================
--- v6.x/create-6.0.7-leez-p710-spi-patch/linux-6.0.7-new/arch/arm64/boot/dts/rockchip/rk3399-leez-p710.dts (revision 384)
+++ v6.x/create-6.0.7-leez-p710-spi-patch/linux-6.0.7-new/arch/arm64/boot/dts/rockchip/rk3399-leez-p710.dts (nonexistent)
@@ -1,674 +0,0 @@
-// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
-/*
- * Copyright (c) 2019 Andy Yan <andy.yan@gmail.com>
- */
-
-/dts-v1/;
-#include <dt-bindings/input/linux-event-codes.h>
-#include <dt-bindings/interrupt-controller/irq.h>
-#include <dt-bindings/pwm/pwm.h>
-#include "rk3399.dtsi"
-#include "rk3399-opp.dtsi"
-
-/ {
- model = "Leez RK3399 P710";
- compatible = "leez,p710", "rockchip,rk3399";
-
- aliases {
- mmc0 = &sdio0;
- mmc1 = &sdmmc;
- mmc2 = &sdhci;
- };
-
- chosen {
- stdout-path = "serial2:1500000n8";
- };
-
- clkin_gmac: external-gmac-clock {
- compatible = "fixed-clock";
- clock-frequency = <125000000>;
- clock-output-names = "clkin_gmac";
- #clock-cells = <0>;
- };
-
- sdio_pwrseq: sdio-pwrseq {
- compatible = "mmc-pwrseq-simple";
- clocks = <&rk808 1>;
- clock-names = "ext_clock";
- pinctrl-names = "default";
- pinctrl-0 = <&wifi_reg_on_h>;
- reset-gpios = <&gpio0 RK_PB2 GPIO_ACTIVE_LOW>;
- };
-
- dc5v_adp: dc5v-adp {
- compatible = "regulator-fixed";
- regulator-name = "dc5v_adapter";
- regulator-always-on;
- regulator-boot-on;
- regulator-min-microvolt = <5000000>;
- regulator-max-microvolt = <5000000>;
- };
-
- vcc3v3_lan: vcc3v3-lan {
- compatible = "regulator-fixed";
- regulator-name = "vcc3v3_lan";
- regulator-always-on;
- regulator-boot-on;
- regulator-min-microvolt = <3300000>;
- regulator-max-microvolt = <3300000>;
- vin-supply = <&vcc3v3_sys>;
- };
-
- vcc3v3_sys: vcc3v3-sys {
- compatible = "regulator-fixed";
- regulator-name = "vcc3v3_sys";
- regulator-always-on;
- regulator-boot-on;
- regulator-min-microvolt = <3300000>;
- regulator-max-microvolt = <3300000>;
- vin-supply = <&vcc5v0_sys>;
- };
-
- vcc5v0_host0: vcc5v0_host1: vcc5v0-host {
- compatible = "regulator-fixed";
- regulator-name = "vcc5v0_host";
- regulator-boot-on;
- regulator-always-on;
- regulator-min-microvolt = <5500000>;
- regulator-max-microvolt = <5500000>;
- vin-supply = <&vcc5v0_sys>;
- };
-
- vcc5v0_host3: vcc5v0-host3 {
- compatible = "regulator-fixed";
- regulator-name = "vcc5v0_host3";
- enable-active-high;
- gpio = <&gpio2 RK_PA2 GPIO_ACTIVE_HIGH>;
- pinctrl-names = "default";
- pinctrl-0 = <&vcc5v0_host3_en>;
- regulator-always-on;
- vin-supply = <&vcc5v0_sys>;
- };
-
- vcc5v0_sys: vcc5v0-sys {
- compatible = "regulator-fixed";
- regulator-name = "vcc5v0_sys";
- regulator-always-on;
- regulator-boot-on;
- regulator-min-microvolt = <5000000>;
- regulator-max-microvolt = <5000000>;
- vin-supply = <&dc5v_adp>;
- };
-
- vdd_log: vdd-log {
- compatible = "pwm-regulator";
- pwms = <&pwm2 0 25000 1>;
- pwm-supply = <&vcc5v0_sys>;
- regulator-name = "vdd_log";
- regulator-always-on;
- regulator-boot-on;
- regulator-min-microvolt = <800000>;
- regulator-max-microvolt = <1400000>;
- };
-};
-
-&cpu_l0 {
- cpu-supply = <&vdd_cpu_l>;
-};
-
-&cpu_l1 {
- cpu-supply = <&vdd_cpu_l>;
-};
-
-&cpu_l2 {
- cpu-supply = <&vdd_cpu_l>;
-};
-
-&cpu_l3 {
- cpu-supply = <&vdd_cpu_l>;
-};
-
-&cpu_b0 {
- cpu-supply = <&vdd_cpu_b>;
-};
-
-&cpu_b1 {
- cpu-supply = <&vdd_cpu_b>;
-};
-
-&emmc_phy {
- status = "okay";
-};
-
-&gmac {
- assigned-clocks = <&cru SCLK_RMII_SRC>;
- assigned-clock-parents = <&clkin_gmac>;
- clock_in_out = "input";
- phy-supply = <&vcc3v3_lan>;
- phy-mode = "rgmii";
- pinctrl-names = "default";
- pinctrl-0 = <&rgmii_pins>;
- snps,reset-gpio = <&gpio3 RK_PB7 GPIO_ACTIVE_LOW>;
- snps,reset-active-low;
- snps,reset-delays-us = <0 10000 50000>;
- tx_delay = <0x28>;
- rx_delay = <0x11>;
- status = "okay";
-};
-
-&gpu {
- mali-supply = <&vdd_gpu>;
- status = "okay";
-};
-
-&hdmi {
- ddc-i2c-bus = <&i2c7>;
- pinctrl-names = "default";
- pinctrl-0 = <&hdmi_cec>;
- status = "okay";
-};
-
-&hdmi_sound {
- status = "okay";
-};
-
-&i2c0 {
- clock-frequency = <400000>;
- i2c-scl-rising-time-ns = <168>;
- i2c-scl-falling-time-ns = <4>;
- status = "okay";
-
- rk808: pmic@1b {
- compatible = "rockchip,rk808";
- reg = <0x1b>;
- interrupt-parent = <&gpio1>;
- interrupts = <21 IRQ_TYPE_LEVEL_LOW>;
- #clock-cells = <1>;
- clock-output-names = "xin32k", "rk808-clkout2";
- pinctrl-names = "default";
- pinctrl-0 = <&pmic_int_l>;
- rockchip,system-power-controller;
- wakeup-source;
-
- vcc1-supply = <&vcc5v0_sys>;
- vcc2-supply = <&vcc5v0_sys>;
- vcc3-supply = <&vcc5v0_sys>;
- vcc4-supply = <&vcc5v0_sys>;
- vcc6-supply = <&vcc5v0_sys>;
- vcc7-supply = <&vcc5v0_sys>;
- vcc8-supply = <&vcc3v3_sys>;
- vcc9-supply = <&vcc5v0_sys>;
- vcc10-supply = <&vcc5v0_sys>;
- vcc11-supply = <&vcc5v0_sys>;
- vcc12-supply = <&vcc3v3_sys>;
- vddio-supply = <&vcc_1v8>;
-
- regulators {
- vdd_center: DCDC_REG1 {
- regulator-name = "vdd_center";
- regulator-always-on;
- regulator-boot-on;
- regulator-min-microvolt = <750000>;
- regulator-max-microvolt = <1350000>;
- regulator-ramp-delay = <6001>;
- regulator-state-mem {
- regulator-off-in-suspend;
- };
- };
-
- vdd_cpu_l: DCDC_REG2 {
- regulator-name = "vdd_cpu_l";
- regulator-always-on;
- regulator-boot-on;
- regulator-min-microvolt = <750000>;
- regulator-max-microvolt = <1350000>;
- regulator-ramp-delay = <6001>;
- regulator-state-mem {
- regulator-off-in-suspend;
- };
- };
-
- vcc_ddr: DCDC_REG3 {
- regulator-name = "vcc_ddr";
- regulator-always-on;
- regulator-boot-on;
- regulator-state-mem {
- regulator-on-in-suspend;
- };
- };
-
- vcc_1v8: DCDC_REG4 {
- regulator-name = "vcc_1v8";
- regulator-always-on;
- regulator-boot-on;
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- regulator-state-mem {
- regulator-on-in-suspend;
- regulator-suspend-microvolt = <1800000>;
- };
- };
-
- vcc1v8_dvp: LDO_REG1 {
- regulator-name = "vcc1v8_dvp";
- regulator-always-on;
- regulator-boot-on;
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- regulator-state-mem {
- regulator-off-in-suspend;
- };
- };
-
- vcc1v8_hdmi: LDO_REG2 {
- regulator-name = "vcc1v8_hdmi";
- regulator-always-on;
- regulator-boot-on;
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- regulator-state-mem {
- regulator-off-in-suspend;
- };
- };
-
- vcca_1v8: LDO_REG3 {
- regulator-name = "vcca_1v8";
- regulator-always-on;
- regulator-boot-on;
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- regulator-state-mem {
- regulator-on-in-suspend;
- regulator-suspend-microvolt = <1800000>;
- };
- };
-
- vccio_sd: LDO_REG4 {
- regulator-name = "vccio_sd";
- regulator-always-on;
- regulator-boot-on;
- regulator-min-microvolt = <3000000>;
- regulator-max-microvolt = <3000000>;
- regulator-state-mem {
- regulator-on-in-suspend;
- regulator-suspend-microvolt = <3000000>;
- };
- };
-
- vcca3v0_codec: LDO_REG5 {
- regulator-name = "vcca3v0_codec";
- regulator-always-on;
- regulator-boot-on;
- regulator-min-microvolt = <3000000>;
- regulator-max-microvolt = <3000000>;
- regulator-state-mem {
- regulator-off-in-suspend;
- };
- };
-
- vcc_1v5: LDO_REG6 {
- regulator-name = "vcc_1v5";
- regulator-always-on;
- regulator-boot-on;
- regulator-min-microvolt = <1500000>;
- regulator-max-microvolt = <1500000>;
- regulator-state-mem {
- regulator-on-in-suspend;
- regulator-suspend-microvolt = <1500000>;
- };
- };
-
- vcc0v9_hdmi: LDO_REG7 {
- regulator-name = "vcc0v9_hdmi";
- regulator-always-on;
- regulator-boot-on;
- regulator-min-microvolt = <900000>;
- regulator-max-microvolt = <900000>;
- regulator-state-mem {
- regulator-off-in-suspend;
- };
- };
-
- vcc_3v0: LDO_REG8 {
- regulator-name = "vcc_3v0";
- regulator-always-on;
- regulator-boot-on;
- regulator-min-microvolt = <3000000>;
- regulator-max-microvolt = <3000000>;
- regulator-state-mem {
- regulator-on-in-suspend;
- regulator-suspend-microvolt = <3000000>;
- };
- };
- };
- };
-
- vdd_cpu_b: regulator@40 {
- compatible = "silergy,syr827";
- reg = <0x40>;
- fcs,suspend-voltage-selector = <1>;
- pinctrl-names = "default";
- pinctrl-0 = <&vsel1_pin>;
- regulator-name = "vdd_cpu_b";
- regulator-min-microvolt = <712500>;
- regulator-max-microvolt = <1500000>;
- regulator-ramp-delay = <1000>;
- regulator-always-on;
- regulator-boot-on;
- vin-supply = <&vcc5v0_sys>;
-
- regulator-state-mem {
- regulator-off-in-suspend;
- };
- };
-
- vdd_gpu: regulator@41 {
- compatible = "silergy,syr828";
- reg = <0x41>;
- fcs,suspend-voltage-selector = <1>;
- pinctrl-names = "default";
- pinctrl-0 = <&vsel2_pin>;
- regulator-name = "vdd_gpu";
- regulator-min-microvolt = <712500>;
- regulator-max-microvolt = <1500000>;
- regulator-ramp-delay = <1000>;
- regulator-always-on;
- regulator-boot-on;
- vin-supply = <&vcc5v0_sys>;
-
- regulator-state-mem {
- regulator-off-in-suspend;
- };
- };
-};
-
-&i2c1 {
- i2c-scl-rising-time-ns = <300>;
- i2c-scl-falling-time-ns = <15>;
- status = "okay";
-};
-
-&i2c3 {
- i2c-scl-rising-time-ns = <450>;
- i2c-scl-falling-time-ns = <15>;
- status = "okay";
-};
-
-&i2c4 {
- i2c-scl-rising-time-ns = <600>;
- i2c-scl-falling-time-ns = <20>;
- status = "okay";
-};
-
-&i2c7 {
- status = "okay";
-};
-
-&i2s0 {
- rockchip,playback-channels = <8>;
- rockchip,capture-channels = <8>;
- status = "okay";
-};
-
-&i2s1 {
- rockchip,playback-channels = <2>;
- rockchip,capture-channels = <2>;
- status = "okay";
-};
-
-&i2s2 {
- status = "okay";
-};
-
-&io_domains {
- status = "okay";
-
- bt656-supply = <&vcc1v8_dvp>;
- audio-supply = <&vcc_1v8>;
- sdmmc-supply = <&vccio_sd>;
- gpio1830-supply = <&vcc_3v0>;
-};
-
-&pmu_io_domains {
- status = "okay";
- pmu1830-supply = <&vcc_3v0>;
-};
-
-&pinctrl {
- bt {
- bt_reg_on_h: bt-reg-on-h {
- rockchip,pins = <0 RK_PB1 RK_FUNC_GPIO &pcfg_pull_none>;
- };
-
- bt_host_wake_l: bt-host-wake-l {
- rockchip,pins = <0 RK_PA4 RK_FUNC_GPIO &pcfg_pull_none>;
- };
-
- bt_wake_l: bt-wake-l {
- rockchip,pins = <2 RK_PD2 RK_FUNC_GPIO &pcfg_pull_none>;
- };
- };
-
- pmic {
- pmic_int_l: pmic-int-l {
- rockchip,pins = <1 RK_PC5 RK_FUNC_GPIO &pcfg_pull_up>;
- };
-
- vsel1_pin: vsel1-pin {
- rockchip,pins = <1 RK_PC1 RK_FUNC_GPIO &pcfg_pull_down>;
- };
-
- vsel2_pin: vsel2-pin {
- rockchip,pins = <1 RK_PB6 RK_FUNC_GPIO &pcfg_pull_down>;
- };
- };
-
- usb2 {
- vcc5v0_host3_en: vcc5v0-host3-en {
- rockchip,pins = <2 RK_PA2 RK_FUNC_GPIO &pcfg_pull_none>;
- };
- };
-
- wifi {
- wifi_reg_on_h: wifi-reg-on-h {
- rockchip,pins =
- <0 RK_PB2 RK_FUNC_GPIO &pcfg_pull_none>;
- };
-
- wifi_host_wake_l: wifi-host-wake-l {
- rockchip,pins = <0 RK_PA3 RK_FUNC_GPIO &pcfg_pull_none>;
- };
- };
-};
-
-&pwm2 {
- status = "okay";
-};
-
-&saradc {
- status = "okay";
-
- vref-supply = <&vcc_1v8>;
-};
-
-&sdio0 {
- #address-cells = <1>;
- #size-cells = <0>;
- bus-width = <4>;
- clock-frequency = <50000000>;
- cap-sdio-irq;
- cap-sd-highspeed;
- keep-power-in-suspend;
- mmc-pwrseq = <&sdio_pwrseq>;
- non-removable;
- pinctrl-names = "default";
- pinctrl-0 = <&sdio0_bus4 &sdio0_cmd &sdio0_clk>;
- sd-uhs-sdr104;
- status = "okay";
-
- brcmf: wifi@1 {
- compatible = "brcm,bcm4329-fmac";
- reg = <1>;
- interrupt-parent = <&gpio0>;
- interrupts = <RK_PA3 IRQ_TYPE_LEVEL_HIGH>;
- interrupt-names = "host-wake";
- pinctrl-names = "default";
- pinctrl-0 = <&wifi_host_wake_l>;
- };
-};
-
-&sdhci {
- bus-width = <8>;
- mmc-hs400-1_8v;
- mmc-hs400-enhanced-strobe;
- non-removable;
- status = "okay";
-};
-
-&sdmmc {
- bus-width = <4>;
- cap-mmc-highspeed;
- cap-sd-highspeed;
- cd-gpios = <&gpio0 RK_PA7 GPIO_ACTIVE_LOW>;
- disable-wp;
- max-frequency = <150000000>;
- pinctrl-names = "default";
- pinctrl-0 = <&sdmmc_clk &sdmmc_cd &sdmmc_cmd &sdmmc_bus4>;
- status = "okay";
-};
-
-&tcphy0 {
- status = "okay";
-};
-
-&tcphy1 {
- status = "okay";
-};
-
-&tsadc {
- status = "okay";
-
- /* tshut mode 0:CRU 1:GPIO */
- rockchip,hw-tshut-mode = <1>;
- /* tshut polarity 0:LOW 1:HIGH */
- rockchip,hw-tshut-polarity = <1>;
-};
-
-&u2phy0 {
- status = "okay";
-
- u2phy0_otg: otg-port {
- status = "okay";
- };
-
- u2phy0_host: host-port {
- phy-supply = <&vcc5v0_host0>;
- status = "okay";
- };
-};
-
-&u2phy1 {
- status = "okay";
-
- u2phy1_otg: otg-port {
- status = "okay";
- };
-
- u2phy1_host: host-port {
- phy-supply = <&vcc5v0_host1>;
- status = "okay";
- };
-};
-
-&uart0 {
- pinctrl-names = "default";
- pinctrl-0 = <&uart0_xfer &uart0_cts &uart0_rts>;
- status = "okay";
-
- bluetooth {
- compatible = "brcm,bcm43438-bt";
- clocks = <&rk808 1>;
- clock-names = "ext_clock";
- device-wakeup-gpios = <&gpio2 RK_PD2 GPIO_ACTIVE_HIGH>;
- host-wakeup-gpios = <&gpio0 RK_PA4 GPIO_ACTIVE_HIGH>;
- shutdown-gpios = <&gpio0 RK_PB1 GPIO_ACTIVE_HIGH>;
- pinctrl-names = "default";
- pinctrl-0 = <&bt_host_wake_l &bt_wake_l &bt_reg_on_h>;
- };
-};
-
-&uart2 {
- status = "okay";
-};
-
-&usb_host0_ehci {
- status = "okay";
-};
-
-&usb_host0_ohci {
- status = "okay";
-};
-
-&usb_host1_ehci {
- status = "okay";
-};
-
-&usb_host1_ohci {
- status = "okay";
-};
-
-&usbdrd3_0 {
- status = "okay";
-};
-
-&usbdrd_dwc3_0 {
- status = "okay";
- dr_mode = "otg";
-};
-
-&usbdrd3_1 {
- status = "okay";
-};
-
-&usbdrd_dwc3_1 {
- status = "okay";
- dr_mode = "host";
-};
-
-&vopb {
- status = "okay";
-};
-
-&vopb_mmu {
- status = "okay";
-};
-
-&vopl {
- status = "okay";
-};
-
-&vopl_mmu {
- status = "okay";
-};
-
-&spi1 {
- status = "okay";
-
- spiflash: flash@0 {
- compatible = "winbond,w25q256", "jedec,spi-nor";
- reg = <0>;
- /* May run faster once verified: */
- spi-max-frequency = <1000000>; // 1MHz
-
- partitions {
- compatible = "fixed-partitions";
- #address-cells = <1>;
- #size-cells = <1>;
-
- spi-flash@0 {
- reg = <0x0 0x2000000>; // 32MiB (Full flash)
- label = "spi-flash";
- };
- };
- };
-};
Index: v6.x/create-6.0.7-leez-p710-spi-patch/linux-6.0.7-new/arch/arm64/boot/dts/rockchip
===================================================================
--- v6.x/create-6.0.7-leez-p710-spi-patch/linux-6.0.7-new/arch/arm64/boot/dts/rockchip (revision 384)
+++ v6.x/create-6.0.7-leez-p710-spi-patch/linux-6.0.7-new/arch/arm64/boot/dts/rockchip (nonexistent)
Property changes on: v6.x/create-6.0.7-leez-p710-spi-patch/linux-6.0.7-new/arch/arm64/boot/dts/rockchip
___________________________________________________________________
Deleted: svn:ignore
## -1,73 +0,0 ##
-
-# install dir
-dist
-
-# Target build dirs
-.a1x-newlib
-.a2x-newlib
-.at91sam7s-newlib
-
-.build-machine
-
-.a1x-glibc
-.a2x-glibc
-.h3-glibc
-.h5-glibc
-.i586-glibc
-.i686-glibc
-.imx6-glibc
-.jz47xx-glibc
-.makefile
-.am335x-glibc
-.omap543x-glibc
-.p5600-glibc
-.power8-glibc
-.power8le-glibc
-.power9-glibc
-.power9le-glibc
-.m1000-glibc
-.riscv64-glibc
-.rk328x-glibc
-.rk33xx-glibc
-.rk339x-glibc
-.s8xx-glibc
-.s9xx-glibc
-.x86_64-glibc
-
-# Hidden files (each file)
-.makefile
-.dist
-.rootfs
-
-# src & hw requires
-.src_requires
-.src_requires_depend
-.requires
-.requires_depend
-
-# Tarballs
-*.gz
-*.bz2
-*.lz
-*.xz
-*.tgz
-*.txz
-
-# Signatures
-*.asc
-*.sig
-*.sign
-*.sha1sum
-
-# Patches
-*.patch
-
-# Descriptions
-*.dsc
-*.txt
-
-# Default linux config files
-*.defconfig
-
-# backup copies
-*~
Index: v6.x/create-6.0.7-leez-p710-spi-patch/linux-6.0.7-new/arch/arm64/boot/dts
===================================================================
--- v6.x/create-6.0.7-leez-p710-spi-patch/linux-6.0.7-new/arch/arm64/boot/dts (revision 384)
+++ v6.x/create-6.0.7-leez-p710-spi-patch/linux-6.0.7-new/arch/arm64/boot/dts (nonexistent)
Property changes on: v6.x/create-6.0.7-leez-p710-spi-patch/linux-6.0.7-new/arch/arm64/boot/dts
___________________________________________________________________
Deleted: svn:ignore
## -1,73 +0,0 ##
-
-# install dir
-dist
-
-# Target build dirs
-.a1x-newlib
-.a2x-newlib
-.at91sam7s-newlib
-
-.build-machine
-
-.a1x-glibc
-.a2x-glibc
-.h3-glibc
-.h5-glibc
-.i586-glibc
-.i686-glibc
-.imx6-glibc
-.jz47xx-glibc
-.makefile
-.am335x-glibc
-.omap543x-glibc
-.p5600-glibc
-.power8-glibc
-.power8le-glibc
-.power9-glibc
-.power9le-glibc
-.m1000-glibc
-.riscv64-glibc
-.rk328x-glibc
-.rk33xx-glibc
-.rk339x-glibc
-.s8xx-glibc
-.s9xx-glibc
-.x86_64-glibc
-
-# Hidden files (each file)
-.makefile
-.dist
-.rootfs
-
-# src & hw requires
-.src_requires
-.src_requires_depend
-.requires
-.requires_depend
-
-# Tarballs
-*.gz
-*.bz2
-*.lz
-*.xz
-*.tgz
-*.txz
-
-# Signatures
-*.asc
-*.sig
-*.sign
-*.sha1sum
-
-# Patches
-*.patch
-
-# Descriptions
-*.dsc
-*.txt
-
-# Default linux config files
-*.defconfig
-
-# backup copies
-*~
Index: v6.x/create-6.0.7-leez-p710-spi-patch/linux-6.0.7-new/arch/arm64/boot
===================================================================
--- v6.x/create-6.0.7-leez-p710-spi-patch/linux-6.0.7-new/arch/arm64/boot (revision 384)
+++ v6.x/create-6.0.7-leez-p710-spi-patch/linux-6.0.7-new/arch/arm64/boot (nonexistent)
Property changes on: v6.x/create-6.0.7-leez-p710-spi-patch/linux-6.0.7-new/arch/arm64/boot
___________________________________________________________________
Deleted: svn:ignore
## -1,73 +0,0 ##
-
-# install dir
-dist
-
-# Target build dirs
-.a1x-newlib
-.a2x-newlib
-.at91sam7s-newlib
-
-.build-machine
-
-.a1x-glibc
-.a2x-glibc
-.h3-glibc
-.h5-glibc
-.i586-glibc
-.i686-glibc
-.imx6-glibc
-.jz47xx-glibc
-.makefile
-.am335x-glibc
-.omap543x-glibc
-.p5600-glibc
-.power8-glibc
-.power8le-glibc
-.power9-glibc
-.power9le-glibc
-.m1000-glibc
-.riscv64-glibc
-.rk328x-glibc
-.rk33xx-glibc
-.rk339x-glibc
-.s8xx-glibc
-.s9xx-glibc
-.x86_64-glibc
-
-# Hidden files (each file)
-.makefile
-.dist
-.rootfs
-
-# src & hw requires
-.src_requires
-.src_requires_depend
-.requires
-.requires_depend
-
-# Tarballs
-*.gz
-*.bz2
-*.lz
-*.xz
-*.tgz
-*.txz
-
-# Signatures
-*.asc
-*.sig
-*.sign
-*.sha1sum
-
-# Patches
-*.patch
-
-# Descriptions
-*.dsc
-*.txt
-
-# Default linux config files
-*.defconfig
-
-# backup copies
-*~
Index: v6.x/create-6.0.7-leez-p710-spi-patch/linux-6.0.7-new/arch/arm64
===================================================================
--- v6.x/create-6.0.7-leez-p710-spi-patch/linux-6.0.7-new/arch/arm64 (revision 384)
+++ v6.x/create-6.0.7-leez-p710-spi-patch/linux-6.0.7-new/arch/arm64 (nonexistent)
Property changes on: v6.x/create-6.0.7-leez-p710-spi-patch/linux-6.0.7-new/arch/arm64
___________________________________________________________________
Deleted: svn:ignore
## -1,73 +0,0 ##
-
-# install dir
-dist
-
-# Target build dirs
-.a1x-newlib
-.a2x-newlib
-.at91sam7s-newlib
-
-.build-machine
-
-.a1x-glibc
-.a2x-glibc
-.h3-glibc
-.h5-glibc
-.i586-glibc
-.i686-glibc
-.imx6-glibc
-.jz47xx-glibc
-.makefile
-.am335x-glibc
-.omap543x-glibc
-.p5600-glibc
-.power8-glibc
-.power8le-glibc
-.power9-glibc
-.power9le-glibc
-.m1000-glibc
-.riscv64-glibc
-.rk328x-glibc
-.rk33xx-glibc
-.rk339x-glibc
-.s8xx-glibc
-.s9xx-glibc
-.x86_64-glibc
-
-# Hidden files (each file)
-.makefile
-.dist
-.rootfs
-
-# src & hw requires
-.src_requires
-.src_requires_depend
-.requires
-.requires_depend
-
-# Tarballs
-*.gz
-*.bz2
-*.lz
-*.xz
-*.tgz
-*.txz
-
-# Signatures
-*.asc
-*.sig
-*.sign
-*.sha1sum
-
-# Patches
-*.patch
-
-# Descriptions
-*.dsc
-*.txt
-
-# Default linux config files
-*.defconfig
-
-# backup copies
-*~
Index: v6.x/create-6.0.7-leez-p710-spi-patch/linux-6.0.7-new/arch
===================================================================
--- v6.x/create-6.0.7-leez-p710-spi-patch/linux-6.0.7-new/arch (revision 384)
+++ v6.x/create-6.0.7-leez-p710-spi-patch/linux-6.0.7-new/arch (nonexistent)
Property changes on: v6.x/create-6.0.7-leez-p710-spi-patch/linux-6.0.7-new/arch
___________________________________________________________________
Deleted: svn:ignore
## -1,73 +0,0 ##
-
-# install dir
-dist
-
-# Target build dirs
-.a1x-newlib
-.a2x-newlib
-.at91sam7s-newlib
-
-.build-machine
-
-.a1x-glibc
-.a2x-glibc
-.h3-glibc
-.h5-glibc
-.i586-glibc
-.i686-glibc
-.imx6-glibc
-.jz47xx-glibc
-.makefile
-.am335x-glibc
-.omap543x-glibc
-.p5600-glibc
-.power8-glibc
-.power8le-glibc
-.power9-glibc
-.power9le-glibc
-.m1000-glibc
-.riscv64-glibc
-.rk328x-glibc
-.rk33xx-glibc
-.rk339x-glibc
-.s8xx-glibc
-.s9xx-glibc
-.x86_64-glibc
-
-# Hidden files (each file)
-.makefile
-.dist
-.rootfs
-
-# src & hw requires
-.src_requires
-.src_requires_depend
-.requires
-.requires_depend
-
-# Tarballs
-*.gz
-*.bz2
-*.lz
-*.xz
-*.tgz
-*.txz
-
-# Signatures
-*.asc
-*.sig
-*.sign
-*.sha1sum
-
-# Patches
-*.patch
-
-# Descriptions
-*.dsc
-*.txt
-
-# Default linux config files
-*.defconfig
-
-# backup copies
-*~
Index: v6.x/create-6.0.7-leez-p710-spi-patch/linux-6.0.7-new
===================================================================
--- v6.x/create-6.0.7-leez-p710-spi-patch/linux-6.0.7-new (revision 384)
+++ v6.x/create-6.0.7-leez-p710-spi-patch/linux-6.0.7-new (nonexistent)
Property changes on: v6.x/create-6.0.7-leez-p710-spi-patch/linux-6.0.7-new
___________________________________________________________________
Deleted: svn:ignore
## -1,73 +0,0 ##
-
-# install dir
-dist
-
-# Target build dirs
-.a1x-newlib
-.a2x-newlib
-.at91sam7s-newlib
-
-.build-machine
-
-.a1x-glibc
-.a2x-glibc
-.h3-glibc
-.h5-glibc
-.i586-glibc
-.i686-glibc
-.imx6-glibc
-.jz47xx-glibc
-.makefile
-.am335x-glibc
-.omap543x-glibc
-.p5600-glibc
-.power8-glibc
-.power8le-glibc
-.power9-glibc
-.power9le-glibc
-.m1000-glibc
-.riscv64-glibc
-.rk328x-glibc
-.rk33xx-glibc
-.rk339x-glibc
-.s8xx-glibc
-.s9xx-glibc
-.x86_64-glibc
-
-# Hidden files (each file)
-.makefile
-.dist
-.rootfs
-
-# src & hw requires
-.src_requires
-.src_requires_depend
-.requires
-.requires_depend
-
-# Tarballs
-*.gz
-*.bz2
-*.lz
-*.xz
-*.tgz
-*.txz
-
-# Signatures
-*.asc
-*.sig
-*.sign
-*.sha1sum
-
-# Patches
-*.patch
-
-# Descriptions
-*.dsc
-*.txt
-
-# Default linux config files
-*.defconfig
-
-# backup copies
-*~
Index: v6.x/create-6.0.7-leez-p710-spi-patch
===================================================================
--- v6.x/create-6.0.7-leez-p710-spi-patch (revision 384)
+++ v6.x/create-6.0.7-leez-p710-spi-patch (nonexistent)
Property changes on: v6.x/create-6.0.7-leez-p710-spi-patch
___________________________________________________________________
Deleted: svn:ignore
## -1,73 +0,0 ##
-
-# install dir
-dist
-
-# Target build dirs
-.a1x-newlib
-.a2x-newlib
-.at91sam7s-newlib
-
-.build-machine
-
-.a1x-glibc
-.a2x-glibc
-.h3-glibc
-.h5-glibc
-.i586-glibc
-.i686-glibc
-.imx6-glibc
-.jz47xx-glibc
-.makefile
-.am335x-glibc
-.omap543x-glibc
-.p5600-glibc
-.power8-glibc
-.power8le-glibc
-.power9-glibc
-.power9le-glibc
-.m1000-glibc
-.riscv64-glibc
-.rk328x-glibc
-.rk33xx-glibc
-.rk339x-glibc
-.s8xx-glibc
-.s9xx-glibc
-.x86_64-glibc
-
-# Hidden files (each file)
-.makefile
-.dist
-.rootfs
-
-# src & hw requires
-.src_requires
-.src_requires_depend
-.requires
-.requires_depend
-
-# Tarballs
-*.gz
-*.bz2
-*.lz
-*.xz
-*.tgz
-*.txz
-
-# Signatures
-*.asc
-*.sig
-*.sign
-*.sha1sum
-
-# Patches
-*.patch
-
-# Descriptions
-*.dsc
-*.txt
-
-# Default linux config files
-*.defconfig
-
-# backup copies
-*~
Index: v6.x/create-6.0.7-dwmac-rk3399-patch/file.list
===================================================================
--- v6.x/create-6.0.7-dwmac-rk3399-patch/file.list (revision 384)
+++ v6.x/create-6.0.7-dwmac-rk3399-patch/file.list (nonexistent)
@@ -1 +0,0 @@
-linux-6.0.7/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
Index: v6.x/create-6.0.7-dwmac-rk3399-patch/create.patch.sh
===================================================================
--- v6.x/create-6.0.7-dwmac-rk3399-patch/create.patch.sh (revision 384)
+++ v6.x/create-6.0.7-dwmac-rk3399-patch/create.patch.sh (nonexistent)
@@ -1,15 +0,0 @@
-#!/bin/sh
-
-VERSION=6.0.7
-
-tar --files-from=file.list -xJvf ../linux-$VERSION.tar.xz
-mv linux-$VERSION linux-$VERSION-orig
-
-cp -rf ./linux-$VERSION-new ./linux-$VERSION
-
-diff --unified -Nr linux-$VERSION-orig linux-$VERSION > linux-$VERSION-dwmac-rk3399.patch
-
-mv linux-$VERSION-dwmac-rk3399.patch ../patches
-
-rm -rf ./linux-$VERSION
-rm -rf ./linux-$VERSION-orig
Property changes on: v6.x/create-6.0.7-dwmac-rk3399-patch/create.patch.sh
___________________________________________________________________
Deleted: svn:executable
## -1 +0,0 ##
-*
\ No newline at end of property
Index: v6.x/create-6.0.7-dwmac-rk3399-patch/linux-6.0.7-new/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
===================================================================
--- v6.x/create-6.0.7-dwmac-rk3399-patch/linux-6.0.7-new/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c (revision 384)
+++ v6.x/create-6.0.7-dwmac-rk3399-patch/linux-6.0.7-new/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c (nonexistent)
@@ -1,1705 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/**
- * DOC: dwmac-rk.c - Rockchip RK3288 DWMAC specific glue layer
- *
- * Copyright (C) 2014 Chen-Zhi (Roger Chen)
- *
- * Chen-Zhi (Roger Chen) <roger.chen@rock-chips.com>
- */
-
-#include <linux/stmmac.h>
-#include <linux/bitops.h>
-#include <linux/clk.h>
-#include <linux/phy.h>
-#include <linux/of_net.h>
-#include <linux/gpio.h>
-#include <linux/module.h>
-#include <linux/of_gpio.h>
-#include <linux/of_device.h>
-#include <linux/platform_device.h>
-#include <linux/regulator/consumer.h>
-#include <linux/delay.h>
-#include <linux/mfd/syscon.h>
-#include <linux/regmap.h>
-#include <linux/pm_runtime.h>
-
-#include "stmmac_platform.h"
-
-struct rk_priv_data;
-struct rk_gmac_ops {
- void (*set_to_rgmii)(struct rk_priv_data *bsp_priv,
- int tx_delay, int rx_delay);
- void (*set_to_rmii)(struct rk_priv_data *bsp_priv);
- void (*set_rgmii_speed)(struct rk_priv_data *bsp_priv, int speed);
- void (*set_rmii_speed)(struct rk_priv_data *bsp_priv, int speed);
- void (*integrated_phy_powerup)(struct rk_priv_data *bsp_priv);
- bool regs_valid;
- u32 regs[];
-};
-
-struct rk_priv_data {
- struct platform_device *pdev;
- phy_interface_t phy_iface;
- int id;
- struct regulator *regulator;
- bool suspended;
- const struct rk_gmac_ops *ops;
-
- bool clk_enabled;
- bool clock_input;
- bool integrated_phy;
-
- struct clk *clk_mac;
- struct clk *gmac_clkin;
- struct clk *mac_clk_rx;
- struct clk *mac_clk_tx;
- struct clk *clk_mac_ref;
- struct clk *clk_mac_refout;
- struct clk *clk_mac_speed;
- struct clk *aclk_mac;
- struct clk *pclk_mac;
- struct clk *clk_phy;
-
- struct reset_control *phy_reset;
-
- int tx_delay;
- int rx_delay;
-
- struct regmap *grf;
-};
-
-#define HIWORD_UPDATE(val, mask, shift) \
- ((val) << (shift) | (mask) << ((shift) + 16))
-
-#define GRF_BIT(nr) (BIT(nr) | BIT(nr+16))
-#define GRF_CLR_BIT(nr) (BIT(nr+16))
-
-#define DELAY_ENABLE(soc, tx, rx) \
- (((tx) ? soc##_GMAC_TXCLK_DLY_ENABLE : soc##_GMAC_TXCLK_DLY_DISABLE) | \
- ((rx) ? soc##_GMAC_RXCLK_DLY_ENABLE : soc##_GMAC_RXCLK_DLY_DISABLE))
-
-#define PX30_GRF_GMAC_CON1 0x0904
-
-/* PX30_GRF_GMAC_CON1 */
-#define PX30_GMAC_PHY_INTF_SEL_RMII (GRF_CLR_BIT(4) | GRF_CLR_BIT(5) | \
- GRF_BIT(6))
-#define PX30_GMAC_SPEED_10M GRF_CLR_BIT(2)
-#define PX30_GMAC_SPEED_100M GRF_BIT(2)
-
-static void px30_set_to_rmii(struct rk_priv_data *bsp_priv)
-{
- struct device *dev = &bsp_priv->pdev->dev;
-
- if (IS_ERR(bsp_priv->grf)) {
- dev_err(dev, "%s: Missing rockchip,grf property\n", __func__);
- return;
- }
-
- regmap_write(bsp_priv->grf, PX30_GRF_GMAC_CON1,
- PX30_GMAC_PHY_INTF_SEL_RMII);
-}
-
-static void px30_set_rmii_speed(struct rk_priv_data *bsp_priv, int speed)
-{
- struct device *dev = &bsp_priv->pdev->dev;
- int ret;
-
- if (IS_ERR(bsp_priv->clk_mac_speed)) {
- dev_err(dev, "%s: Missing clk_mac_speed clock\n", __func__);
- return;
- }
-
- if (speed == 10) {
- regmap_write(bsp_priv->grf, PX30_GRF_GMAC_CON1,
- PX30_GMAC_SPEED_10M);
-
- ret = clk_set_rate(bsp_priv->clk_mac_speed, 2500000);
- if (ret)
- dev_err(dev, "%s: set clk_mac_speed rate 2500000 failed: %d\n",
- __func__, ret);
- } else if (speed == 100) {
- regmap_write(bsp_priv->grf, PX30_GRF_GMAC_CON1,
- PX30_GMAC_SPEED_100M);
-
- ret = clk_set_rate(bsp_priv->clk_mac_speed, 25000000);
- if (ret)
- dev_err(dev, "%s: set clk_mac_speed rate 25000000 failed: %d\n",
- __func__, ret);
-
- } else {
- dev_err(dev, "unknown speed value for RMII! speed=%d", speed);
- }
-}
-
-static const struct rk_gmac_ops px30_ops = {
- .set_to_rmii = px30_set_to_rmii,
- .set_rmii_speed = px30_set_rmii_speed,
-};
-
-#define RK3128_GRF_MAC_CON0 0x0168
-#define RK3128_GRF_MAC_CON1 0x016c
-
-/* RK3128_GRF_MAC_CON0 */
-#define RK3128_GMAC_TXCLK_DLY_ENABLE GRF_BIT(14)
-#define RK3128_GMAC_TXCLK_DLY_DISABLE GRF_CLR_BIT(14)
-#define RK3128_GMAC_RXCLK_DLY_ENABLE GRF_BIT(15)
-#define RK3128_GMAC_RXCLK_DLY_DISABLE GRF_CLR_BIT(15)
-#define RK3128_GMAC_CLK_RX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 7)
-#define RK3128_GMAC_CLK_TX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 0)
-
-/* RK3128_GRF_MAC_CON1 */
-#define RK3128_GMAC_PHY_INTF_SEL_RGMII \
- (GRF_BIT(6) | GRF_CLR_BIT(7) | GRF_CLR_BIT(8))
-#define RK3128_GMAC_PHY_INTF_SEL_RMII \
- (GRF_CLR_BIT(6) | GRF_CLR_BIT(7) | GRF_BIT(8))
-#define RK3128_GMAC_FLOW_CTRL GRF_BIT(9)
-#define RK3128_GMAC_FLOW_CTRL_CLR GRF_CLR_BIT(9)
-#define RK3128_GMAC_SPEED_10M GRF_CLR_BIT(10)
-#define RK3128_GMAC_SPEED_100M GRF_BIT(10)
-#define RK3128_GMAC_RMII_CLK_25M GRF_BIT(11)
-#define RK3128_GMAC_RMII_CLK_2_5M GRF_CLR_BIT(11)
-#define RK3128_GMAC_CLK_125M (GRF_CLR_BIT(12) | GRF_CLR_BIT(13))
-#define RK3128_GMAC_CLK_25M (GRF_BIT(12) | GRF_BIT(13))
-#define RK3128_GMAC_CLK_2_5M (GRF_CLR_BIT(12) | GRF_BIT(13))
-#define RK3128_GMAC_RMII_MODE GRF_BIT(14)
-#define RK3128_GMAC_RMII_MODE_CLR GRF_CLR_BIT(14)
-
-static void rk3128_set_to_rgmii(struct rk_priv_data *bsp_priv,
- int tx_delay, int rx_delay)
-{
- struct device *dev = &bsp_priv->pdev->dev;
-
- if (IS_ERR(bsp_priv->grf)) {
- dev_err(dev, "Missing rockchip,grf property\n");
- return;
- }
-
- regmap_write(bsp_priv->grf, RK3128_GRF_MAC_CON1,
- RK3128_GMAC_PHY_INTF_SEL_RGMII |
- RK3128_GMAC_RMII_MODE_CLR);
- regmap_write(bsp_priv->grf, RK3128_GRF_MAC_CON0,
- DELAY_ENABLE(RK3128, tx_delay, rx_delay) |
- RK3128_GMAC_CLK_RX_DL_CFG(rx_delay) |
- RK3128_GMAC_CLK_TX_DL_CFG(tx_delay));
-}
-
-static void rk3128_set_to_rmii(struct rk_priv_data *bsp_priv)
-{
- struct device *dev = &bsp_priv->pdev->dev;
-
- if (IS_ERR(bsp_priv->grf)) {
- dev_err(dev, "Missing rockchip,grf property\n");
- return;
- }
-
- regmap_write(bsp_priv->grf, RK3128_GRF_MAC_CON1,
- RK3128_GMAC_PHY_INTF_SEL_RMII | RK3128_GMAC_RMII_MODE);
-}
-
-static void rk3128_set_rgmii_speed(struct rk_priv_data *bsp_priv, int speed)
-{
- struct device *dev = &bsp_priv->pdev->dev;
-
- if (IS_ERR(bsp_priv->grf)) {
- dev_err(dev, "Missing rockchip,grf property\n");
- return;
- }
-
- if (speed == 10)
- regmap_write(bsp_priv->grf, RK3128_GRF_MAC_CON1,
- RK3128_GMAC_CLK_2_5M);
- else if (speed == 100)
- regmap_write(bsp_priv->grf, RK3128_GRF_MAC_CON1,
- RK3128_GMAC_CLK_25M);
- else if (speed == 1000)
- regmap_write(bsp_priv->grf, RK3128_GRF_MAC_CON1,
- RK3128_GMAC_CLK_125M);
- else
- dev_err(dev, "unknown speed value for RGMII! speed=%d", speed);
-}
-
-static void rk3128_set_rmii_speed(struct rk_priv_data *bsp_priv, int speed)
-{
- struct device *dev = &bsp_priv->pdev->dev;
-
- if (IS_ERR(bsp_priv->grf)) {
- dev_err(dev, "Missing rockchip,grf property\n");
- return;
- }
-
- if (speed == 10) {
- regmap_write(bsp_priv->grf, RK3128_GRF_MAC_CON1,
- RK3128_GMAC_RMII_CLK_2_5M |
- RK3128_GMAC_SPEED_10M);
- } else if (speed == 100) {
- regmap_write(bsp_priv->grf, RK3128_GRF_MAC_CON1,
- RK3128_GMAC_RMII_CLK_25M |
- RK3128_GMAC_SPEED_100M);
- } else {
- dev_err(dev, "unknown speed value for RMII! speed=%d", speed);
- }
-}
-
-static const struct rk_gmac_ops rk3128_ops = {
- .set_to_rgmii = rk3128_set_to_rgmii,
- .set_to_rmii = rk3128_set_to_rmii,
- .set_rgmii_speed = rk3128_set_rgmii_speed,
- .set_rmii_speed = rk3128_set_rmii_speed,
-};
-
-#define RK3228_GRF_MAC_CON0 0x0900
-#define RK3228_GRF_MAC_CON1 0x0904
-
-#define RK3228_GRF_CON_MUX 0x50
-
-/* RK3228_GRF_MAC_CON0 */
-#define RK3228_GMAC_CLK_RX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 7)
-#define RK3228_GMAC_CLK_TX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 0)
-
-/* RK3228_GRF_MAC_CON1 */
-#define RK3228_GMAC_PHY_INTF_SEL_RGMII \
- (GRF_BIT(4) | GRF_CLR_BIT(5) | GRF_CLR_BIT(6))
-#define RK3228_GMAC_PHY_INTF_SEL_RMII \
- (GRF_CLR_BIT(4) | GRF_CLR_BIT(5) | GRF_BIT(6))
-#define RK3228_GMAC_FLOW_CTRL GRF_BIT(3)
-#define RK3228_GMAC_FLOW_CTRL_CLR GRF_CLR_BIT(3)
-#define RK3228_GMAC_SPEED_10M GRF_CLR_BIT(2)
-#define RK3228_GMAC_SPEED_100M GRF_BIT(2)
-#define RK3228_GMAC_RMII_CLK_25M GRF_BIT(7)
-#define RK3228_GMAC_RMII_CLK_2_5M GRF_CLR_BIT(7)
-#define RK3228_GMAC_CLK_125M (GRF_CLR_BIT(8) | GRF_CLR_BIT(9))
-#define RK3228_GMAC_CLK_25M (GRF_BIT(8) | GRF_BIT(9))
-#define RK3228_GMAC_CLK_2_5M (GRF_CLR_BIT(8) | GRF_BIT(9))
-#define RK3228_GMAC_RMII_MODE GRF_BIT(10)
-#define RK3228_GMAC_RMII_MODE_CLR GRF_CLR_BIT(10)
-#define RK3228_GMAC_TXCLK_DLY_ENABLE GRF_BIT(0)
-#define RK3228_GMAC_TXCLK_DLY_DISABLE GRF_CLR_BIT(0)
-#define RK3228_GMAC_RXCLK_DLY_ENABLE GRF_BIT(1)
-#define RK3228_GMAC_RXCLK_DLY_DISABLE GRF_CLR_BIT(1)
-
-/* RK3228_GRF_COM_MUX */
-#define RK3228_GRF_CON_MUX_GMAC_INTEGRATED_PHY GRF_BIT(15)
-
-static void rk3228_set_to_rgmii(struct rk_priv_data *bsp_priv,
- int tx_delay, int rx_delay)
-{
- struct device *dev = &bsp_priv->pdev->dev;
-
- if (IS_ERR(bsp_priv->grf)) {
- dev_err(dev, "Missing rockchip,grf property\n");
- return;
- }
-
- regmap_write(bsp_priv->grf, RK3228_GRF_MAC_CON1,
- RK3228_GMAC_PHY_INTF_SEL_RGMII |
- RK3228_GMAC_RMII_MODE_CLR |
- DELAY_ENABLE(RK3228, tx_delay, rx_delay));
-
- regmap_write(bsp_priv->grf, RK3228_GRF_MAC_CON0,
- RK3228_GMAC_CLK_RX_DL_CFG(rx_delay) |
- RK3228_GMAC_CLK_TX_DL_CFG(tx_delay));
-}
-
-static void rk3228_set_to_rmii(struct rk_priv_data *bsp_priv)
-{
- struct device *dev = &bsp_priv->pdev->dev;
-
- if (IS_ERR(bsp_priv->grf)) {
- dev_err(dev, "Missing rockchip,grf property\n");
- return;
- }
-
- regmap_write(bsp_priv->grf, RK3228_GRF_MAC_CON1,
- RK3228_GMAC_PHY_INTF_SEL_RMII |
- RK3228_GMAC_RMII_MODE);
-
- /* set MAC to RMII mode */
- regmap_write(bsp_priv->grf, RK3228_GRF_MAC_CON1, GRF_BIT(11));
-}
-
-static void rk3228_set_rgmii_speed(struct rk_priv_data *bsp_priv, int speed)
-{
- struct device *dev = &bsp_priv->pdev->dev;
-
- if (IS_ERR(bsp_priv->grf)) {
- dev_err(dev, "Missing rockchip,grf property\n");
- return;
- }
-
- if (speed == 10)
- regmap_write(bsp_priv->grf, RK3228_GRF_MAC_CON1,
- RK3228_GMAC_CLK_2_5M);
- else if (speed == 100)
- regmap_write(bsp_priv->grf, RK3228_GRF_MAC_CON1,
- RK3228_GMAC_CLK_25M);
- else if (speed == 1000)
- regmap_write(bsp_priv->grf, RK3228_GRF_MAC_CON1,
- RK3228_GMAC_CLK_125M);
- else
- dev_err(dev, "unknown speed value for RGMII! speed=%d", speed);
-}
-
-static void rk3228_set_rmii_speed(struct rk_priv_data *bsp_priv, int speed)
-{
- struct device *dev = &bsp_priv->pdev->dev;
-
- if (IS_ERR(bsp_priv->grf)) {
- dev_err(dev, "Missing rockchip,grf property\n");
- return;
- }
-
- if (speed == 10)
- regmap_write(bsp_priv->grf, RK3228_GRF_MAC_CON1,
- RK3228_GMAC_RMII_CLK_2_5M |
- RK3228_GMAC_SPEED_10M);
- else if (speed == 100)
- regmap_write(bsp_priv->grf, RK3228_GRF_MAC_CON1,
- RK3228_GMAC_RMII_CLK_25M |
- RK3228_GMAC_SPEED_100M);
- else
- dev_err(dev, "unknown speed value for RMII! speed=%d", speed);
-}
-
-static void rk3228_integrated_phy_powerup(struct rk_priv_data *priv)
-{
- regmap_write(priv->grf, RK3228_GRF_CON_MUX,
- RK3228_GRF_CON_MUX_GMAC_INTEGRATED_PHY);
-}
-
-static const struct rk_gmac_ops rk3228_ops = {
- .set_to_rgmii = rk3228_set_to_rgmii,
- .set_to_rmii = rk3228_set_to_rmii,
- .set_rgmii_speed = rk3228_set_rgmii_speed,
- .set_rmii_speed = rk3228_set_rmii_speed,
- .integrated_phy_powerup = rk3228_integrated_phy_powerup,
-};
-
-#define RK3288_GRF_SOC_CON1 0x0248
-#define RK3288_GRF_SOC_CON3 0x0250
-
-/*RK3288_GRF_SOC_CON1*/
-#define RK3288_GMAC_PHY_INTF_SEL_RGMII (GRF_BIT(6) | GRF_CLR_BIT(7) | \
- GRF_CLR_BIT(8))
-#define RK3288_GMAC_PHY_INTF_SEL_RMII (GRF_CLR_BIT(6) | GRF_CLR_BIT(7) | \
- GRF_BIT(8))
-#define RK3288_GMAC_FLOW_CTRL GRF_BIT(9)
-#define RK3288_GMAC_FLOW_CTRL_CLR GRF_CLR_BIT(9)
-#define RK3288_GMAC_SPEED_10M GRF_CLR_BIT(10)
-#define RK3288_GMAC_SPEED_100M GRF_BIT(10)
-#define RK3288_GMAC_RMII_CLK_25M GRF_BIT(11)
-#define RK3288_GMAC_RMII_CLK_2_5M GRF_CLR_BIT(11)
-#define RK3288_GMAC_CLK_125M (GRF_CLR_BIT(12) | GRF_CLR_BIT(13))
-#define RK3288_GMAC_CLK_25M (GRF_BIT(12) | GRF_BIT(13))
-#define RK3288_GMAC_CLK_2_5M (GRF_CLR_BIT(12) | GRF_BIT(13))
-#define RK3288_GMAC_RMII_MODE GRF_BIT(14)
-#define RK3288_GMAC_RMII_MODE_CLR GRF_CLR_BIT(14)
-
-/*RK3288_GRF_SOC_CON3*/
-#define RK3288_GMAC_TXCLK_DLY_ENABLE GRF_BIT(14)
-#define RK3288_GMAC_TXCLK_DLY_DISABLE GRF_CLR_BIT(14)
-#define RK3288_GMAC_RXCLK_DLY_ENABLE GRF_BIT(15)
-#define RK3288_GMAC_RXCLK_DLY_DISABLE GRF_CLR_BIT(15)
-#define RK3288_GMAC_CLK_RX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 7)
-#define RK3288_GMAC_CLK_TX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 0)
-
-static void rk3288_set_to_rgmii(struct rk_priv_data *bsp_priv,
- int tx_delay, int rx_delay)
-{
- struct device *dev = &bsp_priv->pdev->dev;
-
- if (IS_ERR(bsp_priv->grf)) {
- dev_err(dev, "Missing rockchip,grf property\n");
- return;
- }
-
- regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1,
- RK3288_GMAC_PHY_INTF_SEL_RGMII |
- RK3288_GMAC_RMII_MODE_CLR);
- regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON3,
- DELAY_ENABLE(RK3288, tx_delay, rx_delay) |
- RK3288_GMAC_CLK_RX_DL_CFG(rx_delay) |
- RK3288_GMAC_CLK_TX_DL_CFG(tx_delay));
-}
-
-static void rk3288_set_to_rmii(struct rk_priv_data *bsp_priv)
-{
- struct device *dev = &bsp_priv->pdev->dev;
-
- if (IS_ERR(bsp_priv->grf)) {
- dev_err(dev, "Missing rockchip,grf property\n");
- return;
- }
-
- regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1,
- RK3288_GMAC_PHY_INTF_SEL_RMII | RK3288_GMAC_RMII_MODE);
-}
-
-static void rk3288_set_rgmii_speed(struct rk_priv_data *bsp_priv, int speed)
-{
- struct device *dev = &bsp_priv->pdev->dev;
-
- if (IS_ERR(bsp_priv->grf)) {
- dev_err(dev, "Missing rockchip,grf property\n");
- return;
- }
-
- if (speed == 10)
- regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1,
- RK3288_GMAC_CLK_2_5M);
- else if (speed == 100)
- regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1,
- RK3288_GMAC_CLK_25M);
- else if (speed == 1000)
- regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1,
- RK3288_GMAC_CLK_125M);
- else
- dev_err(dev, "unknown speed value for RGMII! speed=%d", speed);
-}
-
-static void rk3288_set_rmii_speed(struct rk_priv_data *bsp_priv, int speed)
-{
- struct device *dev = &bsp_priv->pdev->dev;
-
- if (IS_ERR(bsp_priv->grf)) {
- dev_err(dev, "Missing rockchip,grf property\n");
- return;
- }
-
- if (speed == 10) {
- regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1,
- RK3288_GMAC_RMII_CLK_2_5M |
- RK3288_GMAC_SPEED_10M);
- } else if (speed == 100) {
- regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1,
- RK3288_GMAC_RMII_CLK_25M |
- RK3288_GMAC_SPEED_100M);
- } else {
- dev_err(dev, "unknown speed value for RMII! speed=%d", speed);
- }
-}
-
-static const struct rk_gmac_ops rk3288_ops = {
- .set_to_rgmii = rk3288_set_to_rgmii,
- .set_to_rmii = rk3288_set_to_rmii,
- .set_rgmii_speed = rk3288_set_rgmii_speed,
- .set_rmii_speed = rk3288_set_rmii_speed,
-};
-
-#define RK3308_GRF_MAC_CON0 0x04a0
-
-/* RK3308_GRF_MAC_CON0 */
-#define RK3308_GMAC_PHY_INTF_SEL_RMII (GRF_CLR_BIT(2) | GRF_CLR_BIT(3) | \
- GRF_BIT(4))
-#define RK3308_GMAC_FLOW_CTRL GRF_BIT(3)
-#define RK3308_GMAC_FLOW_CTRL_CLR GRF_CLR_BIT(3)
-#define RK3308_GMAC_SPEED_10M GRF_CLR_BIT(0)
-#define RK3308_GMAC_SPEED_100M GRF_BIT(0)
-
-static void rk3308_set_to_rmii(struct rk_priv_data *bsp_priv)
-{
- struct device *dev = &bsp_priv->pdev->dev;
-
- if (IS_ERR(bsp_priv->grf)) {
- dev_err(dev, "Missing rockchip,grf property\n");
- return;
- }
-
- regmap_write(bsp_priv->grf, RK3308_GRF_MAC_CON0,
- RK3308_GMAC_PHY_INTF_SEL_RMII);
-}
-
-static void rk3308_set_rmii_speed(struct rk_priv_data *bsp_priv, int speed)
-{
- struct device *dev = &bsp_priv->pdev->dev;
-
- if (IS_ERR(bsp_priv->grf)) {
- dev_err(dev, "Missing rockchip,grf property\n");
- return;
- }
-
- if (speed == 10) {
- regmap_write(bsp_priv->grf, RK3308_GRF_MAC_CON0,
- RK3308_GMAC_SPEED_10M);
- } else if (speed == 100) {
- regmap_write(bsp_priv->grf, RK3308_GRF_MAC_CON0,
- RK3308_GMAC_SPEED_100M);
- } else {
- dev_err(dev, "unknown speed value for RMII! speed=%d", speed);
- }
-}
-
-static const struct rk_gmac_ops rk3308_ops = {
- .set_to_rmii = rk3308_set_to_rmii,
- .set_rmii_speed = rk3308_set_rmii_speed,
-};
-
-#define RK3328_GRF_MAC_CON0 0x0900
-#define RK3328_GRF_MAC_CON1 0x0904
-#define RK3328_GRF_MAC_CON2 0x0908
-#define RK3328_GRF_MACPHY_CON1 0xb04
-
-/* RK3328_GRF_MAC_CON0 */
-#define RK3328_GMAC_CLK_RX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 7)
-#define RK3328_GMAC_CLK_TX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 0)
-
-/* RK3328_GRF_MAC_CON1 */
-#define RK3328_GMAC_PHY_INTF_SEL_RGMII \
- (GRF_BIT(4) | GRF_CLR_BIT(5) | GRF_CLR_BIT(6))
-#define RK3328_GMAC_PHY_INTF_SEL_RMII \
- (GRF_CLR_BIT(4) | GRF_CLR_BIT(5) | GRF_BIT(6))
-#define RK3328_GMAC_FLOW_CTRL GRF_BIT(3)
-#define RK3328_GMAC_FLOW_CTRL_CLR GRF_CLR_BIT(3)
-#define RK3328_GMAC_SPEED_10M GRF_CLR_BIT(2)
-#define RK3328_GMAC_SPEED_100M GRF_BIT(2)
-#define RK3328_GMAC_RMII_CLK_25M GRF_BIT(7)
-#define RK3328_GMAC_RMII_CLK_2_5M GRF_CLR_BIT(7)
-#define RK3328_GMAC_CLK_125M (GRF_CLR_BIT(11) | GRF_CLR_BIT(12))
-#define RK3328_GMAC_CLK_25M (GRF_BIT(11) | GRF_BIT(12))
-#define RK3328_GMAC_CLK_2_5M (GRF_CLR_BIT(11) | GRF_BIT(12))
-#define RK3328_GMAC_RMII_MODE GRF_BIT(9)
-#define RK3328_GMAC_RMII_MODE_CLR GRF_CLR_BIT(9)
-#define RK3328_GMAC_TXCLK_DLY_ENABLE GRF_BIT(0)
-#define RK3328_GMAC_TXCLK_DLY_DISABLE GRF_CLR_BIT(0)
-#define RK3328_GMAC_RXCLK_DLY_ENABLE GRF_BIT(1)
-#define RK3328_GMAC_RXCLK_DLY_DISABLE GRF_CLR_BIT(0)
-
-/* RK3328_GRF_MACPHY_CON1 */
-#define RK3328_MACPHY_RMII_MODE GRF_BIT(9)
-
-static void rk3328_set_to_rgmii(struct rk_priv_data *bsp_priv,
- int tx_delay, int rx_delay)
-{
- struct device *dev = &bsp_priv->pdev->dev;
-
- if (IS_ERR(bsp_priv->grf)) {
- dev_err(dev, "Missing rockchip,grf property\n");
- return;
- }
-
- regmap_write(bsp_priv->grf, RK3328_GRF_MAC_CON1,
- RK3328_GMAC_PHY_INTF_SEL_RGMII |
- RK3328_GMAC_RMII_MODE_CLR |
- RK3328_GMAC_RXCLK_DLY_ENABLE |
- RK3328_GMAC_TXCLK_DLY_ENABLE);
-
- regmap_write(bsp_priv->grf, RK3328_GRF_MAC_CON0,
- RK3328_GMAC_CLK_RX_DL_CFG(rx_delay) |
- RK3328_GMAC_CLK_TX_DL_CFG(tx_delay));
-}
-
-static void rk3328_set_to_rmii(struct rk_priv_data *bsp_priv)
-{
- struct device *dev = &bsp_priv->pdev->dev;
- unsigned int reg;
-
- if (IS_ERR(bsp_priv->grf)) {
- dev_err(dev, "Missing rockchip,grf property\n");
- return;
- }
-
- reg = bsp_priv->integrated_phy ? RK3328_GRF_MAC_CON2 :
- RK3328_GRF_MAC_CON1;
-
- regmap_write(bsp_priv->grf, reg,
- RK3328_GMAC_PHY_INTF_SEL_RMII |
- RK3328_GMAC_RMII_MODE);
-}
-
-static void rk3328_set_rgmii_speed(struct rk_priv_data *bsp_priv, int speed)
-{
- struct device *dev = &bsp_priv->pdev->dev;
-
- if (IS_ERR(bsp_priv->grf)) {
- dev_err(dev, "Missing rockchip,grf property\n");
- return;
- }
-
- if (speed == 10)
- regmap_write(bsp_priv->grf, RK3328_GRF_MAC_CON1,
- RK3328_GMAC_CLK_2_5M);
- else if (speed == 100)
- regmap_write(bsp_priv->grf, RK3328_GRF_MAC_CON1,
- RK3328_GMAC_CLK_25M);
- else if (speed == 1000)
- regmap_write(bsp_priv->grf, RK3328_GRF_MAC_CON1,
- RK3328_GMAC_CLK_125M);
- else
- dev_err(dev, "unknown speed value for RGMII! speed=%d", speed);
-}
-
-static void rk3328_set_rmii_speed(struct rk_priv_data *bsp_priv, int speed)
-{
- struct device *dev = &bsp_priv->pdev->dev;
- unsigned int reg;
-
- if (IS_ERR(bsp_priv->grf)) {
- dev_err(dev, "Missing rockchip,grf property\n");
- return;
- }
-
- reg = bsp_priv->integrated_phy ? RK3328_GRF_MAC_CON2 :
- RK3328_GRF_MAC_CON1;
-
- if (speed == 10)
- regmap_write(bsp_priv->grf, reg,
- RK3328_GMAC_RMII_CLK_2_5M |
- RK3328_GMAC_SPEED_10M);
- else if (speed == 100)
- regmap_write(bsp_priv->grf, reg,
- RK3328_GMAC_RMII_CLK_25M |
- RK3328_GMAC_SPEED_100M);
- else
- dev_err(dev, "unknown speed value for RMII! speed=%d", speed);
-}
-
-static void rk3328_integrated_phy_powerup(struct rk_priv_data *priv)
-{
- regmap_write(priv->grf, RK3328_GRF_MACPHY_CON1,
- RK3328_MACPHY_RMII_MODE);
-}
-
-static const struct rk_gmac_ops rk3328_ops = {
- .set_to_rgmii = rk3328_set_to_rgmii,
- .set_to_rmii = rk3328_set_to_rmii,
- .set_rgmii_speed = rk3328_set_rgmii_speed,
- .set_rmii_speed = rk3328_set_rmii_speed,
- .integrated_phy_powerup = rk3328_integrated_phy_powerup,
-};
-
-#define RK3366_GRF_SOC_CON6 0x0418
-#define RK3366_GRF_SOC_CON7 0x041c
-
-/* RK3366_GRF_SOC_CON6 */
-#define RK3366_GMAC_PHY_INTF_SEL_RGMII (GRF_BIT(9) | GRF_CLR_BIT(10) | \
- GRF_CLR_BIT(11))
-#define RK3366_GMAC_PHY_INTF_SEL_RMII (GRF_CLR_BIT(9) | GRF_CLR_BIT(10) | \
- GRF_BIT(11))
-#define RK3366_GMAC_FLOW_CTRL GRF_BIT(8)
-#define RK3366_GMAC_FLOW_CTRL_CLR GRF_CLR_BIT(8)
-#define RK3366_GMAC_SPEED_10M GRF_CLR_BIT(7)
-#define RK3366_GMAC_SPEED_100M GRF_BIT(7)
-#define RK3366_GMAC_RMII_CLK_25M GRF_BIT(3)
-#define RK3366_GMAC_RMII_CLK_2_5M GRF_CLR_BIT(3)
-#define RK3366_GMAC_CLK_125M (GRF_CLR_BIT(4) | GRF_CLR_BIT(5))
-#define RK3366_GMAC_CLK_25M (GRF_BIT(4) | GRF_BIT(5))
-#define RK3366_GMAC_CLK_2_5M (GRF_CLR_BIT(4) | GRF_BIT(5))
-#define RK3366_GMAC_RMII_MODE GRF_BIT(6)
-#define RK3366_GMAC_RMII_MODE_CLR GRF_CLR_BIT(6)
-
-/* RK3366_GRF_SOC_CON7 */
-#define RK3366_GMAC_TXCLK_DLY_ENABLE GRF_BIT(7)
-#define RK3366_GMAC_TXCLK_DLY_DISABLE GRF_CLR_BIT(7)
-#define RK3366_GMAC_RXCLK_DLY_ENABLE GRF_BIT(15)
-#define RK3366_GMAC_RXCLK_DLY_DISABLE GRF_CLR_BIT(15)
-#define RK3366_GMAC_CLK_RX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 8)
-#define RK3366_GMAC_CLK_TX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 0)
-
-static void rk3366_set_to_rgmii(struct rk_priv_data *bsp_priv,
- int tx_delay, int rx_delay)
-{
- struct device *dev = &bsp_priv->pdev->dev;
-
- if (IS_ERR(bsp_priv->grf)) {
- dev_err(dev, "%s: Missing rockchip,grf property\n", __func__);
- return;
- }
-
- regmap_write(bsp_priv->grf, RK3366_GRF_SOC_CON6,
- RK3366_GMAC_PHY_INTF_SEL_RGMII |
- RK3366_GMAC_RMII_MODE_CLR);
- regmap_write(bsp_priv->grf, RK3366_GRF_SOC_CON7,
- DELAY_ENABLE(RK3366, tx_delay, rx_delay) |
- RK3366_GMAC_CLK_RX_DL_CFG(rx_delay) |
- RK3366_GMAC_CLK_TX_DL_CFG(tx_delay));
-}
-
-static void rk3366_set_to_rmii(struct rk_priv_data *bsp_priv)
-{
- struct device *dev = &bsp_priv->pdev->dev;
-
- if (IS_ERR(bsp_priv->grf)) {
- dev_err(dev, "%s: Missing rockchip,grf property\n", __func__);
- return;
- }
-
- regmap_write(bsp_priv->grf, RK3366_GRF_SOC_CON6,
- RK3366_GMAC_PHY_INTF_SEL_RMII | RK3366_GMAC_RMII_MODE);
-}
-
-static void rk3366_set_rgmii_speed(struct rk_priv_data *bsp_priv, int speed)
-{
- struct device *dev = &bsp_priv->pdev->dev;
-
- if (IS_ERR(bsp_priv->grf)) {
- dev_err(dev, "%s: Missing rockchip,grf property\n", __func__);
- return;
- }
-
- if (speed == 10)
- regmap_write(bsp_priv->grf, RK3366_GRF_SOC_CON6,
- RK3366_GMAC_CLK_2_5M);
- else if (speed == 100)
- regmap_write(bsp_priv->grf, RK3366_GRF_SOC_CON6,
- RK3366_GMAC_CLK_25M);
- else if (speed == 1000)
- regmap_write(bsp_priv->grf, RK3366_GRF_SOC_CON6,
- RK3366_GMAC_CLK_125M);
- else
- dev_err(dev, "unknown speed value for RGMII! speed=%d", speed);
-}
-
-static void rk3366_set_rmii_speed(struct rk_priv_data *bsp_priv, int speed)
-{
- struct device *dev = &bsp_priv->pdev->dev;
-
- if (IS_ERR(bsp_priv->grf)) {
- dev_err(dev, "%s: Missing rockchip,grf property\n", __func__);
- return;
- }
-
- if (speed == 10) {
- regmap_write(bsp_priv->grf, RK3366_GRF_SOC_CON6,
- RK3366_GMAC_RMII_CLK_2_5M |
- RK3366_GMAC_SPEED_10M);
- } else if (speed == 100) {
- regmap_write(bsp_priv->grf, RK3366_GRF_SOC_CON6,
- RK3366_GMAC_RMII_CLK_25M |
- RK3366_GMAC_SPEED_100M);
- } else {
- dev_err(dev, "unknown speed value for RMII! speed=%d", speed);
- }
-}
-
-static const struct rk_gmac_ops rk3366_ops = {
- .set_to_rgmii = rk3366_set_to_rgmii,
- .set_to_rmii = rk3366_set_to_rmii,
- .set_rgmii_speed = rk3366_set_rgmii_speed,
- .set_rmii_speed = rk3366_set_rmii_speed,
-};
-
-#define RK3368_GRF_SOC_CON15 0x043c
-#define RK3368_GRF_SOC_CON16 0x0440
-
-/* RK3368_GRF_SOC_CON15 */
-#define RK3368_GMAC_PHY_INTF_SEL_RGMII (GRF_BIT(9) | GRF_CLR_BIT(10) | \
- GRF_CLR_BIT(11))
-#define RK3368_GMAC_PHY_INTF_SEL_RMII (GRF_CLR_BIT(9) | GRF_CLR_BIT(10) | \
- GRF_BIT(11))
-#define RK3368_GMAC_FLOW_CTRL GRF_BIT(8)
-#define RK3368_GMAC_FLOW_CTRL_CLR GRF_CLR_BIT(8)
-#define RK3368_GMAC_SPEED_10M GRF_CLR_BIT(7)
-#define RK3368_GMAC_SPEED_100M GRF_BIT(7)
-#define RK3368_GMAC_RMII_CLK_25M GRF_BIT(3)
-#define RK3368_GMAC_RMII_CLK_2_5M GRF_CLR_BIT(3)
-#define RK3368_GMAC_CLK_125M (GRF_CLR_BIT(4) | GRF_CLR_BIT(5))
-#define RK3368_GMAC_CLK_25M (GRF_BIT(4) | GRF_BIT(5))
-#define RK3368_GMAC_CLK_2_5M (GRF_CLR_BIT(4) | GRF_BIT(5))
-#define RK3368_GMAC_RMII_MODE GRF_BIT(6)
-#define RK3368_GMAC_RMII_MODE_CLR GRF_CLR_BIT(6)
-
-/* RK3368_GRF_SOC_CON16 */
-#define RK3368_GMAC_TXCLK_DLY_ENABLE GRF_BIT(7)
-#define RK3368_GMAC_TXCLK_DLY_DISABLE GRF_CLR_BIT(7)
-#define RK3368_GMAC_RXCLK_DLY_ENABLE GRF_BIT(15)
-#define RK3368_GMAC_RXCLK_DLY_DISABLE GRF_CLR_BIT(15)
-#define RK3368_GMAC_CLK_RX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 8)
-#define RK3368_GMAC_CLK_TX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 0)
-
-static void rk3368_set_to_rgmii(struct rk_priv_data *bsp_priv,
- int tx_delay, int rx_delay)
-{
- struct device *dev = &bsp_priv->pdev->dev;
-
- if (IS_ERR(bsp_priv->grf)) {
- dev_err(dev, "%s: Missing rockchip,grf property\n", __func__);
- return;
- }
-
- regmap_write(bsp_priv->grf, RK3368_GRF_SOC_CON15,
- RK3368_GMAC_PHY_INTF_SEL_RGMII |
- RK3368_GMAC_RMII_MODE_CLR);
- regmap_write(bsp_priv->grf, RK3368_GRF_SOC_CON16,
- DELAY_ENABLE(RK3368, tx_delay, rx_delay) |
- RK3368_GMAC_CLK_RX_DL_CFG(rx_delay) |
- RK3368_GMAC_CLK_TX_DL_CFG(tx_delay));
-}
-
-static void rk3368_set_to_rmii(struct rk_priv_data *bsp_priv)
-{
- struct device *dev = &bsp_priv->pdev->dev;
-
- if (IS_ERR(bsp_priv->grf)) {
- dev_err(dev, "%s: Missing rockchip,grf property\n", __func__);
- return;
- }
-
- regmap_write(bsp_priv->grf, RK3368_GRF_SOC_CON15,
- RK3368_GMAC_PHY_INTF_SEL_RMII | RK3368_GMAC_RMII_MODE);
-}
-
-static void rk3368_set_rgmii_speed(struct rk_priv_data *bsp_priv, int speed)
-{
- struct device *dev = &bsp_priv->pdev->dev;
-
- if (IS_ERR(bsp_priv->grf)) {
- dev_err(dev, "%s: Missing rockchip,grf property\n", __func__);
- return;
- }
-
- if (speed == 10)
- regmap_write(bsp_priv->grf, RK3368_GRF_SOC_CON15,
- RK3368_GMAC_CLK_2_5M);
- else if (speed == 100)
- regmap_write(bsp_priv->grf, RK3368_GRF_SOC_CON15,
- RK3368_GMAC_CLK_25M);
- else if (speed == 1000)
- regmap_write(bsp_priv->grf, RK3368_GRF_SOC_CON15,
- RK3368_GMAC_CLK_125M);
- else
- dev_err(dev, "unknown speed value for RGMII! speed=%d", speed);
-}
-
-static void rk3368_set_rmii_speed(struct rk_priv_data *bsp_priv, int speed)
-{
- struct device *dev = &bsp_priv->pdev->dev;
-
- if (IS_ERR(bsp_priv->grf)) {
- dev_err(dev, "%s: Missing rockchip,grf property\n", __func__);
- return;
- }
-
- if (speed == 10) {
- regmap_write(bsp_priv->grf, RK3368_GRF_SOC_CON15,
- RK3368_GMAC_RMII_CLK_2_5M |
- RK3368_GMAC_SPEED_10M);
- } else if (speed == 100) {
- regmap_write(bsp_priv->grf, RK3368_GRF_SOC_CON15,
- RK3368_GMAC_RMII_CLK_25M |
- RK3368_GMAC_SPEED_100M);
- } else {
- dev_err(dev, "unknown speed value for RMII! speed=%d", speed);
- }
-}
-
-static const struct rk_gmac_ops rk3368_ops = {
- .set_to_rgmii = rk3368_set_to_rgmii,
- .set_to_rmii = rk3368_set_to_rmii,
- .set_rgmii_speed = rk3368_set_rgmii_speed,
- .set_rmii_speed = rk3368_set_rmii_speed,
-};
-
-#define RK3399_GRF_SOC_CON5 0xc214
-#define RK3399_GRF_SOC_CON6 0xc218
-
-/* RK3399_GRF_SOC_CON5 */
-#define RK3399_GMAC_PHY_INTF_SEL_RGMII (GRF_BIT(9) | GRF_CLR_BIT(10) | \
- GRF_CLR_BIT(11))
-#define RK3399_GMAC_PHY_INTF_SEL_RMII (GRF_CLR_BIT(9) | GRF_CLR_BIT(10) | \
- GRF_BIT(11))
-#define RK3399_GMAC_FLOW_CTRL GRF_BIT(8)
-#define RK3399_GMAC_FLOW_CTRL_CLR GRF_CLR_BIT(8)
-#define RK3399_GMAC_SPEED_10M GRF_CLR_BIT(7)
-#define RK3399_GMAC_SPEED_100M GRF_BIT(7)
-#define RK3399_GMAC_RMII_CLK_25M GRF_BIT(3)
-#define RK3399_GMAC_RMII_CLK_2_5M GRF_CLR_BIT(3)
-#define RK3399_GMAC_CLK_125M (GRF_CLR_BIT(4) | GRF_CLR_BIT(5))
-#define RK3399_GMAC_CLK_25M (GRF_BIT(4) | GRF_BIT(5))
-#define RK3399_GMAC_CLK_2_5M (GRF_CLR_BIT(4) | GRF_BIT(5))
-#define RK3399_GMAC_RMII_MODE GRF_BIT(6)
-#define RK3399_GMAC_RMII_MODE_CLR GRF_CLR_BIT(6)
-
-/* RK3399_GRF_SOC_CON6 */
-#define RK3399_GMAC_TXCLK_DLY_ENABLE GRF_BIT(7)
-#define RK3399_GMAC_TXCLK_DLY_DISABLE GRF_CLR_BIT(7)
-#define RK3399_GMAC_RXCLK_DLY_ENABLE GRF_BIT(15)
-#define RK3399_GMAC_RXCLK_DLY_DISABLE GRF_CLR_BIT(15)
-#define RK3399_GMAC_CLK_RX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 8)
-#define RK3399_GMAC_CLK_TX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 0)
-
-static void rk3399_set_to_rgmii(struct rk_priv_data *bsp_priv,
- int tx_delay, int rx_delay)
-{
- struct device *dev = &bsp_priv->pdev->dev;
-
- if (IS_ERR(bsp_priv->grf)) {
- dev_err(dev, "%s: Missing rockchip,grf property\n", __func__);
- return;
- }
-
- regmap_write(bsp_priv->grf, RK3399_GRF_SOC_CON5,
- RK3399_GMAC_PHY_INTF_SEL_RGMII |
- RK3399_GMAC_RMII_MODE_CLR);
- regmap_write(bsp_priv->grf, RK3399_GRF_SOC_CON6,
- DELAY_ENABLE(RK3399, tx_delay, rx_delay) |
- RK3399_GMAC_CLK_RX_DL_CFG(rx_delay) |
- RK3399_GMAC_CLK_TX_DL_CFG(tx_delay));
-}
-
-static void rk3399_set_to_rmii(struct rk_priv_data *bsp_priv)
-{
- struct device *dev = &bsp_priv->pdev->dev;
-
- if (IS_ERR(bsp_priv->grf)) {
- dev_err(dev, "%s: Missing rockchip,grf property\n", __func__);
- return;
- }
-
- regmap_write(bsp_priv->grf, RK3399_GRF_SOC_CON5,
- RK3399_GMAC_PHY_INTF_SEL_RMII | RK3399_GMAC_RMII_MODE);
-}
-
-static void rk3399_set_rgmii_speed(struct rk_priv_data *bsp_priv, int speed)
-{
- struct device *dev = &bsp_priv->pdev->dev;
-
- if (IS_ERR(bsp_priv->grf)) {
- dev_err(dev, "%s: Missing rockchip,grf property\n", __func__);
- return;
- }
-
- if (speed == 10)
- regmap_write(bsp_priv->grf, RK3399_GRF_SOC_CON5,
- RK3399_GMAC_CLK_2_5M);
- else if (speed == 100)
- regmap_write(bsp_priv->grf, RK3399_GRF_SOC_CON5,
- RK3399_GMAC_CLK_25M);
- else if (speed == 1000)
- regmap_write(bsp_priv->grf, RK3399_GRF_SOC_CON5,
- RK3399_GMAC_CLK_125M);
- else
- dev_err(dev, "unknown speed value for RGMII! speed=%d", speed);
-}
-
-static void rk3399_set_rmii_speed(struct rk_priv_data *bsp_priv, int speed)
-{
- struct device *dev = &bsp_priv->pdev->dev;
-
- if (IS_ERR(bsp_priv->grf)) {
- dev_err(dev, "%s: Missing rockchip,grf property\n", __func__);
- return;
- }
-
- if (speed == 10) {
- regmap_write(bsp_priv->grf, RK3399_GRF_SOC_CON5,
- RK3399_GMAC_RMII_CLK_2_5M |
- RK3399_GMAC_SPEED_10M);
- } else if (speed == 100) {
- regmap_write(bsp_priv->grf, RK3399_GRF_SOC_CON5,
- RK3399_GMAC_RMII_CLK_25M |
- RK3399_GMAC_SPEED_100M);
- } else {
- dev_err(dev, "unknown speed value for RMII! speed=%d", speed);
- }
-}
-
-static const struct rk_gmac_ops rk3399_ops = {
- .set_to_rgmii = rk3399_set_to_rgmii,
- .set_to_rmii = rk3399_set_to_rmii,
- .set_rgmii_speed = rk3399_set_rgmii_speed,
- .set_rmii_speed = rk3399_set_rmii_speed,
-};
-
-#define RK3568_GRF_GMAC0_CON0 0x0380
-#define RK3568_GRF_GMAC0_CON1 0x0384
-#define RK3568_GRF_GMAC1_CON0 0x0388
-#define RK3568_GRF_GMAC1_CON1 0x038c
-
-/* RK3568_GRF_GMAC0_CON1 && RK3568_GRF_GMAC1_CON1 */
-#define RK3568_GMAC_PHY_INTF_SEL_RGMII \
- (GRF_BIT(4) | GRF_CLR_BIT(5) | GRF_CLR_BIT(6))
-#define RK3568_GMAC_PHY_INTF_SEL_RMII \
- (GRF_CLR_BIT(4) | GRF_CLR_BIT(5) | GRF_BIT(6))
-#define RK3568_GMAC_FLOW_CTRL GRF_BIT(3)
-#define RK3568_GMAC_FLOW_CTRL_CLR GRF_CLR_BIT(3)
-#define RK3568_GMAC_RXCLK_DLY_ENABLE GRF_BIT(1)
-#define RK3568_GMAC_RXCLK_DLY_DISABLE GRF_CLR_BIT(1)
-#define RK3568_GMAC_TXCLK_DLY_ENABLE GRF_BIT(0)
-#define RK3568_GMAC_TXCLK_DLY_DISABLE GRF_CLR_BIT(0)
-
-/* RK3568_GRF_GMAC0_CON0 && RK3568_GRF_GMAC1_CON0 */
-#define RK3568_GMAC_CLK_RX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 8)
-#define RK3568_GMAC_CLK_TX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 0)
-
-static void rk3568_set_to_rgmii(struct rk_priv_data *bsp_priv,
- int tx_delay, int rx_delay)
-{
- struct device *dev = &bsp_priv->pdev->dev;
- u32 con0, con1;
-
- if (IS_ERR(bsp_priv->grf)) {
- dev_err(dev, "Missing rockchip,grf property\n");
- return;
- }
-
- con0 = (bsp_priv->id == 1) ? RK3568_GRF_GMAC1_CON0 :
- RK3568_GRF_GMAC0_CON0;
- con1 = (bsp_priv->id == 1) ? RK3568_GRF_GMAC1_CON1 :
- RK3568_GRF_GMAC0_CON1;
-
- regmap_write(bsp_priv->grf, con0,
- RK3568_GMAC_CLK_RX_DL_CFG(rx_delay) |
- RK3568_GMAC_CLK_TX_DL_CFG(tx_delay));
-
- regmap_write(bsp_priv->grf, con1,
- RK3568_GMAC_PHY_INTF_SEL_RGMII |
- RK3568_GMAC_RXCLK_DLY_ENABLE |
- RK3568_GMAC_TXCLK_DLY_ENABLE);
-}
-
-static void rk3568_set_to_rmii(struct rk_priv_data *bsp_priv)
-{
- struct device *dev = &bsp_priv->pdev->dev;
- u32 con1;
-
- if (IS_ERR(bsp_priv->grf)) {
- dev_err(dev, "%s: Missing rockchip,grf property\n", __func__);
- return;
- }
-
- con1 = (bsp_priv->id == 1) ? RK3568_GRF_GMAC1_CON1 :
- RK3568_GRF_GMAC0_CON1;
- regmap_write(bsp_priv->grf, con1, RK3568_GMAC_PHY_INTF_SEL_RMII);
-}
-
-static void rk3568_set_gmac_speed(struct rk_priv_data *bsp_priv, int speed)
-{
- struct device *dev = &bsp_priv->pdev->dev;
- unsigned long rate;
- int ret;
-
- switch (speed) {
- case 10:
- rate = 2500000;
- break;
- case 100:
- rate = 25000000;
- break;
- case 1000:
- rate = 125000000;
- break;
- default:
- dev_err(dev, "unknown speed value for GMAC speed=%d", speed);
- return;
- }
-
- ret = clk_set_rate(bsp_priv->clk_mac_speed, rate);
- if (ret)
- dev_err(dev, "%s: set clk_mac_speed rate %ld failed %d\n",
- __func__, rate, ret);
-}
-
-static const struct rk_gmac_ops rk3568_ops = {
- .set_to_rgmii = rk3568_set_to_rgmii,
- .set_to_rmii = rk3568_set_to_rmii,
- .set_rgmii_speed = rk3568_set_gmac_speed,
- .set_rmii_speed = rk3568_set_gmac_speed,
- .regs_valid = true,
- .regs = {
- 0xfe2a0000, /* gmac0 */
- 0xfe010000, /* gmac1 */
- 0x0, /* sentinel */
- },
-};
-
-#define RV1108_GRF_GMAC_CON0 0X0900
-
-/* RV1108_GRF_GMAC_CON0 */
-#define RV1108_GMAC_PHY_INTF_SEL_RMII (GRF_CLR_BIT(4) | GRF_CLR_BIT(5) | \
- GRF_BIT(6))
-#define RV1108_GMAC_FLOW_CTRL GRF_BIT(3)
-#define RV1108_GMAC_FLOW_CTRL_CLR GRF_CLR_BIT(3)
-#define RV1108_GMAC_SPEED_10M GRF_CLR_BIT(2)
-#define RV1108_GMAC_SPEED_100M GRF_BIT(2)
-#define RV1108_GMAC_RMII_CLK_25M GRF_BIT(7)
-#define RV1108_GMAC_RMII_CLK_2_5M GRF_CLR_BIT(7)
-
-static void rv1108_set_to_rmii(struct rk_priv_data *bsp_priv)
-{
- struct device *dev = &bsp_priv->pdev->dev;
-
- if (IS_ERR(bsp_priv->grf)) {
- dev_err(dev, "%s: Missing rockchip,grf property\n", __func__);
- return;
- }
-
- regmap_write(bsp_priv->grf, RV1108_GRF_GMAC_CON0,
- RV1108_GMAC_PHY_INTF_SEL_RMII);
-}
-
-static void rv1108_set_rmii_speed(struct rk_priv_data *bsp_priv, int speed)
-{
- struct device *dev = &bsp_priv->pdev->dev;
-
- if (IS_ERR(bsp_priv->grf)) {
- dev_err(dev, "%s: Missing rockchip,grf property\n", __func__);
- return;
- }
-
- if (speed == 10) {
- regmap_write(bsp_priv->grf, RV1108_GRF_GMAC_CON0,
- RV1108_GMAC_RMII_CLK_2_5M |
- RV1108_GMAC_SPEED_10M);
- } else if (speed == 100) {
- regmap_write(bsp_priv->grf, RV1108_GRF_GMAC_CON0,
- RV1108_GMAC_RMII_CLK_25M |
- RV1108_GMAC_SPEED_100M);
- } else {
- dev_err(dev, "unknown speed value for RMII! speed=%d", speed);
- }
-}
-
-static const struct rk_gmac_ops rv1108_ops = {
- .set_to_rmii = rv1108_set_to_rmii,
- .set_rmii_speed = rv1108_set_rmii_speed,
-};
-
-#define RK_GRF_MACPHY_CON0 0xb00
-#define RK_GRF_MACPHY_CON1 0xb04
-#define RK_GRF_MACPHY_CON2 0xb08
-#define RK_GRF_MACPHY_CON3 0xb0c
-
-#define RK_MACPHY_ENABLE GRF_BIT(0)
-#define RK_MACPHY_DISABLE GRF_CLR_BIT(0)
-#define RK_MACPHY_CFG_CLK_50M GRF_BIT(14)
-#define RK_GMAC2PHY_RMII_MODE (GRF_BIT(6) | GRF_CLR_BIT(7))
-#define RK_GRF_CON2_MACPHY_ID HIWORD_UPDATE(0x1234, 0xffff, 0)
-#define RK_GRF_CON3_MACPHY_ID HIWORD_UPDATE(0x35, 0x3f, 0)
-
-static void rk_gmac_integrated_phy_powerup(struct rk_priv_data *priv)
-{
- if (priv->ops->integrated_phy_powerup)
- priv->ops->integrated_phy_powerup(priv);
-
- regmap_write(priv->grf, RK_GRF_MACPHY_CON0, RK_MACPHY_CFG_CLK_50M);
- regmap_write(priv->grf, RK_GRF_MACPHY_CON0, RK_GMAC2PHY_RMII_MODE);
-
- regmap_write(priv->grf, RK_GRF_MACPHY_CON2, RK_GRF_CON2_MACPHY_ID);
- regmap_write(priv->grf, RK_GRF_MACPHY_CON3, RK_GRF_CON3_MACPHY_ID);
-
- if (priv->phy_reset) {
- /* PHY needs to be disabled before trying to reset it */
- regmap_write(priv->grf, RK_GRF_MACPHY_CON0, RK_MACPHY_DISABLE);
- if (priv->phy_reset)
- reset_control_assert(priv->phy_reset);
- usleep_range(10, 20);
- if (priv->phy_reset)
- reset_control_deassert(priv->phy_reset);
- usleep_range(10, 20);
- regmap_write(priv->grf, RK_GRF_MACPHY_CON0, RK_MACPHY_ENABLE);
- msleep(30);
- }
-}
-
-static void rk_gmac_integrated_phy_powerdown(struct rk_priv_data *priv)
-{
- regmap_write(priv->grf, RK_GRF_MACPHY_CON0, RK_MACPHY_DISABLE);
- if (priv->phy_reset)
- reset_control_assert(priv->phy_reset);
-}
-
-static int rk_gmac_clk_init(struct plat_stmmacenet_data *plat)
-{
- struct rk_priv_data *bsp_priv = plat->bsp_priv;
- struct device *dev = &bsp_priv->pdev->dev;
- int ret;
-
- bsp_priv->clk_enabled = false;
-
- bsp_priv->mac_clk_rx = devm_clk_get(dev, "mac_clk_rx");
- if (IS_ERR(bsp_priv->mac_clk_rx))
- dev_err(dev, "cannot get clock %s\n",
- "mac_clk_rx");
-
- bsp_priv->mac_clk_tx = devm_clk_get(dev, "mac_clk_tx");
- if (IS_ERR(bsp_priv->mac_clk_tx))
- dev_err(dev, "cannot get clock %s\n",
- "mac_clk_tx");
-
- bsp_priv->aclk_mac = devm_clk_get(dev, "aclk_mac");
- if (IS_ERR(bsp_priv->aclk_mac))
- dev_err(dev, "cannot get clock %s\n",
- "aclk_mac");
-
- bsp_priv->pclk_mac = devm_clk_get(dev, "pclk_mac");
- if (IS_ERR(bsp_priv->pclk_mac))
- dev_err(dev, "cannot get clock %s\n",
- "pclk_mac");
-
- bsp_priv->clk_mac = devm_clk_get(dev, "stmmaceth");
- if (IS_ERR(bsp_priv->clk_mac))
- dev_err(dev, "cannot get clock %s\n",
- "stmmaceth");
-
- if (bsp_priv->phy_iface == PHY_INTERFACE_MODE_RMII) {
- bsp_priv->clk_mac_ref = devm_clk_get(dev, "clk_mac_ref");
- if (IS_ERR(bsp_priv->clk_mac_ref))
- dev_err(dev, "cannot get clock %s\n",
- "clk_mac_ref");
-
- if (!bsp_priv->clock_input) {
- bsp_priv->clk_mac_refout =
- devm_clk_get(dev, "clk_mac_refout");
- if (IS_ERR(bsp_priv->clk_mac_refout))
- dev_err(dev, "cannot get clock %s\n",
- "clk_mac_refout");
- }
- }
-
- bsp_priv->clk_mac_speed = devm_clk_get(dev, "clk_mac_speed");
- if (IS_ERR(bsp_priv->clk_mac_speed))
- dev_err(dev, "cannot get clock %s\n", "clk_mac_speed");
-
- if (bsp_priv->clock_input) {
- dev_info(dev, "clock input from PHY\n");
- } else {
- if (bsp_priv->phy_iface == PHY_INTERFACE_MODE_RMII)
- clk_set_rate(bsp_priv->clk_mac, 50000000);
- }
-
- if (plat->phy_node && bsp_priv->integrated_phy) {
- bsp_priv->clk_phy = of_clk_get(plat->phy_node, 0);
- if (IS_ERR(bsp_priv->clk_phy)) {
- ret = PTR_ERR(bsp_priv->clk_phy);
- dev_err(dev, "Cannot get PHY clock: %d\n", ret);
- return -EINVAL;
- }
- clk_set_rate(bsp_priv->clk_phy, 50000000);
- }
-
- return 0;
-}
-
-static int gmac_clk_enable(struct rk_priv_data *bsp_priv, bool enable)
-{
- int phy_iface = bsp_priv->phy_iface;
-
- if (enable) {
- if (!bsp_priv->clk_enabled) {
- if (phy_iface == PHY_INTERFACE_MODE_RMII) {
- if (!IS_ERR(bsp_priv->mac_clk_rx))
- clk_prepare_enable(
- bsp_priv->mac_clk_rx);
-
- if (!IS_ERR(bsp_priv->clk_mac_ref))
- clk_prepare_enable(
- bsp_priv->clk_mac_ref);
-
- if (!IS_ERR(bsp_priv->clk_mac_refout))
- clk_prepare_enable(
- bsp_priv->clk_mac_refout);
- }
-
- if (!IS_ERR(bsp_priv->clk_phy))
- clk_prepare_enable(bsp_priv->clk_phy);
-
- if (!IS_ERR(bsp_priv->aclk_mac))
- clk_prepare_enable(bsp_priv->aclk_mac);
-
- if (!IS_ERR(bsp_priv->pclk_mac))
- clk_prepare_enable(bsp_priv->pclk_mac);
-
- if (!IS_ERR(bsp_priv->mac_clk_tx))
- clk_prepare_enable(bsp_priv->mac_clk_tx);
-
- if (!IS_ERR(bsp_priv->clk_mac_speed))
- clk_prepare_enable(bsp_priv->clk_mac_speed);
-
- /**
- * if (!IS_ERR(bsp_priv->clk_mac))
- * clk_prepare_enable(bsp_priv->clk_mac);
- */
- mdelay(5);
- bsp_priv->clk_enabled = true;
- }
- } else {
- if (bsp_priv->clk_enabled) {
- if (phy_iface == PHY_INTERFACE_MODE_RMII) {
- clk_disable_unprepare(bsp_priv->mac_clk_rx);
-
- clk_disable_unprepare(bsp_priv->clk_mac_ref);
-
- clk_disable_unprepare(bsp_priv->clk_mac_refout);
- }
-
- clk_disable_unprepare(bsp_priv->clk_phy);
-
- clk_disable_unprepare(bsp_priv->aclk_mac);
-
- clk_disable_unprepare(bsp_priv->pclk_mac);
-
- clk_disable_unprepare(bsp_priv->mac_clk_tx);
-
- clk_disable_unprepare(bsp_priv->clk_mac_speed);
- /**
- * if (!IS_ERR(bsp_priv->clk_mac))
- * clk_disable_unprepare(bsp_priv->clk_mac);
- */
- bsp_priv->clk_enabled = false;
- }
- }
-
- return 0;
-}
-
-static int phy_power_on(struct rk_priv_data *bsp_priv, bool enable)
-{
- struct regulator *ldo = bsp_priv->regulator;
- int ret;
- struct device *dev = &bsp_priv->pdev->dev;
-
- if (!ldo)
- return 0;
-
- if (enable) {
- ret = regulator_enable(ldo);
- if (ret)
- dev_err(dev, "fail to enable phy-supply\n");
- } else {
- ret = regulator_disable(ldo);
- if (ret)
- dev_err(dev, "fail to disable phy-supply\n");
- }
-
- return 0;
-}
-
-static struct rk_priv_data *rk_gmac_setup(struct platform_device *pdev,
- struct plat_stmmacenet_data *plat,
- const struct rk_gmac_ops *ops)
-{
- struct rk_priv_data *bsp_priv;
- struct device *dev = &pdev->dev;
- struct resource *res;
- int ret;
- const char *strings = NULL;
- int value;
-
- bsp_priv = devm_kzalloc(dev, sizeof(*bsp_priv), GFP_KERNEL);
- if (!bsp_priv)
- return ERR_PTR(-ENOMEM);
-
- of_get_phy_mode(dev->of_node, &bsp_priv->phy_iface);
- bsp_priv->ops = ops;
-
- /* Some SoCs have multiple MAC controllers, which need
- * to be distinguished.
- */
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (res && ops->regs_valid) {
- int i = 0;
-
- while (ops->regs[i]) {
- if (ops->regs[i] == res->start) {
- bsp_priv->id = i;
- break;
- }
- i++;
- }
- }
-
- bsp_priv->regulator = devm_regulator_get_optional(dev, "phy");
- if (IS_ERR(bsp_priv->regulator)) {
- if (PTR_ERR(bsp_priv->regulator) == -EPROBE_DEFER) {
- dev_err(dev, "phy regulator is not available yet, deferred probing\n");
- return ERR_PTR(-EPROBE_DEFER);
- }
- dev_err(dev, "no regulator found\n");
- bsp_priv->regulator = NULL;
- }
-
- ret = of_property_read_string(dev->of_node, "clock_in_out", &strings);
- if (ret) {
- dev_err(dev, "Can not read property: clock_in_out.\n");
- bsp_priv->clock_input = true;
- } else {
- dev_info(dev, "clock input or output? (%s).\n",
- strings);
- if (!strcmp(strings, "input"))
- bsp_priv->clock_input = true;
- else
- bsp_priv->clock_input = false;
- }
-
- ret = of_property_read_u32(dev->of_node, "tx_delay", &value);
- if (ret) {
- bsp_priv->tx_delay = 0x30;
- dev_err(dev, "Can not read property: tx_delay.");
- dev_err(dev, "set tx_delay to 0x%x\n",
- bsp_priv->tx_delay);
- } else {
- dev_info(dev, "TX delay(0x%x).\n", value);
- bsp_priv->tx_delay = value;
- }
-
- ret = of_property_read_u32(dev->of_node, "rx_delay", &value);
- if (ret) {
- bsp_priv->rx_delay = 0x10;
- dev_err(dev, "Can not read property: rx_delay.");
- dev_err(dev, "set rx_delay to 0x%x\n",
- bsp_priv->rx_delay);
- } else {
- dev_info(dev, "RX delay(0x%x).\n", value);
- bsp_priv->rx_delay = value;
- }
-
- bsp_priv->grf = syscon_regmap_lookup_by_phandle(dev->of_node,
- "rockchip,grf");
-
- if (plat->phy_node) {
- bsp_priv->integrated_phy = of_property_read_bool(plat->phy_node,
- "phy-is-integrated");
- if (bsp_priv->integrated_phy) {
- bsp_priv->phy_reset = of_reset_control_get(plat->phy_node, NULL);
- if (IS_ERR(bsp_priv->phy_reset)) {
- dev_err(&pdev->dev, "No PHY reset control found.\n");
- bsp_priv->phy_reset = NULL;
- }
- }
- }
- dev_info(dev, "integrated PHY? (%s).\n",
- bsp_priv->integrated_phy ? "yes" : "no");
-
- bsp_priv->pdev = pdev;
-
- return bsp_priv;
-}
-
-static int rk_gmac_check_ops(struct rk_priv_data *bsp_priv)
-{
- switch (bsp_priv->phy_iface) {
- case PHY_INTERFACE_MODE_RGMII:
- case PHY_INTERFACE_MODE_RGMII_ID:
- case PHY_INTERFACE_MODE_RGMII_RXID:
- case PHY_INTERFACE_MODE_RGMII_TXID:
- if (!bsp_priv->ops->set_to_rgmii)
- return -EINVAL;
- break;
- case PHY_INTERFACE_MODE_RMII:
- if (!bsp_priv->ops->set_to_rmii)
- return -EINVAL;
- break;
- default:
- dev_err(&bsp_priv->pdev->dev,
- "unsupported interface %d", bsp_priv->phy_iface);
- }
- return 0;
-}
-
-static int rk_gmac_powerup(struct rk_priv_data *bsp_priv)
-{
- int ret;
- struct device *dev = &bsp_priv->pdev->dev;
-
- ret = rk_gmac_check_ops(bsp_priv);
- if (ret)
- return ret;
-
- ret = gmac_clk_enable(bsp_priv, true);
- if (ret)
- return ret;
-
- /*rmii or rgmii*/
- switch (bsp_priv->phy_iface) {
- case PHY_INTERFACE_MODE_RGMII:
- dev_info(dev, "init for RGMII\n");
- bsp_priv->ops->set_to_rgmii(bsp_priv, bsp_priv->tx_delay,
- bsp_priv->rx_delay);
- break;
- case PHY_INTERFACE_MODE_RGMII_ID:
- dev_info(dev, "init for RGMII_ID\n");
- bsp_priv->ops->set_to_rgmii(bsp_priv, 0, 0);
- break;
- case PHY_INTERFACE_MODE_RGMII_RXID:
- dev_info(dev, "init for RGMII_RXID\n");
- bsp_priv->ops->set_to_rgmii(bsp_priv, bsp_priv->tx_delay, 0);
- break;
- case PHY_INTERFACE_MODE_RGMII_TXID:
- dev_info(dev, "init for RGMII_TXID\n");
- bsp_priv->ops->set_to_rgmii(bsp_priv, 0, bsp_priv->rx_delay);
- break;
- case PHY_INTERFACE_MODE_RMII:
- dev_info(dev, "init for RMII\n");
- bsp_priv->ops->set_to_rmii(bsp_priv);
- break;
- default:
- dev_err(dev, "NO interface defined!\n");
- }
-
- ret = phy_power_on(bsp_priv, true);
- if (ret) {
- gmac_clk_enable(bsp_priv, false);
- return ret;
- }
-
- pm_runtime_enable(dev);
- pm_runtime_get_sync(dev);
-
- if (bsp_priv->integrated_phy)
- rk_gmac_integrated_phy_powerup(bsp_priv);
-
- return 0;
-}
-
-static void rk_gmac_powerdown(struct rk_priv_data *gmac)
-{
- struct device *dev = &gmac->pdev->dev;
-
- if (gmac->integrated_phy)
- rk_gmac_integrated_phy_powerdown(gmac);
-
- pm_runtime_put_sync(dev);
- pm_runtime_disable(dev);
-
- phy_power_on(gmac, false);
- gmac_clk_enable(gmac, false);
-}
-
-static void rk_fix_speed(void *priv, unsigned int speed)
-{
- struct rk_priv_data *bsp_priv = priv;
- struct device *dev = &bsp_priv->pdev->dev;
-
- switch (bsp_priv->phy_iface) {
- case PHY_INTERFACE_MODE_RGMII:
- case PHY_INTERFACE_MODE_RGMII_ID:
- case PHY_INTERFACE_MODE_RGMII_RXID:
- case PHY_INTERFACE_MODE_RGMII_TXID:
- if (bsp_priv->ops->set_rgmii_speed)
- bsp_priv->ops->set_rgmii_speed(bsp_priv, speed);
- break;
- case PHY_INTERFACE_MODE_RMII:
- if (bsp_priv->ops->set_rmii_speed)
- bsp_priv->ops->set_rmii_speed(bsp_priv, speed);
- break;
- default:
- dev_err(dev, "unsupported interface %d", bsp_priv->phy_iface);
- }
-}
-
-static int rk_gmac_probe(struct platform_device *pdev)
-{
- struct plat_stmmacenet_data *plat_dat;
- struct stmmac_resources stmmac_res;
- const struct rk_gmac_ops *data;
- int ret;
-
- data = of_device_get_match_data(&pdev->dev);
- if (!data) {
- dev_err(&pdev->dev, "no of match data provided\n");
- return -EINVAL;
- }
-
- ret = stmmac_get_platform_resources(pdev, &stmmac_res);
- if (ret)
- return ret;
-
- plat_dat = stmmac_probe_config_dt(pdev, stmmac_res.mac);
- if (IS_ERR(plat_dat))
- return PTR_ERR(plat_dat);
-
- /* If the stmmac is not already selected as gmac4,
- * then make sure we fallback to gmac.
- */
- if (!plat_dat->has_gmac4)
- plat_dat->has_gmac = true;
- plat_dat->fix_mac_speed = rk_fix_speed;
-
- plat_dat->bsp_priv = rk_gmac_setup(pdev, plat_dat, data);
- if (IS_ERR(plat_dat->bsp_priv)) {
- ret = PTR_ERR(plat_dat->bsp_priv);
- goto err_remove_config_dt;
- }
-
- ret = rk_gmac_clk_init(plat_dat);
- if (ret)
- goto err_remove_config_dt;
-
- ret = rk_gmac_powerup(plat_dat->bsp_priv);
- if (ret)
- goto err_remove_config_dt;
-
- ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
- if (ret)
- goto err_gmac_powerdown;
-
- return 0;
-
-err_gmac_powerdown:
- rk_gmac_powerdown(plat_dat->bsp_priv);
-err_remove_config_dt:
- stmmac_remove_config_dt(pdev, plat_dat);
-
- return ret;
-}
-
-static int rk_gmac_remove(struct platform_device *pdev)
-{
- struct rk_priv_data *bsp_priv = get_stmmac_bsp_priv(&pdev->dev);
- int ret = stmmac_dvr_remove(&pdev->dev);
-
- rk_gmac_powerdown(bsp_priv);
-
- return ret;
-}
-
-#ifdef CONFIG_PM_SLEEP
-static int rk_gmac_suspend(struct device *dev)
-{
- struct rk_priv_data *bsp_priv = get_stmmac_bsp_priv(dev);
- int ret = stmmac_suspend(dev);
-
- /* Keep the PHY up if we use Wake-on-Lan. */
- if (!device_may_wakeup(dev)) {
- rk_gmac_powerdown(bsp_priv);
- bsp_priv->suspended = true;
- }
-
- return ret;
-}
-
-static int rk_gmac_resume(struct device *dev)
-{
- struct rk_priv_data *bsp_priv = get_stmmac_bsp_priv(dev);
-
- /* The PHY was up for Wake-on-Lan. */
- if (bsp_priv->suspended) {
- rk_gmac_powerup(bsp_priv);
- bsp_priv->suspended = false;
- }
-
- return stmmac_resume(dev);
-}
-#endif /* CONFIG_PM_SLEEP */
-
-static SIMPLE_DEV_PM_OPS(rk_gmac_pm_ops, rk_gmac_suspend, rk_gmac_resume);
-
-static const struct of_device_id rk_gmac_dwmac_match[] = {
- { .compatible = "rockchip,px30-gmac", .data = &px30_ops },
- { .compatible = "rockchip,rk3128-gmac", .data = &rk3128_ops },
- { .compatible = "rockchip,rk3228-gmac", .data = &rk3228_ops },
- { .compatible = "rockchip,rk3288-gmac", .data = &rk3288_ops },
- { .compatible = "rockchip,rk3308-gmac", .data = &rk3308_ops },
- { .compatible = "rockchip,rk3328-gmac", .data = &rk3328_ops },
- { .compatible = "rockchip,rk3366-gmac", .data = &rk3366_ops },
- { .compatible = "rockchip,rk3368-gmac", .data = &rk3368_ops },
- { .compatible = "rockchip,rk3399-gmac", .data = &rk3399_ops },
- { .compatible = "rockchip,rk3568-gmac", .data = &rk3568_ops },
- { .compatible = "rockchip,rv1108-gmac", .data = &rv1108_ops },
- { }
-};
-MODULE_DEVICE_TABLE(of, rk_gmac_dwmac_match);
-
-static struct platform_driver rk_gmac_dwmac_driver = {
- .probe = rk_gmac_probe,
- .remove = rk_gmac_remove,
- .driver = {
- .name = "rk_gmac-dwmac",
- .pm = &rk_gmac_pm_ops,
- .of_match_table = rk_gmac_dwmac_match,
- },
-};
-module_platform_driver(rk_gmac_dwmac_driver);
-
-MODULE_AUTHOR("Chen-Zhi (Roger Chen) <roger.chen@rock-chips.com>");
-MODULE_DESCRIPTION("Rockchip RK3288 DWMAC specific glue layer");
-MODULE_LICENSE("GPL");
Index: v6.x/create-6.0.7-dwmac-rk3399-patch/linux-6.0.7-new/drivers/net/ethernet/stmicro/stmmac
===================================================================
--- v6.x/create-6.0.7-dwmac-rk3399-patch/linux-6.0.7-new/drivers/net/ethernet/stmicro/stmmac (revision 384)
+++ v6.x/create-6.0.7-dwmac-rk3399-patch/linux-6.0.7-new/drivers/net/ethernet/stmicro/stmmac (nonexistent)
Property changes on: v6.x/create-6.0.7-dwmac-rk3399-patch/linux-6.0.7-new/drivers/net/ethernet/stmicro/stmmac
___________________________________________________________________
Deleted: svn:ignore
## -1,73 +0,0 ##
-
-# install dir
-dist
-
-# Target build dirs
-.a1x-newlib
-.a2x-newlib
-.at91sam7s-newlib
-
-.build-machine
-
-.a1x-glibc
-.a2x-glibc
-.h3-glibc
-.h5-glibc
-.i586-glibc
-.i686-glibc
-.imx6-glibc
-.jz47xx-glibc
-.makefile
-.am335x-glibc
-.omap543x-glibc
-.p5600-glibc
-.power8-glibc
-.power8le-glibc
-.power9-glibc
-.power9le-glibc
-.m1000-glibc
-.riscv64-glibc
-.rk328x-glibc
-.rk33xx-glibc
-.rk339x-glibc
-.s8xx-glibc
-.s9xx-glibc
-.x86_64-glibc
-
-# Hidden files (each file)
-.makefile
-.dist
-.rootfs
-
-# src & hw requires
-.src_requires
-.src_requires_depend
-.requires
-.requires_depend
-
-# Tarballs
-*.gz
-*.bz2
-*.lz
-*.xz
-*.tgz
-*.txz
-
-# Signatures
-*.asc
-*.sig
-*.sign
-*.sha1sum
-
-# Patches
-*.patch
-
-# Descriptions
-*.dsc
-*.txt
-
-# Default linux config files
-*.defconfig
-
-# backup copies
-*~
Index: v6.x/create-6.0.7-dwmac-rk3399-patch/linux-6.0.7-new/drivers/net/ethernet/stmicro
===================================================================
--- v6.x/create-6.0.7-dwmac-rk3399-patch/linux-6.0.7-new/drivers/net/ethernet/stmicro (revision 384)
+++ v6.x/create-6.0.7-dwmac-rk3399-patch/linux-6.0.7-new/drivers/net/ethernet/stmicro (nonexistent)
Property changes on: v6.x/create-6.0.7-dwmac-rk3399-patch/linux-6.0.7-new/drivers/net/ethernet/stmicro
___________________________________________________________________
Deleted: svn:ignore
## -1,73 +0,0 ##
-
-# install dir
-dist
-
-# Target build dirs
-.a1x-newlib
-.a2x-newlib
-.at91sam7s-newlib
-
-.build-machine
-
-.a1x-glibc
-.a2x-glibc
-.h3-glibc
-.h5-glibc
-.i586-glibc
-.i686-glibc
-.imx6-glibc
-.jz47xx-glibc
-.makefile
-.am335x-glibc
-.omap543x-glibc
-.p5600-glibc
-.power8-glibc
-.power8le-glibc
-.power9-glibc
-.power9le-glibc
-.m1000-glibc
-.riscv64-glibc
-.rk328x-glibc
-.rk33xx-glibc
-.rk339x-glibc
-.s8xx-glibc
-.s9xx-glibc
-.x86_64-glibc
-
-# Hidden files (each file)
-.makefile
-.dist
-.rootfs
-
-# src & hw requires
-.src_requires
-.src_requires_depend
-.requires
-.requires_depend
-
-# Tarballs
-*.gz
-*.bz2
-*.lz
-*.xz
-*.tgz
-*.txz
-
-# Signatures
-*.asc
-*.sig
-*.sign
-*.sha1sum
-
-# Patches
-*.patch
-
-# Descriptions
-*.dsc
-*.txt
-
-# Default linux config files
-*.defconfig
-
-# backup copies
-*~
Index: v6.x/create-6.0.7-dwmac-rk3399-patch/linux-6.0.7-new/drivers/net/ethernet
===================================================================
--- v6.x/create-6.0.7-dwmac-rk3399-patch/linux-6.0.7-new/drivers/net/ethernet (revision 384)
+++ v6.x/create-6.0.7-dwmac-rk3399-patch/linux-6.0.7-new/drivers/net/ethernet (nonexistent)
Property changes on: v6.x/create-6.0.7-dwmac-rk3399-patch/linux-6.0.7-new/drivers/net/ethernet
___________________________________________________________________
Deleted: svn:ignore
## -1,73 +0,0 ##
-
-# install dir
-dist
-
-# Target build dirs
-.a1x-newlib
-.a2x-newlib
-.at91sam7s-newlib
-
-.build-machine
-
-.a1x-glibc
-.a2x-glibc
-.h3-glibc
-.h5-glibc
-.i586-glibc
-.i686-glibc
-.imx6-glibc
-.jz47xx-glibc
-.makefile
-.am335x-glibc
-.omap543x-glibc
-.p5600-glibc
-.power8-glibc
-.power8le-glibc
-.power9-glibc
-.power9le-glibc
-.m1000-glibc
-.riscv64-glibc
-.rk328x-glibc
-.rk33xx-glibc
-.rk339x-glibc
-.s8xx-glibc
-.s9xx-glibc
-.x86_64-glibc
-
-# Hidden files (each file)
-.makefile
-.dist
-.rootfs
-
-# src & hw requires
-.src_requires
-.src_requires_depend
-.requires
-.requires_depend
-
-# Tarballs
-*.gz
-*.bz2
-*.lz
-*.xz
-*.tgz
-*.txz
-
-# Signatures
-*.asc
-*.sig
-*.sign
-*.sha1sum
-
-# Patches
-*.patch
-
-# Descriptions
-*.dsc
-*.txt
-
-# Default linux config files
-*.defconfig
-
-# backup copies
-*~
Index: v6.x/create-6.0.7-dwmac-rk3399-patch/linux-6.0.7-new/drivers/net
===================================================================
--- v6.x/create-6.0.7-dwmac-rk3399-patch/linux-6.0.7-new/drivers/net (revision 384)
+++ v6.x/create-6.0.7-dwmac-rk3399-patch/linux-6.0.7-new/drivers/net (nonexistent)
Property changes on: v6.x/create-6.0.7-dwmac-rk3399-patch/linux-6.0.7-new/drivers/net
___________________________________________________________________
Deleted: svn:ignore
## -1,73 +0,0 ##
-
-# install dir
-dist
-
-# Target build dirs
-.a1x-newlib
-.a2x-newlib
-.at91sam7s-newlib
-
-.build-machine
-
-.a1x-glibc
-.a2x-glibc
-.h3-glibc
-.h5-glibc
-.i586-glibc
-.i686-glibc
-.imx6-glibc
-.jz47xx-glibc
-.makefile
-.am335x-glibc
-.omap543x-glibc
-.p5600-glibc
-.power8-glibc
-.power8le-glibc
-.power9-glibc
-.power9le-glibc
-.m1000-glibc
-.riscv64-glibc
-.rk328x-glibc
-.rk33xx-glibc
-.rk339x-glibc
-.s8xx-glibc
-.s9xx-glibc
-.x86_64-glibc
-
-# Hidden files (each file)
-.makefile
-.dist
-.rootfs
-
-# src & hw requires
-.src_requires
-.src_requires_depend
-.requires
-.requires_depend
-
-# Tarballs
-*.gz
-*.bz2
-*.lz
-*.xz
-*.tgz
-*.txz
-
-# Signatures
-*.asc
-*.sig
-*.sign
-*.sha1sum
-
-# Patches
-*.patch
-
-# Descriptions
-*.dsc
-*.txt
-
-# Default linux config files
-*.defconfig
-
-# backup copies
-*~
Index: v6.x/create-6.0.7-dwmac-rk3399-patch/linux-6.0.7-new/drivers
===================================================================
--- v6.x/create-6.0.7-dwmac-rk3399-patch/linux-6.0.7-new/drivers (revision 384)
+++ v6.x/create-6.0.7-dwmac-rk3399-patch/linux-6.0.7-new/drivers (nonexistent)
Property changes on: v6.x/create-6.0.7-dwmac-rk3399-patch/linux-6.0.7-new/drivers
___________________________________________________________________
Deleted: svn:ignore
## -1,73 +0,0 ##
-
-# install dir
-dist
-
-# Target build dirs
-.a1x-newlib
-.a2x-newlib
-.at91sam7s-newlib
-
-.build-machine
-
-.a1x-glibc
-.a2x-glibc
-.h3-glibc
-.h5-glibc
-.i586-glibc
-.i686-glibc
-.imx6-glibc
-.jz47xx-glibc
-.makefile
-.am335x-glibc
-.omap543x-glibc
-.p5600-glibc
-.power8-glibc
-.power8le-glibc
-.power9-glibc
-.power9le-glibc
-.m1000-glibc
-.riscv64-glibc
-.rk328x-glibc
-.rk33xx-glibc
-.rk339x-glibc
-.s8xx-glibc
-.s9xx-glibc
-.x86_64-glibc
-
-# Hidden files (each file)
-.makefile
-.dist
-.rootfs
-
-# src & hw requires
-.src_requires
-.src_requires_depend
-.requires
-.requires_depend
-
-# Tarballs
-*.gz
-*.bz2
-*.lz
-*.xz
-*.tgz
-*.txz
-
-# Signatures
-*.asc
-*.sig
-*.sign
-*.sha1sum
-
-# Patches
-*.patch
-
-# Descriptions
-*.dsc
-*.txt
-
-# Default linux config files
-*.defconfig
-
-# backup copies
-*~
Index: v6.x/create-6.0.7-dwmac-rk3399-patch/linux-6.0.7-new
===================================================================
--- v6.x/create-6.0.7-dwmac-rk3399-patch/linux-6.0.7-new (revision 384)
+++ v6.x/create-6.0.7-dwmac-rk3399-patch/linux-6.0.7-new (nonexistent)
Property changes on: v6.x/create-6.0.7-dwmac-rk3399-patch/linux-6.0.7-new
___________________________________________________________________
Deleted: svn:ignore
## -1,73 +0,0 ##
-
-# install dir
-dist
-
-# Target build dirs
-.a1x-newlib
-.a2x-newlib
-.at91sam7s-newlib
-
-.build-machine
-
-.a1x-glibc
-.a2x-glibc
-.h3-glibc
-.h5-glibc
-.i586-glibc
-.i686-glibc
-.imx6-glibc
-.jz47xx-glibc
-.makefile
-.am335x-glibc
-.omap543x-glibc
-.p5600-glibc
-.power8-glibc
-.power8le-glibc
-.power9-glibc
-.power9le-glibc
-.m1000-glibc
-.riscv64-glibc
-.rk328x-glibc
-.rk33xx-glibc
-.rk339x-glibc
-.s8xx-glibc
-.s9xx-glibc
-.x86_64-glibc
-
-# Hidden files (each file)
-.makefile
-.dist
-.rootfs
-
-# src & hw requires
-.src_requires
-.src_requires_depend
-.requires
-.requires_depend
-
-# Tarballs
-*.gz
-*.bz2
-*.lz
-*.xz
-*.tgz
-*.txz
-
-# Signatures
-*.asc
-*.sig
-*.sign
-*.sha1sum
-
-# Patches
-*.patch
-
-# Descriptions
-*.dsc
-*.txt
-
-# Default linux config files
-*.defconfig
-
-# backup copies
-*~
Index: v6.x/create-6.0.7-dwmac-rk3399-patch
===================================================================
--- v6.x/create-6.0.7-dwmac-rk3399-patch (revision 384)
+++ v6.x/create-6.0.7-dwmac-rk3399-patch (nonexistent)
Property changes on: v6.x/create-6.0.7-dwmac-rk3399-patch
___________________________________________________________________
Deleted: svn:ignore
## -1,73 +0,0 ##
-
-# install dir
-dist
-
-# Target build dirs
-.a1x-newlib
-.a2x-newlib
-.at91sam7s-newlib
-
-.build-machine
-
-.a1x-glibc
-.a2x-glibc
-.h3-glibc
-.h5-glibc
-.i586-glibc
-.i686-glibc
-.imx6-glibc
-.jz47xx-glibc
-.makefile
-.am335x-glibc
-.omap543x-glibc
-.p5600-glibc
-.power8-glibc
-.power8le-glibc
-.power9-glibc
-.power9le-glibc
-.m1000-glibc
-.riscv64-glibc
-.rk328x-glibc
-.rk33xx-glibc
-.rk339x-glibc
-.s8xx-glibc
-.s9xx-glibc
-.x86_64-glibc
-
-# Hidden files (each file)
-.makefile
-.dist
-.rootfs
-
-# src & hw requires
-.src_requires
-.src_requires_depend
-.requires
-.requires_depend
-
-# Tarballs
-*.gz
-*.bz2
-*.lz
-*.xz
-*.tgz
-*.txz
-
-# Signatures
-*.asc
-*.sig
-*.sign
-*.sha1sum
-
-# Patches
-*.patch
-
-# Descriptions
-*.dsc
-*.txt
-
-# Default linux config files
-*.defconfig
-
-# backup copies
-*~
Index: v6.x/create-6.0.7-sdhci-reset-patch/file.list
===================================================================
--- v6.x/create-6.0.7-sdhci-reset-patch/file.list (revision 384)
+++ v6.x/create-6.0.7-sdhci-reset-patch/file.list (nonexistent)
@@ -1 +0,0 @@
-linux-6.0.7/drivers/mmc/host/sdhci.c
Index: v6.x/create-6.0.7-sdhci-reset-patch/create.patch.sh
===================================================================
--- v6.x/create-6.0.7-sdhci-reset-patch/create.patch.sh (revision 384)
+++ v6.x/create-6.0.7-sdhci-reset-patch/create.patch.sh (nonexistent)
@@ -1,15 +0,0 @@
-#!/bin/sh
-
-VERSION=6.0.7
-
-tar --files-from=file.list -xJvf ../linux-$VERSION.tar.xz
-mv linux-$VERSION linux-$VERSION-orig
-
-cp -rf ./linux-$VERSION-new ./linux-$VERSION
-
-diff --unified -Nr linux-$VERSION-orig linux-$VERSION > linux-$VERSION-sdhci-reset.patch
-
-mv linux-$VERSION-sdhci-reset.patch ../patches
-
-rm -rf ./linux-$VERSION
-rm -rf ./linux-$VERSION-orig
Property changes on: v6.x/create-6.0.7-sdhci-reset-patch/create.patch.sh
___________________________________________________________________
Deleted: svn:executable
## -1 +0,0 ##
-*
\ No newline at end of property
Index: v6.x/create-6.0.7-sdhci-reset-patch/linux-6.0.7-new/drivers/mmc/host/sdhci.c
===================================================================
--- v6.x/create-6.0.7-sdhci-reset-patch/linux-6.0.7-new/drivers/mmc/host/sdhci.c (revision 384)
+++ v6.x/create-6.0.7-sdhci-reset-patch/linux-6.0.7-new/drivers/mmc/host/sdhci.c (nonexistent)
@@ -1,4935 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * linux/drivers/mmc/host/sdhci.c - Secure Digital Host Controller Interface driver
- *
- * Copyright (C) 2005-2008 Pierre Ossman, All Rights Reserved.
- *
- * Thanks to the following companies for their support:
- *
- * - JMicron (hardware and technical support)
- */
-
-#include <linux/bitfield.h>
-#include <linux/delay.h>
-#include <linux/dmaengine.h>
-#include <linux/ktime.h>
-#include <linux/highmem.h>
-#include <linux/io.h>
-#include <linux/module.h>
-#include <linux/dma-mapping.h>
-#include <linux/slab.h>
-#include <linux/scatterlist.h>
-#include <linux/sizes.h>
-#include <linux/regulator/consumer.h>
-#include <linux/pm_runtime.h>
-#include <linux/of.h>
-
-#include <linux/leds.h>
-
-#include <linux/mmc/mmc.h>
-#include <linux/mmc/host.h>
-#include <linux/mmc/card.h>
-#include <linux/mmc/sdio.h>
-#include <linux/mmc/slot-gpio.h>
-
-#include "sdhci.h"
-
-#define DRIVER_NAME "sdhci"
-
-#define DBG(f, x...) \
- pr_debug("%s: " DRIVER_NAME ": " f, mmc_hostname(host->mmc), ## x)
-
-#define SDHCI_DUMP(f, x...) \
- pr_err("%s: " DRIVER_NAME ": " f, mmc_hostname(host->mmc), ## x)
-
-#define MAX_TUNING_LOOP 40
-
-static unsigned int debug_quirks = 0;
-static unsigned int debug_quirks2;
-
-static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable);
-
-static bool sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd);
-
-void sdhci_dumpregs(struct sdhci_host *host)
-{
- SDHCI_DUMP("============ SDHCI REGISTER DUMP ===========\n");
-
- SDHCI_DUMP("Sys addr: 0x%08x | Version: 0x%08x\n",
- sdhci_readl(host, SDHCI_DMA_ADDRESS),
- sdhci_readw(host, SDHCI_HOST_VERSION));
- SDHCI_DUMP("Blk size: 0x%08x | Blk cnt: 0x%08x\n",
- sdhci_readw(host, SDHCI_BLOCK_SIZE),
- sdhci_readw(host, SDHCI_BLOCK_COUNT));
- SDHCI_DUMP("Argument: 0x%08x | Trn mode: 0x%08x\n",
- sdhci_readl(host, SDHCI_ARGUMENT),
- sdhci_readw(host, SDHCI_TRANSFER_MODE));
- SDHCI_DUMP("Present: 0x%08x | Host ctl: 0x%08x\n",
- sdhci_readl(host, SDHCI_PRESENT_STATE),
- sdhci_readb(host, SDHCI_HOST_CONTROL));
- SDHCI_DUMP("Power: 0x%08x | Blk gap: 0x%08x\n",
- sdhci_readb(host, SDHCI_POWER_CONTROL),
- sdhci_readb(host, SDHCI_BLOCK_GAP_CONTROL));
- SDHCI_DUMP("Wake-up: 0x%08x | Clock: 0x%08x\n",
- sdhci_readb(host, SDHCI_WAKE_UP_CONTROL),
- sdhci_readw(host, SDHCI_CLOCK_CONTROL));
- SDHCI_DUMP("Timeout: 0x%08x | Int stat: 0x%08x\n",
- sdhci_readb(host, SDHCI_TIMEOUT_CONTROL),
- sdhci_readl(host, SDHCI_INT_STATUS));
- SDHCI_DUMP("Int enab: 0x%08x | Sig enab: 0x%08x\n",
- sdhci_readl(host, SDHCI_INT_ENABLE),
- sdhci_readl(host, SDHCI_SIGNAL_ENABLE));
- SDHCI_DUMP("ACmd stat: 0x%08x | Slot int: 0x%08x\n",
- sdhci_readw(host, SDHCI_AUTO_CMD_STATUS),
- sdhci_readw(host, SDHCI_SLOT_INT_STATUS));
- SDHCI_DUMP("Caps: 0x%08x | Caps_1: 0x%08x\n",
- sdhci_readl(host, SDHCI_CAPABILITIES),
- sdhci_readl(host, SDHCI_CAPABILITIES_1));
- SDHCI_DUMP("Cmd: 0x%08x | Max curr: 0x%08x\n",
- sdhci_readw(host, SDHCI_COMMAND),
- sdhci_readl(host, SDHCI_MAX_CURRENT));
- SDHCI_DUMP("Resp[0]: 0x%08x | Resp[1]: 0x%08x\n",
- sdhci_readl(host, SDHCI_RESPONSE),
- sdhci_readl(host, SDHCI_RESPONSE + 4));
- SDHCI_DUMP("Resp[2]: 0x%08x | Resp[3]: 0x%08x\n",
- sdhci_readl(host, SDHCI_RESPONSE + 8),
- sdhci_readl(host, SDHCI_RESPONSE + 12));
- SDHCI_DUMP("Host ctl2: 0x%08x\n",
- sdhci_readw(host, SDHCI_HOST_CONTROL2));
-
- if (host->flags & SDHCI_USE_ADMA) {
- if (host->flags & SDHCI_USE_64_BIT_DMA) {
- SDHCI_DUMP("ADMA Err: 0x%08x | ADMA Ptr: 0x%08x%08x\n",
- sdhci_readl(host, SDHCI_ADMA_ERROR),
- sdhci_readl(host, SDHCI_ADMA_ADDRESS_HI),
- sdhci_readl(host, SDHCI_ADMA_ADDRESS));
- } else {
- SDHCI_DUMP("ADMA Err: 0x%08x | ADMA Ptr: 0x%08x\n",
- sdhci_readl(host, SDHCI_ADMA_ERROR),
- sdhci_readl(host, SDHCI_ADMA_ADDRESS));
- }
- }
-
- if (host->ops->dump_vendor_regs)
- host->ops->dump_vendor_regs(host);
-
- SDHCI_DUMP("============================================\n");
-}
-EXPORT_SYMBOL_GPL(sdhci_dumpregs);
-
-/*****************************************************************************\
- * *
- * Low level functions *
- * *
-\*****************************************************************************/
-
-static void sdhci_do_enable_v4_mode(struct sdhci_host *host)
-{
- u16 ctrl2;
-
- ctrl2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
- if (ctrl2 & SDHCI_CTRL_V4_MODE)
- return;
-
- ctrl2 |= SDHCI_CTRL_V4_MODE;
- sdhci_writew(host, ctrl2, SDHCI_HOST_CONTROL2);
-}
-
-/*
- * This can be called before sdhci_add_host() by Vendor's host controller
- * driver to enable v4 mode if supported.
- */
-void sdhci_enable_v4_mode(struct sdhci_host *host)
-{
- host->v4_mode = true;
- sdhci_do_enable_v4_mode(host);
-}
-EXPORT_SYMBOL_GPL(sdhci_enable_v4_mode);
-
-static inline bool sdhci_data_line_cmd(struct mmc_command *cmd)
-{
- return cmd->data || cmd->flags & MMC_RSP_BUSY;
-}
-
-static void sdhci_set_card_detection(struct sdhci_host *host, bool enable)
-{
- u32 present;
-
- if ((host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) ||
- !mmc_card_is_removable(host->mmc) || mmc_can_gpio_cd(host->mmc))
- return;
-
- if (enable) {
- present = sdhci_readl(host, SDHCI_PRESENT_STATE) &
- SDHCI_CARD_PRESENT;
-
- host->ier |= present ? SDHCI_INT_CARD_REMOVE :
- SDHCI_INT_CARD_INSERT;
- } else {
- host->ier &= ~(SDHCI_INT_CARD_REMOVE | SDHCI_INT_CARD_INSERT);
- }
-
- sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
- sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
-}
-
-static void sdhci_enable_card_detection(struct sdhci_host *host)
-{
- sdhci_set_card_detection(host, true);
-}
-
-static void sdhci_disable_card_detection(struct sdhci_host *host)
-{
- sdhci_set_card_detection(host, false);
-}
-
-static void sdhci_runtime_pm_bus_on(struct sdhci_host *host)
-{
- if (host->bus_on)
- return;
- host->bus_on = true;
- pm_runtime_get_noresume(mmc_dev(host->mmc));
-}
-
-static void sdhci_runtime_pm_bus_off(struct sdhci_host *host)
-{
- if (!host->bus_on)
- return;
- host->bus_on = false;
- pm_runtime_put_noidle(mmc_dev(host->mmc));
-}
-
-void sdhci_reset(struct sdhci_host *host, u8 mask)
-{
- ktime_t timeout;
-
- sdhci_writeb(host, mask, SDHCI_SOFTWARE_RESET);
-
- if (mask & SDHCI_RESET_ALL) {
- host->clock = 0;
- /* Reset-all turns off SD Bus Power */
- if (host->quirks2 & SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON)
- sdhci_runtime_pm_bus_off(host);
- if (host->ops->voltage_switch)
- host->ops->voltage_switch(host);
- }
-
- /* Wait max 100 ms */
- timeout = ktime_add_ms(ktime_get(), 100);
-
- /* hw clears the bit when it's done */
- while (1) {
- bool timedout = ktime_after(ktime_get(), timeout);
-
- if (!(sdhci_readb(host, SDHCI_SOFTWARE_RESET) & mask))
- break;
- if (timedout) {
- pr_err("%s: Reset 0x%x never completed.\n",
- mmc_hostname(host->mmc), (int)mask);
- sdhci_err_stats_inc(host, CTRL_TIMEOUT);
- sdhci_dumpregs(host);
- return;
- }
- udelay(10);
- }
-}
-EXPORT_SYMBOL_GPL(sdhci_reset);
-
-static void sdhci_do_reset(struct sdhci_host *host, u8 mask)
-{
- if (host->quirks & SDHCI_QUIRK_NO_CARD_NO_RESET) {
- struct mmc_host *mmc = host->mmc;
-
- if (!mmc->ops->get_cd(mmc))
- return;
- }
-
- host->ops->reset(host, mask);
-
- if (mask & SDHCI_RESET_ALL) {
- if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) {
- if (host->ops->enable_dma)
- host->ops->enable_dma(host);
- }
-
- /* Resetting the controller clears many */
- host->preset_enabled = false;
- }
-}
-
-static void sdhci_set_default_irqs(struct sdhci_host *host)
-{
- host->ier = SDHCI_INT_BUS_POWER | SDHCI_INT_DATA_END_BIT |
- SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_TIMEOUT |
- SDHCI_INT_INDEX | SDHCI_INT_END_BIT | SDHCI_INT_CRC |
- SDHCI_INT_TIMEOUT | SDHCI_INT_DATA_END |
- SDHCI_INT_RESPONSE;
-
- if (host->tuning_mode == SDHCI_TUNING_MODE_2 ||
- host->tuning_mode == SDHCI_TUNING_MODE_3)
- host->ier |= SDHCI_INT_RETUNE;
-
- sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
- sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
-}
-
-static void sdhci_config_dma(struct sdhci_host *host)
-{
- u8 ctrl;
- u16 ctrl2;
-
- if (host->version < SDHCI_SPEC_200)
- return;
-
- ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
-
- /*
- * Always adjust the DMA selection as some controllers
- * (e.g. JMicron) can't do PIO properly when the selection
- * is ADMA.
- */
- ctrl &= ~SDHCI_CTRL_DMA_MASK;
- if (!(host->flags & SDHCI_REQ_USE_DMA))
- goto out;
-
- /* Note if DMA Select is zero then SDMA is selected */
- if (host->flags & SDHCI_USE_ADMA)
- ctrl |= SDHCI_CTRL_ADMA32;
-
- if (host->flags & SDHCI_USE_64_BIT_DMA) {
- /*
- * If v4 mode, all supported DMA can be 64-bit addressing if
- * controller supports 64-bit system address, otherwise only
- * ADMA can support 64-bit addressing.
- */
- if (host->v4_mode) {
- ctrl2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
- ctrl2 |= SDHCI_CTRL_64BIT_ADDR;
- sdhci_writew(host, ctrl2, SDHCI_HOST_CONTROL2);
- } else if (host->flags & SDHCI_USE_ADMA) {
- /*
- * Don't need to undo SDHCI_CTRL_ADMA32 in order to
- * set SDHCI_CTRL_ADMA64.
- */
- ctrl |= SDHCI_CTRL_ADMA64;
- }
- }
-
-out:
- sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
-}
-
-static void sdhci_init(struct sdhci_host *host, int soft)
-{
- struct mmc_host *mmc = host->mmc;
- unsigned long flags;
-
- if (soft)
- sdhci_do_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
- else
- sdhci_do_reset(host, SDHCI_RESET_ALL);
-
- if (host->v4_mode)
- sdhci_do_enable_v4_mode(host);
-
- spin_lock_irqsave(&host->lock, flags);
- sdhci_set_default_irqs(host);
- spin_unlock_irqrestore(&host->lock, flags);
-
- host->cqe_on = false;
-
- if (soft) {
- /* force clock reconfiguration */
- host->clock = 0;
- mmc->ops->set_ios(mmc, &mmc->ios);
- }
-}
-
-static void sdhci_reinit(struct sdhci_host *host)
-{
- u32 cd = host->ier & (SDHCI_INT_CARD_REMOVE | SDHCI_INT_CARD_INSERT);
-
- sdhci_init(host, 0);
- sdhci_enable_card_detection(host);
-
- /*
- * A change to the card detect bits indicates a change in present state,
- * refer sdhci_set_card_detection(). A card detect interrupt might have
- * been missed while the host controller was being reset, so trigger a
- * rescan to check.
- */
- if (cd != (host->ier & (SDHCI_INT_CARD_REMOVE | SDHCI_INT_CARD_INSERT)))
- mmc_detect_change(host->mmc, msecs_to_jiffies(200));
-}
-
-static void __sdhci_led_activate(struct sdhci_host *host)
-{
- u8 ctrl;
-
- if (host->quirks & SDHCI_QUIRK_NO_LED)
- return;
-
- ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
- ctrl |= SDHCI_CTRL_LED;
- sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
-}
-
-static void __sdhci_led_deactivate(struct sdhci_host *host)
-{
- u8 ctrl;
-
- if (host->quirks & SDHCI_QUIRK_NO_LED)
- return;
-
- ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
- ctrl &= ~SDHCI_CTRL_LED;
- sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
-}
-
-#if IS_REACHABLE(CONFIG_LEDS_CLASS)
-static void sdhci_led_control(struct led_classdev *led,
- enum led_brightness brightness)
-{
- struct sdhci_host *host = container_of(led, struct sdhci_host, led);
- unsigned long flags;
-
- spin_lock_irqsave(&host->lock, flags);
-
- if (host->runtime_suspended)
- goto out;
-
- if (brightness == LED_OFF)
- __sdhci_led_deactivate(host);
- else
- __sdhci_led_activate(host);
-out:
- spin_unlock_irqrestore(&host->lock, flags);
-}
-
-static int sdhci_led_register(struct sdhci_host *host)
-{
- struct mmc_host *mmc = host->mmc;
-
- if (host->quirks & SDHCI_QUIRK_NO_LED)
- return 0;
-
- snprintf(host->led_name, sizeof(host->led_name),
- "%s::", mmc_hostname(mmc));
-
- host->led.name = host->led_name;
- host->led.brightness = LED_OFF;
- host->led.default_trigger = mmc_hostname(mmc);
- host->led.brightness_set = sdhci_led_control;
-
- return led_classdev_register(mmc_dev(mmc), &host->led);
-}
-
-static void sdhci_led_unregister(struct sdhci_host *host)
-{
- if (host->quirks & SDHCI_QUIRK_NO_LED)
- return;
-
- led_classdev_unregister(&host->led);
-}
-
-static inline void sdhci_led_activate(struct sdhci_host *host)
-{
-}
-
-static inline void sdhci_led_deactivate(struct sdhci_host *host)
-{
-}
-
-#else
-
-static inline int sdhci_led_register(struct sdhci_host *host)
-{
- return 0;
-}
-
-static inline void sdhci_led_unregister(struct sdhci_host *host)
-{
-}
-
-static inline void sdhci_led_activate(struct sdhci_host *host)
-{
- __sdhci_led_activate(host);
-}
-
-static inline void sdhci_led_deactivate(struct sdhci_host *host)
-{
- __sdhci_led_deactivate(host);
-}
-
-#endif
-
-static void sdhci_mod_timer(struct sdhci_host *host, struct mmc_request *mrq,
- unsigned long timeout)
-{
- if (sdhci_data_line_cmd(mrq->cmd))
- mod_timer(&host->data_timer, timeout);
- else
- mod_timer(&host->timer, timeout);
-}
-
-static void sdhci_del_timer(struct sdhci_host *host, struct mmc_request *mrq)
-{
- if (sdhci_data_line_cmd(mrq->cmd))
- del_timer(&host->data_timer);
- else
- del_timer(&host->timer);
-}
-
-static inline bool sdhci_has_requests(struct sdhci_host *host)
-{
- return host->cmd || host->data_cmd;
-}
-
-/*****************************************************************************\
- * *
- * Core functions *
- * *
-\*****************************************************************************/
-
-static void sdhci_read_block_pio(struct sdhci_host *host)
-{
- unsigned long flags;
- size_t blksize, len, chunk;
- u32 scratch;
- u8 *buf;
-
- DBG("PIO reading\n");
-
- blksize = host->data->blksz;
- chunk = 0;
-
- local_irq_save(flags);
-
- while (blksize) {
- BUG_ON(!sg_miter_next(&host->sg_miter));
-
- len = min(host->sg_miter.length, blksize);
-
- blksize -= len;
- host->sg_miter.consumed = len;
-
- buf = host->sg_miter.addr;
-
- while (len) {
- if (chunk == 0) {
- scratch = sdhci_readl(host, SDHCI_BUFFER);
- chunk = 4;
- }
-
- *buf = scratch & 0xFF;
-
- buf++;
- scratch >>= 8;
- chunk--;
- len--;
- }
- }
-
- sg_miter_stop(&host->sg_miter);
-
- local_irq_restore(flags);
-}
-
-static void sdhci_write_block_pio(struct sdhci_host *host)
-{
- unsigned long flags;
- size_t blksize, len, chunk;
- u32 scratch;
- u8 *buf;
-
- DBG("PIO writing\n");
-
- blksize = host->data->blksz;
- chunk = 0;
- scratch = 0;
-
- local_irq_save(flags);
-
- while (blksize) {
- BUG_ON(!sg_miter_next(&host->sg_miter));
-
- len = min(host->sg_miter.length, blksize);
-
- blksize -= len;
- host->sg_miter.consumed = len;
-
- buf = host->sg_miter.addr;
-
- while (len) {
- scratch |= (u32)*buf << (chunk * 8);
-
- buf++;
- chunk++;
- len--;
-
- if ((chunk == 4) || ((len == 0) && (blksize == 0))) {
- sdhci_writel(host, scratch, SDHCI_BUFFER);
- chunk = 0;
- scratch = 0;
- }
- }
- }
-
- sg_miter_stop(&host->sg_miter);
-
- local_irq_restore(flags);
-}
-
-static void sdhci_transfer_pio(struct sdhci_host *host)
-{
- u32 mask;
-
- if (host->blocks == 0)
- return;
-
- if (host->data->flags & MMC_DATA_READ)
- mask = SDHCI_DATA_AVAILABLE;
- else
- mask = SDHCI_SPACE_AVAILABLE;
-
- /*
- * Some controllers (JMicron JMB38x) mess up the buffer bits
- * for transfers < 4 bytes. As long as it is just one block,
- * we can ignore the bits.
- */
- if ((host->quirks & SDHCI_QUIRK_BROKEN_SMALL_PIO) &&
- (host->data->blocks == 1))
- mask = ~0;
-
- while (sdhci_readl(host, SDHCI_PRESENT_STATE) & mask) {
- if (host->quirks & SDHCI_QUIRK_PIO_NEEDS_DELAY)
- udelay(100);
-
- if (host->data->flags & MMC_DATA_READ)
- sdhci_read_block_pio(host);
- else
- sdhci_write_block_pio(host);
-
- host->blocks--;
- if (host->blocks == 0)
- break;
- }
-
- DBG("PIO transfer complete.\n");
-}
-
-static int sdhci_pre_dma_transfer(struct sdhci_host *host,
- struct mmc_data *data, int cookie)
-{
- int sg_count;
-
- /*
- * If the data buffers are already mapped, return the previous
- * dma_map_sg() result.
- */
- if (data->host_cookie == COOKIE_PRE_MAPPED)
- return data->sg_count;
-
- /* Bounce write requests to the bounce buffer */
- if (host->bounce_buffer) {
- unsigned int length = data->blksz * data->blocks;
-
- if (length > host->bounce_buffer_size) {
- pr_err("%s: asked for transfer of %u bytes exceeds bounce buffer %u bytes\n",
- mmc_hostname(host->mmc), length,
- host->bounce_buffer_size);
- return -EIO;
- }
- if (mmc_get_dma_dir(data) == DMA_TO_DEVICE) {
- /* Copy the data to the bounce buffer */
- if (host->ops->copy_to_bounce_buffer) {
- host->ops->copy_to_bounce_buffer(host,
- data, length);
- } else {
- sg_copy_to_buffer(data->sg, data->sg_len,
- host->bounce_buffer, length);
- }
- }
- /* Switch ownership to the DMA */
- dma_sync_single_for_device(mmc_dev(host->mmc),
- host->bounce_addr,
- host->bounce_buffer_size,
- mmc_get_dma_dir(data));
- /* Just a dummy value */
- sg_count = 1;
- } else {
- /* Just access the data directly from memory */
- sg_count = dma_map_sg(mmc_dev(host->mmc),
- data->sg, data->sg_len,
- mmc_get_dma_dir(data));
- }
-
- if (sg_count == 0)
- return -ENOSPC;
-
- data->sg_count = sg_count;
- data->host_cookie = cookie;
-
- return sg_count;
-}
-
-static char *sdhci_kmap_atomic(struct scatterlist *sg, unsigned long *flags)
-{
- local_irq_save(*flags);
- return kmap_atomic(sg_page(sg)) + sg->offset;
-}
-
-static void sdhci_kunmap_atomic(void *buffer, unsigned long *flags)
-{
- kunmap_atomic(buffer);
- local_irq_restore(*flags);
-}
-
-void sdhci_adma_write_desc(struct sdhci_host *host, void **desc,
- dma_addr_t addr, int len, unsigned int cmd)
-{
- struct sdhci_adma2_64_desc *dma_desc = *desc;
-
- /* 32-bit and 64-bit descriptors have these members in same position */
- dma_desc->cmd = cpu_to_le16(cmd);
- dma_desc->len = cpu_to_le16(len);
- dma_desc->addr_lo = cpu_to_le32(lower_32_bits(addr));
-
- if (host->flags & SDHCI_USE_64_BIT_DMA)
- dma_desc->addr_hi = cpu_to_le32(upper_32_bits(addr));
-
- *desc += host->desc_sz;
-}
-EXPORT_SYMBOL_GPL(sdhci_adma_write_desc);
-
-static inline void __sdhci_adma_write_desc(struct sdhci_host *host,
- void **desc, dma_addr_t addr,
- int len, unsigned int cmd)
-{
- if (host->ops->adma_write_desc)
- host->ops->adma_write_desc(host, desc, addr, len, cmd);
- else
- sdhci_adma_write_desc(host, desc, addr, len, cmd);
-}
-
-static void sdhci_adma_mark_end(void *desc)
-{
- struct sdhci_adma2_64_desc *dma_desc = desc;
-
- /* 32-bit and 64-bit descriptors have 'cmd' in same position */
- dma_desc->cmd |= cpu_to_le16(ADMA2_END);
-}
-
-static void sdhci_adma_table_pre(struct sdhci_host *host,
- struct mmc_data *data, int sg_count)
-{
- struct scatterlist *sg;
- unsigned long flags;
- dma_addr_t addr, align_addr;
- void *desc, *align;
- char *buffer;
- int len, offset, i;
-
- /*
- * The spec does not specify endianness of descriptor table.
- * We currently guess that it is LE.
- */
-
- host->sg_count = sg_count;
-
- desc = host->adma_table;
- align = host->align_buffer;
-
- align_addr = host->align_addr;
-
- for_each_sg(data->sg, sg, host->sg_count, i) {
- addr = sg_dma_address(sg);
- len = sg_dma_len(sg);
-
- /*
- * The SDHCI specification states that ADMA addresses must
- * be 32-bit aligned. If they aren't, then we use a bounce
- * buffer for the (up to three) bytes that screw up the
- * alignment.
- */
- offset = (SDHCI_ADMA2_ALIGN - (addr & SDHCI_ADMA2_MASK)) &
- SDHCI_ADMA2_MASK;
- if (offset) {
- if (data->flags & MMC_DATA_WRITE) {
- buffer = sdhci_kmap_atomic(sg, &flags);
- memcpy(align, buffer, offset);
- sdhci_kunmap_atomic(buffer, &flags);
- }
-
- /* tran, valid */
- __sdhci_adma_write_desc(host, &desc, align_addr,
- offset, ADMA2_TRAN_VALID);
-
- BUG_ON(offset > 65536);
-
- align += SDHCI_ADMA2_ALIGN;
- align_addr += SDHCI_ADMA2_ALIGN;
-
- addr += offset;
- len -= offset;
- }
-
- /*
- * The block layer forces a minimum segment size of PAGE_SIZE,
- * so 'len' can be too big here if PAGE_SIZE >= 64KiB. Write
- * multiple descriptors, noting that the ADMA table is sized
- * for 4KiB chunks anyway, so it will be big enough.
- */
- while (len > host->max_adma) {
- int n = 32 * 1024; /* 32KiB*/
-
- __sdhci_adma_write_desc(host, &desc, addr, n, ADMA2_TRAN_VALID);
- addr += n;
- len -= n;
- }
-
- /* tran, valid */
- if (len)
- __sdhci_adma_write_desc(host, &desc, addr, len,
- ADMA2_TRAN_VALID);
-
- /*
- * If this triggers then we have a calculation bug
- * somewhere. :/
- */
- WARN_ON((desc - host->adma_table) >= host->adma_table_sz);
- }
-
- if (host->quirks & SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC) {
- /* Mark the last descriptor as the terminating descriptor */
- if (desc != host->adma_table) {
- desc -= host->desc_sz;
- sdhci_adma_mark_end(desc);
- }
- } else {
- /* Add a terminating entry - nop, end, valid */
- __sdhci_adma_write_desc(host, &desc, 0, 0, ADMA2_NOP_END_VALID);
- }
-}
-
-static void sdhci_adma_table_post(struct sdhci_host *host,
- struct mmc_data *data)
-{
- struct scatterlist *sg;
- int i, size;
- void *align;
- char *buffer;
- unsigned long flags;
-
- if (data->flags & MMC_DATA_READ) {
- bool has_unaligned = false;
-
- /* Do a quick scan of the SG list for any unaligned mappings */
- for_each_sg(data->sg, sg, host->sg_count, i)
- if (sg_dma_address(sg) & SDHCI_ADMA2_MASK) {
- has_unaligned = true;
- break;
- }
-
- if (has_unaligned) {
- dma_sync_sg_for_cpu(mmc_dev(host->mmc), data->sg,
- data->sg_len, DMA_FROM_DEVICE);
-
- align = host->align_buffer;
-
- for_each_sg(data->sg, sg, host->sg_count, i) {
- if (sg_dma_address(sg) & SDHCI_ADMA2_MASK) {
- size = SDHCI_ADMA2_ALIGN -
- (sg_dma_address(sg) & SDHCI_ADMA2_MASK);
-
- buffer = sdhci_kmap_atomic(sg, &flags);
- memcpy(buffer, align, size);
- sdhci_kunmap_atomic(buffer, &flags);
-
- align += SDHCI_ADMA2_ALIGN;
- }
- }
- }
- }
-}
-
-static void sdhci_set_adma_addr(struct sdhci_host *host, dma_addr_t addr)
-{
- sdhci_writel(host, lower_32_bits(addr), SDHCI_ADMA_ADDRESS);
- if (host->flags & SDHCI_USE_64_BIT_DMA)
- sdhci_writel(host, upper_32_bits(addr), SDHCI_ADMA_ADDRESS_HI);
-}
-
-static dma_addr_t sdhci_sdma_address(struct sdhci_host *host)
-{
- if (host->bounce_buffer)
- return host->bounce_addr;
- else
- return sg_dma_address(host->data->sg);
-}
-
-static void sdhci_set_sdma_addr(struct sdhci_host *host, dma_addr_t addr)
-{
- if (host->v4_mode)
- sdhci_set_adma_addr(host, addr);
- else
- sdhci_writel(host, addr, SDHCI_DMA_ADDRESS);
-}
-
-static unsigned int sdhci_target_timeout(struct sdhci_host *host,
- struct mmc_command *cmd,
- struct mmc_data *data)
-{
- unsigned int target_timeout;
-
- /* timeout in us */
- if (!data) {
- target_timeout = cmd->busy_timeout * 1000;
- } else {
- target_timeout = DIV_ROUND_UP(data->timeout_ns, 1000);
- if (host->clock && data->timeout_clks) {
- unsigned long long val;
-
- /*
- * data->timeout_clks is in units of clock cycles.
- * host->clock is in Hz. target_timeout is in us.
- * Hence, us = 1000000 * cycles / Hz. Round up.
- */
- val = 1000000ULL * data->timeout_clks;
- if (do_div(val, host->clock))
- target_timeout++;
- target_timeout += val;
- }
- }
-
- return target_timeout;
-}
-
-static void sdhci_calc_sw_timeout(struct sdhci_host *host,
- struct mmc_command *cmd)
-{
- struct mmc_data *data = cmd->data;
- struct mmc_host *mmc = host->mmc;
- struct mmc_ios *ios = &mmc->ios;
- unsigned char bus_width = 1 << ios->bus_width;
- unsigned int blksz;
- unsigned int freq;
- u64 target_timeout;
- u64 transfer_time;
-
- target_timeout = sdhci_target_timeout(host, cmd, data);
- target_timeout *= NSEC_PER_USEC;
-
- if (data) {
- blksz = data->blksz;
- freq = mmc->actual_clock ? : host->clock;
- transfer_time = (u64)blksz * NSEC_PER_SEC * (8 / bus_width);
- do_div(transfer_time, freq);
- /* multiply by '2' to account for any unknowns */
- transfer_time = transfer_time * 2;
- /* calculate timeout for the entire data */
- host->data_timeout = data->blocks * target_timeout +
- transfer_time;
- } else {
- host->data_timeout = target_timeout;
- }
-
- if (host->data_timeout)
- host->data_timeout += MMC_CMD_TRANSFER_TIME;
-}
-
-static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd,
- bool *too_big)
-{
- u8 count;
- struct mmc_data *data;
- unsigned target_timeout, current_timeout;
-
- *too_big = false;
-
- /*
- * If the host controller provides us with an incorrect timeout
- * value, just skip the check and use the maximum. The hardware may take
- * longer to time out, but that's much better than having a too-short
- * timeout value.
- */
- if (host->quirks & SDHCI_QUIRK_BROKEN_TIMEOUT_VAL)
- return host->max_timeout_count;
-
- /* Unspecified command, assume max */
- if (cmd == NULL)
- return host->max_timeout_count;
-
- data = cmd->data;
- /* Unspecified timeout, assume max */
- if (!data && !cmd->busy_timeout)
- return host->max_timeout_count;
-
- /* timeout in us */
- target_timeout = sdhci_target_timeout(host, cmd, data);
-
- /*
- * Figure out needed cycles.
- * We do this in steps in order to fit inside a 32 bit int.
- * The first step is the minimum timeout, which will have a
- * minimum resolution of 6 bits:
- * (1) 2^13*1000 > 2^22,
- * (2) host->timeout_clk < 2^16
- * =>
- * (1) / (2) > 2^6
- */
- count = 0;
- current_timeout = (1 << 13) * 1000 / host->timeout_clk;
- while (current_timeout < target_timeout) {
- count++;
- current_timeout <<= 1;
- if (count > host->max_timeout_count) {
- if (!(host->quirks2 & SDHCI_QUIRK2_DISABLE_HW_TIMEOUT))
- DBG("Too large timeout 0x%x requested for CMD%d!\n",
- count, cmd->opcode);
- count = host->max_timeout_count;
- *too_big = true;
- break;
- }
- }
-
- return count;
-}
-
-static void sdhci_set_transfer_irqs(struct sdhci_host *host)
-{
- u32 pio_irqs = SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL;
- u32 dma_irqs = SDHCI_INT_DMA_END | SDHCI_INT_ADMA_ERROR;
-
- if (host->flags & SDHCI_REQ_USE_DMA)
- host->ier = (host->ier & ~pio_irqs) | dma_irqs;
- else
- host->ier = (host->ier & ~dma_irqs) | pio_irqs;
-
- if (host->flags & (SDHCI_AUTO_CMD23 | SDHCI_AUTO_CMD12))
- host->ier |= SDHCI_INT_AUTO_CMD_ERR;
- else
- host->ier &= ~SDHCI_INT_AUTO_CMD_ERR;
-
- sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
- sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
-}
-
-void sdhci_set_data_timeout_irq(struct sdhci_host *host, bool enable)
-{
- if (enable)
- host->ier |= SDHCI_INT_DATA_TIMEOUT;
- else
- host->ier &= ~SDHCI_INT_DATA_TIMEOUT;
- sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
- sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
-}
-EXPORT_SYMBOL_GPL(sdhci_set_data_timeout_irq);
-
-void __sdhci_set_timeout(struct sdhci_host *host, struct mmc_command *cmd)
-{
- bool too_big = false;
- u8 count = sdhci_calc_timeout(host, cmd, &too_big);
-
- if (too_big &&
- host->quirks2 & SDHCI_QUIRK2_DISABLE_HW_TIMEOUT) {
- sdhci_calc_sw_timeout(host, cmd);
- sdhci_set_data_timeout_irq(host, false);
- } else if (!(host->ier & SDHCI_INT_DATA_TIMEOUT)) {
- sdhci_set_data_timeout_irq(host, true);
- }
-
- sdhci_writeb(host, count, SDHCI_TIMEOUT_CONTROL);
-}
-EXPORT_SYMBOL_GPL(__sdhci_set_timeout);
-
-static void sdhci_set_timeout(struct sdhci_host *host, struct mmc_command *cmd)
-{
- if (host->ops->set_timeout)
- host->ops->set_timeout(host, cmd);
- else
- __sdhci_set_timeout(host, cmd);
-}
-
-static void sdhci_initialize_data(struct sdhci_host *host,
- struct mmc_data *data)
-{
- WARN_ON(host->data);
-
- /* Sanity checks */
- BUG_ON(data->blksz * data->blocks > 524288);
- BUG_ON(data->blksz > host->mmc->max_blk_size);
- BUG_ON(data->blocks > 65535);
-
- host->data = data;
- host->data_early = 0;
- host->data->bytes_xfered = 0;
-}
-
-static inline void sdhci_set_block_info(struct sdhci_host *host,
- struct mmc_data *data)
-{
- /* Set the DMA boundary value and block size */
- sdhci_writew(host,
- SDHCI_MAKE_BLKSZ(host->sdma_boundary, data->blksz),
- SDHCI_BLOCK_SIZE);
- /*
- * For Version 4.10 onwards, if v4 mode is enabled, 32-bit Block Count
- * can be supported, in that case 16-bit block count register must be 0.
- */
- if (host->version >= SDHCI_SPEC_410 && host->v4_mode &&
- (host->quirks2 & SDHCI_QUIRK2_USE_32BIT_BLK_CNT)) {
- if (sdhci_readw(host, SDHCI_BLOCK_COUNT))
- sdhci_writew(host, 0, SDHCI_BLOCK_COUNT);
- sdhci_writew(host, data->blocks, SDHCI_32BIT_BLK_CNT);
- } else {
- sdhci_writew(host, data->blocks, SDHCI_BLOCK_COUNT);
- }
-}
-
-static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd)
-{
- struct mmc_data *data = cmd->data;
-
- sdhci_initialize_data(host, data);
-
- if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) {
- struct scatterlist *sg;
- unsigned int length_mask, offset_mask;
- int i;
-
- host->flags |= SDHCI_REQ_USE_DMA;
-
- /*
- * FIXME: This doesn't account for merging when mapping the
- * scatterlist.
- *
- * The assumption here being that alignment and lengths are
- * the same after DMA mapping to device address space.
- */
- length_mask = 0;
- offset_mask = 0;
- if (host->flags & SDHCI_USE_ADMA) {
- if (host->quirks & SDHCI_QUIRK_32BIT_ADMA_SIZE) {
- length_mask = 3;
- /*
- * As we use up to 3 byte chunks to work
- * around alignment problems, we need to
- * check the offset as well.
- */
- offset_mask = 3;
- }
- } else {
- if (host->quirks & SDHCI_QUIRK_32BIT_DMA_SIZE)
- length_mask = 3;
- if (host->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR)
- offset_mask = 3;
- }
-
- if (unlikely(length_mask | offset_mask)) {
- for_each_sg(data->sg, sg, data->sg_len, i) {
- if (sg->length & length_mask) {
- DBG("Reverting to PIO because of transfer size (%d)\n",
- sg->length);
- host->flags &= ~SDHCI_REQ_USE_DMA;
- break;
- }
- if (sg->offset & offset_mask) {
- DBG("Reverting to PIO because of bad alignment\n");
- host->flags &= ~SDHCI_REQ_USE_DMA;
- break;
- }
- }
- }
- }
-
- if (host->flags & SDHCI_REQ_USE_DMA) {
- int sg_cnt = sdhci_pre_dma_transfer(host, data, COOKIE_MAPPED);
-
- if (sg_cnt <= 0) {
- /*
- * This only happens when someone fed
- * us an invalid request.
- */
- WARN_ON(1);
- host->flags &= ~SDHCI_REQ_USE_DMA;
- } else if (host->flags & SDHCI_USE_ADMA) {
- sdhci_adma_table_pre(host, data, sg_cnt);
- sdhci_set_adma_addr(host, host->adma_addr);
- } else {
- WARN_ON(sg_cnt != 1);
- sdhci_set_sdma_addr(host, sdhci_sdma_address(host));
- }
- }
-
- sdhci_config_dma(host);
-
- if (!(host->flags & SDHCI_REQ_USE_DMA)) {
- int flags;
-
- flags = SG_MITER_ATOMIC;
- if (host->data->flags & MMC_DATA_READ)
- flags |= SG_MITER_TO_SG;
- else
- flags |= SG_MITER_FROM_SG;
- sg_miter_start(&host->sg_miter, data->sg, data->sg_len, flags);
- host->blocks = data->blocks;
- }
-
- sdhci_set_transfer_irqs(host);
-
- sdhci_set_block_info(host, data);
-}
-
-#if IS_ENABLED(CONFIG_MMC_SDHCI_EXTERNAL_DMA)
-
-static int sdhci_external_dma_init(struct sdhci_host *host)
-{
- int ret = 0;
- struct mmc_host *mmc = host->mmc;
-
- host->tx_chan = dma_request_chan(mmc_dev(mmc), "tx");
- if (IS_ERR(host->tx_chan)) {
- ret = PTR_ERR(host->tx_chan);
- if (ret != -EPROBE_DEFER)
- pr_warn("Failed to request TX DMA channel.\n");
- host->tx_chan = NULL;
- return ret;
- }
-
- host->rx_chan = dma_request_chan(mmc_dev(mmc), "rx");
- if (IS_ERR(host->rx_chan)) {
- if (host->tx_chan) {
- dma_release_channel(host->tx_chan);
- host->tx_chan = NULL;
- }
-
- ret = PTR_ERR(host->rx_chan);
- if (ret != -EPROBE_DEFER)
- pr_warn("Failed to request RX DMA channel.\n");
- host->rx_chan = NULL;
- }
-
- return ret;
-}
-
-static struct dma_chan *sdhci_external_dma_channel(struct sdhci_host *host,
- struct mmc_data *data)
-{
- return data->flags & MMC_DATA_WRITE ? host->tx_chan : host->rx_chan;
-}
-
-static int sdhci_external_dma_setup(struct sdhci_host *host,
- struct mmc_command *cmd)
-{
- int ret, i;
- enum dma_transfer_direction dir;
- struct dma_async_tx_descriptor *desc;
- struct mmc_data *data = cmd->data;
- struct dma_chan *chan;
- struct dma_slave_config cfg;
- dma_cookie_t cookie;
- int sg_cnt;
-
- if (!host->mapbase)
- return -EINVAL;
-
- memset(&cfg, 0, sizeof(cfg));
- cfg.src_addr = host->mapbase + SDHCI_BUFFER;
- cfg.dst_addr = host->mapbase + SDHCI_BUFFER;
- cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
- cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
- cfg.src_maxburst = data->blksz / 4;
- cfg.dst_maxburst = data->blksz / 4;
-
- /* Sanity check: all the SG entries must be aligned by block size. */
- for (i = 0; i < data->sg_len; i++) {
- if ((data->sg + i)->length % data->blksz)
- return -EINVAL;
- }
-
- chan = sdhci_external_dma_channel(host, data);
-
- ret = dmaengine_slave_config(chan, &cfg);
- if (ret)
- return ret;
-
- sg_cnt = sdhci_pre_dma_transfer(host, data, COOKIE_MAPPED);
- if (sg_cnt <= 0)
- return -EINVAL;
-
- dir = data->flags & MMC_DATA_WRITE ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM;
- desc = dmaengine_prep_slave_sg(chan, data->sg, data->sg_len, dir,
- DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
- if (!desc)
- return -EINVAL;
-
- desc->callback = NULL;
- desc->callback_param = NULL;
-
- cookie = dmaengine_submit(desc);
- if (dma_submit_error(cookie))
- ret = cookie;
-
- return ret;
-}
-
-static void sdhci_external_dma_release(struct sdhci_host *host)
-{
- if (host->tx_chan) {
- dma_release_channel(host->tx_chan);
- host->tx_chan = NULL;
- }
-
- if (host->rx_chan) {
- dma_release_channel(host->rx_chan);
- host->rx_chan = NULL;
- }
-
- sdhci_switch_external_dma(host, false);
-}
-
-static void __sdhci_external_dma_prepare_data(struct sdhci_host *host,
- struct mmc_command *cmd)
-{
- struct mmc_data *data = cmd->data;
-
- sdhci_initialize_data(host, data);
-
- host->flags |= SDHCI_REQ_USE_DMA;
- sdhci_set_transfer_irqs(host);
-
- sdhci_set_block_info(host, data);
-}
-
-static void sdhci_external_dma_prepare_data(struct sdhci_host *host,
- struct mmc_command *cmd)
-{
- if (!sdhci_external_dma_setup(host, cmd)) {
- __sdhci_external_dma_prepare_data(host, cmd);
- } else {
- sdhci_external_dma_release(host);
- pr_err("%s: Cannot use external DMA, switch to the DMA/PIO which standard SDHCI provides.\n",
- mmc_hostname(host->mmc));
- sdhci_prepare_data(host, cmd);
- }
-}
-
-static void sdhci_external_dma_pre_transfer(struct sdhci_host *host,
- struct mmc_command *cmd)
-{
- struct dma_chan *chan;
-
- if (!cmd->data)
- return;
-
- chan = sdhci_external_dma_channel(host, cmd->data);
- if (chan)
- dma_async_issue_pending(chan);
-}
-
-#else
-
-static inline int sdhci_external_dma_init(struct sdhci_host *host)
-{
- return -EOPNOTSUPP;
-}
-
-static inline void sdhci_external_dma_release(struct sdhci_host *host)
-{
-}
-
-static inline void sdhci_external_dma_prepare_data(struct sdhci_host *host,
- struct mmc_command *cmd)
-{
- /* This should never happen */
- WARN_ON_ONCE(1);
-}
-
-static inline void sdhci_external_dma_pre_transfer(struct sdhci_host *host,
- struct mmc_command *cmd)
-{
-}
-
-static inline struct dma_chan *sdhci_external_dma_channel(struct sdhci_host *host,
- struct mmc_data *data)
-{
- return NULL;
-}
-
-#endif
-
-void sdhci_switch_external_dma(struct sdhci_host *host, bool en)
-{
- host->use_external_dma = en;
-}
-EXPORT_SYMBOL_GPL(sdhci_switch_external_dma);
-
-static inline bool sdhci_auto_cmd12(struct sdhci_host *host,
- struct mmc_request *mrq)
-{
- return !mrq->sbc && (host->flags & SDHCI_AUTO_CMD12) &&
- !mrq->cap_cmd_during_tfr;
-}
-
-static inline bool sdhci_auto_cmd23(struct sdhci_host *host,
- struct mmc_request *mrq)
-{
- return mrq->sbc && (host->flags & SDHCI_AUTO_CMD23);
-}
-
-static inline bool sdhci_manual_cmd23(struct sdhci_host *host,
- struct mmc_request *mrq)
-{
- return mrq->sbc && !(host->flags & SDHCI_AUTO_CMD23);
-}
-
-static inline void sdhci_auto_cmd_select(struct sdhci_host *host,
- struct mmc_command *cmd,
- u16 *mode)
-{
- bool use_cmd12 = sdhci_auto_cmd12(host, cmd->mrq) &&
- (cmd->opcode != SD_IO_RW_EXTENDED);
- bool use_cmd23 = sdhci_auto_cmd23(host, cmd->mrq);
- u16 ctrl2;
-
- /*
- * In case of Version 4.10 or later, use of 'Auto CMD Auto
- * Select' is recommended rather than use of 'Auto CMD12
- * Enable' or 'Auto CMD23 Enable'. We require Version 4 Mode
- * here because some controllers (e.g sdhci-of-dwmshc) expect it.
- */
- if (host->version >= SDHCI_SPEC_410 && host->v4_mode &&
- (use_cmd12 || use_cmd23)) {
- *mode |= SDHCI_TRNS_AUTO_SEL;
-
- ctrl2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
- if (use_cmd23)
- ctrl2 |= SDHCI_CMD23_ENABLE;
- else
- ctrl2 &= ~SDHCI_CMD23_ENABLE;
- sdhci_writew(host, ctrl2, SDHCI_HOST_CONTROL2);
-
- return;
- }
-
- /*
- * If we are sending CMD23, CMD12 never gets sent
- * on successful completion (so no Auto-CMD12).
- */
- if (use_cmd12)
- *mode |= SDHCI_TRNS_AUTO_CMD12;
- else if (use_cmd23)
- *mode |= SDHCI_TRNS_AUTO_CMD23;
-}
-
-static void sdhci_set_transfer_mode(struct sdhci_host *host,
- struct mmc_command *cmd)
-{
- u16 mode = 0;
- struct mmc_data *data = cmd->data;
-
- if (data == NULL) {
- if (host->quirks2 &
- SDHCI_QUIRK2_CLEAR_TRANSFERMODE_REG_BEFORE_CMD) {
- /* must not clear SDHCI_TRANSFER_MODE when tuning */
- if (cmd->opcode != MMC_SEND_TUNING_BLOCK_HS200)
- sdhci_writew(host, 0x0, SDHCI_TRANSFER_MODE);
- } else {
- /* clear Auto CMD settings for no data CMDs */
- mode = sdhci_readw(host, SDHCI_TRANSFER_MODE);
- sdhci_writew(host, mode & ~(SDHCI_TRNS_AUTO_CMD12 |
- SDHCI_TRNS_AUTO_CMD23), SDHCI_TRANSFER_MODE);
- }
- return;
- }
-
- WARN_ON(!host->data);
-
- if (!(host->quirks2 & SDHCI_QUIRK2_SUPPORT_SINGLE))
- mode = SDHCI_TRNS_BLK_CNT_EN;
-
- if (mmc_op_multi(cmd->opcode) || data->blocks > 1) {
- mode = SDHCI_TRNS_BLK_CNT_EN | SDHCI_TRNS_MULTI;
- sdhci_auto_cmd_select(host, cmd, &mode);
- if (sdhci_auto_cmd23(host, cmd->mrq))
- sdhci_writel(host, cmd->mrq->sbc->arg, SDHCI_ARGUMENT2);
- }
-
- if (data->flags & MMC_DATA_READ)
- mode |= SDHCI_TRNS_READ;
- if (host->flags & SDHCI_REQ_USE_DMA)
- mode |= SDHCI_TRNS_DMA;
-
- sdhci_writew(host, mode, SDHCI_TRANSFER_MODE);
-}
-
-static bool sdhci_needs_reset(struct sdhci_host *host, struct mmc_request *mrq)
-{
- return (!(host->flags & SDHCI_DEVICE_DEAD) &&
- ((mrq->cmd && mrq->cmd->error) ||
- (mrq->sbc && mrq->sbc->error) ||
- (mrq->data && mrq->data->stop && mrq->data->stop->error) ||
- (host->quirks & SDHCI_QUIRK_RESET_AFTER_REQUEST)));
-}
-
-static void sdhci_set_mrq_done(struct sdhci_host *host, struct mmc_request *mrq)
-{
- int i;
-
- for (i = 0; i < SDHCI_MAX_MRQS; i++) {
- if (host->mrqs_done[i] == mrq) {
- WARN_ON(1);
- return;
- }
- }
-
- for (i = 0; i < SDHCI_MAX_MRQS; i++) {
- if (!host->mrqs_done[i]) {
- host->mrqs_done[i] = mrq;
- break;
- }
- }
-
- WARN_ON(i >= SDHCI_MAX_MRQS);
-}
-
-static void __sdhci_finish_mrq(struct sdhci_host *host, struct mmc_request *mrq)
-{
- if (host->cmd && host->cmd->mrq == mrq)
- host->cmd = NULL;
-
- if (host->data_cmd && host->data_cmd->mrq == mrq)
- host->data_cmd = NULL;
-
- if (host->deferred_cmd && host->deferred_cmd->mrq == mrq)
- host->deferred_cmd = NULL;
-
- if (host->data && host->data->mrq == mrq)
- host->data = NULL;
-
- if (sdhci_needs_reset(host, mrq))
- host->pending_reset = true;
-
- sdhci_set_mrq_done(host, mrq);
-
- sdhci_del_timer(host, mrq);
-
- if (!sdhci_has_requests(host))
- sdhci_led_deactivate(host);
-}
-
-static void sdhci_finish_mrq(struct sdhci_host *host, struct mmc_request *mrq)
-{
- __sdhci_finish_mrq(host, mrq);
-
- queue_work(host->complete_wq, &host->complete_work);
-}
-
-static void __sdhci_finish_data(struct sdhci_host *host, bool sw_data_timeout)
-{
- struct mmc_command *data_cmd = host->data_cmd;
- struct mmc_data *data = host->data;
-
- host->data = NULL;
- host->data_cmd = NULL;
-
- /*
- * The controller needs a reset of internal state machines upon error
- * conditions.
- */
- if (data->error) {
- if (!host->cmd || host->cmd == data_cmd)
- sdhci_do_reset(host, SDHCI_RESET_CMD);
- sdhci_do_reset(host, SDHCI_RESET_DATA);
- }
-
- if ((host->flags & (SDHCI_REQ_USE_DMA | SDHCI_USE_ADMA)) ==
- (SDHCI_REQ_USE_DMA | SDHCI_USE_ADMA))
- sdhci_adma_table_post(host, data);
-
- /*
- * The specification states that the block count register must
- * be updated, but it does not specify at what point in the
- * data flow. That makes the register entirely useless to read
- * back so we have to assume that nothing made it to the card
- * in the event of an error.
- */
- if (data->error)
- data->bytes_xfered = 0;
- else
- data->bytes_xfered = data->blksz * data->blocks;
-
- /*
- * Need to send CMD12 if -
- * a) open-ended multiblock transfer not using auto CMD12 (no CMD23)
- * b) error in multiblock transfer
- */
- if (data->stop &&
- ((!data->mrq->sbc && !sdhci_auto_cmd12(host, data->mrq)) ||
- data->error)) {
- /*
- * 'cap_cmd_during_tfr' request must not use the command line
- * after mmc_command_done() has been called. It is upper layer's
- * responsibility to send the stop command if required.
- */
- if (data->mrq->cap_cmd_during_tfr) {
- __sdhci_finish_mrq(host, data->mrq);
- } else {
- /* Avoid triggering warning in sdhci_send_command() */
- host->cmd = NULL;
- if (!sdhci_send_command(host, data->stop)) {
- if (sw_data_timeout) {
- /*
- * This is anyway a sw data timeout, so
- * give up now.
- */
- data->stop->error = -EIO;
- __sdhci_finish_mrq(host, data->mrq);
- } else {
- WARN_ON(host->deferred_cmd);
- host->deferred_cmd = data->stop;
- }
- }
- }
- } else {
- __sdhci_finish_mrq(host, data->mrq);
- }
-}
-
-static void sdhci_finish_data(struct sdhci_host *host)
-{
- __sdhci_finish_data(host, false);
-}
-
-static bool sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
-{
- int flags;
- u32 mask;
- unsigned long timeout;
-
- WARN_ON(host->cmd);
-
- /* Initially, a command has no error */
- cmd->error = 0;
-
- if ((host->quirks2 & SDHCI_QUIRK2_STOP_WITH_TC) &&
- cmd->opcode == MMC_STOP_TRANSMISSION)
- cmd->flags |= MMC_RSP_BUSY;
-
- mask = SDHCI_CMD_INHIBIT;
- if (sdhci_data_line_cmd(cmd))
- mask |= SDHCI_DATA_INHIBIT;
-
- /* We shouldn't wait for data inihibit for stop commands, even
- though they might use busy signaling */
- if (cmd->mrq->data && (cmd == cmd->mrq->data->stop))
- mask &= ~SDHCI_DATA_INHIBIT;
-
- if (sdhci_readl(host, SDHCI_PRESENT_STATE) & mask)
- return false;
-
- host->cmd = cmd;
- host->data_timeout = 0;
- if (sdhci_data_line_cmd(cmd)) {
- WARN_ON(host->data_cmd);
- host->data_cmd = cmd;
- sdhci_set_timeout(host, cmd);
- }
-
- if (cmd->data) {
- if (host->use_external_dma)
- sdhci_external_dma_prepare_data(host, cmd);
- else
- sdhci_prepare_data(host, cmd);
- }
-
- sdhci_writel(host, cmd->arg, SDHCI_ARGUMENT);
-
- sdhci_set_transfer_mode(host, cmd);
-
- if ((cmd->flags & MMC_RSP_136) && (cmd->flags & MMC_RSP_BUSY)) {
- WARN_ONCE(1, "Unsupported response type!\n");
- /*
- * This does not happen in practice because 136-bit response
- * commands never have busy waiting, so rather than complicate
- * the error path, just remove busy waiting and continue.
- */
- cmd->flags &= ~MMC_RSP_BUSY;
- }
-
- if (!(cmd->flags & MMC_RSP_PRESENT))
- flags = SDHCI_CMD_RESP_NONE;
- else if (cmd->flags & MMC_RSP_136)
- flags = SDHCI_CMD_RESP_LONG;
- else if (cmd->flags & MMC_RSP_BUSY)
- flags = SDHCI_CMD_RESP_SHORT_BUSY;
- else
- flags = SDHCI_CMD_RESP_SHORT;
-
- if (cmd->flags & MMC_RSP_CRC)
- flags |= SDHCI_CMD_CRC;
- if (cmd->flags & MMC_RSP_OPCODE)
- flags |= SDHCI_CMD_INDEX;
-
- /* CMD19 is special in that the Data Present Select should be set */
- if (cmd->data || cmd->opcode == MMC_SEND_TUNING_BLOCK ||
- cmd->opcode == MMC_SEND_TUNING_BLOCK_HS200)
- flags |= SDHCI_CMD_DATA;
-
- timeout = jiffies;
- if (host->data_timeout)
- timeout += nsecs_to_jiffies(host->data_timeout);
- else if (!cmd->data && cmd->busy_timeout > 9000)
- timeout += DIV_ROUND_UP(cmd->busy_timeout, 1000) * HZ + HZ;
- else
- timeout += 10 * HZ;
- sdhci_mod_timer(host, cmd->mrq, timeout);
-
- if (host->use_external_dma)
- sdhci_external_dma_pre_transfer(host, cmd);
-
- sdhci_writew(host, SDHCI_MAKE_CMD(cmd->opcode, flags), SDHCI_COMMAND);
-
- return true;
-}
-
-static bool sdhci_present_error(struct sdhci_host *host,
- struct mmc_command *cmd, bool present)
-{
- if (!present || host->flags & SDHCI_DEVICE_DEAD) {
- cmd->error = -ENOMEDIUM;
- return true;
- }
-
- return false;
-}
-
-static bool sdhci_send_command_retry(struct sdhci_host *host,
- struct mmc_command *cmd,
- unsigned long flags)
- __releases(host->lock)
- __acquires(host->lock)
-{
- struct mmc_command *deferred_cmd = host->deferred_cmd;
- int timeout = 10; /* Approx. 10 ms */
- bool present;
-
- while (!sdhci_send_command(host, cmd)) {
- if (!timeout--) {
- pr_err("%s: Controller never released inhibit bit(s).\n",
- mmc_hostname(host->mmc));
- sdhci_err_stats_inc(host, CTRL_TIMEOUT);
- sdhci_dumpregs(host);
- cmd->error = -EIO;
- return false;
- }
-
- spin_unlock_irqrestore(&host->lock, flags);
-
- usleep_range(1000, 1250);
-
- present = host->mmc->ops->get_cd(host->mmc);
-
- spin_lock_irqsave(&host->lock, flags);
-
- /* A deferred command might disappear, handle that */
- if (cmd == deferred_cmd && cmd != host->deferred_cmd)
- return true;
-
- if (sdhci_present_error(host, cmd, present))
- return false;
- }
-
- if (cmd == host->deferred_cmd)
- host->deferred_cmd = NULL;
-
- return true;
-}
-
-static void sdhci_read_rsp_136(struct sdhci_host *host, struct mmc_command *cmd)
-{
- int i, reg;
-
- for (i = 0; i < 4; i++) {
- reg = SDHCI_RESPONSE + (3 - i) * 4;
- cmd->resp[i] = sdhci_readl(host, reg);
- }
-
- if (host->quirks2 & SDHCI_QUIRK2_RSP_136_HAS_CRC)
- return;
-
- /* CRC is stripped so we need to do some shifting */
- for (i = 0; i < 4; i++) {
- cmd->resp[i] <<= 8;
- if (i != 3)
- cmd->resp[i] |= cmd->resp[i + 1] >> 24;
- }
-}
-
-static void sdhci_finish_command(struct sdhci_host *host)
-{
- struct mmc_command *cmd = host->cmd;
-
- host->cmd = NULL;
-
- if (cmd->flags & MMC_RSP_PRESENT) {
- if (cmd->flags & MMC_RSP_136) {
- sdhci_read_rsp_136(host, cmd);
- } else {
- cmd->resp[0] = sdhci_readl(host, SDHCI_RESPONSE);
- }
- }
-
- if (cmd->mrq->cap_cmd_during_tfr && cmd == cmd->mrq->cmd)
- mmc_command_done(host->mmc, cmd->mrq);
-
- /*
- * The host can send and interrupt when the busy state has
- * ended, allowing us to wait without wasting CPU cycles.
- * The busy signal uses DAT0 so this is similar to waiting
- * for data to complete.
- *
- * Note: The 1.0 specification is a bit ambiguous about this
- * feature so there might be some problems with older
- * controllers.
- */
- if (cmd->flags & MMC_RSP_BUSY) {
- if (cmd->data) {
- DBG("Cannot wait for busy signal when also doing a data transfer");
- } else if (!(host->quirks & SDHCI_QUIRK_NO_BUSY_IRQ) &&
- cmd == host->data_cmd) {
- /* Command complete before busy is ended */
- return;
- }
- }
-
- /* Finished CMD23, now send actual command. */
- if (cmd == cmd->mrq->sbc) {
- if (!sdhci_send_command(host, cmd->mrq->cmd)) {
- WARN_ON(host->deferred_cmd);
- host->deferred_cmd = cmd->mrq->cmd;
- }
- } else {
-
- /* Processed actual command. */
- if (host->data && host->data_early)
- sdhci_finish_data(host);
-
- if (!cmd->data)
- __sdhci_finish_mrq(host, cmd->mrq);
- }
-}
-
-static u16 sdhci_get_preset_value(struct sdhci_host *host)
-{
- u16 preset = 0;
-
- switch (host->timing) {
- case MMC_TIMING_MMC_HS:
- case MMC_TIMING_SD_HS:
- preset = sdhci_readw(host, SDHCI_PRESET_FOR_HIGH_SPEED);
- break;
- case MMC_TIMING_UHS_SDR12:
- preset = sdhci_readw(host, SDHCI_PRESET_FOR_SDR12);
- break;
- case MMC_TIMING_UHS_SDR25:
- preset = sdhci_readw(host, SDHCI_PRESET_FOR_SDR25);
- break;
- case MMC_TIMING_UHS_SDR50:
- preset = sdhci_readw(host, SDHCI_PRESET_FOR_SDR50);
- break;
- case MMC_TIMING_UHS_SDR104:
- case MMC_TIMING_MMC_HS200:
- preset = sdhci_readw(host, SDHCI_PRESET_FOR_SDR104);
- break;
- case MMC_TIMING_UHS_DDR50:
- case MMC_TIMING_MMC_DDR52:
- preset = sdhci_readw(host, SDHCI_PRESET_FOR_DDR50);
- break;
- case MMC_TIMING_MMC_HS400:
- preset = sdhci_readw(host, SDHCI_PRESET_FOR_HS400);
- break;
- default:
- pr_warn("%s: Invalid UHS-I mode selected\n",
- mmc_hostname(host->mmc));
- preset = sdhci_readw(host, SDHCI_PRESET_FOR_SDR12);
- break;
- }
- return preset;
-}
-
-u16 sdhci_calc_clk(struct sdhci_host *host, unsigned int clock,
- unsigned int *actual_clock)
-{
- int div = 0; /* Initialized for compiler warning */
- int real_div = div, clk_mul = 1;
- u16 clk = 0;
- bool switch_base_clk = false;
-
- if (host->version >= SDHCI_SPEC_300) {
- if (host->preset_enabled) {
- u16 pre_val;
-
- clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
- pre_val = sdhci_get_preset_value(host);
- div = FIELD_GET(SDHCI_PRESET_SDCLK_FREQ_MASK, pre_val);
- if (host->clk_mul &&
- (pre_val & SDHCI_PRESET_CLKGEN_SEL)) {
- clk = SDHCI_PROG_CLOCK_MODE;
- real_div = div + 1;
- clk_mul = host->clk_mul;
- } else {
- real_div = max_t(int, 1, div << 1);
- }
- goto clock_set;
- }
-
- /*
- * Check if the Host Controller supports Programmable Clock
- * Mode.
- */
- if (host->clk_mul) {
- for (div = 1; div <= 1024; div++) {
- if ((host->max_clk * host->clk_mul / div)
- <= clock)
- break;
- }
- if ((host->max_clk * host->clk_mul / div) <= clock) {
- /*
- * Set Programmable Clock Mode in the Clock
- * Control register.
- */
- clk = SDHCI_PROG_CLOCK_MODE;
- real_div = div;
- clk_mul = host->clk_mul;
- div--;
- } else {
- /*
- * Divisor can be too small to reach clock
- * speed requirement. Then use the base clock.
- */
- switch_base_clk = true;
- }
- }
-
- if (!host->clk_mul || switch_base_clk) {
- /* Version 3.00 divisors must be a multiple of 2. */
- if (host->max_clk <= clock)
- div = 1;
- else {
- for (div = 2; div < SDHCI_MAX_DIV_SPEC_300;
- div += 2) {
- if ((host->max_clk / div) <= clock)
- break;
- }
- }
- real_div = div;
- div >>= 1;
- if ((host->quirks2 & SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN)
- && !div && host->max_clk <= 25000000)
- div = 1;
- }
- } else {
- /* Version 2.00 divisors must be a power of 2. */
- for (div = 1; div < SDHCI_MAX_DIV_SPEC_200; div *= 2) {
- if ((host->max_clk / div) <= clock)
- break;
- }
- real_div = div;
- div >>= 1;
- }
-
-clock_set:
- if (real_div)
- *actual_clock = (host->max_clk * clk_mul) / real_div;
- clk |= (div & SDHCI_DIV_MASK) << SDHCI_DIVIDER_SHIFT;
- clk |= ((div & SDHCI_DIV_HI_MASK) >> SDHCI_DIV_MASK_LEN)
- << SDHCI_DIVIDER_HI_SHIFT;
-
- return clk;
-}
-EXPORT_SYMBOL_GPL(sdhci_calc_clk);
-
-void sdhci_enable_clk(struct sdhci_host *host, u16 clk)
-{
- ktime_t timeout;
-
- clk |= SDHCI_CLOCK_INT_EN;
- sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
-
- /* Wait max 150 ms */
- timeout = ktime_add_ms(ktime_get(), 150);
- while (1) {
- bool timedout = ktime_after(ktime_get(), timeout);
-
- clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
- if (clk & SDHCI_CLOCK_INT_STABLE)
- break;
- if (timedout) {
- pr_err("%s: Internal clock never stabilised.\n",
- mmc_hostname(host->mmc));
- sdhci_err_stats_inc(host, CTRL_TIMEOUT);
- sdhci_dumpregs(host);
- return;
- }
- udelay(10);
- }
-
- if (host->version >= SDHCI_SPEC_410 && host->v4_mode) {
- clk |= SDHCI_CLOCK_PLL_EN;
- clk &= ~SDHCI_CLOCK_INT_STABLE;
- sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
-
- /* Wait max 150 ms */
- timeout = ktime_add_ms(ktime_get(), 150);
- while (1) {
- bool timedout = ktime_after(ktime_get(), timeout);
-
- clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
- if (clk & SDHCI_CLOCK_INT_STABLE)
- break;
- if (timedout) {
- pr_err("%s: PLL clock never stabilised.\n",
- mmc_hostname(host->mmc));
- sdhci_err_stats_inc(host, CTRL_TIMEOUT);
- sdhci_dumpregs(host);
- return;
- }
- udelay(10);
- }
- }
-
- clk |= SDHCI_CLOCK_CARD_EN;
- sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
-}
-EXPORT_SYMBOL_GPL(sdhci_enable_clk);
-
-void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
-{
- u16 clk;
-
- host->mmc->actual_clock = 0;
-
- sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
-
- if (clock == 0)
- return;
-
- clk = sdhci_calc_clk(host, clock, &host->mmc->actual_clock);
- sdhci_enable_clk(host, clk);
-}
-EXPORT_SYMBOL_GPL(sdhci_set_clock);
-
-static void sdhci_set_power_reg(struct sdhci_host *host, unsigned char mode,
- unsigned short vdd)
-{
- struct mmc_host *mmc = host->mmc;
-
- mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, vdd);
-
- if (mode != MMC_POWER_OFF)
- sdhci_writeb(host, SDHCI_POWER_ON, SDHCI_POWER_CONTROL);
- else
- sdhci_writeb(host, 0, SDHCI_POWER_CONTROL);
-}
-
-void sdhci_set_power_noreg(struct sdhci_host *host, unsigned char mode,
- unsigned short vdd)
-{
- u8 pwr = 0;
-
- if (mode != MMC_POWER_OFF) {
- switch (1 << vdd) {
- case MMC_VDD_165_195:
- /*
- * Without a regulator, SDHCI does not support 2.0v
- * so we only get here if the driver deliberately
- * added the 2.0v range to ocr_avail. Map it to 1.8v
- * for the purpose of turning on the power.
- */
- case MMC_VDD_20_21:
- pwr = SDHCI_POWER_180;
- break;
- case MMC_VDD_29_30:
- case MMC_VDD_30_31:
- pwr = SDHCI_POWER_300;
- break;
- case MMC_VDD_32_33:
- case MMC_VDD_33_34:
- /*
- * 3.4 ~ 3.6V are valid only for those platforms where it's
- * known that the voltage range is supported by hardware.
- */
- case MMC_VDD_34_35:
- case MMC_VDD_35_36:
- pwr = SDHCI_POWER_330;
- break;
- default:
- WARN(1, "%s: Invalid vdd %#x\n",
- mmc_hostname(host->mmc), vdd);
- break;
- }
- }
-
- if (host->pwr == pwr)
- return;
-
- host->pwr = pwr;
-
- if (pwr == 0) {
- sdhci_writeb(host, 0, SDHCI_POWER_CONTROL);
- if (host->quirks2 & SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON)
- sdhci_runtime_pm_bus_off(host);
- } else {
- /*
- * Spec says that we should clear the power reg before setting
- * a new value. Some controllers don't seem to like this though.
- */
- if (!(host->quirks & SDHCI_QUIRK_SINGLE_POWER_WRITE))
- sdhci_writeb(host, 0, SDHCI_POWER_CONTROL);
-
- /*
- * At least the Marvell CaFe chip gets confused if we set the
- * voltage and set turn on power at the same time, so set the
- * voltage first.
- */
- if (host->quirks & SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER)
- sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL);
-
- pwr |= SDHCI_POWER_ON;
-
- sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL);
-
- if (host->quirks2 & SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON)
- sdhci_runtime_pm_bus_on(host);
-
- /*
- * Some controllers need an extra 10ms delay of 10ms before
- * they can apply clock after applying power
- */
- if (host->quirks & SDHCI_QUIRK_DELAY_AFTER_POWER)
- mdelay(10);
- }
-}
-EXPORT_SYMBOL_GPL(sdhci_set_power_noreg);
-
-void sdhci_set_power(struct sdhci_host *host, unsigned char mode,
- unsigned short vdd)
-{
- if (IS_ERR(host->mmc->supply.vmmc))
- sdhci_set_power_noreg(host, mode, vdd);
- else
- sdhci_set_power_reg(host, mode, vdd);
-}
-EXPORT_SYMBOL_GPL(sdhci_set_power);
-
-/*
- * Some controllers need to configure a valid bus voltage on their power
- * register regardless of whether an external regulator is taking care of power
- * supply. This helper function takes care of it if set as the controller's
- * sdhci_ops.set_power callback.
- */
-void sdhci_set_power_and_bus_voltage(struct sdhci_host *host,
- unsigned char mode,
- unsigned short vdd)
-{
- if (!IS_ERR(host->mmc->supply.vmmc)) {
- struct mmc_host *mmc = host->mmc;
-
- mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, vdd);
- }
- sdhci_set_power_noreg(host, mode, vdd);
-}
-EXPORT_SYMBOL_GPL(sdhci_set_power_and_bus_voltage);
-
-/*****************************************************************************\
- * *
- * MMC callbacks *
- * *
-\*****************************************************************************/
-
-void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
-{
- struct sdhci_host *host = mmc_priv(mmc);
- struct mmc_command *cmd;
- unsigned long flags;
- bool present;
-
- /* Firstly check card presence */
- present = mmc->ops->get_cd(mmc);
-
- spin_lock_irqsave(&host->lock, flags);
-
- sdhci_led_activate(host);
-
- if (sdhci_present_error(host, mrq->cmd, present))
- goto out_finish;
-
- cmd = sdhci_manual_cmd23(host, mrq) ? mrq->sbc : mrq->cmd;
-
- if (!sdhci_send_command_retry(host, cmd, flags))
- goto out_finish;
-
- spin_unlock_irqrestore(&host->lock, flags);
-
- return;
-
-out_finish:
- sdhci_finish_mrq(host, mrq);
- spin_unlock_irqrestore(&host->lock, flags);
-}
-EXPORT_SYMBOL_GPL(sdhci_request);
-
-int sdhci_request_atomic(struct mmc_host *mmc, struct mmc_request *mrq)
-{
- struct sdhci_host *host = mmc_priv(mmc);
- struct mmc_command *cmd;
- unsigned long flags;
- int ret = 0;
-
- spin_lock_irqsave(&host->lock, flags);
-
- if (sdhci_present_error(host, mrq->cmd, true)) {
- sdhci_finish_mrq(host, mrq);
- goto out_finish;
- }
-
- cmd = sdhci_manual_cmd23(host, mrq) ? mrq->sbc : mrq->cmd;
-
- /*
- * The HSQ may send a command in interrupt context without polling
- * the busy signaling, which means we should return BUSY if controller
- * has not released inhibit bits to allow HSQ trying to send request
- * again in non-atomic context. So we should not finish this request
- * here.
- */
- if (!sdhci_send_command(host, cmd))
- ret = -EBUSY;
- else
- sdhci_led_activate(host);
-
-out_finish:
- spin_unlock_irqrestore(&host->lock, flags);
- return ret;
-}
-EXPORT_SYMBOL_GPL(sdhci_request_atomic);
-
-void sdhci_set_bus_width(struct sdhci_host *host, int width)
-{
- u8 ctrl;
-
- ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
- if (width == MMC_BUS_WIDTH_8) {
- ctrl &= ~SDHCI_CTRL_4BITBUS;
- ctrl |= SDHCI_CTRL_8BITBUS;
- } else {
- if (host->mmc->caps & MMC_CAP_8_BIT_DATA)
- ctrl &= ~SDHCI_CTRL_8BITBUS;
- if (width == MMC_BUS_WIDTH_4)
- ctrl |= SDHCI_CTRL_4BITBUS;
- else
- ctrl &= ~SDHCI_CTRL_4BITBUS;
- }
- sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
-}
-EXPORT_SYMBOL_GPL(sdhci_set_bus_width);
-
-void sdhci_set_uhs_signaling(struct sdhci_host *host, unsigned timing)
-{
- u16 ctrl_2;
-
- ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
- /* Select Bus Speed Mode for host */
- ctrl_2 &= ~SDHCI_CTRL_UHS_MASK;
- if ((timing == MMC_TIMING_MMC_HS200) ||
- (timing == MMC_TIMING_UHS_SDR104))
- ctrl_2 |= SDHCI_CTRL_UHS_SDR104;
- else if (timing == MMC_TIMING_UHS_SDR12)
- ctrl_2 |= SDHCI_CTRL_UHS_SDR12;
- else if (timing == MMC_TIMING_UHS_SDR25)
- ctrl_2 |= SDHCI_CTRL_UHS_SDR25;
- else if (timing == MMC_TIMING_UHS_SDR50)
- ctrl_2 |= SDHCI_CTRL_UHS_SDR50;
- else if ((timing == MMC_TIMING_UHS_DDR50) ||
- (timing == MMC_TIMING_MMC_DDR52))
- ctrl_2 |= SDHCI_CTRL_UHS_DDR50;
- else if (timing == MMC_TIMING_MMC_HS400)
- ctrl_2 |= SDHCI_CTRL_HS400; /* Non-standard */
- sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
-}
-EXPORT_SYMBOL_GPL(sdhci_set_uhs_signaling);
-
-void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
-{
- struct sdhci_host *host = mmc_priv(mmc);
- u8 ctrl;
-
- if (ios->power_mode == MMC_POWER_UNDEFINED)
- return;
-
- if (host->flags & SDHCI_DEVICE_DEAD) {
- if (!IS_ERR(mmc->supply.vmmc) &&
- ios->power_mode == MMC_POWER_OFF)
- mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0);
- return;
- }
-
- /*
- * Reset the chip on each power off.
- * Should clear out any weird states.
- */
- if (ios->power_mode == MMC_POWER_OFF) {
- sdhci_writel(host, 0, SDHCI_SIGNAL_ENABLE);
- sdhci_reinit(host);
- }
-
- if (host->version >= SDHCI_SPEC_300 &&
- (ios->power_mode == MMC_POWER_UP) &&
- !(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN))
- sdhci_enable_preset_value(host, false);
-
- if (!ios->clock || ios->clock != host->clock) {
- host->ops->set_clock(host, ios->clock);
- host->clock = ios->clock;
-
- if (host->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK &&
- host->clock) {
- host->timeout_clk = mmc->actual_clock ?
- mmc->actual_clock / 1000 :
- host->clock / 1000;
- mmc->max_busy_timeout =
- host->ops->get_max_timeout_count ?
- host->ops->get_max_timeout_count(host) :
- 1 << 27;
- mmc->max_busy_timeout /= host->timeout_clk;
- }
- }
-
- if (host->ops->set_power)
- host->ops->set_power(host, ios->power_mode, ios->vdd);
- else
- sdhci_set_power(host, ios->power_mode, ios->vdd);
-
- if (host->ops->platform_send_init_74_clocks)
- host->ops->platform_send_init_74_clocks(host, ios->power_mode);
-
- host->ops->set_bus_width(host, ios->bus_width);
-
- ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
-
- if (!(host->quirks & SDHCI_QUIRK_NO_HISPD_BIT)) {
- if (ios->timing == MMC_TIMING_SD_HS ||
- ios->timing == MMC_TIMING_MMC_HS ||
- ios->timing == MMC_TIMING_MMC_HS400 ||
- ios->timing == MMC_TIMING_MMC_HS200 ||
- ios->timing == MMC_TIMING_MMC_DDR52 ||
- ios->timing == MMC_TIMING_UHS_SDR50 ||
- ios->timing == MMC_TIMING_UHS_SDR104 ||
- ios->timing == MMC_TIMING_UHS_DDR50 ||
- ios->timing == MMC_TIMING_UHS_SDR25)
- ctrl |= SDHCI_CTRL_HISPD;
- else
- ctrl &= ~SDHCI_CTRL_HISPD;
- }
-
- if (host->version >= SDHCI_SPEC_300) {
- u16 clk, ctrl_2;
-
- if (!host->preset_enabled) {
- sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
- /*
- * We only need to set Driver Strength if the
- * preset value enable is not set.
- */
- ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
- ctrl_2 &= ~SDHCI_CTRL_DRV_TYPE_MASK;
- if (ios->drv_type == MMC_SET_DRIVER_TYPE_A)
- ctrl_2 |= SDHCI_CTRL_DRV_TYPE_A;
- else if (ios->drv_type == MMC_SET_DRIVER_TYPE_B)
- ctrl_2 |= SDHCI_CTRL_DRV_TYPE_B;
- else if (ios->drv_type == MMC_SET_DRIVER_TYPE_C)
- ctrl_2 |= SDHCI_CTRL_DRV_TYPE_C;
- else if (ios->drv_type == MMC_SET_DRIVER_TYPE_D)
- ctrl_2 |= SDHCI_CTRL_DRV_TYPE_D;
- else {
- pr_warn("%s: invalid driver type, default to driver type B\n",
- mmc_hostname(mmc));
- ctrl_2 |= SDHCI_CTRL_DRV_TYPE_B;
- }
-
- sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
- } else {
- /*
- * According to SDHC Spec v3.00, if the Preset Value
- * Enable in the Host Control 2 register is set, we
- * need to reset SD Clock Enable before changing High
- * Speed Enable to avoid generating clock gliches.
- */
-
- /* Reset SD Clock Enable */
- clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
- clk &= ~SDHCI_CLOCK_CARD_EN;
- sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
-
- sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
-
- /* Re-enable SD Clock */
- host->ops->set_clock(host, host->clock);
- }
-
- /* Reset SD Clock Enable */
- clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
- clk &= ~SDHCI_CLOCK_CARD_EN;
- sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
-
- host->ops->set_uhs_signaling(host, ios->timing);
- host->timing = ios->timing;
-
- if (!(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN) &&
- ((ios->timing == MMC_TIMING_UHS_SDR12) ||
- (ios->timing == MMC_TIMING_UHS_SDR25) ||
- (ios->timing == MMC_TIMING_UHS_SDR50) ||
- (ios->timing == MMC_TIMING_UHS_SDR104) ||
- (ios->timing == MMC_TIMING_UHS_DDR50) ||
- (ios->timing == MMC_TIMING_MMC_DDR52))) {
- u16 preset;
-
- sdhci_enable_preset_value(host, true);
- preset = sdhci_get_preset_value(host);
- ios->drv_type = FIELD_GET(SDHCI_PRESET_DRV_MASK,
- preset);
- }
-
- /* Re-enable SD Clock */
- host->ops->set_clock(host, host->clock);
- } else
- sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
-
- /*
- * Some (ENE) controllers go apeshit on some ios operation,
- * signalling timeout and CRC errors even on CMD0. Resetting
- * it on each ios seems to solve the problem.
- */
- if (host->quirks & SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS)
- sdhci_do_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
-}
-EXPORT_SYMBOL_GPL(sdhci_set_ios);
-
-static int sdhci_get_cd(struct mmc_host *mmc)
-{
- struct sdhci_host *host = mmc_priv(mmc);
- int gpio_cd = mmc_gpio_get_cd(mmc);
-
- if (host->flags & SDHCI_DEVICE_DEAD)
- return 0;
-
- /* If nonremovable, assume that the card is always present. */
- if (!mmc_card_is_removable(mmc))
- return 1;
-
- /*
- * Try slot gpio detect, if defined it take precedence
- * over build in controller functionality
- */
- if (gpio_cd >= 0)
- return !!gpio_cd;
-
- /* If polling, assume that the card is always present. */
- if (host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION)
- return 1;
-
- /* Host native card detect */
- return !!(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT);
-}
-
-int sdhci_get_cd_nogpio(struct mmc_host *mmc)
-{
- struct sdhci_host *host = mmc_priv(mmc);
- unsigned long flags;
- int ret = 0;
-
- spin_lock_irqsave(&host->lock, flags);
-
- if (host->flags & SDHCI_DEVICE_DEAD)
- goto out;
-
- ret = !!(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT);
-out:
- spin_unlock_irqrestore(&host->lock, flags);
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(sdhci_get_cd_nogpio);
-
-static int sdhci_check_ro(struct sdhci_host *host)
-{
- unsigned long flags;
- int is_readonly;
-
- spin_lock_irqsave(&host->lock, flags);
-
- if (host->flags & SDHCI_DEVICE_DEAD)
- is_readonly = 0;
- else if (host->ops->get_ro)
- is_readonly = host->ops->get_ro(host);
- else if (mmc_can_gpio_ro(host->mmc))
- is_readonly = mmc_gpio_get_ro(host->mmc);
- else
- is_readonly = !(sdhci_readl(host, SDHCI_PRESENT_STATE)
- & SDHCI_WRITE_PROTECT);
-
- spin_unlock_irqrestore(&host->lock, flags);
-
- /* This quirk needs to be replaced by a callback-function later */
- return host->quirks & SDHCI_QUIRK_INVERTED_WRITE_PROTECT ?
- !is_readonly : is_readonly;
-}
-
-#define SAMPLE_COUNT 5
-
-static int sdhci_get_ro(struct mmc_host *mmc)
-{
- struct sdhci_host *host = mmc_priv(mmc);
- int i, ro_count;
-
- if (!(host->quirks & SDHCI_QUIRK_UNSTABLE_RO_DETECT))
- return sdhci_check_ro(host);
-
- ro_count = 0;
- for (i = 0; i < SAMPLE_COUNT; i++) {
- if (sdhci_check_ro(host)) {
- if (++ro_count > SAMPLE_COUNT / 2)
- return 1;
- }
- msleep(30);
- }
- return 0;
-}
-
-static void sdhci_hw_reset(struct mmc_host *mmc)
-{
- struct sdhci_host *host = mmc_priv(mmc);
-
- if (host->ops && host->ops->hw_reset)
- host->ops->hw_reset(host);
-}
-
-static void sdhci_enable_sdio_irq_nolock(struct sdhci_host *host, int enable)
-{
- if (!(host->flags & SDHCI_DEVICE_DEAD)) {
- if (enable)
- host->ier |= SDHCI_INT_CARD_INT;
- else
- host->ier &= ~SDHCI_INT_CARD_INT;
-
- sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
- sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
- }
-}
-
-void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable)
-{
- struct sdhci_host *host = mmc_priv(mmc);
- unsigned long flags;
-
- if (enable)
- pm_runtime_get_noresume(mmc_dev(mmc));
-
- spin_lock_irqsave(&host->lock, flags);
- sdhci_enable_sdio_irq_nolock(host, enable);
- spin_unlock_irqrestore(&host->lock, flags);
-
- if (!enable)
- pm_runtime_put_noidle(mmc_dev(mmc));
-}
-EXPORT_SYMBOL_GPL(sdhci_enable_sdio_irq);
-
-static void sdhci_ack_sdio_irq(struct mmc_host *mmc)
-{
- struct sdhci_host *host = mmc_priv(mmc);
- unsigned long flags;
-
- spin_lock_irqsave(&host->lock, flags);
- sdhci_enable_sdio_irq_nolock(host, true);
- spin_unlock_irqrestore(&host->lock, flags);
-}
-
-int sdhci_start_signal_voltage_switch(struct mmc_host *mmc,
- struct mmc_ios *ios)
-{
- struct sdhci_host *host = mmc_priv(mmc);
- u16 ctrl;
- int ret;
-
- /*
- * Signal Voltage Switching is only applicable for Host Controllers
- * v3.00 and above.
- */
- if (host->version < SDHCI_SPEC_300)
- return 0;
-
- ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
-
- switch (ios->signal_voltage) {
- case MMC_SIGNAL_VOLTAGE_330:
- if (!(host->flags & SDHCI_SIGNALING_330))
- return -EINVAL;
- /* Set 1.8V Signal Enable in the Host Control2 register to 0 */
- ctrl &= ~SDHCI_CTRL_VDD_180;
- sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
-
- if (!IS_ERR(mmc->supply.vqmmc)) {
- ret = mmc_regulator_set_vqmmc(mmc, ios);
- if (ret < 0) {
- pr_warn("%s: Switching to 3.3V signalling voltage failed\n",
- mmc_hostname(mmc));
- return -EIO;
- }
- }
- /* Wait for 5ms */
- usleep_range(5000, 5500);
-
- /* 3.3V regulator output should be stable within 5 ms */
- ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
- if (!(ctrl & SDHCI_CTRL_VDD_180))
- return 0;
-
- pr_warn("%s: 3.3V regulator output did not become stable\n",
- mmc_hostname(mmc));
-
- return -EAGAIN;
- case MMC_SIGNAL_VOLTAGE_180:
- if (!(host->flags & SDHCI_SIGNALING_180))
- return -EINVAL;
- if (!IS_ERR(mmc->supply.vqmmc)) {
- ret = mmc_regulator_set_vqmmc(mmc, ios);
- if (ret < 0) {
- pr_warn("%s: Switching to 1.8V signalling voltage failed\n",
- mmc_hostname(mmc));
- return -EIO;
- }
- }
-
- /*
- * Enable 1.8V Signal Enable in the Host Control2
- * register
- */
- ctrl |= SDHCI_CTRL_VDD_180;
- sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
-
- /* Some controller need to do more when switching */
- if (host->ops->voltage_switch)
- host->ops->voltage_switch(host);
-
- /* 1.8V regulator output should be stable within 5 ms */
- ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
- if (ctrl & SDHCI_CTRL_VDD_180)
- return 0;
-
- pr_warn("%s: 1.8V regulator output did not become stable\n",
- mmc_hostname(mmc));
-
- return -EAGAIN;
- case MMC_SIGNAL_VOLTAGE_120:
- if (!(host->flags & SDHCI_SIGNALING_120))
- return -EINVAL;
- if (!IS_ERR(mmc->supply.vqmmc)) {
- ret = mmc_regulator_set_vqmmc(mmc, ios);
- if (ret < 0) {
- pr_warn("%s: Switching to 1.2V signalling voltage failed\n",
- mmc_hostname(mmc));
- return -EIO;
- }
- }
- return 0;
- default:
- /* No signal voltage switch required */
- return 0;
- }
-}
-EXPORT_SYMBOL_GPL(sdhci_start_signal_voltage_switch);
-
-static int sdhci_card_busy(struct mmc_host *mmc)
-{
- struct sdhci_host *host = mmc_priv(mmc);
- u32 present_state;
-
- /* Check whether DAT[0] is 0 */
- present_state = sdhci_readl(host, SDHCI_PRESENT_STATE);
-
- return !(present_state & SDHCI_DATA_0_LVL_MASK);
-}
-
-static int sdhci_prepare_hs400_tuning(struct mmc_host *mmc, struct mmc_ios *ios)
-{
- struct sdhci_host *host = mmc_priv(mmc);
- unsigned long flags;
-
- spin_lock_irqsave(&host->lock, flags);
- host->flags |= SDHCI_HS400_TUNING;
- spin_unlock_irqrestore(&host->lock, flags);
-
- return 0;
-}
-
-void sdhci_start_tuning(struct sdhci_host *host)
-{
- u16 ctrl;
-
- ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
- ctrl |= SDHCI_CTRL_EXEC_TUNING;
- if (host->quirks2 & SDHCI_QUIRK2_TUNING_WORK_AROUND)
- ctrl |= SDHCI_CTRL_TUNED_CLK;
- sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
-
- /*
- * As per the Host Controller spec v3.00, tuning command
- * generates Buffer Read Ready interrupt, so enable that.
- *
- * Note: The spec clearly says that when tuning sequence
- * is being performed, the controller does not generate
- * interrupts other than Buffer Read Ready interrupt. But
- * to make sure we don't hit a controller bug, we _only_
- * enable Buffer Read Ready interrupt here.
- */
- sdhci_writel(host, SDHCI_INT_DATA_AVAIL, SDHCI_INT_ENABLE);
- sdhci_writel(host, SDHCI_INT_DATA_AVAIL, SDHCI_SIGNAL_ENABLE);
-}
-EXPORT_SYMBOL_GPL(sdhci_start_tuning);
-
-void sdhci_end_tuning(struct sdhci_host *host)
-{
- sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
- sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
-}
-EXPORT_SYMBOL_GPL(sdhci_end_tuning);
-
-void sdhci_reset_tuning(struct sdhci_host *host)
-{
- u16 ctrl;
-
- ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
- ctrl &= ~SDHCI_CTRL_TUNED_CLK;
- ctrl &= ~SDHCI_CTRL_EXEC_TUNING;
- sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
-}
-EXPORT_SYMBOL_GPL(sdhci_reset_tuning);
-
-void sdhci_abort_tuning(struct sdhci_host *host, u32 opcode)
-{
- sdhci_reset_tuning(host);
-
- sdhci_do_reset(host, SDHCI_RESET_CMD);
- sdhci_do_reset(host, SDHCI_RESET_DATA);
-
- sdhci_end_tuning(host);
-
- mmc_send_abort_tuning(host->mmc, opcode);
-}
-EXPORT_SYMBOL_GPL(sdhci_abort_tuning);
-
-/*
- * We use sdhci_send_tuning() because mmc_send_tuning() is not a good fit. SDHCI
- * tuning command does not have a data payload (or rather the hardware does it
- * automatically) so mmc_send_tuning() will return -EIO. Also the tuning command
- * interrupt setup is different to other commands and there is no timeout
- * interrupt so special handling is needed.
- */
-void sdhci_send_tuning(struct sdhci_host *host, u32 opcode)
-{
- struct mmc_host *mmc = host->mmc;
- struct mmc_command cmd = {};
- struct mmc_request mrq = {};
- unsigned long flags;
- u32 b = host->sdma_boundary;
-
- spin_lock_irqsave(&host->lock, flags);
-
- cmd.opcode = opcode;
- cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
- cmd.mrq = &mrq;
-
- mrq.cmd = &cmd;
- /*
- * In response to CMD19, the card sends 64 bytes of tuning
- * block to the Host Controller. So we set the block size
- * to 64 here.
- */
- if (cmd.opcode == MMC_SEND_TUNING_BLOCK_HS200 &&
- mmc->ios.bus_width == MMC_BUS_WIDTH_8)
- sdhci_writew(host, SDHCI_MAKE_BLKSZ(b, 128), SDHCI_BLOCK_SIZE);
- else
- sdhci_writew(host, SDHCI_MAKE_BLKSZ(b, 64), SDHCI_BLOCK_SIZE);
-
- /*
- * The tuning block is sent by the card to the host controller.
- * So we set the TRNS_READ bit in the Transfer Mode register.
- * This also takes care of setting DMA Enable and Multi Block
- * Select in the same register to 0.
- */
- sdhci_writew(host, SDHCI_TRNS_READ, SDHCI_TRANSFER_MODE);
-
- if (!sdhci_send_command_retry(host, &cmd, flags)) {
- spin_unlock_irqrestore(&host->lock, flags);
- host->tuning_done = 0;
- return;
- }
-
- host->cmd = NULL;
-
- sdhci_del_timer(host, &mrq);
-
- host->tuning_done = 0;
-
- spin_unlock_irqrestore(&host->lock, flags);
-
- /* Wait for Buffer Read Ready interrupt */
- wait_event_timeout(host->buf_ready_int, (host->tuning_done == 1),
- msecs_to_jiffies(50));
-
-}
-EXPORT_SYMBOL_GPL(sdhci_send_tuning);
-
-static int __sdhci_execute_tuning(struct sdhci_host *host, u32 opcode)
-{
- int i;
-
- /*
- * Issue opcode repeatedly till Execute Tuning is set to 0 or the number
- * of loops reaches tuning loop count.
- */
- for (i = 0; i < host->tuning_loop_count; i++) {
- u16 ctrl;
-
- sdhci_send_tuning(host, opcode);
-
- if (!host->tuning_done) {
- pr_debug("%s: Tuning timeout, falling back to fixed sampling clock\n",
- mmc_hostname(host->mmc));
- sdhci_abort_tuning(host, opcode);
- return -ETIMEDOUT;
- }
-
- /* Spec does not require a delay between tuning cycles */
- if (host->tuning_delay > 0)
- mdelay(host->tuning_delay);
-
- ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
- if (!(ctrl & SDHCI_CTRL_EXEC_TUNING)) {
- if (ctrl & SDHCI_CTRL_TUNED_CLK)
- return 0; /* Success! */
- break;
- }
-
- }
-
- pr_info("%s: Tuning failed, falling back to fixed sampling clock\n",
- mmc_hostname(host->mmc));
- sdhci_reset_tuning(host);
- return -EAGAIN;
-}
-
-int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
-{
- struct sdhci_host *host = mmc_priv(mmc);
- int err = 0;
- unsigned int tuning_count = 0;
- bool hs400_tuning;
-
- hs400_tuning = host->flags & SDHCI_HS400_TUNING;
-
- if (host->tuning_mode == SDHCI_TUNING_MODE_1)
- tuning_count = host->tuning_count;
-
- /*
- * The Host Controller needs tuning in case of SDR104 and DDR50
- * mode, and for SDR50 mode when Use Tuning for SDR50 is set in
- * the Capabilities register.
- * If the Host Controller supports the HS200 mode then the
- * tuning function has to be executed.
- */
- switch (host->timing) {
- /* HS400 tuning is done in HS200 mode */
- case MMC_TIMING_MMC_HS400:
- err = -EINVAL;
- goto out;
-
- case MMC_TIMING_MMC_HS200:
- /*
- * Periodic re-tuning for HS400 is not expected to be needed, so
- * disable it here.
- */
- if (hs400_tuning)
- tuning_count = 0;
- break;
-
- case MMC_TIMING_UHS_SDR104:
- case MMC_TIMING_UHS_DDR50:
- break;
-
- case MMC_TIMING_UHS_SDR50:
- if (host->flags & SDHCI_SDR50_NEEDS_TUNING)
- break;
- fallthrough;
-
- default:
- goto out;
- }
-
- if (host->ops->platform_execute_tuning) {
- err = host->ops->platform_execute_tuning(host, opcode);
- goto out;
- }
-
- mmc->retune_period = tuning_count;
-
- if (host->tuning_delay < 0)
- host->tuning_delay = opcode == MMC_SEND_TUNING_BLOCK;
-
- sdhci_start_tuning(host);
-
- host->tuning_err = __sdhci_execute_tuning(host, opcode);
-
- sdhci_end_tuning(host);
-out:
- host->flags &= ~SDHCI_HS400_TUNING;
-
- return err;
-}
-EXPORT_SYMBOL_GPL(sdhci_execute_tuning);
-
-static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable)
-{
- /* Host Controller v3.00 defines preset value registers */
- if (host->version < SDHCI_SPEC_300)
- return;
-
- /*
- * We only enable or disable Preset Value if they are not already
- * enabled or disabled respectively. Otherwise, we bail out.
- */
- if (host->preset_enabled != enable) {
- u16 ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
-
- if (enable)
- ctrl |= SDHCI_CTRL_PRESET_VAL_ENABLE;
- else
- ctrl &= ~SDHCI_CTRL_PRESET_VAL_ENABLE;
-
- sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
-
- if (enable)
- host->flags |= SDHCI_PV_ENABLED;
- else
- host->flags &= ~SDHCI_PV_ENABLED;
-
- host->preset_enabled = enable;
- }
-}
-
-static void sdhci_post_req(struct mmc_host *mmc, struct mmc_request *mrq,
- int err)
-{
- struct mmc_data *data = mrq->data;
-
- if (data->host_cookie != COOKIE_UNMAPPED)
- dma_unmap_sg(mmc_dev(mmc), data->sg, data->sg_len,
- mmc_get_dma_dir(data));
-
- data->host_cookie = COOKIE_UNMAPPED;
-}
-
-static void sdhci_pre_req(struct mmc_host *mmc, struct mmc_request *mrq)
-{
- struct sdhci_host *host = mmc_priv(mmc);
-
- mrq->data->host_cookie = COOKIE_UNMAPPED;
-
- /*
- * No pre-mapping in the pre hook if we're using the bounce buffer,
- * for that we would need two bounce buffers since one buffer is
- * in flight when this is getting called.
- */
- if (host->flags & SDHCI_REQ_USE_DMA && !host->bounce_buffer)
- sdhci_pre_dma_transfer(host, mrq->data, COOKIE_PRE_MAPPED);
-}
-
-static void sdhci_error_out_mrqs(struct sdhci_host *host, int err)
-{
- if (host->data_cmd) {
- host->data_cmd->error = err;
- sdhci_finish_mrq(host, host->data_cmd->mrq);
- }
-
- if (host->cmd) {
- host->cmd->error = err;
- sdhci_finish_mrq(host, host->cmd->mrq);
- }
-}
-
-static void sdhci_card_event(struct mmc_host *mmc)
-{
- struct sdhci_host *host = mmc_priv(mmc);
- unsigned long flags;
- int present;
-
- /* First check if client has provided their own card event */
- if (host->ops->card_event)
- host->ops->card_event(host);
-
- present = mmc->ops->get_cd(mmc);
-
- spin_lock_irqsave(&host->lock, flags);
-
- /* Check sdhci_has_requests() first in case we are runtime suspended */
- if (sdhci_has_requests(host) && !present) {
- pr_err("%s: Card removed during transfer!\n",
- mmc_hostname(mmc));
- pr_err("%s: Resetting controller.\n",
- mmc_hostname(mmc));
-
- sdhci_do_reset(host, SDHCI_RESET_CMD);
- sdhci_do_reset(host, SDHCI_RESET_DATA);
-
- sdhci_error_out_mrqs(host, -ENOMEDIUM);
- }
-
- spin_unlock_irqrestore(&host->lock, flags);
-}
-
-static const struct mmc_host_ops sdhci_ops = {
- .request = sdhci_request,
- .post_req = sdhci_post_req,
- .pre_req = sdhci_pre_req,
- .set_ios = sdhci_set_ios,
- .get_cd = sdhci_get_cd,
- .get_ro = sdhci_get_ro,
- .card_hw_reset = sdhci_hw_reset,
- .enable_sdio_irq = sdhci_enable_sdio_irq,
- .ack_sdio_irq = sdhci_ack_sdio_irq,
- .start_signal_voltage_switch = sdhci_start_signal_voltage_switch,
- .prepare_hs400_tuning = sdhci_prepare_hs400_tuning,
- .execute_tuning = sdhci_execute_tuning,
- .card_event = sdhci_card_event,
- .card_busy = sdhci_card_busy,
-};
-
-/*****************************************************************************\
- * *
- * Request done *
- * *
-\*****************************************************************************/
-
-static bool sdhci_request_done(struct sdhci_host *host)
-{
- unsigned long flags;
- struct mmc_request *mrq;
- int i;
-
- spin_lock_irqsave(&host->lock, flags);
-
- for (i = 0; i < SDHCI_MAX_MRQS; i++) {
- mrq = host->mrqs_done[i];
- if (mrq)
- break;
- }
-
- if (!mrq) {
- spin_unlock_irqrestore(&host->lock, flags);
- return true;
- }
-
- /*
- * The controller needs a reset of internal state machines
- * upon error conditions.
- */
- if (sdhci_needs_reset(host, mrq)) {
- /*
- * Do not finish until command and data lines are available for
- * reset. Note there can only be one other mrq, so it cannot
- * also be in mrqs_done, otherwise host->cmd and host->data_cmd
- * would both be null.
- */
- if (host->cmd || host->data_cmd) {
- spin_unlock_irqrestore(&host->lock, flags);
- return true;
- }
-
- /* Some controllers need this kick or reset won't work here */
- if (host->quirks & SDHCI_QUIRK_CLOCK_BEFORE_RESET)
- /* This is to force an update */
- host->ops->set_clock(host, host->clock);
-
- /*
- * Spec says we should do both at the same time, but Ricoh
- * controllers do not like that.
- */
- sdhci_do_reset(host, SDHCI_RESET_CMD);
- sdhci_do_reset(host, SDHCI_RESET_DATA);
-
- host->pending_reset = false;
- }
-
- /*
- * Always unmap the data buffers if they were mapped by
- * sdhci_prepare_data() whenever we finish with a request.
- * This avoids leaking DMA mappings on error.
- */
- if (host->flags & SDHCI_REQ_USE_DMA) {
- struct mmc_data *data = mrq->data;
-
- if (host->use_external_dma && data &&
- (mrq->cmd->error || data->error)) {
- struct dma_chan *chan = sdhci_external_dma_channel(host, data);
-
- host->mrqs_done[i] = NULL;
- spin_unlock_irqrestore(&host->lock, flags);
- dmaengine_terminate_sync(chan);
- spin_lock_irqsave(&host->lock, flags);
- sdhci_set_mrq_done(host, mrq);
- }
-
- if (data && data->host_cookie == COOKIE_MAPPED) {
- if (host->bounce_buffer) {
- /*
- * On reads, copy the bounced data into the
- * sglist
- */
- if (mmc_get_dma_dir(data) == DMA_FROM_DEVICE) {
- unsigned int length = data->bytes_xfered;
-
- if (length > host->bounce_buffer_size) {
- pr_err("%s: bounce buffer is %u bytes but DMA claims to have transferred %u bytes\n",
- mmc_hostname(host->mmc),
- host->bounce_buffer_size,
- data->bytes_xfered);
- /* Cap it down and continue */
- length = host->bounce_buffer_size;
- }
- dma_sync_single_for_cpu(
- mmc_dev(host->mmc),
- host->bounce_addr,
- host->bounce_buffer_size,
- DMA_FROM_DEVICE);
- sg_copy_from_buffer(data->sg,
- data->sg_len,
- host->bounce_buffer,
- length);
- } else {
- /* No copying, just switch ownership */
- dma_sync_single_for_cpu(
- mmc_dev(host->mmc),
- host->bounce_addr,
- host->bounce_buffer_size,
- mmc_get_dma_dir(data));
- }
- } else {
- /* Unmap the raw data */
- dma_unmap_sg(mmc_dev(host->mmc), data->sg,
- data->sg_len,
- mmc_get_dma_dir(data));
- }
- data->host_cookie = COOKIE_UNMAPPED;
- }
- }
-
- host->mrqs_done[i] = NULL;
-
- spin_unlock_irqrestore(&host->lock, flags);
-
- if (host->ops->request_done)
- host->ops->request_done(host, mrq);
- else
- mmc_request_done(host->mmc, mrq);
-
- return false;
-}
-
-static void sdhci_complete_work(struct work_struct *work)
-{
- struct sdhci_host *host = container_of(work, struct sdhci_host,
- complete_work);
-
- while (!sdhci_request_done(host))
- ;
-}
-
-static void sdhci_timeout_timer(struct timer_list *t)
-{
- struct sdhci_host *host;
- unsigned long flags;
-
- host = from_timer(host, t, timer);
-
- spin_lock_irqsave(&host->lock, flags);
-
- if (host->cmd && !sdhci_data_line_cmd(host->cmd)) {
- pr_err("%s: Timeout waiting for hardware cmd interrupt.\n",
- mmc_hostname(host->mmc));
- sdhci_err_stats_inc(host, REQ_TIMEOUT);
- sdhci_dumpregs(host);
-
- host->cmd->error = -ETIMEDOUT;
- sdhci_finish_mrq(host, host->cmd->mrq);
- }
-
- spin_unlock_irqrestore(&host->lock, flags);
-}
-
-static void sdhci_timeout_data_timer(struct timer_list *t)
-{
- struct sdhci_host *host;
- unsigned long flags;
-
- host = from_timer(host, t, data_timer);
-
- spin_lock_irqsave(&host->lock, flags);
-
- if (host->data || host->data_cmd ||
- (host->cmd && sdhci_data_line_cmd(host->cmd))) {
- pr_err("%s: Timeout waiting for hardware interrupt.\n",
- mmc_hostname(host->mmc));
- sdhci_err_stats_inc(host, REQ_TIMEOUT);
- sdhci_dumpregs(host);
-
- if (host->data) {
- host->data->error = -ETIMEDOUT;
- __sdhci_finish_data(host, true);
- queue_work(host->complete_wq, &host->complete_work);
- } else if (host->data_cmd) {
- host->data_cmd->error = -ETIMEDOUT;
- sdhci_finish_mrq(host, host->data_cmd->mrq);
- } else {
- host->cmd->error = -ETIMEDOUT;
- sdhci_finish_mrq(host, host->cmd->mrq);
- }
- }
-
- spin_unlock_irqrestore(&host->lock, flags);
-}
-
-/*****************************************************************************\
- * *
- * Interrupt handling *
- * *
-\*****************************************************************************/
-
-static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask, u32 *intmask_p)
-{
- /* Handle auto-CMD12 error */
- if (intmask & SDHCI_INT_AUTO_CMD_ERR && host->data_cmd) {
- struct mmc_request *mrq = host->data_cmd->mrq;
- u16 auto_cmd_status = sdhci_readw(host, SDHCI_AUTO_CMD_STATUS);
- int data_err_bit = (auto_cmd_status & SDHCI_AUTO_CMD_TIMEOUT) ?
- SDHCI_INT_DATA_TIMEOUT :
- SDHCI_INT_DATA_CRC;
-
- /* Treat auto-CMD12 error the same as data error */
- if (!mrq->sbc && (host->flags & SDHCI_AUTO_CMD12)) {
- *intmask_p |= data_err_bit;
- return;
- }
- }
-
- if (!host->cmd) {
- /*
- * SDHCI recovers from errors by resetting the cmd and data
- * circuits. Until that is done, there very well might be more
- * interrupts, so ignore them in that case.
- */
- if (host->pending_reset)
- return;
- pr_err("%s: Got command interrupt 0x%08x even though no command operation was in progress.\n",
- mmc_hostname(host->mmc), (unsigned)intmask);
- sdhci_err_stats_inc(host, UNEXPECTED_IRQ);
- sdhci_dumpregs(host);
- return;
- }
-
- if (intmask & (SDHCI_INT_TIMEOUT | SDHCI_INT_CRC |
- SDHCI_INT_END_BIT | SDHCI_INT_INDEX)) {
- if (intmask & SDHCI_INT_TIMEOUT) {
- host->cmd->error = -ETIMEDOUT;
- sdhci_err_stats_inc(host, CMD_TIMEOUT);
- } else {
- host->cmd->error = -EILSEQ;
- if (!mmc_op_tuning(host->cmd->opcode))
- sdhci_err_stats_inc(host, CMD_CRC);
- }
- /* Treat data command CRC error the same as data CRC error */
- if (host->cmd->data &&
- (intmask & (SDHCI_INT_CRC | SDHCI_INT_TIMEOUT)) ==
- SDHCI_INT_CRC) {
- host->cmd = NULL;
- *intmask_p |= SDHCI_INT_DATA_CRC;
- return;
- }
-
- __sdhci_finish_mrq(host, host->cmd->mrq);
- return;
- }
-
- /* Handle auto-CMD23 error */
- if (intmask & SDHCI_INT_AUTO_CMD_ERR) {
- struct mmc_request *mrq = host->cmd->mrq;
- u16 auto_cmd_status = sdhci_readw(host, SDHCI_AUTO_CMD_STATUS);
- int err = (auto_cmd_status & SDHCI_AUTO_CMD_TIMEOUT) ?
- -ETIMEDOUT :
- -EILSEQ;
-
- sdhci_err_stats_inc(host, AUTO_CMD);
-
- if (sdhci_auto_cmd23(host, mrq)) {
- mrq->sbc->error = err;
- __sdhci_finish_mrq(host, mrq);
- return;
- }
- }
-
- if (intmask & SDHCI_INT_RESPONSE)
- sdhci_finish_command(host);
-}
-
-static void sdhci_adma_show_error(struct sdhci_host *host)
-{
- void *desc = host->adma_table;
- dma_addr_t dma = host->adma_addr;
-
- sdhci_dumpregs(host);
-
- while (true) {
- struct sdhci_adma2_64_desc *dma_desc = desc;
-
- if (host->flags & SDHCI_USE_64_BIT_DMA)
- SDHCI_DUMP("%08llx: DMA 0x%08x%08x, LEN 0x%04x, Attr=0x%02x\n",
- (unsigned long long)dma,
- le32_to_cpu(dma_desc->addr_hi),
- le32_to_cpu(dma_desc->addr_lo),
- le16_to_cpu(dma_desc->len),
- le16_to_cpu(dma_desc->cmd));
- else
- SDHCI_DUMP("%08llx: DMA 0x%08x, LEN 0x%04x, Attr=0x%02x\n",
- (unsigned long long)dma,
- le32_to_cpu(dma_desc->addr_lo),
- le16_to_cpu(dma_desc->len),
- le16_to_cpu(dma_desc->cmd));
-
- desc += host->desc_sz;
- dma += host->desc_sz;
-
- if (dma_desc->cmd & cpu_to_le16(ADMA2_END))
- break;
- }
-}
-
-static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
-{
- u32 command;
-
- /*
- * CMD19 generates _only_ Buffer Read Ready interrupt if
- * use sdhci_send_tuning.
- * Need to exclude this case: PIO mode and use mmc_send_tuning,
- * If not, sdhci_transfer_pio will never be called, make the
- * SDHCI_INT_DATA_AVAIL always there, stuck in irq storm.
- */
- if (intmask & SDHCI_INT_DATA_AVAIL && !host->data) {
- command = SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND));
- if (command == MMC_SEND_TUNING_BLOCK ||
- command == MMC_SEND_TUNING_BLOCK_HS200) {
- host->tuning_done = 1;
- wake_up(&host->buf_ready_int);
- return;
- }
- }
-
- if (!host->data) {
- struct mmc_command *data_cmd = host->data_cmd;
-
- /*
- * The "data complete" interrupt is also used to
- * indicate that a busy state has ended. See comment
- * above in sdhci_cmd_irq().
- */
- if (data_cmd && (data_cmd->flags & MMC_RSP_BUSY)) {
- if (intmask & SDHCI_INT_DATA_TIMEOUT) {
- host->data_cmd = NULL;
- data_cmd->error = -ETIMEDOUT;
- sdhci_err_stats_inc(host, CMD_TIMEOUT);
- __sdhci_finish_mrq(host, data_cmd->mrq);
- return;
- }
- if (intmask & SDHCI_INT_DATA_END) {
- host->data_cmd = NULL;
- /*
- * Some cards handle busy-end interrupt
- * before the command completed, so make
- * sure we do things in the proper order.
- */
- if (host->cmd == data_cmd)
- return;
-
- __sdhci_finish_mrq(host, data_cmd->mrq);
- return;
- }
- }
-
- /*
- * SDHCI recovers from errors by resetting the cmd and data
- * circuits. Until that is done, there very well might be more
- * interrupts, so ignore them in that case.
- */
- if (host->pending_reset)
- return;
-
- pr_err("%s: Got data interrupt 0x%08x even though no data operation was in progress.\n",
- mmc_hostname(host->mmc), (unsigned)intmask);
- sdhci_err_stats_inc(host, UNEXPECTED_IRQ);
- sdhci_dumpregs(host);
-
- return;
- }
-
- if (intmask & SDHCI_INT_DATA_TIMEOUT) {
- host->data->error = -ETIMEDOUT;
- sdhci_err_stats_inc(host, DAT_TIMEOUT);
- } else if (intmask & SDHCI_INT_DATA_END_BIT) {
- host->data->error = -EILSEQ;
- if (!mmc_op_tuning(SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND))))
- sdhci_err_stats_inc(host, DAT_CRC);
- } else if ((intmask & SDHCI_INT_DATA_CRC) &&
- SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND))
- != MMC_BUS_TEST_R) {
- host->data->error = -EILSEQ;
- if (!mmc_op_tuning(SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND))))
- sdhci_err_stats_inc(host, DAT_CRC);
- } else if (intmask & SDHCI_INT_ADMA_ERROR) {
- pr_err("%s: ADMA error: 0x%08x\n", mmc_hostname(host->mmc),
- intmask);
- sdhci_adma_show_error(host);
- sdhci_err_stats_inc(host, ADMA);
- host->data->error = -EIO;
- if (host->ops->adma_workaround)
- host->ops->adma_workaround(host, intmask);
- }
-
- if (host->data->error)
- sdhci_finish_data(host);
- else {
- if (intmask & (SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL))
- sdhci_transfer_pio(host);
-
- /*
- * We currently don't do anything fancy with DMA
- * boundaries, but as we can't disable the feature
- * we need to at least restart the transfer.
- *
- * According to the spec sdhci_readl(host, SDHCI_DMA_ADDRESS)
- * should return a valid address to continue from, but as
- * some controllers are faulty, don't trust them.
- */
- if (intmask & SDHCI_INT_DMA_END) {
- dma_addr_t dmastart, dmanow;
-
- dmastart = sdhci_sdma_address(host);
- dmanow = dmastart + host->data->bytes_xfered;
- /*
- * Force update to the next DMA block boundary.
- */
- dmanow = (dmanow &
- ~((dma_addr_t)SDHCI_DEFAULT_BOUNDARY_SIZE - 1)) +
- SDHCI_DEFAULT_BOUNDARY_SIZE;
- host->data->bytes_xfered = dmanow - dmastart;
- DBG("DMA base %pad, transferred 0x%06x bytes, next %pad\n",
- &dmastart, host->data->bytes_xfered, &dmanow);
- sdhci_set_sdma_addr(host, dmanow);
- }
-
- if (intmask & SDHCI_INT_DATA_END) {
- if (host->cmd == host->data_cmd) {
- /*
- * Data managed to finish before the
- * command completed. Make sure we do
- * things in the proper order.
- */
- host->data_early = 1;
- } else {
- sdhci_finish_data(host);
- }
- }
- }
-}
-
-static inline bool sdhci_defer_done(struct sdhci_host *host,
- struct mmc_request *mrq)
-{
- struct mmc_data *data = mrq->data;
-
- return host->pending_reset || host->always_defer_done ||
- ((host->flags & SDHCI_REQ_USE_DMA) && data &&
- data->host_cookie == COOKIE_MAPPED);
-}
-
-static irqreturn_t sdhci_irq(int irq, void *dev_id)
-{
- struct mmc_request *mrqs_done[SDHCI_MAX_MRQS] = {0};
- irqreturn_t result = IRQ_NONE;
- struct sdhci_host *host = dev_id;
- u32 intmask, mask, unexpected = 0;
- int max_loops = 16;
- int i;
-
- spin_lock(&host->lock);
-
- if (host->runtime_suspended) {
- spin_unlock(&host->lock);
- return IRQ_NONE;
- }
-
- intmask = sdhci_readl(host, SDHCI_INT_STATUS);
- if (!intmask || intmask == 0xffffffff) {
- result = IRQ_NONE;
- goto out;
- }
-
- do {
- DBG("IRQ status 0x%08x\n", intmask);
-
- if (host->ops->irq) {
- intmask = host->ops->irq(host, intmask);
- if (!intmask)
- goto cont;
- }
-
- /* Clear selected interrupts. */
- mask = intmask & (SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK |
- SDHCI_INT_BUS_POWER);
- sdhci_writel(host, mask, SDHCI_INT_STATUS);
-
- if (intmask & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE)) {
- u32 present = sdhci_readl(host, SDHCI_PRESENT_STATE) &
- SDHCI_CARD_PRESENT;
-
- /*
- * There is a observation on i.mx esdhc. INSERT
- * bit will be immediately set again when it gets
- * cleared, if a card is inserted. We have to mask
- * the irq to prevent interrupt storm which will
- * freeze the system. And the REMOVE gets the
- * same situation.
- *
- * More testing are needed here to ensure it works
- * for other platforms though.
- */
- host->ier &= ~(SDHCI_INT_CARD_INSERT |
- SDHCI_INT_CARD_REMOVE);
- host->ier |= present ? SDHCI_INT_CARD_REMOVE :
- SDHCI_INT_CARD_INSERT;
- sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
- sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
-
- sdhci_writel(host, intmask & (SDHCI_INT_CARD_INSERT |
- SDHCI_INT_CARD_REMOVE), SDHCI_INT_STATUS);
-
- host->thread_isr |= intmask & (SDHCI_INT_CARD_INSERT |
- SDHCI_INT_CARD_REMOVE);
- result = IRQ_WAKE_THREAD;
- }
-
- if (intmask & SDHCI_INT_CMD_MASK)
- sdhci_cmd_irq(host, intmask & SDHCI_INT_CMD_MASK, &intmask);
-
- if (intmask & SDHCI_INT_DATA_MASK)
- sdhci_data_irq(host, intmask & SDHCI_INT_DATA_MASK);
-
- if (intmask & SDHCI_INT_BUS_POWER)
- pr_err("%s: Card is consuming too much power!\n",
- mmc_hostname(host->mmc));
-
- if (intmask & SDHCI_INT_RETUNE)
- mmc_retune_needed(host->mmc);
-
- if ((intmask & SDHCI_INT_CARD_INT) &&
- (host->ier & SDHCI_INT_CARD_INT)) {
- sdhci_enable_sdio_irq_nolock(host, false);
- sdio_signal_irq(host->mmc);
- }
-
- intmask &= ~(SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE |
- SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK |
- SDHCI_INT_ERROR | SDHCI_INT_BUS_POWER |
- SDHCI_INT_RETUNE | SDHCI_INT_CARD_INT);
-
- if (intmask) {
- unexpected |= intmask;
- sdhci_writel(host, intmask, SDHCI_INT_STATUS);
- }
-cont:
- if (result == IRQ_NONE)
- result = IRQ_HANDLED;
-
- intmask = sdhci_readl(host, SDHCI_INT_STATUS);
- } while (intmask && --max_loops);
-
- /* Determine if mrqs can be completed immediately */
- for (i = 0; i < SDHCI_MAX_MRQS; i++) {
- struct mmc_request *mrq = host->mrqs_done[i];
-
- if (!mrq)
- continue;
-
- if (sdhci_defer_done(host, mrq)) {
- result = IRQ_WAKE_THREAD;
- } else {
- mrqs_done[i] = mrq;
- host->mrqs_done[i] = NULL;
- }
- }
-out:
- if (host->deferred_cmd)
- result = IRQ_WAKE_THREAD;
-
- spin_unlock(&host->lock);
-
- /* Process mrqs ready for immediate completion */
- for (i = 0; i < SDHCI_MAX_MRQS; i++) {
- if (!mrqs_done[i])
- continue;
-
- if (host->ops->request_done)
- host->ops->request_done(host, mrqs_done[i]);
- else
- mmc_request_done(host->mmc, mrqs_done[i]);
- }
-
- if (unexpected) {
- pr_err("%s: Unexpected interrupt 0x%08x.\n",
- mmc_hostname(host->mmc), unexpected);
- sdhci_err_stats_inc(host, UNEXPECTED_IRQ);
- sdhci_dumpregs(host);
- }
-
- return result;
-}
-
-static irqreturn_t sdhci_thread_irq(int irq, void *dev_id)
-{
- struct sdhci_host *host = dev_id;
- struct mmc_command *cmd;
- unsigned long flags;
- u32 isr;
-
- while (!sdhci_request_done(host))
- ;
-
- spin_lock_irqsave(&host->lock, flags);
-
- isr = host->thread_isr;
- host->thread_isr = 0;
-
- cmd = host->deferred_cmd;
- if (cmd && !sdhci_send_command_retry(host, cmd, flags))
- sdhci_finish_mrq(host, cmd->mrq);
-
- spin_unlock_irqrestore(&host->lock, flags);
-
- if (isr & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE)) {
- struct mmc_host *mmc = host->mmc;
-
- mmc->ops->card_event(mmc);
- mmc_detect_change(mmc, msecs_to_jiffies(200));
- }
-
- return IRQ_HANDLED;
-}
-
-/*****************************************************************************\
- * *
- * Suspend/resume *
- * *
-\*****************************************************************************/
-
-#ifdef CONFIG_PM
-
-static bool sdhci_cd_irq_can_wakeup(struct sdhci_host *host)
-{
- return mmc_card_is_removable(host->mmc) &&
- !(host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) &&
- !mmc_can_gpio_cd(host->mmc);
-}
-
-/*
- * To enable wakeup events, the corresponding events have to be enabled in
- * the Interrupt Status Enable register too. See 'Table 1-6: Wakeup Signal
- * Table' in the SD Host Controller Standard Specification.
- * It is useless to restore SDHCI_INT_ENABLE state in
- * sdhci_disable_irq_wakeups() since it will be set by
- * sdhci_enable_card_detection() or sdhci_init().
- */
-static bool sdhci_enable_irq_wakeups(struct sdhci_host *host)
-{
- u8 mask = SDHCI_WAKE_ON_INSERT | SDHCI_WAKE_ON_REMOVE |
- SDHCI_WAKE_ON_INT;
- u32 irq_val = 0;
- u8 wake_val = 0;
- u8 val;
-
- if (sdhci_cd_irq_can_wakeup(host)) {
- wake_val |= SDHCI_WAKE_ON_INSERT | SDHCI_WAKE_ON_REMOVE;
- irq_val |= SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE;
- }
-
- if (mmc_card_wake_sdio_irq(host->mmc)) {
- wake_val |= SDHCI_WAKE_ON_INT;
- irq_val |= SDHCI_INT_CARD_INT;
- }
-
- if (!irq_val)
- return false;
-
- val = sdhci_readb(host, SDHCI_WAKE_UP_CONTROL);
- val &= ~mask;
- val |= wake_val;
- sdhci_writeb(host, val, SDHCI_WAKE_UP_CONTROL);
-
- sdhci_writel(host, irq_val, SDHCI_INT_ENABLE);
-
- host->irq_wake_enabled = !enable_irq_wake(host->irq);
-
- return host->irq_wake_enabled;
-}
-
-static void sdhci_disable_irq_wakeups(struct sdhci_host *host)
-{
- u8 val;
- u8 mask = SDHCI_WAKE_ON_INSERT | SDHCI_WAKE_ON_REMOVE
- | SDHCI_WAKE_ON_INT;
-
- val = sdhci_readb(host, SDHCI_WAKE_UP_CONTROL);
- val &= ~mask;
- sdhci_writeb(host, val, SDHCI_WAKE_UP_CONTROL);
-
- disable_irq_wake(host->irq);
-
- host->irq_wake_enabled = false;
-}
-
-int sdhci_suspend_host(struct sdhci_host *host)
-{
- sdhci_disable_card_detection(host);
-
- mmc_retune_timer_stop(host->mmc);
-
- if (!device_may_wakeup(mmc_dev(host->mmc)) ||
- !sdhci_enable_irq_wakeups(host)) {
- host->ier = 0;
- sdhci_writel(host, 0, SDHCI_INT_ENABLE);
- sdhci_writel(host, 0, SDHCI_SIGNAL_ENABLE);
- free_irq(host->irq, host);
- }
-
- return 0;
-}
-
-EXPORT_SYMBOL_GPL(sdhci_suspend_host);
-
-int sdhci_resume_host(struct sdhci_host *host)
-{
- struct mmc_host *mmc = host->mmc;
- int ret = 0;
-
- if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) {
- if (host->ops->enable_dma)
- host->ops->enable_dma(host);
- }
-
- if ((mmc->pm_flags & MMC_PM_KEEP_POWER) &&
- (host->quirks2 & SDHCI_QUIRK2_HOST_OFF_CARD_ON)) {
- /* Card keeps power but host controller does not */
- sdhci_init(host, 0);
- host->pwr = 0;
- host->clock = 0;
- mmc->ops->set_ios(mmc, &mmc->ios);
- } else {
- sdhci_init(host, (mmc->pm_flags & MMC_PM_KEEP_POWER));
- }
-
- if (host->irq_wake_enabled) {
- sdhci_disable_irq_wakeups(host);
- } else {
- ret = request_threaded_irq(host->irq, sdhci_irq,
- sdhci_thread_irq, IRQF_SHARED,
- mmc_hostname(mmc), host);
- if (ret)
- return ret;
- }
-
- sdhci_enable_card_detection(host);
-
- return ret;
-}
-
-EXPORT_SYMBOL_GPL(sdhci_resume_host);
-
-int sdhci_runtime_suspend_host(struct sdhci_host *host)
-{
- unsigned long flags;
-
- mmc_retune_timer_stop(host->mmc);
-
- spin_lock_irqsave(&host->lock, flags);
- host->ier &= SDHCI_INT_CARD_INT;
- sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
- sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
- spin_unlock_irqrestore(&host->lock, flags);
-
- synchronize_hardirq(host->irq);
-
- spin_lock_irqsave(&host->lock, flags);
- host->runtime_suspended = true;
- spin_unlock_irqrestore(&host->lock, flags);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(sdhci_runtime_suspend_host);
-
-int sdhci_runtime_resume_host(struct sdhci_host *host, int soft_reset)
-{
- struct mmc_host *mmc = host->mmc;
- unsigned long flags;
- int host_flags = host->flags;
-
- if (host_flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) {
- if (host->ops->enable_dma)
- host->ops->enable_dma(host);
- }
-
- sdhci_init(host, soft_reset);
-
- if (mmc->ios.power_mode != MMC_POWER_UNDEFINED &&
- mmc->ios.power_mode != MMC_POWER_OFF) {
- /* Force clock and power re-program */
- host->pwr = 0;
- host->clock = 0;
- mmc->ops->start_signal_voltage_switch(mmc, &mmc->ios);
- mmc->ops->set_ios(mmc, &mmc->ios);
-
- if ((host_flags & SDHCI_PV_ENABLED) &&
- !(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN)) {
- spin_lock_irqsave(&host->lock, flags);
- sdhci_enable_preset_value(host, true);
- spin_unlock_irqrestore(&host->lock, flags);
- }
-
- if ((mmc->caps2 & MMC_CAP2_HS400_ES) &&
- mmc->ops->hs400_enhanced_strobe)
- mmc->ops->hs400_enhanced_strobe(mmc, &mmc->ios);
- }
-
- spin_lock_irqsave(&host->lock, flags);
-
- host->runtime_suspended = false;
-
- /* Enable SDIO IRQ */
- if (sdio_irq_claimed(mmc))
- sdhci_enable_sdio_irq_nolock(host, true);
-
- /* Enable Card Detection */
- sdhci_enable_card_detection(host);
-
- spin_unlock_irqrestore(&host->lock, flags);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(sdhci_runtime_resume_host);
-
-#endif /* CONFIG_PM */
-
-/*****************************************************************************\
- * *
- * Command Queue Engine (CQE) helpers *
- * *
-\*****************************************************************************/
-
-void sdhci_cqe_enable(struct mmc_host *mmc)
-{
- struct sdhci_host *host = mmc_priv(mmc);
- unsigned long flags;
- u8 ctrl;
-
- spin_lock_irqsave(&host->lock, flags);
-
- ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
- ctrl &= ~SDHCI_CTRL_DMA_MASK;
- /*
- * Host from V4.10 supports ADMA3 DMA type.
- * ADMA3 performs integrated descriptor which is more suitable
- * for cmd queuing to fetch both command and transfer descriptors.
- */
- if (host->v4_mode && (host->caps1 & SDHCI_CAN_DO_ADMA3))
- ctrl |= SDHCI_CTRL_ADMA3;
- else if (host->flags & SDHCI_USE_64_BIT_DMA)
- ctrl |= SDHCI_CTRL_ADMA64;
- else
- ctrl |= SDHCI_CTRL_ADMA32;
- sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
-
- sdhci_writew(host, SDHCI_MAKE_BLKSZ(host->sdma_boundary, 512),
- SDHCI_BLOCK_SIZE);
-
- /* Set maximum timeout */
- sdhci_set_timeout(host, NULL);
-
- host->ier = host->cqe_ier;
-
- sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
- sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
-
- host->cqe_on = true;
-
- pr_debug("%s: sdhci: CQE on, IRQ mask %#x, IRQ status %#x\n",
- mmc_hostname(mmc), host->ier,
- sdhci_readl(host, SDHCI_INT_STATUS));
-
- spin_unlock_irqrestore(&host->lock, flags);
-}
-EXPORT_SYMBOL_GPL(sdhci_cqe_enable);
-
-void sdhci_cqe_disable(struct mmc_host *mmc, bool recovery)
-{
- struct sdhci_host *host = mmc_priv(mmc);
- unsigned long flags;
-
- spin_lock_irqsave(&host->lock, flags);
-
- sdhci_set_default_irqs(host);
-
- host->cqe_on = false;
-
- if (recovery) {
- sdhci_do_reset(host, SDHCI_RESET_CMD);
- sdhci_do_reset(host, SDHCI_RESET_DATA);
- }
-
- pr_debug("%s: sdhci: CQE off, IRQ mask %#x, IRQ status %#x\n",
- mmc_hostname(mmc), host->ier,
- sdhci_readl(host, SDHCI_INT_STATUS));
-
- spin_unlock_irqrestore(&host->lock, flags);
-}
-EXPORT_SYMBOL_GPL(sdhci_cqe_disable);
-
-bool sdhci_cqe_irq(struct sdhci_host *host, u32 intmask, int *cmd_error,
- int *data_error)
-{
- u32 mask;
-
- if (!host->cqe_on)
- return false;
-
- if (intmask & (SDHCI_INT_INDEX | SDHCI_INT_END_BIT | SDHCI_INT_CRC)) {
- *cmd_error = -EILSEQ;
- if (!mmc_op_tuning(SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND))))
- sdhci_err_stats_inc(host, CMD_CRC);
- } else if (intmask & SDHCI_INT_TIMEOUT) {
- *cmd_error = -ETIMEDOUT;
- sdhci_err_stats_inc(host, CMD_TIMEOUT);
- } else
- *cmd_error = 0;
-
- if (intmask & (SDHCI_INT_DATA_END_BIT | SDHCI_INT_DATA_CRC)) {
- *data_error = -EILSEQ;
- if (!mmc_op_tuning(SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND))))
- sdhci_err_stats_inc(host, DAT_CRC);
- } else if (intmask & SDHCI_INT_DATA_TIMEOUT) {
- *data_error = -ETIMEDOUT;
- sdhci_err_stats_inc(host, DAT_TIMEOUT);
- } else if (intmask & SDHCI_INT_ADMA_ERROR) {
- *data_error = -EIO;
- sdhci_err_stats_inc(host, ADMA);
- } else
- *data_error = 0;
-
- /* Clear selected interrupts. */
- mask = intmask & host->cqe_ier;
- sdhci_writel(host, mask, SDHCI_INT_STATUS);
-
- if (intmask & SDHCI_INT_BUS_POWER)
- pr_err("%s: Card is consuming too much power!\n",
- mmc_hostname(host->mmc));
-
- intmask &= ~(host->cqe_ier | SDHCI_INT_ERROR);
- if (intmask) {
- sdhci_writel(host, intmask, SDHCI_INT_STATUS);
- pr_err("%s: CQE: Unexpected interrupt 0x%08x.\n",
- mmc_hostname(host->mmc), intmask);
- sdhci_err_stats_inc(host, UNEXPECTED_IRQ);
- sdhci_dumpregs(host);
- }
-
- return true;
-}
-EXPORT_SYMBOL_GPL(sdhci_cqe_irq);
-
-/*****************************************************************************\
- * *
- * Device allocation/registration *
- * *
-\*****************************************************************************/
-
-struct sdhci_host *sdhci_alloc_host(struct device *dev,
- size_t priv_size)
-{
- struct mmc_host *mmc;
- struct sdhci_host *host;
-
- WARN_ON(dev == NULL);
-
- mmc = mmc_alloc_host(sizeof(struct sdhci_host) + priv_size, dev);
- if (!mmc)
- return ERR_PTR(-ENOMEM);
-
- host = mmc_priv(mmc);
- host->mmc = mmc;
- host->mmc_host_ops = sdhci_ops;
- mmc->ops = &host->mmc_host_ops;
-
- host->flags = SDHCI_SIGNALING_330;
-
- host->cqe_ier = SDHCI_CQE_INT_MASK;
- host->cqe_err_ier = SDHCI_CQE_INT_ERR_MASK;
-
- host->tuning_delay = -1;
- host->tuning_loop_count = MAX_TUNING_LOOP;
-
- host->sdma_boundary = SDHCI_DEFAULT_BOUNDARY_ARG;
-
- /*
- * The DMA table descriptor count is calculated as the maximum
- * number of segments times 2, to allow for an alignment
- * descriptor for each segment, plus 1 for a nop end descriptor.
- */
- host->adma_table_cnt = SDHCI_MAX_SEGS * 2 + 1;
- host->max_adma = 65536;
-
- host->max_timeout_count = 0xE;
-
- return host;
-}
-
-EXPORT_SYMBOL_GPL(sdhci_alloc_host);
-
-static int sdhci_set_dma_mask(struct sdhci_host *host)
-{
- struct mmc_host *mmc = host->mmc;
- struct device *dev = mmc_dev(mmc);
- int ret = -EINVAL;
-
- if (host->quirks2 & SDHCI_QUIRK2_BROKEN_64_BIT_DMA)
- host->flags &= ~SDHCI_USE_64_BIT_DMA;
-
- /* Try 64-bit mask if hardware is capable of it */
- if (host->flags & SDHCI_USE_64_BIT_DMA) {
- ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64));
- if (ret) {
- pr_warn("%s: Failed to set 64-bit DMA mask.\n",
- mmc_hostname(mmc));
- host->flags &= ~SDHCI_USE_64_BIT_DMA;
- }
- }
-
- /* 32-bit mask as default & fallback */
- if (ret) {
- ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
- if (ret)
- pr_warn("%s: Failed to set 32-bit DMA mask.\n",
- mmc_hostname(mmc));
- }
-
- return ret;
-}
-
-void __sdhci_read_caps(struct sdhci_host *host, const u16 *ver,
- const u32 *caps, const u32 *caps1)
-{
- u16 v;
- u64 dt_caps_mask = 0;
- u64 dt_caps = 0;
-
- if (host->read_caps)
- return;
-
- host->read_caps = true;
-
- if (debug_quirks)
- host->quirks = debug_quirks;
-
- if (debug_quirks2)
- host->quirks2 = debug_quirks2;
-
- sdhci_do_reset(host, SDHCI_RESET_ALL);
-
- if (host->v4_mode)
- sdhci_do_enable_v4_mode(host);
-
- device_property_read_u64(mmc_dev(host->mmc),
- "sdhci-caps-mask", &dt_caps_mask);
- device_property_read_u64(mmc_dev(host->mmc),
- "sdhci-caps", &dt_caps);
-
- v = ver ? *ver : sdhci_readw(host, SDHCI_HOST_VERSION);
- host->version = (v & SDHCI_SPEC_VER_MASK) >> SDHCI_SPEC_VER_SHIFT;
-
- if (host->quirks & SDHCI_QUIRK_MISSING_CAPS)
- return;
-
- if (caps) {
- host->caps = *caps;
- } else {
- host->caps = sdhci_readl(host, SDHCI_CAPABILITIES);
- host->caps &= ~lower_32_bits(dt_caps_mask);
- host->caps |= lower_32_bits(dt_caps);
- }
-
- if (host->version < SDHCI_SPEC_300)
- return;
-
- if (caps1) {
- host->caps1 = *caps1;
- } else {
- host->caps1 = sdhci_readl(host, SDHCI_CAPABILITIES_1);
- host->caps1 &= ~upper_32_bits(dt_caps_mask);
- host->caps1 |= upper_32_bits(dt_caps);
- }
-}
-EXPORT_SYMBOL_GPL(__sdhci_read_caps);
-
-static void sdhci_allocate_bounce_buffer(struct sdhci_host *host)
-{
- struct mmc_host *mmc = host->mmc;
- unsigned int max_blocks;
- unsigned int bounce_size;
- int ret;
-
- /*
- * Cap the bounce buffer at 64KB. Using a bigger bounce buffer
- * has diminishing returns, this is probably because SD/MMC
- * cards are usually optimized to handle this size of requests.
- */
- bounce_size = SZ_64K;
- /*
- * Adjust downwards to maximum request size if this is less
- * than our segment size, else hammer down the maximum
- * request size to the maximum buffer size.
- */
- if (mmc->max_req_size < bounce_size)
- bounce_size = mmc->max_req_size;
- max_blocks = bounce_size / 512;
-
- /*
- * When we just support one segment, we can get significant
- * speedups by the help of a bounce buffer to group scattered
- * reads/writes together.
- */
- host->bounce_buffer = devm_kmalloc(mmc_dev(mmc),
- bounce_size,
- GFP_KERNEL);
- if (!host->bounce_buffer) {
- pr_err("%s: failed to allocate %u bytes for bounce buffer, falling back to single segments\n",
- mmc_hostname(mmc),
- bounce_size);
- /*
- * Exiting with zero here makes sure we proceed with
- * mmc->max_segs == 1.
- */
- return;
- }
-
- host->bounce_addr = dma_map_single(mmc_dev(mmc),
- host->bounce_buffer,
- bounce_size,
- DMA_BIDIRECTIONAL);
- ret = dma_mapping_error(mmc_dev(mmc), host->bounce_addr);
- if (ret) {
- devm_kfree(mmc_dev(mmc), host->bounce_buffer);
- host->bounce_buffer = NULL;
- /* Again fall back to max_segs == 1 */
- return;
- }
-
- host->bounce_buffer_size = bounce_size;
-
- /* Lie about this since we're bouncing */
- mmc->max_segs = max_blocks;
- mmc->max_seg_size = bounce_size;
- mmc->max_req_size = bounce_size;
-
- pr_info("%s bounce up to %u segments into one, max segment size %u bytes\n",
- mmc_hostname(mmc), max_blocks, bounce_size);
-}
-
-static inline bool sdhci_can_64bit_dma(struct sdhci_host *host)
-{
- /*
- * According to SD Host Controller spec v4.10, bit[27] added from
- * version 4.10 in Capabilities Register is used as 64-bit System
- * Address support for V4 mode.
- */
- if (host->version >= SDHCI_SPEC_410 && host->v4_mode)
- return host->caps & SDHCI_CAN_64BIT_V4;
-
- return host->caps & SDHCI_CAN_64BIT;
-}
-
-int sdhci_setup_host(struct sdhci_host *host)
-{
- struct mmc_host *mmc;
- u32 max_current_caps;
- unsigned int ocr_avail;
- unsigned int override_timeout_clk;
- u32 max_clk;
- int ret = 0;
- bool enable_vqmmc = false;
-
- WARN_ON(host == NULL);
- if (host == NULL)
- return -EINVAL;
-
- mmc = host->mmc;
-
- /*
- * If there are external regulators, get them. Note this must be done
- * early before resetting the host and reading the capabilities so that
- * the host can take the appropriate action if regulators are not
- * available.
- */
- if (!mmc->supply.vqmmc) {
- ret = mmc_regulator_get_supply(mmc);
- if (ret)
- return ret;
- enable_vqmmc = true;
- }
-
- DBG("Version: 0x%08x | Present: 0x%08x\n",
- sdhci_readw(host, SDHCI_HOST_VERSION),
- sdhci_readl(host, SDHCI_PRESENT_STATE));
- DBG("Caps: 0x%08x | Caps_1: 0x%08x\n",
- sdhci_readl(host, SDHCI_CAPABILITIES),
- sdhci_readl(host, SDHCI_CAPABILITIES_1));
-
- sdhci_read_caps(host);
-
- override_timeout_clk = host->timeout_clk;
-
- if (host->version > SDHCI_SPEC_420) {
- pr_err("%s: Unknown controller version (%d). You may experience problems.\n",
- mmc_hostname(mmc), host->version);
- }
-
- if (host->quirks & SDHCI_QUIRK_FORCE_DMA)
- host->flags |= SDHCI_USE_SDMA;
- else if (!(host->caps & SDHCI_CAN_DO_SDMA))
- DBG("Controller doesn't have SDMA capability\n");
- else
- host->flags |= SDHCI_USE_SDMA;
-
- if ((host->quirks & SDHCI_QUIRK_BROKEN_DMA) &&
- (host->flags & SDHCI_USE_SDMA)) {
- DBG("Disabling DMA as it is marked broken\n");
- host->flags &= ~SDHCI_USE_SDMA;
- }
-
- if ((host->version >= SDHCI_SPEC_200) &&
- (host->caps & SDHCI_CAN_DO_ADMA2))
- host->flags |= SDHCI_USE_ADMA;
-
- if ((host->quirks & SDHCI_QUIRK_BROKEN_ADMA) &&
- (host->flags & SDHCI_USE_ADMA)) {
- DBG("Disabling ADMA as it is marked broken\n");
- host->flags &= ~SDHCI_USE_ADMA;
- }
-
- if (sdhci_can_64bit_dma(host))
- host->flags |= SDHCI_USE_64_BIT_DMA;
-
- if (host->use_external_dma) {
- ret = sdhci_external_dma_init(host);
- if (ret == -EPROBE_DEFER)
- goto unreg;
- /*
- * Fall back to use the DMA/PIO integrated in standard SDHCI
- * instead of external DMA devices.
- */
- else if (ret)
- sdhci_switch_external_dma(host, false);
- /* Disable internal DMA sources */
- else
- host->flags &= ~(SDHCI_USE_SDMA | SDHCI_USE_ADMA);
- }
-
- if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) {
- if (host->ops->set_dma_mask)
- ret = host->ops->set_dma_mask(host);
- else
- ret = sdhci_set_dma_mask(host);
-
- if (!ret && host->ops->enable_dma)
- ret = host->ops->enable_dma(host);
-
- if (ret) {
- pr_warn("%s: No suitable DMA available - falling back to PIO\n",
- mmc_hostname(mmc));
- host->flags &= ~(SDHCI_USE_SDMA | SDHCI_USE_ADMA);
-
- ret = 0;
- }
- }
-
- /* SDMA does not support 64-bit DMA if v4 mode not set */
- if ((host->flags & SDHCI_USE_64_BIT_DMA) && !host->v4_mode)
- host->flags &= ~SDHCI_USE_SDMA;
-
- if (host->flags & SDHCI_USE_ADMA) {
- dma_addr_t dma;
- void *buf;
-
- if (!(host->flags & SDHCI_USE_64_BIT_DMA))
- host->alloc_desc_sz = SDHCI_ADMA2_32_DESC_SZ;
- else if (!host->alloc_desc_sz)
- host->alloc_desc_sz = SDHCI_ADMA2_64_DESC_SZ(host);
-
- host->desc_sz = host->alloc_desc_sz;
- host->adma_table_sz = host->adma_table_cnt * host->desc_sz;
-
- host->align_buffer_sz = SDHCI_MAX_SEGS * SDHCI_ADMA2_ALIGN;
- /*
- * Use zalloc to zero the reserved high 32-bits of 128-bit
- * descriptors so that they never need to be written.
- */
- buf = dma_alloc_coherent(mmc_dev(mmc),
- host->align_buffer_sz + host->adma_table_sz,
- &dma, GFP_KERNEL);
- if (!buf) {
- pr_warn("%s: Unable to allocate ADMA buffers - falling back to standard DMA\n",
- mmc_hostname(mmc));
- host->flags &= ~SDHCI_USE_ADMA;
- } else if ((dma + host->align_buffer_sz) &
- (SDHCI_ADMA2_DESC_ALIGN - 1)) {
- pr_warn("%s: unable to allocate aligned ADMA descriptor\n",
- mmc_hostname(mmc));
- host->flags &= ~SDHCI_USE_ADMA;
- dma_free_coherent(mmc_dev(mmc), host->align_buffer_sz +
- host->adma_table_sz, buf, dma);
- } else {
- host->align_buffer = buf;
- host->align_addr = dma;
-
- host->adma_table = buf + host->align_buffer_sz;
- host->adma_addr = dma + host->align_buffer_sz;
- }
- }
-
- /*
- * If we use DMA, then it's up to the caller to set the DMA
- * mask, but PIO does not need the hw shim so we set a new
- * mask here in that case.
- */
- if (!(host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA))) {
- host->dma_mask = DMA_BIT_MASK(64);
- mmc_dev(mmc)->dma_mask = &host->dma_mask;
- }
-
- if (host->version >= SDHCI_SPEC_300)
- host->max_clk = FIELD_GET(SDHCI_CLOCK_V3_BASE_MASK, host->caps);
- else
- host->max_clk = FIELD_GET(SDHCI_CLOCK_BASE_MASK, host->caps);
-
- host->max_clk *= 1000000;
- if (host->max_clk == 0 || host->quirks &
- SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN) {
- if (!host->ops->get_max_clock) {
- pr_err("%s: Hardware doesn't specify base clock frequency.\n",
- mmc_hostname(mmc));
- ret = -ENODEV;
- goto undma;
- }
- host->max_clk = host->ops->get_max_clock(host);
- }
-
- /*
- * In case of Host Controller v3.00, find out whether clock
- * multiplier is supported.
- */
- host->clk_mul = FIELD_GET(SDHCI_CLOCK_MUL_MASK, host->caps1);
-
- /*
- * In case the value in Clock Multiplier is 0, then programmable
- * clock mode is not supported, otherwise the actual clock
- * multiplier is one more than the value of Clock Multiplier
- * in the Capabilities Register.
- */
- if (host->clk_mul)
- host->clk_mul += 1;
-
- /*
- * Set host parameters.
- */
- max_clk = host->max_clk;
-
- if (host->ops->get_min_clock)
- mmc->f_min = host->ops->get_min_clock(host);
- else if (host->version >= SDHCI_SPEC_300) {
- if (host->clk_mul)
- max_clk = host->max_clk * host->clk_mul;
- /*
- * Divided Clock Mode minimum clock rate is always less than
- * Programmable Clock Mode minimum clock rate.
- */
- mmc->f_min = host->max_clk / SDHCI_MAX_DIV_SPEC_300;
- } else
- mmc->f_min = host->max_clk / SDHCI_MAX_DIV_SPEC_200;
-
- if (!mmc->f_max || mmc->f_max > max_clk)
- mmc->f_max = max_clk;
-
- if (!(host->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK)) {
- host->timeout_clk = FIELD_GET(SDHCI_TIMEOUT_CLK_MASK, host->caps);
-
- if (host->caps & SDHCI_TIMEOUT_CLK_UNIT)
- host->timeout_clk *= 1000;
-
- if (host->timeout_clk == 0) {
- if (!host->ops->get_timeout_clock) {
- pr_err("%s: Hardware doesn't specify timeout clock frequency.\n",
- mmc_hostname(mmc));
- ret = -ENODEV;
- goto undma;
- }
-
- host->timeout_clk =
- DIV_ROUND_UP(host->ops->get_timeout_clock(host),
- 1000);
- }
-
- if (override_timeout_clk)
- host->timeout_clk = override_timeout_clk;
-
- mmc->max_busy_timeout = host->ops->get_max_timeout_count ?
- host->ops->get_max_timeout_count(host) : 1 << 27;
- mmc->max_busy_timeout /= host->timeout_clk;
- }
-
- if (host->quirks2 & SDHCI_QUIRK2_DISABLE_HW_TIMEOUT &&
- !host->ops->get_max_timeout_count)
- mmc->max_busy_timeout = 0;
-
- mmc->caps |= MMC_CAP_SDIO_IRQ | MMC_CAP_CMD23;
- mmc->caps2 |= MMC_CAP2_SDIO_IRQ_NOTHREAD;
-
- if (host->quirks & SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12)
- host->flags |= SDHCI_AUTO_CMD12;
-
- /*
- * For v3 mode, Auto-CMD23 stuff only works in ADMA or PIO.
- * For v4 mode, SDMA may use Auto-CMD23 as well.
- */
- if ((host->version >= SDHCI_SPEC_300) &&
- ((host->flags & SDHCI_USE_ADMA) ||
- !(host->flags & SDHCI_USE_SDMA) || host->v4_mode) &&
- !(host->quirks2 & SDHCI_QUIRK2_ACMD23_BROKEN)) {
- host->flags |= SDHCI_AUTO_CMD23;
- DBG("Auto-CMD23 available\n");
- } else {
- DBG("Auto-CMD23 unavailable\n");
- }
-
- /*
- * A controller may support 8-bit width, but the board itself
- * might not have the pins brought out. Boards that support
- * 8-bit width must set "mmc->caps |= MMC_CAP_8_BIT_DATA;" in
- * their platform code before calling sdhci_add_host(), and we
- * won't assume 8-bit width for hosts without that CAP.
- */
- if (!(host->quirks & SDHCI_QUIRK_FORCE_1_BIT_DATA))
- mmc->caps |= MMC_CAP_4_BIT_DATA;
-
- if (host->quirks2 & SDHCI_QUIRK2_HOST_NO_CMD23)
- mmc->caps &= ~MMC_CAP_CMD23;
-
- if (host->caps & SDHCI_CAN_DO_HISPD)
- mmc->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED;
-
- if ((host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) &&
- mmc_card_is_removable(mmc) &&
- mmc_gpio_get_cd(mmc) < 0)
- mmc->caps |= MMC_CAP_NEEDS_POLL;
-
- if (!IS_ERR(mmc->supply.vqmmc)) {
- if (enable_vqmmc) {
- ret = regulator_enable(mmc->supply.vqmmc);
- host->sdhci_core_to_disable_vqmmc = !ret;
- }
-
- /* If vqmmc provides no 1.8V signalling, then there's no UHS */
- if (!regulator_is_supported_voltage(mmc->supply.vqmmc, 1700000,
- 1950000))
- host->caps1 &= ~(SDHCI_SUPPORT_SDR104 |
- SDHCI_SUPPORT_SDR50 |
- SDHCI_SUPPORT_DDR50);
-
- /* In eMMC case vqmmc might be a fixed 1.8V regulator */
- if (!regulator_is_supported_voltage(mmc->supply.vqmmc, 2700000,
- 3600000))
- host->flags &= ~SDHCI_SIGNALING_330;
-
- if (ret) {
- pr_warn("%s: Failed to enable vqmmc regulator: %d\n",
- mmc_hostname(mmc), ret);
- mmc->supply.vqmmc = ERR_PTR(-EINVAL);
- }
-
- }
-
- if (host->quirks2 & SDHCI_QUIRK2_NO_1_8_V) {
- host->caps1 &= ~(SDHCI_SUPPORT_SDR104 | SDHCI_SUPPORT_SDR50 |
- SDHCI_SUPPORT_DDR50);
- /*
- * The SDHCI controller in a SoC might support HS200/HS400
- * (indicated using mmc-hs200-1_8v/mmc-hs400-1_8v dt property),
- * but if the board is modeled such that the IO lines are not
- * connected to 1.8v then HS200/HS400 cannot be supported.
- * Disable HS200/HS400 if the board does not have 1.8v connected
- * to the IO lines. (Applicable for other modes in 1.8v)
- */
- mmc->caps2 &= ~(MMC_CAP2_HSX00_1_8V | MMC_CAP2_HS400_ES);
- mmc->caps &= ~(MMC_CAP_1_8V_DDR | MMC_CAP_UHS);
- }
-
- /* Any UHS-I mode in caps implies SDR12 and SDR25 support. */
- if (host->caps1 & (SDHCI_SUPPORT_SDR104 | SDHCI_SUPPORT_SDR50 |
- SDHCI_SUPPORT_DDR50))
- mmc->caps |= MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25;
-
- /* SDR104 supports also implies SDR50 support */
- if (host->caps1 & SDHCI_SUPPORT_SDR104) {
- mmc->caps |= MMC_CAP_UHS_SDR104 | MMC_CAP_UHS_SDR50;
- /* SD3.0: SDR104 is supported so (for eMMC) the caps2
- * field can be promoted to support HS200.
- */
- if (!(host->quirks2 & SDHCI_QUIRK2_BROKEN_HS200))
- mmc->caps2 |= MMC_CAP2_HS200;
- } else if (host->caps1 & SDHCI_SUPPORT_SDR50) {
- mmc->caps |= MMC_CAP_UHS_SDR50;
- }
-
- if (host->quirks2 & SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400 &&
- (host->caps1 & SDHCI_SUPPORT_HS400))
- mmc->caps2 |= MMC_CAP2_HS400;
-
- if ((mmc->caps2 & MMC_CAP2_HSX00_1_2V) &&
- (IS_ERR(mmc->supply.vqmmc) ||
- !regulator_is_supported_voltage(mmc->supply.vqmmc, 1100000,
- 1300000)))
- mmc->caps2 &= ~MMC_CAP2_HSX00_1_2V;
-
- if ((host->caps1 & SDHCI_SUPPORT_DDR50) &&
- !(host->quirks2 & SDHCI_QUIRK2_BROKEN_DDR50))
- mmc->caps |= MMC_CAP_UHS_DDR50;
-
- /* Does the host need tuning for SDR50? */
- if (host->caps1 & SDHCI_USE_SDR50_TUNING)
- host->flags |= SDHCI_SDR50_NEEDS_TUNING;
-
- /* Driver Type(s) (A, C, D) supported by the host */
- if (host->caps1 & SDHCI_DRIVER_TYPE_A)
- mmc->caps |= MMC_CAP_DRIVER_TYPE_A;
- if (host->caps1 & SDHCI_DRIVER_TYPE_C)
- mmc->caps |= MMC_CAP_DRIVER_TYPE_C;
- if (host->caps1 & SDHCI_DRIVER_TYPE_D)
- mmc->caps |= MMC_CAP_DRIVER_TYPE_D;
-
- /* Initial value for re-tuning timer count */
- host->tuning_count = FIELD_GET(SDHCI_RETUNING_TIMER_COUNT_MASK,
- host->caps1);
-
- /*
- * In case Re-tuning Timer is not disabled, the actual value of
- * re-tuning timer will be 2 ^ (n - 1).
- */
- if (host->tuning_count)
- host->tuning_count = 1 << (host->tuning_count - 1);
-
- /* Re-tuning mode supported by the Host Controller */
- host->tuning_mode = FIELD_GET(SDHCI_RETUNING_MODE_MASK, host->caps1);
-
- ocr_avail = 0;
-
- /*
- * According to SD Host Controller spec v3.00, if the Host System
- * can afford more than 150mA, Host Driver should set XPC to 1. Also
- * the value is meaningful only if Voltage Support in the Capabilities
- * register is set. The actual current value is 4 times the register
- * value.
- */
- max_current_caps = sdhci_readl(host, SDHCI_MAX_CURRENT);
- if (!max_current_caps && !IS_ERR(mmc->supply.vmmc)) {
- int curr = regulator_get_current_limit(mmc->supply.vmmc);
- if (curr > 0) {
-
- /* convert to SDHCI_MAX_CURRENT format */
- curr = curr/1000; /* convert to mA */
- curr = curr/SDHCI_MAX_CURRENT_MULTIPLIER;
-
- curr = min_t(u32, curr, SDHCI_MAX_CURRENT_LIMIT);
- max_current_caps =
- FIELD_PREP(SDHCI_MAX_CURRENT_330_MASK, curr) |
- FIELD_PREP(SDHCI_MAX_CURRENT_300_MASK, curr) |
- FIELD_PREP(SDHCI_MAX_CURRENT_180_MASK, curr);
- }
- }
-
- if (host->caps & SDHCI_CAN_VDD_330) {
- ocr_avail |= MMC_VDD_32_33 | MMC_VDD_33_34;
-
- mmc->max_current_330 = FIELD_GET(SDHCI_MAX_CURRENT_330_MASK,
- max_current_caps) *
- SDHCI_MAX_CURRENT_MULTIPLIER;
- }
- if (host->caps & SDHCI_CAN_VDD_300) {
- ocr_avail |= MMC_VDD_29_30 | MMC_VDD_30_31;
-
- mmc->max_current_300 = FIELD_GET(SDHCI_MAX_CURRENT_300_MASK,
- max_current_caps) *
- SDHCI_MAX_CURRENT_MULTIPLIER;
- }
- if (host->caps & SDHCI_CAN_VDD_180) {
- ocr_avail |= MMC_VDD_165_195;
-
- mmc->max_current_180 = FIELD_GET(SDHCI_MAX_CURRENT_180_MASK,
- max_current_caps) *
- SDHCI_MAX_CURRENT_MULTIPLIER;
- }
-
- /* If OCR set by host, use it instead. */
- if (host->ocr_mask)
- ocr_avail = host->ocr_mask;
-
- /* If OCR set by external regulators, give it highest prio. */
- if (mmc->ocr_avail)
- ocr_avail = mmc->ocr_avail;
-
- mmc->ocr_avail = ocr_avail;
- mmc->ocr_avail_sdio = ocr_avail;
- if (host->ocr_avail_sdio)
- mmc->ocr_avail_sdio &= host->ocr_avail_sdio;
- mmc->ocr_avail_sd = ocr_avail;
- if (host->ocr_avail_sd)
- mmc->ocr_avail_sd &= host->ocr_avail_sd;
- else /* normal SD controllers don't support 1.8V */
- mmc->ocr_avail_sd &= ~MMC_VDD_165_195;
- mmc->ocr_avail_mmc = ocr_avail;
- if (host->ocr_avail_mmc)
- mmc->ocr_avail_mmc &= host->ocr_avail_mmc;
-
- if (mmc->ocr_avail == 0) {
- pr_err("%s: Hardware doesn't report any support voltages.\n",
- mmc_hostname(mmc));
- ret = -ENODEV;
- goto unreg;
- }
-
- if ((mmc->caps & (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 |
- MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 |
- MMC_CAP_UHS_DDR50 | MMC_CAP_1_8V_DDR)) ||
- (mmc->caps2 & (MMC_CAP2_HS200_1_8V_SDR | MMC_CAP2_HS400_1_8V)))
- host->flags |= SDHCI_SIGNALING_180;
-
- if (mmc->caps2 & MMC_CAP2_HSX00_1_2V)
- host->flags |= SDHCI_SIGNALING_120;
-
- spin_lock_init(&host->lock);
-
- /*
- * Maximum number of sectors in one transfer. Limited by SDMA boundary
- * size (512KiB). Note some tuning modes impose a 4MiB limit, but this
- * is less anyway.
- */
- mmc->max_req_size = 524288;
-
- /*
- * Maximum number of segments. Depends on if the hardware
- * can do scatter/gather or not.
- */
- if (host->flags & SDHCI_USE_ADMA) {
- mmc->max_segs = SDHCI_MAX_SEGS;
- } else if (host->flags & SDHCI_USE_SDMA) {
- mmc->max_segs = 1;
- mmc->max_req_size = min_t(size_t, mmc->max_req_size,
- dma_max_mapping_size(mmc_dev(mmc)));
- } else { /* PIO */
- mmc->max_segs = SDHCI_MAX_SEGS;
- }
-
- /*
- * Maximum segment size. Could be one segment with the maximum number
- * of bytes. When doing hardware scatter/gather, each entry cannot
- * be larger than 64 KiB though.
- */
- if (host->flags & SDHCI_USE_ADMA) {
- if (host->quirks & SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC) {
- host->max_adma = 65532; /* 32-bit alignment */
- mmc->max_seg_size = 65535;
- } else {
- mmc->max_seg_size = 65536;
- }
- } else {
- mmc->max_seg_size = mmc->max_req_size;
- }
-
- /*
- * Maximum block size. This varies from controller to controller and
- * is specified in the capabilities register.
- */
- if (host->quirks & SDHCI_QUIRK_FORCE_BLK_SZ_2048) {
- mmc->max_blk_size = 2;
- } else {
- mmc->max_blk_size = (host->caps & SDHCI_MAX_BLOCK_MASK) >>
- SDHCI_MAX_BLOCK_SHIFT;
- if (mmc->max_blk_size >= 3) {
- pr_warn("%s: Invalid maximum block size, assuming 512 bytes\n",
- mmc_hostname(mmc));
- mmc->max_blk_size = 0;
- }
- }
-
- mmc->max_blk_size = 512 << mmc->max_blk_size;
-
- /*
- * Maximum block count.
- */
- mmc->max_blk_count = (host->quirks & SDHCI_QUIRK_NO_MULTIBLOCK) ? 1 : 65535;
-
- if (mmc->max_segs == 1)
- /* This may alter mmc->*_blk_* parameters */
- sdhci_allocate_bounce_buffer(host);
-
- return 0;
-
-unreg:
- if (host->sdhci_core_to_disable_vqmmc)
- regulator_disable(mmc->supply.vqmmc);
-undma:
- if (host->align_buffer)
- dma_free_coherent(mmc_dev(mmc), host->align_buffer_sz +
- host->adma_table_sz, host->align_buffer,
- host->align_addr);
- host->adma_table = NULL;
- host->align_buffer = NULL;
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(sdhci_setup_host);
-
-void sdhci_cleanup_host(struct sdhci_host *host)
-{
- struct mmc_host *mmc = host->mmc;
-
- if (host->sdhci_core_to_disable_vqmmc)
- regulator_disable(mmc->supply.vqmmc);
-
- if (host->align_buffer)
- dma_free_coherent(mmc_dev(mmc), host->align_buffer_sz +
- host->adma_table_sz, host->align_buffer,
- host->align_addr);
-
- if (host->use_external_dma)
- sdhci_external_dma_release(host);
-
- host->adma_table = NULL;
- host->align_buffer = NULL;
-}
-EXPORT_SYMBOL_GPL(sdhci_cleanup_host);
-
-int __sdhci_add_host(struct sdhci_host *host)
-{
- unsigned int flags = WQ_UNBOUND | WQ_MEM_RECLAIM | WQ_HIGHPRI;
- struct mmc_host *mmc = host->mmc;
- int ret;
-
- if ((mmc->caps2 & MMC_CAP2_CQE) &&
- (host->quirks & SDHCI_QUIRK_BROKEN_CQE)) {
- mmc->caps2 &= ~MMC_CAP2_CQE;
- mmc->cqe_ops = NULL;
- }
-
- host->complete_wq = alloc_workqueue("sdhci", flags, 0);
- if (!host->complete_wq)
- return -ENOMEM;
-
- INIT_WORK(&host->complete_work, sdhci_complete_work);
-
- timer_setup(&host->timer, sdhci_timeout_timer, 0);
- timer_setup(&host->data_timer, sdhci_timeout_data_timer, 0);
-
- init_waitqueue_head(&host->buf_ready_int);
-
- sdhci_init(host, 0);
-
- ret = request_threaded_irq(host->irq, sdhci_irq, sdhci_thread_irq,
- IRQF_SHARED, mmc_hostname(mmc), host);
- if (ret) {
- pr_err("%s: Failed to request IRQ %d: %d\n",
- mmc_hostname(mmc), host->irq, ret);
- goto unwq;
- }
-
- ret = sdhci_led_register(host);
- if (ret) {
- pr_err("%s: Failed to register LED device: %d\n",
- mmc_hostname(mmc), ret);
- goto unirq;
- }
-
- ret = mmc_add_host(mmc);
- if (ret)
- goto unled;
-
- pr_info("%s: SDHCI controller on %s [%s] using %s\n",
- mmc_hostname(mmc), host->hw_name, dev_name(mmc_dev(mmc)),
- host->use_external_dma ? "External DMA" :
- (host->flags & SDHCI_USE_ADMA) ?
- (host->flags & SDHCI_USE_64_BIT_DMA) ? "ADMA 64-bit" : "ADMA" :
- (host->flags & SDHCI_USE_SDMA) ? "DMA" : "PIO");
-
- sdhci_enable_card_detection(host);
-
- return 0;
-
-unled:
- sdhci_led_unregister(host);
-unirq:
- sdhci_do_reset(host, SDHCI_RESET_ALL);
- sdhci_writel(host, 0, SDHCI_INT_ENABLE);
- sdhci_writel(host, 0, SDHCI_SIGNAL_ENABLE);
- free_irq(host->irq, host);
-unwq:
- destroy_workqueue(host->complete_wq);
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(__sdhci_add_host);
-
-int sdhci_add_host(struct sdhci_host *host)
-{
- int ret;
-
- ret = sdhci_setup_host(host);
- if (ret)
- return ret;
-
- ret = __sdhci_add_host(host);
- if (ret)
- goto cleanup;
-
- return 0;
-
-cleanup:
- sdhci_cleanup_host(host);
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(sdhci_add_host);
-
-void sdhci_remove_host(struct sdhci_host *host, int dead)
-{
- struct mmc_host *mmc = host->mmc;
- unsigned long flags;
-
- if (dead) {
- spin_lock_irqsave(&host->lock, flags);
-
- host->flags |= SDHCI_DEVICE_DEAD;
-
- if (sdhci_has_requests(host)) {
- pr_err("%s: Controller removed during "
- " transfer!\n", mmc_hostname(mmc));
- sdhci_error_out_mrqs(host, -ENOMEDIUM);
- }
-
- spin_unlock_irqrestore(&host->lock, flags);
- }
-
- sdhci_disable_card_detection(host);
-
- mmc_remove_host(mmc);
-
- sdhci_led_unregister(host);
-
- if (!dead)
- sdhci_do_reset(host, SDHCI_RESET_ALL);
-
- sdhci_writel(host, 0, SDHCI_INT_ENABLE);
- sdhci_writel(host, 0, SDHCI_SIGNAL_ENABLE);
- free_irq(host->irq, host);
-
- del_timer_sync(&host->timer);
- del_timer_sync(&host->data_timer);
-
- destroy_workqueue(host->complete_wq);
-
- if (host->sdhci_core_to_disable_vqmmc)
- regulator_disable(mmc->supply.vqmmc);
-
- if (host->align_buffer)
- dma_free_coherent(mmc_dev(mmc), host->align_buffer_sz +
- host->adma_table_sz, host->align_buffer,
- host->align_addr);
-
- if (host->use_external_dma)
- sdhci_external_dma_release(host);
-
- host->adma_table = NULL;
- host->align_buffer = NULL;
-}
-
-EXPORT_SYMBOL_GPL(sdhci_remove_host);
-
-void sdhci_free_host(struct sdhci_host *host)
-{
- mmc_free_host(host->mmc);
-}
-
-EXPORT_SYMBOL_GPL(sdhci_free_host);
-
-/*****************************************************************************\
- * *
- * Driver init/exit *
- * *
-\*****************************************************************************/
-
-static int __init sdhci_drv_init(void)
-{
- pr_info(DRIVER_NAME
- ": Secure Digital Host Controller Interface driver\n");
- pr_info(DRIVER_NAME ": Copyright(c) Pierre Ossman\n");
-
- return 0;
-}
-
-static void __exit sdhci_drv_exit(void)
-{
-}
-
-module_init(sdhci_drv_init);
-module_exit(sdhci_drv_exit);
-
-module_param(debug_quirks, uint, 0444);
-module_param(debug_quirks2, uint, 0444);
-
-MODULE_AUTHOR("Pierre Ossman <pierre@ossman.eu>");
-MODULE_DESCRIPTION("Secure Digital Host Controller Interface core driver");
-MODULE_LICENSE("GPL");
-
-MODULE_PARM_DESC(debug_quirks, "Force certain quirks.");
-MODULE_PARM_DESC(debug_quirks2, "Force certain other quirks.");
Index: v6.x/create-6.0.7-sdhci-reset-patch/linux-6.0.7-new/drivers/mmc/host
===================================================================
--- v6.x/create-6.0.7-sdhci-reset-patch/linux-6.0.7-new/drivers/mmc/host (revision 384)
+++ v6.x/create-6.0.7-sdhci-reset-patch/linux-6.0.7-new/drivers/mmc/host (nonexistent)
Property changes on: v6.x/create-6.0.7-sdhci-reset-patch/linux-6.0.7-new/drivers/mmc/host
___________________________________________________________________
Deleted: svn:ignore
## -1,73 +0,0 ##
-
-# install dir
-dist
-
-# Target build dirs
-.a1x-newlib
-.a2x-newlib
-.at91sam7s-newlib
-
-.build-machine
-
-.a1x-glibc
-.a2x-glibc
-.h3-glibc
-.h5-glibc
-.i586-glibc
-.i686-glibc
-.imx6-glibc
-.jz47xx-glibc
-.makefile
-.am335x-glibc
-.omap543x-glibc
-.p5600-glibc
-.power8-glibc
-.power8le-glibc
-.power9-glibc
-.power9le-glibc
-.m1000-glibc
-.riscv64-glibc
-.rk328x-glibc
-.rk33xx-glibc
-.rk339x-glibc
-.s8xx-glibc
-.s9xx-glibc
-.x86_64-glibc
-
-# Hidden files (each file)
-.makefile
-.dist
-.rootfs
-
-# src & hw requires
-.src_requires
-.src_requires_depend
-.requires
-.requires_depend
-
-# Tarballs
-*.gz
-*.bz2
-*.lz
-*.xz
-*.tgz
-*.txz
-
-# Signatures
-*.asc
-*.sig
-*.sign
-*.sha1sum
-
-# Patches
-*.patch
-
-# Descriptions
-*.dsc
-*.txt
-
-# Default linux config files
-*.defconfig
-
-# backup copies
-*~
Index: v6.x/create-6.0.7-sdhci-reset-patch/linux-6.0.7-new/drivers/mmc
===================================================================
--- v6.x/create-6.0.7-sdhci-reset-patch/linux-6.0.7-new/drivers/mmc (revision 384)
+++ v6.x/create-6.0.7-sdhci-reset-patch/linux-6.0.7-new/drivers/mmc (nonexistent)
Property changes on: v6.x/create-6.0.7-sdhci-reset-patch/linux-6.0.7-new/drivers/mmc
___________________________________________________________________
Deleted: svn:ignore
## -1,73 +0,0 ##
-
-# install dir
-dist
-
-# Target build dirs
-.a1x-newlib
-.a2x-newlib
-.at91sam7s-newlib
-
-.build-machine
-
-.a1x-glibc
-.a2x-glibc
-.h3-glibc
-.h5-glibc
-.i586-glibc
-.i686-glibc
-.imx6-glibc
-.jz47xx-glibc
-.makefile
-.am335x-glibc
-.omap543x-glibc
-.p5600-glibc
-.power8-glibc
-.power8le-glibc
-.power9-glibc
-.power9le-glibc
-.m1000-glibc
-.riscv64-glibc
-.rk328x-glibc
-.rk33xx-glibc
-.rk339x-glibc
-.s8xx-glibc
-.s9xx-glibc
-.x86_64-glibc
-
-# Hidden files (each file)
-.makefile
-.dist
-.rootfs
-
-# src & hw requires
-.src_requires
-.src_requires_depend
-.requires
-.requires_depend
-
-# Tarballs
-*.gz
-*.bz2
-*.lz
-*.xz
-*.tgz
-*.txz
-
-# Signatures
-*.asc
-*.sig
-*.sign
-*.sha1sum
-
-# Patches
-*.patch
-
-# Descriptions
-*.dsc
-*.txt
-
-# Default linux config files
-*.defconfig
-
-# backup copies
-*~
Index: v6.x/create-6.0.7-sdhci-reset-patch/linux-6.0.7-new/drivers
===================================================================
--- v6.x/create-6.0.7-sdhci-reset-patch/linux-6.0.7-new/drivers (revision 384)
+++ v6.x/create-6.0.7-sdhci-reset-patch/linux-6.0.7-new/drivers (nonexistent)
Property changes on: v6.x/create-6.0.7-sdhci-reset-patch/linux-6.0.7-new/drivers
___________________________________________________________________
Deleted: svn:ignore
## -1,73 +0,0 ##
-
-# install dir
-dist
-
-# Target build dirs
-.a1x-newlib
-.a2x-newlib
-.at91sam7s-newlib
-
-.build-machine
-
-.a1x-glibc
-.a2x-glibc
-.h3-glibc
-.h5-glibc
-.i586-glibc
-.i686-glibc
-.imx6-glibc
-.jz47xx-glibc
-.makefile
-.am335x-glibc
-.omap543x-glibc
-.p5600-glibc
-.power8-glibc
-.power8le-glibc
-.power9-glibc
-.power9le-glibc
-.m1000-glibc
-.riscv64-glibc
-.rk328x-glibc
-.rk33xx-glibc
-.rk339x-glibc
-.s8xx-glibc
-.s9xx-glibc
-.x86_64-glibc
-
-# Hidden files (each file)
-.makefile
-.dist
-.rootfs
-
-# src & hw requires
-.src_requires
-.src_requires_depend
-.requires
-.requires_depend
-
-# Tarballs
-*.gz
-*.bz2
-*.lz
-*.xz
-*.tgz
-*.txz
-
-# Signatures
-*.asc
-*.sig
-*.sign
-*.sha1sum
-
-# Patches
-*.patch
-
-# Descriptions
-*.dsc
-*.txt
-
-# Default linux config files
-*.defconfig
-
-# backup copies
-*~
Index: v6.x/create-6.0.7-sdhci-reset-patch/linux-6.0.7-new
===================================================================
--- v6.x/create-6.0.7-sdhci-reset-patch/linux-6.0.7-new (revision 384)
+++ v6.x/create-6.0.7-sdhci-reset-patch/linux-6.0.7-new (nonexistent)
Property changes on: v6.x/create-6.0.7-sdhci-reset-patch/linux-6.0.7-new
___________________________________________________________________
Deleted: svn:ignore
## -1,73 +0,0 ##
-
-# install dir
-dist
-
-# Target build dirs
-.a1x-newlib
-.a2x-newlib
-.at91sam7s-newlib
-
-.build-machine
-
-.a1x-glibc
-.a2x-glibc
-.h3-glibc
-.h5-glibc
-.i586-glibc
-.i686-glibc
-.imx6-glibc
-.jz47xx-glibc
-.makefile
-.am335x-glibc
-.omap543x-glibc
-.p5600-glibc
-.power8-glibc
-.power8le-glibc
-.power9-glibc
-.power9le-glibc
-.m1000-glibc
-.riscv64-glibc
-.rk328x-glibc
-.rk33xx-glibc
-.rk339x-glibc
-.s8xx-glibc
-.s9xx-glibc
-.x86_64-glibc
-
-# Hidden files (each file)
-.makefile
-.dist
-.rootfs
-
-# src & hw requires
-.src_requires
-.src_requires_depend
-.requires
-.requires_depend
-
-# Tarballs
-*.gz
-*.bz2
-*.lz
-*.xz
-*.tgz
-*.txz
-
-# Signatures
-*.asc
-*.sig
-*.sign
-*.sha1sum
-
-# Patches
-*.patch
-
-# Descriptions
-*.dsc
-*.txt
-
-# Default linux config files
-*.defconfig
-
-# backup copies
-*~
Index: v6.x/create-6.0.7-sdhci-reset-patch
===================================================================
--- v6.x/create-6.0.7-sdhci-reset-patch (revision 384)
+++ v6.x/create-6.0.7-sdhci-reset-patch (nonexistent)
Property changes on: v6.x/create-6.0.7-sdhci-reset-patch
___________________________________________________________________
Deleted: svn:ignore
## -1,73 +0,0 ##
-
-# install dir
-dist
-
-# Target build dirs
-.a1x-newlib
-.a2x-newlib
-.at91sam7s-newlib
-
-.build-machine
-
-.a1x-glibc
-.a2x-glibc
-.h3-glibc
-.h5-glibc
-.i586-glibc
-.i686-glibc
-.imx6-glibc
-.jz47xx-glibc
-.makefile
-.am335x-glibc
-.omap543x-glibc
-.p5600-glibc
-.power8-glibc
-.power8le-glibc
-.power9-glibc
-.power9le-glibc
-.m1000-glibc
-.riscv64-glibc
-.rk328x-glibc
-.rk33xx-glibc
-.rk339x-glibc
-.s8xx-glibc
-.s9xx-glibc
-.x86_64-glibc
-
-# Hidden files (each file)
-.makefile
-.dist
-.rootfs
-
-# src & hw requires
-.src_requires
-.src_requires_depend
-.requires
-.requires_depend
-
-# Tarballs
-*.gz
-*.bz2
-*.lz
-*.xz
-*.tgz
-*.txz
-
-# Signatures
-*.asc
-*.sig
-*.sign
-*.sha1sum
-
-# Patches
-*.patch
-
-# Descriptions
-*.dsc
-*.txt
-
-# Default linux config files
-*.defconfig
-
-# backup copies
-*~
Index: v6.x/Makefile
===================================================================
--- v6.x/Makefile (revision 384)
+++ v6.x/Makefile (revision 385)
@@ -7,15 +7,16 @@
url = $(DOWNLOAD_SERVER)/sources/Linux/v6.x
-versions = 6.0.7
+versions = 6.1.53
tarballs = $(addsuffix .tar.xz, $(addprefix linux-, $(versions)))
sha1s = $(addsuffix .sha1sum, $(tarballs))
-patches = $(CURDIR)/patches/linux-6.0.7-dwmac-rk3399.patch
-patches += $(CURDIR)/patches/linux-6.0.7-host-limits.patch
-patches += $(CURDIR)/patches/linux-6.0.7-sdhci-reset.patch
-patches += $(CURDIR)/patches/linux-6.0.7-leez-p710-spi.patch
+patches = $(CURDIR)/patches/linux-6.1.53-dwmac-rk.patch
+patches += $(CURDIR)/patches/linux-6.1.53-host-limits.patch
+patches += $(CURDIR)/patches/linux-6.1.53-sdhci-reset.patch
+patches += $(CURDIR)/patches/linux-6.1.53-leez-p710-spi.patch
+patches += $(CURDIR)/patches/linux-6.1.53-repka-pi3.patch
.NOTPARALLEL: $(patches)
@@ -50,10 +51,11 @@
$(patches): $(sha1s)
@echo -e "\n======= Create Patches =======\n" ; \
- ( cd create-6.0.7-dwmac-rk3399-patch ; ./create.patch.sh ) ; \
- ( cd create-6.0.7-host-limits-patch ; ./create.patch.sh ) ; \
- ( cd create-6.0.7-sdhci-reset-patch ; ./create.patch.sh ) ; \
- ( cd create-6.0.7-leez-p710-spi-patch ; ./create.patch.sh ) ; \
+ ( cd create-6.1.53-dwmac-rk-patch ; ./create.patch.sh ) ; \
+ ( cd create-6.1.53-host-limits-patch ; ./create.patch.sh ) ; \
+ ( cd create-6.1.53-sdhci-reset-patch ; ./create.patch.sh ) ; \
+ ( cd create-6.1.53-leez-p710-spi-patch ; ./create.patch.sh ) ; \
+ ( cd create-6.1.53-repka-pi3-patch ; ./create.patch.sh ) ; \
echo -e "\n"
download_clean:
Index: v6.x/create-6.1.53-dwmac-rk-patch/create.patch.sh
===================================================================
--- v6.x/create-6.1.53-dwmac-rk-patch/create.patch.sh (nonexistent)
+++ v6.x/create-6.1.53-dwmac-rk-patch/create.patch.sh (revision 385)
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+VERSION=6.1.53
+
+tar --files-from=file.list -xJvf ../linux-$VERSION.tar.xz
+mv linux-$VERSION linux-$VERSION-orig
+
+cp -rf ./linux-$VERSION-new ./linux-$VERSION
+
+diff --unified -Nr linux-$VERSION-orig linux-$VERSION > linux-$VERSION-dwmac-rk.patch
+
+mv linux-$VERSION-dwmac-rk.patch ../patches
+
+rm -rf ./linux-$VERSION
+rm -rf ./linux-$VERSION-orig
Property changes on: v6.x/create-6.1.53-dwmac-rk-patch/create.patch.sh
___________________________________________________________________
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: v6.x/create-6.1.53-dwmac-rk-patch/file.list
===================================================================
--- v6.x/create-6.1.53-dwmac-rk-patch/file.list (nonexistent)
+++ v6.x/create-6.1.53-dwmac-rk-patch/file.list (revision 385)
@@ -0,0 +1 @@
+linux-6.1.53/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
Index: v6.x/create-6.1.53-dwmac-rk-patch/linux-6.1.53-new/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
===================================================================
--- v6.x/create-6.1.53-dwmac-rk-patch/linux-6.1.53-new/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c (nonexistent)
+++ v6.x/create-6.1.53-dwmac-rk-patch/linux-6.1.53-new/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c (revision 385)
@@ -0,0 +1,1942 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/**
+ * DOC: dwmac-rk.c - Rockchip RK3288 DWMAC specific glue layer
+ *
+ * Copyright (C) 2014 Chen-Zhi (Roger Chen)
+ *
+ * Chen-Zhi (Roger Chen) <roger.chen@rock-chips.com>
+ */
+
+#include <linux/stmmac.h>
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/phy.h>
+#include <linux/of_net.h>
+#include <linux/gpio.h>
+#include <linux/module.h>
+#include <linux/of_gpio.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/delay.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
+#include <linux/pm_runtime.h>
+
+#include "stmmac_platform.h"
+
+struct rk_priv_data;
+struct rk_gmac_ops {
+ void (*set_to_rgmii)(struct rk_priv_data *bsp_priv,
+ int tx_delay, int rx_delay);
+ void (*set_to_rmii)(struct rk_priv_data *bsp_priv);
+ void (*set_rgmii_speed)(struct rk_priv_data *bsp_priv, int speed);
+ void (*set_rmii_speed)(struct rk_priv_data *bsp_priv, int speed);
+ void (*set_clock_selection)(struct rk_priv_data *bsp_priv, bool input,
+ bool enable);
+ void (*integrated_phy_powerup)(struct rk_priv_data *bsp_priv);
+ bool regs_valid;
+ u32 regs[];
+};
+
+static const char * const rk_clocks[] = {
+ "aclk_mac", "pclk_mac", "mac_clk_tx", "clk_mac_speed",
+};
+
+static const char * const rk_rmii_clocks[] = {
+ "mac_clk_rx", "clk_mac_ref", "clk_mac_refout",
+};
+
+enum rk_clocks_index {
+ RK_ACLK_MAC = 0,
+ RK_PCLK_MAC,
+ RK_MAC_CLK_TX,
+ RK_CLK_MAC_SPEED,
+ RK_MAC_CLK_RX,
+ RK_CLK_MAC_REF,
+ RK_CLK_MAC_REFOUT,
+};
+
+struct rk_priv_data {
+ struct platform_device *pdev;
+ phy_interface_t phy_iface;
+ int id;
+ struct regulator *regulator;
+ bool suspended;
+ const struct rk_gmac_ops *ops;
+
+ bool clk_enabled;
+ bool clock_input;
+ bool integrated_phy;
+
+ struct clk_bulk_data *clks;
+ int num_clks;
+ struct clk *clk_mac;
+ struct clk *clk_phy;
+
+ struct reset_control *phy_reset;
+
+ int tx_delay;
+ int rx_delay;
+
+ struct regmap *grf;
+ struct regmap *php_grf;
+};
+
+#define HIWORD_UPDATE(val, mask, shift) \
+ ((val) << (shift) | (mask) << ((shift) + 16))
+
+#define GRF_BIT(nr) (BIT(nr) | BIT(nr+16))
+#define GRF_CLR_BIT(nr) (BIT(nr+16))
+
+#define DELAY_ENABLE(soc, tx, rx) \
+ (((tx) ? soc##_GMAC_TXCLK_DLY_ENABLE : soc##_GMAC_TXCLK_DLY_DISABLE) | \
+ ((rx) ? soc##_GMAC_RXCLK_DLY_ENABLE : soc##_GMAC_RXCLK_DLY_DISABLE))
+
+#define PX30_GRF_GMAC_CON1 0x0904
+
+/* PX30_GRF_GMAC_CON1 */
+#define PX30_GMAC_PHY_INTF_SEL_RMII (GRF_CLR_BIT(4) | GRF_CLR_BIT(5) | \
+ GRF_BIT(6))
+#define PX30_GMAC_SPEED_10M GRF_CLR_BIT(2)
+#define PX30_GMAC_SPEED_100M GRF_BIT(2)
+
+static void px30_set_to_rmii(struct rk_priv_data *bsp_priv)
+{
+ struct device *dev = &bsp_priv->pdev->dev;
+
+ if (IS_ERR(bsp_priv->grf)) {
+ dev_err(dev, "%s: Missing rockchip,grf property\n", __func__);
+ return;
+ }
+
+ regmap_write(bsp_priv->grf, PX30_GRF_GMAC_CON1,
+ PX30_GMAC_PHY_INTF_SEL_RMII);
+}
+
+static void px30_set_rmii_speed(struct rk_priv_data *bsp_priv, int speed)
+{
+ struct clk *clk_mac_speed = bsp_priv->clks[RK_CLK_MAC_SPEED].clk;
+ struct device *dev = &bsp_priv->pdev->dev;
+ int ret;
+
+ if (!clk_mac_speed) {
+ dev_err(dev, "%s: Missing clk_mac_speed clock\n", __func__);
+ return;
+ }
+
+ if (speed == 10) {
+ regmap_write(bsp_priv->grf, PX30_GRF_GMAC_CON1,
+ PX30_GMAC_SPEED_10M);
+
+ ret = clk_set_rate(clk_mac_speed, 2500000);
+ if (ret)
+ dev_err(dev, "%s: set clk_mac_speed rate 2500000 failed: %d\n",
+ __func__, ret);
+ } else if (speed == 100) {
+ regmap_write(bsp_priv->grf, PX30_GRF_GMAC_CON1,
+ PX30_GMAC_SPEED_100M);
+
+ ret = clk_set_rate(clk_mac_speed, 25000000);
+ if (ret)
+ dev_err(dev, "%s: set clk_mac_speed rate 25000000 failed: %d\n",
+ __func__, ret);
+
+ } else {
+ dev_err(dev, "unknown speed value for RMII! speed=%d", speed);
+ }
+}
+
+static const struct rk_gmac_ops px30_ops = {
+ .set_to_rmii = px30_set_to_rmii,
+ .set_rmii_speed = px30_set_rmii_speed,
+};
+
+#define RK3128_GRF_MAC_CON0 0x0168
+#define RK3128_GRF_MAC_CON1 0x016c
+
+/* RK3128_GRF_MAC_CON0 */
+#define RK3128_GMAC_TXCLK_DLY_ENABLE GRF_BIT(14)
+#define RK3128_GMAC_TXCLK_DLY_DISABLE GRF_CLR_BIT(14)
+#define RK3128_GMAC_RXCLK_DLY_ENABLE GRF_BIT(15)
+#define RK3128_GMAC_RXCLK_DLY_DISABLE GRF_CLR_BIT(15)
+#define RK3128_GMAC_CLK_RX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 7)
+#define RK3128_GMAC_CLK_TX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 0)
+
+/* RK3128_GRF_MAC_CON1 */
+#define RK3128_GMAC_PHY_INTF_SEL_RGMII \
+ (GRF_BIT(6) | GRF_CLR_BIT(7) | GRF_CLR_BIT(8))
+#define RK3128_GMAC_PHY_INTF_SEL_RMII \
+ (GRF_CLR_BIT(6) | GRF_CLR_BIT(7) | GRF_BIT(8))
+#define RK3128_GMAC_FLOW_CTRL GRF_BIT(9)
+#define RK3128_GMAC_FLOW_CTRL_CLR GRF_CLR_BIT(9)
+#define RK3128_GMAC_SPEED_10M GRF_CLR_BIT(10)
+#define RK3128_GMAC_SPEED_100M GRF_BIT(10)
+#define RK3128_GMAC_RMII_CLK_25M GRF_BIT(11)
+#define RK3128_GMAC_RMII_CLK_2_5M GRF_CLR_BIT(11)
+#define RK3128_GMAC_CLK_125M (GRF_CLR_BIT(12) | GRF_CLR_BIT(13))
+#define RK3128_GMAC_CLK_25M (GRF_BIT(12) | GRF_BIT(13))
+#define RK3128_GMAC_CLK_2_5M (GRF_CLR_BIT(12) | GRF_BIT(13))
+#define RK3128_GMAC_RMII_MODE GRF_BIT(14)
+#define RK3128_GMAC_RMII_MODE_CLR GRF_CLR_BIT(14)
+
+static void rk3128_set_to_rgmii(struct rk_priv_data *bsp_priv,
+ int tx_delay, int rx_delay)
+{
+ struct device *dev = &bsp_priv->pdev->dev;
+
+ if (IS_ERR(bsp_priv->grf)) {
+ dev_err(dev, "Missing rockchip,grf property\n");
+ return;
+ }
+
+ regmap_write(bsp_priv->grf, RK3128_GRF_MAC_CON1,
+ RK3128_GMAC_PHY_INTF_SEL_RGMII |
+ RK3128_GMAC_RMII_MODE_CLR);
+ regmap_write(bsp_priv->grf, RK3128_GRF_MAC_CON0,
+ DELAY_ENABLE(RK3128, tx_delay, rx_delay) |
+ RK3128_GMAC_CLK_RX_DL_CFG(rx_delay) |
+ RK3128_GMAC_CLK_TX_DL_CFG(tx_delay));
+}
+
+static void rk3128_set_to_rmii(struct rk_priv_data *bsp_priv)
+{
+ struct device *dev = &bsp_priv->pdev->dev;
+
+ if (IS_ERR(bsp_priv->grf)) {
+ dev_err(dev, "Missing rockchip,grf property\n");
+ return;
+ }
+
+ regmap_write(bsp_priv->grf, RK3128_GRF_MAC_CON1,
+ RK3128_GMAC_PHY_INTF_SEL_RMII | RK3128_GMAC_RMII_MODE);
+}
+
+static void rk3128_set_rgmii_speed(struct rk_priv_data *bsp_priv, int speed)
+{
+ struct device *dev = &bsp_priv->pdev->dev;
+
+ if (IS_ERR(bsp_priv->grf)) {
+ dev_err(dev, "Missing rockchip,grf property\n");
+ return;
+ }
+
+ if (speed == 10)
+ regmap_write(bsp_priv->grf, RK3128_GRF_MAC_CON1,
+ RK3128_GMAC_CLK_2_5M);
+ else if (speed == 100)
+ regmap_write(bsp_priv->grf, RK3128_GRF_MAC_CON1,
+ RK3128_GMAC_CLK_25M);
+ else if (speed == 1000)
+ regmap_write(bsp_priv->grf, RK3128_GRF_MAC_CON1,
+ RK3128_GMAC_CLK_125M);
+ else
+ dev_err(dev, "unknown speed value for RGMII! speed=%d", speed);
+}
+
+static void rk3128_set_rmii_speed(struct rk_priv_data *bsp_priv, int speed)
+{
+ struct device *dev = &bsp_priv->pdev->dev;
+
+ if (IS_ERR(bsp_priv->grf)) {
+ dev_err(dev, "Missing rockchip,grf property\n");
+ return;
+ }
+
+ if (speed == 10) {
+ regmap_write(bsp_priv->grf, RK3128_GRF_MAC_CON1,
+ RK3128_GMAC_RMII_CLK_2_5M |
+ RK3128_GMAC_SPEED_10M);
+ } else if (speed == 100) {
+ regmap_write(bsp_priv->grf, RK3128_GRF_MAC_CON1,
+ RK3128_GMAC_RMII_CLK_25M |
+ RK3128_GMAC_SPEED_100M);
+ } else {
+ dev_err(dev, "unknown speed value for RMII! speed=%d", speed);
+ }
+}
+
+static const struct rk_gmac_ops rk3128_ops = {
+ .set_to_rgmii = rk3128_set_to_rgmii,
+ .set_to_rmii = rk3128_set_to_rmii,
+ .set_rgmii_speed = rk3128_set_rgmii_speed,
+ .set_rmii_speed = rk3128_set_rmii_speed,
+};
+
+#define RK3228_GRF_MAC_CON0 0x0900
+#define RK3228_GRF_MAC_CON1 0x0904
+
+#define RK3228_GRF_CON_MUX 0x50
+
+/* RK3228_GRF_MAC_CON0 */
+#define RK3228_GMAC_CLK_RX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 7)
+#define RK3228_GMAC_CLK_TX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 0)
+
+/* RK3228_GRF_MAC_CON1 */
+#define RK3228_GMAC_PHY_INTF_SEL_RGMII \
+ (GRF_BIT(4) | GRF_CLR_BIT(5) | GRF_CLR_BIT(6))
+#define RK3228_GMAC_PHY_INTF_SEL_RMII \
+ (GRF_CLR_BIT(4) | GRF_CLR_BIT(5) | GRF_BIT(6))
+#define RK3228_GMAC_FLOW_CTRL GRF_BIT(3)
+#define RK3228_GMAC_FLOW_CTRL_CLR GRF_CLR_BIT(3)
+#define RK3228_GMAC_SPEED_10M GRF_CLR_BIT(2)
+#define RK3228_GMAC_SPEED_100M GRF_BIT(2)
+#define RK3228_GMAC_RMII_CLK_25M GRF_BIT(7)
+#define RK3228_GMAC_RMII_CLK_2_5M GRF_CLR_BIT(7)
+#define RK3228_GMAC_CLK_125M (GRF_CLR_BIT(8) | GRF_CLR_BIT(9))
+#define RK3228_GMAC_CLK_25M (GRF_BIT(8) | GRF_BIT(9))
+#define RK3228_GMAC_CLK_2_5M (GRF_CLR_BIT(8) | GRF_BIT(9))
+#define RK3228_GMAC_RMII_MODE GRF_BIT(10)
+#define RK3228_GMAC_RMII_MODE_CLR GRF_CLR_BIT(10)
+#define RK3228_GMAC_TXCLK_DLY_ENABLE GRF_BIT(0)
+#define RK3228_GMAC_TXCLK_DLY_DISABLE GRF_CLR_BIT(0)
+#define RK3228_GMAC_RXCLK_DLY_ENABLE GRF_BIT(1)
+#define RK3228_GMAC_RXCLK_DLY_DISABLE GRF_CLR_BIT(1)
+
+/* RK3228_GRF_COM_MUX */
+#define RK3228_GRF_CON_MUX_GMAC_INTEGRATED_PHY GRF_BIT(15)
+
+static void rk3228_set_to_rgmii(struct rk_priv_data *bsp_priv,
+ int tx_delay, int rx_delay)
+{
+ struct device *dev = &bsp_priv->pdev->dev;
+
+ if (IS_ERR(bsp_priv->grf)) {
+ dev_err(dev, "Missing rockchip,grf property\n");
+ return;
+ }
+
+ regmap_write(bsp_priv->grf, RK3228_GRF_MAC_CON1,
+ RK3228_GMAC_PHY_INTF_SEL_RGMII |
+ RK3228_GMAC_RMII_MODE_CLR |
+ DELAY_ENABLE(RK3228, tx_delay, rx_delay));
+
+ regmap_write(bsp_priv->grf, RK3228_GRF_MAC_CON0,
+ RK3228_GMAC_CLK_RX_DL_CFG(rx_delay) |
+ RK3228_GMAC_CLK_TX_DL_CFG(tx_delay));
+}
+
+static void rk3228_set_to_rmii(struct rk_priv_data *bsp_priv)
+{
+ struct device *dev = &bsp_priv->pdev->dev;
+
+ if (IS_ERR(bsp_priv->grf)) {
+ dev_err(dev, "Missing rockchip,grf property\n");
+ return;
+ }
+
+ regmap_write(bsp_priv->grf, RK3228_GRF_MAC_CON1,
+ RK3228_GMAC_PHY_INTF_SEL_RMII |
+ RK3228_GMAC_RMII_MODE);
+
+ /* set MAC to RMII mode */
+ regmap_write(bsp_priv->grf, RK3228_GRF_MAC_CON1, GRF_BIT(11));
+}
+
+static void rk3228_set_rgmii_speed(struct rk_priv_data *bsp_priv, int speed)
+{
+ struct device *dev = &bsp_priv->pdev->dev;
+
+ if (IS_ERR(bsp_priv->grf)) {
+ dev_err(dev, "Missing rockchip,grf property\n");
+ return;
+ }
+
+ if (speed == 10)
+ regmap_write(bsp_priv->grf, RK3228_GRF_MAC_CON1,
+ RK3228_GMAC_CLK_2_5M);
+ else if (speed == 100)
+ regmap_write(bsp_priv->grf, RK3228_GRF_MAC_CON1,
+ RK3228_GMAC_CLK_25M);
+ else if (speed == 1000)
+ regmap_write(bsp_priv->grf, RK3228_GRF_MAC_CON1,
+ RK3228_GMAC_CLK_125M);
+ else
+ dev_err(dev, "unknown speed value for RGMII! speed=%d", speed);
+}
+
+static void rk3228_set_rmii_speed(struct rk_priv_data *bsp_priv, int speed)
+{
+ struct device *dev = &bsp_priv->pdev->dev;
+
+ if (IS_ERR(bsp_priv->grf)) {
+ dev_err(dev, "Missing rockchip,grf property\n");
+ return;
+ }
+
+ if (speed == 10)
+ regmap_write(bsp_priv->grf, RK3228_GRF_MAC_CON1,
+ RK3228_GMAC_RMII_CLK_2_5M |
+ RK3228_GMAC_SPEED_10M);
+ else if (speed == 100)
+ regmap_write(bsp_priv->grf, RK3228_GRF_MAC_CON1,
+ RK3228_GMAC_RMII_CLK_25M |
+ RK3228_GMAC_SPEED_100M);
+ else
+ dev_err(dev, "unknown speed value for RMII! speed=%d", speed);
+}
+
+static void rk3228_integrated_phy_powerup(struct rk_priv_data *priv)
+{
+ regmap_write(priv->grf, RK3228_GRF_CON_MUX,
+ RK3228_GRF_CON_MUX_GMAC_INTEGRATED_PHY);
+}
+
+static const struct rk_gmac_ops rk3228_ops = {
+ .set_to_rgmii = rk3228_set_to_rgmii,
+ .set_to_rmii = rk3228_set_to_rmii,
+ .set_rgmii_speed = rk3228_set_rgmii_speed,
+ .set_rmii_speed = rk3228_set_rmii_speed,
+ .integrated_phy_powerup = rk3228_integrated_phy_powerup,
+};
+
+#define RK3288_GRF_SOC_CON1 0x0248
+#define RK3288_GRF_SOC_CON3 0x0250
+
+/*RK3288_GRF_SOC_CON1*/
+#define RK3288_GMAC_PHY_INTF_SEL_RGMII (GRF_BIT(6) | GRF_CLR_BIT(7) | \
+ GRF_CLR_BIT(8))
+#define RK3288_GMAC_PHY_INTF_SEL_RMII (GRF_CLR_BIT(6) | GRF_CLR_BIT(7) | \
+ GRF_BIT(8))
+#define RK3288_GMAC_FLOW_CTRL GRF_BIT(9)
+#define RK3288_GMAC_FLOW_CTRL_CLR GRF_CLR_BIT(9)
+#define RK3288_GMAC_SPEED_10M GRF_CLR_BIT(10)
+#define RK3288_GMAC_SPEED_100M GRF_BIT(10)
+#define RK3288_GMAC_RMII_CLK_25M GRF_BIT(11)
+#define RK3288_GMAC_RMII_CLK_2_5M GRF_CLR_BIT(11)
+#define RK3288_GMAC_CLK_125M (GRF_CLR_BIT(12) | GRF_CLR_BIT(13))
+#define RK3288_GMAC_CLK_25M (GRF_BIT(12) | GRF_BIT(13))
+#define RK3288_GMAC_CLK_2_5M (GRF_CLR_BIT(12) | GRF_BIT(13))
+#define RK3288_GMAC_RMII_MODE GRF_BIT(14)
+#define RK3288_GMAC_RMII_MODE_CLR GRF_CLR_BIT(14)
+
+/*RK3288_GRF_SOC_CON3*/
+#define RK3288_GMAC_TXCLK_DLY_ENABLE GRF_BIT(14)
+#define RK3288_GMAC_TXCLK_DLY_DISABLE GRF_CLR_BIT(14)
+#define RK3288_GMAC_RXCLK_DLY_ENABLE GRF_BIT(15)
+#define RK3288_GMAC_RXCLK_DLY_DISABLE GRF_CLR_BIT(15)
+#define RK3288_GMAC_CLK_RX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 7)
+#define RK3288_GMAC_CLK_TX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 0)
+
+static void rk3288_set_to_rgmii(struct rk_priv_data *bsp_priv,
+ int tx_delay, int rx_delay)
+{
+ struct device *dev = &bsp_priv->pdev->dev;
+
+ if (IS_ERR(bsp_priv->grf)) {
+ dev_err(dev, "Missing rockchip,grf property\n");
+ return;
+ }
+
+ regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1,
+ RK3288_GMAC_PHY_INTF_SEL_RGMII |
+ RK3288_GMAC_RMII_MODE_CLR);
+ regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON3,
+ DELAY_ENABLE(RK3288, tx_delay, rx_delay) |
+ RK3288_GMAC_CLK_RX_DL_CFG(rx_delay) |
+ RK3288_GMAC_CLK_TX_DL_CFG(tx_delay));
+}
+
+static void rk3288_set_to_rmii(struct rk_priv_data *bsp_priv)
+{
+ struct device *dev = &bsp_priv->pdev->dev;
+
+ if (IS_ERR(bsp_priv->grf)) {
+ dev_err(dev, "Missing rockchip,grf property\n");
+ return;
+ }
+
+ regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1,
+ RK3288_GMAC_PHY_INTF_SEL_RMII | RK3288_GMAC_RMII_MODE);
+}
+
+static void rk3288_set_rgmii_speed(struct rk_priv_data *bsp_priv, int speed)
+{
+ struct device *dev = &bsp_priv->pdev->dev;
+
+ if (IS_ERR(bsp_priv->grf)) {
+ dev_err(dev, "Missing rockchip,grf property\n");
+ return;
+ }
+
+ if (speed == 10)
+ regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1,
+ RK3288_GMAC_CLK_2_5M);
+ else if (speed == 100)
+ regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1,
+ RK3288_GMAC_CLK_25M);
+ else if (speed == 1000)
+ regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1,
+ RK3288_GMAC_CLK_125M);
+ else
+ dev_err(dev, "unknown speed value for RGMII! speed=%d", speed);
+}
+
+static void rk3288_set_rmii_speed(struct rk_priv_data *bsp_priv, int speed)
+{
+ struct device *dev = &bsp_priv->pdev->dev;
+
+ if (IS_ERR(bsp_priv->grf)) {
+ dev_err(dev, "Missing rockchip,grf property\n");
+ return;
+ }
+
+ if (speed == 10) {
+ regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1,
+ RK3288_GMAC_RMII_CLK_2_5M |
+ RK3288_GMAC_SPEED_10M);
+ } else if (speed == 100) {
+ regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1,
+ RK3288_GMAC_RMII_CLK_25M |
+ RK3288_GMAC_SPEED_100M);
+ } else {
+ dev_err(dev, "unknown speed value for RMII! speed=%d", speed);
+ }
+}
+
+static const struct rk_gmac_ops rk3288_ops = {
+ .set_to_rgmii = rk3288_set_to_rgmii,
+ .set_to_rmii = rk3288_set_to_rmii,
+ .set_rgmii_speed = rk3288_set_rgmii_speed,
+ .set_rmii_speed = rk3288_set_rmii_speed,
+};
+
+#define RK3308_GRF_MAC_CON0 0x04a0
+
+/* RK3308_GRF_MAC_CON0 */
+#define RK3308_GMAC_PHY_INTF_SEL_RMII (GRF_CLR_BIT(2) | GRF_CLR_BIT(3) | \
+ GRF_BIT(4))
+#define RK3308_GMAC_FLOW_CTRL GRF_BIT(3)
+#define RK3308_GMAC_FLOW_CTRL_CLR GRF_CLR_BIT(3)
+#define RK3308_GMAC_SPEED_10M GRF_CLR_BIT(0)
+#define RK3308_GMAC_SPEED_100M GRF_BIT(0)
+
+static void rk3308_set_to_rmii(struct rk_priv_data *bsp_priv)
+{
+ struct device *dev = &bsp_priv->pdev->dev;
+
+ if (IS_ERR(bsp_priv->grf)) {
+ dev_err(dev, "Missing rockchip,grf property\n");
+ return;
+ }
+
+ regmap_write(bsp_priv->grf, RK3308_GRF_MAC_CON0,
+ RK3308_GMAC_PHY_INTF_SEL_RMII);
+}
+
+static void rk3308_set_rmii_speed(struct rk_priv_data *bsp_priv, int speed)
+{
+ struct device *dev = &bsp_priv->pdev->dev;
+
+ if (IS_ERR(bsp_priv->grf)) {
+ dev_err(dev, "Missing rockchip,grf property\n");
+ return;
+ }
+
+ if (speed == 10) {
+ regmap_write(bsp_priv->grf, RK3308_GRF_MAC_CON0,
+ RK3308_GMAC_SPEED_10M);
+ } else if (speed == 100) {
+ regmap_write(bsp_priv->grf, RK3308_GRF_MAC_CON0,
+ RK3308_GMAC_SPEED_100M);
+ } else {
+ dev_err(dev, "unknown speed value for RMII! speed=%d", speed);
+ }
+}
+
+static const struct rk_gmac_ops rk3308_ops = {
+ .set_to_rmii = rk3308_set_to_rmii,
+ .set_rmii_speed = rk3308_set_rmii_speed,
+};
+
+#define RK3328_GRF_MAC_CON0 0x0900
+#define RK3328_GRF_MAC_CON1 0x0904
+#define RK3328_GRF_MAC_CON2 0x0908
+#define RK3328_GRF_MACPHY_CON1 0xb04
+
+/* RK3328_GRF_MAC_CON0 */
+#define RK3328_GMAC_CLK_RX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 7)
+#define RK3328_GMAC_CLK_TX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 0)
+
+/* RK3328_GRF_MAC_CON1 */
+#define RK3328_GMAC_PHY_INTF_SEL_RGMII \
+ (GRF_BIT(4) | GRF_CLR_BIT(5) | GRF_CLR_BIT(6))
+#define RK3328_GMAC_PHY_INTF_SEL_RMII \
+ (GRF_CLR_BIT(4) | GRF_CLR_BIT(5) | GRF_BIT(6))
+#define RK3328_GMAC_FLOW_CTRL GRF_BIT(3)
+#define RK3328_GMAC_FLOW_CTRL_CLR GRF_CLR_BIT(3)
+#define RK3328_GMAC_SPEED_10M GRF_CLR_BIT(2)
+#define RK3328_GMAC_SPEED_100M GRF_BIT(2)
+#define RK3328_GMAC_RMII_CLK_25M GRF_BIT(7)
+#define RK3328_GMAC_RMII_CLK_2_5M GRF_CLR_BIT(7)
+#define RK3328_GMAC_CLK_125M (GRF_CLR_BIT(11) | GRF_CLR_BIT(12))
+#define RK3328_GMAC_CLK_25M (GRF_BIT(11) | GRF_BIT(12))
+#define RK3328_GMAC_CLK_2_5M (GRF_CLR_BIT(11) | GRF_BIT(12))
+#define RK3328_GMAC_RMII_MODE GRF_BIT(9)
+#define RK3328_GMAC_RMII_MODE_CLR GRF_CLR_BIT(9)
+#define RK3328_GMAC_TXCLK_DLY_ENABLE GRF_BIT(0)
+#define RK3328_GMAC_TXCLK_DLY_DISABLE GRF_CLR_BIT(0)
+#define RK3328_GMAC_RXCLK_DLY_ENABLE GRF_BIT(1)
+#define RK3328_GMAC_RXCLK_DLY_DISABLE GRF_CLR_BIT(0)
+
+/* RK3328_GRF_MACPHY_CON1 */
+#define RK3328_MACPHY_RMII_MODE GRF_BIT(9)
+
+static void rk3328_set_to_rgmii(struct rk_priv_data *bsp_priv,
+ int tx_delay, int rx_delay)
+{
+ struct device *dev = &bsp_priv->pdev->dev;
+
+ if (IS_ERR(bsp_priv->grf)) {
+ dev_err(dev, "Missing rockchip,grf property\n");
+ return;
+ }
+
+ regmap_write(bsp_priv->grf, RK3328_GRF_MAC_CON1,
+ RK3328_GMAC_PHY_INTF_SEL_RGMII |
+ RK3328_GMAC_RMII_MODE_CLR |
+ RK3328_GMAC_RXCLK_DLY_ENABLE |
+ RK3328_GMAC_TXCLK_DLY_ENABLE);
+
+ regmap_write(bsp_priv->grf, RK3328_GRF_MAC_CON0,
+ RK3328_GMAC_CLK_RX_DL_CFG(rx_delay) |
+ RK3328_GMAC_CLK_TX_DL_CFG(tx_delay));
+}
+
+static void rk3328_set_to_rmii(struct rk_priv_data *bsp_priv)
+{
+ struct device *dev = &bsp_priv->pdev->dev;
+ unsigned int reg;
+
+ if (IS_ERR(bsp_priv->grf)) {
+ dev_err(dev, "Missing rockchip,grf property\n");
+ return;
+ }
+
+ reg = bsp_priv->integrated_phy ? RK3328_GRF_MAC_CON2 :
+ RK3328_GRF_MAC_CON1;
+
+ regmap_write(bsp_priv->grf, reg,
+ RK3328_GMAC_PHY_INTF_SEL_RMII |
+ RK3328_GMAC_RMII_MODE);
+}
+
+static void rk3328_set_rgmii_speed(struct rk_priv_data *bsp_priv, int speed)
+{
+ struct device *dev = &bsp_priv->pdev->dev;
+
+ if (IS_ERR(bsp_priv->grf)) {
+ dev_err(dev, "Missing rockchip,grf property\n");
+ return;
+ }
+
+ if (speed == 10)
+ regmap_write(bsp_priv->grf, RK3328_GRF_MAC_CON1,
+ RK3328_GMAC_CLK_2_5M);
+ else if (speed == 100)
+ regmap_write(bsp_priv->grf, RK3328_GRF_MAC_CON1,
+ RK3328_GMAC_CLK_25M);
+ else if (speed == 1000)
+ regmap_write(bsp_priv->grf, RK3328_GRF_MAC_CON1,
+ RK3328_GMAC_CLK_125M);
+ else
+ dev_err(dev, "unknown speed value for RGMII! speed=%d", speed);
+}
+
+static void rk3328_set_rmii_speed(struct rk_priv_data *bsp_priv, int speed)
+{
+ struct device *dev = &bsp_priv->pdev->dev;
+ unsigned int reg;
+
+ if (IS_ERR(bsp_priv->grf)) {
+ dev_err(dev, "Missing rockchip,grf property\n");
+ return;
+ }
+
+ reg = bsp_priv->integrated_phy ? RK3328_GRF_MAC_CON2 :
+ RK3328_GRF_MAC_CON1;
+
+ if (speed == 10)
+ regmap_write(bsp_priv->grf, reg,
+ RK3328_GMAC_RMII_CLK_2_5M |
+ RK3328_GMAC_SPEED_10M);
+ else if (speed == 100)
+ regmap_write(bsp_priv->grf, reg,
+ RK3328_GMAC_RMII_CLK_25M |
+ RK3328_GMAC_SPEED_100M);
+ else
+ dev_err(dev, "unknown speed value for RMII! speed=%d", speed);
+}
+
+static void rk3328_integrated_phy_powerup(struct rk_priv_data *priv)
+{
+ regmap_write(priv->grf, RK3328_GRF_MACPHY_CON1,
+ RK3328_MACPHY_RMII_MODE);
+}
+
+static const struct rk_gmac_ops rk3328_ops = {
+ .set_to_rgmii = rk3328_set_to_rgmii,
+ .set_to_rmii = rk3328_set_to_rmii,
+ .set_rgmii_speed = rk3328_set_rgmii_speed,
+ .set_rmii_speed = rk3328_set_rmii_speed,
+ .integrated_phy_powerup = rk3328_integrated_phy_powerup,
+};
+
+#define RK3366_GRF_SOC_CON6 0x0418
+#define RK3366_GRF_SOC_CON7 0x041c
+
+/* RK3366_GRF_SOC_CON6 */
+#define RK3366_GMAC_PHY_INTF_SEL_RGMII (GRF_BIT(9) | GRF_CLR_BIT(10) | \
+ GRF_CLR_BIT(11))
+#define RK3366_GMAC_PHY_INTF_SEL_RMII (GRF_CLR_BIT(9) | GRF_CLR_BIT(10) | \
+ GRF_BIT(11))
+#define RK3366_GMAC_FLOW_CTRL GRF_BIT(8)
+#define RK3366_GMAC_FLOW_CTRL_CLR GRF_CLR_BIT(8)
+#define RK3366_GMAC_SPEED_10M GRF_CLR_BIT(7)
+#define RK3366_GMAC_SPEED_100M GRF_BIT(7)
+#define RK3366_GMAC_RMII_CLK_25M GRF_BIT(3)
+#define RK3366_GMAC_RMII_CLK_2_5M GRF_CLR_BIT(3)
+#define RK3366_GMAC_CLK_125M (GRF_CLR_BIT(4) | GRF_CLR_BIT(5))
+#define RK3366_GMAC_CLK_25M (GRF_BIT(4) | GRF_BIT(5))
+#define RK3366_GMAC_CLK_2_5M (GRF_CLR_BIT(4) | GRF_BIT(5))
+#define RK3366_GMAC_RMII_MODE GRF_BIT(6)
+#define RK3366_GMAC_RMII_MODE_CLR GRF_CLR_BIT(6)
+
+/* RK3366_GRF_SOC_CON7 */
+#define RK3366_GMAC_TXCLK_DLY_ENABLE GRF_BIT(7)
+#define RK3366_GMAC_TXCLK_DLY_DISABLE GRF_CLR_BIT(7)
+#define RK3366_GMAC_RXCLK_DLY_ENABLE GRF_BIT(15)
+#define RK3366_GMAC_RXCLK_DLY_DISABLE GRF_CLR_BIT(15)
+#define RK3366_GMAC_CLK_RX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 8)
+#define RK3366_GMAC_CLK_TX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 0)
+
+static void rk3366_set_to_rgmii(struct rk_priv_data *bsp_priv,
+ int tx_delay, int rx_delay)
+{
+ struct device *dev = &bsp_priv->pdev->dev;
+
+ if (IS_ERR(bsp_priv->grf)) {
+ dev_err(dev, "%s: Missing rockchip,grf property\n", __func__);
+ return;
+ }
+
+ regmap_write(bsp_priv->grf, RK3366_GRF_SOC_CON6,
+ RK3366_GMAC_PHY_INTF_SEL_RGMII |
+ RK3366_GMAC_RMII_MODE_CLR);
+ regmap_write(bsp_priv->grf, RK3366_GRF_SOC_CON7,
+ DELAY_ENABLE(RK3366, tx_delay, rx_delay) |
+ RK3366_GMAC_CLK_RX_DL_CFG(rx_delay) |
+ RK3366_GMAC_CLK_TX_DL_CFG(tx_delay));
+}
+
+static void rk3366_set_to_rmii(struct rk_priv_data *bsp_priv)
+{
+ struct device *dev = &bsp_priv->pdev->dev;
+
+ if (IS_ERR(bsp_priv->grf)) {
+ dev_err(dev, "%s: Missing rockchip,grf property\n", __func__);
+ return;
+ }
+
+ regmap_write(bsp_priv->grf, RK3366_GRF_SOC_CON6,
+ RK3366_GMAC_PHY_INTF_SEL_RMII | RK3366_GMAC_RMII_MODE);
+}
+
+static void rk3366_set_rgmii_speed(struct rk_priv_data *bsp_priv, int speed)
+{
+ struct device *dev = &bsp_priv->pdev->dev;
+
+ if (IS_ERR(bsp_priv->grf)) {
+ dev_err(dev, "%s: Missing rockchip,grf property\n", __func__);
+ return;
+ }
+
+ if (speed == 10)
+ regmap_write(bsp_priv->grf, RK3366_GRF_SOC_CON6,
+ RK3366_GMAC_CLK_2_5M);
+ else if (speed == 100)
+ regmap_write(bsp_priv->grf, RK3366_GRF_SOC_CON6,
+ RK3366_GMAC_CLK_25M);
+ else if (speed == 1000)
+ regmap_write(bsp_priv->grf, RK3366_GRF_SOC_CON6,
+ RK3366_GMAC_CLK_125M);
+ else
+ dev_err(dev, "unknown speed value for RGMII! speed=%d", speed);
+}
+
+static void rk3366_set_rmii_speed(struct rk_priv_data *bsp_priv, int speed)
+{
+ struct device *dev = &bsp_priv->pdev->dev;
+
+ if (IS_ERR(bsp_priv->grf)) {
+ dev_err(dev, "%s: Missing rockchip,grf property\n", __func__);
+ return;
+ }
+
+ if (speed == 10) {
+ regmap_write(bsp_priv->grf, RK3366_GRF_SOC_CON6,
+ RK3366_GMAC_RMII_CLK_2_5M |
+ RK3366_GMAC_SPEED_10M);
+ } else if (speed == 100) {
+ regmap_write(bsp_priv->grf, RK3366_GRF_SOC_CON6,
+ RK3366_GMAC_RMII_CLK_25M |
+ RK3366_GMAC_SPEED_100M);
+ } else {
+ dev_err(dev, "unknown speed value for RMII! speed=%d", speed);
+ }
+}
+
+static const struct rk_gmac_ops rk3366_ops = {
+ .set_to_rgmii = rk3366_set_to_rgmii,
+ .set_to_rmii = rk3366_set_to_rmii,
+ .set_rgmii_speed = rk3366_set_rgmii_speed,
+ .set_rmii_speed = rk3366_set_rmii_speed,
+};
+
+#define RK3368_GRF_SOC_CON15 0x043c
+#define RK3368_GRF_SOC_CON16 0x0440
+
+/* RK3368_GRF_SOC_CON15 */
+#define RK3368_GMAC_PHY_INTF_SEL_RGMII (GRF_BIT(9) | GRF_CLR_BIT(10) | \
+ GRF_CLR_BIT(11))
+#define RK3368_GMAC_PHY_INTF_SEL_RMII (GRF_CLR_BIT(9) | GRF_CLR_BIT(10) | \
+ GRF_BIT(11))
+#define RK3368_GMAC_FLOW_CTRL GRF_BIT(8)
+#define RK3368_GMAC_FLOW_CTRL_CLR GRF_CLR_BIT(8)
+#define RK3368_GMAC_SPEED_10M GRF_CLR_BIT(7)
+#define RK3368_GMAC_SPEED_100M GRF_BIT(7)
+#define RK3368_GMAC_RMII_CLK_25M GRF_BIT(3)
+#define RK3368_GMAC_RMII_CLK_2_5M GRF_CLR_BIT(3)
+#define RK3368_GMAC_CLK_125M (GRF_CLR_BIT(4) | GRF_CLR_BIT(5))
+#define RK3368_GMAC_CLK_25M (GRF_BIT(4) | GRF_BIT(5))
+#define RK3368_GMAC_CLK_2_5M (GRF_CLR_BIT(4) | GRF_BIT(5))
+#define RK3368_GMAC_RMII_MODE GRF_BIT(6)
+#define RK3368_GMAC_RMII_MODE_CLR GRF_CLR_BIT(6)
+
+/* RK3368_GRF_SOC_CON16 */
+#define RK3368_GMAC_TXCLK_DLY_ENABLE GRF_BIT(7)
+#define RK3368_GMAC_TXCLK_DLY_DISABLE GRF_CLR_BIT(7)
+#define RK3368_GMAC_RXCLK_DLY_ENABLE GRF_BIT(15)
+#define RK3368_GMAC_RXCLK_DLY_DISABLE GRF_CLR_BIT(15)
+#define RK3368_GMAC_CLK_RX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 8)
+#define RK3368_GMAC_CLK_TX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 0)
+
+static void rk3368_set_to_rgmii(struct rk_priv_data *bsp_priv,
+ int tx_delay, int rx_delay)
+{
+ struct device *dev = &bsp_priv->pdev->dev;
+
+ if (IS_ERR(bsp_priv->grf)) {
+ dev_err(dev, "%s: Missing rockchip,grf property\n", __func__);
+ return;
+ }
+
+ regmap_write(bsp_priv->grf, RK3368_GRF_SOC_CON15,
+ RK3368_GMAC_PHY_INTF_SEL_RGMII |
+ RK3368_GMAC_RMII_MODE_CLR);
+ regmap_write(bsp_priv->grf, RK3368_GRF_SOC_CON16,
+ DELAY_ENABLE(RK3368, tx_delay, rx_delay) |
+ RK3368_GMAC_CLK_RX_DL_CFG(rx_delay) |
+ RK3368_GMAC_CLK_TX_DL_CFG(tx_delay));
+}
+
+static void rk3368_set_to_rmii(struct rk_priv_data *bsp_priv)
+{
+ struct device *dev = &bsp_priv->pdev->dev;
+
+ if (IS_ERR(bsp_priv->grf)) {
+ dev_err(dev, "%s: Missing rockchip,grf property\n", __func__);
+ return;
+ }
+
+ regmap_write(bsp_priv->grf, RK3368_GRF_SOC_CON15,
+ RK3368_GMAC_PHY_INTF_SEL_RMII | RK3368_GMAC_RMII_MODE);
+}
+
+static void rk3368_set_rgmii_speed(struct rk_priv_data *bsp_priv, int speed)
+{
+ struct device *dev = &bsp_priv->pdev->dev;
+
+ if (IS_ERR(bsp_priv->grf)) {
+ dev_err(dev, "%s: Missing rockchip,grf property\n", __func__);
+ return;
+ }
+
+ if (speed == 10)
+ regmap_write(bsp_priv->grf, RK3368_GRF_SOC_CON15,
+ RK3368_GMAC_CLK_2_5M);
+ else if (speed == 100)
+ regmap_write(bsp_priv->grf, RK3368_GRF_SOC_CON15,
+ RK3368_GMAC_CLK_25M);
+ else if (speed == 1000)
+ regmap_write(bsp_priv->grf, RK3368_GRF_SOC_CON15,
+ RK3368_GMAC_CLK_125M);
+ else
+ dev_err(dev, "unknown speed value for RGMII! speed=%d", speed);
+}
+
+static void rk3368_set_rmii_speed(struct rk_priv_data *bsp_priv, int speed)
+{
+ struct device *dev = &bsp_priv->pdev->dev;
+
+ if (IS_ERR(bsp_priv->grf)) {
+ dev_err(dev, "%s: Missing rockchip,grf property\n", __func__);
+ return;
+ }
+
+ if (speed == 10) {
+ regmap_write(bsp_priv->grf, RK3368_GRF_SOC_CON15,
+ RK3368_GMAC_RMII_CLK_2_5M |
+ RK3368_GMAC_SPEED_10M);
+ } else if (speed == 100) {
+ regmap_write(bsp_priv->grf, RK3368_GRF_SOC_CON15,
+ RK3368_GMAC_RMII_CLK_25M |
+ RK3368_GMAC_SPEED_100M);
+ } else {
+ dev_err(dev, "unknown speed value for RMII! speed=%d", speed);
+ }
+}
+
+static const struct rk_gmac_ops rk3368_ops = {
+ .set_to_rgmii = rk3368_set_to_rgmii,
+ .set_to_rmii = rk3368_set_to_rmii,
+ .set_rgmii_speed = rk3368_set_rgmii_speed,
+ .set_rmii_speed = rk3368_set_rmii_speed,
+};
+
+#define RK3399_GRF_SOC_CON5 0xc214
+#define RK3399_GRF_SOC_CON6 0xc218
+
+/* RK3399_GRF_SOC_CON5 */
+#define RK3399_GMAC_PHY_INTF_SEL_RGMII (GRF_BIT(9) | GRF_CLR_BIT(10) | \
+ GRF_CLR_BIT(11))
+#define RK3399_GMAC_PHY_INTF_SEL_RMII (GRF_CLR_BIT(9) | GRF_CLR_BIT(10) | \
+ GRF_BIT(11))
+#define RK3399_GMAC_FLOW_CTRL GRF_BIT(8)
+#define RK3399_GMAC_FLOW_CTRL_CLR GRF_CLR_BIT(8)
+#define RK3399_GMAC_SPEED_10M GRF_CLR_BIT(7)
+#define RK3399_GMAC_SPEED_100M GRF_BIT(7)
+#define RK3399_GMAC_RMII_CLK_25M GRF_BIT(3)
+#define RK3399_GMAC_RMII_CLK_2_5M GRF_CLR_BIT(3)
+#define RK3399_GMAC_CLK_125M (GRF_CLR_BIT(4) | GRF_CLR_BIT(5))
+#define RK3399_GMAC_CLK_25M (GRF_BIT(4) | GRF_BIT(5))
+#define RK3399_GMAC_CLK_2_5M (GRF_CLR_BIT(4) | GRF_BIT(5))
+#define RK3399_GMAC_RMII_MODE GRF_BIT(6)
+#define RK3399_GMAC_RMII_MODE_CLR GRF_CLR_BIT(6)
+
+/* RK3399_GRF_SOC_CON6 */
+#define RK3399_GMAC_TXCLK_DLY_ENABLE GRF_BIT(7)
+#define RK3399_GMAC_TXCLK_DLY_DISABLE GRF_CLR_BIT(7)
+#define RK3399_GMAC_RXCLK_DLY_ENABLE GRF_BIT(15)
+#define RK3399_GMAC_RXCLK_DLY_DISABLE GRF_CLR_BIT(15)
+#define RK3399_GMAC_CLK_RX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 8)
+#define RK3399_GMAC_CLK_TX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 0)
+
+static void rk3399_set_to_rgmii(struct rk_priv_data *bsp_priv,
+ int tx_delay, int rx_delay)
+{
+ struct device *dev = &bsp_priv->pdev->dev;
+
+ if (IS_ERR(bsp_priv->grf)) {
+ dev_err(dev, "%s: Missing rockchip,grf property\n", __func__);
+ return;
+ }
+
+ regmap_write(bsp_priv->grf, RK3399_GRF_SOC_CON5,
+ RK3399_GMAC_PHY_INTF_SEL_RGMII |
+ RK3399_GMAC_RMII_MODE_CLR);
+ regmap_write(bsp_priv->grf, RK3399_GRF_SOC_CON6,
+ DELAY_ENABLE(RK3399, tx_delay, rx_delay) |
+ RK3399_GMAC_CLK_RX_DL_CFG(rx_delay) |
+ RK3399_GMAC_CLK_TX_DL_CFG(tx_delay));
+}
+
+static void rk3399_set_to_rmii(struct rk_priv_data *bsp_priv)
+{
+ struct device *dev = &bsp_priv->pdev->dev;
+
+ if (IS_ERR(bsp_priv->grf)) {
+ dev_err(dev, "%s: Missing rockchip,grf property\n", __func__);
+ return;
+ }
+
+ regmap_write(bsp_priv->grf, RK3399_GRF_SOC_CON5,
+ RK3399_GMAC_PHY_INTF_SEL_RMII | RK3399_GMAC_RMII_MODE);
+}
+
+static void rk3399_set_rgmii_speed(struct rk_priv_data *bsp_priv, int speed)
+{
+ struct device *dev = &bsp_priv->pdev->dev;
+
+ if (IS_ERR(bsp_priv->grf)) {
+ dev_err(dev, "%s: Missing rockchip,grf property\n", __func__);
+ return;
+ }
+
+ if (speed == 10)
+ regmap_write(bsp_priv->grf, RK3399_GRF_SOC_CON5,
+ RK3399_GMAC_CLK_2_5M);
+ else if (speed == 100)
+ regmap_write(bsp_priv->grf, RK3399_GRF_SOC_CON5,
+ RK3399_GMAC_CLK_25M);
+ else if (speed == 1000)
+ regmap_write(bsp_priv->grf, RK3399_GRF_SOC_CON5,
+ RK3399_GMAC_CLK_125M);
+ else
+ dev_err(dev, "unknown speed value for RGMII! speed=%d", speed);
+}
+
+static void rk3399_set_rmii_speed(struct rk_priv_data *bsp_priv, int speed)
+{
+ struct device *dev = &bsp_priv->pdev->dev;
+
+ if (IS_ERR(bsp_priv->grf)) {
+ dev_err(dev, "%s: Missing rockchip,grf property\n", __func__);
+ return;
+ }
+
+ if (speed == 10) {
+ regmap_write(bsp_priv->grf, RK3399_GRF_SOC_CON5,
+ RK3399_GMAC_RMII_CLK_2_5M |
+ RK3399_GMAC_SPEED_10M);
+ } else if (speed == 100) {
+ regmap_write(bsp_priv->grf, RK3399_GRF_SOC_CON5,
+ RK3399_GMAC_RMII_CLK_25M |
+ RK3399_GMAC_SPEED_100M);
+ } else {
+ dev_err(dev, "unknown speed value for RMII! speed=%d", speed);
+ }
+}
+
+static const struct rk_gmac_ops rk3399_ops = {
+ .set_to_rgmii = rk3399_set_to_rgmii,
+ .set_to_rmii = rk3399_set_to_rmii,
+ .set_rgmii_speed = rk3399_set_rgmii_speed,
+ .set_rmii_speed = rk3399_set_rmii_speed,
+};
+
+#define RK3568_GRF_GMAC0_CON0 0x0380
+#define RK3568_GRF_GMAC0_CON1 0x0384
+#define RK3568_GRF_GMAC1_CON0 0x0388
+#define RK3568_GRF_GMAC1_CON1 0x038c
+
+/* RK3568_GRF_GMAC0_CON1 && RK3568_GRF_GMAC1_CON1 */
+#define RK3568_GMAC_PHY_INTF_SEL_RGMII \
+ (GRF_BIT(4) | GRF_CLR_BIT(5) | GRF_CLR_BIT(6))
+#define RK3568_GMAC_PHY_INTF_SEL_RMII \
+ (GRF_CLR_BIT(4) | GRF_CLR_BIT(5) | GRF_BIT(6))
+#define RK3568_GMAC_FLOW_CTRL GRF_BIT(3)
+#define RK3568_GMAC_FLOW_CTRL_CLR GRF_CLR_BIT(3)
+#define RK3568_GMAC_RXCLK_DLY_ENABLE GRF_BIT(1)
+#define RK3568_GMAC_RXCLK_DLY_DISABLE GRF_CLR_BIT(1)
+#define RK3568_GMAC_TXCLK_DLY_ENABLE GRF_BIT(0)
+#define RK3568_GMAC_TXCLK_DLY_DISABLE GRF_CLR_BIT(0)
+
+/* RK3568_GRF_GMAC0_CON0 && RK3568_GRF_GMAC1_CON0 */
+#define RK3568_GMAC_CLK_RX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 8)
+#define RK3568_GMAC_CLK_TX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 0)
+
+static void rk3568_set_to_rgmii(struct rk_priv_data *bsp_priv,
+ int tx_delay, int rx_delay)
+{
+ struct device *dev = &bsp_priv->pdev->dev;
+ u32 con0, con1;
+
+ if (IS_ERR(bsp_priv->grf)) {
+ dev_err(dev, "Missing rockchip,grf property\n");
+ return;
+ }
+
+ con0 = (bsp_priv->id == 1) ? RK3568_GRF_GMAC1_CON0 :
+ RK3568_GRF_GMAC0_CON0;
+ con1 = (bsp_priv->id == 1) ? RK3568_GRF_GMAC1_CON1 :
+ RK3568_GRF_GMAC0_CON1;
+
+ regmap_write(bsp_priv->grf, con0,
+ RK3568_GMAC_CLK_RX_DL_CFG(rx_delay) |
+ RK3568_GMAC_CLK_TX_DL_CFG(tx_delay));
+
+ regmap_write(bsp_priv->grf, con1,
+ RK3568_GMAC_PHY_INTF_SEL_RGMII |
+ RK3568_GMAC_RXCLK_DLY_ENABLE |
+ RK3568_GMAC_TXCLK_DLY_ENABLE);
+}
+
+static void rk3568_set_to_rmii(struct rk_priv_data *bsp_priv)
+{
+ struct device *dev = &bsp_priv->pdev->dev;
+ u32 con1;
+
+ if (IS_ERR(bsp_priv->grf)) {
+ dev_err(dev, "%s: Missing rockchip,grf property\n", __func__);
+ return;
+ }
+
+ con1 = (bsp_priv->id == 1) ? RK3568_GRF_GMAC1_CON1 :
+ RK3568_GRF_GMAC0_CON1;
+ regmap_write(bsp_priv->grf, con1, RK3568_GMAC_PHY_INTF_SEL_RMII);
+}
+
+static void rk3568_set_gmac_speed(struct rk_priv_data *bsp_priv, int speed)
+{
+ struct clk *clk_mac_speed = bsp_priv->clks[RK_CLK_MAC_SPEED].clk;
+ struct device *dev = &bsp_priv->pdev->dev;
+ unsigned long rate;
+ int ret;
+
+ switch (speed) {
+ case 10:
+ rate = 2500000;
+ break;
+ case 100:
+ rate = 25000000;
+ break;
+ case 1000:
+ rate = 125000000;
+ break;
+ default:
+ dev_err(dev, "unknown speed value for GMAC speed=%d", speed);
+ return;
+ }
+
+ ret = clk_set_rate(clk_mac_speed, rate);
+ if (ret)
+ dev_err(dev, "%s: set clk_mac_speed rate %ld failed %d\n",
+ __func__, rate, ret);
+}
+
+static const struct rk_gmac_ops rk3568_ops = {
+ .set_to_rgmii = rk3568_set_to_rgmii,
+ .set_to_rmii = rk3568_set_to_rmii,
+ .set_rgmii_speed = rk3568_set_gmac_speed,
+ .set_rmii_speed = rk3568_set_gmac_speed,
+ .regs_valid = true,
+ .regs = {
+ 0xfe2a0000, /* gmac0 */
+ 0xfe010000, /* gmac1 */
+ 0x0, /* sentinel */
+ },
+};
+
+/* sys_grf */
+#define RK3588_GRF_GMAC_CON7 0X031c
+#define RK3588_GRF_GMAC_CON8 0X0320
+#define RK3588_GRF_GMAC_CON9 0X0324
+
+#define RK3588_GMAC_RXCLK_DLY_ENABLE(id) GRF_BIT(2 * (id) + 3)
+#define RK3588_GMAC_RXCLK_DLY_DISABLE(id) GRF_CLR_BIT(2 * (id) + 3)
+#define RK3588_GMAC_TXCLK_DLY_ENABLE(id) GRF_BIT(2 * (id) + 2)
+#define RK3588_GMAC_TXCLK_DLY_DISABLE(id) GRF_CLR_BIT(2 * (id) + 2)
+
+#define RK3588_GMAC_CLK_RX_DL_CFG(val) HIWORD_UPDATE(val, 0xFF, 8)
+#define RK3588_GMAC_CLK_TX_DL_CFG(val) HIWORD_UPDATE(val, 0xFF, 0)
+
+/* php_grf */
+#define RK3588_GRF_GMAC_CON0 0X0008
+#define RK3588_GRF_CLK_CON1 0X0070
+
+#define RK3588_GMAC_PHY_INTF_SEL_RGMII(id) \
+ (GRF_BIT(3 + (id) * 6) | GRF_CLR_BIT(4 + (id) * 6) | GRF_CLR_BIT(5 + (id) * 6))
+#define RK3588_GMAC_PHY_INTF_SEL_RMII(id) \
+ (GRF_CLR_BIT(3 + (id) * 6) | GRF_CLR_BIT(4 + (id) * 6) | GRF_BIT(5 + (id) * 6))
+
+#define RK3588_GMAC_CLK_RMII_MODE(id) GRF_BIT(5 * (id))
+#define RK3588_GMAC_CLK_RGMII_MODE(id) GRF_CLR_BIT(5 * (id))
+
+#define RK3588_GMAC_CLK_SELET_CRU(id) GRF_BIT(5 * (id) + 4)
+#define RK3588_GMAC_CLK_SELET_IO(id) GRF_CLR_BIT(5 * (id) + 4)
+
+#define RK3588_GMA_CLK_RMII_DIV2(id) GRF_BIT(5 * (id) + 2)
+#define RK3588_GMA_CLK_RMII_DIV20(id) GRF_CLR_BIT(5 * (id) + 2)
+
+#define RK3588_GMAC_CLK_RGMII_DIV1(id) \
+ (GRF_CLR_BIT(5 * (id) + 2) | GRF_CLR_BIT(5 * (id) + 3))
+#define RK3588_GMAC_CLK_RGMII_DIV5(id) \
+ (GRF_BIT(5 * (id) + 2) | GRF_BIT(5 * (id) + 3))
+#define RK3588_GMAC_CLK_RGMII_DIV50(id) \
+ (GRF_CLR_BIT(5 * (id) + 2) | GRF_BIT(5 * (id) + 3))
+
+#define RK3588_GMAC_CLK_RMII_GATE(id) GRF_BIT(5 * (id) + 1)
+#define RK3588_GMAC_CLK_RMII_NOGATE(id) GRF_CLR_BIT(5 * (id) + 1)
+
+static void rk3588_set_to_rgmii(struct rk_priv_data *bsp_priv,
+ int tx_delay, int rx_delay)
+{
+ struct device *dev = &bsp_priv->pdev->dev;
+ u32 offset_con, id = bsp_priv->id;
+
+ if (IS_ERR(bsp_priv->grf) || IS_ERR(bsp_priv->php_grf)) {
+ dev_err(dev, "Missing rockchip,grf or rockchip,php_grf property\n");
+ return;
+ }
+
+ offset_con = bsp_priv->id == 1 ? RK3588_GRF_GMAC_CON9 :
+ RK3588_GRF_GMAC_CON8;
+
+ regmap_write(bsp_priv->php_grf, RK3588_GRF_GMAC_CON0,
+ RK3588_GMAC_PHY_INTF_SEL_RGMII(id));
+
+ regmap_write(bsp_priv->php_grf, RK3588_GRF_CLK_CON1,
+ RK3588_GMAC_CLK_RGMII_MODE(id));
+
+ regmap_write(bsp_priv->grf, RK3588_GRF_GMAC_CON7,
+ RK3588_GMAC_RXCLK_DLY_ENABLE(id) |
+ RK3588_GMAC_TXCLK_DLY_ENABLE(id));
+
+ regmap_write(bsp_priv->grf, offset_con,
+ RK3588_GMAC_CLK_RX_DL_CFG(rx_delay) |
+ RK3588_GMAC_CLK_TX_DL_CFG(tx_delay));
+}
+
+static void rk3588_set_to_rmii(struct rk_priv_data *bsp_priv)
+{
+ struct device *dev = &bsp_priv->pdev->dev;
+
+ if (IS_ERR(bsp_priv->php_grf)) {
+ dev_err(dev, "%s: Missing rockchip,php_grf property\n", __func__);
+ return;
+ }
+
+ regmap_write(bsp_priv->php_grf, RK3588_GRF_GMAC_CON0,
+ RK3588_GMAC_PHY_INTF_SEL_RMII(bsp_priv->id));
+
+ regmap_write(bsp_priv->php_grf, RK3588_GRF_CLK_CON1,
+ RK3588_GMAC_CLK_RMII_MODE(bsp_priv->id));
+}
+
+static void rk3588_set_gmac_speed(struct rk_priv_data *bsp_priv, int speed)
+{
+ struct device *dev = &bsp_priv->pdev->dev;
+ unsigned int val = 0, id = bsp_priv->id;
+
+ switch (speed) {
+ case 10:
+ if (bsp_priv->phy_iface == PHY_INTERFACE_MODE_RMII)
+ val = RK3588_GMA_CLK_RMII_DIV20(id);
+ else
+ val = RK3588_GMAC_CLK_RGMII_DIV50(id);
+ break;
+ case 100:
+ if (bsp_priv->phy_iface == PHY_INTERFACE_MODE_RMII)
+ val = RK3588_GMA_CLK_RMII_DIV2(id);
+ else
+ val = RK3588_GMAC_CLK_RGMII_DIV5(id);
+ break;
+ case 1000:
+ if (bsp_priv->phy_iface != PHY_INTERFACE_MODE_RMII)
+ val = RK3588_GMAC_CLK_RGMII_DIV1(id);
+ else
+ goto err;
+ break;
+ default:
+ goto err;
+ }
+
+ regmap_write(bsp_priv->php_grf, RK3588_GRF_CLK_CON1, val);
+
+ return;
+err:
+ dev_err(dev, "unknown speed value for GMAC speed=%d", speed);
+}
+
+static void rk3588_set_clock_selection(struct rk_priv_data *bsp_priv, bool input,
+ bool enable)
+{
+ unsigned int val = input ? RK3588_GMAC_CLK_SELET_IO(bsp_priv->id) :
+ RK3588_GMAC_CLK_SELET_CRU(bsp_priv->id);
+
+ val |= enable ? RK3588_GMAC_CLK_RMII_NOGATE(bsp_priv->id) :
+ RK3588_GMAC_CLK_RMII_GATE(bsp_priv->id);
+
+ regmap_write(bsp_priv->php_grf, RK3588_GRF_CLK_CON1, val);
+}
+
+static const struct rk_gmac_ops rk3588_ops = {
+ .set_to_rgmii = rk3588_set_to_rgmii,
+ .set_to_rmii = rk3588_set_to_rmii,
+ .set_rgmii_speed = rk3588_set_gmac_speed,
+ .set_rmii_speed = rk3588_set_gmac_speed,
+ .set_clock_selection = rk3588_set_clock_selection,
+ .regs_valid = true,
+ .regs = {
+ 0xfe1b0000, /* gmac0 */
+ 0xfe1c0000, /* gmac1 */
+ 0x0, /* sentinel */
+ },
+};
+
+#define RV1108_GRF_GMAC_CON0 0X0900
+
+/* RV1108_GRF_GMAC_CON0 */
+#define RV1108_GMAC_PHY_INTF_SEL_RMII (GRF_CLR_BIT(4) | GRF_CLR_BIT(5) | \
+ GRF_BIT(6))
+#define RV1108_GMAC_FLOW_CTRL GRF_BIT(3)
+#define RV1108_GMAC_FLOW_CTRL_CLR GRF_CLR_BIT(3)
+#define RV1108_GMAC_SPEED_10M GRF_CLR_BIT(2)
+#define RV1108_GMAC_SPEED_100M GRF_BIT(2)
+#define RV1108_GMAC_RMII_CLK_25M GRF_BIT(7)
+#define RV1108_GMAC_RMII_CLK_2_5M GRF_CLR_BIT(7)
+
+static void rv1108_set_to_rmii(struct rk_priv_data *bsp_priv)
+{
+ struct device *dev = &bsp_priv->pdev->dev;
+
+ if (IS_ERR(bsp_priv->grf)) {
+ dev_err(dev, "%s: Missing rockchip,grf property\n", __func__);
+ return;
+ }
+
+ regmap_write(bsp_priv->grf, RV1108_GRF_GMAC_CON0,
+ RV1108_GMAC_PHY_INTF_SEL_RMII);
+}
+
+static void rv1108_set_rmii_speed(struct rk_priv_data *bsp_priv, int speed)
+{
+ struct device *dev = &bsp_priv->pdev->dev;
+
+ if (IS_ERR(bsp_priv->grf)) {
+ dev_err(dev, "%s: Missing rockchip,grf property\n", __func__);
+ return;
+ }
+
+ if (speed == 10) {
+ regmap_write(bsp_priv->grf, RV1108_GRF_GMAC_CON0,
+ RV1108_GMAC_RMII_CLK_2_5M |
+ RV1108_GMAC_SPEED_10M);
+ } else if (speed == 100) {
+ regmap_write(bsp_priv->grf, RV1108_GRF_GMAC_CON0,
+ RV1108_GMAC_RMII_CLK_25M |
+ RV1108_GMAC_SPEED_100M);
+ } else {
+ dev_err(dev, "unknown speed value for RMII! speed=%d", speed);
+ }
+}
+
+static const struct rk_gmac_ops rv1108_ops = {
+ .set_to_rmii = rv1108_set_to_rmii,
+ .set_rmii_speed = rv1108_set_rmii_speed,
+};
+
+#define RV1126_GRF_GMAC_CON0 0X0070
+#define RV1126_GRF_GMAC_CON1 0X0074
+#define RV1126_GRF_GMAC_CON2 0X0078
+
+/* RV1126_GRF_GMAC_CON0 */
+#define RV1126_GMAC_PHY_INTF_SEL_RGMII \
+ (GRF_BIT(4) | GRF_CLR_BIT(5) | GRF_CLR_BIT(6))
+#define RV1126_GMAC_PHY_INTF_SEL_RMII \
+ (GRF_CLR_BIT(4) | GRF_CLR_BIT(5) | GRF_BIT(6))
+#define RV1126_GMAC_FLOW_CTRL GRF_BIT(7)
+#define RV1126_GMAC_FLOW_CTRL_CLR GRF_CLR_BIT(7)
+#define RV1126_GMAC_M0_RXCLK_DLY_ENABLE GRF_BIT(1)
+#define RV1126_GMAC_M0_RXCLK_DLY_DISABLE GRF_CLR_BIT(1)
+#define RV1126_GMAC_M0_TXCLK_DLY_ENABLE GRF_BIT(0)
+#define RV1126_GMAC_M0_TXCLK_DLY_DISABLE GRF_CLR_BIT(0)
+#define RV1126_GMAC_M1_RXCLK_DLY_ENABLE GRF_BIT(3)
+#define RV1126_GMAC_M1_RXCLK_DLY_DISABLE GRF_CLR_BIT(3)
+#define RV1126_GMAC_M1_TXCLK_DLY_ENABLE GRF_BIT(2)
+#define RV1126_GMAC_M1_TXCLK_DLY_DISABLE GRF_CLR_BIT(2)
+
+/* RV1126_GRF_GMAC_CON1 */
+#define RV1126_GMAC_M0_CLK_RX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 8)
+#define RV1126_GMAC_M0_CLK_TX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 0)
+/* RV1126_GRF_GMAC_CON2 */
+#define RV1126_GMAC_M1_CLK_RX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 8)
+#define RV1126_GMAC_M1_CLK_TX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 0)
+
+static void rv1126_set_to_rgmii(struct rk_priv_data *bsp_priv,
+ int tx_delay, int rx_delay)
+{
+ struct device *dev = &bsp_priv->pdev->dev;
+
+ if (IS_ERR(bsp_priv->grf)) {
+ dev_err(dev, "Missing rockchip,grf property\n");
+ return;
+ }
+
+ regmap_write(bsp_priv->grf, RV1126_GRF_GMAC_CON0,
+ RV1126_GMAC_PHY_INTF_SEL_RGMII |
+ RV1126_GMAC_M0_RXCLK_DLY_ENABLE |
+ RV1126_GMAC_M0_TXCLK_DLY_ENABLE |
+ RV1126_GMAC_M1_RXCLK_DLY_ENABLE |
+ RV1126_GMAC_M1_TXCLK_DLY_ENABLE);
+
+ regmap_write(bsp_priv->grf, RV1126_GRF_GMAC_CON1,
+ RV1126_GMAC_M0_CLK_RX_DL_CFG(rx_delay) |
+ RV1126_GMAC_M0_CLK_TX_DL_CFG(tx_delay));
+
+ regmap_write(bsp_priv->grf, RV1126_GRF_GMAC_CON2,
+ RV1126_GMAC_M1_CLK_RX_DL_CFG(rx_delay) |
+ RV1126_GMAC_M1_CLK_TX_DL_CFG(tx_delay));
+}
+
+static void rv1126_set_to_rmii(struct rk_priv_data *bsp_priv)
+{
+ struct device *dev = &bsp_priv->pdev->dev;
+
+ if (IS_ERR(bsp_priv->grf)) {
+ dev_err(dev, "%s: Missing rockchip,grf property\n", __func__);
+ return;
+ }
+
+ regmap_write(bsp_priv->grf, RV1126_GRF_GMAC_CON0,
+ RV1126_GMAC_PHY_INTF_SEL_RMII);
+}
+
+static void rv1126_set_rgmii_speed(struct rk_priv_data *bsp_priv, int speed)
+{
+ struct clk *clk_mac_speed = bsp_priv->clks[RK_CLK_MAC_SPEED].clk;
+ struct device *dev = &bsp_priv->pdev->dev;
+ unsigned long rate;
+ int ret;
+
+ switch (speed) {
+ case 10:
+ rate = 2500000;
+ break;
+ case 100:
+ rate = 25000000;
+ break;
+ case 1000:
+ rate = 125000000;
+ break;
+ default:
+ dev_err(dev, "unknown speed value for RGMII speed=%d", speed);
+ return;
+ }
+
+ ret = clk_set_rate(clk_mac_speed, rate);
+ if (ret)
+ dev_err(dev, "%s: set clk_mac_speed rate %ld failed %d\n",
+ __func__, rate, ret);
+}
+
+static void rv1126_set_rmii_speed(struct rk_priv_data *bsp_priv, int speed)
+{
+ struct clk *clk_mac_speed = bsp_priv->clks[RK_CLK_MAC_SPEED].clk;
+ struct device *dev = &bsp_priv->pdev->dev;
+ unsigned long rate;
+ int ret;
+
+ switch (speed) {
+ case 10:
+ rate = 2500000;
+ break;
+ case 100:
+ rate = 25000000;
+ break;
+ default:
+ dev_err(dev, "unknown speed value for RGMII speed=%d", speed);
+ return;
+ }
+
+ ret = clk_set_rate(clk_mac_speed, rate);
+ if (ret)
+ dev_err(dev, "%s: set clk_mac_speed rate %ld failed %d\n",
+ __func__, rate, ret);
+}
+
+static const struct rk_gmac_ops rv1126_ops = {
+ .set_to_rgmii = rv1126_set_to_rgmii,
+ .set_to_rmii = rv1126_set_to_rmii,
+ .set_rgmii_speed = rv1126_set_rgmii_speed,
+ .set_rmii_speed = rv1126_set_rmii_speed,
+};
+
+#define RK_GRF_MACPHY_CON0 0xb00
+#define RK_GRF_MACPHY_CON1 0xb04
+#define RK_GRF_MACPHY_CON2 0xb08
+#define RK_GRF_MACPHY_CON3 0xb0c
+
+#define RK_MACPHY_ENABLE GRF_BIT(0)
+#define RK_MACPHY_DISABLE GRF_CLR_BIT(0)
+#define RK_MACPHY_CFG_CLK_50M GRF_BIT(14)
+#define RK_GMAC2PHY_RMII_MODE (GRF_BIT(6) | GRF_CLR_BIT(7))
+#define RK_GRF_CON2_MACPHY_ID HIWORD_UPDATE(0x1234, 0xffff, 0)
+#define RK_GRF_CON3_MACPHY_ID HIWORD_UPDATE(0x35, 0x3f, 0)
+
+static void rk_gmac_integrated_phy_powerup(struct rk_priv_data *priv)
+{
+ if (priv->ops->integrated_phy_powerup)
+ priv->ops->integrated_phy_powerup(priv);
+
+ regmap_write(priv->grf, RK_GRF_MACPHY_CON0, RK_MACPHY_CFG_CLK_50M);
+ regmap_write(priv->grf, RK_GRF_MACPHY_CON0, RK_GMAC2PHY_RMII_MODE);
+
+ regmap_write(priv->grf, RK_GRF_MACPHY_CON2, RK_GRF_CON2_MACPHY_ID);
+ regmap_write(priv->grf, RK_GRF_MACPHY_CON3, RK_GRF_CON3_MACPHY_ID);
+
+ if (priv->phy_reset) {
+ /* PHY needs to be disabled before trying to reset it */
+ regmap_write(priv->grf, RK_GRF_MACPHY_CON0, RK_MACPHY_DISABLE);
+ if (priv->phy_reset)
+ reset_control_assert(priv->phy_reset);
+ usleep_range(10, 20);
+ if (priv->phy_reset)
+ reset_control_deassert(priv->phy_reset);
+ usleep_range(10, 20);
+ regmap_write(priv->grf, RK_GRF_MACPHY_CON0, RK_MACPHY_ENABLE);
+ msleep(30);
+ }
+}
+
+static void rk_gmac_integrated_phy_powerdown(struct rk_priv_data *priv)
+{
+ regmap_write(priv->grf, RK_GRF_MACPHY_CON0, RK_MACPHY_DISABLE);
+ if (priv->phy_reset)
+ reset_control_assert(priv->phy_reset);
+}
+
+static int rk_gmac_clk_init(struct plat_stmmacenet_data *plat)
+{
+ struct rk_priv_data *bsp_priv = plat->bsp_priv;
+ struct device *dev = &bsp_priv->pdev->dev;
+ int phy_iface = bsp_priv->phy_iface;
+ int i, j, ret;
+
+ bsp_priv->clk_enabled = false;
+
+ bsp_priv->num_clks = ARRAY_SIZE(rk_clocks);
+ if (phy_iface == PHY_INTERFACE_MODE_RMII)
+ bsp_priv->num_clks += ARRAY_SIZE(rk_rmii_clocks);
+
+ bsp_priv->clks = devm_kcalloc(dev, bsp_priv->num_clks,
+ sizeof(*bsp_priv->clks), GFP_KERNEL);
+ if (!bsp_priv->clks)
+ return -ENOMEM;
+
+ for (i = 0; i < ARRAY_SIZE(rk_clocks); i++)
+ bsp_priv->clks[i].id = rk_clocks[i];
+
+ if (phy_iface == PHY_INTERFACE_MODE_RMII) {
+ for (j = 0; j < ARRAY_SIZE(rk_rmii_clocks); j++)
+ bsp_priv->clks[i++].id = rk_rmii_clocks[j];
+ }
+
+ ret = devm_clk_bulk_get_optional(dev, bsp_priv->num_clks,
+ bsp_priv->clks);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to get clocks\n");
+
+ /* "stmmaceth" will be enabled by the core */
+ bsp_priv->clk_mac = devm_clk_get(dev, "stmmaceth");
+ ret = PTR_ERR_OR_ZERO(bsp_priv->clk_mac);
+ if (ret)
+ return dev_err_probe(dev, ret, "Cannot get stmmaceth clock\n");
+
+ if (bsp_priv->clock_input) {
+ dev_info(dev, "clock input from PHY\n");
+ } else if (phy_iface == PHY_INTERFACE_MODE_RMII) {
+ clk_set_rate(bsp_priv->clk_mac, 50000000);
+ }
+
+ if (plat->phy_node && bsp_priv->integrated_phy) {
+ bsp_priv->clk_phy = of_clk_get(plat->phy_node, 0);
+ ret = PTR_ERR_OR_ZERO(bsp_priv->clk_phy);
+ if (ret)
+ return dev_err_probe(dev, ret, "Cannot get PHY clock\n");
+ clk_set_rate(bsp_priv->clk_phy, 50000000);
+ }
+
+ return 0;
+}
+
+static int gmac_clk_enable(struct rk_priv_data *bsp_priv, bool enable)
+{
+ int ret;
+
+ if (enable) {
+ if (!bsp_priv->clk_enabled) {
+ ret = clk_bulk_prepare_enable(bsp_priv->num_clks,
+ bsp_priv->clks);
+ if (ret)
+ return ret;
+
+ ret = clk_prepare_enable(bsp_priv->clk_phy);
+ if (ret)
+ return ret;
+
+ if (bsp_priv->ops && bsp_priv->ops->set_clock_selection)
+ bsp_priv->ops->set_clock_selection(bsp_priv,
+ bsp_priv->clock_input, true);
+
+ mdelay(5);
+ bsp_priv->clk_enabled = true;
+ }
+ } else {
+ if (bsp_priv->clk_enabled) {
+ clk_bulk_disable_unprepare(bsp_priv->num_clks,
+ bsp_priv->clks);
+ clk_disable_unprepare(bsp_priv->clk_phy);
+
+ if (bsp_priv->ops && bsp_priv->ops->set_clock_selection)
+ bsp_priv->ops->set_clock_selection(bsp_priv,
+ bsp_priv->clock_input, false);
+
+ bsp_priv->clk_enabled = false;
+ }
+ }
+
+ return 0;
+}
+
+static int phy_power_on(struct rk_priv_data *bsp_priv, bool enable)
+{
+ struct regulator *ldo = bsp_priv->regulator;
+ int ret;
+ struct device *dev = &bsp_priv->pdev->dev;
+
+ if (enable) {
+ ret = regulator_enable(ldo);
+ if (ret)
+ dev_err(dev, "fail to enable phy-supply\n");
+ } else {
+ ret = regulator_disable(ldo);
+ if (ret)
+ dev_err(dev, "fail to disable phy-supply\n");
+ }
+
+ return 0;
+}
+
+static struct rk_priv_data *rk_gmac_setup(struct platform_device *pdev,
+ struct plat_stmmacenet_data *plat,
+ const struct rk_gmac_ops *ops)
+{
+ struct rk_priv_data *bsp_priv;
+ struct device *dev = &pdev->dev;
+ struct resource *res;
+ int ret;
+ const char *strings = NULL;
+ int value;
+
+ bsp_priv = devm_kzalloc(dev, sizeof(*bsp_priv), GFP_KERNEL);
+ if (!bsp_priv)
+ return ERR_PTR(-ENOMEM);
+
+ of_get_phy_mode(dev->of_node, &bsp_priv->phy_iface);
+ bsp_priv->ops = ops;
+
+ /* Some SoCs have multiple MAC controllers, which need
+ * to be distinguished.
+ */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res && ops->regs_valid) {
+ int i = 0;
+
+ while (ops->regs[i]) {
+ if (ops->regs[i] == res->start) {
+ bsp_priv->id = i;
+ break;
+ }
+ i++;
+ }
+ }
+
+ bsp_priv->regulator = devm_regulator_get(dev, "phy");
+ if (IS_ERR(bsp_priv->regulator)) {
+ ret = PTR_ERR(bsp_priv->regulator);
+ dev_err_probe(dev, ret, "failed to get phy regulator\n");
+ return ERR_PTR(ret);
+ }
+
+ ret = of_property_read_string(dev->of_node, "clock_in_out", &strings);
+ if (ret) {
+ dev_err(dev, "Can not read property: clock_in_out.\n");
+ bsp_priv->clock_input = true;
+ } else {
+ dev_info(dev, "clock input or output? (%s).\n",
+ strings);
+ if (!strcmp(strings, "input"))
+ bsp_priv->clock_input = true;
+ else
+ bsp_priv->clock_input = false;
+ }
+
+ ret = of_property_read_u32(dev->of_node, "tx_delay", &value);
+ if (ret) {
+ bsp_priv->tx_delay = 0x30;
+ dev_err(dev, "Can not read property: tx_delay.");
+ dev_err(dev, "set tx_delay to 0x%x\n",
+ bsp_priv->tx_delay);
+ } else {
+ dev_info(dev, "TX delay(0x%x).\n", value);
+ bsp_priv->tx_delay = value;
+ }
+
+ ret = of_property_read_u32(dev->of_node, "rx_delay", &value);
+ if (ret) {
+ bsp_priv->rx_delay = 0x10;
+ dev_err(dev, "Can not read property: rx_delay.");
+ dev_err(dev, "set rx_delay to 0x%x\n",
+ bsp_priv->rx_delay);
+ } else {
+ dev_info(dev, "RX delay(0x%x).\n", value);
+ bsp_priv->rx_delay = value;
+ }
+
+ bsp_priv->grf = syscon_regmap_lookup_by_phandle(dev->of_node,
+ "rockchip,grf");
+ bsp_priv->php_grf = syscon_regmap_lookup_by_phandle(dev->of_node,
+ "rockchip,php-grf");
+
+ if (plat->phy_node) {
+ bsp_priv->integrated_phy = of_property_read_bool(plat->phy_node,
+ "phy-is-integrated");
+ if (bsp_priv->integrated_phy) {
+ bsp_priv->phy_reset = of_reset_control_get(plat->phy_node, NULL);
+ if (IS_ERR(bsp_priv->phy_reset)) {
+ dev_err(&pdev->dev, "No PHY reset control found.\n");
+ bsp_priv->phy_reset = NULL;
+ }
+ }
+ }
+ dev_info(dev, "integrated PHY? (%s).\n",
+ bsp_priv->integrated_phy ? "yes" : "no");
+
+ bsp_priv->pdev = pdev;
+
+ return bsp_priv;
+}
+
+static int rk_gmac_check_ops(struct rk_priv_data *bsp_priv)
+{
+ switch (bsp_priv->phy_iface) {
+ case PHY_INTERFACE_MODE_RGMII:
+ case PHY_INTERFACE_MODE_RGMII_ID:
+ case PHY_INTERFACE_MODE_RGMII_RXID:
+ case PHY_INTERFACE_MODE_RGMII_TXID:
+ if (!bsp_priv->ops->set_to_rgmii)
+ return -EINVAL;
+ break;
+ case PHY_INTERFACE_MODE_RMII:
+ if (!bsp_priv->ops->set_to_rmii)
+ return -EINVAL;
+ break;
+ default:
+ dev_err(&bsp_priv->pdev->dev,
+ "unsupported interface %d", bsp_priv->phy_iface);
+ }
+ return 0;
+}
+
+static int rk_gmac_powerup(struct rk_priv_data *bsp_priv)
+{
+ int ret;
+ struct device *dev = &bsp_priv->pdev->dev;
+
+ ret = rk_gmac_check_ops(bsp_priv);
+ if (ret)
+ return ret;
+
+ ret = gmac_clk_enable(bsp_priv, true);
+ if (ret)
+ return ret;
+
+ /*rmii or rgmii*/
+ switch (bsp_priv->phy_iface) {
+ case PHY_INTERFACE_MODE_RGMII:
+ dev_info(dev, "init for RGMII\n");
+ bsp_priv->ops->set_to_rgmii(bsp_priv, bsp_priv->tx_delay,
+ bsp_priv->rx_delay);
+ break;
+ case PHY_INTERFACE_MODE_RGMII_ID:
+ dev_info(dev, "init for RGMII_ID\n");
+ bsp_priv->ops->set_to_rgmii(bsp_priv, 0, 0);
+ break;
+ case PHY_INTERFACE_MODE_RGMII_RXID:
+ dev_info(dev, "init for RGMII_RXID\n");
+ bsp_priv->ops->set_to_rgmii(bsp_priv, bsp_priv->tx_delay, 0);
+ break;
+ case PHY_INTERFACE_MODE_RGMII_TXID:
+ dev_info(dev, "init for RGMII_TXID\n");
+ bsp_priv->ops->set_to_rgmii(bsp_priv, 0, bsp_priv->rx_delay);
+ break;
+ case PHY_INTERFACE_MODE_RMII:
+ dev_info(dev, "init for RMII\n");
+ bsp_priv->ops->set_to_rmii(bsp_priv);
+ break;
+ default:
+ dev_err(dev, "NO interface defined!\n");
+ }
+
+ ret = phy_power_on(bsp_priv, true);
+ if (ret) {
+ gmac_clk_enable(bsp_priv, false);
+ return ret;
+ }
+
+ pm_runtime_enable(dev);
+ pm_runtime_get_sync(dev);
+
+ if (bsp_priv->integrated_phy)
+ rk_gmac_integrated_phy_powerup(bsp_priv);
+
+ return 0;
+}
+
+static void rk_gmac_powerdown(struct rk_priv_data *gmac)
+{
+ struct device *dev = &gmac->pdev->dev;
+
+ if (gmac->integrated_phy)
+ rk_gmac_integrated_phy_powerdown(gmac);
+
+ pm_runtime_put_sync(dev);
+ pm_runtime_disable(dev);
+
+ phy_power_on(gmac, false);
+ gmac_clk_enable(gmac, false);
+}
+
+static void rk_fix_speed(void *priv, unsigned int speed)
+{
+ struct rk_priv_data *bsp_priv = priv;
+ struct device *dev = &bsp_priv->pdev->dev;
+
+ switch (bsp_priv->phy_iface) {
+ case PHY_INTERFACE_MODE_RGMII:
+ case PHY_INTERFACE_MODE_RGMII_ID:
+ case PHY_INTERFACE_MODE_RGMII_RXID:
+ case PHY_INTERFACE_MODE_RGMII_TXID:
+ if (bsp_priv->ops->set_rgmii_speed)
+ bsp_priv->ops->set_rgmii_speed(bsp_priv, speed);
+ break;
+ case PHY_INTERFACE_MODE_RMII:
+ if (bsp_priv->ops->set_rmii_speed)
+ bsp_priv->ops->set_rmii_speed(bsp_priv, speed);
+ break;
+ default:
+ dev_err(dev, "unsupported interface %d", bsp_priv->phy_iface);
+ }
+}
+
+static int rk_gmac_probe(struct platform_device *pdev)
+{
+ struct plat_stmmacenet_data *plat_dat;
+ struct stmmac_resources stmmac_res;
+ const struct rk_gmac_ops *data;
+ int ret;
+
+ data = of_device_get_match_data(&pdev->dev);
+ if (!data) {
+ dev_err(&pdev->dev, "no of match data provided\n");
+ return -EINVAL;
+ }
+
+ ret = stmmac_get_platform_resources(pdev, &stmmac_res);
+ if (ret)
+ return ret;
+
+ plat_dat = stmmac_probe_config_dt(pdev, stmmac_res.mac);
+ if (IS_ERR(plat_dat))
+ return PTR_ERR(plat_dat);
+
+ /* If the stmmac is not already selected as gmac4,
+ * then make sure we fallback to gmac.
+ */
+ if (!plat_dat->has_gmac4)
+ plat_dat->has_gmac = true;
+ plat_dat->fix_mac_speed = rk_fix_speed;
+
+ plat_dat->bsp_priv = rk_gmac_setup(pdev, plat_dat, data);
+ if (IS_ERR(plat_dat->bsp_priv)) {
+ ret = PTR_ERR(plat_dat->bsp_priv);
+ goto err_remove_config_dt;
+ }
+
+ ret = rk_gmac_clk_init(plat_dat);
+ if (ret)
+ goto err_remove_config_dt;
+
+ ret = rk_gmac_powerup(plat_dat->bsp_priv);
+ if (ret)
+ goto err_remove_config_dt;
+
+ ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
+ if (ret)
+ goto err_gmac_powerdown;
+
+ return 0;
+
+err_gmac_powerdown:
+ rk_gmac_powerdown(plat_dat->bsp_priv);
+err_remove_config_dt:
+ stmmac_remove_config_dt(pdev, plat_dat);
+
+ return ret;
+}
+
+static int rk_gmac_remove(struct platform_device *pdev)
+{
+ struct rk_priv_data *bsp_priv = get_stmmac_bsp_priv(&pdev->dev);
+ int ret = stmmac_dvr_remove(&pdev->dev);
+
+ rk_gmac_powerdown(bsp_priv);
+
+ return ret;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int rk_gmac_suspend(struct device *dev)
+{
+ struct rk_priv_data *bsp_priv = get_stmmac_bsp_priv(dev);
+ int ret = stmmac_suspend(dev);
+
+ /* Keep the PHY up if we use Wake-on-Lan. */
+ if (!device_may_wakeup(dev)) {
+ rk_gmac_powerdown(bsp_priv);
+ bsp_priv->suspended = true;
+ }
+
+ return ret;
+}
+
+static int rk_gmac_resume(struct device *dev)
+{
+ struct rk_priv_data *bsp_priv = get_stmmac_bsp_priv(dev);
+
+ /* The PHY was up for Wake-on-Lan. */
+ if (bsp_priv->suspended) {
+ rk_gmac_powerup(bsp_priv);
+ bsp_priv->suspended = false;
+ }
+
+ return stmmac_resume(dev);
+}
+#endif /* CONFIG_PM_SLEEP */
+
+static SIMPLE_DEV_PM_OPS(rk_gmac_pm_ops, rk_gmac_suspend, rk_gmac_resume);
+
+static const struct of_device_id rk_gmac_dwmac_match[] = {
+ { .compatible = "rockchip,px30-gmac", .data = &px30_ops },
+ { .compatible = "rockchip,rk3128-gmac", .data = &rk3128_ops },
+ { .compatible = "rockchip,rk3228-gmac", .data = &rk3228_ops },
+ { .compatible = "rockchip,rk3288-gmac", .data = &rk3288_ops },
+ { .compatible = "rockchip,rk3308-gmac", .data = &rk3308_ops },
+ { .compatible = "rockchip,rk3328-gmac", .data = &rk3328_ops },
+ { .compatible = "rockchip,rk3366-gmac", .data = &rk3366_ops },
+ { .compatible = "rockchip,rk3368-gmac", .data = &rk3368_ops },
+ { .compatible = "rockchip,rk3399-gmac", .data = &rk3399_ops },
+ { .compatible = "rockchip,rk3568-gmac", .data = &rk3568_ops },
+ { .compatible = "rockchip,rk3588-gmac", .data = &rk3588_ops },
+ { .compatible = "rockchip,rv1108-gmac", .data = &rv1108_ops },
+ { .compatible = "rockchip,rv1126-gmac", .data = &rv1126_ops },
+ { }
+};
+MODULE_DEVICE_TABLE(of, rk_gmac_dwmac_match);
+
+static struct platform_driver rk_gmac_dwmac_driver = {
+ .probe = rk_gmac_probe,
+ .remove = rk_gmac_remove,
+ .driver = {
+ .name = "rk_gmac-dwmac",
+ .pm = &rk_gmac_pm_ops,
+ .of_match_table = rk_gmac_dwmac_match,
+ },
+};
+module_platform_driver(rk_gmac_dwmac_driver);
+
+MODULE_AUTHOR("Chen-Zhi (Roger Chen) <roger.chen@rock-chips.com>");
+MODULE_DESCRIPTION("Rockchip RK3288 DWMAC specific glue layer");
+MODULE_LICENSE("GPL");
Index: v6.x/create-6.1.53-host-limits-patch/create.patch.sh
===================================================================
--- v6.x/create-6.1.53-host-limits-patch/create.patch.sh (nonexistent)
+++ v6.x/create-6.1.53-host-limits-patch/create.patch.sh (revision 385)
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+VERSION=6.1.53
+
+tar --files-from=file.list -xJvf ../linux-$VERSION.tar.xz
+mv linux-$VERSION linux-$VERSION-orig
+
+cp -rf ./linux-$VERSION-new ./linux-$VERSION
+
+diff --unified -Nr linux-$VERSION-orig linux-$VERSION > linux-$VERSION-host-limits.patch
+
+mv linux-$VERSION-host-limits.patch ../patches
+
+rm -rf ./linux-$VERSION
+rm -rf ./linux-$VERSION-orig
Property changes on: v6.x/create-6.1.53-host-limits-patch/create.patch.sh
___________________________________________________________________
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: v6.x/create-6.1.53-host-limits-patch/file.list
===================================================================
--- v6.x/create-6.1.53-host-limits-patch/file.list (nonexistent)
+++ v6.x/create-6.1.53-host-limits-patch/file.list (revision 385)
@@ -0,0 +1,7 @@
+linux-6.1.53/scripts/kconfig/conf.c
+linux-6.1.53/scripts/kconfig/confdata.c
+linux-6.1.53/scripts/kconfig/lexer.l
+linux-6.1.53/scripts/mod/modpost.c
+linux-6.1.53/scripts/mod/sumversion.c
+linux-6.1.53/tools/build/fixdep.c
+linux-6.1.53/usr/gen_init_cpio.c
Index: v6.x/create-6.1.53-host-limits-patch/linux-6.1.53-new/scripts/kconfig/conf.c
===================================================================
--- v6.x/create-6.1.53-host-limits-patch/linux-6.1.53-new/scripts/kconfig/conf.c (nonexistent)
+++ v6.x/create-6.1.53-host-limits-patch/linux-6.1.53-new/scripts/kconfig/conf.c (revision 385)
@@ -0,0 +1,921 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ */
+
+#include <ctype.h>
+#include <linux/limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <sys/time.h>
+#include <errno.h>
+
+#include "lkc.h"
+
+static void conf(struct menu *menu);
+static void check_conf(struct menu *menu);
+
+enum input_mode {
+ oldaskconfig,
+ syncconfig,
+ oldconfig,
+ allnoconfig,
+ allyesconfig,
+ allmodconfig,
+ alldefconfig,
+ randconfig,
+ defconfig,
+ savedefconfig,
+ listnewconfig,
+ helpnewconfig,
+ olddefconfig,
+ yes2modconfig,
+ mod2yesconfig,
+ mod2noconfig,
+};
+static enum input_mode input_mode = oldaskconfig;
+static int input_mode_opt;
+static int indent = 1;
+static int tty_stdio;
+static int sync_kconfig;
+static int conf_cnt;
+static char line[PATH_MAX];
+static struct menu *rootEntry;
+
+static void print_help(struct menu *menu)
+{
+ struct gstr help = str_new();
+
+ menu_get_ext_help(menu, &help);
+
+ printf("\n%s\n", str_get(&help));
+ str_free(&help);
+}
+
+static void strip(char *str)
+{
+ char *p = str;
+ int l;
+
+ while ((isspace(*p)))
+ p++;
+ l = strlen(p);
+ if (p != str)
+ memmove(str, p, l + 1);
+ if (!l)
+ return;
+ p = str + l - 1;
+ while ((isspace(*p)))
+ *p-- = 0;
+}
+
+/* Helper function to facilitate fgets() by Jean Sacren. */
+static void xfgets(char *str, int size, FILE *in)
+{
+ if (!fgets(str, size, in))
+ fprintf(stderr, "\nError in reading or end of file.\n");
+
+ if (!tty_stdio)
+ printf("%s", str);
+}
+
+static void set_randconfig_seed(void)
+{
+ unsigned int seed;
+ char *env;
+ bool seed_set = false;
+
+ env = getenv("KCONFIG_SEED");
+ if (env && *env) {
+ char *endp;
+
+ seed = strtol(env, &endp, 0);
+ if (*endp == '\0')
+ seed_set = true;
+ }
+
+ if (!seed_set) {
+ struct timeval now;
+
+ /*
+ * Use microseconds derived seed, compensate for systems where it may
+ * be zero.
+ */
+ gettimeofday(&now, NULL);
+ seed = (now.tv_sec + 1) * (now.tv_usec + 1);
+ }
+
+ printf("KCONFIG_SEED=0x%X\n", seed);
+ srand(seed);
+}
+
+static bool randomize_choice_values(struct symbol *csym)
+{
+ struct property *prop;
+ struct symbol *sym;
+ struct expr *e;
+ int cnt, def;
+
+ /*
+ * If choice is mod then we may have more items selected
+ * and if no then no-one.
+ * In both cases stop.
+ */
+ if (csym->curr.tri != yes)
+ return false;
+
+ prop = sym_get_choice_prop(csym);
+
+ /* count entries in choice block */
+ cnt = 0;
+ expr_list_for_each_sym(prop->expr, e, sym)
+ cnt++;
+
+ /*
+ * find a random value and set it to yes,
+ * set the rest to no so we have only one set
+ */
+ def = rand() % cnt;
+
+ cnt = 0;
+ expr_list_for_each_sym(prop->expr, e, sym) {
+ if (def == cnt++) {
+ sym->def[S_DEF_USER].tri = yes;
+ csym->def[S_DEF_USER].val = sym;
+ } else {
+ sym->def[S_DEF_USER].tri = no;
+ }
+ sym->flags |= SYMBOL_DEF_USER;
+ /* clear VALID to get value calculated */
+ sym->flags &= ~SYMBOL_VALID;
+ }
+ csym->flags |= SYMBOL_DEF_USER;
+ /* clear VALID to get value calculated */
+ csym->flags &= ~SYMBOL_VALID;
+
+ return true;
+}
+
+enum conf_def_mode {
+ def_default,
+ def_yes,
+ def_mod,
+ def_no,
+ def_random
+};
+
+static bool conf_set_all_new_symbols(enum conf_def_mode mode)
+{
+ struct symbol *sym, *csym;
+ int i, cnt;
+ /*
+ * can't go as the default in switch-case below, otherwise gcc whines
+ * about -Wmaybe-uninitialized
+ */
+ int pby = 50; /* probability of bool = y */
+ int pty = 33; /* probability of tristate = y */
+ int ptm = 33; /* probability of tristate = m */
+ bool has_changed = false;
+
+ if (mode == def_random) {
+ int n, p[3];
+ char *env = getenv("KCONFIG_PROBABILITY");
+
+ n = 0;
+ while (env && *env) {
+ char *endp;
+ int tmp = strtol(env, &endp, 10);
+
+ if (tmp >= 0 && tmp <= 100) {
+ p[n++] = tmp;
+ } else {
+ errno = ERANGE;
+ perror("KCONFIG_PROBABILITY");
+ exit(1);
+ }
+ env = (*endp == ':') ? endp + 1 : endp;
+ if (n >= 3)
+ break;
+ }
+ switch (n) {
+ case 1:
+ pby = p[0];
+ ptm = pby / 2;
+ pty = pby - ptm;
+ break;
+ case 2:
+ pty = p[0];
+ ptm = p[1];
+ pby = pty + ptm;
+ break;
+ case 3:
+ pby = p[0];
+ pty = p[1];
+ ptm = p[2];
+ break;
+ }
+
+ if (pty + ptm > 100) {
+ errno = ERANGE;
+ perror("KCONFIG_PROBABILITY");
+ exit(1);
+ }
+ }
+
+ for_all_symbols(i, sym) {
+ if (sym_has_value(sym) || sym->flags & SYMBOL_VALID)
+ continue;
+ switch (sym_get_type(sym)) {
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ has_changed = true;
+ switch (mode) {
+ case def_yes:
+ sym->def[S_DEF_USER].tri = yes;
+ break;
+ case def_mod:
+ sym->def[S_DEF_USER].tri = mod;
+ break;
+ case def_no:
+ sym->def[S_DEF_USER].tri = no;
+ break;
+ case def_random:
+ sym->def[S_DEF_USER].tri = no;
+ cnt = rand() % 100;
+ if (sym->type == S_TRISTATE) {
+ if (cnt < pty)
+ sym->def[S_DEF_USER].tri = yes;
+ else if (cnt < pty + ptm)
+ sym->def[S_DEF_USER].tri = mod;
+ } else if (cnt < pby)
+ sym->def[S_DEF_USER].tri = yes;
+ break;
+ default:
+ continue;
+ }
+ if (!(sym_is_choice(sym) && mode == def_random))
+ sym->flags |= SYMBOL_DEF_USER;
+ break;
+ default:
+ break;
+ }
+
+ }
+
+ sym_clear_all_valid();
+
+ /*
+ * We have different type of choice blocks.
+ * If curr.tri equals to mod then we can select several
+ * choice symbols in one block.
+ * In this case we do nothing.
+ * If curr.tri equals yes then only one symbol can be
+ * selected in a choice block and we set it to yes,
+ * and the rest to no.
+ */
+ if (mode != def_random) {
+ for_all_symbols(i, csym) {
+ if ((sym_is_choice(csym) && !sym_has_value(csym)) ||
+ sym_is_choice_value(csym))
+ csym->flags |= SYMBOL_NEED_SET_CHOICE_VALUES;
+ }
+ }
+
+ for_all_symbols(i, csym) {
+ if (sym_has_value(csym) || !sym_is_choice(csym))
+ continue;
+
+ sym_calc_value(csym);
+ if (mode == def_random)
+ has_changed |= randomize_choice_values(csym);
+ else {
+ set_all_choice_values(csym);
+ has_changed = true;
+ }
+ }
+
+ return has_changed;
+}
+
+static void conf_rewrite_tristates(tristate old_val, tristate new_val)
+{
+ struct symbol *sym;
+ int i;
+
+ for_all_symbols(i, sym) {
+ if (sym_get_type(sym) == S_TRISTATE &&
+ sym->def[S_DEF_USER].tri == old_val)
+ sym->def[S_DEF_USER].tri = new_val;
+ }
+ sym_clear_all_valid();
+}
+
+static int conf_askvalue(struct symbol *sym, const char *def)
+{
+ if (!sym_has_value(sym))
+ printf("(NEW) ");
+
+ line[0] = '\n';
+ line[1] = 0;
+
+ if (!sym_is_changeable(sym)) {
+ printf("%s\n", def);
+ line[0] = '\n';
+ line[1] = 0;
+ return 0;
+ }
+
+ switch (input_mode) {
+ case oldconfig:
+ case syncconfig:
+ if (sym_has_value(sym)) {
+ printf("%s\n", def);
+ return 0;
+ }
+ /* fall through */
+ default:
+ fflush(stdout);
+ xfgets(line, sizeof(line), stdin);
+ break;
+ }
+
+ return 1;
+}
+
+static int conf_string(struct menu *menu)
+{
+ struct symbol *sym = menu->sym;
+ const char *def;
+
+ while (1) {
+ printf("%*s%s ", indent - 1, "", menu->prompt->text);
+ printf("(%s) ", sym->name);
+ def = sym_get_string_value(sym);
+ if (def)
+ printf("[%s] ", def);
+ if (!conf_askvalue(sym, def))
+ return 0;
+ switch (line[0]) {
+ case '\n':
+ break;
+ case '?':
+ /* print help */
+ if (line[1] == '\n') {
+ print_help(menu);
+ def = NULL;
+ break;
+ }
+ /* fall through */
+ default:
+ line[strlen(line)-1] = 0;
+ def = line;
+ }
+ if (def && sym_set_string_value(sym, def))
+ return 0;
+ }
+}
+
+static int conf_sym(struct menu *menu)
+{
+ struct symbol *sym = menu->sym;
+ tristate oldval, newval;
+
+ while (1) {
+ printf("%*s%s ", indent - 1, "", menu->prompt->text);
+ if (sym->name)
+ printf("(%s) ", sym->name);
+ putchar('[');
+ oldval = sym_get_tristate_value(sym);
+ switch (oldval) {
+ case no:
+ putchar('N');
+ break;
+ case mod:
+ putchar('M');
+ break;
+ case yes:
+ putchar('Y');
+ break;
+ }
+ if (oldval != no && sym_tristate_within_range(sym, no))
+ printf("/n");
+ if (oldval != mod && sym_tristate_within_range(sym, mod))
+ printf("/m");
+ if (oldval != yes && sym_tristate_within_range(sym, yes))
+ printf("/y");
+ printf("/?] ");
+ if (!conf_askvalue(sym, sym_get_string_value(sym)))
+ return 0;
+ strip(line);
+
+ switch (line[0]) {
+ case 'n':
+ case 'N':
+ newval = no;
+ if (!line[1] || !strcmp(&line[1], "o"))
+ break;
+ continue;
+ case 'm':
+ case 'M':
+ newval = mod;
+ if (!line[1])
+ break;
+ continue;
+ case 'y':
+ case 'Y':
+ newval = yes;
+ if (!line[1] || !strcmp(&line[1], "es"))
+ break;
+ continue;
+ case 0:
+ newval = oldval;
+ break;
+ case '?':
+ goto help;
+ default:
+ continue;
+ }
+ if (sym_set_tristate_value(sym, newval))
+ return 0;
+help:
+ print_help(menu);
+ }
+}
+
+static int conf_choice(struct menu *menu)
+{
+ struct symbol *sym, *def_sym;
+ struct menu *child;
+ bool is_new;
+
+ sym = menu->sym;
+ is_new = !sym_has_value(sym);
+ if (sym_is_changeable(sym)) {
+ conf_sym(menu);
+ sym_calc_value(sym);
+ switch (sym_get_tristate_value(sym)) {
+ case no:
+ return 1;
+ case mod:
+ return 0;
+ case yes:
+ break;
+ }
+ } else {
+ switch (sym_get_tristate_value(sym)) {
+ case no:
+ return 1;
+ case mod:
+ printf("%*s%s\n", indent - 1, "", menu_get_prompt(menu));
+ return 0;
+ case yes:
+ break;
+ }
+ }
+
+ while (1) {
+ int cnt, def;
+
+ printf("%*s%s\n", indent - 1, "", menu_get_prompt(menu));
+ def_sym = sym_get_choice_value(sym);
+ cnt = def = 0;
+ line[0] = 0;
+ for (child = menu->list; child; child = child->next) {
+ if (!menu_is_visible(child))
+ continue;
+ if (!child->sym) {
+ printf("%*c %s\n", indent, '*', menu_get_prompt(child));
+ continue;
+ }
+ cnt++;
+ if (child->sym == def_sym) {
+ def = cnt;
+ printf("%*c", indent, '>');
+ } else
+ printf("%*c", indent, ' ');
+ printf(" %d. %s", cnt, menu_get_prompt(child));
+ if (child->sym->name)
+ printf(" (%s)", child->sym->name);
+ if (!sym_has_value(child->sym))
+ printf(" (NEW)");
+ printf("\n");
+ }
+ printf("%*schoice", indent - 1, "");
+ if (cnt == 1) {
+ printf("[1]: 1\n");
+ goto conf_childs;
+ }
+ printf("[1-%d?]: ", cnt);
+ switch (input_mode) {
+ case oldconfig:
+ case syncconfig:
+ if (!is_new) {
+ cnt = def;
+ printf("%d\n", cnt);
+ break;
+ }
+ /* fall through */
+ case oldaskconfig:
+ fflush(stdout);
+ xfgets(line, sizeof(line), stdin);
+ strip(line);
+ if (line[0] == '?') {
+ print_help(menu);
+ continue;
+ }
+ if (!line[0])
+ cnt = def;
+ else if (isdigit(line[0]))
+ cnt = atoi(line);
+ else
+ continue;
+ break;
+ default:
+ break;
+ }
+
+ conf_childs:
+ for (child = menu->list; child; child = child->next) {
+ if (!child->sym || !menu_is_visible(child))
+ continue;
+ if (!--cnt)
+ break;
+ }
+ if (!child)
+ continue;
+ if (line[0] && line[strlen(line) - 1] == '?') {
+ print_help(child);
+ continue;
+ }
+ sym_set_tristate_value(child->sym, yes);
+ for (child = child->list; child; child = child->next) {
+ indent += 2;
+ conf(child);
+ indent -= 2;
+ }
+ return 1;
+ }
+}
+
+static void conf(struct menu *menu)
+{
+ struct symbol *sym;
+ struct property *prop;
+ struct menu *child;
+
+ if (!menu_is_visible(menu))
+ return;
+
+ sym = menu->sym;
+ prop = menu->prompt;
+ if (prop) {
+ const char *prompt;
+
+ switch (prop->type) {
+ case P_MENU:
+ /*
+ * Except in oldaskconfig mode, we show only menus that
+ * contain new symbols.
+ */
+ if (input_mode != oldaskconfig && rootEntry != menu) {
+ check_conf(menu);
+ return;
+ }
+ /* fall through */
+ case P_COMMENT:
+ prompt = menu_get_prompt(menu);
+ if (prompt)
+ printf("%*c\n%*c %s\n%*c\n",
+ indent, '*',
+ indent, '*', prompt,
+ indent, '*');
+ default:
+ ;
+ }
+ }
+
+ if (!sym)
+ goto conf_childs;
+
+ if (sym_is_choice(sym)) {
+ conf_choice(menu);
+ if (sym->curr.tri != mod)
+ return;
+ goto conf_childs;
+ }
+
+ switch (sym->type) {
+ case S_INT:
+ case S_HEX:
+ case S_STRING:
+ conf_string(menu);
+ break;
+ default:
+ conf_sym(menu);
+ break;
+ }
+
+conf_childs:
+ if (sym)
+ indent += 2;
+ for (child = menu->list; child; child = child->next)
+ conf(child);
+ if (sym)
+ indent -= 2;
+}
+
+static void check_conf(struct menu *menu)
+{
+ struct symbol *sym;
+ struct menu *child;
+
+ if (!menu_is_visible(menu))
+ return;
+
+ sym = menu->sym;
+ if (sym && !sym_has_value(sym) &&
+ (sym_is_changeable(sym) ||
+ (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes))) {
+
+ switch (input_mode) {
+ case listnewconfig:
+ if (sym->name)
+ print_symbol_for_listconfig(sym);
+ break;
+ case helpnewconfig:
+ printf("-----\n");
+ print_help(menu);
+ printf("-----\n");
+ break;
+ default:
+ if (!conf_cnt++)
+ printf("*\n* Restart config...\n*\n");
+ rootEntry = menu_get_parent_menu(menu);
+ conf(rootEntry);
+ break;
+ }
+ }
+
+ for (child = menu->list; child; child = child->next)
+ check_conf(child);
+}
+
+static const struct option long_opts[] = {
+ {"help", no_argument, NULL, 'h'},
+ {"silent", no_argument, NULL, 's'},
+ {"oldaskconfig", no_argument, &input_mode_opt, oldaskconfig},
+ {"oldconfig", no_argument, &input_mode_opt, oldconfig},
+ {"syncconfig", no_argument, &input_mode_opt, syncconfig},
+ {"defconfig", required_argument, &input_mode_opt, defconfig},
+ {"savedefconfig", required_argument, &input_mode_opt, savedefconfig},
+ {"allnoconfig", no_argument, &input_mode_opt, allnoconfig},
+ {"allyesconfig", no_argument, &input_mode_opt, allyesconfig},
+ {"allmodconfig", no_argument, &input_mode_opt, allmodconfig},
+ {"alldefconfig", no_argument, &input_mode_opt, alldefconfig},
+ {"randconfig", no_argument, &input_mode_opt, randconfig},
+ {"listnewconfig", no_argument, &input_mode_opt, listnewconfig},
+ {"helpnewconfig", no_argument, &input_mode_opt, helpnewconfig},
+ {"olddefconfig", no_argument, &input_mode_opt, olddefconfig},
+ {"yes2modconfig", no_argument, &input_mode_opt, yes2modconfig},
+ {"mod2yesconfig", no_argument, &input_mode_opt, mod2yesconfig},
+ {"mod2noconfig", no_argument, &input_mode_opt, mod2noconfig},
+ {NULL, 0, NULL, 0}
+};
+
+static void conf_usage(const char *progname)
+{
+ printf("Usage: %s [options] <kconfig-file>\n", progname);
+ printf("\n");
+ printf("Generic options:\n");
+ printf(" -h, --help Print this message and exit.\n");
+ printf(" -s, --silent Do not print log.\n");
+ printf("\n");
+ printf("Mode options:\n");
+ printf(" --listnewconfig List new options\n");
+ printf(" --helpnewconfig List new options and help text\n");
+ printf(" --oldaskconfig Start a new configuration using a line-oriented program\n");
+ printf(" --oldconfig Update a configuration using a provided .config as base\n");
+ printf(" --syncconfig Similar to oldconfig but generates configuration in\n"
+ " include/{generated/,config/}\n");
+ printf(" --olddefconfig Same as oldconfig but sets new symbols to their default value\n");
+ printf(" --defconfig <file> New config with default defined in <file>\n");
+ printf(" --savedefconfig <file> Save the minimal current configuration to <file>\n");
+ printf(" --allnoconfig New config where all options are answered with no\n");
+ printf(" --allyesconfig New config where all options are answered with yes\n");
+ printf(" --allmodconfig New config where all options are answered with mod\n");
+ printf(" --alldefconfig New config with all symbols set to default\n");
+ printf(" --randconfig New config with random answer to all options\n");
+ printf(" --yes2modconfig Change answers from yes to mod if possible\n");
+ printf(" --mod2yesconfig Change answers from mod to yes if possible\n");
+ printf(" --mod2noconfig Change answers from mod to no if possible\n");
+ printf(" (If none of the above is given, --oldaskconfig is the default)\n");
+}
+
+int main(int ac, char **av)
+{
+ const char *progname = av[0];
+ int opt;
+ const char *name, *defconfig_file = NULL /* gcc uninit */;
+ int no_conf_write = 0;
+
+ tty_stdio = isatty(0) && isatty(1);
+
+ while ((opt = getopt_long(ac, av, "hs", long_opts, NULL)) != -1) {
+ switch (opt) {
+ case 'h':
+ conf_usage(progname);
+ exit(1);
+ break;
+ case 's':
+ conf_set_message_callback(NULL);
+ break;
+ case 0:
+ input_mode = input_mode_opt;
+ switch (input_mode) {
+ case syncconfig:
+ /*
+ * syncconfig is invoked during the build stage.
+ * Suppress distracting
+ * "configuration written to ..."
+ */
+ conf_set_message_callback(NULL);
+ sync_kconfig = 1;
+ break;
+ case defconfig:
+ case savedefconfig:
+ defconfig_file = optarg;
+ break;
+ case randconfig:
+ set_randconfig_seed();
+ break;
+ default:
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ if (ac == optind) {
+ fprintf(stderr, "%s: Kconfig file missing\n", av[0]);
+ conf_usage(progname);
+ exit(1);
+ }
+ conf_parse(av[optind]);
+ //zconfdump(stdout);
+
+ switch (input_mode) {
+ case defconfig:
+ if (conf_read(defconfig_file)) {
+ fprintf(stderr,
+ "***\n"
+ "*** Can't find default configuration \"%s\"!\n"
+ "***\n",
+ defconfig_file);
+ exit(1);
+ }
+ break;
+ case savedefconfig:
+ case syncconfig:
+ case oldaskconfig:
+ case oldconfig:
+ case listnewconfig:
+ case helpnewconfig:
+ case olddefconfig:
+ case yes2modconfig:
+ case mod2yesconfig:
+ case mod2noconfig:
+ conf_read(NULL);
+ break;
+ case allnoconfig:
+ case allyesconfig:
+ case allmodconfig:
+ case alldefconfig:
+ case randconfig:
+ name = getenv("KCONFIG_ALLCONFIG");
+ if (!name)
+ break;
+ if ((strcmp(name, "") != 0) && (strcmp(name, "1") != 0)) {
+ if (conf_read_simple(name, S_DEF_USER)) {
+ fprintf(stderr,
+ "*** Can't read seed configuration \"%s\"!\n",
+ name);
+ exit(1);
+ }
+ break;
+ }
+ switch (input_mode) {
+ case allnoconfig: name = "allno.config"; break;
+ case allyesconfig: name = "allyes.config"; break;
+ case allmodconfig: name = "allmod.config"; break;
+ case alldefconfig: name = "alldef.config"; break;
+ case randconfig: name = "allrandom.config"; break;
+ default: break;
+ }
+ if (conf_read_simple(name, S_DEF_USER) &&
+ conf_read_simple("all.config", S_DEF_USER)) {
+ fprintf(stderr,
+ "*** KCONFIG_ALLCONFIG set, but no \"%s\" or \"all.config\" file found\n",
+ name);
+ exit(1);
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (sync_kconfig) {
+ name = getenv("KCONFIG_NOSILENTUPDATE");
+ if (name && *name) {
+ if (conf_get_changed()) {
+ fprintf(stderr,
+ "\n*** The configuration requires explicit update.\n\n");
+ return 1;
+ }
+ no_conf_write = 1;
+ }
+ }
+
+ switch (input_mode) {
+ case allnoconfig:
+ conf_set_all_new_symbols(def_no);
+ break;
+ case allyesconfig:
+ conf_set_all_new_symbols(def_yes);
+ break;
+ case allmodconfig:
+ conf_set_all_new_symbols(def_mod);
+ break;
+ case alldefconfig:
+ conf_set_all_new_symbols(def_default);
+ break;
+ case randconfig:
+ /* Really nothing to do in this loop */
+ while (conf_set_all_new_symbols(def_random)) ;
+ break;
+ case defconfig:
+ conf_set_all_new_symbols(def_default);
+ break;
+ case savedefconfig:
+ break;
+ case yes2modconfig:
+ conf_rewrite_tristates(yes, mod);
+ break;
+ case mod2yesconfig:
+ conf_rewrite_tristates(mod, yes);
+ break;
+ case mod2noconfig:
+ conf_rewrite_tristates(mod, no);
+ break;
+ case oldaskconfig:
+ rootEntry = &rootmenu;
+ conf(&rootmenu);
+ input_mode = oldconfig;
+ /* fall through */
+ case oldconfig:
+ case listnewconfig:
+ case helpnewconfig:
+ case syncconfig:
+ /* Update until a loop caused no more changes */
+ do {
+ conf_cnt = 0;
+ check_conf(&rootmenu);
+ } while (conf_cnt);
+ break;
+ case olddefconfig:
+ default:
+ break;
+ }
+
+ if (input_mode == savedefconfig) {
+ if (conf_write_defconfig(defconfig_file)) {
+ fprintf(stderr, "n*** Error while saving defconfig to: %s\n\n",
+ defconfig_file);
+ return 1;
+ }
+ } else if (input_mode != listnewconfig && input_mode != helpnewconfig) {
+ if (!no_conf_write && conf_write(NULL)) {
+ fprintf(stderr, "\n*** Error during writing of the configuration.\n\n");
+ exit(1);
+ }
+
+ /*
+ * Create auto.conf if it does not exist.
+ * This prevents GNU Make 4.1 or older from emitting
+ * "include/config/auto.conf: No such file or directory"
+ * in the top-level Makefile
+ *
+ * syncconfig always creates or updates auto.conf because it is
+ * used during the build.
+ */
+ if (conf_write_autoconf(sync_kconfig) && sync_kconfig) {
+ fprintf(stderr,
+ "\n*** Error during sync of the configuration.\n\n");
+ return 1;
+ }
+ }
+ return 0;
+}
Index: v6.x/create-6.1.53-host-limits-patch/linux-6.1.53-new/scripts/kconfig/confdata.c
===================================================================
--- v6.x/create-6.1.53-host-limits-patch/linux-6.1.53-new/scripts/kconfig/confdata.c (nonexistent)
+++ v6.x/create-6.1.53-host-limits-patch/linux-6.1.53-new/scripts/kconfig/confdata.c (revision 385)
@@ -0,0 +1,1265 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ */
+
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <linux/limits.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "lkc.h"
+
+/* return true if 'path' exists, false otherwise */
+static bool is_present(const char *path)
+{
+ struct stat st;
+
+ return !stat(path, &st);
+}
+
+/* return true if 'path' exists and it is a directory, false otherwise */
+static bool is_dir(const char *path)
+{
+ struct stat st;
+
+ if (stat(path, &st))
+ return false;
+
+ return S_ISDIR(st.st_mode);
+}
+
+/* return true if the given two files are the same, false otherwise */
+static bool is_same(const char *file1, const char *file2)
+{
+ int fd1, fd2;
+ struct stat st1, st2;
+ void *map1, *map2;
+ bool ret = false;
+
+ fd1 = open(file1, O_RDONLY);
+ if (fd1 < 0)
+ return ret;
+
+ fd2 = open(file2, O_RDONLY);
+ if (fd2 < 0)
+ goto close1;
+
+ ret = fstat(fd1, &st1);
+ if (ret)
+ goto close2;
+ ret = fstat(fd2, &st2);
+ if (ret)
+ goto close2;
+
+ if (st1.st_size != st2.st_size)
+ goto close2;
+
+ map1 = mmap(NULL, st1.st_size, PROT_READ, MAP_PRIVATE, fd1, 0);
+ if (map1 == MAP_FAILED)
+ goto close2;
+
+ map2 = mmap(NULL, st2.st_size, PROT_READ, MAP_PRIVATE, fd2, 0);
+ if (map2 == MAP_FAILED)
+ goto close2;
+
+ if (bcmp(map1, map2, st1.st_size))
+ goto close2;
+
+ ret = true;
+close2:
+ close(fd2);
+close1:
+ close(fd1);
+
+ return ret;
+}
+
+/*
+ * Create the parent directory of the given path.
+ *
+ * For example, if 'include/config/auto.conf' is given, create 'include/config'.
+ */
+static int make_parent_dir(const char *path)
+{
+ char tmp[PATH_MAX + 1];
+ char *p;
+
+ strncpy(tmp, path, sizeof(tmp));
+ tmp[sizeof(tmp) - 1] = 0;
+
+ /* Remove the base name. Just return if nothing is left */
+ p = strrchr(tmp, '/');
+ if (!p)
+ return 0;
+ *(p + 1) = 0;
+
+ /* Just in case it is an absolute path */
+ p = tmp;
+ while (*p == '/')
+ p++;
+
+ while ((p = strchr(p, '/'))) {
+ *p = 0;
+
+ /* skip if the directory exists */
+ if (!is_dir(tmp) && mkdir(tmp, 0755))
+ return -1;
+
+ *p = '/';
+ while (*p == '/')
+ p++;
+ }
+
+ return 0;
+}
+
+static char depfile_path[PATH_MAX];
+static size_t depfile_prefix_len;
+
+/* touch depfile for symbol 'name' */
+static int conf_touch_dep(const char *name)
+{
+ int fd;
+
+ /* check overflow: prefix + name + '\0' must fit in buffer. */
+ if (depfile_prefix_len + strlen(name) + 1 > sizeof(depfile_path))
+ return -1;
+
+ strcpy(depfile_path + depfile_prefix_len, name);
+
+ fd = open(depfile_path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
+ if (fd == -1)
+ return -1;
+ close(fd);
+
+ return 0;
+}
+
+static void conf_warning(const char *fmt, ...)
+ __attribute__ ((format (printf, 1, 2)));
+
+static void conf_message(const char *fmt, ...)
+ __attribute__ ((format (printf, 1, 2)));
+
+static const char *conf_filename;
+static int conf_lineno, conf_warnings;
+
+static void conf_warning(const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ fprintf(stderr, "%s:%d:warning: ", conf_filename, conf_lineno);
+ vfprintf(stderr, fmt, ap);
+ fprintf(stderr, "\n");
+ va_end(ap);
+ conf_warnings++;
+}
+
+static void conf_default_message_callback(const char *s)
+{
+ printf("#\n# ");
+ printf("%s", s);
+ printf("\n#\n");
+}
+
+static void (*conf_message_callback)(const char *s) =
+ conf_default_message_callback;
+void conf_set_message_callback(void (*fn)(const char *s))
+{
+ conf_message_callback = fn;
+}
+
+static void conf_message(const char *fmt, ...)
+{
+ va_list ap;
+ char buf[4096];
+
+ if (!conf_message_callback)
+ return;
+
+ va_start(ap, fmt);
+
+ vsnprintf(buf, sizeof(buf), fmt, ap);
+ conf_message_callback(buf);
+ va_end(ap);
+}
+
+const char *conf_get_configname(void)
+{
+ char *name = getenv("KCONFIG_CONFIG");
+
+ return name ? name : ".config";
+}
+
+static const char *conf_get_autoconfig_name(void)
+{
+ char *name = getenv("KCONFIG_AUTOCONFIG");
+
+ return name ? name : "include/config/auto.conf";
+}
+
+static const char *conf_get_autoheader_name(void)
+{
+ char *name = getenv("KCONFIG_AUTOHEADER");
+
+ return name ? name : "include/generated/autoconf.h";
+}
+
+static const char *conf_get_rustccfg_name(void)
+{
+ char *name = getenv("KCONFIG_RUSTCCFG");
+
+ return name ? name : "include/generated/rustc_cfg";
+}
+
+static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p)
+{
+ char *p2;
+
+ switch (sym->type) {
+ case S_TRISTATE:
+ if (p[0] == 'm') {
+ sym->def[def].tri = mod;
+ sym->flags |= def_flags;
+ break;
+ }
+ /* fall through */
+ case S_BOOLEAN:
+ if (p[0] == 'y') {
+ sym->def[def].tri = yes;
+ sym->flags |= def_flags;
+ break;
+ }
+ if (p[0] == 'n') {
+ sym->def[def].tri = no;
+ sym->flags |= def_flags;
+ break;
+ }
+ if (def != S_DEF_AUTO)
+ conf_warning("symbol value '%s' invalid for %s",
+ p, sym->name);
+ return 1;
+ case S_STRING:
+ /* No escaping for S_DEF_AUTO (include/config/auto.conf) */
+ if (def != S_DEF_AUTO) {
+ if (*p++ != '"')
+ break;
+ for (p2 = p; (p2 = strpbrk(p2, "\"\\")); p2++) {
+ if (*p2 == '"') {
+ *p2 = 0;
+ break;
+ }
+ memmove(p2, p2 + 1, strlen(p2));
+ }
+ if (!p2) {
+ conf_warning("invalid string found");
+ return 1;
+ }
+ }
+ /* fall through */
+ case S_INT:
+ case S_HEX:
+ if (sym_string_valid(sym, p)) {
+ sym->def[def].val = xstrdup(p);
+ sym->flags |= def_flags;
+ } else {
+ if (def != S_DEF_AUTO)
+ conf_warning("symbol value '%s' invalid for %s",
+ p, sym->name);
+ return 1;
+ }
+ break;
+ default:
+ ;
+ }
+ return 0;
+}
+
+#define LINE_GROWTH 16
+static int add_byte(int c, char **lineptr, size_t slen, size_t *n)
+{
+ char *nline;
+ size_t new_size = slen + 1;
+ if (new_size > *n) {
+ new_size += LINE_GROWTH - 1;
+ new_size *= 2;
+ nline = xrealloc(*lineptr, new_size);
+ if (!nline)
+ return -1;
+
+ *lineptr = nline;
+ *n = new_size;
+ }
+
+ (*lineptr)[slen] = c;
+
+ return 0;
+}
+
+static ssize_t compat_getline(char **lineptr, size_t *n, FILE *stream)
+{
+ char *line = *lineptr;
+ size_t slen = 0;
+
+ for (;;) {
+ int c = getc(stream);
+
+ switch (c) {
+ case '\n':
+ if (add_byte(c, &line, slen, n) < 0)
+ goto e_out;
+ slen++;
+ /* fall through */
+ case EOF:
+ if (add_byte('\0', &line, slen, n) < 0)
+ goto e_out;
+ *lineptr = line;
+ if (slen == 0)
+ return -1;
+ return slen;
+ default:
+ if (add_byte(c, &line, slen, n) < 0)
+ goto e_out;
+ slen++;
+ }
+ }
+
+e_out:
+ line[slen-1] = '\0';
+ *lineptr = line;
+ return -1;
+}
+
+int conf_read_simple(const char *name, int def)
+{
+ FILE *in = NULL;
+ char *line = NULL;
+ size_t line_asize = 0;
+ char *p, *p2;
+ struct symbol *sym;
+ int i, def_flags;
+
+ if (name) {
+ in = zconf_fopen(name);
+ } else {
+ char *env;
+
+ name = conf_get_configname();
+ in = zconf_fopen(name);
+ if (in)
+ goto load;
+ conf_set_changed(true);
+
+ env = getenv("KCONFIG_DEFCONFIG_LIST");
+ if (!env)
+ return 1;
+
+ while (1) {
+ bool is_last;
+
+ while (isspace(*env))
+ env++;
+
+ if (!*env)
+ break;
+
+ p = env;
+ while (*p && !isspace(*p))
+ p++;
+
+ is_last = (*p == '\0');
+
+ *p = '\0';
+
+ in = zconf_fopen(env);
+ if (in) {
+ conf_message("using defaults found in %s",
+ env);
+ goto load;
+ }
+
+ if (is_last)
+ break;
+
+ env = p + 1;
+ }
+ }
+ if (!in)
+ return 1;
+
+load:
+ conf_filename = name;
+ conf_lineno = 0;
+ conf_warnings = 0;
+
+ def_flags = SYMBOL_DEF << def;
+ for_all_symbols(i, sym) {
+ sym->flags |= SYMBOL_CHANGED;
+ sym->flags &= ~(def_flags|SYMBOL_VALID);
+ if (sym_is_choice(sym))
+ sym->flags |= def_flags;
+ switch (sym->type) {
+ case S_INT:
+ case S_HEX:
+ case S_STRING:
+ if (sym->def[def].val)
+ free(sym->def[def].val);
+ /* fall through */
+ default:
+ sym->def[def].val = NULL;
+ sym->def[def].tri = no;
+ }
+ }
+
+ while (compat_getline(&line, &line_asize, in) != -1) {
+ conf_lineno++;
+ sym = NULL;
+ if (line[0] == '#') {
+ if (memcmp(line + 2, CONFIG_, strlen(CONFIG_)))
+ continue;
+ p = strchr(line + 2 + strlen(CONFIG_), ' ');
+ if (!p)
+ continue;
+ *p++ = 0;
+ if (strncmp(p, "is not set", 10))
+ continue;
+ if (def == S_DEF_USER) {
+ sym = sym_find(line + 2 + strlen(CONFIG_));
+ if (!sym) {
+ conf_set_changed(true);
+ continue;
+ }
+ } else {
+ sym = sym_lookup(line + 2 + strlen(CONFIG_), 0);
+ if (sym->type == S_UNKNOWN)
+ sym->type = S_BOOLEAN;
+ }
+ if (sym->flags & def_flags) {
+ conf_warning("override: reassigning to symbol %s", sym->name);
+ }
+ switch (sym->type) {
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ sym->def[def].tri = no;
+ sym->flags |= def_flags;
+ break;
+ default:
+ ;
+ }
+ } else if (memcmp(line, CONFIG_, strlen(CONFIG_)) == 0) {
+ p = strchr(line + strlen(CONFIG_), '=');
+ if (!p)
+ continue;
+ *p++ = 0;
+ p2 = strchr(p, '\n');
+ if (p2) {
+ *p2-- = 0;
+ if (*p2 == '\r')
+ *p2 = 0;
+ }
+
+ sym = sym_find(line + strlen(CONFIG_));
+ if (!sym) {
+ if (def == S_DEF_AUTO)
+ /*
+ * Reading from include/config/auto.conf
+ * If CONFIG_FOO previously existed in
+ * auto.conf but it is missing now,
+ * include/config/FOO must be touched.
+ */
+ conf_touch_dep(line + strlen(CONFIG_));
+ else
+ conf_set_changed(true);
+ continue;
+ }
+
+ if (sym->flags & def_flags) {
+ conf_warning("override: reassigning to symbol %s", sym->name);
+ }
+ if (conf_set_sym_val(sym, def, def_flags, p))
+ continue;
+ } else {
+ if (line[0] != '\r' && line[0] != '\n')
+ conf_warning("unexpected data: %.*s",
+ (int)strcspn(line, "\r\n"), line);
+
+ continue;
+ }
+
+ if (sym && sym_is_choice_value(sym)) {
+ struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym));
+ switch (sym->def[def].tri) {
+ case no:
+ break;
+ case mod:
+ if (cs->def[def].tri == yes) {
+ conf_warning("%s creates inconsistent choice state", sym->name);
+ cs->flags &= ~def_flags;
+ }
+ break;
+ case yes:
+ if (cs->def[def].tri != no)
+ conf_warning("override: %s changes choice state", sym->name);
+ cs->def[def].val = sym;
+ break;
+ }
+ cs->def[def].tri = EXPR_OR(cs->def[def].tri, sym->def[def].tri);
+ }
+ }
+ free(line);
+ fclose(in);
+ return 0;
+}
+
+int conf_read(const char *name)
+{
+ struct symbol *sym;
+ int conf_unsaved = 0;
+ int i;
+
+ conf_set_changed(false);
+
+ if (conf_read_simple(name, S_DEF_USER)) {
+ sym_calc_value(modules_sym);
+ return 1;
+ }
+
+ sym_calc_value(modules_sym);
+
+ for_all_symbols(i, sym) {
+ sym_calc_value(sym);
+ if (sym_is_choice(sym) || (sym->flags & SYMBOL_NO_WRITE))
+ continue;
+ if (sym_has_value(sym) && (sym->flags & SYMBOL_WRITE)) {
+ /* check that calculated value agrees with saved value */
+ switch (sym->type) {
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ if (sym->def[S_DEF_USER].tri == sym_get_tristate_value(sym))
+ continue;
+ break;
+ default:
+ if (!strcmp(sym->curr.val, sym->def[S_DEF_USER].val))
+ continue;
+ break;
+ }
+ } else if (!sym_has_value(sym) && !(sym->flags & SYMBOL_WRITE))
+ /* no previous value and not saved */
+ continue;
+ conf_unsaved++;
+ /* maybe print value in verbose mode... */
+ }
+
+ for_all_symbols(i, sym) {
+ if (sym_has_value(sym) && !sym_is_choice_value(sym)) {
+ /* Reset values of generates values, so they'll appear
+ * as new, if they should become visible, but that
+ * doesn't quite work if the Kconfig and the saved
+ * configuration disagree.
+ */
+ if (sym->visible == no && !conf_unsaved)
+ sym->flags &= ~SYMBOL_DEF_USER;
+ switch (sym->type) {
+ case S_STRING:
+ case S_INT:
+ case S_HEX:
+ /* Reset a string value if it's out of range */
+ if (sym_string_within_range(sym, sym->def[S_DEF_USER].val))
+ break;
+ sym->flags &= ~(SYMBOL_VALID|SYMBOL_DEF_USER);
+ conf_unsaved++;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ if (conf_warnings || conf_unsaved)
+ conf_set_changed(true);
+
+ return 0;
+}
+
+struct comment_style {
+ const char *decoration;
+ const char *prefix;
+ const char *postfix;
+};
+
+static const struct comment_style comment_style_pound = {
+ .decoration = "#",
+ .prefix = "#",
+ .postfix = "#",
+};
+
+static const struct comment_style comment_style_c = {
+ .decoration = " *",
+ .prefix = "/*",
+ .postfix = " */",
+};
+
+static void conf_write_heading(FILE *fp, const struct comment_style *cs)
+{
+ if (!cs)
+ return;
+
+ fprintf(fp, "%s\n", cs->prefix);
+
+ fprintf(fp, "%s Automatically generated file; DO NOT EDIT.\n",
+ cs->decoration);
+
+ fprintf(fp, "%s %s\n", cs->decoration, rootmenu.prompt->text);
+
+ fprintf(fp, "%s\n", cs->postfix);
+}
+
+/* The returned pointer must be freed on the caller side */
+static char *escape_string_value(const char *in)
+{
+ const char *p;
+ char *out;
+ size_t len;
+
+ len = strlen(in) + strlen("\"\"") + 1;
+
+ p = in;
+ while (1) {
+ p += strcspn(p, "\"\\");
+
+ if (p[0] == '\0')
+ break;
+
+ len++;
+ p++;
+ }
+
+ out = xmalloc(len);
+ out[0] = '\0';
+
+ strcat(out, "\"");
+
+ p = in;
+ while (1) {
+ len = strcspn(p, "\"\\");
+ strncat(out, p, len);
+ p += len;
+
+ if (p[0] == '\0')
+ break;
+
+ strcat(out, "\\");
+ strncat(out, p++, 1);
+ }
+
+ strcat(out, "\"");
+
+ return out;
+}
+
+enum output_n { OUTPUT_N, OUTPUT_N_AS_UNSET, OUTPUT_N_NONE };
+
+static void __print_symbol(FILE *fp, struct symbol *sym, enum output_n output_n,
+ bool escape_string)
+{
+ const char *val;
+ char *escaped = NULL;
+
+ if (sym->type == S_UNKNOWN)
+ return;
+
+ val = sym_get_string_value(sym);
+
+ if ((sym->type == S_BOOLEAN || sym->type == S_TRISTATE) &&
+ output_n != OUTPUT_N && *val == 'n') {
+ if (output_n == OUTPUT_N_AS_UNSET)
+ fprintf(fp, "# %s%s is not set\n", CONFIG_, sym->name);
+ return;
+ }
+
+ if (sym->type == S_STRING && escape_string) {
+ escaped = escape_string_value(val);
+ val = escaped;
+ }
+
+ fprintf(fp, "%s%s=%s\n", CONFIG_, sym->name, val);
+
+ free(escaped);
+}
+
+static void print_symbol_for_dotconfig(FILE *fp, struct symbol *sym)
+{
+ __print_symbol(fp, sym, OUTPUT_N_AS_UNSET, true);
+}
+
+static void print_symbol_for_autoconf(FILE *fp, struct symbol *sym)
+{
+ __print_symbol(fp, sym, OUTPUT_N_NONE, false);
+}
+
+void print_symbol_for_listconfig(struct symbol *sym)
+{
+ __print_symbol(stdout, sym, OUTPUT_N, true);
+}
+
+static void print_symbol_for_c(FILE *fp, struct symbol *sym)
+{
+ const char *val;
+ const char *sym_suffix = "";
+ const char *val_prefix = "";
+ char *escaped = NULL;
+
+ if (sym->type == S_UNKNOWN)
+ return;
+
+ val = sym_get_string_value(sym);
+
+ switch (sym->type) {
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ switch (*val) {
+ case 'n':
+ return;
+ case 'm':
+ sym_suffix = "_MODULE";
+ /* fall through */
+ default:
+ val = "1";
+ }
+ break;
+ case S_HEX:
+ if (val[0] != '0' || (val[1] != 'x' && val[1] != 'X'))
+ val_prefix = "0x";
+ break;
+ case S_STRING:
+ escaped = escape_string_value(val);
+ val = escaped;
+ default:
+ break;
+ }
+
+ fprintf(fp, "#define %s%s%s %s%s\n", CONFIG_, sym->name, sym_suffix,
+ val_prefix, val);
+
+ free(escaped);
+}
+
+static void print_symbol_for_rustccfg(FILE *fp, struct symbol *sym)
+{
+ const char *val;
+ const char *val_prefix = "";
+ char *val_prefixed = NULL;
+ size_t val_prefixed_len;
+ char *escaped = NULL;
+
+ if (sym->type == S_UNKNOWN)
+ return;
+
+ val = sym_get_string_value(sym);
+
+ switch (sym->type) {
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ /*
+ * We do not care about disabled ones, i.e. no need for
+ * what otherwise are "comments" in other printers.
+ */
+ if (*val == 'n')
+ return;
+
+ /*
+ * To have similar functionality to the C macro `IS_ENABLED()`
+ * we provide an empty `--cfg CONFIG_X` here in both `y`
+ * and `m` cases.
+ *
+ * Then, the common `fprintf()` below will also give us
+ * a `--cfg CONFIG_X="y"` or `--cfg CONFIG_X="m"`, which can
+ * be used as the equivalent of `IS_BUILTIN()`/`IS_MODULE()`.
+ */
+ fprintf(fp, "--cfg=%s%s\n", CONFIG_, sym->name);
+ break;
+ case S_HEX:
+ if (val[0] != '0' || (val[1] != 'x' && val[1] != 'X'))
+ val_prefix = "0x";
+ break;
+ default:
+ break;
+ }
+
+ if (strlen(val_prefix) > 0) {
+ val_prefixed_len = strlen(val) + strlen(val_prefix) + 1;
+ val_prefixed = xmalloc(val_prefixed_len);
+ snprintf(val_prefixed, val_prefixed_len, "%s%s", val_prefix, val);
+ val = val_prefixed;
+ }
+
+ /* All values get escaped: the `--cfg` option only takes strings */
+ escaped = escape_string_value(val);
+ val = escaped;
+
+ fprintf(fp, "--cfg=%s%s=%s\n", CONFIG_, sym->name, val);
+
+ free(escaped);
+ free(val_prefixed);
+}
+
+/*
+ * Write out a minimal config.
+ * All values that has default values are skipped as this is redundant.
+ */
+int conf_write_defconfig(const char *filename)
+{
+ struct symbol *sym;
+ struct menu *menu;
+ FILE *out;
+
+ out = fopen(filename, "w");
+ if (!out)
+ return 1;
+
+ sym_clear_all_valid();
+
+ /* Traverse all menus to find all relevant symbols */
+ menu = rootmenu.list;
+
+ while (menu != NULL)
+ {
+ sym = menu->sym;
+ if (sym == NULL) {
+ if (!menu_is_visible(menu))
+ goto next_menu;
+ } else if (!sym_is_choice(sym)) {
+ sym_calc_value(sym);
+ if (!(sym->flags & SYMBOL_WRITE))
+ goto next_menu;
+ sym->flags &= ~SYMBOL_WRITE;
+ /* If we cannot change the symbol - skip */
+ if (!sym_is_changeable(sym))
+ goto next_menu;
+ /* If symbol equals to default value - skip */
+ if (strcmp(sym_get_string_value(sym), sym_get_string_default(sym)) == 0)
+ goto next_menu;
+
+ /*
+ * If symbol is a choice value and equals to the
+ * default for a choice - skip.
+ * But only if value is bool and equal to "y" and
+ * choice is not "optional".
+ * (If choice is "optional" then all values can be "n")
+ */
+ if (sym_is_choice_value(sym)) {
+ struct symbol *cs;
+ struct symbol *ds;
+
+ cs = prop_get_symbol(sym_get_choice_prop(sym));
+ ds = sym_choice_default(cs);
+ if (!sym_is_optional(cs) && sym == ds) {
+ if ((sym->type == S_BOOLEAN) &&
+ sym_get_tristate_value(sym) == yes)
+ goto next_menu;
+ }
+ }
+ print_symbol_for_dotconfig(out, sym);
+ }
+next_menu:
+ if (menu->list != NULL) {
+ menu = menu->list;
+ }
+ else if (menu->next != NULL) {
+ menu = menu->next;
+ } else {
+ while ((menu = menu->parent)) {
+ if (menu->next != NULL) {
+ menu = menu->next;
+ break;
+ }
+ }
+ }
+ }
+ fclose(out);
+ return 0;
+}
+
+int conf_write(const char *name)
+{
+ FILE *out;
+ struct symbol *sym;
+ struct menu *menu;
+ const char *str;
+ char tmpname[PATH_MAX + 1], oldname[PATH_MAX + 1];
+ char *env;
+ int i;
+ bool need_newline = false;
+
+ if (!name)
+ name = conf_get_configname();
+
+ if (!*name) {
+ fprintf(stderr, "config name is empty\n");
+ return -1;
+ }
+
+ if (is_dir(name)) {
+ fprintf(stderr, "%s: Is a directory\n", name);
+ return -1;
+ }
+
+ if (make_parent_dir(name))
+ return -1;
+
+ env = getenv("KCONFIG_OVERWRITECONFIG");
+ if (env && *env) {
+ *tmpname = 0;
+ out = fopen(name, "w");
+ } else {
+ snprintf(tmpname, sizeof(tmpname), "%s.%d.tmp",
+ name, (int)getpid());
+ out = fopen(tmpname, "w");
+ }
+ if (!out)
+ return 1;
+
+ conf_write_heading(out, &comment_style_pound);
+
+ if (!conf_get_changed())
+ sym_clear_all_valid();
+
+ menu = rootmenu.list;
+ while (menu) {
+ sym = menu->sym;
+ if (!sym) {
+ if (!menu_is_visible(menu))
+ goto next;
+ str = menu_get_prompt(menu);
+ fprintf(out, "\n"
+ "#\n"
+ "# %s\n"
+ "#\n", str);
+ need_newline = false;
+ } else if (!(sym->flags & SYMBOL_CHOICE) &&
+ !(sym->flags & SYMBOL_WRITTEN)) {
+ sym_calc_value(sym);
+ if (!(sym->flags & SYMBOL_WRITE))
+ goto next;
+ if (need_newline) {
+ fprintf(out, "\n");
+ need_newline = false;
+ }
+ sym->flags |= SYMBOL_WRITTEN;
+ print_symbol_for_dotconfig(out, sym);
+ }
+
+next:
+ if (menu->list) {
+ menu = menu->list;
+ continue;
+ }
+
+end_check:
+ if (!menu->sym && menu_is_visible(menu) && menu != &rootmenu &&
+ menu->prompt->type == P_MENU) {
+ fprintf(out, "# end of %s\n", menu_get_prompt(menu));
+ need_newline = true;
+ }
+
+ if (menu->next) {
+ menu = menu->next;
+ } else {
+ menu = menu->parent;
+ if (menu)
+ goto end_check;
+ }
+ }
+ fclose(out);
+
+ for_all_symbols(i, sym)
+ sym->flags &= ~SYMBOL_WRITTEN;
+
+ if (*tmpname) {
+ if (is_same(name, tmpname)) {
+ conf_message("No change to %s", name);
+ unlink(tmpname);
+ conf_set_changed(false);
+ return 0;
+ }
+
+ snprintf(oldname, sizeof(oldname), "%s.old", name);
+ rename(name, oldname);
+ if (rename(tmpname, name))
+ return 1;
+ }
+
+ conf_message("configuration written to %s", name);
+
+ conf_set_changed(false);
+
+ return 0;
+}
+
+/* write a dependency file as used by kbuild to track dependencies */
+static int conf_write_autoconf_cmd(const char *autoconf_name)
+{
+ char name[PATH_MAX], tmp[PATH_MAX];
+ struct file *file;
+ FILE *out;
+ int ret;
+
+ ret = snprintf(name, sizeof(name), "%s.cmd", autoconf_name);
+ if (ret >= sizeof(name)) /* check truncation */
+ return -1;
+
+ if (make_parent_dir(name))
+ return -1;
+
+ ret = snprintf(tmp, sizeof(tmp), "%s.cmd.tmp", autoconf_name);
+ if (ret >= sizeof(tmp)) /* check truncation */
+ return -1;
+
+ out = fopen(tmp, "w");
+ if (!out) {
+ perror("fopen");
+ return -1;
+ }
+
+ fprintf(out, "deps_config := \\\n");
+ for (file = file_list; file; file = file->next)
+ fprintf(out, "\t%s \\\n", file->name);
+
+ fprintf(out, "\n%s: $(deps_config)\n\n", autoconf_name);
+
+ env_write_dep(out, autoconf_name);
+
+ fprintf(out, "\n$(deps_config): ;\n");
+
+ fflush(out);
+ ret = ferror(out); /* error check for all fprintf() calls */
+ fclose(out);
+ if (ret)
+ return -1;
+
+ if (rename(tmp, name)) {
+ perror("rename");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int conf_touch_deps(void)
+{
+ const char *name, *tmp;
+ struct symbol *sym;
+ int res, i;
+
+ name = conf_get_autoconfig_name();
+ tmp = strrchr(name, '/');
+ depfile_prefix_len = tmp ? tmp - name + 1 : 0;
+ if (depfile_prefix_len + 1 > sizeof(depfile_path))
+ return -1;
+
+ strncpy(depfile_path, name, depfile_prefix_len);
+ depfile_path[depfile_prefix_len] = 0;
+
+ conf_read_simple(name, S_DEF_AUTO);
+ sym_calc_value(modules_sym);
+
+ for_all_symbols(i, sym) {
+ sym_calc_value(sym);
+ if ((sym->flags & SYMBOL_NO_WRITE) || !sym->name)
+ continue;
+ if (sym->flags & SYMBOL_WRITE) {
+ if (sym->flags & SYMBOL_DEF_AUTO) {
+ /*
+ * symbol has old and new value,
+ * so compare them...
+ */
+ switch (sym->type) {
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ if (sym_get_tristate_value(sym) ==
+ sym->def[S_DEF_AUTO].tri)
+ continue;
+ break;
+ case S_STRING:
+ case S_HEX:
+ case S_INT:
+ if (!strcmp(sym_get_string_value(sym),
+ sym->def[S_DEF_AUTO].val))
+ continue;
+ break;
+ default:
+ break;
+ }
+ } else {
+ /*
+ * If there is no old value, only 'no' (unset)
+ * is allowed as new value.
+ */
+ switch (sym->type) {
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ if (sym_get_tristate_value(sym) == no)
+ continue;
+ break;
+ default:
+ break;
+ }
+ }
+ } else if (!(sym->flags & SYMBOL_DEF_AUTO))
+ /* There is neither an old nor a new value. */
+ continue;
+ /* else
+ * There is an old value, but no new value ('no' (unset)
+ * isn't saved in auto.conf, so the old value is always
+ * different from 'no').
+ */
+
+ res = conf_touch_dep(sym->name);
+ if (res)
+ return res;
+ }
+
+ return 0;
+}
+
+static int __conf_write_autoconf(const char *filename,
+ void (*print_symbol)(FILE *, struct symbol *),
+ const struct comment_style *comment_style)
+{
+ char tmp[PATH_MAX];
+ FILE *file;
+ struct symbol *sym;
+ int ret, i;
+
+ if (make_parent_dir(filename))
+ return -1;
+
+ ret = snprintf(tmp, sizeof(tmp), "%s.tmp", filename);
+ if (ret >= sizeof(tmp)) /* check truncation */
+ return -1;
+
+ file = fopen(tmp, "w");
+ if (!file) {
+ perror("fopen");
+ return -1;
+ }
+
+ conf_write_heading(file, comment_style);
+
+ for_all_symbols(i, sym)
+ if ((sym->flags & SYMBOL_WRITE) && sym->name)
+ print_symbol(file, sym);
+
+ fflush(file);
+ /* check possible errors in conf_write_heading() and print_symbol() */
+ ret = ferror(file);
+ fclose(file);
+ if (ret)
+ return -1;
+
+ if (rename(tmp, filename)) {
+ perror("rename");
+ return -1;
+ }
+
+ return 0;
+}
+
+int conf_write_autoconf(int overwrite)
+{
+ struct symbol *sym;
+ const char *autoconf_name = conf_get_autoconfig_name();
+ int ret, i;
+
+ if (!overwrite && is_present(autoconf_name))
+ return 0;
+
+ ret = conf_write_autoconf_cmd(autoconf_name);
+ if (ret)
+ return -1;
+
+ if (conf_touch_deps())
+ return 1;
+
+ for_all_symbols(i, sym)
+ sym_calc_value(sym);
+
+ ret = __conf_write_autoconf(conf_get_autoheader_name(),
+ print_symbol_for_c,
+ &comment_style_c);
+ if (ret)
+ return ret;
+
+ ret = __conf_write_autoconf(conf_get_rustccfg_name(),
+ print_symbol_for_rustccfg,
+ NULL);
+ if (ret)
+ return ret;
+
+ /*
+ * Create include/config/auto.conf. This must be the last step because
+ * Kbuild has a dependency on auto.conf and this marks the successful
+ * completion of the previous steps.
+ */
+ ret = __conf_write_autoconf(conf_get_autoconfig_name(),
+ print_symbol_for_autoconf,
+ &comment_style_pound);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static bool conf_changed;
+static void (*conf_changed_callback)(void);
+
+void conf_set_changed(bool val)
+{
+ bool changed = conf_changed != val;
+
+ conf_changed = val;
+
+ if (conf_changed_callback && changed)
+ conf_changed_callback();
+}
+
+bool conf_get_changed(void)
+{
+ return conf_changed;
+}
+
+void conf_set_changed_callback(void (*fn)(void))
+{
+ conf_changed_callback = fn;
+}
+
+void set_all_choice_values(struct symbol *csym)
+{
+ struct property *prop;
+ struct symbol *sym;
+ struct expr *e;
+
+ prop = sym_get_choice_prop(csym);
+
+ /*
+ * Set all non-assinged choice values to no
+ */
+ expr_list_for_each_sym(prop->expr, e, sym) {
+ if (!sym_has_value(sym))
+ sym->def[S_DEF_USER].tri = no;
+ }
+ csym->flags |= SYMBOL_DEF_USER;
+ /* clear VALID to get value calculated */
+ csym->flags &= ~(SYMBOL_VALID | SYMBOL_NEED_SET_CHOICE_VALUES);
+}
Index: v6.x/create-6.1.53-host-limits-patch/linux-6.1.53-new/scripts/kconfig/lexer.l
===================================================================
--- v6.x/create-6.1.53-host-limits-patch/linux-6.1.53-new/scripts/kconfig/lexer.l (nonexistent)
+++ v6.x/create-6.1.53-host-limits-patch/linux-6.1.53-new/scripts/kconfig/lexer.l (revision 385)
@@ -0,0 +1,468 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ */
+%option nostdinit noyywrap never-interactive full ecs
+%option 8bit nodefault yylineno
+%x ASSIGN_VAL HELP STRING
+%{
+
+#include <assert.h>
+#include <linux/limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "lkc.h"
+#include "parser.tab.h"
+
+#define YY_DECL static int yylex1(void)
+
+#define START_STRSIZE 16
+
+static struct {
+ struct file *file;
+ int lineno;
+} current_pos;
+
+static int prev_prev_token = T_EOL;
+static int prev_token = T_EOL;
+static char *text;
+static int text_size, text_asize;
+
+struct buffer {
+ struct buffer *parent;
+ YY_BUFFER_STATE state;
+};
+
+static struct buffer *current_buf;
+
+static int last_ts, first_ts;
+
+static char *expand_token(const char *in, size_t n);
+static void append_expanded_string(const char *in);
+static void zconf_endhelp(void);
+static void zconf_endfile(void);
+
+static void new_string(void)
+{
+ text = xmalloc(START_STRSIZE);
+ text_asize = START_STRSIZE;
+ text_size = 0;
+ *text = 0;
+}
+
+static void append_string(const char *str, int size)
+{
+ int new_size = text_size + size + 1;
+ if (new_size > text_asize) {
+ new_size += START_STRSIZE - 1;
+ new_size &= -START_STRSIZE;
+ text = xrealloc(text, new_size);
+ text_asize = new_size;
+ }
+ memcpy(text + text_size, str, size);
+ text_size += size;
+ text[text_size] = 0;
+}
+
+static void alloc_string(const char *str, int size)
+{
+ text = xmalloc(size + 1);
+ memcpy(text, str, size);
+ text[size] = 0;
+}
+
+static void warn_ignored_character(char chr)
+{
+ fprintf(stderr,
+ "%s:%d:warning: ignoring unsupported character '%c'\n",
+ current_file->name, yylineno, chr);
+}
+%}
+
+n [A-Za-z0-9_-]
+
+%%
+ char open_quote = 0;
+
+#.* /* ignore comment */
+[ \t]* /* whitespaces */
+\\\n /* escaped new line */
+\n return T_EOL;
+"bool" return T_BOOL;
+"choice" return T_CHOICE;
+"comment" return T_COMMENT;
+"config" return T_CONFIG;
+"def_bool" return T_DEF_BOOL;
+"def_tristate" return T_DEF_TRISTATE;
+"default" return T_DEFAULT;
+"depends" return T_DEPENDS;
+"endchoice" return T_ENDCHOICE;
+"endif" return T_ENDIF;
+"endmenu" return T_ENDMENU;
+"help" return T_HELP;
+"hex" return T_HEX;
+"if" return T_IF;
+"imply" return T_IMPLY;
+"int" return T_INT;
+"mainmenu" return T_MAINMENU;
+"menu" return T_MENU;
+"menuconfig" return T_MENUCONFIG;
+"modules" return T_MODULES;
+"on" return T_ON;
+"optional" return T_OPTIONAL;
+"prompt" return T_PROMPT;
+"range" return T_RANGE;
+"select" return T_SELECT;
+"source" return T_SOURCE;
+"string" return T_STRING;
+"tristate" return T_TRISTATE;
+"visible" return T_VISIBLE;
+"||" return T_OR;
+"&&" return T_AND;
+"=" return T_EQUAL;
+"!=" return T_UNEQUAL;
+"<" return T_LESS;
+"<=" return T_LESS_EQUAL;
+">" return T_GREATER;
+">=" return T_GREATER_EQUAL;
+"!" return T_NOT;
+"(" return T_OPEN_PAREN;
+")" return T_CLOSE_PAREN;
+":=" return T_COLON_EQUAL;
+"+=" return T_PLUS_EQUAL;
+\"|\' {
+ open_quote = yytext[0];
+ new_string();
+ BEGIN(STRING);
+ }
+{n}+ {
+ alloc_string(yytext, yyleng);
+ yylval.string = text;
+ return T_WORD;
+ }
+({n}|$)+ {
+ /* this token includes at least one '$' */
+ yylval.string = expand_token(yytext, yyleng);
+ if (strlen(yylval.string))
+ return T_WORD;
+ free(yylval.string);
+ }
+. warn_ignored_character(*yytext);
+
+<ASSIGN_VAL>{
+ [^[:blank:]\n]+.* {
+ alloc_string(yytext, yyleng);
+ yylval.string = text;
+ return T_ASSIGN_VAL;
+ }
+ \n { BEGIN(INITIAL); return T_EOL; }
+ .
+}
+
+<STRING>{
+ "$".* append_expanded_string(yytext);
+ [^$'"\\\n]+ {
+ append_string(yytext, yyleng);
+ }
+ \\.? {
+ append_string(yytext + 1, yyleng - 1);
+ }
+ \'|\" {
+ if (open_quote == yytext[0]) {
+ BEGIN(INITIAL);
+ yylval.string = text;
+ return T_WORD_QUOTE;
+ } else
+ append_string(yytext, 1);
+ }
+ \n {
+ fprintf(stderr,
+ "%s:%d:warning: multi-line strings not supported\n",
+ zconf_curname(), zconf_lineno());
+ unput('\n');
+ BEGIN(INITIAL);
+ yylval.string = text;
+ return T_WORD_QUOTE;
+ }
+ <<EOF>> {
+ BEGIN(INITIAL);
+ yylval.string = text;
+ return T_WORD_QUOTE;
+ }
+}
+
+<HELP>{
+ [ \t]+ {
+ int ts, i;
+
+ ts = 0;
+ for (i = 0; i < yyleng; i++) {
+ if (yytext[i] == '\t')
+ ts = (ts & ~7) + 8;
+ else
+ ts++;
+ }
+ last_ts = ts;
+ if (first_ts) {
+ if (ts < first_ts) {
+ zconf_endhelp();
+ return T_HELPTEXT;
+ }
+ ts -= first_ts;
+ while (ts > 8) {
+ append_string(" ", 8);
+ ts -= 8;
+ }
+ append_string(" ", ts);
+ }
+ }
+ [ \t]*\n/[^ \t\n] {
+ zconf_endhelp();
+ return T_HELPTEXT;
+ }
+ [ \t]*\n {
+ append_string("\n", 1);
+ }
+ [^ \t\n].* {
+ while (yyleng) {
+ if ((yytext[yyleng-1] != ' ') && (yytext[yyleng-1] != '\t'))
+ break;
+ yyleng--;
+ }
+ append_string(yytext, yyleng);
+ if (!first_ts)
+ first_ts = last_ts;
+ }
+ <<EOF>> {
+ zconf_endhelp();
+ return T_HELPTEXT;
+ }
+}
+
+<<EOF>> {
+ BEGIN(INITIAL);
+
+ if (prev_token != T_EOL && prev_token != T_HELPTEXT)
+ fprintf(stderr, "%s:%d:warning: no new line at end of file\n",
+ current_file->name, yylineno);
+
+ if (current_file) {
+ zconf_endfile();
+ return T_EOL;
+ }
+ fclose(yyin);
+ yyterminate();
+}
+
+%%
+
+/* second stage lexer */
+int yylex(void)
+{
+ int token;
+
+repeat:
+ token = yylex1();
+
+ if (prev_token == T_EOL || prev_token == T_HELPTEXT) {
+ if (token == T_EOL) {
+ /* Do not pass unneeded T_EOL to the parser. */
+ goto repeat;
+ } else {
+ /*
+ * For the parser, update file/lineno at the first token
+ * of each statement. Generally, \n is a statement
+ * terminator in Kconfig, but it is not always true
+ * because \n could be escaped by a backslash.
+ */
+ current_pos.file = current_file;
+ current_pos.lineno = yylineno;
+ }
+ }
+
+ if (prev_prev_token == T_EOL && prev_token == T_WORD &&
+ (token == T_EQUAL || token == T_COLON_EQUAL || token == T_PLUS_EQUAL))
+ BEGIN(ASSIGN_VAL);
+
+ prev_prev_token = prev_token;
+ prev_token = token;
+
+ return token;
+}
+
+static char *expand_token(const char *in, size_t n)
+{
+ char *out;
+ int c;
+ char c2;
+ const char *rest, *end;
+
+ new_string();
+ append_string(in, n);
+
+ /* get the whole line because we do not know the end of token. */
+ while ((c = input()) != EOF) {
+ if (c == '\n') {
+ unput(c);
+ break;
+ }
+ c2 = c;
+ append_string(&c2, 1);
+ }
+
+ rest = text;
+ out = expand_one_token(&rest);
+
+ /* push back unused characters to the input stream */
+ end = rest + strlen(rest);
+ while (end > rest)
+ unput(*--end);
+
+ free(text);
+
+ return out;
+}
+
+static void append_expanded_string(const char *str)
+{
+ const char *end;
+ char *res;
+
+ str++;
+
+ res = expand_dollar(&str);
+
+ /* push back unused characters to the input stream */
+ end = str + strlen(str);
+ while (end > str)
+ unput(*--end);
+
+ append_string(res, strlen(res));
+
+ free(res);
+}
+
+void zconf_starthelp(void)
+{
+ new_string();
+ last_ts = first_ts = 0;
+ BEGIN(HELP);
+}
+
+static void zconf_endhelp(void)
+{
+ yylval.string = text;
+ BEGIN(INITIAL);
+}
+
+
+/*
+ * Try to open specified file with following names:
+ * ./name
+ * $(srctree)/name
+ * The latter is used when srctree is separate from objtree
+ * when compiling the kernel.
+ * Return NULL if file is not found.
+ */
+FILE *zconf_fopen(const char *name)
+{
+ char *env, fullname[PATH_MAX+1];
+ FILE *f;
+
+ f = fopen(name, "r");
+ if (!f && name != NULL && name[0] != '/') {
+ env = getenv(SRCTREE);
+ if (env) {
+ snprintf(fullname, sizeof(fullname),
+ "%s/%s", env, name);
+ f = fopen(fullname, "r");
+ }
+ }
+ return f;
+}
+
+void zconf_initscan(const char *name)
+{
+ yyin = zconf_fopen(name);
+ if (!yyin) {
+ fprintf(stderr, "can't find file %s\n", name);
+ exit(1);
+ }
+
+ current_buf = xmalloc(sizeof(*current_buf));
+ memset(current_buf, 0, sizeof(*current_buf));
+
+ current_file = file_lookup(name);
+ yylineno = 1;
+}
+
+void zconf_nextfile(const char *name)
+{
+ struct file *iter;
+ struct file *file = file_lookup(name);
+ struct buffer *buf = xmalloc(sizeof(*buf));
+ memset(buf, 0, sizeof(*buf));
+
+ current_buf->state = YY_CURRENT_BUFFER;
+ yyin = zconf_fopen(file->name);
+ if (!yyin) {
+ fprintf(stderr, "%s:%d: can't open file \"%s\"\n",
+ zconf_curname(), zconf_lineno(), file->name);
+ exit(1);
+ }
+ yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE));
+ buf->parent = current_buf;
+ current_buf = buf;
+
+ current_file->lineno = yylineno;
+ file->parent = current_file;
+
+ for (iter = current_file; iter; iter = iter->parent) {
+ if (!strcmp(iter->name, file->name)) {
+ fprintf(stderr,
+ "Recursive inclusion detected.\n"
+ "Inclusion path:\n"
+ " current file : %s\n", file->name);
+ iter = file;
+ do {
+ iter = iter->parent;
+ fprintf(stderr, " included from: %s:%d\n",
+ iter->name, iter->lineno - 1);
+ } while (strcmp(iter->name, file->name));
+ exit(1);
+ }
+ }
+
+ yylineno = 1;
+ current_file = file;
+}
+
+static void zconf_endfile(void)
+{
+ struct buffer *parent;
+
+ current_file = current_file->parent;
+ if (current_file)
+ yylineno = current_file->lineno;
+
+ parent = current_buf->parent;
+ if (parent) {
+ fclose(yyin);
+ yy_delete_buffer(YY_CURRENT_BUFFER);
+ yy_switch_to_buffer(parent->state);
+ }
+ free(current_buf);
+ current_buf = parent;
+}
+
+int zconf_lineno(void)
+{
+ return current_pos.lineno;
+}
+
+const char *zconf_curname(void)
+{
+ return current_pos.file ? current_pos.file->name : "<none>";
+}
Index: v6.x/create-6.1.53-host-limits-patch/linux-6.1.53-new/scripts/mod/modpost.c
===================================================================
--- v6.x/create-6.1.53-host-limits-patch/linux-6.1.53-new/scripts/mod/modpost.c (nonexistent)
+++ v6.x/create-6.1.53-host-limits-patch/linux-6.1.53-new/scripts/mod/modpost.c (revision 385)
@@ -0,0 +1,2371 @@
+/* Postprocess module symbol versions
+ *
+ * Copyright 2003 Kai Germaschewski
+ * Copyright 2002-2004 Rusty Russell, IBM Corporation
+ * Copyright 2006-2008 Sam Ravnborg
+ * Based in part on module-init-tools/depmod.c,file2alias
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ *
+ * Usage: modpost vmlinux module1.o module2.o ...
+ */
+
+#define _GNU_SOURCE
+#include <elf.h>
+#include <fnmatch.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <linux/limits.h>
+#include <stdbool.h>
+#include <errno.h>
+#include "modpost.h"
+#include "../../include/linux/license.h"
+
+/* Are we using CONFIG_MODVERSIONS? */
+static bool modversions;
+/* Is CONFIG_MODULE_SRCVERSION_ALL set? */
+static bool all_versions;
+/* If we are modposting external module set to 1 */
+static bool external_module;
+/* Only warn about unresolved symbols */
+static bool warn_unresolved;
+
+static int sec_mismatch_count;
+static bool sec_mismatch_warn_only = true;
+/* ignore missing files */
+static bool ignore_missing_files;
+/* If set to 1, only warn (instead of error) about missing ns imports */
+static bool allow_missing_ns_imports;
+
+static bool error_occurred;
+
+/*
+ * Cut off the warnings when there are too many. This typically occurs when
+ * vmlinux is missing. ('make modules' without building vmlinux.)
+ */
+#define MAX_UNRESOLVED_REPORTS 10
+static unsigned int nr_unresolved;
+
+/* In kernel, this size is defined in linux/module.h;
+ * here we use Elf_Addr instead of long for covering cross-compile
+ */
+
+#define MODULE_NAME_LEN (64 - sizeof(Elf_Addr))
+
+void __attribute__((format(printf, 2, 3)))
+modpost_log(enum loglevel loglevel, const char *fmt, ...)
+{
+ va_list arglist;
+
+ switch (loglevel) {
+ case LOG_WARN:
+ fprintf(stderr, "WARNING: ");
+ break;
+ case LOG_ERROR:
+ fprintf(stderr, "ERROR: ");
+ break;
+ case LOG_FATAL:
+ fprintf(stderr, "FATAL: ");
+ break;
+ default: /* invalid loglevel, ignore */
+ break;
+ }
+
+ fprintf(stderr, "modpost: ");
+
+ va_start(arglist, fmt);
+ vfprintf(stderr, fmt, arglist);
+ va_end(arglist);
+
+ if (loglevel == LOG_FATAL)
+ exit(1);
+ if (loglevel == LOG_ERROR)
+ error_occurred = true;
+}
+
+static inline bool strends(const char *str, const char *postfix)
+{
+ if (strlen(str) < strlen(postfix))
+ return false;
+
+ return strcmp(str + strlen(str) - strlen(postfix), postfix) == 0;
+}
+
+void *do_nofail(void *ptr, const char *expr)
+{
+ if (!ptr)
+ fatal("Memory allocation failure: %s.\n", expr);
+
+ return ptr;
+}
+
+char *read_text_file(const char *filename)
+{
+ struct stat st;
+ size_t nbytes;
+ int fd;
+ char *buf;
+
+ fd = open(filename, O_RDONLY);
+ if (fd < 0) {
+ perror(filename);
+ exit(1);
+ }
+
+ if (fstat(fd, &st) < 0) {
+ perror(filename);
+ exit(1);
+ }
+
+ buf = NOFAIL(malloc(st.st_size + 1));
+
+ nbytes = st.st_size;
+
+ while (nbytes) {
+ ssize_t bytes_read;
+
+ bytes_read = read(fd, buf, nbytes);
+ if (bytes_read < 0) {
+ perror(filename);
+ exit(1);
+ }
+
+ nbytes -= bytes_read;
+ }
+ buf[st.st_size] = '\0';
+
+ close(fd);
+
+ return buf;
+}
+
+char *get_line(char **stringp)
+{
+ char *orig = *stringp, *next;
+
+ /* do not return the unwanted extra line at EOF */
+ if (!orig || *orig == '\0')
+ return NULL;
+
+ /* don't use strsep here, it is not available everywhere */
+ next = strchr(orig, '\n');
+ if (next)
+ *next++ = '\0';
+
+ *stringp = next;
+
+ return orig;
+}
+
+/* A list of all modules we processed */
+LIST_HEAD(modules);
+
+static struct module *find_module(const char *modname)
+{
+ struct module *mod;
+
+ list_for_each_entry(mod, &modules, list) {
+ if (strcmp(mod->name, modname) == 0)
+ return mod;
+ }
+ return NULL;
+}
+
+static struct module *new_module(const char *name, size_t namelen)
+{
+ struct module *mod;
+
+ mod = NOFAIL(malloc(sizeof(*mod) + namelen + 1));
+ memset(mod, 0, sizeof(*mod));
+
+ INIT_LIST_HEAD(&mod->exported_symbols);
+ INIT_LIST_HEAD(&mod->unresolved_symbols);
+ INIT_LIST_HEAD(&mod->missing_namespaces);
+ INIT_LIST_HEAD(&mod->imported_namespaces);
+
+ memcpy(mod->name, name, namelen);
+ mod->name[namelen] = '\0';
+ mod->is_vmlinux = (strcmp(mod->name, "vmlinux") == 0);
+
+ /*
+ * Set mod->is_gpl_compatible to true by default. If MODULE_LICENSE()
+ * is missing, do not check the use for EXPORT_SYMBOL_GPL() becasue
+ * modpost will exit wiht error anyway.
+ */
+ mod->is_gpl_compatible = true;
+
+ list_add_tail(&mod->list, &modules);
+
+ return mod;
+}
+
+/* A hash of all exported symbols,
+ * struct symbol is also used for lists of unresolved symbols */
+
+#define SYMBOL_HASH_SIZE 1024
+
+struct symbol {
+ struct symbol *next;
+ struct list_head list; /* link to module::exported_symbols or module::unresolved_symbols */
+ struct module *module;
+ char *namespace;
+ unsigned int crc;
+ bool crc_valid;
+ bool weak;
+ bool is_gpl_only; /* exported by EXPORT_SYMBOL_GPL */
+ char name[];
+};
+
+static struct symbol *symbolhash[SYMBOL_HASH_SIZE];
+
+/* This is based on the hash algorithm from gdbm, via tdb */
+static inline unsigned int tdb_hash(const char *name)
+{
+ unsigned value; /* Used to compute the hash value. */
+ unsigned i; /* Used to cycle through random values. */
+
+ /* Set the initial value from the key size. */
+ for (value = 0x238F13AF * strlen(name), i = 0; name[i]; i++)
+ value = (value + (((unsigned char *)name)[i] << (i*5 % 24)));
+
+ return (1103515243 * value + 12345);
+}
+
+/**
+ * Allocate a new symbols for use in the hash of exported symbols or
+ * the list of unresolved symbols per module
+ **/
+static struct symbol *alloc_symbol(const char *name)
+{
+ struct symbol *s = NOFAIL(malloc(sizeof(*s) + strlen(name) + 1));
+
+ memset(s, 0, sizeof(*s));
+ strcpy(s->name, name);
+
+ return s;
+}
+
+/* For the hash of exported symbols */
+static void hash_add_symbol(struct symbol *sym)
+{
+ unsigned int hash;
+
+ hash = tdb_hash(sym->name) % SYMBOL_HASH_SIZE;
+ sym->next = symbolhash[hash];
+ symbolhash[hash] = sym;
+}
+
+static void sym_add_unresolved(const char *name, struct module *mod, bool weak)
+{
+ struct symbol *sym;
+
+ sym = alloc_symbol(name);
+ sym->weak = weak;
+
+ list_add_tail(&sym->list, &mod->unresolved_symbols);
+}
+
+static struct symbol *sym_find_with_module(const char *name, struct module *mod)
+{
+ struct symbol *s;
+
+ /* For our purposes, .foo matches foo. PPC64 needs this. */
+ if (name[0] == '.')
+ name++;
+
+ for (s = symbolhash[tdb_hash(name) % SYMBOL_HASH_SIZE]; s; s = s->next) {
+ if (strcmp(s->name, name) == 0 && (!mod || s->module == mod))
+ return s;
+ }
+ return NULL;
+}
+
+static struct symbol *find_symbol(const char *name)
+{
+ return sym_find_with_module(name, NULL);
+}
+
+struct namespace_list {
+ struct list_head list;
+ char namespace[];
+};
+
+static bool contains_namespace(struct list_head *head, const char *namespace)
+{
+ struct namespace_list *list;
+
+ list_for_each_entry(list, head, list) {
+ if (!strcmp(list->namespace, namespace))
+ return true;
+ }
+
+ return false;
+}
+
+static void add_namespace(struct list_head *head, const char *namespace)
+{
+ struct namespace_list *ns_entry;
+
+ if (!contains_namespace(head, namespace)) {
+ ns_entry = NOFAIL(malloc(sizeof(*ns_entry) +
+ strlen(namespace) + 1));
+ strcpy(ns_entry->namespace, namespace);
+ list_add_tail(&ns_entry->list, head);
+ }
+}
+
+static void *sym_get_data_by_offset(const struct elf_info *info,
+ unsigned int secindex, unsigned long offset)
+{
+ Elf_Shdr *sechdr = &info->sechdrs[secindex];
+
+ return (void *)info->hdr + sechdr->sh_offset + offset;
+}
+
+void *sym_get_data(const struct elf_info *info, const Elf_Sym *sym)
+{
+ return sym_get_data_by_offset(info, get_secindex(info, sym),
+ sym->st_value);
+}
+
+static const char *sech_name(const struct elf_info *info, Elf_Shdr *sechdr)
+{
+ return sym_get_data_by_offset(info, info->secindex_strings,
+ sechdr->sh_name);
+}
+
+static const char *sec_name(const struct elf_info *info, unsigned int secindex)
+{
+ /*
+ * If sym->st_shndx is a special section index, there is no
+ * corresponding section header.
+ * Return "" if the index is out of range of info->sechdrs[] array.
+ */
+ if (secindex >= info->num_sections)
+ return "";
+
+ return sech_name(info, &info->sechdrs[secindex]);
+}
+
+#define strstarts(str, prefix) (strncmp(str, prefix, strlen(prefix)) == 0)
+
+static void sym_update_namespace(const char *symname, const char *namespace)
+{
+ struct symbol *s = find_symbol(symname);
+
+ /*
+ * That symbol should have been created earlier and thus this is
+ * actually an assertion.
+ */
+ if (!s) {
+ error("Could not update namespace(%s) for symbol %s\n",
+ namespace, symname);
+ return;
+ }
+
+ free(s->namespace);
+ s->namespace = namespace[0] ? NOFAIL(strdup(namespace)) : NULL;
+}
+
+static struct symbol *sym_add_exported(const char *name, struct module *mod,
+ bool gpl_only)
+{
+ struct symbol *s = find_symbol(name);
+
+ if (s && (!external_module || s->module->is_vmlinux || s->module == mod)) {
+ error("%s: '%s' exported twice. Previous export was in %s%s\n",
+ mod->name, name, s->module->name,
+ s->module->is_vmlinux ? "" : ".ko");
+ }
+
+ s = alloc_symbol(name);
+ s->module = mod;
+ s->is_gpl_only = gpl_only;
+ list_add_tail(&s->list, &mod->exported_symbols);
+ hash_add_symbol(s);
+
+ return s;
+}
+
+static void sym_set_crc(struct symbol *sym, unsigned int crc)
+{
+ sym->crc = crc;
+ sym->crc_valid = true;
+}
+
+static void *grab_file(const char *filename, size_t *size)
+{
+ struct stat st;
+ void *map = MAP_FAILED;
+ int fd;
+
+ fd = open(filename, O_RDONLY);
+ if (fd < 0)
+ return NULL;
+ if (fstat(fd, &st))
+ goto failed;
+
+ *size = st.st_size;
+ map = mmap(NULL, *size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
+
+failed:
+ close(fd);
+ if (map == MAP_FAILED)
+ return NULL;
+ return map;
+}
+
+static void release_file(void *file, size_t size)
+{
+ munmap(file, size);
+}
+
+static int parse_elf(struct elf_info *info, const char *filename)
+{
+ unsigned int i;
+ Elf_Ehdr *hdr;
+ Elf_Shdr *sechdrs;
+ Elf_Sym *sym;
+ const char *secstrings;
+ unsigned int symtab_idx = ~0U, symtab_shndx_idx = ~0U;
+
+ hdr = grab_file(filename, &info->size);
+ if (!hdr) {
+ if (ignore_missing_files) {
+ fprintf(stderr, "%s: %s (ignored)\n", filename,
+ strerror(errno));
+ return 0;
+ }
+ perror(filename);
+ exit(1);
+ }
+ info->hdr = hdr;
+ if (info->size < sizeof(*hdr)) {
+ /* file too small, assume this is an empty .o file */
+ return 0;
+ }
+ /* Is this a valid ELF file? */
+ if ((hdr->e_ident[EI_MAG0] != ELFMAG0) ||
+ (hdr->e_ident[EI_MAG1] != ELFMAG1) ||
+ (hdr->e_ident[EI_MAG2] != ELFMAG2) ||
+ (hdr->e_ident[EI_MAG3] != ELFMAG3)) {
+ /* Not an ELF file - silently ignore it */
+ return 0;
+ }
+ /* Fix endianness in ELF header */
+ hdr->e_type = TO_NATIVE(hdr->e_type);
+ hdr->e_machine = TO_NATIVE(hdr->e_machine);
+ hdr->e_version = TO_NATIVE(hdr->e_version);
+ hdr->e_entry = TO_NATIVE(hdr->e_entry);
+ hdr->e_phoff = TO_NATIVE(hdr->e_phoff);
+ hdr->e_shoff = TO_NATIVE(hdr->e_shoff);
+ hdr->e_flags = TO_NATIVE(hdr->e_flags);
+ hdr->e_ehsize = TO_NATIVE(hdr->e_ehsize);
+ hdr->e_phentsize = TO_NATIVE(hdr->e_phentsize);
+ hdr->e_phnum = TO_NATIVE(hdr->e_phnum);
+ hdr->e_shentsize = TO_NATIVE(hdr->e_shentsize);
+ hdr->e_shnum = TO_NATIVE(hdr->e_shnum);
+ hdr->e_shstrndx = TO_NATIVE(hdr->e_shstrndx);
+ sechdrs = (void *)hdr + hdr->e_shoff;
+ info->sechdrs = sechdrs;
+
+ /* modpost only works for relocatable objects */
+ if (hdr->e_type != ET_REL)
+ fatal("%s: not relocatable object.", filename);
+
+ /* Check if file offset is correct */
+ if (hdr->e_shoff > info->size) {
+ fatal("section header offset=%lu in file '%s' is bigger than filesize=%zu\n",
+ (unsigned long)hdr->e_shoff, filename, info->size);
+ return 0;
+ }
+
+ if (hdr->e_shnum == SHN_UNDEF) {
+ /*
+ * There are more than 64k sections,
+ * read count from .sh_size.
+ */
+ info->num_sections = TO_NATIVE(sechdrs[0].sh_size);
+ }
+ else {
+ info->num_sections = hdr->e_shnum;
+ }
+ if (hdr->e_shstrndx == SHN_XINDEX) {
+ info->secindex_strings = TO_NATIVE(sechdrs[0].sh_link);
+ }
+ else {
+ info->secindex_strings = hdr->e_shstrndx;
+ }
+
+ /* Fix endianness in section headers */
+ for (i = 0; i < info->num_sections; i++) {
+ sechdrs[i].sh_name = TO_NATIVE(sechdrs[i].sh_name);
+ sechdrs[i].sh_type = TO_NATIVE(sechdrs[i].sh_type);
+ sechdrs[i].sh_flags = TO_NATIVE(sechdrs[i].sh_flags);
+ sechdrs[i].sh_addr = TO_NATIVE(sechdrs[i].sh_addr);
+ sechdrs[i].sh_offset = TO_NATIVE(sechdrs[i].sh_offset);
+ sechdrs[i].sh_size = TO_NATIVE(sechdrs[i].sh_size);
+ sechdrs[i].sh_link = TO_NATIVE(sechdrs[i].sh_link);
+ sechdrs[i].sh_info = TO_NATIVE(sechdrs[i].sh_info);
+ sechdrs[i].sh_addralign = TO_NATIVE(sechdrs[i].sh_addralign);
+ sechdrs[i].sh_entsize = TO_NATIVE(sechdrs[i].sh_entsize);
+ }
+ /* Find symbol table. */
+ secstrings = (void *)hdr + sechdrs[info->secindex_strings].sh_offset;
+ for (i = 1; i < info->num_sections; i++) {
+ const char *secname;
+ int nobits = sechdrs[i].sh_type == SHT_NOBITS;
+
+ if (!nobits && sechdrs[i].sh_offset > info->size) {
+ fatal("%s is truncated. sechdrs[i].sh_offset=%lu > "
+ "sizeof(*hrd)=%zu\n", filename,
+ (unsigned long)sechdrs[i].sh_offset,
+ sizeof(*hdr));
+ return 0;
+ }
+ secname = secstrings + sechdrs[i].sh_name;
+ if (strcmp(secname, ".modinfo") == 0) {
+ if (nobits)
+ fatal("%s has NOBITS .modinfo\n", filename);
+ info->modinfo = (void *)hdr + sechdrs[i].sh_offset;
+ info->modinfo_len = sechdrs[i].sh_size;
+ }
+
+ if (sechdrs[i].sh_type == SHT_SYMTAB) {
+ unsigned int sh_link_idx;
+ symtab_idx = i;
+ info->symtab_start = (void *)hdr +
+ sechdrs[i].sh_offset;
+ info->symtab_stop = (void *)hdr +
+ sechdrs[i].sh_offset + sechdrs[i].sh_size;
+ sh_link_idx = sechdrs[i].sh_link;
+ info->strtab = (void *)hdr +
+ sechdrs[sh_link_idx].sh_offset;
+ }
+
+ /* 32bit section no. table? ("more than 64k sections") */
+ if (sechdrs[i].sh_type == SHT_SYMTAB_SHNDX) {
+ symtab_shndx_idx = i;
+ info->symtab_shndx_start = (void *)hdr +
+ sechdrs[i].sh_offset;
+ info->symtab_shndx_stop = (void *)hdr +
+ sechdrs[i].sh_offset + sechdrs[i].sh_size;
+ }
+ }
+ if (!info->symtab_start)
+ fatal("%s has no symtab?\n", filename);
+
+ /* Fix endianness in symbols */
+ for (sym = info->symtab_start; sym < info->symtab_stop; sym++) {
+ sym->st_shndx = TO_NATIVE(sym->st_shndx);
+ sym->st_name = TO_NATIVE(sym->st_name);
+ sym->st_value = TO_NATIVE(sym->st_value);
+ sym->st_size = TO_NATIVE(sym->st_size);
+ }
+
+ if (symtab_shndx_idx != ~0U) {
+ Elf32_Word *p;
+ if (symtab_idx != sechdrs[symtab_shndx_idx].sh_link)
+ fatal("%s: SYMTAB_SHNDX has bad sh_link: %u!=%u\n",
+ filename, sechdrs[symtab_shndx_idx].sh_link,
+ symtab_idx);
+ /* Fix endianness */
+ for (p = info->symtab_shndx_start; p < info->symtab_shndx_stop;
+ p++)
+ *p = TO_NATIVE(*p);
+ }
+
+ return 1;
+}
+
+static void parse_elf_finish(struct elf_info *info)
+{
+ release_file(info->hdr, info->size);
+}
+
+static int ignore_undef_symbol(struct elf_info *info, const char *symname)
+{
+ /* ignore __this_module, it will be resolved shortly */
+ if (strcmp(symname, "__this_module") == 0)
+ return 1;
+ /* ignore global offset table */
+ if (strcmp(symname, "_GLOBAL_OFFSET_TABLE_") == 0)
+ return 1;
+ if (info->hdr->e_machine == EM_PPC)
+ /* Special register function linked on all modules during final link of .ko */
+ if (strstarts(symname, "_restgpr_") ||
+ strstarts(symname, "_savegpr_") ||
+ strstarts(symname, "_rest32gpr_") ||
+ strstarts(symname, "_save32gpr_") ||
+ strstarts(symname, "_restvr_") ||
+ strstarts(symname, "_savevr_"))
+ return 1;
+ if (info->hdr->e_machine == EM_PPC64)
+ /* Special register function linked on all modules during final link of .ko */
+ if (strstarts(symname, "_restgpr0_") ||
+ strstarts(symname, "_savegpr0_") ||
+ strstarts(symname, "_restvr_") ||
+ strstarts(symname, "_savevr_") ||
+ strcmp(symname, ".TOC.") == 0)
+ return 1;
+
+ if (info->hdr->e_machine == EM_S390)
+ /* Expoline thunks are linked on all kernel modules during final link of .ko */
+ if (strstarts(symname, "__s390_indirect_jump_r"))
+ return 1;
+ /* Do not ignore this symbol */
+ return 0;
+}
+
+static void handle_symbol(struct module *mod, struct elf_info *info,
+ const Elf_Sym *sym, const char *symname)
+{
+ switch (sym->st_shndx) {
+ case SHN_COMMON:
+ if (strstarts(symname, "__gnu_lto_")) {
+ /* Should warn here, but modpost runs before the linker */
+ } else
+ warn("\"%s\" [%s] is COMMON symbol\n", symname, mod->name);
+ break;
+ case SHN_UNDEF:
+ /* undefined symbol */
+ if (ELF_ST_BIND(sym->st_info) != STB_GLOBAL &&
+ ELF_ST_BIND(sym->st_info) != STB_WEAK)
+ break;
+ if (ignore_undef_symbol(info, symname))
+ break;
+ if (info->hdr->e_machine == EM_SPARC ||
+ info->hdr->e_machine == EM_SPARCV9) {
+ /* Ignore register directives. */
+ if (ELF_ST_TYPE(sym->st_info) == STT_SPARC_REGISTER)
+ break;
+ if (symname[0] == '.') {
+ char *munged = NOFAIL(strdup(symname));
+ munged[0] = '_';
+ munged[1] = toupper(munged[1]);
+ symname = munged;
+ }
+ }
+
+ sym_add_unresolved(symname, mod,
+ ELF_ST_BIND(sym->st_info) == STB_WEAK);
+ break;
+ default:
+ /* All exported symbols */
+ if (strstarts(symname, "__ksymtab_")) {
+ const char *name, *secname;
+
+ name = symname + strlen("__ksymtab_");
+ secname = sec_name(info, get_secindex(info, sym));
+
+ if (strstarts(secname, "___ksymtab_gpl+"))
+ sym_add_exported(name, mod, true);
+ else if (strstarts(secname, "___ksymtab+"))
+ sym_add_exported(name, mod, false);
+ }
+ if (strcmp(symname, "init_module") == 0)
+ mod->has_init = true;
+ if (strcmp(symname, "cleanup_module") == 0)
+ mod->has_cleanup = true;
+ break;
+ }
+}
+
+/**
+ * Parse tag=value strings from .modinfo section
+ **/
+static char *next_string(char *string, unsigned long *secsize)
+{
+ /* Skip non-zero chars */
+ while (string[0]) {
+ string++;
+ if ((*secsize)-- <= 1)
+ return NULL;
+ }
+
+ /* Skip any zero padding. */
+ while (!string[0]) {
+ string++;
+ if ((*secsize)-- <= 1)
+ return NULL;
+ }
+ return string;
+}
+
+static char *get_next_modinfo(struct elf_info *info, const char *tag,
+ char *prev)
+{
+ char *p;
+ unsigned int taglen = strlen(tag);
+ char *modinfo = info->modinfo;
+ unsigned long size = info->modinfo_len;
+
+ if (prev) {
+ size -= prev - modinfo;
+ modinfo = next_string(prev, &size);
+ }
+
+ for (p = modinfo; p; p = next_string(p, &size)) {
+ if (strncmp(p, tag, taglen) == 0 && p[taglen] == '=')
+ return p + taglen + 1;
+ }
+ return NULL;
+}
+
+static char *get_modinfo(struct elf_info *info, const char *tag)
+
+{
+ return get_next_modinfo(info, tag, NULL);
+}
+
+static const char *sym_name(struct elf_info *elf, Elf_Sym *sym)
+{
+ if (sym)
+ return elf->strtab + sym->st_name;
+ else
+ return "(unknown)";
+}
+
+/*
+ * Check whether the 'string' argument matches one of the 'patterns',
+ * an array of shell wildcard patterns (glob).
+ *
+ * Return true is there is a match.
+ */
+static bool match(const char *string, const char *const patterns[])
+{
+ const char *pattern;
+
+ while ((pattern = *patterns++)) {
+ if (!fnmatch(pattern, string, 0))
+ return true;
+ }
+
+ return false;
+}
+
+/* useful to pass patterns to match() directly */
+#define PATTERNS(...) \
+ ({ \
+ static const char *const patterns[] = {__VA_ARGS__, NULL}; \
+ patterns; \
+ })
+
+/* sections that we do not want to do full section mismatch check on */
+static const char *const section_white_list[] =
+{
+ ".comment*",
+ ".debug*",
+ ".zdebug*", /* Compressed debug sections. */
+ ".GCC.command.line", /* record-gcc-switches */
+ ".mdebug*", /* alpha, score, mips etc. */
+ ".pdr", /* alpha, score, mips etc. */
+ ".stab*",
+ ".note*",
+ ".got*",
+ ".toc*",
+ ".xt.prop", /* xtensa */
+ ".xt.lit", /* xtensa */
+ ".arcextmap*", /* arc */
+ ".gnu.linkonce.arcext*", /* arc : modules */
+ ".cmem*", /* EZchip */
+ ".fmt_slot*", /* EZchip */
+ ".gnu.lto*",
+ ".discard.*",
+ NULL
+};
+
+/*
+ * This is used to find sections missing the SHF_ALLOC flag.
+ * The cause of this is often a section specified in assembler
+ * without "ax" / "aw".
+ */
+static void check_section(const char *modname, struct elf_info *elf,
+ Elf_Shdr *sechdr)
+{
+ const char *sec = sech_name(elf, sechdr);
+
+ if (sechdr->sh_type == SHT_PROGBITS &&
+ !(sechdr->sh_flags & SHF_ALLOC) &&
+ !match(sec, section_white_list)) {
+ warn("%s (%s): unexpected non-allocatable section.\n"
+ "Did you forget to use \"ax\"/\"aw\" in a .S file?\n"
+ "Note that for example <linux/init.h> contains\n"
+ "section definitions for use in .S files.\n\n",
+ modname, sec);
+ }
+}
+
+
+
+#define ALL_INIT_DATA_SECTIONS \
+ ".init.setup", ".init.rodata", ".meminit.rodata", \
+ ".init.data", ".meminit.data"
+#define ALL_EXIT_DATA_SECTIONS \
+ ".exit.data", ".memexit.data"
+
+#define ALL_INIT_TEXT_SECTIONS \
+ ".init.text", ".meminit.text"
+#define ALL_EXIT_TEXT_SECTIONS \
+ ".exit.text", ".memexit.text"
+
+#define ALL_PCI_INIT_SECTIONS \
+ ".pci_fixup_early", ".pci_fixup_header", ".pci_fixup_final", \
+ ".pci_fixup_enable", ".pci_fixup_resume", \
+ ".pci_fixup_resume_early", ".pci_fixup_suspend"
+
+#define ALL_XXXINIT_SECTIONS MEM_INIT_SECTIONS
+#define ALL_XXXEXIT_SECTIONS MEM_EXIT_SECTIONS
+
+#define ALL_INIT_SECTIONS INIT_SECTIONS, ALL_XXXINIT_SECTIONS
+#define ALL_EXIT_SECTIONS EXIT_SECTIONS, ALL_XXXEXIT_SECTIONS
+
+#define DATA_SECTIONS ".data", ".data.rel"
+#define TEXT_SECTIONS ".text", ".text.unlikely", ".sched.text", \
+ ".kprobes.text", ".cpuidle.text", ".noinstr.text"
+#define OTHER_TEXT_SECTIONS ".ref.text", ".head.text", ".spinlock.text", \
+ ".fixup", ".entry.text", ".exception.text", ".text.*", \
+ ".coldtext", ".softirqentry.text"
+
+#define INIT_SECTIONS ".init.*"
+#define MEM_INIT_SECTIONS ".meminit.*"
+
+#define EXIT_SECTIONS ".exit.*"
+#define MEM_EXIT_SECTIONS ".memexit.*"
+
+#define ALL_TEXT_SECTIONS ALL_INIT_TEXT_SECTIONS, ALL_EXIT_TEXT_SECTIONS, \
+ TEXT_SECTIONS, OTHER_TEXT_SECTIONS
+
+/* init data sections */
+static const char *const init_data_sections[] =
+ { ALL_INIT_DATA_SECTIONS, NULL };
+
+/* all init sections */
+static const char *const init_sections[] = { ALL_INIT_SECTIONS, NULL };
+
+/* all text sections */
+static const char *const text_sections[] = { ALL_TEXT_SECTIONS, NULL };
+
+/* data section */
+static const char *const data_sections[] = { DATA_SECTIONS, NULL };
+
+static const char *const head_sections[] = { ".head.text*", NULL };
+static const char *const linker_symbols[] =
+ { "__init_begin", "_sinittext", "_einittext", NULL };
+static const char *const optim_symbols[] = { "*.constprop.*", NULL };
+
+enum mismatch {
+ TEXT_TO_ANY_INIT,
+ DATA_TO_ANY_INIT,
+ TEXT_TO_ANY_EXIT,
+ DATA_TO_ANY_EXIT,
+ XXXINIT_TO_SOME_INIT,
+ XXXEXIT_TO_SOME_EXIT,
+ ANY_INIT_TO_ANY_EXIT,
+ ANY_EXIT_TO_ANY_INIT,
+ EXPORT_TO_INIT_EXIT,
+ EXTABLE_TO_NON_TEXT,
+};
+
+/**
+ * Describe how to match sections on different criteria:
+ *
+ * @fromsec: Array of sections to be matched.
+ *
+ * @bad_tosec: Relocations applied to a section in @fromsec to a section in
+ * this array is forbidden (black-list). Can be empty.
+ *
+ * @good_tosec: Relocations applied to a section in @fromsec must be
+ * targeting sections in this array (white-list). Can be empty.
+ *
+ * @mismatch: Type of mismatch.
+ *
+ * @handler: Specific handler to call when a match is found. If NULL,
+ * default_mismatch_handler() will be called.
+ *
+ */
+struct sectioncheck {
+ const char *fromsec[20];
+ const char *bad_tosec[20];
+ const char *good_tosec[20];
+ enum mismatch mismatch;
+ void (*handler)(const char *modname, struct elf_info *elf,
+ const struct sectioncheck* const mismatch,
+ Elf_Rela *r, Elf_Sym *sym, const char *fromsec);
+
+};
+
+static void extable_mismatch_handler(const char *modname, struct elf_info *elf,
+ const struct sectioncheck* const mismatch,
+ Elf_Rela *r, Elf_Sym *sym,
+ const char *fromsec);
+
+static const struct sectioncheck sectioncheck[] = {
+/* Do not reference init/exit code/data from
+ * normal code and data
+ */
+{
+ .fromsec = { TEXT_SECTIONS, NULL },
+ .bad_tosec = { ALL_INIT_SECTIONS, NULL },
+ .mismatch = TEXT_TO_ANY_INIT,
+},
+{
+ .fromsec = { DATA_SECTIONS, NULL },
+ .bad_tosec = { ALL_XXXINIT_SECTIONS, NULL },
+ .mismatch = DATA_TO_ANY_INIT,
+},
+{
+ .fromsec = { DATA_SECTIONS, NULL },
+ .bad_tosec = { INIT_SECTIONS, NULL },
+ .mismatch = DATA_TO_ANY_INIT,
+},
+{
+ .fromsec = { TEXT_SECTIONS, NULL },
+ .bad_tosec = { ALL_EXIT_SECTIONS, NULL },
+ .mismatch = TEXT_TO_ANY_EXIT,
+},
+{
+ .fromsec = { DATA_SECTIONS, NULL },
+ .bad_tosec = { ALL_EXIT_SECTIONS, NULL },
+ .mismatch = DATA_TO_ANY_EXIT,
+},
+/* Do not reference init code/data from meminit code/data */
+{
+ .fromsec = { ALL_XXXINIT_SECTIONS, NULL },
+ .bad_tosec = { INIT_SECTIONS, NULL },
+ .mismatch = XXXINIT_TO_SOME_INIT,
+},
+/* Do not reference exit code/data from memexit code/data */
+{
+ .fromsec = { ALL_XXXEXIT_SECTIONS, NULL },
+ .bad_tosec = { EXIT_SECTIONS, NULL },
+ .mismatch = XXXEXIT_TO_SOME_EXIT,
+},
+/* Do not use exit code/data from init code */
+{
+ .fromsec = { ALL_INIT_SECTIONS, NULL },
+ .bad_tosec = { ALL_EXIT_SECTIONS, NULL },
+ .mismatch = ANY_INIT_TO_ANY_EXIT,
+},
+/* Do not use init code/data from exit code */
+{
+ .fromsec = { ALL_EXIT_SECTIONS, NULL },
+ .bad_tosec = { ALL_INIT_SECTIONS, NULL },
+ .mismatch = ANY_EXIT_TO_ANY_INIT,
+},
+{
+ .fromsec = { ALL_PCI_INIT_SECTIONS, NULL },
+ .bad_tosec = { INIT_SECTIONS, NULL },
+ .mismatch = ANY_INIT_TO_ANY_EXIT,
+},
+/* Do not export init/exit functions or data */
+{
+ .fromsec = { "___ksymtab*", NULL },
+ .bad_tosec = { INIT_SECTIONS, EXIT_SECTIONS, NULL },
+ .mismatch = EXPORT_TO_INIT_EXIT,
+},
+{
+ .fromsec = { "__ex_table", NULL },
+ /* If you're adding any new black-listed sections in here, consider
+ * adding a special 'printer' for them in scripts/check_extable.
+ */
+ .bad_tosec = { ".altinstr_replacement", NULL },
+ .good_tosec = {ALL_TEXT_SECTIONS , NULL},
+ .mismatch = EXTABLE_TO_NON_TEXT,
+ .handler = extable_mismatch_handler,
+}
+};
+
+static const struct sectioncheck *section_mismatch(
+ const char *fromsec, const char *tosec)
+{
+ int i;
+
+ /*
+ * The target section could be the SHT_NUL section when we're
+ * handling relocations to un-resolved symbols, trying to match it
+ * doesn't make much sense and causes build failures on parisc
+ * architectures.
+ */
+ if (*tosec == '\0')
+ return NULL;
+
+ for (i = 0; i < ARRAY_SIZE(sectioncheck); i++) {
+ const struct sectioncheck *check = §ioncheck[i];
+
+ if (match(fromsec, check->fromsec)) {
+ if (check->bad_tosec[0] && match(tosec, check->bad_tosec))
+ return check;
+ if (check->good_tosec[0] && !match(tosec, check->good_tosec))
+ return check;
+ }
+ }
+ return NULL;
+}
+
+/**
+ * Whitelist to allow certain references to pass with no warning.
+ *
+ * Pattern 1:
+ * If a module parameter is declared __initdata and permissions=0
+ * then this is legal despite the warning generated.
+ * We cannot see value of permissions here, so just ignore
+ * this pattern.
+ * The pattern is identified by:
+ * tosec = .init.data
+ * fromsec = .data*
+ * atsym =__param*
+ *
+ * Pattern 1a:
+ * module_param_call() ops can refer to __init set function if permissions=0
+ * The pattern is identified by:
+ * tosec = .init.text
+ * fromsec = .data*
+ * atsym = __param_ops_*
+ *
+ * Pattern 3:
+ * Whitelist all references from .head.text to any init section
+ *
+ * Pattern 4:
+ * Some symbols belong to init section but still it is ok to reference
+ * these from non-init sections as these symbols don't have any memory
+ * allocated for them and symbol address and value are same. So even
+ * if init section is freed, its ok to reference those symbols.
+ * For ex. symbols marking the init section boundaries.
+ * This pattern is identified by
+ * refsymname = __init_begin, _sinittext, _einittext
+ *
+ * Pattern 5:
+ * GCC may optimize static inlines when fed constant arg(s) resulting
+ * in functions like cpumask_empty() -- generating an associated symbol
+ * cpumask_empty.constprop.3 that appears in the audit. If the const that
+ * is passed in comes from __init, like say nmi_ipi_mask, we get a
+ * meaningless section warning. May need to add isra symbols too...
+ * This pattern is identified by
+ * tosec = init section
+ * fromsec = text section
+ * refsymname = *.constprop.*
+ *
+ * Pattern 6:
+ * Hide section mismatch warnings for ELF local symbols. The goal
+ * is to eliminate false positive modpost warnings caused by
+ * compiler-generated ELF local symbol names such as ".LANCHOR1".
+ * Autogenerated symbol names bypass modpost's "Pattern 2"
+ * whitelisting, which relies on pattern-matching against symbol
+ * names to work. (One situation where gcc can autogenerate ELF
+ * local symbols is when "-fsection-anchors" is used.)
+ **/
+static int secref_whitelist(const struct sectioncheck *mismatch,
+ const char *fromsec, const char *fromsym,
+ const char *tosec, const char *tosym)
+{
+ /* Check for pattern 1 */
+ if (match(tosec, init_data_sections) &&
+ match(fromsec, data_sections) &&
+ strstarts(fromsym, "__param"))
+ return 0;
+
+ /* Check for pattern 1a */
+ if (strcmp(tosec, ".init.text") == 0 &&
+ match(fromsec, data_sections) &&
+ strstarts(fromsym, "__param_ops_"))
+ return 0;
+
+ /* symbols in data sections that may refer to any init/exit sections */
+ if (match(fromsec, PATTERNS(DATA_SECTIONS)) &&
+ match(tosec, PATTERNS(ALL_INIT_SECTIONS, ALL_EXIT_SECTIONS)) &&
+ match(fromsym, PATTERNS("*_template", // scsi uses *_template a lot
+ "*_timer", // arm uses ops structures named _timer a lot
+ "*_sht", // scsi also used *_sht to some extent
+ "*_ops",
+ "*_probe",
+ "*_probe_one",
+ "*_console")))
+ return 0;
+
+ /* symbols in data sections that may refer to meminit/exit sections */
+ if (match(fromsec, PATTERNS(DATA_SECTIONS)) &&
+ match(tosec, PATTERNS(ALL_XXXINIT_SECTIONS, ALL_EXIT_SECTIONS)) &&
+ match(fromsym, PATTERNS("*driver")))
+ return 0;
+
+ /* Check for pattern 3 */
+ if (match(fromsec, head_sections) &&
+ match(tosec, init_sections))
+ return 0;
+
+ /* Check for pattern 4 */
+ if (match(tosym, linker_symbols))
+ return 0;
+
+ /* Check for pattern 5 */
+ if (match(fromsec, text_sections) &&
+ match(tosec, init_sections) &&
+ match(fromsym, optim_symbols))
+ return 0;
+
+ /* Check for pattern 6 */
+ if (strstarts(fromsym, ".L"))
+ return 0;
+
+ return 1;
+}
+
+static inline int is_arm_mapping_symbol(const char *str)
+{
+ return str[0] == '$' &&
+ (str[1] == 'a' || str[1] == 'd' || str[1] == 't' || str[1] == 'x')
+ && (str[2] == '\0' || str[2] == '.');
+}
+
+/*
+ * If there's no name there, ignore it; likewise, ignore it if it's
+ * one of the magic symbols emitted used by current ARM tools.
+ *
+ * Otherwise if find_symbols_between() returns those symbols, they'll
+ * fail the whitelist tests and cause lots of false alarms ... fixable
+ * only by merging __exit and __init sections into __text, bloating
+ * the kernel (which is especially evil on embedded platforms).
+ */
+static inline int is_valid_name(struct elf_info *elf, Elf_Sym *sym)
+{
+ const char *name = elf->strtab + sym->st_name;
+
+ if (!name || !strlen(name))
+ return 0;
+ return !is_arm_mapping_symbol(name);
+}
+
+/**
+ * Find symbol based on relocation record info.
+ * In some cases the symbol supplied is a valid symbol so
+ * return refsym. If st_name != 0 we assume this is a valid symbol.
+ * In other cases the symbol needs to be looked up in the symbol table
+ * based on section and address.
+ * **/
+static Elf_Sym *find_elf_symbol(struct elf_info *elf, Elf64_Sword addr,
+ Elf_Sym *relsym)
+{
+ Elf_Sym *sym;
+ Elf_Sym *near = NULL;
+ Elf64_Sword distance = 20;
+ Elf64_Sword d;
+ unsigned int relsym_secindex;
+
+ if (relsym->st_name != 0)
+ return relsym;
+
+ /*
+ * Strive to find a better symbol name, but the resulting name may not
+ * match the symbol referenced in the original code.
+ */
+ relsym_secindex = get_secindex(elf, relsym);
+ for (sym = elf->symtab_start; sym < elf->symtab_stop; sym++) {
+ if (get_secindex(elf, sym) != relsym_secindex)
+ continue;
+ if (ELF_ST_TYPE(sym->st_info) == STT_SECTION)
+ continue;
+ if (!is_valid_name(elf, sym))
+ continue;
+ if (sym->st_value == addr)
+ return sym;
+ /* Find a symbol nearby - addr are maybe negative */
+ d = sym->st_value - addr;
+ if (d < 0)
+ d = addr - sym->st_value;
+ if (d < distance) {
+ distance = d;
+ near = sym;
+ }
+ }
+ /* We need a close match */
+ if (distance < 20)
+ return near;
+ else
+ return NULL;
+}
+
+/*
+ * Find symbols before or equal addr and after addr - in the section sec.
+ * If we find two symbols with equal offset prefer one with a valid name.
+ * The ELF format may have a better way to detect what type of symbol
+ * it is, but this works for now.
+ **/
+static Elf_Sym *find_elf_symbol2(struct elf_info *elf, Elf_Addr addr,
+ const char *sec)
+{
+ Elf_Sym *sym;
+ Elf_Sym *near = NULL;
+ Elf_Addr distance = ~0;
+
+ for (sym = elf->symtab_start; sym < elf->symtab_stop; sym++) {
+ const char *symsec;
+
+ if (is_shndx_special(sym->st_shndx))
+ continue;
+ symsec = sec_name(elf, get_secindex(elf, sym));
+ if (strcmp(symsec, sec) != 0)
+ continue;
+ if (!is_valid_name(elf, sym))
+ continue;
+ if (sym->st_value <= addr && addr - sym->st_value <= distance) {
+ distance = addr - sym->st_value;
+ near = sym;
+ }
+ }
+ return near;
+}
+
+static int is_function(Elf_Sym *sym)
+{
+ if (sym)
+ return ELF_ST_TYPE(sym->st_info) == STT_FUNC;
+ else
+ return -1;
+}
+
+static inline void get_pretty_name(int is_func, const char** name, const char** name_p)
+{
+ switch (is_func) {
+ case 0: *name = "variable"; *name_p = ""; break;
+ case 1: *name = "function"; *name_p = "()"; break;
+ default: *name = "(unknown reference)"; *name_p = ""; break;
+ }
+}
+
+/*
+ * Print a warning about a section mismatch.
+ * Try to find symbols near it so user can find it.
+ * Check whitelist before warning - it may be a false positive.
+ */
+static void report_sec_mismatch(const char *modname,
+ const struct sectioncheck *mismatch,
+ const char *fromsec,
+ const char *fromsym,
+ const char *tosec, const char *tosym)
+{
+ sec_mismatch_count++;
+
+ switch (mismatch->mismatch) {
+ case TEXT_TO_ANY_INIT:
+ case DATA_TO_ANY_INIT:
+ case TEXT_TO_ANY_EXIT:
+ case DATA_TO_ANY_EXIT:
+ case XXXINIT_TO_SOME_INIT:
+ case XXXEXIT_TO_SOME_EXIT:
+ case ANY_INIT_TO_ANY_EXIT:
+ case ANY_EXIT_TO_ANY_INIT:
+ warn("%s: section mismatch in reference: %s (section: %s) -> %s (section: %s)\n",
+ modname, fromsym, fromsec, tosym, tosec);
+ break;
+ case EXPORT_TO_INIT_EXIT:
+ warn("%s: EXPORT_SYMBOL used for init/exit symbol: %s (section: %s)\n",
+ modname, tosym, tosec);
+ break;
+ case EXTABLE_TO_NON_TEXT:
+ fatal("There's a special handler for this mismatch type, we should never get here.\n");
+ break;
+ }
+}
+
+static void default_mismatch_handler(const char *modname, struct elf_info *elf,
+ const struct sectioncheck* const mismatch,
+ Elf_Rela *r, Elf_Sym *sym, const char *fromsec)
+{
+ const char *tosec;
+ Elf_Sym *to;
+ Elf_Sym *from;
+ const char *tosym;
+ const char *fromsym;
+
+ from = find_elf_symbol2(elf, r->r_offset, fromsec);
+ fromsym = sym_name(elf, from);
+
+ tosec = sec_name(elf, get_secindex(elf, sym));
+ to = find_elf_symbol(elf, r->r_addend, sym);
+ tosym = sym_name(elf, to);
+
+ /* check whitelist - we may ignore it */
+ if (secref_whitelist(mismatch,
+ fromsec, fromsym, tosec, tosym)) {
+ report_sec_mismatch(modname, mismatch,
+ fromsec, fromsym, tosec, tosym);
+ }
+}
+
+static int is_executable_section(struct elf_info* elf, unsigned int section_index)
+{
+ if (section_index >= elf->num_sections)
+ fatal("section_index is outside elf->num_sections!\n");
+
+ return ((elf->sechdrs[section_index].sh_flags & SHF_EXECINSTR) == SHF_EXECINSTR);
+}
+
+static void report_extable_warnings(const char* modname, struct elf_info* elf,
+ const struct sectioncheck* const mismatch,
+ Elf_Rela* r, Elf_Sym* sym,
+ const char* fromsec, const char* tosec)
+{
+ Elf_Sym* fromsym = find_elf_symbol2(elf, r->r_offset, fromsec);
+ const char* fromsym_name = sym_name(elf, fromsym);
+ Elf_Sym* tosym = find_elf_symbol(elf, r->r_addend, sym);
+ const char* tosym_name = sym_name(elf, tosym);
+ const char* from_pretty_name;
+ const char* from_pretty_name_p;
+ const char* to_pretty_name;
+ const char* to_pretty_name_p;
+
+ get_pretty_name(is_function(fromsym),
+ &from_pretty_name, &from_pretty_name_p);
+ get_pretty_name(is_function(tosym),
+ &to_pretty_name, &to_pretty_name_p);
+
+ warn("%s(%s+0x%lx): Section mismatch in reference"
+ " from the %s %s%s to the %s %s:%s%s\n",
+ modname, fromsec, (long)r->r_offset, from_pretty_name,
+ fromsym_name, from_pretty_name_p,
+ to_pretty_name, tosec, tosym_name, to_pretty_name_p);
+
+ if (!match(tosec, mismatch->bad_tosec) &&
+ is_executable_section(elf, get_secindex(elf, sym)))
+ fprintf(stderr,
+ "The relocation at %s+0x%lx references\n"
+ "section \"%s\" which is not in the list of\n"
+ "authorized sections. If you're adding a new section\n"
+ "and/or if this reference is valid, add \"%s\" to the\n"
+ "list of authorized sections to jump to on fault.\n"
+ "This can be achieved by adding \"%s\" to \n"
+ "OTHER_TEXT_SECTIONS in scripts/mod/modpost.c.\n",
+ fromsec, (long)r->r_offset, tosec, tosec, tosec);
+}
+
+static void extable_mismatch_handler(const char* modname, struct elf_info *elf,
+ const struct sectioncheck* const mismatch,
+ Elf_Rela* r, Elf_Sym* sym,
+ const char *fromsec)
+{
+ const char* tosec = sec_name(elf, get_secindex(elf, sym));
+
+ sec_mismatch_count++;
+
+ report_extable_warnings(modname, elf, mismatch, r, sym, fromsec, tosec);
+
+ if (match(tosec, mismatch->bad_tosec))
+ fatal("The relocation at %s+0x%lx references\n"
+ "section \"%s\" which is black-listed.\n"
+ "Something is seriously wrong and should be fixed.\n"
+ "You might get more information about where this is\n"
+ "coming from by using scripts/check_extable.sh %s\n",
+ fromsec, (long)r->r_offset, tosec, modname);
+ else if (!is_executable_section(elf, get_secindex(elf, sym)))
+ error("%s+0x%lx references non-executable section '%s'\n",
+ fromsec, (long)r->r_offset, tosec);
+}
+
+static void check_section_mismatch(const char *modname, struct elf_info *elf,
+ Elf_Rela *r, Elf_Sym *sym, const char *fromsec)
+{
+ const char *tosec = sec_name(elf, get_secindex(elf, sym));
+ const struct sectioncheck *mismatch = section_mismatch(fromsec, tosec);
+
+ if (mismatch) {
+ if (mismatch->handler)
+ mismatch->handler(modname, elf, mismatch,
+ r, sym, fromsec);
+ else
+ default_mismatch_handler(modname, elf, mismatch,
+ r, sym, fromsec);
+ }
+}
+
+static unsigned int *reloc_location(struct elf_info *elf,
+ Elf_Shdr *sechdr, Elf_Rela *r)
+{
+ return sym_get_data_by_offset(elf, sechdr->sh_info, r->r_offset);
+}
+
+static int addend_386_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r)
+{
+ unsigned int r_typ = ELF_R_TYPE(r->r_info);
+ unsigned int *location = reloc_location(elf, sechdr, r);
+
+ switch (r_typ) {
+ case R_386_32:
+ r->r_addend = TO_NATIVE(*location);
+ break;
+ case R_386_PC32:
+ r->r_addend = TO_NATIVE(*location) + 4;
+ break;
+ }
+ return 0;
+}
+
+#ifndef R_ARM_CALL
+#define R_ARM_CALL 28
+#endif
+#ifndef R_ARM_JUMP24
+#define R_ARM_JUMP24 29
+#endif
+
+#ifndef R_ARM_THM_CALL
+#define R_ARM_THM_CALL 10
+#endif
+#ifndef R_ARM_THM_JUMP24
+#define R_ARM_THM_JUMP24 30
+#endif
+#ifndef R_ARM_THM_JUMP19
+#define R_ARM_THM_JUMP19 51
+#endif
+
+static int32_t sign_extend32(int32_t value, int index)
+{
+ uint8_t shift = 31 - index;
+
+ return (int32_t)(value << shift) >> shift;
+}
+
+static int addend_arm_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r)
+{
+ unsigned int r_typ = ELF_R_TYPE(r->r_info);
+ Elf_Sym *sym = elf->symtab_start + ELF_R_SYM(r->r_info);
+ void *loc = reloc_location(elf, sechdr, r);
+ uint32_t inst;
+ int32_t offset;
+
+ switch (r_typ) {
+ case R_ARM_ABS32:
+ inst = TO_NATIVE(*(uint32_t *)loc);
+ r->r_addend = inst + sym->st_value;
+ break;
+ case R_ARM_PC24:
+ case R_ARM_CALL:
+ case R_ARM_JUMP24:
+ inst = TO_NATIVE(*(uint32_t *)loc);
+ offset = sign_extend32((inst & 0x00ffffff) << 2, 25);
+ r->r_addend = offset + sym->st_value + 8;
+ break;
+ case R_ARM_THM_CALL:
+ case R_ARM_THM_JUMP24:
+ case R_ARM_THM_JUMP19:
+ /* From ARM ABI: ((S + A) | T) - P */
+ r->r_addend = (int)(long)(elf->hdr +
+ sechdr->sh_offset +
+ (r->r_offset - sechdr->sh_addr));
+ break;
+ default:
+ return 1;
+ }
+ return 0;
+}
+
+static int addend_mips_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r)
+{
+ unsigned int r_typ = ELF_R_TYPE(r->r_info);
+ unsigned int *location = reloc_location(elf, sechdr, r);
+ unsigned int inst;
+
+ if (r_typ == R_MIPS_HI16)
+ return 1; /* skip this */
+ inst = TO_NATIVE(*location);
+ switch (r_typ) {
+ case R_MIPS_LO16:
+ r->r_addend = inst & 0xffff;
+ break;
+ case R_MIPS_26:
+ r->r_addend = (inst & 0x03ffffff) << 2;
+ break;
+ case R_MIPS_32:
+ r->r_addend = inst;
+ break;
+ }
+ return 0;
+}
+
+#ifndef EM_RISCV
+#define EM_RISCV 243
+#endif
+
+#ifndef R_RISCV_SUB32
+#define R_RISCV_SUB32 39
+#endif
+
+static void section_rela(const char *modname, struct elf_info *elf,
+ Elf_Shdr *sechdr)
+{
+ Elf_Sym *sym;
+ Elf_Rela *rela;
+ Elf_Rela r;
+ unsigned int r_sym;
+ const char *fromsec;
+
+ Elf_Rela *start = (void *)elf->hdr + sechdr->sh_offset;
+ Elf_Rela *stop = (void *)start + sechdr->sh_size;
+
+ fromsec = sec_name(elf, sechdr->sh_info);
+ /* if from section (name) is know good then skip it */
+ if (match(fromsec, section_white_list))
+ return;
+
+ for (rela = start; rela < stop; rela++) {
+ r.r_offset = TO_NATIVE(rela->r_offset);
+#if KERNEL_ELFCLASS == ELFCLASS64
+ if (elf->hdr->e_machine == EM_MIPS) {
+ unsigned int r_typ;
+ r_sym = ELF64_MIPS_R_SYM(rela->r_info);
+ r_sym = TO_NATIVE(r_sym);
+ r_typ = ELF64_MIPS_R_TYPE(rela->r_info);
+ r.r_info = ELF64_R_INFO(r_sym, r_typ);
+ } else {
+ r.r_info = TO_NATIVE(rela->r_info);
+ r_sym = ELF_R_SYM(r.r_info);
+ }
+#else
+ r.r_info = TO_NATIVE(rela->r_info);
+ r_sym = ELF_R_SYM(r.r_info);
+#endif
+ r.r_addend = TO_NATIVE(rela->r_addend);
+ switch (elf->hdr->e_machine) {
+ case EM_RISCV:
+ if (!strcmp("__ex_table", fromsec) &&
+ ELF_R_TYPE(r.r_info) == R_RISCV_SUB32)
+ continue;
+ break;
+ }
+ sym = elf->symtab_start + r_sym;
+ /* Skip special sections */
+ if (is_shndx_special(sym->st_shndx))
+ continue;
+ check_section_mismatch(modname, elf, &r, sym, fromsec);
+ }
+}
+
+static void section_rel(const char *modname, struct elf_info *elf,
+ Elf_Shdr *sechdr)
+{
+ Elf_Sym *sym;
+ Elf_Rel *rel;
+ Elf_Rela r;
+ unsigned int r_sym;
+ const char *fromsec;
+
+ Elf_Rel *start = (void *)elf->hdr + sechdr->sh_offset;
+ Elf_Rel *stop = (void *)start + sechdr->sh_size;
+
+ fromsec = sec_name(elf, sechdr->sh_info);
+ /* if from section (name) is know good then skip it */
+ if (match(fromsec, section_white_list))
+ return;
+
+ for (rel = start; rel < stop; rel++) {
+ r.r_offset = TO_NATIVE(rel->r_offset);
+#if KERNEL_ELFCLASS == ELFCLASS64
+ if (elf->hdr->e_machine == EM_MIPS) {
+ unsigned int r_typ;
+ r_sym = ELF64_MIPS_R_SYM(rel->r_info);
+ r_sym = TO_NATIVE(r_sym);
+ r_typ = ELF64_MIPS_R_TYPE(rel->r_info);
+ r.r_info = ELF64_R_INFO(r_sym, r_typ);
+ } else {
+ r.r_info = TO_NATIVE(rel->r_info);
+ r_sym = ELF_R_SYM(r.r_info);
+ }
+#else
+ r.r_info = TO_NATIVE(rel->r_info);
+ r_sym = ELF_R_SYM(r.r_info);
+#endif
+ r.r_addend = 0;
+ switch (elf->hdr->e_machine) {
+ case EM_386:
+ if (addend_386_rel(elf, sechdr, &r))
+ continue;
+ break;
+ case EM_ARM:
+ if (addend_arm_rel(elf, sechdr, &r))
+ continue;
+ break;
+ case EM_MIPS:
+ if (addend_mips_rel(elf, sechdr, &r))
+ continue;
+ break;
+ }
+ sym = elf->symtab_start + r_sym;
+ /* Skip special sections */
+ if (is_shndx_special(sym->st_shndx))
+ continue;
+ check_section_mismatch(modname, elf, &r, sym, fromsec);
+ }
+}
+
+/**
+ * A module includes a number of sections that are discarded
+ * either when loaded or when used as built-in.
+ * For loaded modules all functions marked __init and all data
+ * marked __initdata will be discarded when the module has been initialized.
+ * Likewise for modules used built-in the sections marked __exit
+ * are discarded because __exit marked function are supposed to be called
+ * only when a module is unloaded which never happens for built-in modules.
+ * The check_sec_ref() function traverses all relocation records
+ * to find all references to a section that reference a section that will
+ * be discarded and warns about it.
+ **/
+static void check_sec_ref(const char *modname, struct elf_info *elf)
+{
+ int i;
+ Elf_Shdr *sechdrs = elf->sechdrs;
+
+ /* Walk through all sections */
+ for (i = 0; i < elf->num_sections; i++) {
+ check_section(modname, elf, &elf->sechdrs[i]);
+ /* We want to process only relocation sections and not .init */
+ if (sechdrs[i].sh_type == SHT_RELA)
+ section_rela(modname, elf, &elf->sechdrs[i]);
+ else if (sechdrs[i].sh_type == SHT_REL)
+ section_rel(modname, elf, &elf->sechdrs[i]);
+ }
+}
+
+static char *remove_dot(char *s)
+{
+ size_t n = strcspn(s, ".");
+
+ if (n && s[n]) {
+ size_t m = strspn(s + n + 1, "0123456789");
+ if (m && (s[n + m + 1] == '.' || s[n + m + 1] == 0))
+ s[n] = 0;
+ }
+ return s;
+}
+
+/*
+ * The CRCs are recorded in .*.cmd files in the form of:
+ * #SYMVER <name> <crc>
+ */
+static void extract_crcs_for_object(const char *object, struct module *mod)
+{
+ char cmd_file[PATH_MAX];
+ char *buf, *p;
+ const char *base;
+ int dirlen, ret;
+
+ base = strrchr(object, '/');
+ if (base) {
+ base++;
+ dirlen = base - object;
+ } else {
+ dirlen = 0;
+ base = object;
+ }
+
+ ret = snprintf(cmd_file, sizeof(cmd_file), "%.*s.%s.cmd",
+ dirlen, object, base);
+ if (ret >= sizeof(cmd_file)) {
+ error("%s: too long path was truncated\n", cmd_file);
+ return;
+ }
+
+ buf = read_text_file(cmd_file);
+ p = buf;
+
+ while ((p = strstr(p, "\n#SYMVER "))) {
+ char *name;
+ size_t namelen;
+ unsigned int crc;
+ struct symbol *sym;
+
+ name = p + strlen("\n#SYMVER ");
+
+ p = strchr(name, ' ');
+ if (!p)
+ break;
+
+ namelen = p - name;
+ p++;
+
+ if (!isdigit(*p))
+ continue; /* skip this line */
+
+ crc = strtoul(p, &p, 0);
+ if (*p != '\n')
+ continue; /* skip this line */
+
+ name[namelen] = '\0';
+
+ /*
+ * sym_find_with_module() may return NULL here.
+ * It typically occurs when CONFIG_TRIM_UNUSED_KSYMS=y.
+ * Since commit e1327a127703, genksyms calculates CRCs of all
+ * symbols, including trimmed ones. Ignore orphan CRCs.
+ */
+ sym = sym_find_with_module(name, mod);
+ if (sym)
+ sym_set_crc(sym, crc);
+ }
+
+ free(buf);
+}
+
+/*
+ * The symbol versions (CRC) are recorded in the .*.cmd files.
+ * Parse them to retrieve CRCs for the current module.
+ */
+static void mod_set_crcs(struct module *mod)
+{
+ char objlist[PATH_MAX];
+ char *buf, *p, *obj;
+ int ret;
+
+ if (mod->is_vmlinux) {
+ strcpy(objlist, ".vmlinux.objs");
+ } else {
+ /* objects for a module are listed in the *.mod file. */
+ ret = snprintf(objlist, sizeof(objlist), "%s.mod", mod->name);
+ if (ret >= sizeof(objlist)) {
+ error("%s: too long path was truncated\n", objlist);
+ return;
+ }
+ }
+
+ buf = read_text_file(objlist);
+ p = buf;
+
+ while ((obj = strsep(&p, "\n")) && obj[0])
+ extract_crcs_for_object(obj, mod);
+
+ free(buf);
+}
+
+static void read_symbols(const char *modname)
+{
+ const char *symname;
+ char *version;
+ char *license;
+ char *namespace;
+ struct module *mod;
+ struct elf_info info = { };
+ Elf_Sym *sym;
+
+ if (!parse_elf(&info, modname))
+ return;
+
+ if (!strends(modname, ".o")) {
+ error("%s: filename must be suffixed with .o\n", modname);
+ return;
+ }
+
+ /* strip trailing .o */
+ mod = new_module(modname, strlen(modname) - strlen(".o"));
+
+ if (!mod->is_vmlinux) {
+ license = get_modinfo(&info, "license");
+ if (!license)
+ error("missing MODULE_LICENSE() in %s\n", modname);
+ while (license) {
+ if (!license_is_gpl_compatible(license)) {
+ mod->is_gpl_compatible = false;
+ break;
+ }
+ license = get_next_modinfo(&info, "license", license);
+ }
+
+ namespace = get_modinfo(&info, "import_ns");
+ while (namespace) {
+ add_namespace(&mod->imported_namespaces, namespace);
+ namespace = get_next_modinfo(&info, "import_ns",
+ namespace);
+ }
+ }
+
+ for (sym = info.symtab_start; sym < info.symtab_stop; sym++) {
+ symname = remove_dot(info.strtab + sym->st_name);
+
+ handle_symbol(mod, &info, sym, symname);
+ handle_moddevtable(mod, &info, sym, symname);
+ }
+
+ for (sym = info.symtab_start; sym < info.symtab_stop; sym++) {
+ symname = remove_dot(info.strtab + sym->st_name);
+
+ /* Apply symbol namespaces from __kstrtabns_<symbol> entries. */
+ if (strstarts(symname, "__kstrtabns_"))
+ sym_update_namespace(symname + strlen("__kstrtabns_"),
+ sym_get_data(&info, sym));
+ }
+
+ check_sec_ref(modname, &info);
+
+ if (!mod->is_vmlinux) {
+ version = get_modinfo(&info, "version");
+ if (version || all_versions)
+ get_src_version(mod->name, mod->srcversion,
+ sizeof(mod->srcversion) - 1);
+ }
+
+ parse_elf_finish(&info);
+
+ if (modversions) {
+ /*
+ * Our trick to get versioning for module struct etc. - it's
+ * never passed as an argument to an exported function, so
+ * the automatic versioning doesn't pick it up, but it's really
+ * important anyhow.
+ */
+ sym_add_unresolved("module_layout", mod, false);
+
+ mod_set_crcs(mod);
+ }
+}
+
+static void read_symbols_from_files(const char *filename)
+{
+ FILE *in = stdin;
+ char fname[PATH_MAX];
+
+ if (strcmp(filename, "-") != 0) {
+ in = fopen(filename, "r");
+ if (!in)
+ fatal("Can't open filenames file %s: %m", filename);
+ }
+
+ while (fgets(fname, PATH_MAX, in) != NULL) {
+ if (strends(fname, "\n"))
+ fname[strlen(fname)-1] = '\0';
+ read_symbols(fname);
+ }
+
+ if (in != stdin)
+ fclose(in);
+}
+
+#define SZ 500
+
+/* We first write the generated file into memory using the
+ * following helper, then compare to the file on disk and
+ * only update the later if anything changed */
+
+void __attribute__((format(printf, 2, 3))) buf_printf(struct buffer *buf,
+ const char *fmt, ...)
+{
+ char tmp[SZ];
+ int len;
+ va_list ap;
+
+ va_start(ap, fmt);
+ len = vsnprintf(tmp, SZ, fmt, ap);
+ buf_write(buf, tmp, len);
+ va_end(ap);
+}
+
+void buf_write(struct buffer *buf, const char *s, int len)
+{
+ if (buf->size - buf->pos < len) {
+ buf->size += len + SZ;
+ buf->p = NOFAIL(realloc(buf->p, buf->size));
+ }
+ strncpy(buf->p + buf->pos, s, len);
+ buf->pos += len;
+}
+
+static void check_exports(struct module *mod)
+{
+ struct symbol *s, *exp;
+
+ list_for_each_entry(s, &mod->unresolved_symbols, list) {
+ const char *basename;
+ exp = find_symbol(s->name);
+ if (!exp) {
+ if (!s->weak && nr_unresolved++ < MAX_UNRESOLVED_REPORTS)
+ modpost_log(warn_unresolved ? LOG_WARN : LOG_ERROR,
+ "\"%s\" [%s.ko] undefined!\n",
+ s->name, mod->name);
+ continue;
+ }
+ if (exp->module == mod) {
+ error("\"%s\" [%s.ko] was exported without definition\n",
+ s->name, mod->name);
+ continue;
+ }
+
+ s->module = exp->module;
+ s->crc_valid = exp->crc_valid;
+ s->crc = exp->crc;
+
+ basename = strrchr(mod->name, '/');
+ if (basename)
+ basename++;
+ else
+ basename = mod->name;
+
+ if (exp->namespace &&
+ !contains_namespace(&mod->imported_namespaces, exp->namespace)) {
+ modpost_log(allow_missing_ns_imports ? LOG_WARN : LOG_ERROR,
+ "module %s uses symbol %s from namespace %s, but does not import it.\n",
+ basename, exp->name, exp->namespace);
+ add_namespace(&mod->missing_namespaces, exp->namespace);
+ }
+
+ if (!mod->is_gpl_compatible && exp->is_gpl_only)
+ error("GPL-incompatible module %s.ko uses GPL-only symbol '%s'\n",
+ basename, exp->name);
+ }
+}
+
+static void check_modname_len(struct module *mod)
+{
+ const char *mod_name;
+
+ mod_name = strrchr(mod->name, '/');
+ if (mod_name == NULL)
+ mod_name = mod->name;
+ else
+ mod_name++;
+ if (strlen(mod_name) >= MODULE_NAME_LEN)
+ error("module name is too long [%s.ko]\n", mod->name);
+}
+
+/**
+ * Header for the generated file
+ **/
+static void add_header(struct buffer *b, struct module *mod)
+{
+ buf_printf(b, "#include <linux/module.h>\n");
+ /*
+ * Include build-salt.h after module.h in order to
+ * inherit the definitions.
+ */
+ buf_printf(b, "#define INCLUDE_VERMAGIC\n");
+ buf_printf(b, "#include <linux/build-salt.h>\n");
+ buf_printf(b, "#include <linux/elfnote-lto.h>\n");
+ buf_printf(b, "#include <linux/export-internal.h>\n");
+ buf_printf(b, "#include <linux/vermagic.h>\n");
+ buf_printf(b, "#include <linux/compiler.h>\n");
+ buf_printf(b, "\n");
+ buf_printf(b, "BUILD_SALT;\n");
+ buf_printf(b, "BUILD_LTO_INFO;\n");
+ buf_printf(b, "\n");
+ buf_printf(b, "MODULE_INFO(vermagic, VERMAGIC_STRING);\n");
+ buf_printf(b, "MODULE_INFO(name, KBUILD_MODNAME);\n");
+ buf_printf(b, "\n");
+ buf_printf(b, "__visible struct module __this_module\n");
+ buf_printf(b, "__section(\".gnu.linkonce.this_module\") = {\n");
+ buf_printf(b, "\t.name = KBUILD_MODNAME,\n");
+ if (mod->has_init)
+ buf_printf(b, "\t.init = init_module,\n");
+ if (mod->has_cleanup)
+ buf_printf(b, "#ifdef CONFIG_MODULE_UNLOAD\n"
+ "\t.exit = cleanup_module,\n"
+ "#endif\n");
+ buf_printf(b, "\t.arch = MODULE_ARCH_INIT,\n");
+ buf_printf(b, "};\n");
+
+ if (!external_module)
+ buf_printf(b, "\nMODULE_INFO(intree, \"Y\");\n");
+
+ buf_printf(b,
+ "\n"
+ "#ifdef CONFIG_RETPOLINE\n"
+ "MODULE_INFO(retpoline, \"Y\");\n"
+ "#endif\n");
+
+ if (strstarts(mod->name, "drivers/staging"))
+ buf_printf(b, "\nMODULE_INFO(staging, \"Y\");\n");
+
+ if (strstarts(mod->name, "tools/testing"))
+ buf_printf(b, "\nMODULE_INFO(test, \"Y\");\n");
+}
+
+static void add_exported_symbols(struct buffer *buf, struct module *mod)
+{
+ struct symbol *sym;
+
+ if (!modversions)
+ return;
+
+ /* record CRCs for exported symbols */
+ buf_printf(buf, "\n");
+ list_for_each_entry(sym, &mod->exported_symbols, list) {
+ if (!sym->crc_valid)
+ warn("EXPORT symbol \"%s\" [%s%s] version generation failed, symbol will not be versioned.\n"
+ "Is \"%s\" prototyped in <asm/asm-prototypes.h>?\n",
+ sym->name, mod->name, mod->is_vmlinux ? "" : ".ko",
+ sym->name);
+
+ buf_printf(buf, "SYMBOL_CRC(%s, 0x%08x, \"%s\");\n",
+ sym->name, sym->crc, sym->is_gpl_only ? "_gpl" : "");
+ }
+}
+
+/**
+ * Record CRCs for unresolved symbols
+ **/
+static void add_versions(struct buffer *b, struct module *mod)
+{
+ struct symbol *s;
+
+ if (!modversions)
+ return;
+
+ buf_printf(b, "\n");
+ buf_printf(b, "static const struct modversion_info ____versions[]\n");
+ buf_printf(b, "__used __section(\"__versions\") = {\n");
+
+ list_for_each_entry(s, &mod->unresolved_symbols, list) {
+ if (!s->module)
+ continue;
+ if (!s->crc_valid) {
+ warn("\"%s\" [%s.ko] has no CRC!\n",
+ s->name, mod->name);
+ continue;
+ }
+ if (strlen(s->name) >= MODULE_NAME_LEN) {
+ error("too long symbol \"%s\" [%s.ko]\n",
+ s->name, mod->name);
+ break;
+ }
+ buf_printf(b, "\t{ %#8x, \"%s\" },\n",
+ s->crc, s->name);
+ }
+
+ buf_printf(b, "};\n");
+}
+
+static void add_depends(struct buffer *b, struct module *mod)
+{
+ struct symbol *s;
+ int first = 1;
+
+ /* Clear ->seen flag of modules that own symbols needed by this. */
+ list_for_each_entry(s, &mod->unresolved_symbols, list) {
+ if (s->module)
+ s->module->seen = s->module->is_vmlinux;
+ }
+
+ buf_printf(b, "\n");
+ buf_printf(b, "MODULE_INFO(depends, \"");
+ list_for_each_entry(s, &mod->unresolved_symbols, list) {
+ const char *p;
+ if (!s->module)
+ continue;
+
+ if (s->module->seen)
+ continue;
+
+ s->module->seen = true;
+ p = strrchr(s->module->name, '/');
+ if (p)
+ p++;
+ else
+ p = s->module->name;
+ buf_printf(b, "%s%s", first ? "" : ",", p);
+ first = 0;
+ }
+ buf_printf(b, "\");\n");
+}
+
+static void add_srcversion(struct buffer *b, struct module *mod)
+{
+ if (mod->srcversion[0]) {
+ buf_printf(b, "\n");
+ buf_printf(b, "MODULE_INFO(srcversion, \"%s\");\n",
+ mod->srcversion);
+ }
+}
+
+static void write_buf(struct buffer *b, const char *fname)
+{
+ FILE *file;
+
+ if (error_occurred)
+ return;
+
+ file = fopen(fname, "w");
+ if (!file) {
+ perror(fname);
+ exit(1);
+ }
+ if (fwrite(b->p, 1, b->pos, file) != b->pos) {
+ perror(fname);
+ exit(1);
+ }
+ if (fclose(file) != 0) {
+ perror(fname);
+ exit(1);
+ }
+}
+
+static void write_if_changed(struct buffer *b, const char *fname)
+{
+ char *tmp;
+ FILE *file;
+ struct stat st;
+
+ file = fopen(fname, "r");
+ if (!file)
+ goto write;
+
+ if (fstat(fileno(file), &st) < 0)
+ goto close_write;
+
+ if (st.st_size != b->pos)
+ goto close_write;
+
+ tmp = NOFAIL(malloc(b->pos));
+ if (fread(tmp, 1, b->pos, file) != b->pos)
+ goto free_write;
+
+ if (memcmp(tmp, b->p, b->pos) != 0)
+ goto free_write;
+
+ free(tmp);
+ fclose(file);
+ return;
+
+ free_write:
+ free(tmp);
+ close_write:
+ fclose(file);
+ write:
+ write_buf(b, fname);
+}
+
+static void write_vmlinux_export_c_file(struct module *mod)
+{
+ struct buffer buf = { };
+
+ buf_printf(&buf,
+ "#include <linux/export-internal.h>\n");
+
+ add_exported_symbols(&buf, mod);
+ write_if_changed(&buf, ".vmlinux.export.c");
+ free(buf.p);
+}
+
+/* do sanity checks, and generate *.mod.c file */
+static void write_mod_c_file(struct module *mod)
+{
+ struct buffer buf = { };
+ char fname[PATH_MAX];
+ int ret;
+
+ check_modname_len(mod);
+ check_exports(mod);
+
+ add_header(&buf, mod);
+ add_exported_symbols(&buf, mod);
+ add_versions(&buf, mod);
+ add_depends(&buf, mod);
+ add_moddevtable(&buf, mod);
+ add_srcversion(&buf, mod);
+
+ ret = snprintf(fname, sizeof(fname), "%s.mod.c", mod->name);
+ if (ret >= sizeof(fname)) {
+ error("%s: too long path was truncated\n", fname);
+ goto free;
+ }
+
+ write_if_changed(&buf, fname);
+
+free:
+ free(buf.p);
+}
+
+/* parse Module.symvers file. line format:
+ * 0x12345678<tab>symbol<tab>module<tab>export<tab>namespace
+ **/
+static void read_dump(const char *fname)
+{
+ char *buf, *pos, *line;
+
+ buf = read_text_file(fname);
+ if (!buf)
+ /* No symbol versions, silently ignore */
+ return;
+
+ pos = buf;
+
+ while ((line = get_line(&pos))) {
+ char *symname, *namespace, *modname, *d, *export;
+ unsigned int crc;
+ struct module *mod;
+ struct symbol *s;
+ bool gpl_only;
+
+ if (!(symname = strchr(line, '\t')))
+ goto fail;
+ *symname++ = '\0';
+ if (!(modname = strchr(symname, '\t')))
+ goto fail;
+ *modname++ = '\0';
+ if (!(export = strchr(modname, '\t')))
+ goto fail;
+ *export++ = '\0';
+ if (!(namespace = strchr(export, '\t')))
+ goto fail;
+ *namespace++ = '\0';
+
+ crc = strtoul(line, &d, 16);
+ if (*symname == '\0' || *modname == '\0' || *d != '\0')
+ goto fail;
+
+ if (!strcmp(export, "EXPORT_SYMBOL_GPL")) {
+ gpl_only = true;
+ } else if (!strcmp(export, "EXPORT_SYMBOL")) {
+ gpl_only = false;
+ } else {
+ error("%s: unknown license %s. skip", symname, export);
+ continue;
+ }
+
+ mod = find_module(modname);
+ if (!mod) {
+ mod = new_module(modname, strlen(modname));
+ mod->from_dump = true;
+ }
+ s = sym_add_exported(symname, mod, gpl_only);
+ sym_set_crc(s, crc);
+ sym_update_namespace(symname, namespace);
+ }
+ free(buf);
+ return;
+fail:
+ free(buf);
+ fatal("parse error in symbol dump file\n");
+}
+
+static void write_dump(const char *fname)
+{
+ struct buffer buf = { };
+ struct module *mod;
+ struct symbol *sym;
+
+ list_for_each_entry(mod, &modules, list) {
+ if (mod->from_dump)
+ continue;
+ list_for_each_entry(sym, &mod->exported_symbols, list) {
+ buf_printf(&buf, "0x%08x\t%s\t%s\tEXPORT_SYMBOL%s\t%s\n",
+ sym->crc, sym->name, mod->name,
+ sym->is_gpl_only ? "_GPL" : "",
+ sym->namespace ?: "");
+ }
+ }
+ write_buf(&buf, fname);
+ free(buf.p);
+}
+
+static void write_namespace_deps_files(const char *fname)
+{
+ struct module *mod;
+ struct namespace_list *ns;
+ struct buffer ns_deps_buf = {};
+
+ list_for_each_entry(mod, &modules, list) {
+
+ if (mod->from_dump || list_empty(&mod->missing_namespaces))
+ continue;
+
+ buf_printf(&ns_deps_buf, "%s.ko:", mod->name);
+
+ list_for_each_entry(ns, &mod->missing_namespaces, list)
+ buf_printf(&ns_deps_buf, " %s", ns->namespace);
+
+ buf_printf(&ns_deps_buf, "\n");
+ }
+
+ write_if_changed(&ns_deps_buf, fname);
+ free(ns_deps_buf.p);
+}
+
+struct dump_list {
+ struct list_head list;
+ const char *file;
+};
+
+int main(int argc, char **argv)
+{
+ struct module *mod;
+ char *missing_namespace_deps = NULL;
+ char *dump_write = NULL, *files_source = NULL;
+ int opt;
+ LIST_HEAD(dump_lists);
+ struct dump_list *dl, *dl2;
+
+ while ((opt = getopt(argc, argv, "ei:mnT:o:awENd:")) != -1) {
+ switch (opt) {
+ case 'e':
+ external_module = true;
+ break;
+ case 'i':
+ dl = NOFAIL(malloc(sizeof(*dl)));
+ dl->file = optarg;
+ list_add_tail(&dl->list, &dump_lists);
+ break;
+ case 'm':
+ modversions = true;
+ break;
+ case 'n':
+ ignore_missing_files = true;
+ break;
+ case 'o':
+ dump_write = optarg;
+ break;
+ case 'a':
+ all_versions = true;
+ break;
+ case 'T':
+ files_source = optarg;
+ break;
+ case 'w':
+ warn_unresolved = true;
+ break;
+ case 'E':
+ sec_mismatch_warn_only = false;
+ break;
+ case 'N':
+ allow_missing_ns_imports = true;
+ break;
+ case 'd':
+ missing_namespace_deps = optarg;
+ break;
+ default:
+ exit(1);
+ }
+ }
+
+ list_for_each_entry_safe(dl, dl2, &dump_lists, list) {
+ read_dump(dl->file);
+ list_del(&dl->list);
+ free(dl);
+ }
+
+ while (optind < argc)
+ read_symbols(argv[optind++]);
+
+ if (files_source)
+ read_symbols_from_files(files_source);
+
+ list_for_each_entry(mod, &modules, list) {
+ if (mod->from_dump)
+ continue;
+
+ if (mod->is_vmlinux)
+ write_vmlinux_export_c_file(mod);
+ else
+ write_mod_c_file(mod);
+ }
+
+ if (missing_namespace_deps)
+ write_namespace_deps_files(missing_namespace_deps);
+
+ if (dump_write)
+ write_dump(dump_write);
+ if (sec_mismatch_count && !sec_mismatch_warn_only)
+ error("Section mismatches detected.\n"
+ "Set CONFIG_SECTION_MISMATCH_WARN_ONLY=y to allow them.\n");
+
+ if (nr_unresolved > MAX_UNRESOLVED_REPORTS)
+ warn("suppressed %u unresolved symbol warnings because there were too many)\n",
+ nr_unresolved - MAX_UNRESOLVED_REPORTS);
+
+ return error_occurred ? 1 : 0;
+}
Index: v6.x/create-6.1.53-host-limits-patch/linux-6.1.53-new/scripts/mod/sumversion.c
===================================================================
--- v6.x/create-6.1.53-host-limits-patch/linux-6.1.53-new/scripts/mod/sumversion.c (nonexistent)
+++ v6.x/create-6.1.53-host-limits-patch/linux-6.1.53-new/scripts/mod/sumversion.c (revision 385)
@@ -0,0 +1,410 @@
+#include <netinet/in.h>
+#ifdef __sun__
+#include <inttypes.h>
+#else
+#include <stdint.h>
+#endif
+#include <ctype.h>
+#include <errno.h>
+#include <string.h>
+#include <linux/limits.h>
+#include "modpost.h"
+
+/*
+ * Stolen form Cryptographic API.
+ *
+ * MD4 Message Digest Algorithm (RFC1320).
+ *
+ * Implementation derived from Andrew Tridgell and Steve French's
+ * CIFS MD4 implementation, and the cryptoapi implementation
+ * originally based on the public domain implementation written
+ * by Colin Plumb in 1993.
+ *
+ * Copyright (c) Andrew Tridgell 1997-1998.
+ * Modified by Steve French (sfrench@us.ibm.com) 2002
+ * Copyright (c) Cryptoapi developers.
+ * Copyright (c) 2002 David S. Miller (davem@redhat.com)
+ * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+#define MD4_DIGEST_SIZE 16
+#define MD4_HMAC_BLOCK_SIZE 64
+#define MD4_BLOCK_WORDS 16
+#define MD4_HASH_WORDS 4
+
+struct md4_ctx {
+ uint32_t hash[MD4_HASH_WORDS];
+ uint32_t block[MD4_BLOCK_WORDS];
+ uint64_t byte_count;
+};
+
+static inline uint32_t lshift(uint32_t x, unsigned int s)
+{
+ x &= 0xFFFFFFFF;
+ return ((x << s) & 0xFFFFFFFF) | (x >> (32 - s));
+}
+
+static inline uint32_t F(uint32_t x, uint32_t y, uint32_t z)
+{
+ return (x & y) | ((~x) & z);
+}
+
+static inline uint32_t G(uint32_t x, uint32_t y, uint32_t z)
+{
+ return (x & y) | (x & z) | (y & z);
+}
+
+static inline uint32_t H(uint32_t x, uint32_t y, uint32_t z)
+{
+ return x ^ y ^ z;
+}
+
+#define ROUND1(a,b,c,d,k,s) (a = lshift(a + F(b,c,d) + k, s))
+#define ROUND2(a,b,c,d,k,s) (a = lshift(a + G(b,c,d) + k + (uint32_t)0x5A827999,s))
+#define ROUND3(a,b,c,d,k,s) (a = lshift(a + H(b,c,d) + k + (uint32_t)0x6ED9EBA1,s))
+
+/* XXX: this stuff can be optimized */
+static inline void le32_to_cpu_array(uint32_t *buf, unsigned int words)
+{
+ while (words--) {
+ *buf = ntohl(*buf);
+ buf++;
+ }
+}
+
+static inline void cpu_to_le32_array(uint32_t *buf, unsigned int words)
+{
+ while (words--) {
+ *buf = htonl(*buf);
+ buf++;
+ }
+}
+
+static void md4_transform(uint32_t *hash, uint32_t const *in)
+{
+ uint32_t a, b, c, d;
+
+ a = hash[0];
+ b = hash[1];
+ c = hash[2];
+ d = hash[3];
+
+ ROUND1(a, b, c, d, in[0], 3);
+ ROUND1(d, a, b, c, in[1], 7);
+ ROUND1(c, d, a, b, in[2], 11);
+ ROUND1(b, c, d, a, in[3], 19);
+ ROUND1(a, b, c, d, in[4], 3);
+ ROUND1(d, a, b, c, in[5], 7);
+ ROUND1(c, d, a, b, in[6], 11);
+ ROUND1(b, c, d, a, in[7], 19);
+ ROUND1(a, b, c, d, in[8], 3);
+ ROUND1(d, a, b, c, in[9], 7);
+ ROUND1(c, d, a, b, in[10], 11);
+ ROUND1(b, c, d, a, in[11], 19);
+ ROUND1(a, b, c, d, in[12], 3);
+ ROUND1(d, a, b, c, in[13], 7);
+ ROUND1(c, d, a, b, in[14], 11);
+ ROUND1(b, c, d, a, in[15], 19);
+
+ ROUND2(a, b, c, d,in[ 0], 3);
+ ROUND2(d, a, b, c, in[4], 5);
+ ROUND2(c, d, a, b, in[8], 9);
+ ROUND2(b, c, d, a, in[12], 13);
+ ROUND2(a, b, c, d, in[1], 3);
+ ROUND2(d, a, b, c, in[5], 5);
+ ROUND2(c, d, a, b, in[9], 9);
+ ROUND2(b, c, d, a, in[13], 13);
+ ROUND2(a, b, c, d, in[2], 3);
+ ROUND2(d, a, b, c, in[6], 5);
+ ROUND2(c, d, a, b, in[10], 9);
+ ROUND2(b, c, d, a, in[14], 13);
+ ROUND2(a, b, c, d, in[3], 3);
+ ROUND2(d, a, b, c, in[7], 5);
+ ROUND2(c, d, a, b, in[11], 9);
+ ROUND2(b, c, d, a, in[15], 13);
+
+ ROUND3(a, b, c, d,in[ 0], 3);
+ ROUND3(d, a, b, c, in[8], 9);
+ ROUND3(c, d, a, b, in[4], 11);
+ ROUND3(b, c, d, a, in[12], 15);
+ ROUND3(a, b, c, d, in[2], 3);
+ ROUND3(d, a, b, c, in[10], 9);
+ ROUND3(c, d, a, b, in[6], 11);
+ ROUND3(b, c, d, a, in[14], 15);
+ ROUND3(a, b, c, d, in[1], 3);
+ ROUND3(d, a, b, c, in[9], 9);
+ ROUND3(c, d, a, b, in[5], 11);
+ ROUND3(b, c, d, a, in[13], 15);
+ ROUND3(a, b, c, d, in[3], 3);
+ ROUND3(d, a, b, c, in[11], 9);
+ ROUND3(c, d, a, b, in[7], 11);
+ ROUND3(b, c, d, a, in[15], 15);
+
+ hash[0] += a;
+ hash[1] += b;
+ hash[2] += c;
+ hash[3] += d;
+}
+
+static inline void md4_transform_helper(struct md4_ctx *ctx)
+{
+ le32_to_cpu_array(ctx->block, sizeof(ctx->block) / sizeof(uint32_t));
+ md4_transform(ctx->hash, ctx->block);
+}
+
+static void md4_init(struct md4_ctx *mctx)
+{
+ mctx->hash[0] = 0x67452301;
+ mctx->hash[1] = 0xefcdab89;
+ mctx->hash[2] = 0x98badcfe;
+ mctx->hash[3] = 0x10325476;
+ mctx->byte_count = 0;
+}
+
+static void md4_update(struct md4_ctx *mctx,
+ const unsigned char *data, unsigned int len)
+{
+ const uint32_t avail = sizeof(mctx->block) - (mctx->byte_count & 0x3f);
+
+ mctx->byte_count += len;
+
+ if (avail > len) {
+ memcpy((char *)mctx->block + (sizeof(mctx->block) - avail),
+ data, len);
+ return;
+ }
+
+ memcpy((char *)mctx->block + (sizeof(mctx->block) - avail),
+ data, avail);
+
+ md4_transform_helper(mctx);
+ data += avail;
+ len -= avail;
+
+ while (len >= sizeof(mctx->block)) {
+ memcpy(mctx->block, data, sizeof(mctx->block));
+ md4_transform_helper(mctx);
+ data += sizeof(mctx->block);
+ len -= sizeof(mctx->block);
+ }
+
+ memcpy(mctx->block, data, len);
+}
+
+static void md4_final_ascii(struct md4_ctx *mctx, char *out, unsigned int len)
+{
+ const unsigned int offset = mctx->byte_count & 0x3f;
+ char *p = (char *)mctx->block + offset;
+ int padding = 56 - (offset + 1);
+
+ *p++ = 0x80;
+ if (padding < 0) {
+ memset(p, 0x00, padding + sizeof (uint64_t));
+ md4_transform_helper(mctx);
+ p = (char *)mctx->block;
+ padding = 56;
+ }
+
+ memset(p, 0, padding);
+ mctx->block[14] = mctx->byte_count << 3;
+ mctx->block[15] = mctx->byte_count >> 29;
+ le32_to_cpu_array(mctx->block, (sizeof(mctx->block) -
+ sizeof(uint64_t)) / sizeof(uint32_t));
+ md4_transform(mctx->hash, mctx->block);
+ cpu_to_le32_array(mctx->hash, sizeof(mctx->hash) / sizeof(uint32_t));
+
+ snprintf(out, len, "%08X%08X%08X%08X",
+ mctx->hash[0], mctx->hash[1], mctx->hash[2], mctx->hash[3]);
+}
+
+static inline void add_char(unsigned char c, struct md4_ctx *md)
+{
+ md4_update(md, &c, 1);
+}
+
+static int parse_string(const char *file, unsigned long len,
+ struct md4_ctx *md)
+{
+ unsigned long i;
+
+ add_char(file[0], md);
+ for (i = 1; i < len; i++) {
+ add_char(file[i], md);
+ if (file[i] == '"' && file[i-1] != '\\')
+ break;
+ }
+ return i;
+}
+
+static int parse_comment(const char *file, unsigned long len)
+{
+ unsigned long i;
+
+ for (i = 2; i < len; i++) {
+ if (file[i-1] == '*' && file[i] == '/')
+ break;
+ }
+ return i;
+}
+
+/* FIXME: Handle .s files differently (eg. # starts comments) --RR */
+static int parse_file(const char *fname, struct md4_ctx *md)
+{
+ char *file;
+ unsigned long i, len;
+
+ file = read_text_file(fname);
+ len = strlen(file);
+
+ for (i = 0; i < len; i++) {
+ /* Collapse and ignore \ and CR. */
+ if (file[i] == '\\' && (i+1 < len) && file[i+1] == '\n') {
+ i++;
+ continue;
+ }
+
+ /* Ignore whitespace */
+ if (isspace(file[i]))
+ continue;
+
+ /* Handle strings as whole units */
+ if (file[i] == '"') {
+ i += parse_string(file+i, len - i, md);
+ continue;
+ }
+
+ /* Comments: ignore */
+ if (file[i] == '/' && file[i+1] == '*') {
+ i += parse_comment(file+i, len - i);
+ continue;
+ }
+
+ add_char(file[i], md);
+ }
+ free(file);
+ return 1;
+}
+/* Check whether the file is a static library or not */
+static bool is_static_library(const char *objfile)
+{
+ int len = strlen(objfile);
+
+ return objfile[len - 2] == '.' && objfile[len - 1] == 'a';
+}
+
+/* We have dir/file.o. Open dir/.file.o.cmd, look for source_ and deps_ line
+ * to figure out source files. */
+static int parse_source_files(const char *objfile, struct md4_ctx *md)
+{
+ char *cmd, *file, *line, *dir, *pos;
+ const char *base;
+ int dirlen, ret = 0, check_files = 0;
+
+ cmd = NOFAIL(malloc(strlen(objfile) + sizeof("..cmd")));
+
+ base = strrchr(objfile, '/');
+ if (base) {
+ base++;
+ dirlen = base - objfile;
+ sprintf(cmd, "%.*s.%s.cmd", dirlen, objfile, base);
+ } else {
+ dirlen = 0;
+ sprintf(cmd, ".%s.cmd", objfile);
+ }
+ dir = NOFAIL(malloc(dirlen + 1));
+ strncpy(dir, objfile, dirlen);
+ dir[dirlen] = '\0';
+
+ file = read_text_file(cmd);
+
+ pos = file;
+
+ /* Sum all files in the same dir or subdirs. */
+ while ((line = get_line(&pos))) {
+ char* p = line;
+
+ if (strncmp(line, "source_", sizeof("source_")-1) == 0) {
+ p = strrchr(line, ' ');
+ if (!p) {
+ warn("malformed line: %s\n", line);
+ goto out_file;
+ }
+ p++;
+ if (!parse_file(p, md)) {
+ warn("could not open %s: %s\n",
+ p, strerror(errno));
+ goto out_file;
+ }
+ continue;
+ }
+ if (strncmp(line, "deps_", sizeof("deps_")-1) == 0) {
+ check_files = 1;
+ continue;
+ }
+ if (!check_files)
+ continue;
+
+ /* Continue until line does not end with '\' */
+ if ( *(p + strlen(p)-1) != '\\')
+ break;
+ /* Terminate line at first space, to get rid of final ' \' */
+ while (*p) {
+ if (isspace(*p)) {
+ *p = '\0';
+ break;
+ }
+ p++;
+ }
+
+ /* Check if this file is in same dir as objfile */
+ if ((strstr(line, dir)+strlen(dir)-1) == strrchr(line, '/')) {
+ if (!parse_file(line, md)) {
+ warn("could not open %s: %s\n",
+ line, strerror(errno));
+ goto out_file;
+ }
+
+ }
+
+ }
+
+ /* Everyone parsed OK */
+ ret = 1;
+out_file:
+ free(file);
+ free(dir);
+ free(cmd);
+ return ret;
+}
+
+/* Calc and record src checksum. */
+void get_src_version(const char *modname, char sum[], unsigned sumlen)
+{
+ char *buf;
+ struct md4_ctx md;
+ char *fname;
+ char filelist[PATH_MAX + 1];
+
+ /* objects for a module are listed in the first line of *.mod file. */
+ snprintf(filelist, sizeof(filelist), "%s.mod", modname);
+
+ buf = read_text_file(filelist);
+
+ md4_init(&md);
+ while ((fname = strsep(&buf, "\n"))) {
+ if (!*fname)
+ continue;
+ if (!(is_static_library(fname)) &&
+ !parse_source_files(fname, &md))
+ goto free;
+ }
+
+ md4_final_ascii(&md, sum, sumlen);
+free:
+ free(buf);
+}
Index: v6.x/create-6.1.53-host-limits-patch/linux-6.1.53-new/tools/build/fixdep.c
===================================================================
--- v6.x/create-6.1.53-host-limits-patch/linux-6.1.53-new/tools/build/fixdep.c (nonexistent)
+++ v6.x/create-6.1.53-host-limits-patch/linux-6.1.53-new/tools/build/fixdep.c (revision 385)
@@ -0,0 +1,170 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * "Optimize" a list of dependencies as spit out by gcc -MD
+ * for the build framework.
+ *
+ * Original author:
+ * Copyright 2002 by Kai Germaschewski <kai.germaschewski@gmx.de>
+ *
+ * This code has been borrowed from kbuild's fixdep (scripts/basic/fixdep.c),
+ * Please check it for detailed explanation. This fixdep borow only the
+ * base transformation of dependecies without the CONFIG mangle.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <linux/limits.h>
+
+char *target;
+char *depfile;
+char *cmdline;
+
+static void usage(void)
+{
+ fprintf(stderr, "Usage: fixdep <depfile> <target> <cmdline>\n");
+ exit(1);
+}
+
+/*
+ * Print out the commandline prefixed with cmd_<target filename> :=
+ */
+static void print_cmdline(void)
+{
+ printf("cmd_%s := %s\n\n", target, cmdline);
+}
+
+/*
+ * Important: The below generated source_foo.o and deps_foo.o variable
+ * assignments are parsed not only by make, but also by the rather simple
+ * parser in scripts/mod/sumversion.c.
+ */
+static void parse_dep_file(void *map, size_t len)
+{
+ char *m = map;
+ char *end = m + len;
+ char *p;
+ char s[PATH_MAX];
+ int is_target, has_target = 0;
+ int saw_any_target = 0;
+ int is_first_dep = 0;
+
+ while (m < end) {
+ /* Skip any "white space" */
+ while (m < end && (*m == ' ' || *m == '\\' || *m == '\n'))
+ m++;
+ /* Find next "white space" */
+ p = m;
+ while (p < end && *p != ' ' && *p != '\\' && *p != '\n')
+ p++;
+ /* Is the token we found a target name? */
+ is_target = (*(p-1) == ':');
+ /* Don't write any target names into the dependency file */
+ if (is_target) {
+ /* The /next/ file is the first dependency */
+ is_first_dep = 1;
+ has_target = 1;
+ } else if (has_target) {
+ /* Save this token/filename */
+ memcpy(s, m, p-m);
+ s[p - m] = 0;
+
+ /*
+ * Do not list the source file as dependency,
+ * so that kbuild is not confused if a .c file
+ * is rewritten into .S or vice versa. Storing
+ * it in source_* is needed for modpost to
+ * compute srcversions.
+ */
+ if (is_first_dep) {
+ /*
+ * If processing the concatenation of
+ * multiple dependency files, only
+ * process the first target name, which
+ * will be the original source name,
+ * and ignore any other target names,
+ * which will be intermediate temporary
+ * files.
+ */
+ if (!saw_any_target) {
+ saw_any_target = 1;
+ printf("source_%s := %s\n\n",
+ target, s);
+ printf("deps_%s := \\\n",
+ target);
+ }
+ is_first_dep = 0;
+ } else
+ printf(" %s \\\n", s);
+ }
+ /*
+ * Start searching for next token immediately after the first
+ * "whitespace" character that follows this token.
+ */
+ m = p + 1;
+ }
+
+ if (!saw_any_target) {
+ fprintf(stderr, "fixdep: parse error; no targets found\n");
+ exit(1);
+ }
+
+ printf("\n%s: $(deps_%s)\n\n", target, target);
+ printf("$(deps_%s):\n", target);
+}
+
+static void print_deps(void)
+{
+ struct stat st;
+ int fd;
+ void *map;
+
+ fd = open(depfile, O_RDONLY);
+ if (fd < 0) {
+ fprintf(stderr, "fixdep: error opening depfile: ");
+ perror(depfile);
+ exit(2);
+ }
+ if (fstat(fd, &st) < 0) {
+ fprintf(stderr, "fixdep: error fstat'ing depfile: ");
+ perror(depfile);
+ exit(2);
+ }
+ if (st.st_size == 0) {
+ fprintf(stderr, "fixdep: %s is empty\n", depfile);
+ close(fd);
+ return;
+ }
+ map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+ if ((long) map == -1) {
+ perror("fixdep: mmap");
+ close(fd);
+ return;
+ }
+
+ parse_dep_file(map, st.st_size);
+
+ munmap(map, st.st_size);
+
+ close(fd);
+}
+
+int main(int argc, char **argv)
+{
+ if (argc != 4)
+ usage();
+
+ depfile = argv[1];
+ target = argv[2];
+ cmdline = argv[3];
+
+ print_cmdline();
+ print_deps();
+
+ return 0;
+}
Index: v6.x/create-6.1.53-host-limits-patch/linux-6.1.53-new/usr/gen_init_cpio.c
===================================================================
--- v6.x/create-6.1.53-host-limits-patch/linux-6.1.53-new/usr/gen_init_cpio.c (nonexistent)
+++ v6.x/create-6.1.53-host-limits-patch/linux-6.1.53-new/usr/gen_init_cpio.c (revision 385)
@@ -0,0 +1,682 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <unistd.h>
+#include <time.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <ctype.h>
+#include <linux/limits.h>
+
+/*
+ * Original work by Jeff Garzik
+ *
+ * External file lists, symlink, pipe and fifo support by Thayne Harbaugh
+ * Hard link support by Luciano Rocha
+ */
+
+#define xstr(s) #s
+#define str(s) xstr(s)
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+
+static unsigned int offset;
+static unsigned int ino = 721;
+static time_t default_mtime;
+static bool do_csum = false;
+
+struct file_handler {
+ const char *type;
+ int (*handler)(const char *line);
+};
+
+static void push_string(const char *name)
+{
+ unsigned int name_len = strlen(name) + 1;
+
+ fputs(name, stdout);
+ putchar(0);
+ offset += name_len;
+}
+
+static void push_pad (void)
+{
+ while (offset & 3) {
+ putchar(0);
+ offset++;
+ }
+}
+
+static void push_rest(const char *name)
+{
+ unsigned int name_len = strlen(name) + 1;
+ unsigned int tmp_ofs;
+
+ fputs(name, stdout);
+ putchar(0);
+ offset += name_len;
+
+ tmp_ofs = name_len + 110;
+ while (tmp_ofs & 3) {
+ putchar(0);
+ offset++;
+ tmp_ofs++;
+ }
+}
+
+static void push_hdr(const char *s)
+{
+ fputs(s, stdout);
+ offset += 110;
+}
+
+static void cpio_trailer(void)
+{
+ char s[256];
+ const char name[] = "TRAILER!!!";
+
+ sprintf(s, "%s%08X%08X%08lX%08lX%08X%08lX"
+ "%08X%08X%08X%08X%08X%08X%08X",
+ do_csum ? "070702" : "070701", /* magic */
+ 0, /* ino */
+ 0, /* mode */
+ (long) 0, /* uid */
+ (long) 0, /* gid */
+ 1, /* nlink */
+ (long) 0, /* mtime */
+ 0, /* filesize */
+ 0, /* major */
+ 0, /* minor */
+ 0, /* rmajor */
+ 0, /* rminor */
+ (unsigned)strlen(name)+1, /* namesize */
+ 0); /* chksum */
+ push_hdr(s);
+ push_rest(name);
+
+ while (offset % 512) {
+ putchar(0);
+ offset++;
+ }
+}
+
+static int cpio_mkslink(const char *name, const char *target,
+ unsigned int mode, uid_t uid, gid_t gid)
+{
+ char s[256];
+
+ if (name[0] == '/')
+ name++;
+ sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
+ "%08X%08X%08X%08X%08X%08X%08X",
+ do_csum ? "070702" : "070701", /* magic */
+ ino++, /* ino */
+ S_IFLNK | mode, /* mode */
+ (long) uid, /* uid */
+ (long) gid, /* gid */
+ 1, /* nlink */
+ (long) default_mtime, /* mtime */
+ (unsigned)strlen(target)+1, /* filesize */
+ 3, /* major */
+ 1, /* minor */
+ 0, /* rmajor */
+ 0, /* rminor */
+ (unsigned)strlen(name) + 1,/* namesize */
+ 0); /* chksum */
+ push_hdr(s);
+ push_string(name);
+ push_pad();
+ push_string(target);
+ push_pad();
+ return 0;
+}
+
+static int cpio_mkslink_line(const char *line)
+{
+ char name[PATH_MAX + 1];
+ char target[PATH_MAX + 1];
+ unsigned int mode;
+ int uid;
+ int gid;
+ int rc = -1;
+
+ if (5 != sscanf(line, "%" str(PATH_MAX) "s %" str(PATH_MAX) "s %o %d %d", name, target, &mode, &uid, &gid)) {
+ fprintf(stderr, "Unrecognized dir format '%s'", line);
+ goto fail;
+ }
+ rc = cpio_mkslink(name, target, mode, uid, gid);
+ fail:
+ return rc;
+}
+
+static int cpio_mkgeneric(const char *name, unsigned int mode,
+ uid_t uid, gid_t gid)
+{
+ char s[256];
+
+ if (name[0] == '/')
+ name++;
+ sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
+ "%08X%08X%08X%08X%08X%08X%08X",
+ do_csum ? "070702" : "070701", /* magic */
+ ino++, /* ino */
+ mode, /* mode */
+ (long) uid, /* uid */
+ (long) gid, /* gid */
+ 2, /* nlink */
+ (long) default_mtime, /* mtime */
+ 0, /* filesize */
+ 3, /* major */
+ 1, /* minor */
+ 0, /* rmajor */
+ 0, /* rminor */
+ (unsigned)strlen(name) + 1,/* namesize */
+ 0); /* chksum */
+ push_hdr(s);
+ push_rest(name);
+ return 0;
+}
+
+enum generic_types {
+ GT_DIR,
+ GT_PIPE,
+ GT_SOCK
+};
+
+struct generic_type {
+ const char *type;
+ mode_t mode;
+};
+
+static const struct generic_type generic_type_table[] = {
+ [GT_DIR] = {
+ .type = "dir",
+ .mode = S_IFDIR
+ },
+ [GT_PIPE] = {
+ .type = "pipe",
+ .mode = S_IFIFO
+ },
+ [GT_SOCK] = {
+ .type = "sock",
+ .mode = S_IFSOCK
+ }
+};
+
+static int cpio_mkgeneric_line(const char *line, enum generic_types gt)
+{
+ char name[PATH_MAX + 1];
+ unsigned int mode;
+ int uid;
+ int gid;
+ int rc = -1;
+
+ if (4 != sscanf(line, "%" str(PATH_MAX) "s %o %d %d", name, &mode, &uid, &gid)) {
+ fprintf(stderr, "Unrecognized %s format '%s'",
+ line, generic_type_table[gt].type);
+ goto fail;
+ }
+ mode |= generic_type_table[gt].mode;
+ rc = cpio_mkgeneric(name, mode, uid, gid);
+ fail:
+ return rc;
+}
+
+static int cpio_mkdir_line(const char *line)
+{
+ return cpio_mkgeneric_line(line, GT_DIR);
+}
+
+static int cpio_mkpipe_line(const char *line)
+{
+ return cpio_mkgeneric_line(line, GT_PIPE);
+}
+
+static int cpio_mksock_line(const char *line)
+{
+ return cpio_mkgeneric_line(line, GT_SOCK);
+}
+
+static int cpio_mknod(const char *name, unsigned int mode,
+ uid_t uid, gid_t gid, char dev_type,
+ unsigned int maj, unsigned int min)
+{
+ char s[256];
+
+ if (dev_type == 'b')
+ mode |= S_IFBLK;
+ else
+ mode |= S_IFCHR;
+
+ if (name[0] == '/')
+ name++;
+ sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
+ "%08X%08X%08X%08X%08X%08X%08X",
+ do_csum ? "070702" : "070701", /* magic */
+ ino++, /* ino */
+ mode, /* mode */
+ (long) uid, /* uid */
+ (long) gid, /* gid */
+ 1, /* nlink */
+ (long) default_mtime, /* mtime */
+ 0, /* filesize */
+ 3, /* major */
+ 1, /* minor */
+ maj, /* rmajor */
+ min, /* rminor */
+ (unsigned)strlen(name) + 1,/* namesize */
+ 0); /* chksum */
+ push_hdr(s);
+ push_rest(name);
+ return 0;
+}
+
+static int cpio_mknod_line(const char *line)
+{
+ char name[PATH_MAX + 1];
+ unsigned int mode;
+ int uid;
+ int gid;
+ char dev_type;
+ unsigned int maj;
+ unsigned int min;
+ int rc = -1;
+
+ if (7 != sscanf(line, "%" str(PATH_MAX) "s %o %d %d %c %u %u",
+ name, &mode, &uid, &gid, &dev_type, &maj, &min)) {
+ fprintf(stderr, "Unrecognized nod format '%s'", line);
+ goto fail;
+ }
+ rc = cpio_mknod(name, mode, uid, gid, dev_type, maj, min);
+ fail:
+ return rc;
+}
+
+static int cpio_mkfile_csum(int fd, unsigned long size, uint32_t *csum)
+{
+ while (size) {
+ unsigned char filebuf[65536];
+ ssize_t this_read;
+ size_t i, this_size = MIN(size, sizeof(filebuf));
+
+ this_read = read(fd, filebuf, this_size);
+ if (this_read <= 0 || this_read > this_size)
+ return -1;
+
+ for (i = 0; i < this_read; i++)
+ *csum += filebuf[i];
+
+ size -= this_read;
+ }
+ /* seek back to the start for data segment I/O */
+ if (lseek(fd, 0, SEEK_SET) < 0)
+ return -1;
+
+ return 0;
+}
+
+static int cpio_mkfile(const char *name, const char *location,
+ unsigned int mode, uid_t uid, gid_t gid,
+ unsigned int nlinks)
+{
+ char s[256];
+ struct stat buf;
+ unsigned long size;
+ int file;
+ int retval;
+ int rc = -1;
+ int namesize;
+ unsigned int i;
+ uint32_t csum = 0;
+
+ mode |= S_IFREG;
+
+ file = open (location, O_RDONLY);
+ if (file < 0) {
+ fprintf (stderr, "File %s could not be opened for reading\n", location);
+ goto error;
+ }
+
+ retval = fstat(file, &buf);
+ if (retval) {
+ fprintf(stderr, "File %s could not be stat()'ed\n", location);
+ goto error;
+ }
+
+ if (buf.st_mtime > 0xffffffff) {
+ fprintf(stderr, "%s: Timestamp exceeds maximum cpio timestamp, clipping.\n",
+ location);
+ buf.st_mtime = 0xffffffff;
+ }
+
+ if (buf.st_size > 0xffffffff) {
+ fprintf(stderr, "%s: Size exceeds maximum cpio file size\n",
+ location);
+ goto error;
+ }
+
+ if (do_csum && cpio_mkfile_csum(file, buf.st_size, &csum) < 0) {
+ fprintf(stderr, "Failed to checksum file %s\n", location);
+ goto error;
+ }
+
+ size = 0;
+ for (i = 1; i <= nlinks; i++) {
+ /* data goes on last link */
+ if (i == nlinks)
+ size = buf.st_size;
+
+ if (name[0] == '/')
+ name++;
+ namesize = strlen(name) + 1;
+ sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
+ "%08lX%08X%08X%08X%08X%08X%08X",
+ do_csum ? "070702" : "070701", /* magic */
+ ino, /* ino */
+ mode, /* mode */
+ (long) uid, /* uid */
+ (long) gid, /* gid */
+ nlinks, /* nlink */
+ (long) buf.st_mtime, /* mtime */
+ size, /* filesize */
+ 3, /* major */
+ 1, /* minor */
+ 0, /* rmajor */
+ 0, /* rminor */
+ namesize, /* namesize */
+ size ? csum : 0); /* chksum */
+ push_hdr(s);
+ push_string(name);
+ push_pad();
+
+ while (size) {
+ unsigned char filebuf[65536];
+ ssize_t this_read;
+ size_t this_size = MIN(size, sizeof(filebuf));
+
+ this_read = read(file, filebuf, this_size);
+ if (this_read <= 0 || this_read > this_size) {
+ fprintf(stderr, "Can not read %s file\n", location);
+ goto error;
+ }
+
+ if (fwrite(filebuf, this_read, 1, stdout) != 1) {
+ fprintf(stderr, "writing filebuf failed\n");
+ goto error;
+ }
+ offset += this_read;
+ size -= this_read;
+ }
+ push_pad();
+
+ name += namesize;
+ }
+ ino++;
+ rc = 0;
+
+error:
+ if (file >= 0)
+ close(file);
+ return rc;
+}
+
+static char *cpio_replace_env(char *new_location)
+{
+ char expanded[PATH_MAX + 1];
+ char *start, *end, *var;
+
+ while ((start = strstr(new_location, "${")) &&
+ (end = strchr(start + 2, '}'))) {
+ *start = *end = 0;
+ var = getenv(start + 2);
+ snprintf(expanded, sizeof expanded, "%s%s%s",
+ new_location, var ? var : "", end + 1);
+ strcpy(new_location, expanded);
+ }
+
+ return new_location;
+}
+
+static int cpio_mkfile_line(const char *line)
+{
+ char name[PATH_MAX + 1];
+ char *dname = NULL; /* malloc'ed buffer for hard links */
+ char location[PATH_MAX + 1];
+ unsigned int mode;
+ int uid;
+ int gid;
+ int nlinks = 1;
+ int end = 0, dname_len = 0;
+ int rc = -1;
+
+ if (5 > sscanf(line, "%" str(PATH_MAX) "s %" str(PATH_MAX)
+ "s %o %d %d %n",
+ name, location, &mode, &uid, &gid, &end)) {
+ fprintf(stderr, "Unrecognized file format '%s'", line);
+ goto fail;
+ }
+ if (end && isgraph(line[end])) {
+ int len;
+ int nend;
+
+ dname = malloc(strlen(line));
+ if (!dname) {
+ fprintf (stderr, "out of memory (%d)\n", dname_len);
+ goto fail;
+ }
+
+ dname_len = strlen(name) + 1;
+ memcpy(dname, name, dname_len);
+
+ do {
+ nend = 0;
+ if (sscanf(line + end, "%" str(PATH_MAX) "s %n",
+ name, &nend) < 1)
+ break;
+ len = strlen(name) + 1;
+ memcpy(dname + dname_len, name, len);
+ dname_len += len;
+ nlinks++;
+ end += nend;
+ } while (isgraph(line[end]));
+ } else {
+ dname = name;
+ }
+ rc = cpio_mkfile(dname, cpio_replace_env(location),
+ mode, uid, gid, nlinks);
+ fail:
+ if (dname_len) free(dname);
+ return rc;
+}
+
+static void usage(const char *prog)
+{
+ fprintf(stderr, "Usage:\n"
+ "\t%s [-t <timestamp>] [-c] <cpio_list>\n"
+ "\n"
+ "<cpio_list> is a file containing newline separated entries that\n"
+ "describe the files to be included in the initramfs archive:\n"
+ "\n"
+ "# a comment\n"
+ "file <name> <location> <mode> <uid> <gid> [<hard links>]\n"
+ "dir <name> <mode> <uid> <gid>\n"
+ "nod <name> <mode> <uid> <gid> <dev_type> <maj> <min>\n"
+ "slink <name> <target> <mode> <uid> <gid>\n"
+ "pipe <name> <mode> <uid> <gid>\n"
+ "sock <name> <mode> <uid> <gid>\n"
+ "\n"
+ "<name> name of the file/dir/nod/etc in the archive\n"
+ "<location> location of the file in the current filesystem\n"
+ " expands shell variables quoted with ${}\n"
+ "<target> link target\n"
+ "<mode> mode/permissions of the file\n"
+ "<uid> user id (0=root)\n"
+ "<gid> group id (0=root)\n"
+ "<dev_type> device type (b=block, c=character)\n"
+ "<maj> major number of nod\n"
+ "<min> minor number of nod\n"
+ "<hard links> space separated list of other links to file\n"
+ "\n"
+ "example:\n"
+ "# A simple initramfs\n"
+ "dir /dev 0755 0 0\n"
+ "nod /dev/console 0600 0 0 c 5 1\n"
+ "dir /root 0700 0 0\n"
+ "dir /sbin 0755 0 0\n"
+ "file /sbin/kinit /usr/src/klibc/kinit/kinit 0755 0 0\n"
+ "\n"
+ "<timestamp> is time in seconds since Epoch that will be used\n"
+ "as mtime for symlinks, special files and directories. The default\n"
+ "is to use the current time for these entries.\n"
+ "-c: calculate and store 32-bit checksums for file data.\n",
+ prog);
+}
+
+static const struct file_handler file_handler_table[] = {
+ {
+ .type = "file",
+ .handler = cpio_mkfile_line,
+ }, {
+ .type = "nod",
+ .handler = cpio_mknod_line,
+ }, {
+ .type = "dir",
+ .handler = cpio_mkdir_line,
+ }, {
+ .type = "slink",
+ .handler = cpio_mkslink_line,
+ }, {
+ .type = "pipe",
+ .handler = cpio_mkpipe_line,
+ }, {
+ .type = "sock",
+ .handler = cpio_mksock_line,
+ }, {
+ .type = NULL,
+ .handler = NULL,
+ }
+};
+
+#define LINE_SIZE (2 * PATH_MAX + 50)
+
+int main (int argc, char *argv[])
+{
+ FILE *cpio_list;
+ char line[LINE_SIZE];
+ char *args, *type;
+ int ec = 0;
+ int line_nr = 0;
+ const char *filename;
+
+ default_mtime = time(NULL);
+ while (1) {
+ int opt = getopt(argc, argv, "t:ch");
+ char *invalid;
+
+ if (opt == -1)
+ break;
+ switch (opt) {
+ case 't':
+ default_mtime = strtol(optarg, &invalid, 10);
+ if (!*optarg || *invalid) {
+ fprintf(stderr, "Invalid timestamp: %s\n",
+ optarg);
+ usage(argv[0]);
+ exit(1);
+ }
+ break;
+ case 'c':
+ do_csum = true;
+ break;
+ case 'h':
+ case '?':
+ usage(argv[0]);
+ exit(opt == 'h' ? 0 : 1);
+ }
+ }
+
+ /*
+ * Timestamps after 2106-02-07 06:28:15 UTC have an ascii hex time_t
+ * representation that exceeds 8 chars and breaks the cpio header
+ * specification.
+ */
+ if (default_mtime > 0xffffffff) {
+ fprintf(stderr, "ERROR: Timestamp too large for cpio format\n");
+ exit(1);
+ }
+
+ if (argc - optind != 1) {
+ usage(argv[0]);
+ exit(1);
+ }
+ filename = argv[optind];
+ if (!strcmp(filename, "-"))
+ cpio_list = stdin;
+ else if (!(cpio_list = fopen(filename, "r"))) {
+ fprintf(stderr, "ERROR: unable to open '%s': %s\n\n",
+ filename, strerror(errno));
+ usage(argv[0]);
+ exit(1);
+ }
+
+ while (fgets(line, LINE_SIZE, cpio_list)) {
+ int type_idx;
+ size_t slen = strlen(line);
+
+ line_nr++;
+
+ if ('#' == *line) {
+ /* comment - skip to next line */
+ continue;
+ }
+
+ if (! (type = strtok(line, " \t"))) {
+ fprintf(stderr,
+ "ERROR: incorrect format, could not locate file type line %d: '%s'\n",
+ line_nr, line);
+ ec = -1;
+ break;
+ }
+
+ if ('\n' == *type) {
+ /* a blank line */
+ continue;
+ }
+
+ if (slen == strlen(type)) {
+ /* must be an empty line */
+ continue;
+ }
+
+ if (! (args = strtok(NULL, "\n"))) {
+ fprintf(stderr,
+ "ERROR: incorrect format, newline required line %d: '%s'\n",
+ line_nr, line);
+ ec = -1;
+ }
+
+ for (type_idx = 0; file_handler_table[type_idx].type; type_idx++) {
+ int rc;
+ if (! strcmp(line, file_handler_table[type_idx].type)) {
+ if ((rc = file_handler_table[type_idx].handler(args))) {
+ ec = rc;
+ fprintf(stderr, " line %d\n", line_nr);
+ }
+ break;
+ }
+ }
+
+ if (NULL == file_handler_table[type_idx].type) {
+ fprintf(stderr, "unknown file type line %d: '%s'\n",
+ line_nr, line);
+ }
+ }
+ if (ec == 0)
+ cpio_trailer();
+
+ exit(ec);
+}
Index: v6.x/create-6.1.53-leez-p710-spi-patch/create.patch.sh
===================================================================
--- v6.x/create-6.1.53-leez-p710-spi-patch/create.patch.sh (nonexistent)
+++ v6.x/create-6.1.53-leez-p710-spi-patch/create.patch.sh (revision 385)
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+VERSION=6.1.53
+
+tar --files-from=file.list -xJvf ../linux-$VERSION.tar.xz
+mv linux-$VERSION linux-$VERSION-orig
+
+cp -rf ./linux-$VERSION-new ./linux-$VERSION
+
+diff --unified -Nr linux-$VERSION-orig linux-$VERSION > linux-$VERSION-leez-p710-spi.patch
+
+mv linux-$VERSION-leez-p710-spi.patch ../patches
+
+rm -rf ./linux-$VERSION
+rm -rf ./linux-$VERSION-orig
Property changes on: v6.x/create-6.1.53-leez-p710-spi-patch/create.patch.sh
___________________________________________________________________
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: v6.x/create-6.1.53-leez-p710-spi-patch/file.list
===================================================================
--- v6.x/create-6.1.53-leez-p710-spi-patch/file.list (nonexistent)
+++ v6.x/create-6.1.53-leez-p710-spi-patch/file.list (revision 385)
@@ -0,0 +1 @@
+linux-6.1.53/arch/arm64/boot/dts/rockchip/rk3399-leez-p710.dts
Index: v6.x/create-6.1.53-leez-p710-spi-patch/linux-6.1.53-new/arch/arm64/boot/dts/rockchip/rk3399-leez-p710.dts
===================================================================
--- v6.x/create-6.1.53-leez-p710-spi-patch/linux-6.1.53-new/arch/arm64/boot/dts/rockchip/rk3399-leez-p710.dts (nonexistent)
+++ v6.x/create-6.1.53-leez-p710-spi-patch/linux-6.1.53-new/arch/arm64/boot/dts/rockchip/rk3399-leez-p710.dts (revision 385)
@@ -0,0 +1,674 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2019 Andy Yan <andy.yan@gmail.com>
+ */
+
+/dts-v1/;
+#include <dt-bindings/input/linux-event-codes.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/pwm/pwm.h>
+#include "rk3399.dtsi"
+#include "rk3399-opp.dtsi"
+
+/ {
+ model = "Leez RK3399 P710";
+ compatible = "leez,p710", "rockchip,rk3399";
+
+ aliases {
+ mmc0 = &sdio0;
+ mmc1 = &sdmmc;
+ mmc2 = &sdhci;
+ };
+
+ chosen {
+ stdout-path = "serial2:1500000n8";
+ };
+
+ clkin_gmac: external-gmac-clock {
+ compatible = "fixed-clock";
+ clock-frequency = <125000000>;
+ clock-output-names = "clkin_gmac";
+ #clock-cells = <0>;
+ };
+
+ sdio_pwrseq: sdio-pwrseq {
+ compatible = "mmc-pwrseq-simple";
+ clocks = <&rk808 1>;
+ clock-names = "ext_clock";
+ pinctrl-names = "default";
+ pinctrl-0 = <&wifi_reg_on_h>;
+ reset-gpios = <&gpio0 RK_PB2 GPIO_ACTIVE_LOW>;
+ };
+
+ dc5v_adp: dc5v-adp {
+ compatible = "regulator-fixed";
+ regulator-name = "dc5v_adapter";
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ };
+
+ vcc3v3_lan: vcc3v3-lan {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc3v3_lan";
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ vin-supply = <&vcc3v3_sys>;
+ };
+
+ vcc3v3_sys: vcc3v3-sys {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc3v3_sys";
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ vin-supply = <&vcc5v0_sys>;
+ };
+
+ vcc5v0_host0: vcc5v0_host1: vcc5v0-host {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc5v0_host";
+ regulator-boot-on;
+ regulator-always-on;
+ regulator-min-microvolt = <5500000>;
+ regulator-max-microvolt = <5500000>;
+ vin-supply = <&vcc5v0_sys>;
+ };
+
+ vcc5v0_host3: vcc5v0-host3 {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc5v0_host3";
+ enable-active-high;
+ gpio = <&gpio2 RK_PA2 GPIO_ACTIVE_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&vcc5v0_host3_en>;
+ regulator-always-on;
+ vin-supply = <&vcc5v0_sys>;
+ };
+
+ vcc5v0_sys: vcc5v0-sys {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc5v0_sys";
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ vin-supply = <&dc5v_adp>;
+ };
+
+ vdd_log: vdd-log {
+ compatible = "pwm-regulator";
+ pwms = <&pwm2 0 25000 1>;
+ pwm-supply = <&vcc5v0_sys>;
+ regulator-name = "vdd_log";
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <1400000>;
+ };
+};
+
+&cpu_l0 {
+ cpu-supply = <&vdd_cpu_l>;
+};
+
+&cpu_l1 {
+ cpu-supply = <&vdd_cpu_l>;
+};
+
+&cpu_l2 {
+ cpu-supply = <&vdd_cpu_l>;
+};
+
+&cpu_l3 {
+ cpu-supply = <&vdd_cpu_l>;
+};
+
+&cpu_b0 {
+ cpu-supply = <&vdd_cpu_b>;
+};
+
+&cpu_b1 {
+ cpu-supply = <&vdd_cpu_b>;
+};
+
+&emmc_phy {
+ status = "okay";
+};
+
+&gmac {
+ assigned-clocks = <&cru SCLK_RMII_SRC>;
+ assigned-clock-parents = <&clkin_gmac>;
+ clock_in_out = "input";
+ phy-supply = <&vcc3v3_lan>;
+ phy-mode = "rgmii";
+ pinctrl-names = "default";
+ pinctrl-0 = <&rgmii_pins>;
+ snps,reset-gpio = <&gpio3 RK_PB7 GPIO_ACTIVE_LOW>;
+ snps,reset-active-low;
+ snps,reset-delays-us = <0 10000 50000>;
+ tx_delay = <0x28>;
+ rx_delay = <0x11>;
+ status = "okay";
+};
+
+&gpu {
+ mali-supply = <&vdd_gpu>;
+ status = "okay";
+};
+
+&hdmi {
+ ddc-i2c-bus = <&i2c7>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&hdmi_cec>;
+ status = "okay";
+};
+
+&hdmi_sound {
+ status = "okay";
+};
+
+&i2c0 {
+ clock-frequency = <400000>;
+ i2c-scl-rising-time-ns = <168>;
+ i2c-scl-falling-time-ns = <4>;
+ status = "okay";
+
+ rk808: pmic@1b {
+ compatible = "rockchip,rk808";
+ reg = <0x1b>;
+ interrupt-parent = <&gpio1>;
+ interrupts = <21 IRQ_TYPE_LEVEL_LOW>;
+ #clock-cells = <1>;
+ clock-output-names = "xin32k", "rk808-clkout2";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pmic_int_l>;
+ rockchip,system-power-controller;
+ wakeup-source;
+
+ vcc1-supply = <&vcc5v0_sys>;
+ vcc2-supply = <&vcc5v0_sys>;
+ vcc3-supply = <&vcc5v0_sys>;
+ vcc4-supply = <&vcc5v0_sys>;
+ vcc6-supply = <&vcc5v0_sys>;
+ vcc7-supply = <&vcc5v0_sys>;
+ vcc8-supply = <&vcc3v3_sys>;
+ vcc9-supply = <&vcc5v0_sys>;
+ vcc10-supply = <&vcc5v0_sys>;
+ vcc11-supply = <&vcc5v0_sys>;
+ vcc12-supply = <&vcc3v3_sys>;
+ vddio-supply = <&vcc_1v8>;
+
+ regulators {
+ vdd_center: DCDC_REG1 {
+ regulator-name = "vdd_center";
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <750000>;
+ regulator-max-microvolt = <1350000>;
+ regulator-ramp-delay = <6001>;
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ };
+ };
+
+ vdd_cpu_l: DCDC_REG2 {
+ regulator-name = "vdd_cpu_l";
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <750000>;
+ regulator-max-microvolt = <1350000>;
+ regulator-ramp-delay = <6001>;
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ };
+ };
+
+ vcc_ddr: DCDC_REG3 {
+ regulator-name = "vcc_ddr";
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ };
+ };
+
+ vcc_1v8: DCDC_REG4 {
+ regulator-name = "vcc_1v8";
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ regulator-suspend-microvolt = <1800000>;
+ };
+ };
+
+ vcc1v8_dvp: LDO_REG1 {
+ regulator-name = "vcc1v8_dvp";
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ };
+ };
+
+ vcc1v8_hdmi: LDO_REG2 {
+ regulator-name = "vcc1v8_hdmi";
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ };
+ };
+
+ vcca_1v8: LDO_REG3 {
+ regulator-name = "vcca_1v8";
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ regulator-suspend-microvolt = <1800000>;
+ };
+ };
+
+ vccio_sd: LDO_REG4 {
+ regulator-name = "vccio_sd";
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ regulator-suspend-microvolt = <3000000>;
+ };
+ };
+
+ vcca3v0_codec: LDO_REG5 {
+ regulator-name = "vcca3v0_codec";
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ };
+ };
+
+ vcc_1v5: LDO_REG6 {
+ regulator-name = "vcc_1v5";
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <1500000>;
+ regulator-max-microvolt = <1500000>;
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ regulator-suspend-microvolt = <1500000>;
+ };
+ };
+
+ vcc0v9_hdmi: LDO_REG7 {
+ regulator-name = "vcc0v9_hdmi";
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <900000>;
+ regulator-max-microvolt = <900000>;
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ };
+ };
+
+ vcc_3v0: LDO_REG8 {
+ regulator-name = "vcc_3v0";
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ regulator-suspend-microvolt = <3000000>;
+ };
+ };
+ };
+ };
+
+ vdd_cpu_b: regulator@40 {
+ compatible = "silergy,syr827";
+ reg = <0x40>;
+ fcs,suspend-voltage-selector = <1>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&vsel1_pin>;
+ regulator-name = "vdd_cpu_b";
+ regulator-min-microvolt = <712500>;
+ regulator-max-microvolt = <1500000>;
+ regulator-ramp-delay = <1000>;
+ regulator-always-on;
+ regulator-boot-on;
+ vin-supply = <&vcc5v0_sys>;
+
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ };
+ };
+
+ vdd_gpu: regulator@41 {
+ compatible = "silergy,syr828";
+ reg = <0x41>;
+ fcs,suspend-voltage-selector = <1>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&vsel2_pin>;
+ regulator-name = "vdd_gpu";
+ regulator-min-microvolt = <712500>;
+ regulator-max-microvolt = <1500000>;
+ regulator-ramp-delay = <1000>;
+ regulator-always-on;
+ regulator-boot-on;
+ vin-supply = <&vcc5v0_sys>;
+
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ };
+ };
+};
+
+&i2c1 {
+ i2c-scl-rising-time-ns = <300>;
+ i2c-scl-falling-time-ns = <15>;
+ status = "okay";
+};
+
+&i2c3 {
+ i2c-scl-rising-time-ns = <450>;
+ i2c-scl-falling-time-ns = <15>;
+ status = "okay";
+};
+
+&i2c4 {
+ i2c-scl-rising-time-ns = <600>;
+ i2c-scl-falling-time-ns = <20>;
+ status = "okay";
+};
+
+&i2c7 {
+ status = "okay";
+};
+
+&i2s0 {
+ rockchip,playback-channels = <8>;
+ rockchip,capture-channels = <8>;
+ status = "okay";
+};
+
+&i2s1 {
+ rockchip,playback-channels = <2>;
+ rockchip,capture-channels = <2>;
+ status = "okay";
+};
+
+&i2s2 {
+ status = "okay";
+};
+
+&io_domains {
+ status = "okay";
+
+ bt656-supply = <&vcc1v8_dvp>;
+ audio-supply = <&vcc_1v8>;
+ sdmmc-supply = <&vccio_sd>;
+ gpio1830-supply = <&vcc_3v0>;
+};
+
+&pmu_io_domains {
+ status = "okay";
+ pmu1830-supply = <&vcc_3v0>;
+};
+
+&pinctrl {
+ bt {
+ bt_reg_on_h: bt-reg-on-h {
+ rockchip,pins = <0 RK_PB1 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+
+ bt_host_wake_l: bt-host-wake-l {
+ rockchip,pins = <0 RK_PA4 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+
+ bt_wake_l: bt-wake-l {
+ rockchip,pins = <2 RK_PD2 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ };
+
+ pmic {
+ pmic_int_l: pmic-int-l {
+ rockchip,pins = <1 RK_PC5 RK_FUNC_GPIO &pcfg_pull_up>;
+ };
+
+ vsel1_pin: vsel1-pin {
+ rockchip,pins = <1 RK_PC1 RK_FUNC_GPIO &pcfg_pull_down>;
+ };
+
+ vsel2_pin: vsel2-pin {
+ rockchip,pins = <1 RK_PB6 RK_FUNC_GPIO &pcfg_pull_down>;
+ };
+ };
+
+ usb2 {
+ vcc5v0_host3_en: vcc5v0-host3-en {
+ rockchip,pins = <2 RK_PA2 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ };
+
+ wifi {
+ wifi_reg_on_h: wifi-reg-on-h {
+ rockchip,pins =
+ <0 RK_PB2 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+
+ wifi_host_wake_l: wifi-host-wake-l {
+ rockchip,pins = <0 RK_PA3 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ };
+};
+
+&pwm2 {
+ status = "okay";
+};
+
+&saradc {
+ status = "okay";
+
+ vref-supply = <&vcc_1v8>;
+};
+
+&sdio0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ bus-width = <4>;
+ clock-frequency = <50000000>;
+ cap-sdio-irq;
+ cap-sd-highspeed;
+ keep-power-in-suspend;
+ mmc-pwrseq = <&sdio_pwrseq>;
+ non-removable;
+ pinctrl-names = "default";
+ pinctrl-0 = <&sdio0_bus4 &sdio0_cmd &sdio0_clk>;
+ sd-uhs-sdr104;
+ status = "okay";
+
+ brcmf: wifi@1 {
+ compatible = "brcm,bcm4329-fmac";
+ reg = <1>;
+ interrupt-parent = <&gpio0>;
+ interrupts = <RK_PA3 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "host-wake";
+ pinctrl-names = "default";
+ pinctrl-0 = <&wifi_host_wake_l>;
+ };
+};
+
+&sdhci {
+ bus-width = <8>;
+ mmc-hs400-1_8v;
+ mmc-hs400-enhanced-strobe;
+ non-removable;
+ status = "okay";
+};
+
+&sdmmc {
+ bus-width = <4>;
+ cap-mmc-highspeed;
+ cap-sd-highspeed;
+ cd-gpios = <&gpio0 RK_PA7 GPIO_ACTIVE_LOW>;
+ disable-wp;
+ max-frequency = <150000000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&sdmmc_clk &sdmmc_cd &sdmmc_cmd &sdmmc_bus4>;
+ status = "okay";
+};
+
+&tcphy0 {
+ status = "okay";
+};
+
+&tcphy1 {
+ status = "okay";
+};
+
+&tsadc {
+ status = "okay";
+
+ /* tshut mode 0:CRU 1:GPIO */
+ rockchip,hw-tshut-mode = <1>;
+ /* tshut polarity 0:LOW 1:HIGH */
+ rockchip,hw-tshut-polarity = <1>;
+};
+
+&u2phy0 {
+ status = "okay";
+
+ u2phy0_otg: otg-port {
+ status = "okay";
+ };
+
+ u2phy0_host: host-port {
+ phy-supply = <&vcc5v0_host0>;
+ status = "okay";
+ };
+};
+
+&u2phy1 {
+ status = "okay";
+
+ u2phy1_otg: otg-port {
+ status = "okay";
+ };
+
+ u2phy1_host: host-port {
+ phy-supply = <&vcc5v0_host1>;
+ status = "okay";
+ };
+};
+
+&uart0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_xfer &uart0_cts &uart0_rts>;
+ status = "okay";
+
+ bluetooth {
+ compatible = "brcm,bcm43438-bt";
+ clocks = <&rk808 1>;
+ clock-names = "ext_clock";
+ device-wakeup-gpios = <&gpio2 RK_PD2 GPIO_ACTIVE_HIGH>;
+ host-wakeup-gpios = <&gpio0 RK_PA4 GPIO_ACTIVE_HIGH>;
+ shutdown-gpios = <&gpio0 RK_PB1 GPIO_ACTIVE_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&bt_host_wake_l &bt_wake_l &bt_reg_on_h>;
+ };
+};
+
+&uart2 {
+ status = "okay";
+};
+
+&usb_host0_ehci {
+ status = "okay";
+};
+
+&usb_host0_ohci {
+ status = "okay";
+};
+
+&usb_host1_ehci {
+ status = "okay";
+};
+
+&usb_host1_ohci {
+ status = "okay";
+};
+
+&usbdrd3_0 {
+ status = "okay";
+};
+
+&usbdrd_dwc3_0 {
+ status = "okay";
+ dr_mode = "otg";
+};
+
+&usbdrd3_1 {
+ status = "okay";
+};
+
+&usbdrd_dwc3_1 {
+ status = "okay";
+ dr_mode = "host";
+};
+
+&vopb {
+ status = "okay";
+};
+
+&vopb_mmu {
+ status = "okay";
+};
+
+&vopl {
+ status = "okay";
+};
+
+&vopl_mmu {
+ status = "okay";
+};
+
+&spi1 {
+ status = "okay";
+
+ spiflash: flash@0 {
+ compatible = "winbond,w25q256", "jedec,spi-nor";
+ reg = <0>;
+ /* May run faster once verified: */
+ spi-max-frequency = <1000000>; // 1MHz
+
+ partitions {
+ compatible = "fixed-partitions";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ spi-flash@0 {
+ reg = <0x0 0x2000000>; // 32MiB (Full flash)
+ label = "spi-flash";
+ };
+ };
+ };
+};
Index: v6.x/create-6.1.53-repka-pi3-patch/create.patch.sh
===================================================================
--- v6.x/create-6.1.53-repka-pi3-patch/create.patch.sh (nonexistent)
+++ v6.x/create-6.1.53-repka-pi3-patch/create.patch.sh (revision 385)
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+VERSION=6.1.53
+
+tar --files-from=file.list -xJvf ../linux-$VERSION.tar.xz
+mv linux-$VERSION linux-$VERSION-orig
+
+cp -rf ./linux-$VERSION-new ./linux-$VERSION
+
+diff --unified -Nr linux-$VERSION-orig linux-$VERSION > linux-$VERSION-repka-pi3.patch
+
+mv linux-$VERSION-repka-pi3.patch ../patches
+
+rm -rf ./linux-$VERSION
+rm -rf ./linux-$VERSION-orig
Property changes on: v6.x/create-6.1.53-repka-pi3-patch/create.patch.sh
___________________________________________________________________
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: v6.x/create-6.1.53-repka-pi3-patch/file.list
===================================================================
--- v6.x/create-6.1.53-repka-pi3-patch/file.list (nonexistent)
+++ v6.x/create-6.1.53-repka-pi3-patch/file.list (revision 385)
@@ -0,0 +1,4 @@
+linux-6.1.53/arch/arm64/boot/dts/allwinner/Makefile
+linux-6.1.53/arch/arm64/boot/dts/allwinner/sun50i-h5-cpu-opp.dtsi
+linux-6.1.53/arch/arm64/boot/dts/allwinner/sun50i-h5.dtsi
+linux-6.1.53/arch/arm/boot/dts/sunxi-h3-h5.dtsi
\ No newline at end of file
Index: v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm/boot/dts/sunxi-h3-h5.dtsi
===================================================================
--- v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm/boot/dts/sunxi-h3-h5.dtsi (nonexistent)
+++ v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm/boot/dts/sunxi-h3-h5.dtsi (revision 385)
@@ -0,0 +1,996 @@
+/*
+ * Copyright (C) 2015 Jens Kuske <jenskuske@gmail.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <dt-bindings/clock/sun6i-rtc.h>
+#include <dt-bindings/clock/sun8i-de2.h>
+#include <dt-bindings/clock/sun8i-h3-ccu.h>
+#include <dt-bindings/clock/sun8i-r-ccu.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/reset/sun8i-de2.h>
+#include <dt-bindings/reset/sun8i-h3-ccu.h>
+#include <dt-bindings/reset/sun8i-r-ccu.h>
+
+/ {
+ interrupt-parent = <&gic>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ chosen {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ framebuffer-hdmi {
+ compatible = "allwinner,simple-framebuffer",
+ "simple-framebuffer";
+ allwinner,pipeline = "mixer0-lcd0-hdmi";
+ clocks = <&display_clocks CLK_MIXER0>,
+ <&ccu CLK_TCON0>, <&ccu CLK_HDMI>;
+ status = "disabled";
+ };
+
+ framebuffer-tve {
+ compatible = "allwinner,simple-framebuffer",
+ "simple-framebuffer";
+ allwinner,pipeline = "mixer1-lcd1-tve";
+ clocks = <&display_clocks CLK_MIXER1>,
+ <&ccu CLK_TVE>;
+ status = "disabled";
+ };
+ };
+
+ clocks {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ osc24M: osc24M_clk {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <24000000>;
+ clock-accuracy = <50000>;
+ clock-output-names = "osc24M";
+ };
+
+ osc32k: osc32k_clk {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <32768>;
+ clock-accuracy = <50000>;
+ clock-output-names = "ext_osc32k";
+ };
+ };
+
+ de: display-engine {
+ compatible = "allwinner,sun8i-h3-display-engine";
+ allwinner,pipelines = <&mixer0>;
+ status = "disabled";
+ };
+
+ scpi_protocol: scpi {
+ compatible = "arm,scpi";
+ mboxes = <&msgbox 2>, <&msgbox 3>;
+ mbox-names = "tx", "rx";
+ shmem = <&scpi_sram>;
+ };
+
+ sound_hdmi: sound_hdmi {
+ compatible = "allwinner,sun9i-a80-hdmi-audio",
+ "allwinner,sun8i-h3-hdmi-audio";
+ status = "disabled";
+
+ codec {
+ sound-dai = <&hdmi>;
+ };
+
+ cpu {
+ sound-dai = <&i2s2>;
+ };
+ };
+
+ soc {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ dma-ranges;
+ ranges;
+
+ display_clocks: clock@1000000 {
+ /* compatible is in per SoC .dtsi file */
+ reg = <0x01000000 0x10000>;
+ clocks = <&ccu CLK_BUS_DE>,
+ <&ccu CLK_DE>;
+ clock-names = "bus",
+ "mod";
+ resets = <&ccu RST_BUS_DE>;
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ };
+
+ mixer0: mixer@1100000 {
+ compatible = "allwinner,sun8i-h3-de2-mixer-0";
+ reg = <0x01100000 0x100000>;
+ clocks = <&display_clocks CLK_BUS_MIXER0>,
+ <&display_clocks CLK_MIXER0>;
+ clock-names = "bus",
+ "mod";
+ resets = <&display_clocks RST_MIXER0>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ mixer0_out: port@1 {
+ reg = <1>;
+
+ mixer0_out_tcon0: endpoint {
+ remote-endpoint = <&tcon0_in_mixer0>;
+ };
+ };
+ };
+ };
+
+ dma: dma-controller@1c02000 {
+ compatible = "allwinner,sun8i-h3-dma";
+ reg = <0x01c02000 0x1000>;
+ interrupts = <GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_DMA>;
+ resets = <&ccu RST_BUS_DMA>;
+ #dma-cells = <1>;
+ };
+
+ tcon0: lcd-controller@1c0c000 {
+ compatible = "allwinner,sun8i-h3-tcon-tv",
+ "allwinner,sun8i-a83t-tcon-tv";
+ reg = <0x01c0c000 0x1000>;
+ interrupts = <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_TCON0>, <&ccu CLK_TCON0>;
+ clock-names = "ahb", "tcon-ch1";
+ resets = <&ccu RST_BUS_TCON0>;
+ reset-names = "lcd";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ tcon0_in: port@0 {
+ reg = <0>;
+
+ tcon0_in_mixer0: endpoint {
+ remote-endpoint = <&mixer0_out_tcon0>;
+ };
+ };
+
+ tcon0_out: port@1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <1>;
+
+ tcon0_out_hdmi: endpoint@1 {
+ reg = <1>;
+ remote-endpoint = <&hdmi_in_tcon0>;
+ };
+ };
+ };
+ };
+
+ mmc0: mmc@1c0f000 {
+ /* compatible and clocks are in per SoC .dtsi file */
+ reg = <0x01c0f000 0x1000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc0_pins>;
+ resets = <&ccu RST_BUS_MMC0>;
+ reset-names = "ahb";
+ interrupts = <GIC_SPI 60 IRQ_TYPE_LEVEL_HIGH>;
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+ mmc1: mmc@1c10000 {
+ /* compatible and clocks are in per SoC .dtsi file */
+ reg = <0x01c10000 0x1000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc1_pins>;
+ resets = <&ccu RST_BUS_MMC1>;
+ reset-names = "ahb";
+ interrupts = <GIC_SPI 61 IRQ_TYPE_LEVEL_HIGH>;
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+ mmc2: mmc@1c11000 {
+ /* compatible and clocks are in per SoC .dtsi file */
+ reg = <0x01c11000 0x1000>;
+ resets = <&ccu RST_BUS_MMC2>;
+ reset-names = "ahb";
+ interrupts = <GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>;
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+ sid: eeprom@1c14000 {
+ /* compatible is in per SoC .dtsi file */
+ reg = <0x1c14000 0x400>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ ths_calibration: thermal-sensor-calibration@34 {
+ reg = <0x34 4>;
+ };
+ };
+
+ msgbox: mailbox@1c17000 {
+ compatible = "allwinner,sun8i-h3-msgbox",
+ "allwinner,sun6i-a31-msgbox";
+ reg = <0x01c17000 0x1000>;
+ clocks = <&ccu CLK_BUS_MSGBOX>;
+ resets = <&ccu RST_BUS_MSGBOX>;
+ interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>;
+ #mbox-cells = <1>;
+ };
+
+ usb_otg: usb@1c19000 {
+ compatible = "allwinner,sun8i-h3-musb";
+ reg = <0x01c19000 0x400>;
+ clocks = <&ccu CLK_BUS_OTG>;
+ resets = <&ccu RST_BUS_OTG>;
+ interrupts = <GIC_SPI 71 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "mc";
+ phys = <&usbphy 0>;
+ phy-names = "usb";
+ extcon = <&usbphy 0>;
+ dr_mode = "otg";
+ status = "disabled";
+ };
+
+ usbphy: phy@1c19400 {
+ compatible = "allwinner,sun8i-h3-usb-phy";
+ reg = <0x01c19400 0x2c>,
+ <0x01c1a800 0x4>,
+ <0x01c1b800 0x4>,
+ <0x01c1c800 0x4>,
+ <0x01c1d800 0x4>;
+ reg-names = "phy_ctrl",
+ "pmu0",
+ "pmu1",
+ "pmu2",
+ "pmu3";
+ clocks = <&ccu CLK_USB_PHY0>,
+ <&ccu CLK_USB_PHY1>,
+ <&ccu CLK_USB_PHY2>,
+ <&ccu CLK_USB_PHY3>;
+ clock-names = "usb0_phy",
+ "usb1_phy",
+ "usb2_phy",
+ "usb3_phy";
+ resets = <&ccu RST_USB_PHY0>,
+ <&ccu RST_USB_PHY1>,
+ <&ccu RST_USB_PHY2>,
+ <&ccu RST_USB_PHY3>;
+ reset-names = "usb0_reset",
+ "usb1_reset",
+ "usb2_reset",
+ "usb3_reset";
+ status = "disabled";
+ #phy-cells = <1>;
+ };
+
+ ehci0: usb@1c1a000 {
+ compatible = "allwinner,sun8i-h3-ehci", "generic-ehci";
+ reg = <0x01c1a000 0x100>;
+ interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_EHCI0>, <&ccu CLK_BUS_OHCI0>;
+ resets = <&ccu RST_BUS_EHCI0>, <&ccu RST_BUS_OHCI0>;
+ status = "disabled";
+ };
+
+ ohci0: usb@1c1a400 {
+ compatible = "allwinner,sun8i-h3-ohci", "generic-ohci";
+ reg = <0x01c1a400 0x100>;
+ interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_EHCI0>, <&ccu CLK_BUS_OHCI0>,
+ <&ccu CLK_USB_OHCI0>;
+ resets = <&ccu RST_BUS_EHCI0>, <&ccu RST_BUS_OHCI0>;
+ status = "disabled";
+ };
+
+ ehci1: usb@1c1b000 {
+ compatible = "allwinner,sun8i-h3-ehci", "generic-ehci";
+ reg = <0x01c1b000 0x100>;
+ interrupts = <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_EHCI1>, <&ccu CLK_BUS_OHCI1>;
+ resets = <&ccu RST_BUS_EHCI1>, <&ccu RST_BUS_OHCI1>;
+ phys = <&usbphy 1>;
+ phy-names = "usb";
+ status = "disabled";
+ };
+
+ ohci1: usb@1c1b400 {
+ compatible = "allwinner,sun8i-h3-ohci", "generic-ohci";
+ reg = <0x01c1b400 0x100>;
+ interrupts = <GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_EHCI1>, <&ccu CLK_BUS_OHCI1>,
+ <&ccu CLK_USB_OHCI1>;
+ resets = <&ccu RST_BUS_EHCI1>, <&ccu RST_BUS_OHCI1>;
+ phys = <&usbphy 1>;
+ phy-names = "usb";
+ status = "disabled";
+ };
+
+ ehci2: usb@1c1c000 {
+ compatible = "allwinner,sun8i-h3-ehci", "generic-ehci";
+ reg = <0x01c1c000 0x100>;
+ interrupts = <GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_EHCI2>, <&ccu CLK_BUS_OHCI2>;
+ resets = <&ccu RST_BUS_EHCI2>, <&ccu RST_BUS_OHCI2>;
+ phys = <&usbphy 2>;
+ phy-names = "usb";
+ status = "disabled";
+ };
+
+ ohci2: usb@1c1c400 {
+ compatible = "allwinner,sun8i-h3-ohci", "generic-ohci";
+ reg = <0x01c1c400 0x100>;
+ interrupts = <GIC_SPI 77 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_EHCI2>, <&ccu CLK_BUS_OHCI2>,
+ <&ccu CLK_USB_OHCI2>;
+ resets = <&ccu RST_BUS_EHCI2>, <&ccu RST_BUS_OHCI2>;
+ phys = <&usbphy 2>;
+ phy-names = "usb";
+ status = "disabled";
+ };
+
+ ehci3: usb@1c1d000 {
+ compatible = "allwinner,sun8i-h3-ehci", "generic-ehci";
+ reg = <0x01c1d000 0x100>;
+ interrupts = <GIC_SPI 78 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_EHCI3>, <&ccu CLK_BUS_OHCI3>;
+ resets = <&ccu RST_BUS_EHCI3>, <&ccu RST_BUS_OHCI3>;
+ phys = <&usbphy 3>;
+ phy-names = "usb";
+ status = "disabled";
+ };
+
+ ohci3: usb@1c1d400 {
+ compatible = "allwinner,sun8i-h3-ohci", "generic-ohci";
+ reg = <0x01c1d400 0x100>;
+ interrupts = <GIC_SPI 79 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_EHCI3>, <&ccu CLK_BUS_OHCI3>,
+ <&ccu CLK_USB_OHCI3>;
+ resets = <&ccu RST_BUS_EHCI3>, <&ccu RST_BUS_OHCI3>;
+ phys = <&usbphy 3>;
+ phy-names = "usb";
+ status = "disabled";
+ };
+
+ ccu: clock@1c20000 {
+ /* compatible is in per SoC .dtsi file */
+ reg = <0x01c20000 0x400>;
+ clocks = <&osc24M>, <&rtc CLK_OSC32K>;
+ clock-names = "hosc", "losc";
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ };
+
+ pio: pinctrl@1c20800 {
+ /* compatible is in per SoC .dtsi file */
+ reg = <0x01c20800 0x400>;
+ interrupt-parent = <&r_intc>;
+ interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_PIO>, <&osc24M>,
+ <&rtc CLK_OSC32K>;
+ clock-names = "apb", "hosc", "losc";
+ gpio-controller;
+ #gpio-cells = <3>;
+ interrupt-controller;
+ #interrupt-cells = <3>;
+
+ csi_pins: csi-pins {
+ pins = "PE0", "PE2", "PE3", "PE4", "PE5",
+ "PE6", "PE7", "PE8", "PE9", "PE10",
+ "PE11";
+ function = "csi";
+ };
+
+ emac_rgmii_pins: emac-rgmii-pins {
+ pins = "PD0", "PD1", "PD2", "PD3", "PD4",
+ "PD5", "PD7", "PD8", "PD9", "PD10",
+ "PD12", "PD13", "PD15", "PD16", "PD17";
+ function = "emac";
+ drive-strength = <40>;
+ };
+
+ i2c0_pins: i2c0-pins {
+ pins = "PA11", "PA12";
+ function = "i2c0";
+ };
+
+ i2c1_pins: i2c1-pins {
+ pins = "PA18", "PA19";
+ function = "i2c1";
+ };
+
+ i2c2_pins: i2c2-pins {
+ pins = "PE12", "PE13";
+ function = "i2c2";
+ };
+
+ mmc0_pins: mmc0-pins {
+ pins = "PF0", "PF1", "PF2", "PF3",
+ "PF4", "PF5";
+ function = "mmc0";
+ drive-strength = <30>;
+ bias-pull-up;
+ };
+
+ mmc1_pins: mmc1-pins {
+ pins = "PG0", "PG1", "PG2", "PG3",
+ "PG4", "PG5";
+ function = "mmc1";
+ drive-strength = <30>;
+ bias-pull-up;
+ };
+
+ mmc2_8bit_pins: mmc2-8bit-pins {
+ pins = "PC5", "PC6", "PC8",
+ "PC9", "PC10", "PC11",
+ "PC12", "PC13", "PC14",
+ "PC15", "PC16";
+ function = "mmc2";
+ drive-strength = <30>;
+ bias-pull-up;
+ };
+
+ spdif_tx_pin: spdif-tx-pin {
+ pins = "PA17";
+ function = "spdif";
+ };
+
+ spi0_pins: spi0-pins {
+ pins = "PC0", "PC1", "PC2", "PC3";
+ function = "spi0";
+ };
+
+ spi1_pins: spi1-pins {
+ pins = "PA15", "PA16", "PA14", "PA13";
+ function = "spi1";
+ };
+
+ uart0_pa_pins: uart0-pa-pins {
+ pins = "PA4", "PA5";
+ function = "uart0";
+ };
+
+ uart1_pins: uart1-pins {
+ pins = "PG6", "PG7";
+ function = "uart1";
+ };
+
+ uart1_rts_cts_pins: uart1-rts-cts-pins {
+ pins = "PG8", "PG9";
+ function = "uart1";
+ };
+
+ uart2_pins: uart2-pins {
+ pins = "PA0", "PA1";
+ function = "uart2";
+ };
+
+ uart2_rts_cts_pins: uart2-rts-cts-pins {
+ pins = "PA2", "PA3";
+ function = "uart2";
+ };
+
+ uart3_pins: uart3-pins {
+ pins = "PA13", "PA14";
+ function = "uart3";
+ };
+
+ uart3_rts_cts_pins: uart3-rts-cts-pins {
+ pins = "PA15", "PA16";
+ function = "uart3";
+ };
+ };
+
+ timer@1c20c00 {
+ compatible = "allwinner,sun8i-a23-timer";
+ reg = <0x01c20c00 0xa0>;
+ interrupts = <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&osc24M>;
+ };
+
+ emac: ethernet@1c30000 {
+ compatible = "allwinner,sun8i-h3-emac";
+ syscon = <&syscon>;
+ reg = <0x01c30000 0x10000>;
+ interrupts = <GIC_SPI 82 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "macirq";
+ resets = <&ccu RST_BUS_EMAC>;
+ reset-names = "stmmaceth";
+ clocks = <&ccu CLK_BUS_EMAC>;
+ clock-names = "stmmaceth";
+ status = "disabled";
+
+ mdio: mdio {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "snps,dwmac-mdio";
+ };
+
+ mdio-mux {
+ compatible = "allwinner,sun8i-h3-mdio-mux";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ mdio-parent-bus = <&mdio>;
+ /* Only one MDIO is usable at the time */
+ internal_mdio: mdio@1 {
+ compatible = "allwinner,sun8i-h3-mdio-internal";
+ reg = <1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ int_mii_phy: ethernet-phy@1 {
+ compatible = "ethernet-phy-ieee802.3-c22";
+ reg = <1>;
+ clocks = <&ccu CLK_BUS_EPHY>;
+ resets = <&ccu RST_BUS_EPHY>;
+ };
+ };
+
+ external_mdio: mdio@2 {
+ reg = <2>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+ };
+ };
+
+ mbus: dram-controller@1c62000 {
+ /* compatible is in per SoC .dtsi file */
+ reg = <0x01c62000 0x1000>,
+ <0x01c63000 0x1000>;
+ reg-names = "mbus", "dram";
+ clocks = <&ccu CLK_MBUS>,
+ <&ccu CLK_DRAM>,
+ <&ccu CLK_BUS_DRAM>;
+ clock-names = "mbus", "dram", "bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ dma-ranges = <0x00000000 0x40000000 0xc0000000>;
+ #interconnect-cells = <1>;
+ };
+
+ spi0: spi@1c68000 {
+ compatible = "allwinner,sun8i-h3-spi";
+ reg = <0x01c68000 0x1000>;
+ interrupts = <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_SPI0>, <&ccu CLK_SPI0>;
+ clock-names = "ahb", "mod";
+ dmas = <&dma 23>, <&dma 23>;
+ dma-names = "rx", "tx";
+ pinctrl-names = "default";
+ pinctrl-0 = <&spi0_pins>;
+ resets = <&ccu RST_BUS_SPI0>;
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+ spi1: spi@1c69000 {
+ compatible = "allwinner,sun8i-h3-spi";
+ reg = <0x01c69000 0x1000>;
+ interrupts = <GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_SPI1>, <&ccu CLK_SPI1>;
+ clock-names = "ahb", "mod";
+ dmas = <&dma 24>, <&dma 24>;
+ dma-names = "rx", "tx";
+ pinctrl-names = "default";
+ pinctrl-0 = <&spi1_pins>;
+ resets = <&ccu RST_BUS_SPI1>;
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+ wdt0: watchdog@1c20ca0 {
+ compatible = "allwinner,sun6i-a31-wdt";
+ reg = <0x01c20ca0 0x20>;
+ interrupts = <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&osc24M>;
+ };
+
+ spdif: spdif@1c21000 {
+ #sound-dai-cells = <0>;
+ compatible = "allwinner,sun8i-h3-spdif";
+ reg = <0x01c21000 0x400>;
+ interrupts = <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_SPDIF>, <&ccu CLK_SPDIF>;
+ resets = <&ccu RST_BUS_SPDIF>;
+ clock-names = "apb", "spdif";
+ dmas = <&dma 2>;
+ dma-names = "tx";
+ status = "disabled";
+ };
+
+ pwm: pwm@1c21400 {
+ compatible = "allwinner,sun8i-h3-pwm";
+ reg = <0x01c21400 0x8>;
+ clocks = <&osc24M>;
+ #pwm-cells = <3>;
+ status = "disabled";
+ };
+
+ i2s0: i2s@1c22000 {
+ #sound-dai-cells = <0>;
+ compatible = "allwinner,sun8i-h3-i2s";
+ reg = <0x01c22000 0x400>;
+ interrupts = <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_I2S0>, <&ccu CLK_I2S0>;
+ clock-names = "apb", "mod";
+ dmas = <&dma 3>, <&dma 3>;
+ resets = <&ccu RST_BUS_I2S0>;
+ dma-names = "rx", "tx";
+ status = "disabled";
+ };
+
+ i2s1: i2s@1c22400 {
+ #sound-dai-cells = <0>;
+ compatible = "allwinner,sun8i-h3-i2s";
+ reg = <0x01c22400 0x400>;
+ interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_I2S1>, <&ccu CLK_I2S1>;
+ clock-names = "apb", "mod";
+ dmas = <&dma 4>, <&dma 4>;
+ resets = <&ccu RST_BUS_I2S1>;
+ dma-names = "rx", "tx";
+ status = "disabled";
+ };
+
+ i2s2: i2s@1c22800 {
+ #sound-dai-cells = <0>;
+ compatible = "allwinner,sun8i-h3-i2s";
+ reg = <0x01c22800 0x400>;
+ interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_I2S2>, <&ccu CLK_I2S2>;
+ clock-names = "apb", "mod";
+ dmas = <&dma 27>;
+ resets = <&ccu RST_BUS_I2S2>;
+ dma-names = "tx";
+ status = "disabled";
+ };
+
+ codec: codec@1c22c00 {
+ #sound-dai-cells = <0>;
+ compatible = "allwinner,sun8i-h3-codec";
+ reg = <0x01c22c00 0x400>;
+ interrupts = <GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_CODEC>, <&ccu CLK_AC_DIG>;
+ clock-names = "apb", "codec";
+ resets = <&ccu RST_BUS_CODEC>;
+ dmas = <&dma 15>, <&dma 15>;
+ dma-names = "rx", "tx";
+ allwinner,codec-analog-controls = <&codec_analog>;
+ status = "disabled";
+ };
+
+ uart0: serial@1c28000 {
+ compatible = "snps,dw-apb-uart";
+ reg = <0x01c28000 0x400>;
+ interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>;
+ reg-shift = <2>;
+ reg-io-width = <4>;
+ clocks = <&ccu CLK_BUS_UART0>;
+ resets = <&ccu RST_BUS_UART0>;
+ dmas = <&dma 6>, <&dma 6>;
+ dma-names = "rx", "tx";
+ status = "disabled";
+ };
+
+ uart1: serial@1c28400 {
+ compatible = "snps,dw-apb-uart";
+ reg = <0x01c28400 0x400>;
+ interrupts = <GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>;
+ reg-shift = <2>;
+ reg-io-width = <4>;
+ clocks = <&ccu CLK_BUS_UART1>;
+ resets = <&ccu RST_BUS_UART1>;
+ dmas = <&dma 7>, <&dma 7>;
+ dma-names = "rx", "tx";
+ status = "disabled";
+ };
+
+ uart2: serial@1c28800 {
+ compatible = "snps,dw-apb-uart";
+ reg = <0x01c28800 0x400>;
+ interrupts = <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>;
+ reg-shift = <2>;
+ reg-io-width = <4>;
+ clocks = <&ccu CLK_BUS_UART2>;
+ resets = <&ccu RST_BUS_UART2>;
+ dmas = <&dma 8>, <&dma 8>;
+ dma-names = "rx", "tx";
+ status = "disabled";
+ };
+
+ uart3: serial@1c28c00 {
+ compatible = "snps,dw-apb-uart";
+ reg = <0x01c28c00 0x400>;
+ interrupts = <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>;
+ reg-shift = <2>;
+ reg-io-width = <4>;
+ clocks = <&ccu CLK_BUS_UART3>;
+ resets = <&ccu RST_BUS_UART3>;
+ dmas = <&dma 9>, <&dma 9>;
+ dma-names = "rx", "tx";
+ status = "disabled";
+ };
+
+ i2c0: i2c@1c2ac00 {
+ compatible = "allwinner,sun6i-a31-i2c";
+ reg = <0x01c2ac00 0x400>;
+ interrupts = <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_I2C0>;
+ resets = <&ccu RST_BUS_I2C0>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c0_pins>;
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+ i2c1: i2c@1c2b000 {
+ compatible = "allwinner,sun6i-a31-i2c";
+ reg = <0x01c2b000 0x400>;
+ interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_I2C1>;
+ resets = <&ccu RST_BUS_I2C1>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c1_pins>;
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+ i2c2: i2c@1c2b400 {
+ compatible = "allwinner,sun6i-a31-i2c";
+ reg = <0x01c2b400 0x400>;
+ interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_I2C2>;
+ resets = <&ccu RST_BUS_I2C2>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c2_pins>;
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+ gic: interrupt-controller@1c81000 {
+ compatible = "arm,gic-400";
+ reg = <0x01c81000 0x1000>,
+ <0x01c82000 0x2000>,
+ <0x01c84000 0x2000>,
+ <0x01c86000 0x2000>;
+ interrupt-controller;
+ #interrupt-cells = <3>;
+ interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
+ };
+
+ csi: camera@1cb0000 {
+ compatible = "allwinner,sun8i-h3-csi";
+ reg = <0x01cb0000 0x1000>;
+ interrupts = <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_CSI>,
+ <&ccu CLK_CSI_SCLK>,
+ <&ccu CLK_DRAM_CSI>;
+ clock-names = "bus", "mod", "ram";
+ resets = <&ccu RST_BUS_CSI>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&csi_pins>;
+ status = "disabled";
+ };
+
+ hdmi: hdmi@1ee0000 {
+ compatible = "allwinner,sun8i-h3-dw-hdmi",
+ "allwinner,sun8i-a83t-dw-hdmi";
+ reg = <0x01ee0000 0x10000>;
+ reg-io-width = <1>;
+ interrupts = <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_HDMI>, <&ccu CLK_HDMI_DDC>,
+ <&ccu CLK_HDMI>, <&rtc CLK_OSC32K>;
+ clock-names = "iahb", "isfr", "tmds", "cec";
+ resets = <&ccu RST_BUS_HDMI1>;
+ reset-names = "ctrl";
+ phys = <&hdmi_phy>;
+ phy-names = "phy";
+ status = "disabled";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ hdmi_in: port@0 {
+ reg = <0>;
+
+ hdmi_in_tcon0: endpoint {
+ remote-endpoint = <&tcon0_out_hdmi>;
+ };
+ };
+
+ hdmi_out: port@1 {
+ reg = <1>;
+ };
+ };
+ };
+
+ hdmi_phy: hdmi-phy@1ef0000 {
+ compatible = "allwinner,sun8i-h3-hdmi-phy";
+ reg = <0x01ef0000 0x10000>;
+ clocks = <&ccu CLK_BUS_HDMI>, <&ccu CLK_HDMI_DDC>,
+ <&ccu CLK_PLL_VIDEO>;
+ clock-names = "bus", "mod", "pll-0";
+ resets = <&ccu RST_BUS_HDMI0>;
+ reset-names = "phy";
+ #phy-cells = <0>;
+ };
+
+ rtc: rtc@1f00000 {
+ /* compatible is in per SoC .dtsi file */
+ reg = <0x01f00000 0x400>;
+ interrupt-parent = <&r_intc>;
+ interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>;
+ clock-output-names = "osc32k", "osc32k-out", "iosc";
+ clocks = <&osc32k>;
+ #clock-cells = <1>;
+ };
+
+ r_intc: interrupt-controller@1f00c00 {
+ compatible = "allwinner,sun8i-h3-r-intc",
+ "allwinner,sun6i-a31-r-intc";
+ interrupt-controller;
+ #interrupt-cells = <3>;
+ reg = <0x01f00c00 0x400>;
+ interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ r_ccu: clock@1f01400 {
+ compatible = "allwinner,sun8i-h3-r-ccu";
+ reg = <0x01f01400 0x100>;
+ clocks = <&osc24M>, <&rtc CLK_OSC32K>, <&rtc CLK_IOSC>,
+ <&ccu CLK_PLL_PERIPH0>;
+ clock-names = "hosc", "losc", "iosc", "pll-periph";
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ };
+
+ codec_analog: codec-analog@1f015c0 {
+ compatible = "allwinner,sun8i-h3-codec-analog";
+ reg = <0x01f015c0 0x4>;
+ };
+
+ ir: ir@1f02000 {
+ compatible = "allwinner,sun6i-a31-ir";
+ clocks = <&r_ccu CLK_APB0_IR>, <&r_ccu CLK_IR>;
+ clock-names = "apb", "ir";
+ resets = <&r_ccu RST_APB0_IR>;
+ interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
+ reg = <0x01f02000 0x400>;
+ status = "disabled";
+ };
+
+ r_i2c: i2c@1f02400 {
+ compatible = "allwinner,sun6i-a31-i2c";
+ reg = <0x01f02400 0x400>;
+ interrupts = <GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&r_i2c_pins>;
+ clocks = <&r_ccu CLK_APB0_I2C>;
+ resets = <&r_ccu RST_APB0_I2C>;
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+ r_uart: serial@1f02800 {
+ compatible = "snps,dw-apb-uart";
+ reg = <0x01f02800 0x400>;
+ interrupts = <GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>;
+ reg-shift = <2>;
+ reg-io-width = <4>;
+ clocks = <&r_ccu CLK_APB0_UART>;
+ resets = <&r_ccu RST_APB0_UART>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&r_uart_pins>;
+ status = "disabled";
+ };
+
+ r_pio: pinctrl@1f02c00 {
+ compatible = "allwinner,sun8i-h3-r-pinctrl";
+ reg = <0x01f02c00 0x400>;
+ interrupt-parent = <&r_intc>;
+ interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&r_ccu CLK_APB0_PIO>, <&osc24M>,
+ <&rtc CLK_OSC32K>;
+ clock-names = "apb", "hosc", "losc";
+ gpio-controller;
+ #gpio-cells = <3>;
+ interrupt-controller;
+ #interrupt-cells = <3>;
+
+ r_ir_rx_pin: r-ir-rx-pin {
+ pins = "PL11";
+ function = "s_cir_rx";
+ };
+
+ r_i2c_pins: r-i2c-pins {
+ pins = "PL0", "PL1";
+ function = "s_i2c";
+ };
+
+ r_pwm_pin: r-pwm-pin {
+ pins = "PL10";
+ function = "s_pwm";
+ };
+
+ r_uart_pins: r-uart-pins {
+ pins = "PL2", "PL3";
+ function = "s_uart";
+ };
+ };
+
+ r_pwm: pwm@1f03800 {
+ compatible = "allwinner,sun8i-h3-pwm";
+ reg = <0x01f03800 0x8>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&r_pwm_pin>;
+ clocks = <&osc24M>;
+ #pwm-cells = <3>;
+ status = "disabled";
+ };
+ };
+};
Index: v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/Makefile
===================================================================
--- v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/Makefile (nonexistent)
+++ v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/Makefile (revision 385)
@@ -0,0 +1,67 @@
+# SPDX-License-Identifier: GPL-2.0
+dtb-$(CONFIG_ARCH_SUNXI) += sun50i-a64-amarula-relic.dtb
+dtb-$(CONFIG_ARCH_SUNXI) += sun50i-a64-bananapi-m64.dtb
+dtb-$(CONFIG_ARCH_SUNXI) += sun50i-a64-nanopi-a64.dtb
+dtb-$(CONFIG_ARCH_SUNXI) += sun50i-a64-oceanic-5205-5inmfd.dtb
+dtb-$(CONFIG_ARCH_SUNXI) += sun50i-a64-olinuxino.dtb
+dtb-$(CONFIG_ARCH_SUNXI) += sun50i-a64-olinuxino-emmc.dtb
+dtb-$(CONFIG_ARCH_SUNXI) += sun50i-a64-orangepi-win.dtb
+dtb-$(CONFIG_ARCH_SUNXI) += sun50i-a64-pine64-lts.dtb
+dtb-$(CONFIG_ARCH_SUNXI) += sun50i-a64-pine64-plus.dtb sun50i-a64-pine64.dtb
+dtb-$(CONFIG_ARCH_SUNXI) += sun50i-a64-pinebook.dtb
+dtb-$(CONFIG_ARCH_SUNXI) += sun50i-a64-pinephone-1.0.dtb
+dtb-$(CONFIG_ARCH_SUNXI) += sun50i-a64-pinephone-1.1.dtb
+dtb-$(CONFIG_ARCH_SUNXI) += sun50i-a64-pinephone-1.2.dtb
+dtb-$(CONFIG_ARCH_SUNXI) += sun50i-a64-pinetab.dtb
+dtb-$(CONFIG_ARCH_SUNXI) += sun50i-a64-pinetab-early-adopter.dtb
+dtb-$(CONFIG_ARCH_SUNXI) += sun50i-a64-sopine-baseboard.dtb
+dtb-$(CONFIG_ARCH_SUNXI) += sun50i-a64-teres-i.dtb
+dtb-$(CONFIG_ARCH_SUNXI) += sun50i-a100-allwinner-perf1.dtb
+dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h5-bananapi-m2-plus.dtb
+dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h5-bananapi-m2-plus-v1.2.dtb
+dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h5-emlid-neutis-n5-devboard.dtb
+dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h5-libretech-all-h3-cc.dtb
+dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h5-libretech-all-h3-it.dtb
+dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h5-libretech-all-h5-cc.dtb
+dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h5-nanopi-neo2.dtb
+dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h5-nanopi-neo-plus2.dtb
+dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h5-nanopi-r1s-h5.dtb
+dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h5-orangepi-pc2.dtb
+dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h5-orangepi-prime.dtb
+dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h5-orangepi-zero-plus.dtb
+dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h5-orangepi-zero-plus2.dtb
+dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h5-repka-pi3-1.0ghz.dtb
+dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h5-repka-pi3-1.2ghz.dtb
+dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h5-repka-pi3-1.4ghz.dtb
+dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h5-repka-pi3-alt-1.0ghz.dtb
+dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h5-repka-pi3-alt-1.2ghz.dtb
+dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h5-repka-pi3-alt-1.4ghz.dtb
+dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h5-repka-pi3-alt-uart-1.0ghz.dtb
+dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h5-repka-pi3-alt-uart-1.2ghz.dtb
+dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h5-repka-pi3-alt-uart-1.4ghz.dtb
+dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h5-repka-pi3-alt-pwm-1.0ghz.dtb
+dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h5-repka-pi3-alt-pwm-1.2ghz.dtb
+dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h5-repka-pi3-alt-pwm-1.4ghz.dtb
+dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h5-repka-pi3-alt-i2c2-1.0ghz.dtb
+dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h5-repka-pi3-alt-i2c2-1.2ghz.dtb
+dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h5-repka-pi3-alt-i2c2-1.4ghz.dtb
+dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h5-repka-pi3-v1.4.dtb
+dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h5-repka-pi3-v1.4p.dtb
+dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h5-repka-pi3-alt-v1.4.dtb
+dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h5-repka-pi3-alt-v1.4p.dtb
+dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h5-repka-pi3-alt-uart-v1.4.dtb
+dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h5-repka-pi3-alt-uart-v1.4p.dtb
+dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h5-repka-pi3-alt-pwm-v1.4.dtb
+dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h5-repka-pi3-alt-pwm-v1.4p.dtb
+dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h5-repka-pi3-alt-i2c2-v1.4.dtb
+dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h5-repka-pi3-alt-i2c2-v1.4p.dtb
+dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h6-beelink-gs1.dtb
+dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h6-orangepi-3.dtb
+dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h6-orangepi-lite2.dtb
+dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h6-orangepi-one-plus.dtb
+dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h6-pine-h64.dtb
+dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h6-pine-h64-model-b.dtb
+dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h6-tanix-tx6.dtb
+dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h6-tanix-tx6-mini.dtb
+dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h616-orangepi-zero2.dtb
+dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h616-x96-mate.dtb
Index: v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-cpu-opp-1.0ghz.dtsi
===================================================================
--- v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-cpu-opp-1.0ghz.dtsi (nonexistent)
+++ v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-cpu-opp-1.0ghz.dtsi (revision 385)
@@ -0,0 +1,74 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+// Copyright (C) 2020 Chen-Yu Tsai <wens@csie.org>
+
+/ {
+ cpu_opp_table: opp-table-cpu {
+ compatible = "operating-points-v2";
+ opp-shared;
+
+ opp-288000000 {
+ opp-hz = /bits/ 64 <288000000>;
+ opp-microvolt = <1040000>;
+ clock-latency-ns = <244144>; /* 8 32k periods */
+ };
+
+ opp-336000000 {
+ opp-hz = /bits/ 64 <336000000>;
+ opp-microvolt = <1040000>;
+ clock-latency-ns = <244144>; /* 8 32k periods */
+ };
+
+ opp-480000000 {
+ opp-hz = /bits/ 64 <480000000>;
+ opp-microvolt = <1040000>;
+ clock-latency-ns = <244144>; /* 8 32k periods */
+ };
+
+ opp-576000000 {
+ opp-hz = /bits/ 64 <576000000>;
+ opp-microvolt = <1040000>;
+ clock-latency-ns = <244144>; /* 8 32k periods */
+ };
+
+ opp-648000000 {
+ opp-hz = /bits/ 64 <648000000>;
+ opp-microvolt = <1040000>;
+ clock-latency-ns = <244144>; /* 8 32k periods */
+ };
+
+ opp-816000000 {
+ opp-hz = /bits/ 64 <816000000>;
+ opp-microvolt = <1040000>;
+ clock-latency-ns = <244144>; /* 8 32k periods */
+ };
+
+ opp-912000000 {
+ opp-hz = /bits/ 64 <912000000>;
+ opp-microvolt = <1120000>;
+ clock-latency-ns = <244144>; /* 8 32k periods */
+ };
+
+ opp-1008000000 {
+ opp-hz = /bits/ 64 <1008000000>;
+ opp-microvolt = <1120000>;
+ clock-latency-ns = <244144>; /* 8 32k periods */
+ };
+
+ };
+};
+
+&cpu0 {
+ operating-points-v2 = <&cpu_opp_table>;
+};
+
+&cpu1 {
+ operating-points-v2 = <&cpu_opp_table>;
+};
+
+&cpu2 {
+ operating-points-v2 = <&cpu_opp_table>;
+};
+
+&cpu3 {
+ operating-points-v2 = <&cpu_opp_table>;
+};
Index: v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-cpu-opp-1.2ghz.dtsi
===================================================================
--- v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-cpu-opp-1.2ghz.dtsi (nonexistent)
+++ v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-cpu-opp-1.2ghz.dtsi (revision 385)
@@ -0,0 +1,73 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+// Copyright (C) 2020 Chen-Yu Tsai <wens@csie.org>
+
+/ {
+ cpu_opp_table: opp-table-cpu {
+ compatible = "operating-points-v2";
+ opp-shared;
+
+ opp-288000000 {
+ opp-hz = /bits/ 64 <288000000>;
+ opp-microvolt = <1000000>;
+ clock-latency-ns = <244144>; /* 8 32k periods */
+ };
+
+ opp-336000000 {
+ opp-hz = /bits/ 64 <336000000>;
+ opp-microvolt = <1040000>;
+ clock-latency-ns = <244144>; /* 8 32k periods */
+ };
+
+ opp-480000000 {
+ opp-hz = /bits/ 64 <480000000>;
+ opp-microvolt = <1040000>;
+ clock-latency-ns = <244144>; /* 8 32k periods */
+ };
+
+ opp-648000000 {
+ opp-hz = /bits/ 64 <648000000>;
+ opp-microvolt = <1040000>;
+ clock-latency-ns = <244144>; /* 8 32k periods */
+ };
+
+ opp-816000000 {
+ opp-hz = /bits/ 64 <816000000>;
+ opp-microvolt = <1040000>;
+ clock-latency-ns = <244144>; /* 8 32k periods */
+ };
+
+ opp-1008000000 {
+ opp-hz = /bits/ 64 <1008000000>;
+ opp-microvolt = <1120000>;
+ clock-latency-ns = <244144>; /* 8 32k periods */
+ };
+
+ opp-10560000000 {
+ opp-hz = /bits/ 64 <1056000000>;
+ opp-microvolt = <1140000>;
+ clock-latency-ns = <244144>; /* 8 32k periods */
+ };
+
+ opp-1200000000 {
+ opp-hz = /bits/ 64 <1200000000>;
+ opp-microvolt = <1180000>;
+ clock-latency-ns = <244144>; /* 8 32k periods */
+ };
+ };
+};
+
+&cpu0 {
+ operating-points-v2 = <&cpu_opp_table>;
+};
+
+&cpu1 {
+ operating-points-v2 = <&cpu_opp_table>;
+};
+
+&cpu2 {
+ operating-points-v2 = <&cpu_opp_table>;
+};
+
+&cpu3 {
+ operating-points-v2 = <&cpu_opp_table>;
+};
Index: v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-cpu-opp-1.4ghz.dtsi
===================================================================
--- v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-cpu-opp-1.4ghz.dtsi (nonexistent)
+++ v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-cpu-opp-1.4ghz.dtsi (revision 385)
@@ -0,0 +1,73 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+// Copyright (C) 2020 Chen-Yu Tsai <wens@csie.org>
+
+/ {
+ cpu_opp_table: opp-table-cpu {
+ compatible = "operating-points-v2";
+ opp-shared;
+
+ opp-288000000 {
+ opp-hz = /bits/ 64 <288000000>;
+ opp-microvolt = <1040000>;
+ clock-latency-ns = <244144>; /* 8 32k periods */
+ };
+
+ opp-336000000 {
+ opp-hz = /bits/ 64 <336000000>;
+ opp-microvolt = <1040000>;
+ clock-latency-ns = <244144>; /* 8 32k periods */
+ };
+
+ opp-480000000 {
+ opp-hz = /bits/ 64 <480000000>;
+ opp-microvolt = <1040000>;
+ clock-latency-ns = <244144>; /* 8 32k periods */
+ };
+
+ opp-648000000 {
+ opp-hz = /bits/ 64 <648000000>;
+ opp-microvolt = <1040000>;
+ clock-latency-ns = <244144>; /* 8 32k periods */
+ };
+
+ opp-816000000 {
+ opp-hz = /bits/ 64 <816000000>;
+ opp-microvolt = <1040000>;
+ clock-latency-ns = <244144>; /* 8 32k periods */
+ };
+
+ opp-1008000000 {
+ opp-hz = /bits/ 64 <1008000000>;
+ opp-microvolt = <1120000>;
+ clock-latency-ns = <244144>; /* 8 32k periods */
+ };
+
+ opp-1200000000 {
+ opp-hz = /bits/ 64 <1200000000>;
+ opp-microvolt = <1180000>;
+ clock-latency-ns = <244144>; /* 8 32k periods */
+ };
+
+ opp-1368000000 {
+ opp-hz = /bits/ 64 <1368000000>;
+ opp-microvolt = <1300000>;
+ clock-latency-ns = <244144>; /* 8 32k periods */
+ };
+ };
+};
+
+&cpu0 {
+ operating-points-v2 = <&cpu_opp_table>;
+};
+
+&cpu1 {
+ operating-points-v2 = <&cpu_opp_table>;
+};
+
+&cpu2 {
+ operating-points-v2 = <&cpu_opp_table>;
+};
+
+&cpu3 {
+ operating-points-v2 = <&cpu_opp_table>;
+};
Index: v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-cpu-opp.dtsi
===================================================================
--- v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-cpu-opp.dtsi (nonexistent)
+++ v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-cpu-opp.dtsi (revision 385)
@@ -0,0 +1,73 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+// Copyright (C) 2020 Chen-Yu Tsai <wens@csie.org>
+
+/ {
+ cpu_opp_table: opp-table-cpu {
+ compatible = "operating-points-v2";
+ opp-shared;
+
+ opp-288000000 {
+ opp-hz = /bits/ 64 <288000000>;
+ opp-microvolt = <1000000>;
+ clock-latency-ns = <244144>; /* 8 32k periods */
+ };
+
+ opp-336000000 {
+ opp-hz = /bits/ 64 <336000000>;
+ opp-microvolt = <1040000>;
+ clock-latency-ns = <244144>; /* 8 32k periods */
+ };
+
+ opp-480000000 {
+ opp-hz = /bits/ 64 <480000000>;
+ opp-microvolt = <1040000>;
+ clock-latency-ns = <244144>; /* 8 32k periods */
+ };
+
+ opp-648000000 {
+ opp-hz = /bits/ 64 <648000000>;
+ opp-microvolt = <1040000>;
+ clock-latency-ns = <244144>; /* 8 32k periods */
+ };
+
+ opp-816000000 {
+ opp-hz = /bits/ 64 <816000000>;
+ opp-microvolt = <1040000>;
+ clock-latency-ns = <244144>; /* 8 32k periods */
+ };
+
+ opp-1008000000 {
+ opp-hz = /bits/ 64 <1008000000>;
+ opp-microvolt = <1200000>;
+ clock-latency-ns = <244144>; /* 8 32k periods */
+ };
+
+ opp-1200000000 {
+ opp-hz = /bits/ 64 <1200000000>;
+ opp-microvolt = <1240000>;
+ clock-latency-ns = <244144>; /* 8 32k periods */
+ };
+
+ opp-1368000000 {
+ opp-hz = /bits/ 64 <1368000000>;
+ opp-microvolt = <1300000>;
+ clock-latency-ns = <244144>; /* 8 32k periods */
+ };
+ };
+};
+
+&cpu0 {
+ operating-points-v2 = <&cpu_opp_table>;
+};
+
+&cpu1 {
+ operating-points-v2 = <&cpu_opp_table>;
+};
+
+&cpu2 {
+ operating-points-v2 = <&cpu_opp_table>;
+};
+
+&cpu3 {
+ operating-points-v2 = <&cpu_opp_table>;
+};
Index: v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-repka-3-1.4.dtsi
===================================================================
--- v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-repka-3-1.4.dtsi (nonexistent)
+++ v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-repka-3-1.4.dtsi (revision 385)
@@ -0,0 +1,348 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+// Copyright (C) 2016 ARM Ltd.
+
+#include <arm/sunxi-h3-h5.dtsi>
+
+#include <dt-bindings/thermal/thermal.h>
+
+/ {
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cpu0: cpu@0 {
+ compatible = "arm,cortex-a53";
+ device_type = "cpu";
+ reg = <0>;
+ enable-method = "psci";
+ clocks = <&ccu CLK_CPUX>;
+ clock-latency-ns = <244144>; /* 8 32k periods */
+ #cooling-cells = <2>;
+ };
+
+ cpu1: cpu@1 {
+ compatible = "arm,cortex-a53";
+ device_type = "cpu";
+ reg = <1>;
+ enable-method = "psci";
+ clocks = <&ccu CLK_CPUX>;
+ clock-latency-ns = <244144>; /* 8 32k periods */
+ #cooling-cells = <2>;
+ };
+
+ cpu2: cpu@2 {
+ compatible = "arm,cortex-a53";
+ device_type = "cpu";
+ reg = <2>;
+ enable-method = "psci";
+ clocks = <&ccu CLK_CPUX>;
+ clock-latency-ns = <244144>; /* 8 32k periods */
+ #cooling-cells = <2>;
+ };
+
+ cpu3: cpu@3 {
+ compatible = "arm,cortex-a53";
+ device_type = "cpu";
+ reg = <3>;
+ enable-method = "psci";
+ clocks = <&ccu CLK_CPUX>;
+ clock-latency-ns = <244144>; /* 8 32k periods */
+ #cooling-cells = <2>;
+ };
+ };
+
+ pmu {
+ compatible = "arm,cortex-a53-pmu";
+ interrupts = <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-affinity = <&cpu0>, <&cpu1>, <&cpu2>, <&cpu3>;
+ };
+
+ psci {
+ compatible = "arm,psci-0.2";
+ method = "smc";
+ };
+
+ timer {
+ compatible = "arm,armv8-timer";
+ arm,no-tick-in-suspend;
+ interrupts = <GIC_PPI 13
+ (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+ <GIC_PPI 14
+ (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+ <GIC_PPI 11
+ (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+ <GIC_PPI 10
+ (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>;
+ };
+
+ soc {
+ syscon: system-control@1c00000 {
+ compatible = "allwinner,sun50i-h5-system-control";
+ reg = <0x01c00000 0x1000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ sram_a2: sram@40000 {
+ compatible = "mmio-sram";
+ reg = <0x00040000 0x14000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 0x00040000 0x14000>;
+
+ scpi_sram: scp-shmem@13c00 {
+ compatible = "arm,scp-shmem";
+ reg = <0x13c00 0x200>;
+ };
+ };
+
+ sram_c1: sram@18000 {
+ compatible = "mmio-sram";
+ reg = <0x00018000 0x1c000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 0x00018000 0x1c000>;
+
+ ve_sram: sram-section@0 {
+ compatible = "allwinner,sun50i-h5-sram-c1",
+ "allwinner,sun4i-a10-sram-c1";
+ reg = <0x000000 0x1c000>;
+ };
+ };
+ };
+
+ video-codec@1c0e000 {
+ compatible = "allwinner,sun50i-h5-video-engine";
+ reg = <0x01c0e000 0x1000>;
+ clocks = <&ccu CLK_BUS_VE>, <&ccu CLK_VE>,
+ <&ccu CLK_DRAM_VE>;
+ clock-names = "ahb", "mod", "ram";
+ resets = <&ccu RST_BUS_VE>;
+ interrupts = <GIC_SPI 58 IRQ_TYPE_LEVEL_HIGH>;
+ allwinner,sram = <&ve_sram 1>;
+ };
+
+ crypto: crypto@1c15000 {
+ compatible = "allwinner,sun50i-h5-crypto";
+ reg = <0x01c15000 0x1000>;
+ interrupts = <GIC_SPI 94 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_CE>, <&ccu CLK_CE>;
+ clock-names = "bus", "mod";
+ resets = <&ccu RST_BUS_CE>;
+ };
+
+ deinterlace: deinterlace@1e00000 {
+ compatible = "allwinner,sun8i-h3-deinterlace";
+ reg = <0x01e00000 0x20000>;
+ clocks = <&ccu CLK_BUS_DEINTERLACE>,
+ <&ccu CLK_DEINTERLACE>,
+ <&ccu CLK_DRAM_DEINTERLACE>;
+ clock-names = "bus", "mod", "ram";
+ resets = <&ccu RST_BUS_DEINTERLACE>;
+ interrupts = <GIC_SPI 93 IRQ_TYPE_LEVEL_HIGH>;
+ interconnects = <&mbus 9>;
+ interconnect-names = "dma-mem";
+ };
+
+ mali: gpu@1e80000 {
+ compatible = "allwinner,sun50i-h5-mali", "arm,mali-450";
+ reg = <0x01e80000 0x30000>;
+ /*
+ * While the datasheet lists an interrupt for the
+ * PMU, the actual silicon does not have the PMU
+ * block. Reads all return zero, and writes are
+ * ignored.
+ */
+ interrupts = <GIC_SPI 96 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 97 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 99 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 104 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 106 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 107 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "gp",
+ "gpmmu",
+ "pp",
+ "pp0",
+ "ppmmu0",
+ "pp1",
+ "ppmmu1",
+ "pp2",
+ "ppmmu2",
+ "pp3",
+ "ppmmu3";
+ clocks = <&ccu CLK_BUS_GPU>, <&ccu CLK_GPU>;
+ clock-names = "bus", "core";
+ resets = <&ccu RST_BUS_GPU>;
+
+ assigned-clocks = <&ccu CLK_GPU>;
+ assigned-clock-rates = <384000000>;
+ };
+
+ ths: thermal-sensor@1c25000 {
+ compatible = "allwinner,sun50i-h5-ths";
+ reg = <0x01c25000 0x400>;
+ interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
+ resets = <&ccu RST_BUS_THS>;
+ clocks = <&ccu CLK_BUS_THS>, <&ccu CLK_THS>;
+ clock-names = "bus", "mod";
+ nvmem-cells = <&ths_calibration>;
+ nvmem-cell-names = "calibration";
+ #thermal-sensor-cells = <1>;
+ };
+ };
+
+ thermal-zones {
+ cpu_thermal: cpu-thermal {
+ /* milliseconds */
+ polling-delay-passive = <250>;
+ polling-delay = <1000>;
+ thermal-sensors = <&ths 0>;
+
+ trips {
+ cpu_warm: cpu_warm {
+ temperature = <75000>;
+ hysteresis = <2000>;
+ type = "passive";
+ };
+
+ cpu_hot0: cpu_hot0 {
+ temperature = <78000>;
+ hysteresis = <2000>;
+ type = "passive";
+ };
+
+ cpu_hot1: cpu_hot1 {
+ temperature = <81000>;
+ hysteresis = <2000>;
+ type = "passive";
+ };
+
+ cpu_very_hot0: cpu_very_hot0 {
+ temperature = <84000>;
+ hysteresis = <2000>;
+ type = "passive";
+ };
+
+ cpu_very_hot1: cpu_very_hot1 {
+ temperature = <87000>;
+ hysteresis = <2000>;
+ type = "passive";
+ };
+
+ cpu_very_hot2: cpu_very_hot2 {
+ temperature = <90000>;
+ hysteresis = <2000>;
+ type = "passive";
+ };
+
+ cpu_very_hot3: cpu_very_hot3 {
+ temperature = <92000>;
+ hysteresis = <2000>;
+ type = "passive";
+ };
+
+ cpu_crit: cpu_crit {
+ temperature = <95000>;
+ hysteresis = <2000>;
+ type = "critical";
+ };
+ };
+
+ cooling-maps {
+ cpu_warm_limit_cpu {
+ trip = <&cpu_warm>;
+ cooling-device = <&cpu0 THERMAL_NO_LIMIT 1>;
+ };
+
+ cpu_hot_limit_cpu0 {
+ trip = <&cpu_hot0>;
+ cooling-device = <&cpu0 1 2>;
+ };
+
+ cpu_hot_limit_cpu1 {
+ trip = <&cpu_hot1>;
+ cooling-device = <&cpu0 2 3>;
+ };
+
+ cpu_very_hot_limit_cpu0 {
+ trip = <&cpu_very_hot0>;
+ cooling-device = <&cpu0 3 4>;
+ };
+
+ cpu_very_hot_limit_cpu1 {
+ trip = <&cpu_very_hot1>;
+ cooling-device = <&cpu0 4 5>;
+ };
+
+ cpu_very_hot_limit_cpu2 {
+ trip = <&cpu_very_hot2>;
+ cooling-device = <&cpu0 5 6>;
+ };
+
+ cpu_very_hot_limit_cpu3 {
+ trip = <&cpu_very_hot3>;
+ cooling-device = <&cpu0 7 THERMAL_NO_LIMIT>;
+ };
+
+ };
+ };
+
+ gpu-thermal {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&ths 1>;
+ };
+ };
+};
+
+&ccu {
+ compatible = "allwinner,sun50i-h5-ccu";
+};
+
+&display_clocks {
+ compatible = "allwinner,sun50i-h5-de2-clk";
+};
+
+&mmc0 {
+ compatible = "allwinner,sun50i-h5-mmc",
+ "allwinner,sun50i-a64-mmc";
+ clocks = <&ccu CLK_BUS_MMC0>, <&ccu CLK_MMC0>;
+ clock-names = "ahb", "mmc";
+};
+
+&mmc1 {
+ compatible = "allwinner,sun50i-h5-mmc",
+ "allwinner,sun50i-a64-mmc";
+ clocks = <&ccu CLK_BUS_MMC1>, <&ccu CLK_MMC1>;
+ clock-names = "ahb", "mmc";
+};
+
+&mmc2 {
+ compatible = "allwinner,sun50i-h5-emmc",
+ "allwinner,sun50i-a64-emmc";
+ clocks = <&ccu CLK_BUS_MMC2>, <&ccu CLK_MMC2>;
+ clock-names = "ahb", "mmc";
+};
+
+&pio {
+ interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH>;
+ compatible = "allwinner,sun50i-h5-pinctrl";
+};
+
+&rtc {
+ compatible = "allwinner,sun50i-h5-rtc";
+};
+
+&sid {
+ compatible = "allwinner,sun50i-h5-sid";
+};
Index: v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-repka-3-1.4p.dtsi
===================================================================
--- v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-repka-3-1.4p.dtsi (nonexistent)
+++ v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-repka-3-1.4p.dtsi (revision 385)
@@ -0,0 +1,348 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+// Copyright (C) 2016 ARM Ltd.
+
+#include <arm/sunxi-h3-h5.dtsi>
+
+#include <dt-bindings/thermal/thermal.h>
+
+/ {
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cpu0: cpu@0 {
+ compatible = "arm,cortex-a53";
+ device_type = "cpu";
+ reg = <0>;
+ enable-method = "psci";
+ clocks = <&ccu CLK_CPUX>;
+ clock-latency-ns = <244144>; /* 8 32k periods */
+ #cooling-cells = <2>;
+ };
+
+ cpu1: cpu@1 {
+ compatible = "arm,cortex-a53";
+ device_type = "cpu";
+ reg = <1>;
+ enable-method = "psci";
+ clocks = <&ccu CLK_CPUX>;
+ clock-latency-ns = <244144>; /* 8 32k periods */
+ #cooling-cells = <2>;
+ };
+
+ cpu2: cpu@2 {
+ compatible = "arm,cortex-a53";
+ device_type = "cpu";
+ reg = <2>;
+ enable-method = "psci";
+ clocks = <&ccu CLK_CPUX>;
+ clock-latency-ns = <244144>; /* 8 32k periods */
+ #cooling-cells = <2>;
+ };
+
+ cpu3: cpu@3 {
+ compatible = "arm,cortex-a53";
+ device_type = "cpu";
+ reg = <3>;
+ enable-method = "psci";
+ clocks = <&ccu CLK_CPUX>;
+ clock-latency-ns = <244144>; /* 8 32k periods */
+ #cooling-cells = <2>;
+ };
+ };
+
+ pmu {
+ compatible = "arm,cortex-a53-pmu";
+ interrupts = <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-affinity = <&cpu0>, <&cpu1>, <&cpu2>, <&cpu3>;
+ };
+
+ psci {
+ compatible = "arm,psci-0.2";
+ method = "smc";
+ };
+
+ timer {
+ compatible = "arm,armv8-timer";
+ arm,no-tick-in-suspend;
+ interrupts = <GIC_PPI 13
+ (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+ <GIC_PPI 14
+ (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+ <GIC_PPI 11
+ (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+ <GIC_PPI 10
+ (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>;
+ };
+
+ soc {
+ syscon: system-control@1c00000 {
+ compatible = "allwinner,sun50i-h5-system-control";
+ reg = <0x01c00000 0x1000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ sram_a2: sram@40000 {
+ compatible = "mmio-sram";
+ reg = <0x00040000 0x14000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 0x00040000 0x14000>;
+
+ scpi_sram: scp-shmem@13c00 {
+ compatible = "arm,scp-shmem";
+ reg = <0x13c00 0x200>;
+ };
+ };
+
+ sram_c1: sram@18000 {
+ compatible = "mmio-sram";
+ reg = <0x00018000 0x1c000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 0x00018000 0x1c000>;
+
+ ve_sram: sram-section@0 {
+ compatible = "allwinner,sun50i-h5-sram-c1",
+ "allwinner,sun4i-a10-sram-c1";
+ reg = <0x000000 0x1c000>;
+ };
+ };
+ };
+
+ video-codec@1c0e000 {
+ compatible = "allwinner,sun50i-h5-video-engine";
+ reg = <0x01c0e000 0x1000>;
+ clocks = <&ccu CLK_BUS_VE>, <&ccu CLK_VE>,
+ <&ccu CLK_DRAM_VE>;
+ clock-names = "ahb", "mod", "ram";
+ resets = <&ccu RST_BUS_VE>;
+ interrupts = <GIC_SPI 58 IRQ_TYPE_LEVEL_HIGH>;
+ allwinner,sram = <&ve_sram 1>;
+ };
+
+ crypto: crypto@1c15000 {
+ compatible = "allwinner,sun50i-h5-crypto";
+ reg = <0x01c15000 0x1000>;
+ interrupts = <GIC_SPI 94 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_CE>, <&ccu CLK_CE>;
+ clock-names = "bus", "mod";
+ resets = <&ccu RST_BUS_CE>;
+ };
+
+ deinterlace: deinterlace@1e00000 {
+ compatible = "allwinner,sun8i-h3-deinterlace";
+ reg = <0x01e00000 0x20000>;
+ clocks = <&ccu CLK_BUS_DEINTERLACE>,
+ <&ccu CLK_DEINTERLACE>,
+ <&ccu CLK_DRAM_DEINTERLACE>;
+ clock-names = "bus", "mod", "ram";
+ resets = <&ccu RST_BUS_DEINTERLACE>;
+ interrupts = <GIC_SPI 93 IRQ_TYPE_LEVEL_HIGH>;
+ interconnects = <&mbus 9>;
+ interconnect-names = "dma-mem";
+ };
+
+ mali: gpu@1e80000 {
+ compatible = "allwinner,sun50i-h5-mali", "arm,mali-450";
+ reg = <0x01e80000 0x30000>;
+ /*
+ * While the datasheet lists an interrupt for the
+ * PMU, the actual silicon does not have the PMU
+ * block. Reads all return zero, and writes are
+ * ignored.
+ */
+ interrupts = <GIC_SPI 96 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 97 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 99 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 104 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 106 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 107 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "gp",
+ "gpmmu",
+ "pp",
+ "pp0",
+ "ppmmu0",
+ "pp1",
+ "ppmmu1",
+ "pp2",
+ "ppmmu2",
+ "pp3",
+ "ppmmu3";
+ clocks = <&ccu CLK_BUS_GPU>, <&ccu CLK_GPU>;
+ clock-names = "bus", "core";
+ resets = <&ccu RST_BUS_GPU>;
+
+ assigned-clocks = <&ccu CLK_GPU>;
+ assigned-clock-rates = <384000000>;
+ };
+
+ ths: thermal-sensor@1c25000 {
+ compatible = "allwinner,sun50i-h5-ths";
+ reg = <0x01c25000 0x400>;
+ interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
+ resets = <&ccu RST_BUS_THS>;
+ clocks = <&ccu CLK_BUS_THS>, <&ccu CLK_THS>;
+ clock-names = "bus", "mod";
+ nvmem-cells = <&ths_calibration>;
+ nvmem-cell-names = "calibration";
+ #thermal-sensor-cells = <1>;
+ };
+ };
+
+ thermal-zones {
+ cpu_thermal: cpu-thermal {
+ /* milliseconds */
+ polling-delay-passive = <250>;
+ polling-delay = <1000>;
+ thermal-sensors = <&ths 0>;
+
+ trips {
+ cpu_warm: cpu_warm {
+ temperature = <65000>;
+ hysteresis = <2000>;
+ type = "passive";
+ };
+
+ cpu_hot0: cpu_hot0 {
+ temperature = <68000>;
+ hysteresis = <2000>;
+ type = "passive";
+ };
+
+ cpu_hot1: cpu_hot1 {
+ temperature = <72000>;
+ hysteresis = <2000>;
+ type = "passive";
+ };
+
+ cpu_very_hot0: cpu_very_hot0 {
+ temperature = <74000>;
+ hysteresis = <2000>;
+ type = "passive";
+ };
+
+ cpu_very_hot1: cpu_very_hot1 {
+ temperature = <78000>;
+ hysteresis = <2000>;
+ type = "passive";
+ };
+
+ cpu_very_hot2: cpu_very_hot2 {
+ temperature = <82000>;
+ hysteresis = <2000>;
+ type = "passive";
+ };
+
+ cpu_very_hot3: cpu_very_hot3 {
+ temperature = <86000>;
+ hysteresis = <2000>;
+ type = "passive";
+ };
+
+ cpu_crit: cpu_crit {
+ temperature = <95000>;
+ hysteresis = <2000>;
+ type = "critical";
+ };
+ };
+
+ cooling-maps {
+ cpu_warm_limit_cpu {
+ trip = <&cpu_warm>;
+ cooling-device = <&cpu0 THERMAL_NO_LIMIT 1>;
+ };
+
+ cpu_hot_limit_cpu0 {
+ trip = <&cpu_hot0>;
+ cooling-device = <&cpu0 1 2>;
+ };
+
+ cpu_hot_limit_cpu1 {
+ trip = <&cpu_hot1>;
+ cooling-device = <&cpu0 2 3>;
+ };
+
+ cpu_very_hot_limit_cpu0 {
+ trip = <&cpu_very_hot0>;
+ cooling-device = <&cpu0 3 4>;
+ };
+
+ cpu_very_hot_limit_cpu1 {
+ trip = <&cpu_very_hot1>;
+ cooling-device = <&cpu0 4 5>;
+ };
+
+ cpu_very_hot_limit_cpu2 {
+ trip = <&cpu_very_hot2>;
+ cooling-device = <&cpu0 5 6>;
+ };
+
+ cpu_very_hot_limit_cpu3 {
+ trip = <&cpu_very_hot3>;
+ cooling-device = <&cpu0 7 THERMAL_NO_LIMIT>;
+ };
+
+ };
+ };
+
+ gpu-thermal {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&ths 1>;
+ };
+ };
+};
+
+&ccu {
+ compatible = "allwinner,sun50i-h5-ccu";
+};
+
+&display_clocks {
+ compatible = "allwinner,sun50i-h5-de2-clk";
+};
+
+&mmc0 {
+ compatible = "allwinner,sun50i-h5-mmc",
+ "allwinner,sun50i-a64-mmc";
+ clocks = <&ccu CLK_BUS_MMC0>, <&ccu CLK_MMC0>;
+ clock-names = "ahb", "mmc";
+};
+
+&mmc1 {
+ compatible = "allwinner,sun50i-h5-mmc",
+ "allwinner,sun50i-a64-mmc";
+ clocks = <&ccu CLK_BUS_MMC1>, <&ccu CLK_MMC1>;
+ clock-names = "ahb", "mmc";
+};
+
+&mmc2 {
+ compatible = "allwinner,sun50i-h5-emmc",
+ "allwinner,sun50i-a64-emmc";
+ clocks = <&ccu CLK_BUS_MMC2>, <&ccu CLK_MMC2>;
+ clock-names = "ahb", "mmc";
+};
+
+&pio {
+ interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH>;
+ compatible = "allwinner,sun50i-h5-pinctrl";
+};
+
+&rtc {
+ compatible = "allwinner,sun50i-h5-rtc";
+};
+
+&sid {
+ compatible = "allwinner,sun50i-h5-sid";
+};
Index: v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-repka-pi3-1.0ghz.dts
===================================================================
--- v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-repka-pi3-1.0ghz.dts (nonexistent)
+++ v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-repka-pi3-1.0ghz.dts (revision 385)
@@ -0,0 +1,424 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+// Copyright (C) 2016 ARM Ltd.
+
+/dts-v1/;
+#include "sun50i-h5.dtsi"
+#include "sun50i-h5-cpu-opp-1.0ghz.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
+
+/ {
+ model = "Repka-Pi3-H5";
+ repka-freq = "1.0 GHz";
+ repka-pinout = "1";
+ compatible = "rbs,repka-pi3", "allwinner,sun50i-h5";
+
+ reg_vcc3v3: vcc3v3 {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc3v3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ aliases {
+ mmc0 = &mmc0;
+ ethernet0 = &emac;
+ serial0 = &uart0;
+ serial1 = &uart1;
+ spi0 = &spi0;
+ spi1 = &spi1;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ connector {
+ compatible = "hdmi-connector";
+ type = "a";
+
+ port {
+ hdmi_con_in: endpoint {
+ remote-endpoint = <&hdmi_out_con>;
+ };
+ };
+ };
+
+ ext_osc32k: ext_osc32k_clk {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <32768>;
+ clock-output-names = "ext_osc32k";
+ };
+
+ leds {
+ compatible = "gpio-leds";
+
+ status {
+ label = "rbs:red:status";
+ gpios = <&pio 0 20 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "heartbeat";
+ };
+ };
+
+ wifi_pwrseq: wifi_pwrseq {
+ compatible = "mmc-pwrseq-simple";
+ reset-gpios = <&r_pio 0 8 GPIO_ACTIVE_LOW>;
+ post-power-on-delay-ms = <200>;
+ };
+
+};
+
+&codec {
+ allwinner,audio-routing =
+ "Line Out", "LINEOUT",
+ "MIC1", "Mic",
+ "Mic", "MBIAS";
+ status = "okay";
+};
+
+&cpu0 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&cpu1 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&cpu2 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&cpu3 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&de {
+ status = "okay";
+};
+
+&ehci0 {
+ status = "okay";
+};
+
+&ehci1 {
+ status = "okay";
+};
+
+&ehci2 {
+ status = "okay";
+};
+
+&ehci3 {
+ status = "okay";
+};
+
+&emac {
+ phy-handle = <&int_mii_phy>;
+ phy-mode = "mii";
+ allwinner,leds-active-low;
+ status = "okay";
+};
+
+&hdmi {
+ status = "okay";
+};
+
+&hdmi_out {
+ hdmi_out_con: endpoint {
+ remote-endpoint = <&hdmi_con_in>;
+ };
+};
+
+&i2s2 {
+ status = "okay";
+};
+
+&sound_hdmi {
+ status = "okay";
+};
+
+&ir {
+ pinctrl-names = "default";
+ pinctrl-0 = <&r_ir_rx_pin>;
+ status = "disabled";
+};
+
+&rtc {
+ clocks = <&ext_osc32k>;
+};
+
+&mmc0 {
+ vmmc-supply = <®_vcc3v3>;
+ bus-width = <4>;
+ cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>; /* PF6 */
+ status = "okay";
+};
+
+&mmc1 {
+ vmmc-supply = <®_vcc3v3>;
+ mmc-pwrseq = <&wifi_pwrseq>;
+ bus-width = <4>;
+ non-removable;
+ status = "okay";
+
+ brcmf: wifi@1 {
+ reg = <1>;
+ compatible = "brcm,bcm4329-fmac";
+ interrupt-parent = <&r_pio>;
+ interrupts = <0 7 IRQ_TYPE_LEVEL_LOW>; /* PL7 */
+ interrupt-names = "host-wake";
+ };
+
+};
+
+&mmc2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc2_8bit_pins>;
+ vmmc-supply = <®_vcc3v3>;
+ bus-width = <8>;
+ non-removable;
+ cap-mmc-hw-reset;
+ status = "disabled";
+};
+
+&ohci0 {
+ status = "okay";
+};
+
+&ohci1 {
+ status = "okay";
+};
+
+&ohci2 {
+ status = "okay";
+};
+
+&ohci3 {
+ status = "okay";
+};
+
+&i2c1 {
+ status = "disabled"; /* PA19,PA18 */
+};
+
+&i2c0 {
+ status = "disabled"; /* PA11, PA12 */
+};
+
+&r_i2c {
+ status = "okay";
+
+ axp22x: pmic@34 {
+ compatible = "x-powers,axp221";
+ reg = <0x34>;
+ interrupt-parent = <&r_intc>;
+ interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+ };
+};
+
+#include "arm/axp22x.dtsi"
+
+&ac_power_supply {
+ status = "okay";
+};
+
+®_aldo2 { /* VCC-PG 1.8 */
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-pg";
+};
+
+®_aldo3 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-pll-avcc";
+};
+
+®_dc1sw {
+ regulator-name = "vcc-phy";
+};
+
+®_dcdc1 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-3v3";
+};
+
+®_dcdc2 {
+ regulator-always-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1360000>;
+ regulator-name = "vdd-cpux-a";
+};
+
+®_dcdc3 {
+ regulator-always-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1360000>;
+ regulator-name = "vdd-cpux-b";
+};
+
+/* DCDC3 is polyphased with DCDC2 */
+
+/*
+ * The DRAM chips used by rbs-h5 boards are DDR3 -compatibl
+ *
+ */
+®_dcdc5 {
+ regulator-always-on;
+ regulator-min-microvolt = <1500000>;
+ regulator-max-microvolt = <1500000>;
+ regulator-name = "vcc-dram";
+};
+
+®_dldo1 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-1";
+};
+
+®_dldo2 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-2";
+};
+
+®_dldo3 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-3";
+};
+
+®_dldo4 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-4";
+};
+ /* VCC-wifi-IO 1.8 */
+®_eldo1 {
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-wifi-io-1";
+};
+
+®_eldo2 {
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-wifi-io-2";
+};
+
+®_eldo3 {
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-wifi-io-3";
+};
+
+
+®_rtc_ldo {
+ regulator-name = "vcc-rtc";
+};
+
+&spi0 {
+ pinctrl-names = "default", "default";
+ pinctrl-1 = <&spi0_cs1>;
+ cs-gpios = <0>, <&pio 0 3 0>; /* PA3 */
+
+ status = "disabled";
+ spidev@0 {
+ compatible = "rohm,dh2228fv";
+ status = "okay";
+ reg = <0>;
+ spi-max-frequency = <1000000>;
+ };
+ spidev@1 {
+ compatible = "rohm,dh2228fv";
+ status = "okay";
+ reg = <1>;
+ spi-max-frequency = <1000000>;
+ };
+};
+
+&spi1 {
+ pinctrl-names = "default", "default";
+ status = "disabled";
+ spidev@0 {
+ compatible = "rohm,dh2228fv";
+ status = "okay";
+ reg = <0>;
+ spi-max-frequency = <1000000>;
+ };
+};
+
+&pio {
+ spi0_cs1: spi0_cs1 { /* для совместимости с распбери создаем cs1 */
+ pins = "PA3";
+ function = "gpio_out";
+ output-high;
+ };
+};
+
+
+&r_pwm {
+ status = "disabled";
+};
+
+/* to debag serial */
+&uart0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_pa_pins>;
+ status = "okay";
+};
+
+/* to bt-wifi module */
+&uart1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart1_pins>, <&uart1_rts_cts_pins>;
+ uart-has-rtscts;
+ status = "okay";
+
+ bluetooth {
+ compatible = "brcm,bcm43438-bt";
+ clocks = <&rtc 1>;
+ clock-names = "lpo";
+ device-wakeup-gpios = <&r_pio 0 4 GPIO_ACTIVE_HIGH>; /* PL4 AP-WAKE-BT */
+ host-wakeup-gpios = <&r_pio 0 6 GPIO_ACTIVE_HIGH>; /* PL6 BT-WAKE-AP */
+ shutdown-gpios = <&r_pio 0 5 GPIO_ACTIVE_HIGH>; /* PL5 BT-RST-N */
+ max-speed = <1500000>;
+ };
+};
+
+&uart2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart2_pins>, <&uart2_rts_cts_pins>;
+ status = "disabled";
+};
+
+&r_uart {
+ pinctrl-names = "default";
+ pinctrl-0 = <&r_uart_pins>;
+ status = "disabled";
+};
+
+&usb_otg {
+ dr_mode = "host";
+ status = "okay";
+};
+
+&usbphy {
+ status = "okay";
+};
+
+
Index: v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-repka-pi3-1.2ghz.dts
===================================================================
--- v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-repka-pi3-1.2ghz.dts (nonexistent)
+++ v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-repka-pi3-1.2ghz.dts (revision 385)
@@ -0,0 +1,425 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+// Copyright (C) 2016 ARM Ltd.
+
+/dts-v1/;
+#include "sun50i-h5.dtsi"
+#include "sun50i-h5-cpu-opp-1.2ghz.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
+
+/ {
+ model = "Repka-Pi3-H5";
+ repka-freq = "1.2 GHz";
+ repka-pinout = "1";
+ compatible = "rbs,repka-pi3", "allwinner,sun50i-h5";
+
+ reg_vcc3v3: vcc3v3 {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc3v3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ aliases {
+ mmc0 = &mmc0;
+ ethernet0 = &emac;
+ serial0 = &uart0;
+ serial1 = &uart1;
+ spi0 = &spi0;
+ spi1 = &spi1;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ connector {
+ compatible = "hdmi-connector";
+ type = "a";
+
+ port {
+ hdmi_con_in: endpoint {
+ remote-endpoint = <&hdmi_out_con>;
+ };
+ };
+ };
+
+ ext_osc32k: ext_osc32k_clk {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <32768>;
+ clock-output-names = "ext_osc32k";
+ };
+
+ leds {
+ compatible = "gpio-leds";
+
+ status {
+ label = "rbs:red:status";
+ gpios = <&pio 0 20 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "heartbeat";
+ };
+ };
+
+ wifi_pwrseq: wifi_pwrseq {
+ compatible = "mmc-pwrseq-simple";
+ reset-gpios = <&r_pio 0 8 GPIO_ACTIVE_LOW>;
+ post-power-on-delay-ms = <200>;
+ };
+
+};
+
+&codec {
+ allwinner,audio-routing =
+ "Line Out", "LINEOUT",
+ "MIC1", "Mic",
+ "Mic", "MBIAS";
+ status = "okay";
+};
+
+&cpu0 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&cpu1 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&cpu2 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&cpu3 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&de {
+ status = "okay";
+};
+
+&ehci0 {
+ status = "okay";
+};
+
+&ehci1 {
+ status = "okay";
+};
+
+&ehci2 {
+ status = "okay";
+};
+
+&ehci3 {
+ status = "okay";
+};
+
+&emac {
+ phy-handle = <&int_mii_phy>;
+ phy-mode = "mii";
+ allwinner,leds-active-low;
+ status = "okay";
+};
+
+&hdmi {
+ status = "okay";
+};
+
+&hdmi_out {
+ hdmi_out_con: endpoint {
+ remote-endpoint = <&hdmi_con_in>;
+ };
+};
+
+&i2s2 {
+ status = "okay";
+};
+
+&sound_hdmi {
+ status = "okay";
+};
+
+&ir {
+ pinctrl-names = "default";
+ pinctrl-0 = <&r_ir_rx_pin>;
+ status = "disabled";
+};
+
+&rtc {
+ clocks = <&ext_osc32k>;
+};
+
+&mmc0 {
+ vmmc-supply = <®_vcc3v3>;
+ bus-width = <4>;
+ cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>; /* PF6 */
+ status = "okay";
+};
+
+&mmc1 {
+ vmmc-supply = <®_vcc3v3>;
+ mmc-pwrseq = <&wifi_pwrseq>;
+ bus-width = <4>;
+ non-removable;
+ status = "okay";
+
+ brcmf: wifi@1 {
+ reg = <1>;
+ compatible = "brcm,bcm4329-fmac";
+ interrupt-parent = <&r_pio>;
+ interrupts = <0 7 IRQ_TYPE_LEVEL_LOW>; /* PL7 */
+ interrupt-names = "host-wake";
+ };
+
+};
+
+&mmc2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc2_8bit_pins>;
+ vmmc-supply = <®_vcc3v3>;
+ bus-width = <8>;
+ non-removable;
+ cap-mmc-hw-reset;
+ status = "disabled";
+};
+
+&ohci0 {
+ status = "okay";
+};
+
+&ohci1 {
+ status = "okay";
+};
+
+&ohci2 {
+ status = "okay";
+};
+
+&ohci3 {
+ status = "okay";
+};
+
+&i2c1 {
+ status = "disabled"; /* PA19,PA18 */
+};
+
+&i2c0 {
+ status = "disabled"; /* PA11, PA12 */
+};
+
+&r_i2c {
+ status = "okay";
+
+ axp22x: pmic@34 {
+ compatible = "x-powers,axp221";
+ reg = <0x34>;
+ interrupt-parent = <&r_intc>;
+ interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+ };
+};
+
+#include "arm/axp22x.dtsi"
+
+&ac_power_supply {
+ status = "okay";
+};
+
+®_aldo2 { /* VCC-PG 1.8 */
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-pg";
+};
+
+®_aldo3 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-pll-avcc";
+};
+
+®_dc1sw {
+ regulator-name = "vcc-phy";
+};
+
+®_dcdc1 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-3v3";
+};
+
+®_dcdc2 {
+ regulator-always-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1360000>;
+ regulator-name = "vdd-cpux-a";
+};
+
+®_dcdc3 {
+ regulator-always-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1360000>;
+ regulator-name = "vdd-cpux-b";
+};
+
+/* DCDC3 is polyphased with DCDC2 */
+
+/*
+ * The DRAM chips used by rbs-h5 boards are DDR3 -compatibl
+ *
+ */
+®_dcdc5 {
+ regulator-always-on;
+ regulator-min-microvolt = <1500000>;
+ regulator-max-microvolt = <1500000>;
+ regulator-name = "vcc-dram";
+};
+
+®_dldo1 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-1";
+};
+
+®_dldo2 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-2";
+};
+
+®_dldo3 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-3";
+};
+
+®_dldo4 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-4";
+};
+ /* VCC-wifi-IO 1.8 */
+®_eldo1 {
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-wifi-io-1";
+};
+
+®_eldo2 {
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-wifi-io-2";
+};
+
+®_eldo3 {
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-wifi-io-3";
+};
+
+
+®_rtc_ldo {
+ regulator-name = "vcc-rtc";
+};
+
+&spi0 {
+ pinctrl-names = "default", "default";
+ pinctrl-1 = <&spi0_cs1>;
+ cs-gpios = <0>, <&pio 0 3 0>; /* PA3 */
+
+ status = "disabled";
+ spidev@0 {
+ compatible = "rohm,dh2228fv";
+ status = "okay";
+ reg = <0>;
+ spi-max-frequency = <1000000>;
+ };
+ spidev@1 {
+ compatible = "rohm,dh2228fv";
+ status = "okay";
+ reg = <1>;
+ spi-max-frequency = <1000000>;
+ };
+};
+
+&spi1 {
+ pinctrl-names = "default", "default";
+
+ status = "disabled";
+ spidev@0 {
+ compatible = "rohm,dh2228fv";
+ status = "okay";
+ reg = <0>;
+ spi-max-frequency = <1000000>;
+ };
+};
+
+&pio {
+ spi0_cs1: spi0_cs1 {
+ pins = "PA3";
+ function = "gpio_out";
+ output-high;
+ };
+};
+
+
+&r_pwm {
+ status = "disabled";
+};
+
+/* to debag serial */
+&uart0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_pa_pins>;
+ status = "okay";
+};
+
+/* to bt-wifi module */
+&uart1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart1_pins>, <&uart1_rts_cts_pins>;
+ uart-has-rtscts;
+ status = "okay";
+
+ bluetooth {
+ compatible = "brcm,bcm43438-bt";
+ clocks = <&rtc 1>;
+ clock-names = "lpo";
+ device-wakeup-gpios = <&r_pio 0 4 GPIO_ACTIVE_HIGH>; /* PL4 AP-WAKE-BT */
+ host-wakeup-gpios = <&r_pio 0 6 GPIO_ACTIVE_HIGH>; /* PL6 BT-WAKE-AP */
+ shutdown-gpios = <&r_pio 0 5 GPIO_ACTIVE_HIGH>; /* PL5 BT-RST-N */
+ max-speed = <1500000>;
+ };
+};
+
+&uart2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart2_pins>, <&uart2_rts_cts_pins>;
+ status = "disabled";
+};
+
+&r_uart {
+ pinctrl-names = "default";
+ pinctrl-0 = <&r_uart_pins>;
+ status = "disabled";
+};
+
+&usb_otg {
+ dr_mode = "host";
+ status = "okay";
+};
+
+&usbphy {
+ status = "okay";
+};
+
+
Index: v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-repka-pi3-1.4ghz.dts
===================================================================
--- v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-repka-pi3-1.4ghz.dts (nonexistent)
+++ v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-repka-pi3-1.4ghz.dts (revision 385)
@@ -0,0 +1,425 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+// Copyright (C) 2016 ARM Ltd.
+
+/dts-v1/;
+#include "sun50i-h5.dtsi"
+#include "sun50i-h5-cpu-opp-1.4ghz.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
+
+/ {
+ model = "Repka-Pi3-H5";
+ repka-freq = "1.4 GHz";
+ repka-pinout = "1";
+ compatible = "rbs,repka-pi3", "allwinner,sun50i-h5";
+
+ reg_vcc3v3: vcc3v3 {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc3v3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ aliases {
+ mmc0 = &mmc0;
+ ethernet0 = &emac;
+ serial0 = &uart0;
+ serial1 = &uart1;
+ spi0 = &spi0;
+ spi1 = &spi1;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ connector {
+ compatible = "hdmi-connector";
+ type = "a";
+
+ port {
+ hdmi_con_in: endpoint {
+ remote-endpoint = <&hdmi_out_con>;
+ };
+ };
+ };
+
+ ext_osc32k: ext_osc32k_clk {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <32768>;
+ clock-output-names = "ext_osc32k";
+ };
+
+ leds {
+ compatible = "gpio-leds";
+
+ status {
+ label = "rbs:red:status";
+ gpios = <&pio 0 20 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "heartbeat";
+ };
+ };
+
+ wifi_pwrseq: wifi_pwrseq {
+ compatible = "mmc-pwrseq-simple";
+ reset-gpios = <&r_pio 0 8 GPIO_ACTIVE_LOW>;
+ post-power-on-delay-ms = <200>;
+ };
+
+};
+
+&codec {
+ allwinner,audio-routing =
+ "Line Out", "LINEOUT",
+ "MIC1", "Mic",
+ "Mic", "MBIAS";
+ status = "okay";
+};
+
+&cpu0 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&cpu1 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&cpu2 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&cpu3 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&de {
+ status = "okay";
+};
+
+&ehci0 {
+ status = "okay";
+};
+
+&ehci1 {
+ status = "okay";
+};
+
+&ehci2 {
+ status = "okay";
+};
+
+&ehci3 {
+ status = "okay";
+};
+
+&emac {
+ phy-handle = <&int_mii_phy>;
+ phy-mode = "mii";
+ allwinner,leds-active-low;
+ status = "okay";
+};
+
+&hdmi {
+ status = "okay";
+};
+
+&hdmi_out {
+ hdmi_out_con: endpoint {
+ remote-endpoint = <&hdmi_con_in>;
+ };
+};
+
+&i2s2 {
+ status = "okay";
+};
+
+&sound_hdmi {
+ status = "okay";
+};
+
+&ir {
+ pinctrl-names = "default";
+ pinctrl-0 = <&r_ir_rx_pin>;
+ status = "disabled";
+};
+
+&rtc {
+ clocks = <&ext_osc32k>;
+};
+
+&mmc0 {
+ vmmc-supply = <®_vcc3v3>;
+ bus-width = <4>;
+ cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>; /* PF6 */
+ status = "okay";
+};
+
+&mmc1 {
+ vmmc-supply = <®_vcc3v3>;
+ mmc-pwrseq = <&wifi_pwrseq>;
+ bus-width = <4>;
+ non-removable;
+ status = "okay";
+
+ brcmf: wifi@1 {
+ reg = <1>;
+ compatible = "brcm,bcm4329-fmac";
+ interrupt-parent = <&r_pio>;
+ interrupts = <0 7 IRQ_TYPE_LEVEL_LOW>; /* PL7 */
+ interrupt-names = "host-wake";
+ };
+
+};
+
+&mmc2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc2_8bit_pins>;
+ vmmc-supply = <®_vcc3v3>;
+ bus-width = <8>;
+ non-removable;
+ cap-mmc-hw-reset;
+ status = "disabled";
+};
+
+&ohci0 {
+ status = "okay";
+};
+
+&ohci1 {
+ status = "okay";
+};
+
+&ohci2 {
+ status = "okay";
+};
+
+&ohci3 {
+ status = "okay";
+};
+
+&i2c1 {
+ status = "disabled"; /* PA19,PA18 */
+};
+
+&i2c0 {
+ status = "disabled"; /* PA11, PA12 */
+};
+
+&r_i2c {
+ status = "okay";
+
+ axp22x: pmic@34 {
+ compatible = "x-powers,axp221";
+ reg = <0x34>;
+ interrupt-parent = <&r_intc>;
+ interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+ };
+};
+
+#include "arm/axp22x.dtsi"
+
+&ac_power_supply {
+ status = "okay";
+};
+
+®_aldo2 { /* VCC-PG 1.8 */
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-pg";
+};
+
+®_aldo3 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-pll-avcc";
+};
+
+®_dc1sw {
+ regulator-name = "vcc-phy";
+};
+
+®_dcdc1 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-3v3";
+};
+
+®_dcdc2 {
+ regulator-always-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1360000>;
+ regulator-name = "vdd-cpux-a";
+};
+
+®_dcdc3 {
+ regulator-always-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1360000>;
+ regulator-name = "vdd-cpux-b";
+};
+
+/* DCDC3 is polyphased with DCDC2 */
+
+/*
+ * The DRAM chips used by rbs-h5 boards are DDR3 -compatibl
+ *
+ */
+®_dcdc5 {
+ regulator-always-on;
+ regulator-min-microvolt = <1500000>;
+ regulator-max-microvolt = <1500000>;
+ regulator-name = "vcc-dram";
+};
+
+®_dldo1 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-1";
+};
+
+®_dldo2 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-2";
+};
+
+®_dldo3 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-3";
+};
+
+®_dldo4 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-4";
+};
+ /* VCC-wifi-IO 1.8 */
+®_eldo1 {
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-wifi-io-1";
+};
+
+®_eldo2 {
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-wifi-io-2";
+};
+
+®_eldo3 {
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-wifi-io-3";
+};
+
+
+®_rtc_ldo {
+ regulator-name = "vcc-rtc";
+};
+
+&spi0 {
+ pinctrl-names = "default", "default";
+ pinctrl-1 = <&spi0_cs1>;
+ cs-gpios = <0>, <&pio 0 3 0>; /* PA3 */
+
+ status = "disabled";
+ spidev@0 {
+ compatible = "rohm,dh2228fv";
+ status = "okay";
+ reg = <0>;
+ spi-max-frequency = <1000000>;
+ };
+ spidev@1 {
+ compatible = "rohm,dh2228fv";
+ status = "okay";
+ reg = <1>;
+ spi-max-frequency = <1000000>;
+ };
+};
+
+&spi1 {
+ pinctrl-names = "default", "default";
+
+ status = "disabled";
+ spidev@0 {
+ compatible = "rohm,dh2228fv";
+ status = "okay";
+ reg = <0>;
+ spi-max-frequency = <1000000>;
+ };
+};
+
+&pio {
+ spi0_cs1: spi0_cs1 {
+ pins = "PA3";
+ function = "gpio_out";
+ output-high;
+ };
+};
+
+
+&r_pwm {
+ status = "disabled";
+};
+
+/* to debag serial */
+&uart0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_pa_pins>;
+ status = "okay";
+};
+
+/* to bt-wifi module */
+&uart1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart1_pins>, <&uart1_rts_cts_pins>;
+ uart-has-rtscts;
+ status = "okay";
+
+ bluetooth {
+ compatible = "brcm,bcm43438-bt";
+ clocks = <&rtc 1>;
+ clock-names = "lpo";
+ device-wakeup-gpios = <&r_pio 0 4 GPIO_ACTIVE_HIGH>; /* PL4 AP-WAKE-BT */
+ host-wakeup-gpios = <&r_pio 0 6 GPIO_ACTIVE_HIGH>; /* PL6 BT-WAKE-AP */
+ shutdown-gpios = <&r_pio 0 5 GPIO_ACTIVE_HIGH>; /* PL5 BT-RST-N */
+ max-speed = <1500000>;
+ };
+};
+
+&uart2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart2_pins>, <&uart2_rts_cts_pins>;
+ status = "disabled";
+};
+
+&r_uart {
+ pinctrl-names = "default";
+ pinctrl-0 = <&r_uart_pins>;
+ status = "disabled";
+};
+
+&usb_otg {
+ dr_mode = "host";
+ status = "okay";
+};
+
+&usbphy {
+ status = "okay";
+};
+
+
Index: v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-repka-pi3-alt-1.0ghz.dts
===================================================================
--- v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-repka-pi3-alt-1.0ghz.dts (nonexistent)
+++ v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-repka-pi3-alt-1.0ghz.dts (revision 385)
@@ -0,0 +1,425 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+// Copyright (C) 2016 ARM Ltd.
+
+/dts-v1/;
+#include "sun50i-h5.dtsi"
+#include "sun50i-h5-cpu-opp-1.0ghz.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
+
+/ {
+ model = "Repka-Pi3-H5";
+ repka-freq = "1.0 GHz";
+ repka-pinout = "2";
+ compatible = "rbs,repka-pi3", "allwinner,sun50i-h5";
+
+ reg_vcc3v3: vcc3v3 {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc3v3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ aliases {
+ mmc0 = &mmc0;
+ ethernet0 = &emac;
+ serial0 = &uart0;
+ serial1 = &uart1;
+ spi0 = &spi0;
+ spi1 = &spi1;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ connector {
+ compatible = "hdmi-connector";
+ type = "a";
+
+ port {
+ hdmi_con_in: endpoint {
+ remote-endpoint = <&hdmi_out_con>;
+ };
+ };
+ };
+
+ ext_osc32k: ext_osc32k_clk {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <32768>;
+ clock-output-names = "ext_osc32k";
+ };
+
+ leds {
+ compatible = "gpio-leds";
+
+ status {
+ label = "rbs:red:status";
+ gpios = <&pio 0 20 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "heartbeat";
+ };
+ };
+
+ wifi_pwrseq: wifi_pwrseq {
+ compatible = "mmc-pwrseq-simple";
+ reset-gpios = <&r_pio 0 8 GPIO_ACTIVE_LOW>;
+ post-power-on-delay-ms = <200>;
+ };
+
+};
+
+&codec {
+ allwinner,audio-routing =
+ "Line Out", "LINEOUT",
+ "MIC1", "Mic",
+ "Mic", "MBIAS";
+ status = "okay";
+};
+
+&cpu0 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&cpu1 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&cpu2 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&cpu3 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&de {
+ status = "okay";
+};
+
+&ehci0 {
+ status = "okay";
+};
+
+&ehci1 {
+ status = "okay";
+};
+
+&ehci2 {
+ status = "okay";
+};
+
+&ehci3 {
+ status = "okay";
+};
+
+&emac {
+ phy-handle = <&int_mii_phy>;
+ phy-mode = "mii";
+ allwinner,leds-active-low;
+ status = "okay";
+};
+
+&hdmi {
+ status = "okay";
+};
+
+&hdmi_out {
+ hdmi_out_con: endpoint {
+ remote-endpoint = <&hdmi_con_in>;
+ };
+};
+
+&i2s2 {
+ status = "okay";
+};
+
+&sound_hdmi {
+ status = "okay";
+};
+
+&ir {
+ pinctrl-names = "default";
+ pinctrl-0 = <&r_ir_rx_pin>;
+ status = "disabled";
+};
+
+&rtc {
+ clocks = <&ext_osc32k>;
+};
+
+&mmc0 {
+ vmmc-supply = <®_vcc3v3>;
+ bus-width = <4>;
+ cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>; /* PF6 */
+ status = "okay";
+};
+
+&mmc1 {
+ vmmc-supply = <®_vcc3v3>;
+ mmc-pwrseq = <&wifi_pwrseq>;
+ bus-width = <4>;
+ non-removable;
+ status = "okay";
+
+ brcmf: wifi@1 {
+ reg = <1>;
+ compatible = "brcm,bcm4329-fmac";
+ interrupt-parent = <&r_pio>;
+ interrupts = <0 7 IRQ_TYPE_LEVEL_LOW>; /* PL7 */
+ interrupt-names = "host-wake";
+ };
+
+};
+
+&mmc2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc2_8bit_pins>;
+ vmmc-supply = <®_vcc3v3>;
+ bus-width = <8>;
+ non-removable;
+ cap-mmc-hw-reset;
+ status = "disabled";
+};
+
+&ohci0 {
+ status = "okay";
+};
+
+&ohci1 {
+ status = "okay";
+};
+
+&ohci2 {
+ status = "okay";
+};
+
+&ohci3 {
+ status = "okay";
+};
+
+&i2c1 {
+ status = "disabled"; /* PA19,PA18 */
+};
+
+&i2c0 {
+ status = "okay"; /* PA11, PA12 */
+};
+
+&r_i2c {
+ status = "okay";
+
+ axp22x: pmic@34 {
+ compatible = "x-powers,axp221";
+ reg = <0x34>;
+ interrupt-parent = <&r_intc>;
+ interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+ };
+};
+
+#include "arm/axp22x.dtsi"
+
+&ac_power_supply {
+ status = "okay";
+};
+
+®_aldo2 { /* VCC-PG 1.8 */
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-pg";
+};
+
+®_aldo3 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-pll-avcc";
+};
+
+®_dc1sw {
+ regulator-name = "vcc-phy";
+};
+
+®_dcdc1 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-3v3";
+};
+
+®_dcdc2 {
+ regulator-always-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1360000>;
+ regulator-name = "vdd-cpux-a";
+};
+
+®_dcdc3 {
+ regulator-always-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1360000>;
+ regulator-name = "vdd-cpux-b";
+};
+
+/* DCDC3 is polyphased with DCDC2 */
+
+/*
+ * The DRAM chips used by rbs-h5 boards are DDR3 -compatibl
+ *
+ */
+®_dcdc5 {
+ regulator-always-on;
+ regulator-min-microvolt = <1500000>;
+ regulator-max-microvolt = <1500000>;
+ regulator-name = "vcc-dram";
+};
+
+®_dldo1 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-1";
+};
+
+®_dldo2 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-2";
+};
+
+®_dldo3 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-3";
+};
+
+®_dldo4 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-4";
+};
+ /* VCC-wifi-IO 1.8 */
+®_eldo1 {
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-wifi-io-1";
+};
+
+®_eldo2 {
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-wifi-io-2";
+};
+
+®_eldo3 {
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-wifi-io-3";
+};
+
+
+®_rtc_ldo {
+ regulator-name = "vcc-rtc";
+};
+
+&spi0 {
+ pinctrl-names = "default", "default";
+ pinctrl-1 = <&spi0_cs1>;
+ cs-gpios = <0>, <&pio 0 3 0>; /* PA3 */
+
+ status = "okay";
+ spidev@0 {
+ compatible = "rohm,dh2228fv";
+ status = "okay";
+ reg = <0>;
+ spi-max-frequency = <1000000>;
+ };
+ spidev@1 {
+ compatible = "rohm,dh2228fv";
+ status = "okay";
+ reg = <1>;
+ spi-max-frequency = <1000000>;
+ };
+};
+
+&spi1 {
+ pinctrl-names = "default", "default";
+
+ status = "okay";
+ spidev@0 {
+ compatible = "rohm,dh2228fv";
+ status = "okay";
+ reg = <0>;
+ spi-max-frequency = <1000000>;
+ };
+};
+
+&pio {
+ spi0_cs1: spi0_cs1 {
+ pins = "PA3";
+ function = "gpio_out";
+ output-high;
+ };
+};
+
+
+&r_pwm {
+ status = "disabled";
+};
+
+/* to debag serial */
+&uart0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_pa_pins>;
+ status = "okay";
+};
+
+/* to bt-wifi module */
+&uart1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart1_pins>, <&uart1_rts_cts_pins>;
+ uart-has-rtscts;
+ status = "okay";
+
+ bluetooth {
+ compatible = "brcm,bcm43438-bt";
+ clocks = <&rtc 1>;
+ clock-names = "lpo";
+ device-wakeup-gpios = <&r_pio 0 4 GPIO_ACTIVE_HIGH>; /* PL4 AP-WAKE-BT */
+ host-wakeup-gpios = <&r_pio 0 6 GPIO_ACTIVE_HIGH>; /* PL6 BT-WAKE-AP */
+ shutdown-gpios = <&r_pio 0 5 GPIO_ACTIVE_HIGH>; /* PL5 BT-RST-N */
+ max-speed = <1500000>;
+ };
+};
+
+&uart2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart2_pins>, <&uart2_rts_cts_pins>;
+ status = "disabled";
+};
+
+&r_uart {
+ pinctrl-names = "default";
+ pinctrl-0 = <&r_uart_pins>;
+ status = "disabled";
+};
+
+&usb_otg {
+ dr_mode = "host";
+ status = "okay";
+};
+
+&usbphy {
+ status = "okay";
+};
+
+
Index: v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-repka-pi3-alt-1.2ghz.dts
===================================================================
--- v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-repka-pi3-alt-1.2ghz.dts (nonexistent)
+++ v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-repka-pi3-alt-1.2ghz.dts (revision 385)
@@ -0,0 +1,425 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+// Copyright (C) 2016 ARM Ltd.
+
+/dts-v1/;
+#include "sun50i-h5.dtsi"
+#include "sun50i-h5-cpu-opp-1.2ghz.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
+
+/ {
+ model = "Repka-Pi3-H5";
+ repka-freq = "1.2 GHz";
+ repka-pinout = "2";
+ compatible = "rbs,repka-pi3", "allwinner,sun50i-h5";
+
+ reg_vcc3v3: vcc3v3 {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc3v3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ aliases {
+ mmc0 = &mmc0;
+ ethernet0 = &emac;
+ serial0 = &uart0;
+ serial1 = &uart1;
+ spi0 = &spi0;
+ spi1 = &spi1;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ connector {
+ compatible = "hdmi-connector";
+ type = "a";
+
+ port {
+ hdmi_con_in: endpoint {
+ remote-endpoint = <&hdmi_out_con>;
+ };
+ };
+ };
+
+ ext_osc32k: ext_osc32k_clk {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <32768>;
+ clock-output-names = "ext_osc32k";
+ };
+
+ leds {
+ compatible = "gpio-leds";
+
+ status {
+ label = "rbs:red:status";
+ gpios = <&pio 0 20 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "heartbeat";
+ };
+ };
+
+ wifi_pwrseq: wifi_pwrseq {
+ compatible = "mmc-pwrseq-simple";
+ reset-gpios = <&r_pio 0 8 GPIO_ACTIVE_LOW>;
+ post-power-on-delay-ms = <200>;
+ };
+
+};
+
+&codec {
+ allwinner,audio-routing =
+ "Line Out", "LINEOUT",
+ "MIC1", "Mic",
+ "Mic", "MBIAS";
+ status = "okay";
+};
+
+&cpu0 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&cpu1 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&cpu2 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&cpu3 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&de {
+ status = "okay";
+};
+
+&ehci0 {
+ status = "okay";
+};
+
+&ehci1 {
+ status = "okay";
+};
+
+&ehci2 {
+ status = "okay";
+};
+
+&ehci3 {
+ status = "okay";
+};
+
+&emac {
+ phy-handle = <&int_mii_phy>;
+ phy-mode = "mii";
+ allwinner,leds-active-low;
+ status = "okay";
+};
+
+&hdmi {
+ status = "okay";
+};
+
+&hdmi_out {
+ hdmi_out_con: endpoint {
+ remote-endpoint = <&hdmi_con_in>;
+ };
+};
+
+&i2s2 {
+ status = "okay";
+};
+
+&sound_hdmi {
+ status = "okay";
+};
+
+&ir {
+ pinctrl-names = "default";
+ pinctrl-0 = <&r_ir_rx_pin>;
+ status = "disabled";
+};
+
+&rtc {
+ clocks = <&ext_osc32k>;
+};
+
+&mmc0 {
+ vmmc-supply = <®_vcc3v3>;
+ bus-width = <4>;
+ cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>; /* PF6 */
+ status = "okay";
+};
+
+&mmc1 {
+ vmmc-supply = <®_vcc3v3>;
+ mmc-pwrseq = <&wifi_pwrseq>;
+ bus-width = <4>;
+ non-removable;
+ status = "okay";
+
+ brcmf: wifi@1 {
+ reg = <1>;
+ compatible = "brcm,bcm4329-fmac";
+ interrupt-parent = <&r_pio>;
+ interrupts = <0 7 IRQ_TYPE_LEVEL_LOW>; /* PL7 */
+ interrupt-names = "host-wake";
+ };
+
+};
+
+&mmc2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc2_8bit_pins>;
+ vmmc-supply = <®_vcc3v3>;
+ bus-width = <8>;
+ non-removable;
+ cap-mmc-hw-reset;
+ status = "disabled";
+};
+
+&ohci0 {
+ status = "okay";
+};
+
+&ohci1 {
+ status = "okay";
+};
+
+&ohci2 {
+ status = "okay";
+};
+
+&ohci3 {
+ status = "okay";
+};
+
+&i2c1 {
+ status = "disabled"; /* PA19,PA18 */
+};
+
+&i2c0 {
+ status = "okay"; /* PA11, PA12 */
+};
+
+&r_i2c {
+ status = "okay";
+
+ axp22x: pmic@34 {
+ compatible = "x-powers,axp221";
+ reg = <0x34>;
+ interrupt-parent = <&r_intc>;
+ interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+ };
+};
+
+#include "arm/axp22x.dtsi"
+
+&ac_power_supply {
+ status = "okay";
+};
+
+®_aldo2 { /* VCC-PG 1.8 */
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-pg";
+};
+
+®_aldo3 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-pll-avcc";
+};
+
+®_dc1sw {
+ regulator-name = "vcc-phy";
+};
+
+®_dcdc1 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-3v3";
+};
+
+®_dcdc2 {
+ regulator-always-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1360000>;
+ regulator-name = "vdd-cpux-a";
+};
+
+®_dcdc3 {
+ regulator-always-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1360000>;
+ regulator-name = "vdd-cpux-b";
+};
+
+/* DCDC3 is polyphased with DCDC2 */
+
+/*
+ * The DRAM chips used by rbs-h5 boards are DDR3 -compatibl
+ *
+ */
+®_dcdc5 {
+ regulator-always-on;
+ regulator-min-microvolt = <1500000>;
+ regulator-max-microvolt = <1500000>;
+ regulator-name = "vcc-dram";
+};
+
+®_dldo1 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-1";
+};
+
+®_dldo2 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-2";
+};
+
+®_dldo3 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-3";
+};
+
+®_dldo4 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-4";
+};
+ /* VCC-wifi-IO 1.8 */
+®_eldo1 {
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-wifi-io-1";
+};
+
+®_eldo2 {
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-wifi-io-2";
+};
+
+®_eldo3 {
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-wifi-io-3";
+};
+
+
+®_rtc_ldo {
+ regulator-name = "vcc-rtc";
+};
+
+&spi0 {
+ pinctrl-names = "default", "default";
+ pinctrl-1 = <&spi0_cs1>;
+ cs-gpios = <0>, <&pio 0 3 0>; /* PA3 */
+
+ status = "okay";
+ spidev@0 {
+ compatible = "rohm,dh2228fv";
+ status = "okay";
+ reg = <0>;
+ spi-max-frequency = <1000000>;
+ };
+ spidev@1 {
+ compatible = "rohm,dh2228fv";
+ status = "okay";
+ reg = <1>;
+ spi-max-frequency = <1000000>;
+ };
+};
+
+&spi1 {
+ pinctrl-names = "default", "default";
+
+ status = "okay";
+ spidev@0 {
+ compatible = "rohm,dh2228fv";
+ status = "okay";
+ reg = <0>;
+ spi-max-frequency = <1000000>;
+ };
+};
+
+&pio {
+ spi0_cs1: spi0_cs1 {
+ pins = "PA3";
+ function = "gpio_out";
+ output-high;
+ };
+};
+
+
+&r_pwm {
+ status = "disabled";
+};
+
+/* to debag serial */
+&uart0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_pa_pins>;
+ status = "okay";
+};
+
+/* to bt-wifi module */
+&uart1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart1_pins>, <&uart1_rts_cts_pins>;
+ uart-has-rtscts;
+ status = "okay";
+
+ bluetooth {
+ compatible = "brcm,bcm43438-bt";
+ clocks = <&rtc 1>;
+ clock-names = "lpo";
+ device-wakeup-gpios = <&r_pio 0 4 GPIO_ACTIVE_HIGH>; /* PL4 AP-WAKE-BT */
+ host-wakeup-gpios = <&r_pio 0 6 GPIO_ACTIVE_HIGH>; /* PL6 BT-WAKE-AP */
+ shutdown-gpios = <&r_pio 0 5 GPIO_ACTIVE_HIGH>; /* PL5 BT-RST-N */
+ max-speed = <1500000>;
+ };
+};
+
+&uart2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart2_pins>, <&uart2_rts_cts_pins>;
+ status = "disabled";
+};
+
+&r_uart {
+ pinctrl-names = "default";
+ pinctrl-0 = <&r_uart_pins>;
+ status = "disabled";
+};
+
+&usb_otg {
+ dr_mode = "host";
+ status = "okay";
+};
+
+&usbphy {
+ status = "okay";
+};
+
+
Index: v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-repka-pi3-alt-1.4ghz.dts
===================================================================
--- v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-repka-pi3-alt-1.4ghz.dts (nonexistent)
+++ v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-repka-pi3-alt-1.4ghz.dts (revision 385)
@@ -0,0 +1,425 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+// Copyright (C) 2016 ARM Ltd.
+
+/dts-v1/;
+#include "sun50i-h5.dtsi"
+#include "sun50i-h5-cpu-opp-1.4ghz.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
+
+/ {
+ model = "Repka-Pi3-H5";
+ repka-freq = "1.4 GHz";
+ repka-pinout = "2";
+ compatible = "rbs,repka-pi3", "allwinner,sun50i-h5";
+
+ reg_vcc3v3: vcc3v3 {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc3v3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ aliases {
+ mmc0 = &mmc0;
+ ethernet0 = &emac;
+ serial0 = &uart0;
+ serial1 = &uart1;
+ spi0 = &spi0;
+ spi1 = &spi1;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ connector {
+ compatible = "hdmi-connector";
+ type = "a";
+
+ port {
+ hdmi_con_in: endpoint {
+ remote-endpoint = <&hdmi_out_con>;
+ };
+ };
+ };
+
+ ext_osc32k: ext_osc32k_clk {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <32768>;
+ clock-output-names = "ext_osc32k";
+ };
+
+ leds {
+ compatible = "gpio-leds";
+
+ status {
+ label = "rbs:red:status";
+ gpios = <&pio 0 20 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "heartbeat";
+ };
+ };
+
+ wifi_pwrseq: wifi_pwrseq {
+ compatible = "mmc-pwrseq-simple";
+ reset-gpios = <&r_pio 0 8 GPIO_ACTIVE_LOW>;
+ post-power-on-delay-ms = <200>;
+ };
+
+};
+
+&codec {
+ allwinner,audio-routing =
+ "Line Out", "LINEOUT",
+ "MIC1", "Mic",
+ "Mic", "MBIAS";
+ status = "okay";
+};
+
+&cpu0 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&cpu1 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&cpu2 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&cpu3 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&de {
+ status = "okay";
+};
+
+&ehci0 {
+ status = "okay";
+};
+
+&ehci1 {
+ status = "okay";
+};
+
+&ehci2 {
+ status = "okay";
+};
+
+&ehci3 {
+ status = "okay";
+};
+
+&emac {
+ phy-handle = <&int_mii_phy>;
+ phy-mode = "mii";
+ allwinner,leds-active-low;
+ status = "okay";
+};
+
+&hdmi {
+ status = "okay";
+};
+
+&hdmi_out {
+ hdmi_out_con: endpoint {
+ remote-endpoint = <&hdmi_con_in>;
+ };
+};
+
+&i2s2 {
+ status = "okay";
+};
+
+&sound_hdmi {
+ status = "okay";
+};
+
+&ir {
+ pinctrl-names = "default";
+ pinctrl-0 = <&r_ir_rx_pin>;
+ status = "disabled";
+};
+
+&rtc {
+ clocks = <&ext_osc32k>;
+};
+
+&mmc0 {
+ vmmc-supply = <®_vcc3v3>;
+ bus-width = <4>;
+ cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>; /* PF6 */
+ status = "okay";
+};
+
+&mmc1 {
+ vmmc-supply = <®_vcc3v3>;
+ mmc-pwrseq = <&wifi_pwrseq>;
+ bus-width = <4>;
+ non-removable;
+ status = "okay";
+
+ brcmf: wifi@1 {
+ reg = <1>;
+ compatible = "brcm,bcm4329-fmac";
+ interrupt-parent = <&r_pio>;
+ interrupts = <0 7 IRQ_TYPE_LEVEL_LOW>; /* PL7 */
+ interrupt-names = "host-wake";
+ };
+
+};
+
+&mmc2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc2_8bit_pins>;
+ vmmc-supply = <®_vcc3v3>;
+ bus-width = <8>;
+ non-removable;
+ cap-mmc-hw-reset;
+ status = "disabled";
+};
+
+&ohci0 {
+ status = "okay";
+};
+
+&ohci1 {
+ status = "okay";
+};
+
+&ohci2 {
+ status = "okay";
+};
+
+&ohci3 {
+ status = "okay";
+};
+
+&i2c1 {
+ status = "disabled"; /* PA19,PA18 */
+};
+
+&i2c0 {
+ status = "okay"; /* PA11, PA12 */
+};
+
+&r_i2c {
+ status = "okay";
+
+ axp22x: pmic@34 {
+ compatible = "x-powers,axp221";
+ reg = <0x34>;
+ interrupt-parent = <&r_intc>;
+ interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+ };
+};
+
+#include "arm/axp22x.dtsi"
+
+&ac_power_supply {
+ status = "okay";
+};
+
+®_aldo2 { /* VCC-PG 1.8 */
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-pg";
+};
+
+®_aldo3 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-pll-avcc";
+};
+
+®_dc1sw {
+ regulator-name = "vcc-phy";
+};
+
+®_dcdc1 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-3v3";
+};
+
+®_dcdc2 {
+ regulator-always-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1360000>;
+ regulator-name = "vdd-cpux-a";
+};
+
+®_dcdc3 {
+ regulator-always-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1360000>;
+ regulator-name = "vdd-cpux-b";
+};
+
+/* DCDC3 is polyphased with DCDC2 */
+
+/*
+ * The DRAM chips used by rbs-h5 boards are DDR3 -compatibl
+ *
+ */
+®_dcdc5 {
+ regulator-always-on;
+ regulator-min-microvolt = <1500000>;
+ regulator-max-microvolt = <1500000>;
+ regulator-name = "vcc-dram";
+};
+
+®_dldo1 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-1";
+};
+
+®_dldo2 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-2";
+};
+
+®_dldo3 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-3";
+};
+
+®_dldo4 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-4";
+};
+ /* VCC-wifi-IO 1.8 */
+®_eldo1 {
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-wifi-io-1";
+};
+
+®_eldo2 {
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-wifi-io-2";
+};
+
+®_eldo3 {
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-wifi-io-3";
+};
+
+
+®_rtc_ldo {
+ regulator-name = "vcc-rtc";
+};
+
+&spi0 {
+ pinctrl-names = "default", "default";
+ pinctrl-1 = <&spi0_cs1>;
+ cs-gpios = <0>, <&pio 0 3 0>; /* PA3 */
+
+ status = "okay";
+ spidev@0 {
+ compatible = "rohm,dh2228fv";
+ status = "okay";
+ reg = <0>;
+ spi-max-frequency = <1000000>;
+ };
+ spidev@1 {
+ compatible = "rohm,dh2228fv";
+ status = "okay";
+ reg = <1>;
+ spi-max-frequency = <1000000>;
+ };
+};
+
+&spi1 {
+ pinctrl-names = "default", "default";
+
+ status = "okay";
+ spidev@0 {
+ compatible = "rohm,dh2228fv";
+ status = "okay";
+ reg = <0>;
+ spi-max-frequency = <1000000>;
+ };
+};
+
+&pio {
+ spi0_cs1: spi0_cs1 {
+ pins = "PA3";
+ function = "gpio_out";
+ output-high;
+ };
+};
+
+
+&r_pwm {
+ status = "disabled";
+};
+
+/* to debag serial */
+&uart0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_pa_pins>;
+ status = "okay";
+};
+
+/* to bt-wifi module */
+&uart1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart1_pins>, <&uart1_rts_cts_pins>;
+ uart-has-rtscts;
+ status = "okay";
+
+ bluetooth {
+ compatible = "brcm,bcm43438-bt";
+ clocks = <&rtc 1>;
+ clock-names = "lpo";
+ device-wakeup-gpios = <&r_pio 0 4 GPIO_ACTIVE_HIGH>; /* PL4 AP-WAKE-BT */
+ host-wakeup-gpios = <&r_pio 0 6 GPIO_ACTIVE_HIGH>; /* PL6 BT-WAKE-AP */
+ shutdown-gpios = <&r_pio 0 5 GPIO_ACTIVE_HIGH>; /* PL5 BT-RST-N */
+ max-speed = <1500000>;
+ };
+};
+
+&uart2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart2_pins>, <&uart2_rts_cts_pins>;
+ status = "disabled";
+};
+
+&r_uart {
+ pinctrl-names = "default";
+ pinctrl-0 = <&r_uart_pins>;
+ status = "disabled";
+};
+
+&usb_otg {
+ dr_mode = "host";
+ status = "okay";
+};
+
+&usbphy {
+ status = "okay";
+};
+
+
Index: v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-repka-pi3-alt-i2c2-1.0ghz.dts
===================================================================
--- v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-repka-pi3-alt-i2c2-1.0ghz.dts (nonexistent)
+++ v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-repka-pi3-alt-i2c2-1.0ghz.dts (revision 385)
@@ -0,0 +1,425 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+// Copyright (C) 2016 ARM Ltd.
+
+/dts-v1/;
+#include "sun50i-h5.dtsi"
+#include "sun50i-h5-cpu-opp-1.0ghz.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
+
+/ {
+ model = "Repka-Pi3-H5";
+ repka-freq = "1.0 GHz";
+ repka-pinout = "4";
+ compatible = "rbs,repka-pi3", "allwinner,sun50i-h5";
+
+ reg_vcc3v3: vcc3v3 {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc3v3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ aliases {
+ mmc0 = &mmc0;
+ ethernet0 = &emac;
+ serial0 = &uart0;
+ serial1 = &uart1;
+ spi0 = &spi0;
+ spi1 = &spi1;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ connector {
+ compatible = "hdmi-connector";
+ type = "a";
+
+ port {
+ hdmi_con_in: endpoint {
+ remote-endpoint = <&hdmi_out_con>;
+ };
+ };
+ };
+
+ ext_osc32k: ext_osc32k_clk {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <32768>;
+ clock-output-names = "ext_osc32k";
+ };
+
+ leds {
+ compatible = "gpio-leds";
+
+ status {
+ label = "rbs:red:status";
+ gpios = <&pio 0 20 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "heartbeat";
+ };
+ };
+
+ wifi_pwrseq: wifi_pwrseq {
+ compatible = "mmc-pwrseq-simple";
+ reset-gpios = <&r_pio 0 8 GPIO_ACTIVE_LOW>;
+ post-power-on-delay-ms = <200>;
+ };
+
+};
+
+&codec {
+ allwinner,audio-routing =
+ "Line Out", "LINEOUT",
+ "MIC1", "Mic",
+ "Mic", "MBIAS";
+ status = "okay";
+};
+
+&cpu0 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&cpu1 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&cpu2 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&cpu3 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&de {
+ status = "okay";
+};
+
+&ehci0 {
+ status = "okay";
+};
+
+&ehci1 {
+ status = "okay";
+};
+
+&ehci2 {
+ status = "okay";
+};
+
+&ehci3 {
+ status = "okay";
+};
+
+&emac {
+ phy-handle = <&int_mii_phy>;
+ phy-mode = "mii";
+ allwinner,leds-active-low;
+ status = "okay";
+};
+
+&hdmi {
+ status = "okay";
+};
+
+&hdmi_out {
+ hdmi_out_con: endpoint {
+ remote-endpoint = <&hdmi_con_in>;
+ };
+};
+
+&i2s2 {
+ status = "okay";
+};
+
+&sound_hdmi {
+ status = "okay";
+};
+
+&ir {
+ pinctrl-names = "default";
+ pinctrl-0 = <&r_ir_rx_pin>;
+ status = "disabled";
+};
+
+&rtc {
+ clocks = <&ext_osc32k>;
+};
+
+&mmc0 {
+ vmmc-supply = <®_vcc3v3>;
+ bus-width = <4>;
+ cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>; /* PF6 */
+ status = "okay";
+};
+
+&mmc1 {
+ vmmc-supply = <®_vcc3v3>;
+ mmc-pwrseq = <&wifi_pwrseq>;
+ bus-width = <4>;
+ non-removable;
+ status = "okay";
+
+ brcmf: wifi@1 {
+ reg = <1>;
+ compatible = "brcm,bcm4329-fmac";
+ interrupt-parent = <&r_pio>;
+ interrupts = <0 7 IRQ_TYPE_LEVEL_LOW>; /* PL7 */
+ interrupt-names = "host-wake";
+ };
+
+};
+
+&mmc2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc2_8bit_pins>;
+ vmmc-supply = <®_vcc3v3>;
+ bus-width = <8>;
+ non-removable;
+ cap-mmc-hw-reset;
+ status = "disabled";
+};
+
+&ohci0 {
+ status = "okay";
+};
+
+&ohci1 {
+ status = "okay";
+};
+
+&ohci2 {
+ status = "okay";
+};
+
+&ohci3 {
+ status = "okay";
+};
+
+&i2c1 {
+ status = "okay"; /* PA19,PA18 */
+};
+
+&i2c0 {
+ status = "okay"; /* PA11, PA12 */
+};
+
+&r_i2c {
+ status = "okay";
+
+ axp22x: pmic@34 {
+ compatible = "x-powers,axp221";
+ reg = <0x34>;
+ interrupt-parent = <&r_intc>;
+ interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+ };
+};
+
+#include "arm/axp22x.dtsi"
+
+&ac_power_supply {
+ status = "okay";
+};
+
+®_aldo2 { /* VCC-PG 1.8 */
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-pg";
+};
+
+®_aldo3 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-pll-avcc";
+};
+
+®_dc1sw {
+ regulator-name = "vcc-phy";
+};
+
+®_dcdc1 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-3v3";
+};
+
+®_dcdc2 {
+ regulator-always-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1360000>;
+ regulator-name = "vdd-cpux-a";
+};
+
+®_dcdc3 {
+ regulator-always-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1360000>;
+ regulator-name = "vdd-cpux-b";
+};
+
+/* DCDC3 is polyphased with DCDC2 */
+
+/*
+ * The DRAM chips used by rbs-h5 boards are DDR3 -compatibl
+ *
+ */
+®_dcdc5 {
+ regulator-always-on;
+ regulator-min-microvolt = <1500000>;
+ regulator-max-microvolt = <1500000>;
+ regulator-name = "vcc-dram";
+};
+
+®_dldo1 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-1";
+};
+
+®_dldo2 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-2";
+};
+
+®_dldo3 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-3";
+};
+
+®_dldo4 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-4";
+};
+ /* VCC-wifi-IO 1.8 */
+®_eldo1 {
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-wifi-io-1";
+};
+
+®_eldo2 {
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-wifi-io-2";
+};
+
+®_eldo3 {
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-wifi-io-3";
+};
+
+
+®_rtc_ldo {
+ regulator-name = "vcc-rtc";
+};
+
+&spi0 {
+ pinctrl-names = "default", "default";
+ pinctrl-1 = <&spi0_cs1>;
+ cs-gpios = <0>, <&pio 0 3 0>; /* PA3 */
+
+ status = "okay";
+ spidev@0 {
+ compatible = "rohm,dh2228fv";
+ status = "okay";
+ reg = <0>;
+ spi-max-frequency = <1000000>;
+ };
+ spidev@1 {
+ compatible = "rohm,dh2228fv";
+ status = "okay";
+ reg = <1>;
+ spi-max-frequency = <1000000>;
+ };
+};
+
+&spi1 {
+ pinctrl-names = "default", "default";
+
+ status = "okay";
+ spidev@0 {
+ compatible = "rohm,dh2228fv";
+ status = "okay";
+ reg = <0>;
+ spi-max-frequency = <1000000>;
+ };
+};
+
+&pio {
+ spi0_cs1: spi0_cs1 {
+ pins = "PA3";
+ function = "gpio_out";
+ output-high;
+ };
+};
+
+
+&r_pwm {
+ status = "disabled";
+};
+
+/* to debag serial */
+&uart0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_pa_pins>;
+ status = "okay";
+};
+
+/* to bt-wifi module */
+&uart1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart1_pins>, <&uart1_rts_cts_pins>;
+ uart-has-rtscts;
+ status = "okay";
+
+ bluetooth {
+ compatible = "brcm,bcm43438-bt";
+ clocks = <&rtc 1>;
+ clock-names = "lpo";
+ device-wakeup-gpios = <&r_pio 0 4 GPIO_ACTIVE_HIGH>; /* PL4 AP-WAKE-BT */
+ host-wakeup-gpios = <&r_pio 0 6 GPIO_ACTIVE_HIGH>; /* PL6 BT-WAKE-AP */
+ shutdown-gpios = <&r_pio 0 5 GPIO_ACTIVE_HIGH>; /* PL5 BT-RST-N */
+ max-speed = <1500000>;
+ };
+};
+
+&uart2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart2_pins>, <&uart2_rts_cts_pins>;
+ status = "disabled";
+};
+
+&r_uart {
+ pinctrl-names = "default";
+ pinctrl-0 = <&r_uart_pins>;
+ status = "disabled";
+};
+
+&usb_otg {
+ dr_mode = "host";
+ status = "okay";
+};
+
+&usbphy {
+ status = "okay";
+};
+
+
Index: v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-repka-pi3-alt-i2c2-1.2ghz.dts
===================================================================
--- v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-repka-pi3-alt-i2c2-1.2ghz.dts (nonexistent)
+++ v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-repka-pi3-alt-i2c2-1.2ghz.dts (revision 385)
@@ -0,0 +1,425 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+// Copyright (C) 2016 ARM Ltd.
+
+/dts-v1/;
+#include "sun50i-h5.dtsi"
+#include "sun50i-h5-cpu-opp-1.2ghz.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
+
+/ {
+ model = "Repka-Pi3-H5";
+ repka-freq = "1.2 GHz";
+ repka-pinout = "4";
+ compatible = "rbs,repka-pi3", "allwinner,sun50i-h5";
+
+ reg_vcc3v3: vcc3v3 {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc3v3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ aliases {
+ mmc0 = &mmc0;
+ ethernet0 = &emac;
+ serial0 = &uart0;
+ serial1 = &uart1;
+ spi0 = &spi0;
+ spi1 = &spi1;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ connector {
+ compatible = "hdmi-connector";
+ type = "a";
+
+ port {
+ hdmi_con_in: endpoint {
+ remote-endpoint = <&hdmi_out_con>;
+ };
+ };
+ };
+
+ ext_osc32k: ext_osc32k_clk {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <32768>;
+ clock-output-names = "ext_osc32k";
+ };
+
+ leds {
+ compatible = "gpio-leds";
+
+ status {
+ label = "rbs:red:status";
+ gpios = <&pio 0 20 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "heartbeat";
+ };
+ };
+
+ wifi_pwrseq: wifi_pwrseq {
+ compatible = "mmc-pwrseq-simple";
+ reset-gpios = <&r_pio 0 8 GPIO_ACTIVE_LOW>;
+ post-power-on-delay-ms = <200>;
+ };
+
+};
+
+&codec {
+ allwinner,audio-routing =
+ "Line Out", "LINEOUT",
+ "MIC1", "Mic",
+ "Mic", "MBIAS";
+ status = "okay";
+};
+
+&cpu0 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&cpu1 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&cpu2 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&cpu3 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&de {
+ status = "okay";
+};
+
+&ehci0 {
+ status = "okay";
+};
+
+&ehci1 {
+ status = "okay";
+};
+
+&ehci2 {
+ status = "okay";
+};
+
+&ehci3 {
+ status = "okay";
+};
+
+&emac {
+ phy-handle = <&int_mii_phy>;
+ phy-mode = "mii";
+ allwinner,leds-active-low;
+ status = "okay";
+};
+
+&hdmi {
+ status = "okay";
+};
+
+&hdmi_out {
+ hdmi_out_con: endpoint {
+ remote-endpoint = <&hdmi_con_in>;
+ };
+};
+
+&i2s2 {
+ status = "okay";
+};
+
+&sound_hdmi {
+ status = "okay";
+};
+
+&ir {
+ pinctrl-names = "default";
+ pinctrl-0 = <&r_ir_rx_pin>;
+ status = "disabled";
+};
+
+&rtc {
+ clocks = <&ext_osc32k>;
+};
+
+&mmc0 {
+ vmmc-supply = <®_vcc3v3>;
+ bus-width = <4>;
+ cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>; /* PF6 */
+ status = "okay";
+};
+
+&mmc1 {
+ vmmc-supply = <®_vcc3v3>;
+ mmc-pwrseq = <&wifi_pwrseq>;
+ bus-width = <4>;
+ non-removable;
+ status = "okay";
+
+ brcmf: wifi@1 {
+ reg = <1>;
+ compatible = "brcm,bcm4329-fmac";
+ interrupt-parent = <&r_pio>;
+ interrupts = <0 7 IRQ_TYPE_LEVEL_LOW>; /* PL7 */
+ interrupt-names = "host-wake";
+ };
+
+};
+
+&mmc2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc2_8bit_pins>;
+ vmmc-supply = <®_vcc3v3>;
+ bus-width = <8>;
+ non-removable;
+ cap-mmc-hw-reset;
+ status = "disabled";
+};
+
+&ohci0 {
+ status = "okay";
+};
+
+&ohci1 {
+ status = "okay";
+};
+
+&ohci2 {
+ status = "okay";
+};
+
+&ohci3 {
+ status = "okay";
+};
+
+&i2c1 {
+ status = "okay"; /* PA19,PA18 */
+};
+
+&i2c0 {
+ status = "okay"; /* PA11, PA12 */
+};
+
+&r_i2c {
+ status = "okay";
+
+ axp22x: pmic@34 {
+ compatible = "x-powers,axp221";
+ reg = <0x34>;
+ interrupt-parent = <&r_intc>;
+ interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+ };
+};
+
+#include "arm/axp22x.dtsi"
+
+&ac_power_supply {
+ status = "okay";
+};
+
+®_aldo2 { /* VCC-PG 1.8 */
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-pg";
+};
+
+®_aldo3 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-pll-avcc";
+};
+
+®_dc1sw {
+ regulator-name = "vcc-phy";
+};
+
+®_dcdc1 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-3v3";
+};
+
+®_dcdc2 {
+ regulator-always-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1360000>;
+ regulator-name = "vdd-cpux-a";
+};
+
+®_dcdc3 {
+ regulator-always-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1360000>;
+ regulator-name = "vdd-cpux-b";
+};
+
+/* DCDC3 is polyphased with DCDC2 */
+
+/*
+ * The DRAM chips used by rbs-h5 boards are DDR3 -compatibl
+ *
+ */
+®_dcdc5 {
+ regulator-always-on;
+ regulator-min-microvolt = <1500000>;
+ regulator-max-microvolt = <1500000>;
+ regulator-name = "vcc-dram";
+};
+
+®_dldo1 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-1";
+};
+
+®_dldo2 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-2";
+};
+
+®_dldo3 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-3";
+};
+
+®_dldo4 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-4";
+};
+ /* VCC-wifi-IO 1.8 */
+®_eldo1 {
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-wifi-io-1";
+};
+
+®_eldo2 {
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-wifi-io-2";
+};
+
+®_eldo3 {
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-wifi-io-3";
+};
+
+
+®_rtc_ldo {
+ regulator-name = "vcc-rtc";
+};
+
+&spi0 {
+ pinctrl-names = "default", "default";
+ pinctrl-1 = <&spi0_cs1>;
+ cs-gpios = <0>, <&pio 0 3 0>; /* PA3 */
+
+ status = "okay";
+ spidev@0 {
+ compatible = "rohm,dh2228fv";
+ status = "okay";
+ reg = <0>;
+ spi-max-frequency = <1000000>;
+ };
+ spidev@1 {
+ compatible = "rohm,dh2228fv";
+ status = "okay";
+ reg = <1>;
+ spi-max-frequency = <1000000>;
+ };
+};
+
+&spi1 {
+ pinctrl-names = "default", "default";
+
+ status = "okay";
+ spidev@0 {
+ compatible = "rohm,dh2228fv";
+ status = "okay";
+ reg = <0>;
+ spi-max-frequency = <1000000>;
+ };
+};
+
+&pio {
+ spi0_cs1: spi0_cs1 {
+ pins = "PA3";
+ function = "gpio_out";
+ output-high;
+ };
+};
+
+
+&r_pwm {
+ status = "disabled";
+};
+
+/* to debag serial */
+&uart0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_pa_pins>;
+ status = "okay";
+};
+
+/* to bt-wifi module */
+&uart1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart1_pins>, <&uart1_rts_cts_pins>;
+ uart-has-rtscts;
+ status = "okay";
+
+ bluetooth {
+ compatible = "brcm,bcm43438-bt";
+ clocks = <&rtc 1>;
+ clock-names = "lpo";
+ device-wakeup-gpios = <&r_pio 0 4 GPIO_ACTIVE_HIGH>; /* PL4 AP-WAKE-BT */
+ host-wakeup-gpios = <&r_pio 0 6 GPIO_ACTIVE_HIGH>; /* PL6 BT-WAKE-AP */
+ shutdown-gpios = <&r_pio 0 5 GPIO_ACTIVE_HIGH>; /* PL5 BT-RST-N */
+ max-speed = <1500000>;
+ };
+};
+
+&uart2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart2_pins>, <&uart2_rts_cts_pins>;
+ status = "disabled";
+};
+
+&r_uart {
+ pinctrl-names = "default";
+ pinctrl-0 = <&r_uart_pins>;
+ status = "disabled";
+};
+
+&usb_otg {
+ dr_mode = "host";
+ status = "okay";
+};
+
+&usbphy {
+ status = "okay";
+};
+
+
Index: v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-repka-pi3-alt-i2c2-1.4ghz.dts
===================================================================
--- v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-repka-pi3-alt-i2c2-1.4ghz.dts (nonexistent)
+++ v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-repka-pi3-alt-i2c2-1.4ghz.dts (revision 385)
@@ -0,0 +1,425 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+// Copyright (C) 2016 ARM Ltd.
+
+/dts-v1/;
+#include "sun50i-h5.dtsi"
+#include "sun50i-h5-cpu-opp-1.4ghz.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
+
+/ {
+ model = "Repka-Pi3-H5";
+ repka-freq = "1.4 GHz";
+ repka-pinout = "4";
+ compatible = "rbs,repka-pi3", "allwinner,sun50i-h5";
+
+ reg_vcc3v3: vcc3v3 {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc3v3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ aliases {
+ mmc0 = &mmc0;
+ ethernet0 = &emac;
+ serial0 = &uart0;
+ serial1 = &uart1;
+ spi0 = &spi0;
+ spi1 = &spi1;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ connector {
+ compatible = "hdmi-connector";
+ type = "a";
+
+ port {
+ hdmi_con_in: endpoint {
+ remote-endpoint = <&hdmi_out_con>;
+ };
+ };
+ };
+
+ ext_osc32k: ext_osc32k_clk {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <32768>;
+ clock-output-names = "ext_osc32k";
+ };
+
+ leds {
+ compatible = "gpio-leds";
+
+ status {
+ label = "rbs:red:status";
+ gpios = <&pio 0 20 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "heartbeat";
+ };
+ };
+
+ wifi_pwrseq: wifi_pwrseq {
+ compatible = "mmc-pwrseq-simple";
+ reset-gpios = <&r_pio 0 8 GPIO_ACTIVE_LOW>;
+ post-power-on-delay-ms = <200>;
+ };
+
+};
+
+&codec {
+ allwinner,audio-routing =
+ "Line Out", "LINEOUT",
+ "MIC1", "Mic",
+ "Mic", "MBIAS";
+ status = "okay";
+};
+
+&cpu0 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&cpu1 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&cpu2 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&cpu3 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&de {
+ status = "okay";
+};
+
+&ehci0 {
+ status = "okay";
+};
+
+&ehci1 {
+ status = "okay";
+};
+
+&ehci2 {
+ status = "okay";
+};
+
+&ehci3 {
+ status = "okay";
+};
+
+&emac {
+ phy-handle = <&int_mii_phy>;
+ phy-mode = "mii";
+ allwinner,leds-active-low;
+ status = "okay";
+};
+
+&hdmi {
+ status = "okay";
+};
+
+&hdmi_out {
+ hdmi_out_con: endpoint {
+ remote-endpoint = <&hdmi_con_in>;
+ };
+};
+
+&i2s2 {
+ status = "okay";
+};
+
+&sound_hdmi {
+ status = "okay";
+};
+
+&ir {
+ pinctrl-names = "default";
+ pinctrl-0 = <&r_ir_rx_pin>;
+ status = "disabled";
+};
+
+&rtc {
+ clocks = <&ext_osc32k>;
+};
+
+&mmc0 {
+ vmmc-supply = <®_vcc3v3>;
+ bus-width = <4>;
+ cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>; /* PF6 */
+ status = "okay";
+};
+
+&mmc1 {
+ vmmc-supply = <®_vcc3v3>;
+ mmc-pwrseq = <&wifi_pwrseq>;
+ bus-width = <4>;
+ non-removable;
+ status = "okay";
+
+ brcmf: wifi@1 {
+ reg = <1>;
+ compatible = "brcm,bcm4329-fmac";
+ interrupt-parent = <&r_pio>;
+ interrupts = <0 7 IRQ_TYPE_LEVEL_LOW>; /* PL7 */
+ interrupt-names = "host-wake";
+ };
+
+};
+
+&mmc2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc2_8bit_pins>;
+ vmmc-supply = <®_vcc3v3>;
+ bus-width = <8>;
+ non-removable;
+ cap-mmc-hw-reset;
+ status = "disabled";
+};
+
+&ohci0 {
+ status = "okay";
+};
+
+&ohci1 {
+ status = "okay";
+};
+
+&ohci2 {
+ status = "okay";
+};
+
+&ohci3 {
+ status = "okay";
+};
+
+&i2c1 {
+ status = "okay"; /* PA19,PA18 */
+};
+
+&i2c0 {
+ status = "okay"; /* PA11, PA12 */
+};
+
+&r_i2c {
+ status = "okay";
+
+ axp22x: pmic@34 {
+ compatible = "x-powers,axp221";
+ reg = <0x34>;
+ interrupt-parent = <&r_intc>;
+ interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+ };
+};
+
+#include "arm/axp22x.dtsi"
+
+&ac_power_supply {
+ status = "okay";
+};
+
+®_aldo2 { /* VCC-PG 1.8 */
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-pg";
+};
+
+®_aldo3 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-pll-avcc";
+};
+
+®_dc1sw {
+ regulator-name = "vcc-phy";
+};
+
+®_dcdc1 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-3v3";
+};
+
+®_dcdc2 {
+ regulator-always-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1360000>;
+ regulator-name = "vdd-cpux-a";
+};
+
+®_dcdc3 {
+ regulator-always-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1360000>;
+ regulator-name = "vdd-cpux-b";
+};
+
+/* DCDC3 is polyphased with DCDC2 */
+
+/*
+ * The DRAM chips used by rbs-h5 boards are DDR3 -compatibl
+ *
+ */
+®_dcdc5 {
+ regulator-always-on;
+ regulator-min-microvolt = <1500000>;
+ regulator-max-microvolt = <1500000>;
+ regulator-name = "vcc-dram";
+};
+
+®_dldo1 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-1";
+};
+
+®_dldo2 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-2";
+};
+
+®_dldo3 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-3";
+};
+
+®_dldo4 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-4";
+};
+ /* VCC-wifi-IO 1.8 */
+®_eldo1 {
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-wifi-io-1";
+};
+
+®_eldo2 {
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-wifi-io-2";
+};
+
+®_eldo3 {
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-wifi-io-3";
+};
+
+
+®_rtc_ldo {
+ regulator-name = "vcc-rtc";
+};
+
+&spi0 {
+ pinctrl-names = "default", "default";
+ pinctrl-1 = <&spi0_cs1>;
+ cs-gpios = <0>, <&pio 0 3 0>; /* PA3 */
+
+ status = "okay";
+ spidev@0 {
+ compatible = "rohm,dh2228fv";
+ status = "okay";
+ reg = <0>;
+ spi-max-frequency = <1000000>;
+ };
+ spidev@1 {
+ compatible = "rohm,dh2228fv";
+ status = "okay";
+ reg = <1>;
+ spi-max-frequency = <1000000>;
+ };
+};
+
+&spi1 {
+ pinctrl-names = "default", "default";
+
+ status = "okay";
+ spidev@0 {
+ compatible = "rohm,dh2228fv";
+ status = "okay";
+ reg = <0>;
+ spi-max-frequency = <1000000>;
+ };
+};
+
+&pio {
+ spi0_cs1: spi0_cs1 {
+ pins = "PA3";
+ function = "gpio_out";
+ output-high;
+ };
+};
+
+
+&r_pwm {
+ status = "disabled";
+};
+
+/* to debag serial */
+&uart0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_pa_pins>;
+ status = "okay";
+};
+
+/* to bt-wifi module */
+&uart1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart1_pins>, <&uart1_rts_cts_pins>;
+ uart-has-rtscts;
+ status = "okay";
+
+ bluetooth {
+ compatible = "brcm,bcm43438-bt";
+ clocks = <&rtc 1>;
+ clock-names = "lpo";
+ device-wakeup-gpios = <&r_pio 0 4 GPIO_ACTIVE_HIGH>; /* PL4 AP-WAKE-BT */
+ host-wakeup-gpios = <&r_pio 0 6 GPIO_ACTIVE_HIGH>; /* PL6 BT-WAKE-AP */
+ shutdown-gpios = <&r_pio 0 5 GPIO_ACTIVE_HIGH>; /* PL5 BT-RST-N */
+ max-speed = <1500000>;
+ };
+};
+
+&uart2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart2_pins>, <&uart2_rts_cts_pins>;
+ status = "disabled";
+};
+
+&r_uart {
+ pinctrl-names = "default";
+ pinctrl-0 = <&r_uart_pins>;
+ status = "disabled";
+};
+
+&usb_otg {
+ dr_mode = "host";
+ status = "okay";
+};
+
+&usbphy {
+ status = "okay";
+};
+
+
Index: v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-repka-pi3-alt-i2c2-v1.4.dts
===================================================================
--- v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-repka-pi3-alt-i2c2-v1.4.dts (nonexistent)
+++ v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-repka-pi3-alt-i2c2-v1.4.dts (revision 385)
@@ -0,0 +1,424 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+// Copyright (C) 2016 ARM Ltd.
+
+/dts-v1/;
+#include "sun50i-h5-repka-3-1.4.dtsi"
+#include "sun50i-h5-cpu-opp-1.4ghz.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
+
+/ {
+ model = "Repka-Pi3-H5";
+ repka-freq = "1.4 GHz";
+ repka-pinout = "4";
+ compatible = "rbs,repka-pi3", "allwinner,sun50i-h5";
+
+ reg_vcc3v3: vcc3v3 {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc3v3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ aliases {
+ mmc0 = &mmc0;
+ ethernet0 = &emac;
+ serial0 = &uart0;
+ serial1 = &uart1;
+ spi0 = &spi0;
+ spi1 = &spi1;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ connector {
+ compatible = "hdmi-connector";
+ type = "a";
+
+ port {
+ hdmi_con_in: endpoint {
+ remote-endpoint = <&hdmi_out_con>;
+ };
+ };
+ };
+
+ ext_osc32k: ext_osc32k_clk {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <32768>;
+ clock-output-names = "ext_osc32k";
+ };
+
+ leds {
+ compatible = "gpio-leds";
+
+ status {
+ label = "rbs:red:status";
+ gpios = <&pio 0 20 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "heartbeat";
+ };
+ };
+
+ wifi_pwrseq: wifi_pwrseq {
+ compatible = "mmc-pwrseq-simple";
+ reset-gpios = <&r_pio 0 8 GPIO_ACTIVE_LOW>;
+ post-power-on-delay-ms = <200>;
+ };
+
+};
+
+&codec {
+ allwinner,audio-routing =
+ "Line Out", "LINEOUT",
+ "MIC1", "Mic",
+ "Mic", "MBIAS";
+ status = "okay";
+};
+
+&cpu0 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&cpu1 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&cpu2 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&cpu3 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&de {
+ status = "okay";
+};
+
+&ehci0 {
+ status = "okay";
+};
+
+&ehci1 {
+ status = "okay";
+};
+
+&ehci2 {
+ status = "okay";
+};
+
+&ehci3 {
+ status = "okay";
+};
+
+&emac {
+ phy-handle = <&int_mii_phy>;
+ phy-mode = "mii";
+ allwinner,leds-active-low;
+ status = "okay";
+};
+
+&hdmi {
+ status = "okay";
+};
+
+&hdmi_out {
+ hdmi_out_con: endpoint {
+ remote-endpoint = <&hdmi_con_in>;
+ };
+};
+
+&i2s2 {
+ status = "okay";
+};
+
+&sound_hdmi {
+ status = "okay";
+};
+
+&ir {
+ pinctrl-names = "default";
+ pinctrl-0 = <&r_ir_rx_pin>;
+ status = "disabled";
+};
+
+&rtc {
+ clocks = <&ext_osc32k>;
+};
+
+&mmc0 {
+ vmmc-supply = <®_vcc3v3>;
+ bus-width = <4>;
+ cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>; /* PF6 */
+ status = "okay";
+};
+
+&mmc1 {
+ vmmc-supply = <®_vcc3v3>;
+ mmc-pwrseq = <&wifi_pwrseq>;
+ bus-width = <4>;
+ non-removable;
+ status = "okay";
+
+ brcmf: wifi@1 {
+ reg = <1>;
+ compatible = "brcm,bcm4329-fmac";
+ interrupt-parent = <&r_pio>;
+ interrupts = <0 7 IRQ_TYPE_LEVEL_LOW>; /* PL7 */
+ interrupt-names = "host-wake";
+ };
+
+};
+
+&mmc2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc2_8bit_pins>;
+ vmmc-supply = <®_vcc3v3>;
+ bus-width = <8>;
+ non-removable;
+ cap-mmc-hw-reset;
+ status = "disabled";
+};
+
+&ohci0 {
+ status = "okay";
+};
+
+&ohci1 {
+ status = "okay";
+};
+
+&ohci2 {
+ status = "okay";
+};
+
+&ohci3 {
+ status = "okay";
+};
+
+&i2c1 {
+ status = "okay"; /* PA19,PA18 */
+};
+
+&i2c0 {
+ status = "okay"; /* PA11, PA12 */
+};
+
+&r_i2c {
+ status = "okay";
+
+ axp22x: pmic@34 {
+ compatible = "x-powers,axp221";
+ reg = <0x34>;
+ interrupt-parent = <&r_intc>;
+ interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+ };
+};
+
+#include "arm/axp22x.dtsi"
+
+&ac_power_supply {
+ status = "okay";
+};
+
+®_aldo2 { /* VCC-PG 1.8 */
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-pg";
+};
+
+®_aldo3 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-pll-avcc";
+};
+
+®_dc1sw {
+ regulator-name = "vcc-phy";
+};
+
+®_dcdc1 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-3v3";
+};
+
+®_dcdc2 {
+ regulator-always-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1360000>;
+ regulator-name = "vdd-cpux-a";
+};
+
+®_dcdc3 {
+ regulator-always-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1360000>;
+ regulator-name = "vdd-cpux-b";
+};
+
+/* DCDC3 is polyphased with DCDC2 */
+
+/*
+ * The DRAM chips used by rbs-h5 boards are DDR3 -compatibl
+ *
+ */
+®_dcdc5 {
+ regulator-always-on;
+ regulator-min-microvolt = <1500000>;
+ regulator-max-microvolt = <1500000>;
+ regulator-name = "vcc-dram";
+};
+
+®_dldo1 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-1";
+};
+
+®_dldo2 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-2";
+};
+
+®_dldo3 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-3";
+};
+
+®_dldo4 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-4";
+};
+ /* VCC-wifi-IO 1.8 */
+®_eldo1 {
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-wifi-io-1";
+};
+
+®_eldo2 {
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-wifi-io-2";
+};
+
+®_eldo3 {
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-wifi-io-3";
+};
+
+
+®_rtc_ldo {
+ regulator-name = "vcc-rtc";
+};
+
+&spi0 {
+ pinctrl-names = "default", "default";
+ pinctrl-1 = <&spi0_cs1>;
+ cs-gpios = <0>, <&pio 0 3 0>; /* PA3 */
+
+ status = "okay";
+ spidev@0 {
+ compatible = "rohm,dh2228fv";
+ status = "okay";
+ reg = <0>;
+ spi-max-frequency = <1000000>;
+ };
+ spidev@1 {
+ compatible = "rohm,dh2228fv";
+ status = "okay";
+ reg = <1>;
+ spi-max-frequency = <1000000>;
+ };
+};
+
+&spi1 {
+ pinctrl-names = "default", "default";
+
+ status = "okay";
+ spidev@0 {
+ compatible = "rohm,dh2228fv";
+ status = "okay";
+ reg = <0>;
+ spi-max-frequency = <1000000>;
+ };
+};
+
+&pio {
+ spi0_cs1: spi0_cs1 {
+ pins = "PA3";
+ function = "gpio_out";
+ output-high;
+ };
+};
+
+
+&r_pwm {
+ status = "disabled";
+};
+
+/* to debag serial */
+&uart0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_pa_pins>;
+ status = "okay";
+};
+
+/* to bt-wifi module */
+&uart1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart1_pins>, <&uart1_rts_cts_pins>;
+ uart-has-rtscts;
+ status = "okay";
+
+ bluetooth {
+ compatible = "brcm,bcm43438-bt";
+ clocks = <&rtc 1>;
+ clock-names = "lpo";
+ device-wakeup-gpios = <&r_pio 0 4 GPIO_ACTIVE_HIGH>; /* PL4 AP-WAKE-BT */
+ host-wakeup-gpios = <&r_pio 0 6 GPIO_ACTIVE_HIGH>; /* PL6 BT-WAKE-AP */
+ shutdown-gpios = <&r_pio 0 5 GPIO_ACTIVE_HIGH>; /* PL5 BT-RST-N */
+ max-speed = <1500000>;
+ };
+};
+
+&uart2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart2_pins>, <&uart2_rts_cts_pins>;
+ status = "disabled";
+};
+
+&r_uart {
+ pinctrl-names = "default";
+ pinctrl-0 = <&r_uart_pins>;
+ status = "disabled";
+};
+
+&usb_otg {
+ dr_mode = "host";
+ status = "okay";
+};
+
+&usbphy {
+ status = "okay";
+};
+
Index: v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-repka-pi3-alt-i2c2-v1.4p.dts
===================================================================
--- v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-repka-pi3-alt-i2c2-v1.4p.dts (nonexistent)
+++ v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-repka-pi3-alt-i2c2-v1.4p.dts (revision 385)
@@ -0,0 +1,424 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+// Copyright (C) 2016 ARM Ltd.
+
+/dts-v1/;
+#include "sun50i-h5-repka-3-1.4p.dtsi"
+#include "sun50i-h5-cpu-opp-1.4ghz.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
+
+/ {
+ model = "Repka-Pi3-H5";
+ repka-freq = "1.4 GHz";
+ repka-pinout = "4";
+ compatible = "rbs,repka-pi3", "allwinner,sun50i-h5";
+
+ reg_vcc3v3: vcc3v3 {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc3v3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ aliases {
+ mmc0 = &mmc0;
+ ethernet0 = &emac;
+ serial0 = &uart0;
+ serial1 = &uart1;
+ spi0 = &spi0;
+ spi1 = &spi1;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ connector {
+ compatible = "hdmi-connector";
+ type = "a";
+
+ port {
+ hdmi_con_in: endpoint {
+ remote-endpoint = <&hdmi_out_con>;
+ };
+ };
+ };
+
+ ext_osc32k: ext_osc32k_clk {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <32768>;
+ clock-output-names = "ext_osc32k";
+ };
+
+ leds {
+ compatible = "gpio-leds";
+
+ status {
+ label = "rbs:red:status";
+ gpios = <&pio 0 20 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "heartbeat";
+ };
+ };
+
+ wifi_pwrseq: wifi_pwrseq {
+ compatible = "mmc-pwrseq-simple";
+ reset-gpios = <&r_pio 0 8 GPIO_ACTIVE_LOW>;
+ post-power-on-delay-ms = <200>;
+ };
+
+};
+
+&codec {
+ allwinner,audio-routing =
+ "Line Out", "LINEOUT",
+ "MIC1", "Mic",
+ "Mic", "MBIAS";
+ status = "okay";
+};
+
+&cpu0 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&cpu1 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&cpu2 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&cpu3 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&de {
+ status = "okay";
+};
+
+&ehci0 {
+ status = "okay";
+};
+
+&ehci1 {
+ status = "okay";
+};
+
+&ehci2 {
+ status = "okay";
+};
+
+&ehci3 {
+ status = "okay";
+};
+
+&emac {
+ phy-handle = <&int_mii_phy>;
+ phy-mode = "mii";
+ allwinner,leds-active-low;
+ status = "okay";
+};
+
+&hdmi {
+ status = "okay";
+};
+
+&hdmi_out {
+ hdmi_out_con: endpoint {
+ remote-endpoint = <&hdmi_con_in>;
+ };
+};
+
+&i2s2 {
+ status = "okay";
+};
+
+&sound_hdmi {
+ status = "okay";
+};
+
+&ir {
+ pinctrl-names = "default";
+ pinctrl-0 = <&r_ir_rx_pin>;
+ status = "disabled";
+};
+
+&rtc {
+ clocks = <&ext_osc32k>;
+};
+
+&mmc0 {
+ vmmc-supply = <®_vcc3v3>;
+ bus-width = <4>;
+ cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>; /* PF6 */
+ status = "okay";
+};
+
+&mmc1 {
+ vmmc-supply = <®_vcc3v3>;
+ mmc-pwrseq = <&wifi_pwrseq>;
+ bus-width = <4>;
+ non-removable;
+ status = "okay";
+
+ brcmf: wifi@1 {
+ reg = <1>;
+ compatible = "brcm,bcm4329-fmac";
+ interrupt-parent = <&r_pio>;
+ interrupts = <0 7 IRQ_TYPE_LEVEL_LOW>; /* PL7 */
+ interrupt-names = "host-wake";
+ };
+
+};
+
+&mmc2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc2_8bit_pins>;
+ vmmc-supply = <®_vcc3v3>;
+ bus-width = <8>;
+ non-removable;
+ cap-mmc-hw-reset;
+ status = "disabled";
+};
+
+&ohci0 {
+ status = "okay";
+};
+
+&ohci1 {
+ status = "okay";
+};
+
+&ohci2 {
+ status = "okay";
+};
+
+&ohci3 {
+ status = "okay";
+};
+
+&i2c1 {
+ status = "okay"; /* PA19,PA18 */
+};
+
+&i2c0 {
+ status = "okay"; /* PA11, PA12 */
+};
+
+&r_i2c {
+ status = "okay";
+
+ axp22x: pmic@34 {
+ compatible = "x-powers,axp221";
+ reg = <0x34>;
+ interrupt-parent = <&r_intc>;
+ interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+ };
+};
+
+#include "arm/axp22x.dtsi"
+
+&ac_power_supply {
+ status = "okay";
+};
+
+®_aldo2 { /* VCC-PG 1.8 */
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-pg";
+};
+
+®_aldo3 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-pll-avcc";
+};
+
+®_dc1sw {
+ regulator-name = "vcc-phy";
+};
+
+®_dcdc1 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-3v3";
+};
+
+®_dcdc2 {
+ regulator-always-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1360000>;
+ regulator-name = "vdd-cpux-a";
+};
+
+®_dcdc3 {
+ regulator-always-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1360000>;
+ regulator-name = "vdd-cpux-b";
+};
+
+/* DCDC3 is polyphased with DCDC2 */
+
+/*
+ * The DRAM chips used by rbs-h5 boards are DDR3 -compatibl
+ *
+ */
+®_dcdc5 {
+ regulator-always-on;
+ regulator-min-microvolt = <1500000>;
+ regulator-max-microvolt = <1500000>;
+ regulator-name = "vcc-dram";
+};
+
+®_dldo1 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-1";
+};
+
+®_dldo2 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-2";
+};
+
+®_dldo3 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-3";
+};
+
+®_dldo4 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-4";
+};
+ /* VCC-wifi-IO 1.8 */
+®_eldo1 {
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-wifi-io-1";
+};
+
+®_eldo2 {
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-wifi-io-2";
+};
+
+®_eldo3 {
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-wifi-io-3";
+};
+
+
+®_rtc_ldo {
+ regulator-name = "vcc-rtc";
+};
+
+&spi0 {
+ pinctrl-names = "default", "default";
+ pinctrl-1 = <&spi0_cs1>;
+ cs-gpios = <0>, <&pio 0 3 0>; /* PA3 */
+
+ status = "okay";
+ spidev@0 {
+ compatible = "rohm,dh2228fv";
+ status = "okay";
+ reg = <0>;
+ spi-max-frequency = <1000000>;
+ };
+ spidev@1 {
+ compatible = "rohm,dh2228fv";
+ status = "okay";
+ reg = <1>;
+ spi-max-frequency = <1000000>;
+ };
+};
+
+&spi1 {
+ pinctrl-names = "default", "default";
+
+ status = "okay";
+ spidev@0 {
+ compatible = "rohm,dh2228fv";
+ status = "okay";
+ reg = <0>;
+ spi-max-frequency = <1000000>;
+ };
+};
+
+&pio {
+ spi0_cs1: spi0_cs1 {
+ pins = "PA3";
+ function = "gpio_out";
+ output-high;
+ };
+};
+
+
+&r_pwm {
+ status = "disabled";
+};
+
+/* to debag serial */
+&uart0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_pa_pins>;
+ status = "okay";
+};
+
+/* to bt-wifi module */
+&uart1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart1_pins>, <&uart1_rts_cts_pins>;
+ uart-has-rtscts;
+ status = "okay";
+
+ bluetooth {
+ compatible = "brcm,bcm43438-bt";
+ clocks = <&rtc 1>;
+ clock-names = "lpo";
+ device-wakeup-gpios = <&r_pio 0 4 GPIO_ACTIVE_HIGH>; /* PL4 AP-WAKE-BT */
+ host-wakeup-gpios = <&r_pio 0 6 GPIO_ACTIVE_HIGH>; /* PL6 BT-WAKE-AP */
+ shutdown-gpios = <&r_pio 0 5 GPIO_ACTIVE_HIGH>; /* PL5 BT-RST-N */
+ max-speed = <1500000>;
+ };
+};
+
+&uart2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart2_pins>, <&uart2_rts_cts_pins>;
+ status = "disabled";
+};
+
+&r_uart {
+ pinctrl-names = "default";
+ pinctrl-0 = <&r_uart_pins>;
+ status = "disabled";
+};
+
+&usb_otg {
+ dr_mode = "host";
+ status = "okay";
+};
+
+&usbphy {
+ status = "okay";
+};
+
Index: v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-repka-pi3-alt-pwm-1.0ghz.dts
===================================================================
--- v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-repka-pi3-alt-pwm-1.0ghz.dts (nonexistent)
+++ v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-repka-pi3-alt-pwm-1.0ghz.dts (revision 385)
@@ -0,0 +1,425 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+// Copyright (C) 2016 ARM Ltd.
+
+/dts-v1/;
+#include "sun50i-h5.dtsi"
+#include "sun50i-h5-cpu-opp-1.0ghz.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
+
+/ {
+ model = "Repka-Pi3-H5";
+ repka-freq = "1.0 GHz";
+ repka-pinout = "5";
+ compatible = "rbs,repka-pi3", "allwinner,sun50i-h5";
+
+ reg_vcc3v3: vcc3v3 {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc3v3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ aliases {
+ mmc0 = &mmc0;
+ ethernet0 = &emac;
+ serial0 = &uart0;
+ serial1 = &uart1;
+ spi0 = &spi0;
+ spi1 = &spi1;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ connector {
+ compatible = "hdmi-connector";
+ type = "a";
+
+ port {
+ hdmi_con_in: endpoint {
+ remote-endpoint = <&hdmi_out_con>;
+ };
+ };
+ };
+
+ ext_osc32k: ext_osc32k_clk {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <32768>;
+ clock-output-names = "ext_osc32k";
+ };
+
+ leds {
+ compatible = "gpio-leds";
+
+ status {
+ label = "rbs:red:status";
+ gpios = <&pio 0 20 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "heartbeat";
+ };
+ };
+
+ wifi_pwrseq: wifi_pwrseq {
+ compatible = "mmc-pwrseq-simple";
+ reset-gpios = <&r_pio 0 8 GPIO_ACTIVE_LOW>;
+ post-power-on-delay-ms = <200>;
+ };
+
+};
+
+&codec {
+ allwinner,audio-routing =
+ "Line Out", "LINEOUT",
+ "MIC1", "Mic",
+ "Mic", "MBIAS";
+ status = "okay";
+};
+
+&cpu0 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&cpu1 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&cpu2 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&cpu3 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&de {
+ status = "okay";
+};
+
+&ehci0 {
+ status = "okay";
+};
+
+&ehci1 {
+ status = "okay";
+};
+
+&ehci2 {
+ status = "okay";
+};
+
+&ehci3 {
+ status = "okay";
+};
+
+&emac {
+ phy-handle = <&int_mii_phy>;
+ phy-mode = "mii";
+ allwinner,leds-active-low;
+ status = "okay";
+};
+
+&hdmi {
+ status = "okay";
+};
+
+&hdmi_out {
+ hdmi_out_con: endpoint {
+ remote-endpoint = <&hdmi_con_in>;
+ };
+};
+
+&i2s2 {
+ status = "okay";
+};
+
+&sound_hdmi {
+ status = "okay";
+};
+
+&ir {
+ pinctrl-names = "default";
+ pinctrl-0 = <&r_ir_rx_pin>;
+ status = "disabled";
+};
+
+&rtc {
+ clocks = <&ext_osc32k>;
+};
+
+&mmc0 {
+ vmmc-supply = <®_vcc3v3>;
+ bus-width = <4>;
+ cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>; /* PF6 */
+ status = "okay";
+};
+
+&mmc1 {
+ vmmc-supply = <®_vcc3v3>;
+ mmc-pwrseq = <&wifi_pwrseq>;
+ bus-width = <4>;
+ non-removable;
+ status = "okay";
+
+ brcmf: wifi@1 {
+ reg = <1>;
+ compatible = "brcm,bcm4329-fmac";
+ interrupt-parent = <&r_pio>;
+ interrupts = <0 7 IRQ_TYPE_LEVEL_LOW>; /* PL7 */
+ interrupt-names = "host-wake";
+ };
+
+};
+
+&mmc2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc2_8bit_pins>;
+ vmmc-supply = <®_vcc3v3>;
+ bus-width = <8>;
+ non-removable;
+ cap-mmc-hw-reset;
+ status = "disabled";
+};
+
+&ohci0 {
+ status = "okay";
+};
+
+&ohci1 {
+ status = "okay";
+};
+
+&ohci2 {
+ status = "okay";
+};
+
+&ohci3 {
+ status = "okay";
+};
+
+&i2c1 {
+ status = "disabled"; /* PA19,PA18 */
+};
+
+&i2c0 {
+ status = "okay"; /* PA11, PA12 */
+};
+
+&r_i2c {
+ status = "okay";
+
+ axp22x: pmic@34 {
+ compatible = "x-powers,axp221";
+ reg = <0x34>;
+ interrupt-parent = <&r_intc>;
+ interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+ };
+};
+
+#include "arm/axp22x.dtsi"
+
+&ac_power_supply {
+ status = "okay";
+};
+
+®_aldo2 { /* VCC-PG 1.8 */
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-pg";
+};
+
+®_aldo3 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-pll-avcc";
+};
+
+®_dc1sw {
+ regulator-name = "vcc-phy";
+};
+
+®_dcdc1 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-3v3";
+};
+
+®_dcdc2 {
+ regulator-always-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1360000>;
+ regulator-name = "vdd-cpux-a";
+};
+
+®_dcdc3 {
+ regulator-always-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1360000>;
+ regulator-name = "vdd-cpux-b";
+};
+
+/* DCDC3 is polyphased with DCDC2 */
+
+/*
+ * The DRAM chips used by rbs-h5 boards are DDR3 -compatibl
+ *
+ */
+®_dcdc5 {
+ regulator-always-on;
+ regulator-min-microvolt = <1500000>;
+ regulator-max-microvolt = <1500000>;
+ regulator-name = "vcc-dram";
+};
+
+®_dldo1 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-1";
+};
+
+®_dldo2 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-2";
+};
+
+®_dldo3 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-3";
+};
+
+®_dldo4 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-4";
+};
+ /* VCC-wifi-IO 1.8 */
+®_eldo1 {
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-wifi-io-1";
+};
+
+®_eldo2 {
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-wifi-io-2";
+};
+
+®_eldo3 {
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-wifi-io-3";
+};
+
+
+®_rtc_ldo {
+ regulator-name = "vcc-rtc";
+};
+
+&spi0 {
+ pinctrl-names = "default", "default";
+ pinctrl-1 = <&spi0_cs1>;
+ cs-gpios = <0>, <&pio 0 3 0>; /* PA3 */
+
+ status = "okay";
+ spidev@0 {
+ compatible = "rohm,dh2228fv";
+ status = "okay";
+ reg = <0>;
+ spi-max-frequency = <1000000>;
+ };
+ spidev@1 {
+ compatible = "rohm,dh2228fv";
+ status = "okay";
+ reg = <1>;
+ spi-max-frequency = <1000000>;
+ };
+};
+
+&spi1 {
+ pinctrl-names = "default", "default";
+
+ status = "okay";
+ spidev@0 {
+ compatible = "rohm,dh2228fv";
+ status = "okay";
+ reg = <0>;
+ spi-max-frequency = <1000000>;
+ };
+};
+
+&pio {
+ spi0_cs1: spi0_cs1 {
+ pins = "PA3";
+ function = "gpio_out";
+ output-high;
+ };
+};
+
+
+&r_pwm {
+ status = "okay";
+};
+
+/* to debag serial */
+&uart0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_pa_pins>;
+ status = "okay";
+};
+
+/* to bt-wifi module */
+&uart1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart1_pins>, <&uart1_rts_cts_pins>;
+ uart-has-rtscts;
+ status = "okay";
+
+ bluetooth {
+ compatible = "brcm,bcm43438-bt";
+ clocks = <&rtc 1>;
+ clock-names = "lpo";
+ device-wakeup-gpios = <&r_pio 0 4 GPIO_ACTIVE_HIGH>; /* PL4 AP-WAKE-BT */
+ host-wakeup-gpios = <&r_pio 0 6 GPIO_ACTIVE_HIGH>; /* PL6 BT-WAKE-AP */
+ shutdown-gpios = <&r_pio 0 5 GPIO_ACTIVE_HIGH>; /* PL5 BT-RST-N */
+ max-speed = <1500000>;
+ };
+};
+
+&uart2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart2_pins>, <&uart2_rts_cts_pins>;
+ status = "disabled";
+};
+
+&r_uart {
+ pinctrl-names = "default";
+ pinctrl-0 = <&r_uart_pins>;
+ status = "disabled";
+};
+
+&usb_otg {
+ dr_mode = "host";
+ status = "okay";
+};
+
+&usbphy {
+ status = "okay";
+};
+
+
Index: v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-repka-pi3-alt-pwm-1.2ghz.dts
===================================================================
--- v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-repka-pi3-alt-pwm-1.2ghz.dts (nonexistent)
+++ v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-repka-pi3-alt-pwm-1.2ghz.dts (revision 385)
@@ -0,0 +1,425 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+// Copyright (C) 2016 ARM Ltd.
+
+/dts-v1/;
+#include "sun50i-h5.dtsi"
+#include "sun50i-h5-cpu-opp-1.2ghz.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
+
+/ {
+ model = "Repka-Pi3-H5";
+ repka-freq = "1.2 GHz";
+ repka-pinout = "5";
+ compatible = "rbs,repka-pi3", "allwinner,sun50i-h5";
+
+ reg_vcc3v3: vcc3v3 {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc3v3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ aliases {
+ mmc0 = &mmc0;
+ ethernet0 = &emac;
+ serial0 = &uart0;
+ serial1 = &uart1;
+ spi0 = &spi0;
+ spi1 = &spi1;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ connector {
+ compatible = "hdmi-connector";
+ type = "a";
+
+ port {
+ hdmi_con_in: endpoint {
+ remote-endpoint = <&hdmi_out_con>;
+ };
+ };
+ };
+
+ ext_osc32k: ext_osc32k_clk {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <32768>;
+ clock-output-names = "ext_osc32k";
+ };
+
+ leds {
+ compatible = "gpio-leds";
+
+ status {
+ label = "rbs:red:status";
+ gpios = <&pio 0 20 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "heartbeat";
+ };
+ };
+
+ wifi_pwrseq: wifi_pwrseq {
+ compatible = "mmc-pwrseq-simple";
+ reset-gpios = <&r_pio 0 8 GPIO_ACTIVE_LOW>;
+ post-power-on-delay-ms = <200>;
+ };
+
+};
+
+&codec {
+ allwinner,audio-routing =
+ "Line Out", "LINEOUT",
+ "MIC1", "Mic",
+ "Mic", "MBIAS";
+ status = "okay";
+};
+
+&cpu0 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&cpu1 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&cpu2 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&cpu3 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&de {
+ status = "okay";
+};
+
+&ehci0 {
+ status = "okay";
+};
+
+&ehci1 {
+ status = "okay";
+};
+
+&ehci2 {
+ status = "okay";
+};
+
+&ehci3 {
+ status = "okay";
+};
+
+&emac {
+ phy-handle = <&int_mii_phy>;
+ phy-mode = "mii";
+ allwinner,leds-active-low;
+ status = "okay";
+};
+
+&hdmi {
+ status = "okay";
+};
+
+&hdmi_out {
+ hdmi_out_con: endpoint {
+ remote-endpoint = <&hdmi_con_in>;
+ };
+};
+
+&i2s2 {
+ status = "okay";
+};
+
+&sound_hdmi {
+ status = "okay";
+};
+
+&ir {
+ pinctrl-names = "default";
+ pinctrl-0 = <&r_ir_rx_pin>;
+ status = "disabled";
+};
+
+&rtc {
+ clocks = <&ext_osc32k>;
+};
+
+&mmc0 {
+ vmmc-supply = <®_vcc3v3>;
+ bus-width = <4>;
+ cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>; /* PF6 */
+ status = "okay";
+};
+
+&mmc1 {
+ vmmc-supply = <®_vcc3v3>;
+ mmc-pwrseq = <&wifi_pwrseq>;
+ bus-width = <4>;
+ non-removable;
+ status = "okay";
+
+ brcmf: wifi@1 {
+ reg = <1>;
+ compatible = "brcm,bcm4329-fmac";
+ interrupt-parent = <&r_pio>;
+ interrupts = <0 7 IRQ_TYPE_LEVEL_LOW>; /* PL7 */
+ interrupt-names = "host-wake";
+ };
+
+};
+
+&mmc2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc2_8bit_pins>;
+ vmmc-supply = <®_vcc3v3>;
+ bus-width = <8>;
+ non-removable;
+ cap-mmc-hw-reset;
+ status = "disabled";
+};
+
+&ohci0 {
+ status = "okay";
+};
+
+&ohci1 {
+ status = "okay";
+};
+
+&ohci2 {
+ status = "okay";
+};
+
+&ohci3 {
+ status = "okay";
+};
+
+&i2c1 {
+ status = "disabled"; /* PA19,PA18 */
+};
+
+&i2c0 {
+ status = "okay"; /* PA11, PA12 */
+};
+
+&r_i2c {
+ status = "okay";
+
+ axp22x: pmic@34 {
+ compatible = "x-powers,axp221";
+ reg = <0x34>;
+ interrupt-parent = <&r_intc>;
+ interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+ };
+};
+
+#include "arm/axp22x.dtsi"
+
+&ac_power_supply {
+ status = "okay";
+};
+
+®_aldo2 { /* VCC-PG 1.8 */
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-pg";
+};
+
+®_aldo3 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-pll-avcc";
+};
+
+®_dc1sw {
+ regulator-name = "vcc-phy";
+};
+
+®_dcdc1 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-3v3";
+};
+
+®_dcdc2 {
+ regulator-always-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1360000>;
+ regulator-name = "vdd-cpux-a";
+};
+
+®_dcdc3 {
+ regulator-always-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1360000>;
+ regulator-name = "vdd-cpux-b";
+};
+
+/* DCDC3 is polyphased with DCDC2 */
+
+/*
+ * The DRAM chips used by rbs-h5 boards are DDR3 -compatibl
+ *
+ */
+®_dcdc5 {
+ regulator-always-on;
+ regulator-min-microvolt = <1500000>;
+ regulator-max-microvolt = <1500000>;
+ regulator-name = "vcc-dram";
+};
+
+®_dldo1 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-1";
+};
+
+®_dldo2 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-2";
+};
+
+®_dldo3 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-3";
+};
+
+®_dldo4 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-4";
+};
+ /* VCC-wifi-IO 1.8 */
+®_eldo1 {
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-wifi-io-1";
+};
+
+®_eldo2 {
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-wifi-io-2";
+};
+
+®_eldo3 {
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-wifi-io-3";
+};
+
+
+®_rtc_ldo {
+ regulator-name = "vcc-rtc";
+};
+
+&spi0 {
+ pinctrl-names = "default", "default";
+ pinctrl-1 = <&spi0_cs1>;
+ cs-gpios = <0>, <&pio 0 3 0>; /* PA3 */
+
+ status = "okay";
+ spidev@0 {
+ compatible = "rohm,dh2228fv";
+ status = "okay";
+ reg = <0>;
+ spi-max-frequency = <1000000>;
+ };
+ spidev@1 {
+ compatible = "rohm,dh2228fv";
+ status = "okay";
+ reg = <1>;
+ spi-max-frequency = <1000000>;
+ };
+};
+
+&spi1 {
+ pinctrl-names = "default", "default";
+
+ status = "okay";
+ spidev@0 {
+ compatible = "rohm,dh2228fv";
+ status = "okay";
+ reg = <0>;
+ spi-max-frequency = <1000000>;
+ };
+};
+
+&pio {
+ spi0_cs1: spi0_cs1 {
+ pins = "PA3";
+ function = "gpio_out";
+ output-high;
+ };
+};
+
+
+&r_pwm {
+ status = "okay";
+};
+
+/* to debag serial */
+&uart0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_pa_pins>;
+ status = "okay";
+};
+
+/* to bt-wifi module */
+&uart1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart1_pins>, <&uart1_rts_cts_pins>;
+ uart-has-rtscts;
+ status = "okay";
+
+ bluetooth {
+ compatible = "brcm,bcm43438-bt";
+ clocks = <&rtc 1>;
+ clock-names = "lpo";
+ device-wakeup-gpios = <&r_pio 0 4 GPIO_ACTIVE_HIGH>; /* PL4 AP-WAKE-BT */
+ host-wakeup-gpios = <&r_pio 0 6 GPIO_ACTIVE_HIGH>; /* PL6 BT-WAKE-AP */
+ shutdown-gpios = <&r_pio 0 5 GPIO_ACTIVE_HIGH>; /* PL5 BT-RST-N */
+ max-speed = <1500000>;
+ };
+};
+
+&uart2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart2_pins>, <&uart2_rts_cts_pins>;
+ status = "disabled";
+};
+
+&r_uart {
+ pinctrl-names = "default";
+ pinctrl-0 = <&r_uart_pins>;
+ status = "disabled";
+};
+
+&usb_otg {
+ dr_mode = "host";
+ status = "okay";
+};
+
+&usbphy {
+ status = "okay";
+};
+
+
Index: v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-repka-pi3-alt-pwm-1.4ghz.dts
===================================================================
--- v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-repka-pi3-alt-pwm-1.4ghz.dts (nonexistent)
+++ v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-repka-pi3-alt-pwm-1.4ghz.dts (revision 385)
@@ -0,0 +1,425 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+// Copyright (C) 2016 ARM Ltd.
+
+/dts-v1/;
+#include "sun50i-h5.dtsi"
+#include "sun50i-h5-cpu-opp-1.4ghz.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
+
+/ {
+ model = "Repka-Pi3-H5";
+ repka-freq = "1.4 GHz";
+ repka-pinout = "5";
+ compatible = "rbs,repka-pi3", "allwinner,sun50i-h5";
+
+ reg_vcc3v3: vcc3v3 {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc3v3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ aliases {
+ mmc0 = &mmc0;
+ ethernet0 = &emac;
+ serial0 = &uart0;
+ serial1 = &uart1;
+ spi0 = &spi0;
+ spi1 = &spi1;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ connector {
+ compatible = "hdmi-connector";
+ type = "a";
+
+ port {
+ hdmi_con_in: endpoint {
+ remote-endpoint = <&hdmi_out_con>;
+ };
+ };
+ };
+
+ ext_osc32k: ext_osc32k_clk {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <32768>;
+ clock-output-names = "ext_osc32k";
+ };
+
+ leds {
+ compatible = "gpio-leds";
+
+ status {
+ label = "rbs:red:status";
+ gpios = <&pio 0 20 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "heartbeat";
+ };
+ };
+
+ wifi_pwrseq: wifi_pwrseq {
+ compatible = "mmc-pwrseq-simple";
+ reset-gpios = <&r_pio 0 8 GPIO_ACTIVE_LOW>;
+ post-power-on-delay-ms = <200>;
+ };
+
+};
+
+&codec {
+ allwinner,audio-routing =
+ "Line Out", "LINEOUT",
+ "MIC1", "Mic",
+ "Mic", "MBIAS";
+ status = "okay";
+};
+
+&cpu0 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&cpu1 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&cpu2 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&cpu3 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&de {
+ status = "okay";
+};
+
+&ehci0 {
+ status = "okay";
+};
+
+&ehci1 {
+ status = "okay";
+};
+
+&ehci2 {
+ status = "okay";
+};
+
+&ehci3 {
+ status = "okay";
+};
+
+&emac {
+ phy-handle = <&int_mii_phy>;
+ phy-mode = "mii";
+ allwinner,leds-active-low;
+ status = "okay";
+};
+
+&hdmi {
+ status = "okay";
+};
+
+&hdmi_out {
+ hdmi_out_con: endpoint {
+ remote-endpoint = <&hdmi_con_in>;
+ };
+};
+
+&i2s2 {
+ status = "okay";
+};
+
+&sound_hdmi {
+ status = "okay";
+};
+
+&ir {
+ pinctrl-names = "default";
+ pinctrl-0 = <&r_ir_rx_pin>;
+ status = "disabled";
+};
+
+&rtc {
+ clocks = <&ext_osc32k>;
+};
+
+&mmc0 {
+ vmmc-supply = <®_vcc3v3>;
+ bus-width = <4>;
+ cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>; /* PF6 */
+ status = "okay";
+};
+
+&mmc1 {
+ vmmc-supply = <®_vcc3v3>;
+ mmc-pwrseq = <&wifi_pwrseq>;
+ bus-width = <4>;
+ non-removable;
+ status = "okay";
+
+ brcmf: wifi@1 {
+ reg = <1>;
+ compatible = "brcm,bcm4329-fmac";
+ interrupt-parent = <&r_pio>;
+ interrupts = <0 7 IRQ_TYPE_LEVEL_LOW>; /* PL7 */
+ interrupt-names = "host-wake";
+ };
+
+};
+
+&mmc2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc2_8bit_pins>;
+ vmmc-supply = <®_vcc3v3>;
+ bus-width = <8>;
+ non-removable;
+ cap-mmc-hw-reset;
+ status = "disabled";
+};
+
+&ohci0 {
+ status = "okay";
+};
+
+&ohci1 {
+ status = "okay";
+};
+
+&ohci2 {
+ status = "okay";
+};
+
+&ohci3 {
+ status = "okay";
+};
+
+&i2c1 {
+ status = "disabled"; /* PA19,PA18 */
+};
+
+&i2c0 {
+ status = "okay"; /* PA11, PA12 */
+};
+
+&r_i2c {
+ status = "okay";
+
+ axp22x: pmic@34 {
+ compatible = "x-powers,axp221";
+ reg = <0x34>;
+ interrupt-parent = <&r_intc>;
+ interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+ };
+};
+
+#include "arm/axp22x.dtsi"
+
+&ac_power_supply {
+ status = "okay";
+};
+
+®_aldo2 { /* VCC-PG 1.8 */
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-pg";
+};
+
+®_aldo3 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-pll-avcc";
+};
+
+®_dc1sw {
+ regulator-name = "vcc-phy";
+};
+
+®_dcdc1 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-3v3";
+};
+
+®_dcdc2 {
+ regulator-always-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1360000>;
+ regulator-name = "vdd-cpux-a";
+};
+
+®_dcdc3 {
+ regulator-always-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1360000>;
+ regulator-name = "vdd-cpux-b";
+};
+
+/* DCDC3 is polyphased with DCDC2 */
+
+/*
+ * The DRAM chips used by rbs-h5 boards are DDR3 -compatibl
+ *
+ */
+®_dcdc5 {
+ regulator-always-on;
+ regulator-min-microvolt = <1500000>;
+ regulator-max-microvolt = <1500000>;
+ regulator-name = "vcc-dram";
+};
+
+®_dldo1 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-1";
+};
+
+®_dldo2 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-2";
+};
+
+®_dldo3 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-3";
+};
+
+®_dldo4 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-4";
+};
+ /* VCC-wifi-IO 1.8 */
+®_eldo1 {
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-wifi-io-1";
+};
+
+®_eldo2 {
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-wifi-io-2";
+};
+
+®_eldo3 {
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-wifi-io-3";
+};
+
+
+®_rtc_ldo {
+ regulator-name = "vcc-rtc";
+};
+
+&spi0 {
+ pinctrl-names = "default", "default";
+ pinctrl-1 = <&spi0_cs1>;
+ cs-gpios = <0>, <&pio 0 3 0>; /* PA3 */
+
+ status = "okay";
+ spidev@0 {
+ compatible = "rohm,dh2228fv";
+ status = "okay";
+ reg = <0>;
+ spi-max-frequency = <1000000>;
+ };
+ spidev@1 {
+ compatible = "rohm,dh2228fv";
+ status = "okay";
+ reg = <1>;
+ spi-max-frequency = <1000000>;
+ };
+};
+
+&spi1 {
+ pinctrl-names = "default", "default";
+
+ status = "okay";
+ spidev@0 {
+ compatible = "rohm,dh2228fv";
+ status = "okay";
+ reg = <0>;
+ spi-max-frequency = <1000000>;
+ };
+};
+
+&pio {
+ spi0_cs1: spi0_cs1 {
+ pins = "PA3";
+ function = "gpio_out";
+ output-high;
+ };
+};
+
+
+&r_pwm {
+ status = "okay";
+};
+
+/* to debag serial */
+&uart0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_pa_pins>;
+ status = "okay";
+};
+
+/* to bt-wifi module */
+&uart1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart1_pins>, <&uart1_rts_cts_pins>;
+ uart-has-rtscts;
+ status = "okay";
+
+ bluetooth {
+ compatible = "brcm,bcm43438-bt";
+ clocks = <&rtc 1>;
+ clock-names = "lpo";
+ device-wakeup-gpios = <&r_pio 0 4 GPIO_ACTIVE_HIGH>; /* PL4 AP-WAKE-BT */
+ host-wakeup-gpios = <&r_pio 0 6 GPIO_ACTIVE_HIGH>; /* PL6 BT-WAKE-AP */
+ shutdown-gpios = <&r_pio 0 5 GPIO_ACTIVE_HIGH>; /* PL5 BT-RST-N */
+ max-speed = <1500000>;
+ };
+};
+
+&uart2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart2_pins>, <&uart2_rts_cts_pins>;
+ status = "disabled";
+};
+
+&r_uart {
+ pinctrl-names = "default";
+ pinctrl-0 = <&r_uart_pins>;
+ status = "disabled";
+};
+
+&usb_otg {
+ dr_mode = "host";
+ status = "okay";
+};
+
+&usbphy {
+ status = "okay";
+};
+
+
Index: v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-repka-pi3-alt-pwm-v1.4.dts
===================================================================
--- v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-repka-pi3-alt-pwm-v1.4.dts (nonexistent)
+++ v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-repka-pi3-alt-pwm-v1.4.dts (revision 385)
@@ -0,0 +1,424 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+// Copyright (C) 2016 ARM Ltd.
+
+/dts-v1/;
+#include "sun50i-h5-repka-3-1.4.dtsi"
+#include "sun50i-h5-cpu-opp-1.4ghz.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
+
+/ {
+ model = "Repka-Pi3-H5";
+ repka-freq = "1.4 GHz";
+ repka-pinout = "5";
+ compatible = "rbs,repka-pi3", "allwinner,sun50i-h5";
+
+ reg_vcc3v3: vcc3v3 {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc3v3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ aliases {
+ mmc0 = &mmc0;
+ ethernet0 = &emac;
+ serial0 = &uart0;
+ serial1 = &uart1;
+ spi0 = &spi0;
+ spi1 = &spi1;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ connector {
+ compatible = "hdmi-connector";
+ type = "a";
+
+ port {
+ hdmi_con_in: endpoint {
+ remote-endpoint = <&hdmi_out_con>;
+ };
+ };
+ };
+
+ ext_osc32k: ext_osc32k_clk {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <32768>;
+ clock-output-names = "ext_osc32k";
+ };
+
+ leds {
+ compatible = "gpio-leds";
+
+ status {
+ label = "rbs:red:status";
+ gpios = <&pio 0 20 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "heartbeat";
+ };
+ };
+
+ wifi_pwrseq: wifi_pwrseq {
+ compatible = "mmc-pwrseq-simple";
+ reset-gpios = <&r_pio 0 8 GPIO_ACTIVE_LOW>;
+ post-power-on-delay-ms = <200>;
+ };
+
+};
+
+&codec {
+ allwinner,audio-routing =
+ "Line Out", "LINEOUT",
+ "MIC1", "Mic",
+ "Mic", "MBIAS";
+ status = "okay";
+};
+
+&cpu0 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&cpu1 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&cpu2 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&cpu3 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&de {
+ status = "okay";
+};
+
+&ehci0 {
+ status = "okay";
+};
+
+&ehci1 {
+ status = "okay";
+};
+
+&ehci2 {
+ status = "okay";
+};
+
+&ehci3 {
+ status = "okay";
+};
+
+&emac {
+ phy-handle = <&int_mii_phy>;
+ phy-mode = "mii";
+ allwinner,leds-active-low;
+ status = "okay";
+};
+
+&hdmi {
+ status = "okay";
+};
+
+&hdmi_out {
+ hdmi_out_con: endpoint {
+ remote-endpoint = <&hdmi_con_in>;
+ };
+};
+
+&i2s2 {
+ status = "okay";
+};
+
+&sound_hdmi {
+ status = "okay";
+};
+
+&ir {
+ pinctrl-names = "default";
+ pinctrl-0 = <&r_ir_rx_pin>;
+ status = "disabled";
+};
+
+&rtc {
+ clocks = <&ext_osc32k>;
+};
+
+&mmc0 {
+ vmmc-supply = <®_vcc3v3>;
+ bus-width = <4>;
+ cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>; /* PF6 */
+ status = "okay";
+};
+
+&mmc1 {
+ vmmc-supply = <®_vcc3v3>;
+ mmc-pwrseq = <&wifi_pwrseq>;
+ bus-width = <4>;
+ non-removable;
+ status = "okay";
+
+ brcmf: wifi@1 {
+ reg = <1>;
+ compatible = "brcm,bcm4329-fmac";
+ interrupt-parent = <&r_pio>;
+ interrupts = <0 7 IRQ_TYPE_LEVEL_LOW>; /* PL7 */
+ interrupt-names = "host-wake";
+ };
+
+};
+
+&mmc2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc2_8bit_pins>;
+ vmmc-supply = <®_vcc3v3>;
+ bus-width = <8>;
+ non-removable;
+ cap-mmc-hw-reset;
+ status = "disabled";
+};
+
+&ohci0 {
+ status = "okay";
+};
+
+&ohci1 {
+ status = "okay";
+};
+
+&ohci2 {
+ status = "okay";
+};
+
+&ohci3 {
+ status = "okay";
+};
+
+&i2c1 {
+ status = "disabled"; /* PA19,PA18 */
+};
+
+&i2c0 {
+ status = "okay"; /* PA11, PA12 */
+};
+
+&r_i2c {
+ status = "okay";
+
+ axp22x: pmic@34 {
+ compatible = "x-powers,axp221";
+ reg = <0x34>;
+ interrupt-parent = <&r_intc>;
+ interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+ };
+};
+
+#include "arm/axp22x.dtsi"
+
+&ac_power_supply {
+ status = "okay";
+};
+
+®_aldo2 { /* VCC-PG 1.8 */
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-pg";
+};
+
+®_aldo3 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-pll-avcc";
+};
+
+®_dc1sw {
+ regulator-name = "vcc-phy";
+};
+
+®_dcdc1 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-3v3";
+};
+
+®_dcdc2 {
+ regulator-always-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1360000>;
+ regulator-name = "vdd-cpux-a";
+};
+
+®_dcdc3 {
+ regulator-always-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1360000>;
+ regulator-name = "vdd-cpux-b";
+};
+
+/* DCDC3 is polyphased with DCDC2 */
+
+/*
+ * The DRAM chips used by rbs-h5 boards are DDR3 -compatibl
+ *
+ */
+®_dcdc5 {
+ regulator-always-on;
+ regulator-min-microvolt = <1500000>;
+ regulator-max-microvolt = <1500000>;
+ regulator-name = "vcc-dram";
+};
+
+®_dldo1 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-1";
+};
+
+®_dldo2 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-2";
+};
+
+®_dldo3 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-3";
+};
+
+®_dldo4 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-4";
+};
+ /* VCC-wifi-IO 1.8 */
+®_eldo1 {
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-wifi-io-1";
+};
+
+®_eldo2 {
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-wifi-io-2";
+};
+
+®_eldo3 {
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-wifi-io-3";
+};
+
+
+®_rtc_ldo {
+ regulator-name = "vcc-rtc";
+};
+
+&spi0 {
+ pinctrl-names = "default", "default";
+ pinctrl-1 = <&spi0_cs1>;
+ cs-gpios = <0>, <&pio 0 3 0>; /* PA3 */
+
+ status = "okay";
+ spidev@0 {
+ compatible = "rohm,dh2228fv";
+ status = "okay";
+ reg = <0>;
+ spi-max-frequency = <1000000>;
+ };
+ spidev@1 {
+ compatible = "rohm,dh2228fv";
+ status = "okay";
+ reg = <1>;
+ spi-max-frequency = <1000000>;
+ };
+};
+
+&spi1 {
+ pinctrl-names = "default", "default";
+
+ status = "okay";
+ spidev@0 {
+ compatible = "rohm,dh2228fv";
+ status = "okay";
+ reg = <0>;
+ spi-max-frequency = <1000000>;
+ };
+};
+
+&pio {
+ spi0_cs1: spi0_cs1 {
+ pins = "PA3";
+ function = "gpio_out";
+ output-high;
+ };
+};
+
+
+&r_pwm {
+ status = "okay";
+};
+
+/* to debag serial */
+&uart0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_pa_pins>;
+ status = "okay";
+};
+
+/* to bt-wifi module */
+&uart1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart1_pins>, <&uart1_rts_cts_pins>;
+ uart-has-rtscts;
+ status = "okay";
+
+ bluetooth {
+ compatible = "brcm,bcm43438-bt";
+ clocks = <&rtc 1>;
+ clock-names = "lpo";
+ device-wakeup-gpios = <&r_pio 0 4 GPIO_ACTIVE_HIGH>; /* PL4 AP-WAKE-BT */
+ host-wakeup-gpios = <&r_pio 0 6 GPIO_ACTIVE_HIGH>; /* PL6 BT-WAKE-AP */
+ shutdown-gpios = <&r_pio 0 5 GPIO_ACTIVE_HIGH>; /* PL5 BT-RST-N */
+ max-speed = <1500000>;
+ };
+};
+
+&uart2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart2_pins>, <&uart2_rts_cts_pins>;
+ status = "disabled";
+};
+
+&r_uart {
+ pinctrl-names = "default";
+ pinctrl-0 = <&r_uart_pins>;
+ status = "disabled";
+};
+
+&usb_otg {
+ dr_mode = "host";
+ status = "okay";
+};
+
+&usbphy {
+ status = "okay";
+};
+
Index: v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-repka-pi3-alt-pwm-v1.4p.dts
===================================================================
--- v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-repka-pi3-alt-pwm-v1.4p.dts (nonexistent)
+++ v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-repka-pi3-alt-pwm-v1.4p.dts (revision 385)
@@ -0,0 +1,424 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+// Copyright (C) 2016 ARM Ltd.
+
+/dts-v1/;
+#include "sun50i-h5-repka-3-1.4p.dtsi"
+#include "sun50i-h5-cpu-opp-1.4ghz.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
+
+/ {
+ model = "Repka-Pi3-H5";
+ repka-freq = "1.4 GHz";
+ repka-pinout = "5";
+ compatible = "rbs,repka-pi3", "allwinner,sun50i-h5";
+
+ reg_vcc3v3: vcc3v3 {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc3v3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ aliases {
+ mmc0 = &mmc0;
+ ethernet0 = &emac;
+ serial0 = &uart0;
+ serial1 = &uart1;
+ spi0 = &spi0;
+ spi1 = &spi1;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ connector {
+ compatible = "hdmi-connector";
+ type = "a";
+
+ port {
+ hdmi_con_in: endpoint {
+ remote-endpoint = <&hdmi_out_con>;
+ };
+ };
+ };
+
+ ext_osc32k: ext_osc32k_clk {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <32768>;
+ clock-output-names = "ext_osc32k";
+ };
+
+ leds {
+ compatible = "gpio-leds";
+
+ status {
+ label = "rbs:red:status";
+ gpios = <&pio 0 20 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "heartbeat";
+ };
+ };
+
+ wifi_pwrseq: wifi_pwrseq {
+ compatible = "mmc-pwrseq-simple";
+ reset-gpios = <&r_pio 0 8 GPIO_ACTIVE_LOW>;
+ post-power-on-delay-ms = <200>;
+ };
+
+};
+
+&codec {
+ allwinner,audio-routing =
+ "Line Out", "LINEOUT",
+ "MIC1", "Mic",
+ "Mic", "MBIAS";
+ status = "okay";
+};
+
+&cpu0 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&cpu1 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&cpu2 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&cpu3 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&de {
+ status = "okay";
+};
+
+&ehci0 {
+ status = "okay";
+};
+
+&ehci1 {
+ status = "okay";
+};
+
+&ehci2 {
+ status = "okay";
+};
+
+&ehci3 {
+ status = "okay";
+};
+
+&emac {
+ phy-handle = <&int_mii_phy>;
+ phy-mode = "mii";
+ allwinner,leds-active-low;
+ status = "okay";
+};
+
+&hdmi {
+ status = "okay";
+};
+
+&hdmi_out {
+ hdmi_out_con: endpoint {
+ remote-endpoint = <&hdmi_con_in>;
+ };
+};
+
+&i2s2 {
+ status = "okay";
+};
+
+&sound_hdmi {
+ status = "okay";
+};
+
+&ir {
+ pinctrl-names = "default";
+ pinctrl-0 = <&r_ir_rx_pin>;
+ status = "disabled";
+};
+
+&rtc {
+ clocks = <&ext_osc32k>;
+};
+
+&mmc0 {
+ vmmc-supply = <®_vcc3v3>;
+ bus-width = <4>;
+ cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>; /* PF6 */
+ status = "okay";
+};
+
+&mmc1 {
+ vmmc-supply = <®_vcc3v3>;
+ mmc-pwrseq = <&wifi_pwrseq>;
+ bus-width = <4>;
+ non-removable;
+ status = "okay";
+
+ brcmf: wifi@1 {
+ reg = <1>;
+ compatible = "brcm,bcm4329-fmac";
+ interrupt-parent = <&r_pio>;
+ interrupts = <0 7 IRQ_TYPE_LEVEL_LOW>; /* PL7 */
+ interrupt-names = "host-wake";
+ };
+
+};
+
+&mmc2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc2_8bit_pins>;
+ vmmc-supply = <®_vcc3v3>;
+ bus-width = <8>;
+ non-removable;
+ cap-mmc-hw-reset;
+ status = "disabled";
+};
+
+&ohci0 {
+ status = "okay";
+};
+
+&ohci1 {
+ status = "okay";
+};
+
+&ohci2 {
+ status = "okay";
+};
+
+&ohci3 {
+ status = "okay";
+};
+
+&i2c1 {
+ status = "disabled"; /* PA19,PA18 */
+};
+
+&i2c0 {
+ status = "okay"; /* PA11, PA12 */
+};
+
+&r_i2c {
+ status = "okay";
+
+ axp22x: pmic@34 {
+ compatible = "x-powers,axp221";
+ reg = <0x34>;
+ interrupt-parent = <&r_intc>;
+ interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+ };
+};
+
+#include "arm/axp22x.dtsi"
+
+&ac_power_supply {
+ status = "okay";
+};
+
+®_aldo2 { /* VCC-PG 1.8 */
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-pg";
+};
+
+®_aldo3 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-pll-avcc";
+};
+
+®_dc1sw {
+ regulator-name = "vcc-phy";
+};
+
+®_dcdc1 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-3v3";
+};
+
+®_dcdc2 {
+ regulator-always-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1360000>;
+ regulator-name = "vdd-cpux-a";
+};
+
+®_dcdc3 {
+ regulator-always-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1360000>;
+ regulator-name = "vdd-cpux-b";
+};
+
+/* DCDC3 is polyphased with DCDC2 */
+
+/*
+ * The DRAM chips used by rbs-h5 boards are DDR3 -compatibl
+ *
+ */
+®_dcdc5 {
+ regulator-always-on;
+ regulator-min-microvolt = <1500000>;
+ regulator-max-microvolt = <1500000>;
+ regulator-name = "vcc-dram";
+};
+
+®_dldo1 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-1";
+};
+
+®_dldo2 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-2";
+};
+
+®_dldo3 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-3";
+};
+
+®_dldo4 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-4";
+};
+ /* VCC-wifi-IO 1.8 */
+®_eldo1 {
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-wifi-io-1";
+};
+
+®_eldo2 {
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-wifi-io-2";
+};
+
+®_eldo3 {
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-wifi-io-3";
+};
+
+
+®_rtc_ldo {
+ regulator-name = "vcc-rtc";
+};
+
+&spi0 {
+ pinctrl-names = "default", "default";
+ pinctrl-1 = <&spi0_cs1>;
+ cs-gpios = <0>, <&pio 0 3 0>; /* PA3 */
+
+ status = "okay";
+ spidev@0 {
+ compatible = "rohm,dh2228fv";
+ status = "okay";
+ reg = <0>;
+ spi-max-frequency = <1000000>;
+ };
+ spidev@1 {
+ compatible = "rohm,dh2228fv";
+ status = "okay";
+ reg = <1>;
+ spi-max-frequency = <1000000>;
+ };
+};
+
+&spi1 {
+ pinctrl-names = "default", "default";
+
+ status = "okay";
+ spidev@0 {
+ compatible = "rohm,dh2228fv";
+ status = "okay";
+ reg = <0>;
+ spi-max-frequency = <1000000>;
+ };
+};
+
+&pio {
+ spi0_cs1: spi0_cs1 {
+ pins = "PA3";
+ function = "gpio_out";
+ output-high;
+ };
+};
+
+
+&r_pwm {
+ status = "okay";
+};
+
+/* to debag serial */
+&uart0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_pa_pins>;
+ status = "okay";
+};
+
+/* to bt-wifi module */
+&uart1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart1_pins>, <&uart1_rts_cts_pins>;
+ uart-has-rtscts;
+ status = "okay";
+
+ bluetooth {
+ compatible = "brcm,bcm43438-bt";
+ clocks = <&rtc 1>;
+ clock-names = "lpo";
+ device-wakeup-gpios = <&r_pio 0 4 GPIO_ACTIVE_HIGH>; /* PL4 AP-WAKE-BT */
+ host-wakeup-gpios = <&r_pio 0 6 GPIO_ACTIVE_HIGH>; /* PL6 BT-WAKE-AP */
+ shutdown-gpios = <&r_pio 0 5 GPIO_ACTIVE_HIGH>; /* PL5 BT-RST-N */
+ max-speed = <1500000>;
+ };
+};
+
+&uart2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart2_pins>, <&uart2_rts_cts_pins>;
+ status = "disabled";
+};
+
+&r_uart {
+ pinctrl-names = "default";
+ pinctrl-0 = <&r_uart_pins>;
+ status = "disabled";
+};
+
+&usb_otg {
+ dr_mode = "host";
+ status = "okay";
+};
+
+&usbphy {
+ status = "okay";
+};
+
Index: v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-repka-pi3-alt-uart-1.0ghz.dts
===================================================================
--- v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-repka-pi3-alt-uart-1.0ghz.dts (nonexistent)
+++ v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-repka-pi3-alt-uart-1.0ghz.dts (revision 385)
@@ -0,0 +1,425 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+// Copyright (C) 2016 ARM Ltd.
+
+/dts-v1/;
+#include "sun50i-h5.dtsi"
+#include "sun50i-h5-cpu-opp-1.0ghz.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
+
+/ {
+ model = "Repka-Pi3-H5";
+ repka-freq = "1.0 GHz";
+ repka-pinout = "3";
+ compatible = "rbs,repka-pi3", "allwinner,sun50i-h5";
+
+ reg_vcc3v3: vcc3v3 {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc3v3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ aliases {
+ mmc0 = &mmc0;
+ ethernet0 = &emac;
+ serial0 = &uart0;
+ serial1 = &uart1;
+ spi0 = &spi0;
+ spi1 = &spi1;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ connector {
+ compatible = "hdmi-connector";
+ type = "a";
+
+ port {
+ hdmi_con_in: endpoint {
+ remote-endpoint = <&hdmi_out_con>;
+ };
+ };
+ };
+
+ ext_osc32k: ext_osc32k_clk {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <32768>;
+ clock-output-names = "ext_osc32k";
+ };
+
+ leds {
+ compatible = "gpio-leds";
+
+ status {
+ label = "rbs:red:status";
+ gpios = <&pio 0 20 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "heartbeat";
+ };
+ };
+
+ wifi_pwrseq: wifi_pwrseq {
+ compatible = "mmc-pwrseq-simple";
+ reset-gpios = <&r_pio 0 8 GPIO_ACTIVE_LOW>;
+ post-power-on-delay-ms = <200>;
+ };
+
+};
+
+&codec {
+ allwinner,audio-routing =
+ "Line Out", "LINEOUT",
+ "MIC1", "Mic",
+ "Mic", "MBIAS";
+ status = "okay";
+};
+
+&cpu0 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&cpu1 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&cpu2 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&cpu3 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&de {
+ status = "okay";
+};
+
+&ehci0 {
+ status = "okay";
+};
+
+&ehci1 {
+ status = "okay";
+};
+
+&ehci2 {
+ status = "okay";
+};
+
+&ehci3 {
+ status = "okay";
+};
+
+&emac {
+ phy-handle = <&int_mii_phy>;
+ phy-mode = "mii";
+ allwinner,leds-active-low;
+ status = "okay";
+};
+
+&hdmi {
+ status = "okay";
+};
+
+&hdmi_out {
+ hdmi_out_con: endpoint {
+ remote-endpoint = <&hdmi_con_in>;
+ };
+};
+
+&i2s2 {
+ status = "okay";
+};
+
+&sound_hdmi {
+ status = "okay";
+};
+
+&ir {
+ pinctrl-names = "default";
+ pinctrl-0 = <&r_ir_rx_pin>;
+ status = "disabled";
+};
+
+&rtc {
+ clocks = <&ext_osc32k>;
+};
+
+&mmc0 {
+ vmmc-supply = <®_vcc3v3>;
+ bus-width = <4>;
+ cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>; /* PF6 */
+ status = "okay";
+};
+
+&mmc1 {
+ vmmc-supply = <®_vcc3v3>;
+ mmc-pwrseq = <&wifi_pwrseq>;
+ bus-width = <4>;
+ non-removable;
+ status = "okay";
+
+ brcmf: wifi@1 {
+ reg = <1>;
+ compatible = "brcm,bcm4329-fmac";
+ interrupt-parent = <&r_pio>;
+ interrupts = <0 7 IRQ_TYPE_LEVEL_LOW>; /* PL7 */
+ interrupt-names = "host-wake";
+ };
+
+};
+
+&mmc2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc2_8bit_pins>;
+ vmmc-supply = <®_vcc3v3>;
+ bus-width = <8>;
+ non-removable;
+ cap-mmc-hw-reset;
+ status = "disabled";
+};
+
+&ohci0 {
+ status = "okay";
+};
+
+&ohci1 {
+ status = "okay";
+};
+
+&ohci2 {
+ status = "okay";
+};
+
+&ohci3 {
+ status = "okay";
+};
+
+&i2c1 {
+ status = "disabled"; /* PA19,PA18 */
+};
+
+&i2c0 {
+ status = "okay"; /* PA11, PA12 */
+};
+
+&r_i2c {
+ status = "okay";
+
+ axp22x: pmic@34 {
+ compatible = "x-powers,axp221";
+ reg = <0x34>;
+ interrupt-parent = <&r_intc>;
+ interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+ };
+};
+
+#include "arm/axp22x.dtsi"
+
+&ac_power_supply {
+ status = "okay";
+};
+
+®_aldo2 { /* VCC-PG 1.8 */
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-pg";
+};
+
+®_aldo3 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-pll-avcc";
+};
+
+®_dc1sw {
+ regulator-name = "vcc-phy";
+};
+
+®_dcdc1 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-3v3";
+};
+
+®_dcdc2 {
+ regulator-always-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1360000>;
+ regulator-name = "vdd-cpux-a";
+};
+
+®_dcdc3 {
+ regulator-always-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1360000>;
+ regulator-name = "vdd-cpux-b";
+};
+
+/* DCDC3 is polyphased with DCDC2 */
+
+/*
+ * The DRAM chips used by rbs-h5 boards are DDR3 -compatibl
+ *
+ */
+®_dcdc5 {
+ regulator-always-on;
+ regulator-min-microvolt = <1500000>;
+ regulator-max-microvolt = <1500000>;
+ regulator-name = "vcc-dram";
+};
+
+®_dldo1 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-1";
+};
+
+®_dldo2 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-2";
+};
+
+®_dldo3 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-3";
+};
+
+®_dldo4 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-4";
+};
+ /* VCC-wifi-IO 1.8 */
+®_eldo1 {
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-wifi-io-1";
+};
+
+®_eldo2 {
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-wifi-io-2";
+};
+
+®_eldo3 {
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-wifi-io-3";
+};
+
+
+®_rtc_ldo {
+ regulator-name = "vcc-rtc";
+};
+
+&spi0 {
+ pinctrl-names = "default", "default";
+ pinctrl-1 = <&spi0_cs1>;
+ cs-gpios = <0>, <&pio 0 3 0>; /* PA3 */
+
+ status = "okay";
+ spidev@0 {
+ compatible = "rohm,dh2228fv";
+ status = "okay";
+ reg = <0>;
+ spi-max-frequency = <1000000>;
+ };
+ spidev@1 {
+ compatible = "rohm,dh2228fv";
+ status = "okay";
+ reg = <1>;
+ spi-max-frequency = <1000000>;
+ };
+};
+
+&spi1 {
+ pinctrl-names = "default", "default";
+
+ status = "okay";
+ spidev@0 {
+ compatible = "rohm,dh2228fv";
+ status = "okay";
+ reg = <0>;
+ spi-max-frequency = <1000000>;
+ };
+};
+
+&pio {
+ spi0_cs1: spi0_cs1 {
+ pins = "PA3";
+ function = "gpio_out";
+ output-high;
+ };
+};
+
+
+&r_pwm {
+ status = "disabled";
+};
+
+/* to debag serial */
+&uart0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_pa_pins>;
+ status = "okay";
+};
+
+/* to bt-wifi module */
+&uart1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart1_pins>, <&uart1_rts_cts_pins>;
+ uart-has-rtscts;
+ status = "okay";
+
+ bluetooth {
+ compatible = "brcm,bcm43438-bt";
+ clocks = <&rtc 1>;
+ clock-names = "lpo";
+ device-wakeup-gpios = <&r_pio 0 4 GPIO_ACTIVE_HIGH>; /* PL4 AP-WAKE-BT */
+ host-wakeup-gpios = <&r_pio 0 6 GPIO_ACTIVE_HIGH>; /* PL6 BT-WAKE-AP */
+ shutdown-gpios = <&r_pio 0 5 GPIO_ACTIVE_HIGH>; /* PL5 BT-RST-N */
+ max-speed = <1500000>;
+ };
+};
+
+&uart2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart2_pins>;
+ status = "okay";
+};
+
+&r_uart {
+ pinctrl-names = "default";
+ pinctrl-0 = <&r_uart_pins>;
+ status = "okay";
+};
+
+&usb_otg {
+ dr_mode = "host";
+ status = "okay";
+};
+
+&usbphy {
+ status = "okay";
+};
+
+
Index: v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-repka-pi3-alt-uart-1.2ghz.dts
===================================================================
--- v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-repka-pi3-alt-uart-1.2ghz.dts (nonexistent)
+++ v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-repka-pi3-alt-uart-1.2ghz.dts (revision 385)
@@ -0,0 +1,425 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+// Copyright (C) 2016 ARM Ltd.
+
+/dts-v1/;
+#include "sun50i-h5.dtsi"
+#include "sun50i-h5-cpu-opp-1.2ghz.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
+
+/ {
+ model = "Repka-Pi3-H5";
+ repka-freq = "1.2 GHz";
+ repka-pinout = "3";
+ compatible = "rbs,repka-pi3", "allwinner,sun50i-h5";
+
+ reg_vcc3v3: vcc3v3 {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc3v3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ aliases {
+ mmc0 = &mmc0;
+ ethernet0 = &emac;
+ serial0 = &uart0;
+ serial1 = &uart1;
+ spi0 = &spi0;
+ spi1 = &spi1;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ connector {
+ compatible = "hdmi-connector";
+ type = "a";
+
+ port {
+ hdmi_con_in: endpoint {
+ remote-endpoint = <&hdmi_out_con>;
+ };
+ };
+ };
+
+ ext_osc32k: ext_osc32k_clk {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <32768>;
+ clock-output-names = "ext_osc32k";
+ };
+
+ leds {
+ compatible = "gpio-leds";
+
+ status {
+ label = "rbs:red:status";
+ gpios = <&pio 0 20 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "heartbeat";
+ };
+ };
+
+ wifi_pwrseq: wifi_pwrseq {
+ compatible = "mmc-pwrseq-simple";
+ reset-gpios = <&r_pio 0 8 GPIO_ACTIVE_LOW>;
+ post-power-on-delay-ms = <200>;
+ };
+
+};
+
+&codec {
+ allwinner,audio-routing =
+ "Line Out", "LINEOUT",
+ "MIC1", "Mic",
+ "Mic", "MBIAS";
+ status = "okay";
+};
+
+&cpu0 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&cpu1 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&cpu2 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&cpu3 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&de {
+ status = "okay";
+};
+
+&ehci0 {
+ status = "okay";
+};
+
+&ehci1 {
+ status = "okay";
+};
+
+&ehci2 {
+ status = "okay";
+};
+
+&ehci3 {
+ status = "okay";
+};
+
+&emac {
+ phy-handle = <&int_mii_phy>;
+ phy-mode = "mii";
+ allwinner,leds-active-low;
+ status = "okay";
+};
+
+&hdmi {
+ status = "okay";
+};
+
+&hdmi_out {
+ hdmi_out_con: endpoint {
+ remote-endpoint = <&hdmi_con_in>;
+ };
+};
+
+&i2s2 {
+ status = "okay";
+};
+
+&sound_hdmi {
+ status = "okay";
+};
+
+&ir {
+ pinctrl-names = "default";
+ pinctrl-0 = <&r_ir_rx_pin>;
+ status = "disabled";
+};
+
+&rtc {
+ clocks = <&ext_osc32k>;
+};
+
+&mmc0 {
+ vmmc-supply = <®_vcc3v3>;
+ bus-width = <4>;
+ cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>; /* PF6 */
+ status = "okay";
+};
+
+&mmc1 {
+ vmmc-supply = <®_vcc3v3>;
+ mmc-pwrseq = <&wifi_pwrseq>;
+ bus-width = <4>;
+ non-removable;
+ status = "okay";
+
+ brcmf: wifi@1 {
+ reg = <1>;
+ compatible = "brcm,bcm4329-fmac";
+ interrupt-parent = <&r_pio>;
+ interrupts = <0 7 IRQ_TYPE_LEVEL_LOW>; /* PL7 */
+ interrupt-names = "host-wake";
+ };
+
+};
+
+&mmc2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc2_8bit_pins>;
+ vmmc-supply = <®_vcc3v3>;
+ bus-width = <8>;
+ non-removable;
+ cap-mmc-hw-reset;
+ status = "disabled";
+};
+
+&ohci0 {
+ status = "okay";
+};
+
+&ohci1 {
+ status = "okay";
+};
+
+&ohci2 {
+ status = "okay";
+};
+
+&ohci3 {
+ status = "okay";
+};
+
+&i2c1 {
+ status = "disabled"; /* PA19,PA18 */
+};
+
+&i2c0 {
+ status = "okay"; /* PA11, PA12 */
+};
+
+&r_i2c {
+ status = "okay";
+
+ axp22x: pmic@34 {
+ compatible = "x-powers,axp221";
+ reg = <0x34>;
+ interrupt-parent = <&r_intc>;
+ interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+ };
+};
+
+#include "arm/axp22x.dtsi"
+
+&ac_power_supply {
+ status = "okay";
+};
+
+®_aldo2 { /* VCC-PG 1.8 */
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-pg";
+};
+
+®_aldo3 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-pll-avcc";
+};
+
+®_dc1sw {
+ regulator-name = "vcc-phy";
+};
+
+®_dcdc1 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-3v3";
+};
+
+®_dcdc2 {
+ regulator-always-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1360000>;
+ regulator-name = "vdd-cpux-a";
+};
+
+®_dcdc3 {
+ regulator-always-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1360000>;
+ regulator-name = "vdd-cpux-b";
+};
+
+/* DCDC3 is polyphased with DCDC2 */
+
+/*
+ * The DRAM chips used by rbs-h5 boards are DDR3 -compatibl
+ *
+ */
+®_dcdc5 {
+ regulator-always-on;
+ regulator-min-microvolt = <1500000>;
+ regulator-max-microvolt = <1500000>;
+ regulator-name = "vcc-dram";
+};
+
+®_dldo1 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-1";
+};
+
+®_dldo2 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-2";
+};
+
+®_dldo3 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-3";
+};
+
+®_dldo4 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-4";
+};
+ /* VCC-wifi-IO 1.8 */
+®_eldo1 {
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-wifi-io-1";
+};
+
+®_eldo2 {
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-wifi-io-2";
+};
+
+®_eldo3 {
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-wifi-io-3";
+};
+
+
+®_rtc_ldo {
+ regulator-name = "vcc-rtc";
+};
+
+&spi0 {
+ pinctrl-names = "default", "default";
+ pinctrl-1 = <&spi0_cs1>;
+ cs-gpios = <0>, <&pio 0 3 0>; /* PA3 */
+
+ status = "okay";
+ spidev@0 {
+ compatible = "rohm,dh2228fv";
+ status = "okay";
+ reg = <0>;
+ spi-max-frequency = <1000000>;
+ };
+ spidev@1 {
+ compatible = "rohm,dh2228fv";
+ status = "okay";
+ reg = <1>;
+ spi-max-frequency = <1000000>;
+ };
+};
+
+&spi1 {
+ pinctrl-names = "default", "default";
+
+ status = "okay";
+ spidev@0 {
+ compatible = "rohm,dh2228fv";
+ status = "okay";
+ reg = <0>;
+ spi-max-frequency = <1000000>;
+ };
+};
+
+&pio {
+ spi0_cs1: spi0_cs1 {
+ pins = "PA3";
+ function = "gpio_out";
+ output-high;
+ };
+};
+
+
+&r_pwm {
+ status = "disabled";
+};
+
+/* to debag serial */
+&uart0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_pa_pins>;
+ status = "okay";
+};
+
+/* to bt-wifi module */
+&uart1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart1_pins>, <&uart1_rts_cts_pins>;
+ uart-has-rtscts;
+ status = "okay";
+
+ bluetooth {
+ compatible = "brcm,bcm43438-bt";
+ clocks = <&rtc 1>;
+ clock-names = "lpo";
+ device-wakeup-gpios = <&r_pio 0 4 GPIO_ACTIVE_HIGH>; /* PL4 AP-WAKE-BT */
+ host-wakeup-gpios = <&r_pio 0 6 GPIO_ACTIVE_HIGH>; /* PL6 BT-WAKE-AP */
+ shutdown-gpios = <&r_pio 0 5 GPIO_ACTIVE_HIGH>; /* PL5 BT-RST-N */
+ max-speed = <1500000>;
+ };
+};
+
+&uart2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart2_pins>;
+ status = "okay";
+};
+
+&r_uart {
+ pinctrl-names = "default";
+ pinctrl-0 = <&r_uart_pins>;
+ status = "okay";
+};
+
+&usb_otg {
+ dr_mode = "host";
+ status = "okay";
+};
+
+&usbphy {
+ status = "okay";
+};
+
+
Index: v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-repka-pi3-alt-uart-1.4ghz.dts
===================================================================
--- v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-repka-pi3-alt-uart-1.4ghz.dts (nonexistent)
+++ v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-repka-pi3-alt-uart-1.4ghz.dts (revision 385)
@@ -0,0 +1,425 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+// Copyright (C) 2016 ARM Ltd.
+
+/dts-v1/;
+#include "sun50i-h5.dtsi"
+#include "sun50i-h5-cpu-opp-1.4ghz.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
+
+/ {
+ model = "Repka-Pi3-H5";
+ repka-freq = "1.4 GHz";
+ repka-pinout = "3";
+ compatible = "rbs,repka-pi3", "allwinner,sun50i-h5";
+
+ reg_vcc3v3: vcc3v3 {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc3v3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ aliases {
+ mmc0 = &mmc0;
+ ethernet0 = &emac;
+ serial0 = &uart0;
+ serial1 = &uart1;
+ spi0 = &spi0;
+ spi1 = &spi1;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ connector {
+ compatible = "hdmi-connector";
+ type = "a";
+
+ port {
+ hdmi_con_in: endpoint {
+ remote-endpoint = <&hdmi_out_con>;
+ };
+ };
+ };
+
+ ext_osc32k: ext_osc32k_clk {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <32768>;
+ clock-output-names = "ext_osc32k";
+ };
+
+ leds {
+ compatible = "gpio-leds";
+
+ status {
+ label = "rbs:red:status";
+ gpios = <&pio 0 20 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "heartbeat";
+ };
+ };
+
+ wifi_pwrseq: wifi_pwrseq {
+ compatible = "mmc-pwrseq-simple";
+ reset-gpios = <&r_pio 0 8 GPIO_ACTIVE_LOW>;
+ post-power-on-delay-ms = <200>;
+ };
+
+};
+
+&codec {
+ allwinner,audio-routing =
+ "Line Out", "LINEOUT",
+ "MIC1", "Mic",
+ "Mic", "MBIAS";
+ status = "okay";
+};
+
+&cpu0 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&cpu1 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&cpu2 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&cpu3 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&de {
+ status = "okay";
+};
+
+&ehci0 {
+ status = "okay";
+};
+
+&ehci1 {
+ status = "okay";
+};
+
+&ehci2 {
+ status = "okay";
+};
+
+&ehci3 {
+ status = "okay";
+};
+
+&emac {
+ phy-handle = <&int_mii_phy>;
+ phy-mode = "mii";
+ allwinner,leds-active-low;
+ status = "okay";
+};
+
+&hdmi {
+ status = "okay";
+};
+
+&hdmi_out {
+ hdmi_out_con: endpoint {
+ remote-endpoint = <&hdmi_con_in>;
+ };
+};
+
+&i2s2 {
+ status = "okay";
+};
+
+&sound_hdmi {
+ status = "okay";
+};
+
+&ir {
+ pinctrl-names = "default";
+ pinctrl-0 = <&r_ir_rx_pin>;
+ status = "disabled";
+};
+
+&rtc {
+ clocks = <&ext_osc32k>;
+};
+
+&mmc0 {
+ vmmc-supply = <®_vcc3v3>;
+ bus-width = <4>;
+ cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>; /* PF6 */
+ status = "okay";
+};
+
+&mmc1 {
+ vmmc-supply = <®_vcc3v3>;
+ mmc-pwrseq = <&wifi_pwrseq>;
+ bus-width = <4>;
+ non-removable;
+ status = "okay";
+
+ brcmf: wifi@1 {
+ reg = <1>;
+ compatible = "brcm,bcm4329-fmac";
+ interrupt-parent = <&r_pio>;
+ interrupts = <0 7 IRQ_TYPE_LEVEL_LOW>; /* PL7 */
+ interrupt-names = "host-wake";
+ };
+
+};
+
+&mmc2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc2_8bit_pins>;
+ vmmc-supply = <®_vcc3v3>;
+ bus-width = <8>;
+ non-removable;
+ cap-mmc-hw-reset;
+ status = "disabled";
+};
+
+&ohci0 {
+ status = "okay";
+};
+
+&ohci1 {
+ status = "okay";
+};
+
+&ohci2 {
+ status = "okay";
+};
+
+&ohci3 {
+ status = "okay";
+};
+
+&i2c1 {
+ status = "disabled"; /* PA19,PA18 */
+};
+
+&i2c0 {
+ status = "okay"; /* PA11, PA12 */
+};
+
+&r_i2c {
+ status = "okay";
+
+ axp22x: pmic@34 {
+ compatible = "x-powers,axp221";
+ reg = <0x34>;
+ interrupt-parent = <&r_intc>;
+ interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+ };
+};
+
+#include "arm/axp22x.dtsi"
+
+&ac_power_supply {
+ status = "okay";
+};
+
+®_aldo2 { /* VCC-PG 1.8 */
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-pg";
+};
+
+®_aldo3 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-pll-avcc";
+};
+
+®_dc1sw {
+ regulator-name = "vcc-phy";
+};
+
+®_dcdc1 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-3v3";
+};
+
+®_dcdc2 {
+ regulator-always-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1360000>;
+ regulator-name = "vdd-cpux-a";
+};
+
+®_dcdc3 {
+ regulator-always-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1360000>;
+ regulator-name = "vdd-cpux-b";
+};
+
+/* DCDC3 is polyphased with DCDC2 */
+
+/*
+ * The DRAM chips used by rbs-h5 boards are DDR3 -compatibl
+ *
+ */
+®_dcdc5 {
+ regulator-always-on;
+ regulator-min-microvolt = <1500000>;
+ regulator-max-microvolt = <1500000>;
+ regulator-name = "vcc-dram";
+};
+
+®_dldo1 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-1";
+};
+
+®_dldo2 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-2";
+};
+
+®_dldo3 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-3";
+};
+
+®_dldo4 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-4";
+};
+ /* VCC-wifi-IO 1.8 */
+®_eldo1 {
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-wifi-io-1";
+};
+
+®_eldo2 {
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-wifi-io-2";
+};
+
+®_eldo3 {
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-wifi-io-3";
+};
+
+
+®_rtc_ldo {
+ regulator-name = "vcc-rtc";
+};
+
+&spi0 {
+ pinctrl-names = "default", "default";
+ pinctrl-1 = <&spi0_cs1>;
+ cs-gpios = <0>, <&pio 0 3 0>; /* PA3 */
+
+ status = "okay";
+ spidev@0 {
+ compatible = "rohm,dh2228fv";
+ status = "okay";
+ reg = <0>;
+ spi-max-frequency = <1000000>;
+ };
+ spidev@1 {
+ compatible = "rohm,dh2228fv";
+ status = "okay";
+ reg = <1>;
+ spi-max-frequency = <1000000>;
+ };
+};
+
+&spi1 {
+ pinctrl-names = "default", "default";
+
+ status = "okay";
+ spidev@0 {
+ compatible = "rohm,dh2228fv";
+ status = "okay";
+ reg = <0>;
+ spi-max-frequency = <1000000>;
+ };
+};
+
+&pio {
+ spi0_cs1: spi0_cs1 {
+ pins = "PA3";
+ function = "gpio_out";
+ output-high;
+ };
+};
+
+
+&r_pwm {
+ status = "disabled";
+};
+
+/* to debag serial */
+&uart0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_pa_pins>;
+ status = "okay";
+};
+
+/* to bt-wifi module */
+&uart1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart1_pins>, <&uart1_rts_cts_pins>;
+ uart-has-rtscts;
+ status = "okay";
+
+ bluetooth {
+ compatible = "brcm,bcm43438-bt";
+ clocks = <&rtc 1>;
+ clock-names = "lpo";
+ device-wakeup-gpios = <&r_pio 0 4 GPIO_ACTIVE_HIGH>; /* PL4 AP-WAKE-BT */
+ host-wakeup-gpios = <&r_pio 0 6 GPIO_ACTIVE_HIGH>; /* PL6 BT-WAKE-AP */
+ shutdown-gpios = <&r_pio 0 5 GPIO_ACTIVE_HIGH>; /* PL5 BT-RST-N */
+ max-speed = <1500000>;
+ };
+};
+
+&uart2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart2_pins>; /* , <&uart2_rts_cts_pins> пересекается с spi cs1 */
+ status = "okay";
+};
+
+&r_uart {
+ pinctrl-names = "default";
+ pinctrl-0 = <&r_uart_pins>;
+ status = "okay";
+};
+
+&usb_otg {
+ dr_mode = "host";
+ status = "okay";
+};
+
+&usbphy {
+ status = "okay";
+};
+
+
Index: v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-repka-pi3-alt-uart-v1.4.dts
===================================================================
--- v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-repka-pi3-alt-uart-v1.4.dts (nonexistent)
+++ v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-repka-pi3-alt-uart-v1.4.dts (revision 385)
@@ -0,0 +1,424 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+// Copyright (C) 2016 ARM Ltd.
+
+/dts-v1/;
+#include "sun50i-h5-repka-3-1.4.dtsi"
+#include "sun50i-h5-cpu-opp-1.4ghz.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
+
+/ {
+ model = "Repka-Pi3-H5";
+ repka-freq = "1.4 GHz";
+ repka-pinout = "3";
+ compatible = "rbs,repka-pi3", "allwinner,sun50i-h5";
+
+ reg_vcc3v3: vcc3v3 {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc3v3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ aliases {
+ mmc0 = &mmc0;
+ ethernet0 = &emac;
+ serial0 = &uart0;
+ serial1 = &uart1;
+ spi0 = &spi0;
+ spi1 = &spi1;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ connector {
+ compatible = "hdmi-connector";
+ type = "a";
+
+ port {
+ hdmi_con_in: endpoint {
+ remote-endpoint = <&hdmi_out_con>;
+ };
+ };
+ };
+
+ ext_osc32k: ext_osc32k_clk {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <32768>;
+ clock-output-names = "ext_osc32k";
+ };
+
+ leds {
+ compatible = "gpio-leds";
+
+ status {
+ label = "rbs:red:status";
+ gpios = <&pio 0 20 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "heartbeat";
+ };
+ };
+
+ wifi_pwrseq: wifi_pwrseq {
+ compatible = "mmc-pwrseq-simple";
+ reset-gpios = <&r_pio 0 8 GPIO_ACTIVE_LOW>;
+ post-power-on-delay-ms = <200>;
+ };
+
+};
+
+&codec {
+ allwinner,audio-routing =
+ "Line Out", "LINEOUT",
+ "MIC1", "Mic",
+ "Mic", "MBIAS";
+ status = "okay";
+};
+
+&cpu0 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&cpu1 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&cpu2 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&cpu3 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&de {
+ status = "okay";
+};
+
+&ehci0 {
+ status = "okay";
+};
+
+&ehci1 {
+ status = "okay";
+};
+
+&ehci2 {
+ status = "okay";
+};
+
+&ehci3 {
+ status = "okay";
+};
+
+&emac {
+ phy-handle = <&int_mii_phy>;
+ phy-mode = "mii";
+ allwinner,leds-active-low;
+ status = "okay";
+};
+
+&hdmi {
+ status = "okay";
+};
+
+&hdmi_out {
+ hdmi_out_con: endpoint {
+ remote-endpoint = <&hdmi_con_in>;
+ };
+};
+
+&i2s2 {
+ status = "okay";
+};
+
+&sound_hdmi {
+ status = "okay";
+};
+
+&ir {
+ pinctrl-names = "default";
+ pinctrl-0 = <&r_ir_rx_pin>;
+ status = "disabled";
+};
+
+&rtc {
+ clocks = <&ext_osc32k>;
+};
+
+&mmc0 {
+ vmmc-supply = <®_vcc3v3>;
+ bus-width = <4>;
+ cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>; /* PF6 */
+ status = "okay";
+};
+
+&mmc1 {
+ vmmc-supply = <®_vcc3v3>;
+ mmc-pwrseq = <&wifi_pwrseq>;
+ bus-width = <4>;
+ non-removable;
+ status = "okay";
+
+ brcmf: wifi@1 {
+ reg = <1>;
+ compatible = "brcm,bcm4329-fmac";
+ interrupt-parent = <&r_pio>;
+ interrupts = <0 7 IRQ_TYPE_LEVEL_LOW>; /* PL7 */
+ interrupt-names = "host-wake";
+ };
+
+};
+
+&mmc2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc2_8bit_pins>;
+ vmmc-supply = <®_vcc3v3>;
+ bus-width = <8>;
+ non-removable;
+ cap-mmc-hw-reset;
+ status = "disabled";
+};
+
+&ohci0 {
+ status = "okay";
+};
+
+&ohci1 {
+ status = "okay";
+};
+
+&ohci2 {
+ status = "okay";
+};
+
+&ohci3 {
+ status = "okay";
+};
+
+&i2c1 {
+ status = "disabled"; /* PA19,PA18 */
+};
+
+&i2c0 {
+ status = "okay"; /* PA11, PA12 */
+};
+
+&r_i2c {
+ status = "okay";
+
+ axp22x: pmic@34 {
+ compatible = "x-powers,axp221";
+ reg = <0x34>;
+ interrupt-parent = <&r_intc>;
+ interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+ };
+};
+
+#include "arm/axp22x.dtsi"
+
+&ac_power_supply {
+ status = "okay";
+};
+
+®_aldo2 { /* VCC-PG 1.8 */
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-pg";
+};
+
+®_aldo3 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-pll-avcc";
+};
+
+®_dc1sw {
+ regulator-name = "vcc-phy";
+};
+
+®_dcdc1 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-3v3";
+};
+
+®_dcdc2 {
+ regulator-always-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1360000>;
+ regulator-name = "vdd-cpux-a";
+};
+
+®_dcdc3 {
+ regulator-always-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1360000>;
+ regulator-name = "vdd-cpux-b";
+};
+
+/* DCDC3 is polyphased with DCDC2 */
+
+/*
+ * The DRAM chips used by rbs-h5 boards are DDR3 -compatibl
+ *
+ */
+®_dcdc5 {
+ regulator-always-on;
+ regulator-min-microvolt = <1500000>;
+ regulator-max-microvolt = <1500000>;
+ regulator-name = "vcc-dram";
+};
+
+®_dldo1 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-1";
+};
+
+®_dldo2 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-2";
+};
+
+®_dldo3 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-3";
+};
+
+®_dldo4 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-4";
+};
+ /* VCC-wifi-IO 1.8 */
+®_eldo1 {
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-wifi-io-1";
+};
+
+®_eldo2 {
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-wifi-io-2";
+};
+
+®_eldo3 {
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-wifi-io-3";
+};
+
+
+®_rtc_ldo {
+ regulator-name = "vcc-rtc";
+};
+
+&spi0 {
+ pinctrl-names = "default", "default";
+ pinctrl-1 = <&spi0_cs1>;
+ cs-gpios = <0>, <&pio 0 3 0>; /* PA3 */
+
+ status = "okay";
+ spidev@0 {
+ compatible = "rohm,dh2228fv";
+ status = "okay";
+ reg = <0>;
+ spi-max-frequency = <1000000>;
+ };
+ spidev@1 {
+ compatible = "rohm,dh2228fv";
+ status = "okay";
+ reg = <1>;
+ spi-max-frequency = <1000000>;
+ };
+};
+
+&spi1 {
+ pinctrl-names = "default", "default";
+
+ status = "okay";
+ spidev@0 {
+ compatible = "rohm,dh2228fv";
+ status = "okay";
+ reg = <0>;
+ spi-max-frequency = <1000000>;
+ };
+};
+
+&pio {
+ spi0_cs1: spi0_cs1 {
+ pins = "PA3";
+ function = "gpio_out";
+ output-high;
+ };
+};
+
+
+&r_pwm {
+ status = "disabled";
+};
+
+/* to debag serial */
+&uart0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_pa_pins>;
+ status = "okay";
+};
+
+/* to bt-wifi module */
+&uart1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart1_pins>, <&uart1_rts_cts_pins>;
+ uart-has-rtscts;
+ status = "okay";
+
+ bluetooth {
+ compatible = "brcm,bcm43438-bt";
+ clocks = <&rtc 1>;
+ clock-names = "lpo";
+ device-wakeup-gpios = <&r_pio 0 4 GPIO_ACTIVE_HIGH>; /* PL4 AP-WAKE-BT */
+ host-wakeup-gpios = <&r_pio 0 6 GPIO_ACTIVE_HIGH>; /* PL6 BT-WAKE-AP */
+ shutdown-gpios = <&r_pio 0 5 GPIO_ACTIVE_HIGH>; /* PL5 BT-RST-N */
+ max-speed = <1500000>;
+ };
+};
+
+&uart2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart2_pins>;
+ status = "okay";
+};
+
+&r_uart {
+ pinctrl-names = "default";
+ pinctrl-0 = <&r_uart_pins>;
+ status = "okay";
+};
+
+&usb_otg {
+ dr_mode = "host";
+ status = "okay";
+};
+
+&usbphy {
+ status = "okay";
+};
+
Index: v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-repka-pi3-alt-uart-v1.4p.dts
===================================================================
--- v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-repka-pi3-alt-uart-v1.4p.dts (nonexistent)
+++ v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-repka-pi3-alt-uart-v1.4p.dts (revision 385)
@@ -0,0 +1,424 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+// Copyright (C) 2016 ARM Ltd.
+
+/dts-v1/;
+#include "sun50i-h5-repka-3-1.4p.dtsi"
+#include "sun50i-h5-cpu-opp-1.4ghz.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
+
+/ {
+ model = "Repka-Pi3-H5";
+ repka-freq = "1.4 GHz";
+ repka-pinout = "3";
+ compatible = "rbs,repka-pi3", "allwinner,sun50i-h5";
+
+ reg_vcc3v3: vcc3v3 {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc3v3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ aliases {
+ mmc0 = &mmc0;
+ ethernet0 = &emac;
+ serial0 = &uart0;
+ serial1 = &uart1;
+ spi0 = &spi0;
+ spi1 = &spi1;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ connector {
+ compatible = "hdmi-connector";
+ type = "a";
+
+ port {
+ hdmi_con_in: endpoint {
+ remote-endpoint = <&hdmi_out_con>;
+ };
+ };
+ };
+
+ ext_osc32k: ext_osc32k_clk {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <32768>;
+ clock-output-names = "ext_osc32k";
+ };
+
+ leds {
+ compatible = "gpio-leds";
+
+ status {
+ label = "rbs:red:status";
+ gpios = <&pio 0 20 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "heartbeat";
+ };
+ };
+
+ wifi_pwrseq: wifi_pwrseq {
+ compatible = "mmc-pwrseq-simple";
+ reset-gpios = <&r_pio 0 8 GPIO_ACTIVE_LOW>;
+ post-power-on-delay-ms = <200>;
+ };
+
+};
+
+&codec {
+ allwinner,audio-routing =
+ "Line Out", "LINEOUT",
+ "MIC1", "Mic",
+ "Mic", "MBIAS";
+ status = "okay";
+};
+
+&cpu0 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&cpu1 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&cpu2 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&cpu3 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&de {
+ status = "okay";
+};
+
+&ehci0 {
+ status = "okay";
+};
+
+&ehci1 {
+ status = "okay";
+};
+
+&ehci2 {
+ status = "okay";
+};
+
+&ehci3 {
+ status = "okay";
+};
+
+&emac {
+ phy-handle = <&int_mii_phy>;
+ phy-mode = "mii";
+ allwinner,leds-active-low;
+ status = "okay";
+};
+
+&hdmi {
+ status = "okay";
+};
+
+&hdmi_out {
+ hdmi_out_con: endpoint {
+ remote-endpoint = <&hdmi_con_in>;
+ };
+};
+
+&i2s2 {
+ status = "okay";
+};
+
+&sound_hdmi {
+ status = "okay";
+};
+
+&ir {
+ pinctrl-names = "default";
+ pinctrl-0 = <&r_ir_rx_pin>;
+ status = "disabled";
+};
+
+&rtc {
+ clocks = <&ext_osc32k>;
+};
+
+&mmc0 {
+ vmmc-supply = <®_vcc3v3>;
+ bus-width = <4>;
+ cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>; /* PF6 */
+ status = "okay";
+};
+
+&mmc1 {
+ vmmc-supply = <®_vcc3v3>;
+ mmc-pwrseq = <&wifi_pwrseq>;
+ bus-width = <4>;
+ non-removable;
+ status = "okay";
+
+ brcmf: wifi@1 {
+ reg = <1>;
+ compatible = "brcm,bcm4329-fmac";
+ interrupt-parent = <&r_pio>;
+ interrupts = <0 7 IRQ_TYPE_LEVEL_LOW>; /* PL7 */
+ interrupt-names = "host-wake";
+ };
+
+};
+
+&mmc2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc2_8bit_pins>;
+ vmmc-supply = <®_vcc3v3>;
+ bus-width = <8>;
+ non-removable;
+ cap-mmc-hw-reset;
+ status = "disabled";
+};
+
+&ohci0 {
+ status = "okay";
+};
+
+&ohci1 {
+ status = "okay";
+};
+
+&ohci2 {
+ status = "okay";
+};
+
+&ohci3 {
+ status = "okay";
+};
+
+&i2c1 {
+ status = "disabled"; /* PA19,PA18 */
+};
+
+&i2c0 {
+ status = "okay"; /* PA11, PA12 */
+};
+
+&r_i2c {
+ status = "okay";
+
+ axp22x: pmic@34 {
+ compatible = "x-powers,axp221";
+ reg = <0x34>;
+ interrupt-parent = <&r_intc>;
+ interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+ };
+};
+
+#include "arm/axp22x.dtsi"
+
+&ac_power_supply {
+ status = "okay";
+};
+
+®_aldo2 { /* VCC-PG 1.8 */
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-pg";
+};
+
+®_aldo3 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-pll-avcc";
+};
+
+®_dc1sw {
+ regulator-name = "vcc-phy";
+};
+
+®_dcdc1 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-3v3";
+};
+
+®_dcdc2 {
+ regulator-always-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1360000>;
+ regulator-name = "vdd-cpux-a";
+};
+
+®_dcdc3 {
+ regulator-always-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1360000>;
+ regulator-name = "vdd-cpux-b";
+};
+
+/* DCDC3 is polyphased with DCDC2 */
+
+/*
+ * The DRAM chips used by rbs-h5 boards are DDR3 -compatibl
+ *
+ */
+®_dcdc5 {
+ regulator-always-on;
+ regulator-min-microvolt = <1500000>;
+ regulator-max-microvolt = <1500000>;
+ regulator-name = "vcc-dram";
+};
+
+®_dldo1 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-1";
+};
+
+®_dldo2 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-2";
+};
+
+®_dldo3 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-3";
+};
+
+®_dldo4 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-4";
+};
+ /* VCC-wifi-IO 1.8 */
+®_eldo1 {
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-wifi-io-1";
+};
+
+®_eldo2 {
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-wifi-io-2";
+};
+
+®_eldo3 {
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-wifi-io-3";
+};
+
+
+®_rtc_ldo {
+ regulator-name = "vcc-rtc";
+};
+
+&spi0 {
+ pinctrl-names = "default", "default";
+ pinctrl-1 = <&spi0_cs1>;
+ cs-gpios = <0>, <&pio 0 3 0>; /* PA3 */
+
+ status = "okay";
+ spidev@0 {
+ compatible = "rohm,dh2228fv";
+ status = "okay";
+ reg = <0>;
+ spi-max-frequency = <1000000>;
+ };
+ spidev@1 {
+ compatible = "rohm,dh2228fv";
+ status = "okay";
+ reg = <1>;
+ spi-max-frequency = <1000000>;
+ };
+};
+
+&spi1 {
+ pinctrl-names = "default", "default";
+
+ status = "okay";
+ spidev@0 {
+ compatible = "rohm,dh2228fv";
+ status = "okay";
+ reg = <0>;
+ spi-max-frequency = <1000000>;
+ };
+};
+
+&pio {
+ spi0_cs1: spi0_cs1 {
+ pins = "PA3";
+ function = "gpio_out";
+ output-high;
+ };
+};
+
+
+&r_pwm {
+ status = "disabled";
+};
+
+/* to debag serial */
+&uart0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_pa_pins>;
+ status = "okay";
+};
+
+/* to bt-wifi module */
+&uart1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart1_pins>, <&uart1_rts_cts_pins>;
+ uart-has-rtscts;
+ status = "okay";
+
+ bluetooth {
+ compatible = "brcm,bcm43438-bt";
+ clocks = <&rtc 1>;
+ clock-names = "lpo";
+ device-wakeup-gpios = <&r_pio 0 4 GPIO_ACTIVE_HIGH>; /* PL4 AP-WAKE-BT */
+ host-wakeup-gpios = <&r_pio 0 6 GPIO_ACTIVE_HIGH>; /* PL6 BT-WAKE-AP */
+ shutdown-gpios = <&r_pio 0 5 GPIO_ACTIVE_HIGH>; /* PL5 BT-RST-N */
+ max-speed = <1500000>;
+ };
+};
+
+&uart2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart2_pins>;
+ status = "okay";
+};
+
+&r_uart {
+ pinctrl-names = "default";
+ pinctrl-0 = <&r_uart_pins>;
+ status = "okay";
+};
+
+&usb_otg {
+ dr_mode = "host";
+ status = "okay";
+};
+
+&usbphy {
+ status = "okay";
+};
+
Index: v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-repka-pi3-alt-v1.4.dts
===================================================================
--- v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-repka-pi3-alt-v1.4.dts (nonexistent)
+++ v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-repka-pi3-alt-v1.4.dts (revision 385)
@@ -0,0 +1,424 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+// Copyright (C) 2016 ARM Ltd.
+
+/dts-v1/;
+#include "sun50i-h5-repka-3-1.4.dtsi"
+#include "sun50i-h5-cpu-opp-1.4ghz.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
+
+/ {
+ model = "Repka-Pi3-H5";
+ repka-freq = "1.4 GHz";
+ repka-pinout = "2";
+ compatible = "rbs,repka-pi3", "allwinner,sun50i-h5";
+
+ reg_vcc3v3: vcc3v3 {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc3v3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ aliases {
+ mmc0 = &mmc0;
+ ethernet0 = &emac;
+ serial0 = &uart0;
+ serial1 = &uart1;
+ spi0 = &spi0;
+ spi1 = &spi1;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ connector {
+ compatible = "hdmi-connector";
+ type = "a";
+
+ port {
+ hdmi_con_in: endpoint {
+ remote-endpoint = <&hdmi_out_con>;
+ };
+ };
+ };
+
+ ext_osc32k: ext_osc32k_clk {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <32768>;
+ clock-output-names = "ext_osc32k";
+ };
+
+ leds {
+ compatible = "gpio-leds";
+
+ status {
+ label = "rbs:red:status";
+ gpios = <&pio 0 20 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "heartbeat";
+ };
+ };
+
+ wifi_pwrseq: wifi_pwrseq {
+ compatible = "mmc-pwrseq-simple";
+ reset-gpios = <&r_pio 0 8 GPIO_ACTIVE_LOW>;
+ post-power-on-delay-ms = <200>;
+ };
+
+};
+
+&codec {
+ allwinner,audio-routing =
+ "Line Out", "LINEOUT",
+ "MIC1", "Mic",
+ "Mic", "MBIAS";
+ status = "okay";
+};
+
+&cpu0 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&cpu1 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&cpu2 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&cpu3 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&de {
+ status = "okay";
+};
+
+&ehci0 {
+ status = "okay";
+};
+
+&ehci1 {
+ status = "okay";
+};
+
+&ehci2 {
+ status = "okay";
+};
+
+&ehci3 {
+ status = "okay";
+};
+
+&emac {
+ phy-handle = <&int_mii_phy>;
+ phy-mode = "mii";
+ allwinner,leds-active-low;
+ status = "okay";
+};
+
+&hdmi {
+ status = "okay";
+};
+
+&hdmi_out {
+ hdmi_out_con: endpoint {
+ remote-endpoint = <&hdmi_con_in>;
+ };
+};
+
+&i2s2 {
+ status = "okay";
+};
+
+&sound_hdmi {
+ status = "okay";
+};
+
+&ir {
+ pinctrl-names = "default";
+ pinctrl-0 = <&r_ir_rx_pin>;
+ status = "disabled";
+};
+
+&rtc {
+ clocks = <&ext_osc32k>;
+};
+
+&mmc0 {
+ vmmc-supply = <®_vcc3v3>;
+ bus-width = <4>;
+ cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>; /* PF6 */
+ status = "okay";
+};
+
+&mmc1 {
+ vmmc-supply = <®_vcc3v3>;
+ mmc-pwrseq = <&wifi_pwrseq>;
+ bus-width = <4>;
+ non-removable;
+ status = "okay";
+
+ brcmf: wifi@1 {
+ reg = <1>;
+ compatible = "brcm,bcm4329-fmac";
+ interrupt-parent = <&r_pio>;
+ interrupts = <0 7 IRQ_TYPE_LEVEL_LOW>; /* PL7 */
+ interrupt-names = "host-wake";
+ };
+
+};
+
+&mmc2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc2_8bit_pins>;
+ vmmc-supply = <®_vcc3v3>;
+ bus-width = <8>;
+ non-removable;
+ cap-mmc-hw-reset;
+ status = "disabled";
+};
+
+&ohci0 {
+ status = "okay";
+};
+
+&ohci1 {
+ status = "okay";
+};
+
+&ohci2 {
+ status = "okay";
+};
+
+&ohci3 {
+ status = "okay";
+};
+
+&i2c1 {
+ status = "disabled"; /* PA19,PA18 */
+};
+
+&i2c0 {
+ status = "okay"; /* PA11, PA12 */
+};
+
+&r_i2c {
+ status = "okay";
+
+ axp22x: pmic@34 {
+ compatible = "x-powers,axp221";
+ reg = <0x34>;
+ interrupt-parent = <&r_intc>;
+ interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+ };
+};
+
+#include "arm/axp22x.dtsi"
+
+&ac_power_supply {
+ status = "okay";
+};
+
+®_aldo2 { /* VCC-PG 1.8 */
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-pg";
+};
+
+®_aldo3 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-pll-avcc";
+};
+
+®_dc1sw {
+ regulator-name = "vcc-phy";
+};
+
+®_dcdc1 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-3v3";
+};
+
+®_dcdc2 {
+ regulator-always-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1360000>;
+ regulator-name = "vdd-cpux-a";
+};
+
+®_dcdc3 {
+ regulator-always-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1360000>;
+ regulator-name = "vdd-cpux-b";
+};
+
+/* DCDC3 is polyphased with DCDC2 */
+
+/*
+ * The DRAM chips used by rbs-h5 boards are DDR3 -compatibl
+ *
+ */
+®_dcdc5 {
+ regulator-always-on;
+ regulator-min-microvolt = <1500000>;
+ regulator-max-microvolt = <1500000>;
+ regulator-name = "vcc-dram";
+};
+
+®_dldo1 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-1";
+};
+
+®_dldo2 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-2";
+};
+
+®_dldo3 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-3";
+};
+
+®_dldo4 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-4";
+};
+ /* VCC-wifi-IO 1.8 */
+®_eldo1 {
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-wifi-io-1";
+};
+
+®_eldo2 {
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-wifi-io-2";
+};
+
+®_eldo3 {
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-wifi-io-3";
+};
+
+
+®_rtc_ldo {
+ regulator-name = "vcc-rtc";
+};
+
+&spi0 {
+ pinctrl-names = "default", "default";
+ pinctrl-1 = <&spi0_cs1>;
+ cs-gpios = <0>, <&pio 0 3 0>; /* PA3 */
+
+ status = "okay";
+ spidev@0 {
+ compatible = "rohm,dh2228fv";
+ status = "okay";
+ reg = <0>;
+ spi-max-frequency = <1000000>;
+ };
+ spidev@1 {
+ compatible = "rohm,dh2228fv";
+ status = "okay";
+ reg = <1>;
+ spi-max-frequency = <1000000>;
+ };
+};
+
+&spi1 {
+ pinctrl-names = "default", "default";
+
+ status = "okay";
+ spidev@0 {
+ compatible = "rohm,dh2228fv";
+ status = "okay";
+ reg = <0>;
+ spi-max-frequency = <1000000>;
+ };
+};
+
+&pio {
+ spi0_cs1: spi0_cs1 {
+ pins = "PA3";
+ function = "gpio_out";
+ output-high;
+ };
+};
+
+
+&r_pwm {
+ status = "disabled";
+};
+
+/* to debag serial */
+&uart0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_pa_pins>;
+ status = "okay";
+};
+
+/* to bt-wifi module */
+&uart1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart1_pins>, <&uart1_rts_cts_pins>;
+ uart-has-rtscts;
+ status = "okay";
+
+ bluetooth {
+ compatible = "brcm,bcm43438-bt";
+ clocks = <&rtc 1>;
+ clock-names = "lpo";
+ device-wakeup-gpios = <&r_pio 0 4 GPIO_ACTIVE_HIGH>; /* PL4 AP-WAKE-BT */
+ host-wakeup-gpios = <&r_pio 0 6 GPIO_ACTIVE_HIGH>; /* PL6 BT-WAKE-AP */
+ shutdown-gpios = <&r_pio 0 5 GPIO_ACTIVE_HIGH>; /* PL5 BT-RST-N */
+ max-speed = <1500000>;
+ };
+};
+
+&uart2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart2_pins>, <&uart2_rts_cts_pins>;
+ status = "disabled";
+};
+
+&r_uart {
+ pinctrl-names = "default";
+ pinctrl-0 = <&r_uart_pins>;
+ status = "disabled";
+};
+
+&usb_otg {
+ dr_mode = "host";
+ status = "okay";
+};
+
+&usbphy {
+ status = "okay";
+};
+
Index: v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-repka-pi3-alt-v1.4p.dts
===================================================================
--- v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-repka-pi3-alt-v1.4p.dts (nonexistent)
+++ v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-repka-pi3-alt-v1.4p.dts (revision 385)
@@ -0,0 +1,424 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+// Copyright (C) 2016 ARM Ltd.
+
+/dts-v1/;
+#include "sun50i-h5-repka-3-1.4p.dtsi"
+#include "sun50i-h5-cpu-opp-1.4ghz.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
+
+/ {
+ model = "Repka-Pi3-H5";
+ repka-freq = "1.4 GHz";
+ repka-pinout = "2";
+ compatible = "rbs,repka-pi3", "allwinner,sun50i-h5";
+
+ reg_vcc3v3: vcc3v3 {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc3v3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ aliases {
+ mmc0 = &mmc0;
+ ethernet0 = &emac;
+ serial0 = &uart0;
+ serial1 = &uart1;
+ spi0 = &spi0;
+ spi1 = &spi1;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ connector {
+ compatible = "hdmi-connector";
+ type = "a";
+
+ port {
+ hdmi_con_in: endpoint {
+ remote-endpoint = <&hdmi_out_con>;
+ };
+ };
+ };
+
+ ext_osc32k: ext_osc32k_clk {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <32768>;
+ clock-output-names = "ext_osc32k";
+ };
+
+ leds {
+ compatible = "gpio-leds";
+
+ status {
+ label = "rbs:red:status";
+ gpios = <&pio 0 20 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "heartbeat";
+ };
+ };
+
+ wifi_pwrseq: wifi_pwrseq {
+ compatible = "mmc-pwrseq-simple";
+ reset-gpios = <&r_pio 0 8 GPIO_ACTIVE_LOW>;
+ post-power-on-delay-ms = <200>;
+ };
+
+};
+
+&codec {
+ allwinner,audio-routing =
+ "Line Out", "LINEOUT",
+ "MIC1", "Mic",
+ "Mic", "MBIAS";
+ status = "okay";
+};
+
+&cpu0 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&cpu1 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&cpu2 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&cpu3 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&de {
+ status = "okay";
+};
+
+&ehci0 {
+ status = "okay";
+};
+
+&ehci1 {
+ status = "okay";
+};
+
+&ehci2 {
+ status = "okay";
+};
+
+&ehci3 {
+ status = "okay";
+};
+
+&emac {
+ phy-handle = <&int_mii_phy>;
+ phy-mode = "mii";
+ allwinner,leds-active-low;
+ status = "okay";
+};
+
+&hdmi {
+ status = "okay";
+};
+
+&hdmi_out {
+ hdmi_out_con: endpoint {
+ remote-endpoint = <&hdmi_con_in>;
+ };
+};
+
+&i2s2 {
+ status = "okay";
+};
+
+&sound_hdmi {
+ status = "okay";
+};
+
+&ir {
+ pinctrl-names = "default";
+ pinctrl-0 = <&r_ir_rx_pin>;
+ status = "disabled";
+};
+
+&rtc {
+ clocks = <&ext_osc32k>;
+};
+
+&mmc0 {
+ vmmc-supply = <®_vcc3v3>;
+ bus-width = <4>;
+ cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>; /* PF6 */
+ status = "okay";
+};
+
+&mmc1 {
+ vmmc-supply = <®_vcc3v3>;
+ mmc-pwrseq = <&wifi_pwrseq>;
+ bus-width = <4>;
+ non-removable;
+ status = "okay";
+
+ brcmf: wifi@1 {
+ reg = <1>;
+ compatible = "brcm,bcm4329-fmac";
+ interrupt-parent = <&r_pio>;
+ interrupts = <0 7 IRQ_TYPE_LEVEL_LOW>; /* PL7 */
+ interrupt-names = "host-wake";
+ };
+
+};
+
+&mmc2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc2_8bit_pins>;
+ vmmc-supply = <®_vcc3v3>;
+ bus-width = <8>;
+ non-removable;
+ cap-mmc-hw-reset;
+ status = "disabled";
+};
+
+&ohci0 {
+ status = "okay";
+};
+
+&ohci1 {
+ status = "okay";
+};
+
+&ohci2 {
+ status = "okay";
+};
+
+&ohci3 {
+ status = "okay";
+};
+
+&i2c1 {
+ status = "disabled"; /* PA19,PA18 */
+};
+
+&i2c0 {
+ status = "okay"; /* PA11, PA12 */
+};
+
+&r_i2c {
+ status = "okay";
+
+ axp22x: pmic@34 {
+ compatible = "x-powers,axp221";
+ reg = <0x34>;
+ interrupt-parent = <&r_intc>;
+ interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+ };
+};
+
+#include "arm/axp22x.dtsi"
+
+&ac_power_supply {
+ status = "okay";
+};
+
+®_aldo2 { /* VCC-PG 1.8 */
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-pg";
+};
+
+®_aldo3 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-pll-avcc";
+};
+
+®_dc1sw {
+ regulator-name = "vcc-phy";
+};
+
+®_dcdc1 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-3v3";
+};
+
+®_dcdc2 {
+ regulator-always-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1360000>;
+ regulator-name = "vdd-cpux-a";
+};
+
+®_dcdc3 {
+ regulator-always-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1360000>;
+ regulator-name = "vdd-cpux-b";
+};
+
+/* DCDC3 is polyphased with DCDC2 */
+
+/*
+ * The DRAM chips used by rbs-h5 boards are DDR3 -compatibl
+ *
+ */
+®_dcdc5 {
+ regulator-always-on;
+ regulator-min-microvolt = <1500000>;
+ regulator-max-microvolt = <1500000>;
+ regulator-name = "vcc-dram";
+};
+
+®_dldo1 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-1";
+};
+
+®_dldo2 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-2";
+};
+
+®_dldo3 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-3";
+};
+
+®_dldo4 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-4";
+};
+ /* VCC-wifi-IO 1.8 */
+®_eldo1 {
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-wifi-io-1";
+};
+
+®_eldo2 {
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-wifi-io-2";
+};
+
+®_eldo3 {
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-wifi-io-3";
+};
+
+
+®_rtc_ldo {
+ regulator-name = "vcc-rtc";
+};
+
+&spi0 {
+ pinctrl-names = "default", "default";
+ pinctrl-1 = <&spi0_cs1>;
+ cs-gpios = <0>, <&pio 0 3 0>; /* PA3 */
+
+ status = "okay";
+ spidev@0 {
+ compatible = "rohm,dh2228fv";
+ status = "okay";
+ reg = <0>;
+ spi-max-frequency = <1000000>;
+ };
+ spidev@1 {
+ compatible = "rohm,dh2228fv";
+ status = "okay";
+ reg = <1>;
+ spi-max-frequency = <1000000>;
+ };
+};
+
+&spi1 {
+ pinctrl-names = "default", "default";
+
+ status = "okay";
+ spidev@0 {
+ compatible = "rohm,dh2228fv";
+ status = "okay";
+ reg = <0>;
+ spi-max-frequency = <1000000>;
+ };
+};
+
+&pio {
+ spi0_cs1: spi0_cs1 {
+ pins = "PA3";
+ function = "gpio_out";
+ output-high;
+ };
+};
+
+
+&r_pwm {
+ status = "disabled";
+};
+
+/* to debag serial */
+&uart0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_pa_pins>;
+ status = "okay";
+};
+
+/* to bt-wifi module */
+&uart1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart1_pins>, <&uart1_rts_cts_pins>;
+ uart-has-rtscts;
+ status = "okay";
+
+ bluetooth {
+ compatible = "brcm,bcm43438-bt";
+ clocks = <&rtc 1>;
+ clock-names = "lpo";
+ device-wakeup-gpios = <&r_pio 0 4 GPIO_ACTIVE_HIGH>; /* PL4 AP-WAKE-BT */
+ host-wakeup-gpios = <&r_pio 0 6 GPIO_ACTIVE_HIGH>; /* PL6 BT-WAKE-AP */
+ shutdown-gpios = <&r_pio 0 5 GPIO_ACTIVE_HIGH>; /* PL5 BT-RST-N */
+ max-speed = <1500000>;
+ };
+};
+
+&uart2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart2_pins>, <&uart2_rts_cts_pins>;
+ status = "disabled";
+};
+
+&r_uart {
+ pinctrl-names = "default";
+ pinctrl-0 = <&r_uart_pins>;
+ status = "disabled";
+};
+
+&usb_otg {
+ dr_mode = "host";
+ status = "okay";
+};
+
+&usbphy {
+ status = "okay";
+};
+
Index: v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-repka-pi3-alt.dts
===================================================================
--- v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-repka-pi3-alt.dts (nonexistent)
+++ v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-repka-pi3-alt.dts (revision 385)
@@ -0,0 +1,408 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+// Copyright (C) 2016 ARM Ltd.
+
+/dts-v1/;
+#include "sun50i-h5.dtsi"
+#include "sun50i-h5-cpu-opp.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
+
+/ {
+ model = "Repka-Pi3-H5";
+ compatible = "rbs,repka-pi3", "allwinner,sun50i-h5";
+
+ reg_vcc3v3: vcc3v3 {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc3v3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ aliases {
+ mmc0 = &mmc0;
+ ethernet0 = &emac;
+ serial0 = &uart0;
+ serial1 = &uart1;
+ spi0 = &spi0;
+ spi1 = &spi1;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ connector {
+ compatible = "hdmi-connector";
+ type = "a";
+
+ port {
+ hdmi_con_in: endpoint {
+ remote-endpoint = <&hdmi_out_con>;
+ };
+ };
+ };
+
+ ext_osc32k: ext_osc32k_clk {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <32768>;
+ clock-output-names = "ext_osc32k";
+ };
+
+ leds {
+ compatible = "gpio-leds";
+
+ status {
+ label = "rbs:red:status";
+ gpios = <&pio 0 20 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "heartbeat";
+ };
+ };
+
+ wifi_pwrseq: wifi_pwrseq {
+ compatible = "mmc-pwrseq-simple";
+ reset-gpios = <&r_pio 0 8 GPIO_ACTIVE_LOW>;
+ post-power-on-delay-ms = <200>;
+ };
+
+};
+
+&codec {
+ allwinner,audio-routing =
+ "Line Out", "LINEOUT",
+ "MIC1", "Mic",
+ "Mic", "MBIAS";
+ status = "okay";
+};
+
+&cpu0 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&cpu1 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&cpu2 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&cpu3 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&de {
+ status = "okay";
+};
+
+&ehci0 {
+ status = "okay";
+};
+
+&ehci1 {
+ status = "okay";
+};
+
+&ehci2 {
+ status = "okay";
+};
+
+&ehci3 {
+ status = "okay";
+};
+
+&emac {
+ phy-handle = <&int_mii_phy>;
+ phy-mode = "mii";
+ allwinner,leds-active-low;
+ status = "okay";
+};
+
+&hdmi {
+ status = "okay";
+};
+
+&hdmi_out {
+ hdmi_out_con: endpoint {
+ remote-endpoint = <&hdmi_con_in>;
+ };
+};
+
+&ir {
+ pinctrl-names = "default";
+ pinctrl-0 = <&r_ir_rx_pin>;
+ status = "disabled";
+};
+
+&rtc {
+ clocks = <&ext_osc32k>;
+};
+
+&mmc0 {
+ vmmc-supply = <®_vcc3v3>;
+ bus-width = <4>;
+ cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>; /* PF6 */
+ status = "okay";
+};
+
+&mmc1 {
+ vmmc-supply = <®_vcc3v3>;
+ mmc-pwrseq = <&wifi_pwrseq>;
+ bus-width = <4>;
+ non-removable;
+ status = "okay";
+
+ brcmf: wifi@1 {
+ reg = <1>;
+ compatible = "brcm,bcm4329-fmac";
+ interrupt-parent = <&r_pio>;
+ interrupts = <0 7 IRQ_TYPE_LEVEL_LOW>; /* PL7 */
+ interrupt-names = "host-wake";
+ };
+
+};
+
+&mmc2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc2_8bit_pins>;
+ vmmc-supply = <®_vcc3v3>;
+ bus-width = <8>;
+ non-removable;
+ cap-mmc-hw-reset;
+ status = "disabled";
+};
+
+&ohci0 {
+ status = "okay";
+};
+
+&ohci1 {
+ status = "okay";
+};
+
+&ohci2 {
+ status = "okay";
+};
+
+&ohci3 {
+ status = "okay";
+};
+
+&i2c1 {
+ status = "disabled"; /* PA19,PA18 */
+};
+
+&i2c0 {
+ status = "okay"; /* PA11, PA12 */
+};
+
+&r_i2c {
+ status = "okay";
+
+ axp22x: pmic@34 {
+ compatible = "x-powers,axp221";
+ reg = <0x34>;
+ interrupt-parent = <&r_intc>;
+ interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+ };
+};
+
+#include "arm/axp22x.dtsi"
+
+&ac_power_supply {
+ status = "okay";
+};
+
+®_aldo2 { /* VCC-PG 1.8 */
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-pg";
+};
+
+®_aldo3 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-pll-avcc";
+};
+
+®_dc1sw {
+ regulator-name = "vcc-phy";
+};
+
+®_dcdc1 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-3v3";
+};
+
+®_dcdc2 {
+ regulator-always-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1360000>;
+ regulator-name = "vdd-cpux-a";
+};
+
+®_dcdc3 {
+ regulator-always-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1360000>;
+ regulator-name = "vdd-cpux-b";
+};
+
+/* DCDC3 is polyphased with DCDC2 */
+
+/*
+ * The DRAM chips used by rbs-h5 boards are DDR3 -compatibl
+ *
+ */
+®_dcdc5 {
+ regulator-always-on;
+ regulator-min-microvolt = <1500000>;
+ regulator-max-microvolt = <1500000>;
+ regulator-name = "vcc-dram";
+};
+
+®_dldo1 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-1";
+};
+
+®_dldo2 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-2";
+};
+
+®_dldo3 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-3";
+};
+
+®_dldo4 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-4";
+};
+ /* VCC-wifi-IO 1.8 */
+®_eldo1 {
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-wifi-io-1";
+};
+
+®_eldo2 {
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-wifi-io-2";
+};
+
+®_eldo3 {
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-wifi-io-3";
+};
+
+
+®_rtc_ldo {
+ regulator-name = "vcc-rtc";
+};
+
+&spi0 {
+ pinctrl-names = "default", "default";
+ pinctrl-1 = <&spi0_cs1>;
+ cs-gpios = <0>, <&pio 0 3 0>; /* PA3 */
+
+ status = "okay";
+ spidev@0 {
+ compatible = "rohm,dh2228fv";
+ status = "okay";
+ reg = <0>;
+ spi-max-frequency = <1000000>;
+ };
+ spidev@1 {
+ compatible = "rohm,dh2228fv";
+ status = "okay";
+ reg = <1>;
+ spi-max-frequency = <1000000>;
+ };
+};
+
+&spi1 {
+ pinctrl-names = "default", "default";
+
+ status = "okay";
+ spidev@0 {
+ compatible = "rohm,dh2228fv";
+ status = "okay";
+ reg = <0>;
+ spi-max-frequency = <1000000>;
+ };
+};
+
+&pio {
+ spi0_cs1: spi0_cs1 {
+ pins = "PA3";
+ function = "gpio_out";
+ output-high;
+ };
+};
+
+
+&r_pwm {
+ status = "disabled";
+};
+
+/* to debag serial */
+&uart0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_pa_pins>;
+ status = "okay";
+};
+
+/* to bt-wifi module */
+&uart1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart1_pins>, <&uart1_rts_cts_pins>;
+ uart-has-rtscts;
+ status = "okay";
+
+
+
+};
+
+&uart2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart2_pins>, <&uart2_rts_cts_pins>;
+ status = "disabled";
+};
+
+&r_uart {
+ pinctrl-names = "default";
+ pinctrl-0 = <&r_uart_pins>;
+ status = "disabled";
+};
+
+&usb_otg {
+ dr_mode = "host";
+ status = "okay";
+};
+
+&usbphy {
+ status = "okay";
+};
+
+
Index: v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-repka-pi3-v1.4.dts
===================================================================
--- v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-repka-pi3-v1.4.dts (nonexistent)
+++ v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-repka-pi3-v1.4.dts (revision 385)
@@ -0,0 +1,424 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+// Copyright (C) 2016 ARM Ltd.
+
+/dts-v1/;
+#include "sun50i-h5-repka-3-1.4.dtsi"
+#include "sun50i-h5-cpu-opp-1.4ghz.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
+
+/ {
+ model = "Repka-Pi3-H5";
+ repka-freq = "1.4 GHz";
+ repka-pinout = "1";
+ compatible = "rbs,repka-pi3", "allwinner,sun50i-h5";
+
+ reg_vcc3v3: vcc3v3 {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc3v3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ aliases {
+ mmc0 = &mmc0;
+ ethernet0 = &emac;
+ serial0 = &uart0;
+ serial1 = &uart1;
+ spi0 = &spi0;
+ spi1 = &spi1;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ connector {
+ compatible = "hdmi-connector";
+ type = "a";
+
+ port {
+ hdmi_con_in: endpoint {
+ remote-endpoint = <&hdmi_out_con>;
+ };
+ };
+ };
+
+ ext_osc32k: ext_osc32k_clk {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <32768>;
+ clock-output-names = "ext_osc32k";
+ };
+
+ leds {
+ compatible = "gpio-leds";
+
+ status {
+ label = "rbs:red:status";
+ gpios = <&pio 0 20 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "heartbeat";
+ };
+ };
+
+ wifi_pwrseq: wifi_pwrseq {
+ compatible = "mmc-pwrseq-simple";
+ reset-gpios = <&r_pio 0 8 GPIO_ACTIVE_LOW>;
+ post-power-on-delay-ms = <200>;
+ };
+
+};
+
+&codec {
+ allwinner,audio-routing =
+ "Line Out", "LINEOUT",
+ "MIC1", "Mic",
+ "Mic", "MBIAS";
+ status = "okay";
+};
+
+&cpu0 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&cpu1 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&cpu2 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&cpu3 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&de {
+ status = "okay";
+};
+
+&ehci0 {
+ status = "okay";
+};
+
+&ehci1 {
+ status = "okay";
+};
+
+&ehci2 {
+ status = "okay";
+};
+
+&ehci3 {
+ status = "okay";
+};
+
+&emac {
+ phy-handle = <&int_mii_phy>;
+ phy-mode = "mii";
+ allwinner,leds-active-low;
+ status = "okay";
+};
+
+&hdmi {
+ status = "okay";
+};
+
+&hdmi_out {
+ hdmi_out_con: endpoint {
+ remote-endpoint = <&hdmi_con_in>;
+ };
+};
+
+&i2s2 {
+ status = "okay";
+};
+
+&sound_hdmi {
+ status = "okay";
+};
+
+&ir {
+ pinctrl-names = "default";
+ pinctrl-0 = <&r_ir_rx_pin>;
+ status = "disabled";
+};
+
+&rtc {
+ clocks = <&ext_osc32k>;
+};
+
+&mmc0 {
+ vmmc-supply = <®_vcc3v3>;
+ bus-width = <4>;
+ cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>; /* PF6 */
+ status = "okay";
+};
+
+&mmc1 {
+ vmmc-supply = <®_vcc3v3>;
+ mmc-pwrseq = <&wifi_pwrseq>;
+ bus-width = <4>;
+ non-removable;
+ status = "okay";
+
+ brcmf: wifi@1 {
+ reg = <1>;
+ compatible = "brcm,bcm4329-fmac";
+ interrupt-parent = <&r_pio>;
+ interrupts = <0 7 IRQ_TYPE_LEVEL_LOW>; /* PL7 */
+ interrupt-names = "host-wake";
+ };
+
+};
+
+&mmc2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc2_8bit_pins>;
+ vmmc-supply = <®_vcc3v3>;
+ bus-width = <8>;
+ non-removable;
+ cap-mmc-hw-reset;
+ status = "disabled";
+};
+
+&ohci0 {
+ status = "okay";
+};
+
+&ohci1 {
+ status = "okay";
+};
+
+&ohci2 {
+ status = "okay";
+};
+
+&ohci3 {
+ status = "okay";
+};
+
+&i2c1 {
+ status = "disabled"; /* PA19,PA18 */
+};
+
+&i2c0 {
+ status = "disabled"; /* PA11, PA12 */
+};
+
+&r_i2c {
+ status = "okay";
+
+ axp22x: pmic@34 {
+ compatible = "x-powers,axp221";
+ reg = <0x34>;
+ interrupt-parent = <&r_intc>;
+ interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+ };
+};
+
+#include "arm/axp22x.dtsi"
+
+&ac_power_supply {
+ status = "okay";
+};
+
+®_aldo2 { /* VCC-PG 1.8 */
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-pg";
+};
+
+®_aldo3 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-pll-avcc";
+};
+
+®_dc1sw {
+ regulator-name = "vcc-phy";
+};
+
+®_dcdc1 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-3v3";
+};
+
+®_dcdc2 {
+ regulator-always-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1360000>;
+ regulator-name = "vdd-cpux-a";
+};
+
+®_dcdc3 {
+ regulator-always-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1360000>;
+ regulator-name = "vdd-cpux-b";
+};
+
+/* DCDC3 is polyphased with DCDC2 */
+
+/*
+ * The DRAM chips used by rbs-h5 boards are DDR3 -compatibl
+ *
+ */
+®_dcdc5 {
+ regulator-always-on;
+ regulator-min-microvolt = <1500000>;
+ regulator-max-microvolt = <1500000>;
+ regulator-name = "vcc-dram";
+};
+
+®_dldo1 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-1";
+};
+
+®_dldo2 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-2";
+};
+
+®_dldo3 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-3";
+};
+
+®_dldo4 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-4";
+};
+ /* VCC-wifi-IO 1.8 */
+®_eldo1 {
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-wifi-io-1";
+};
+
+®_eldo2 {
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-wifi-io-2";
+};
+
+®_eldo3 {
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-wifi-io-3";
+};
+
+
+®_rtc_ldo {
+ regulator-name = "vcc-rtc";
+};
+
+&spi0 {
+ pinctrl-names = "default", "default";
+ pinctrl-1 = <&spi0_cs1>;
+ cs-gpios = <0>, <&pio 0 3 0>; /* PA3 */
+
+ status = "disabled";
+ spidev@0 {
+ compatible = "rohm,dh2228fv";
+ status = "okay";
+ reg = <0>;
+ spi-max-frequency = <1000000>;
+ };
+ spidev@1 {
+ compatible = "rohm,dh2228fv";
+ status = "okay";
+ reg = <1>;
+ spi-max-frequency = <1000000>;
+ };
+};
+
+&spi1 {
+ pinctrl-names = "default", "default";
+
+ status = "disabled";
+ spidev@0 {
+ compatible = "rohm,dh2228fv";
+ status = "okay";
+ reg = <0>;
+ spi-max-frequency = <1000000>;
+ };
+};
+
+&pio {
+ spi0_cs1: spi0_cs1 {
+ pins = "PA3";
+ function = "gpio_out";
+ output-high;
+ };
+};
+
+
+&r_pwm {
+ status = "disabled";
+};
+
+/* to debag serial */
+&uart0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_pa_pins>;
+ status = "okay";
+};
+
+/* to bt-wifi module */
+&uart1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart1_pins>, <&uart1_rts_cts_pins>;
+ uart-has-rtscts;
+ status = "okay";
+
+ bluetooth {
+ compatible = "brcm,bcm43438-bt";
+ clocks = <&rtc 1>;
+ clock-names = "lpo";
+ device-wakeup-gpios = <&r_pio 0 4 GPIO_ACTIVE_HIGH>; /* PL4 AP-WAKE-BT */
+ host-wakeup-gpios = <&r_pio 0 6 GPIO_ACTIVE_HIGH>; /* PL6 BT-WAKE-AP */
+ shutdown-gpios = <&r_pio 0 5 GPIO_ACTIVE_HIGH>; /* PL5 BT-RST-N */
+ max-speed = <1500000>;
+ };
+};
+
+&uart2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart2_pins>, <&uart2_rts_cts_pins>;
+ status = "disabled";
+};
+
+&r_uart {
+ pinctrl-names = "default";
+ pinctrl-0 = <&r_uart_pins>;
+ status = "disabled";
+};
+
+&usb_otg {
+ dr_mode = "host";
+ status = "okay";
+};
+
+&usbphy {
+ status = "okay";
+};
+
Index: v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-repka-pi3-v1.4p.dts
===================================================================
--- v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-repka-pi3-v1.4p.dts (nonexistent)
+++ v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-repka-pi3-v1.4p.dts (revision 385)
@@ -0,0 +1,424 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+// Copyright (C) 2016 ARM Ltd.
+
+/dts-v1/;
+#include "sun50i-h5-repka-3-1.4p.dtsi"
+#include "sun50i-h5-cpu-opp-1.4ghz.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
+
+/ {
+ model = "Repka-Pi3-H5";
+ repka-freq = "1.4 GHz";
+ repka-pinout = "1";
+ compatible = "rbs,repka-pi3", "allwinner,sun50i-h5";
+
+ reg_vcc3v3: vcc3v3 {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc3v3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ aliases {
+ mmc0 = &mmc0;
+ ethernet0 = &emac;
+ serial0 = &uart0;
+ serial1 = &uart1;
+ spi0 = &spi0;
+ spi1 = &spi1;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ connector {
+ compatible = "hdmi-connector";
+ type = "a";
+
+ port {
+ hdmi_con_in: endpoint {
+ remote-endpoint = <&hdmi_out_con>;
+ };
+ };
+ };
+
+ ext_osc32k: ext_osc32k_clk {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <32768>;
+ clock-output-names = "ext_osc32k";
+ };
+
+ leds {
+ compatible = "gpio-leds";
+
+ status {
+ label = "rbs:red:status";
+ gpios = <&pio 0 20 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "heartbeat";
+ };
+ };
+
+ wifi_pwrseq: wifi_pwrseq {
+ compatible = "mmc-pwrseq-simple";
+ reset-gpios = <&r_pio 0 8 GPIO_ACTIVE_LOW>;
+ post-power-on-delay-ms = <200>;
+ };
+
+};
+
+&codec {
+ allwinner,audio-routing =
+ "Line Out", "LINEOUT",
+ "MIC1", "Mic",
+ "Mic", "MBIAS";
+ status = "okay";
+};
+
+&cpu0 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&cpu1 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&cpu2 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&cpu3 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&de {
+ status = "okay";
+};
+
+&ehci0 {
+ status = "okay";
+};
+
+&ehci1 {
+ status = "okay";
+};
+
+&ehci2 {
+ status = "okay";
+};
+
+&ehci3 {
+ status = "okay";
+};
+
+&emac {
+ phy-handle = <&int_mii_phy>;
+ phy-mode = "mii";
+ allwinner,leds-active-low;
+ status = "okay";
+};
+
+&hdmi {
+ status = "okay";
+};
+
+&hdmi_out {
+ hdmi_out_con: endpoint {
+ remote-endpoint = <&hdmi_con_in>;
+ };
+};
+
+&i2s2 {
+ status = "okay";
+};
+
+&sound_hdmi {
+ status = "okay";
+};
+
+&ir {
+ pinctrl-names = "default";
+ pinctrl-0 = <&r_ir_rx_pin>;
+ status = "disabled";
+};
+
+&rtc {
+ clocks = <&ext_osc32k>;
+};
+
+&mmc0 {
+ vmmc-supply = <®_vcc3v3>;
+ bus-width = <4>;
+ cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>; /* PF6 */
+ status = "okay";
+};
+
+&mmc1 {
+ vmmc-supply = <®_vcc3v3>;
+ mmc-pwrseq = <&wifi_pwrseq>;
+ bus-width = <4>;
+ non-removable;
+ status = "okay";
+
+ brcmf: wifi@1 {
+ reg = <1>;
+ compatible = "brcm,bcm4329-fmac";
+ interrupt-parent = <&r_pio>;
+ interrupts = <0 7 IRQ_TYPE_LEVEL_LOW>; /* PL7 */
+ interrupt-names = "host-wake";
+ };
+
+};
+
+&mmc2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc2_8bit_pins>;
+ vmmc-supply = <®_vcc3v3>;
+ bus-width = <8>;
+ non-removable;
+ cap-mmc-hw-reset;
+ status = "disabled";
+};
+
+&ohci0 {
+ status = "okay";
+};
+
+&ohci1 {
+ status = "okay";
+};
+
+&ohci2 {
+ status = "okay";
+};
+
+&ohci3 {
+ status = "okay";
+};
+
+&i2c1 {
+ status = "disabled"; /* PA19,PA18 */
+};
+
+&i2c0 {
+ status = "disabled"; /* PA11, PA12 */
+};
+
+&r_i2c {
+ status = "okay";
+
+ axp22x: pmic@34 {
+ compatible = "x-powers,axp221";
+ reg = <0x34>;
+ interrupt-parent = <&r_intc>;
+ interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+ };
+};
+
+#include "arm/axp22x.dtsi"
+
+&ac_power_supply {
+ status = "okay";
+};
+
+®_aldo2 { /* VCC-PG 1.8 */
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-pg";
+};
+
+®_aldo3 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-pll-avcc";
+};
+
+®_dc1sw {
+ regulator-name = "vcc-phy";
+};
+
+®_dcdc1 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-3v3";
+};
+
+®_dcdc2 {
+ regulator-always-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1360000>;
+ regulator-name = "vdd-cpux-a";
+};
+
+®_dcdc3 {
+ regulator-always-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1360000>;
+ regulator-name = "vdd-cpux-b";
+};
+
+/* DCDC3 is polyphased with DCDC2 */
+
+/*
+ * The DRAM chips used by rbs-h5 boards are DDR3 -compatibl
+ *
+ */
+®_dcdc5 {
+ regulator-always-on;
+ regulator-min-microvolt = <1500000>;
+ regulator-max-microvolt = <1500000>;
+ regulator-name = "vcc-dram";
+};
+
+®_dldo1 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-1";
+};
+
+®_dldo2 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-2";
+};
+
+®_dldo3 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-3";
+};
+
+®_dldo4 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-4";
+};
+ /* VCC-wifi-IO 1.8 */
+®_eldo1 {
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-wifi-io-1";
+};
+
+®_eldo2 {
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-wifi-io-2";
+};
+
+®_eldo3 {
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-wifi-io-3";
+};
+
+
+®_rtc_ldo {
+ regulator-name = "vcc-rtc";
+};
+
+&spi0 {
+ pinctrl-names = "default", "default";
+ pinctrl-1 = <&spi0_cs1>;
+ cs-gpios = <0>, <&pio 0 3 0>; /* PA3 */
+
+ status = "disabled";
+ spidev@0 {
+ compatible = "rohm,dh2228fv";
+ status = "okay";
+ reg = <0>;
+ spi-max-frequency = <1000000>;
+ };
+ spidev@1 {
+ compatible = "rohm,dh2228fv";
+ status = "okay";
+ reg = <1>;
+ spi-max-frequency = <1000000>;
+ };
+};
+
+&spi1 {
+ pinctrl-names = "default", "default";
+
+ status = "disabled";
+ spidev@0 {
+ compatible = "rohm,dh2228fv";
+ status = "okay";
+ reg = <0>;
+ spi-max-frequency = <1000000>;
+ };
+};
+
+&pio {
+ spi0_cs1: spi0_cs1 {
+ pins = "PA3";
+ function = "gpio_out";
+ output-high;
+ };
+};
+
+
+&r_pwm {
+ status = "disabled";
+};
+
+/* to debag serial */
+&uart0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_pa_pins>;
+ status = "okay";
+};
+
+/* to bt-wifi module */
+&uart1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart1_pins>, <&uart1_rts_cts_pins>;
+ uart-has-rtscts;
+ status = "okay";
+
+ bluetooth {
+ compatible = "brcm,bcm43438-bt";
+ clocks = <&rtc 1>;
+ clock-names = "lpo";
+ device-wakeup-gpios = <&r_pio 0 4 GPIO_ACTIVE_HIGH>; /* PL4 AP-WAKE-BT */
+ host-wakeup-gpios = <&r_pio 0 6 GPIO_ACTIVE_HIGH>; /* PL6 BT-WAKE-AP */
+ shutdown-gpios = <&r_pio 0 5 GPIO_ACTIVE_HIGH>; /* PL5 BT-RST-N */
+ max-speed = <1500000>;
+ };
+};
+
+&uart2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart2_pins>, <&uart2_rts_cts_pins>;
+ status = "disabled";
+};
+
+&r_uart {
+ pinctrl-names = "default";
+ pinctrl-0 = <&r_uart_pins>;
+ status = "disabled";
+};
+
+&usb_otg {
+ dr_mode = "host";
+ status = "okay";
+};
+
+&usbphy {
+ status = "okay";
+};
+
Index: v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-repka-pi3.dts
===================================================================
--- v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-repka-pi3.dts (nonexistent)
+++ v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5-repka-pi3.dts (revision 385)
@@ -0,0 +1,425 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+// Copyright (C) 2016 ARM Ltd.
+
+/dts-v1/;
+#include "sun50i-h5.dtsi"
+#include "sun50i-h5-cpu-opp-1.0ghz.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
+
+/ {
+ model = "Repka-Pi3-H5";
+ option = "uboot";
+ compatible = "rbs,repka-pi3", "allwinner,sun50i-h5";
+
+ reg_vcc3v3: vcc3v3 {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc3v3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ aliases {
+ mmc0 = &mmc0;
+ ethernet0 = &emac;
+ serial0 = &uart0;
+ serial1 = &uart1;
+ spi0 = &spi0;
+ spi1 = &spi1;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ connector {
+ compatible = "hdmi-connector";
+ type = "a";
+
+ port {
+ hdmi_con_in: endpoint {
+ remote-endpoint = <&hdmi_out_con>;
+ };
+ };
+ };
+
+ ext_osc32k: ext_osc32k_clk {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <32768>;
+ clock-output-names = "ext_osc32k";
+ };
+
+ leds {
+ pinctrl-names = "default";
+
+ status {
+ label = "rbs:red:status";
+ gpios = <&pio 0 20 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "heartbeat";
+ };
+ };
+
+ wifi_pwrseq: wifi_pwrseq {
+ compatible = "mmc-pwrseq-simple";
+ reset-gpios = <&r_pio 0 8 GPIO_ACTIVE_LOW>;
+ post-power-on-delay-ms = <200>;
+ };
+
+};
+
+&codec {
+ allwinner,audio-routing =
+ "Line Out", "LINEOUT",
+ "MIC1", "Mic",
+ "Mic", "MBIAS";
+ status = "okay";
+};
+
+&cpu0 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&cpu1 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&cpu2 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&cpu3 {
+ cpu-supply = <®_dcdc2>;
+};
+
+&de {
+ status = "okay";
+};
+
+&ehci0 {
+ status = "okay";
+};
+
+&ehci1 {
+ status = "okay";
+};
+
+&ehci2 {
+ status = "okay";
+};
+
+&ehci3 {
+ status = "okay";
+};
+
+&emac {
+ phy-handle = <&int_mii_phy>;
+ phy-mode = "mii";
+ allwinner,leds-active-low;
+ status = "okay";
+};
+
+&hdmi {
+ status = "okay";
+};
+
+&hdmi_out {
+ hdmi_out_con: endpoint {
+ remote-endpoint = <&hdmi_con_in>;
+ };
+};
+
+&i2s2 {
+ status = "okay";
+};
+
+&sound_hdmi {
+ status = "okay";
+};
+
+&ir {
+ pinctrl-names = "default";
+ pinctrl-0 = <&r_ir_rx_pin>;
+ status = "disabled";
+};
+
+&rtc {
+ clocks = <&ext_osc32k>;
+};
+
+&mmc0 {
+ vmmc-supply = <®_vcc3v3>;
+ bus-width = <4>;
+ cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>; /* PF6 */
+ status = "okay";
+};
+
+&mmc1 {
+ vmmc-supply = <®_vcc3v3>;
+ mmc-pwrseq = <&wifi_pwrseq>;
+ bus-width = <4>;
+ non-removable;
+ status = "okay";
+
+ brcmf: wifi@1 {
+ reg = <1>;
+ compatible = "brcm,bcm4329-fmac";
+ interrupt-parent = <&r_pio>;
+ interrupts = <0 7 IRQ_TYPE_LEVEL_LOW>; /* PL7 */
+ interrupt-names = "host-wake";
+ };
+
+};
+
+&mmc2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc2_8bit_pins>;
+ vmmc-supply = <®_vcc3v3>;
+ bus-width = <8>;
+ non-removable;
+ cap-mmc-hw-reset;
+ status = "disabled";
+};
+
+&ohci0 {
+ status = "okay";
+};
+
+&ohci1 {
+ status = "okay";
+};
+
+&ohci2 {
+ status = "okay";
+};
+
+&ohci3 {
+ status = "okay";
+};
+
+&i2c1 {
+ status = "disabled"; /* PA19,PA18 */
+};
+
+&i2c0 {
+ status = "disabled"; /* PA11, PA12 */
+};
+
+&r_i2c {
+ status = "disabled";
+
+ axp22x: pmic@34 {
+ compatible = "x-powers,axp221";
+ reg = <0x34>;
+ interrupt-parent = <&r_intc>;
+ interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+ };
+};
+
+#include "arm/axp22x.dtsi"
+
+®_aldo2 { /* VCC-PG 1.8 */
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-pg";
+};
+
+®_aldo3 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-pll-avcc";
+};
+
+®_dc1sw {
+ regulator-name = "vcc-phy";
+};
+
+®_dcdc1 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-3v3";
+};
+
+®_dcdc2 {
+ regulator-always-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1360000>; /* 1360000 because AXP outputs 0.05 more than expected */
+ regulator-name = "vdd-cpux-a";
+};
+
+®_dcdc3 {
+ regulator-always-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1360000>;
+ regulator-name = "vdd-cpux-b";
+};
+
+/* DCDC3 is polyphased with DCDC2 */
+
+/*
+ * The DRAM chips used by rbs-h5 boards are DDR3 -compatibl
+ *
+ */
+®_dcdc5 {
+ regulator-always-on;
+ regulator-min-microvolt = <1500000>;
+ regulator-max-microvolt = <1500000>;
+ regulator-name = "vcc-dram";
+};
+
+®_dldo1 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-1";
+};
+
+®_dldo2 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-2";
+};
+
+®_dldo3 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-3";
+};
+
+®_dldo4 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi-4";
+};
+ /* VCC-wifi-IO 1.8 */
+®_eldo1 {
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-wifi-io-1";
+};
+
+®_eldo2 {
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-wifi-io-2";
+};
+
+®_eldo3 {
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-wifi-io-3";
+};
+
+/*
+ *
+ *
+ * ^__________^
+*
+*
+*/
+
+®_rtc_ldo {
+ regulator-name = "vcc-rtc";
+};
+
+&spi0 {
+ pinctrl-names = "default", "default";
+
+ status = "disabled";
+ spidev@0 {
+ compatible = "rohm,dh2228fv"; /* a crutch, since now "spidev" is missing from the kernel driver (spidev.c) */
+ status = "okay";
+ reg = <0>;
+ spi-max-frequency = <1000000>;
+ };
+ spidev@1 {
+ compatible = "rohm,dh2228fv"; /* a crutch, since now "spidev" is missing from the kernel driver (spidev.c) */
+ status = "okay";
+ reg = <1>;
+ spi-max-frequency = <1000000>;
+ };
+};
+
+&spi1 {
+ pinctrl-names = "default", "default";
+
+ status = "disabled";
+ spidev@0 {
+ compatible = "rohm,dh2228fv";
+ status = "okay";
+ reg = <0>;
+ spi-max-frequency = <1000000>;
+ };
+};
+
+&pio {
+ spi0_cs1: spi0_cs1 { /* для совместимости с распбери создаем cs1 */
+ pins = "PA3";
+ function = "gpio_out";
+ output-high;
+ };
+};
+
+
+&r_pwm {
+ status = "disabled";
+};
+
+/* to debag serial */
+&uart0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_pa_pins>;
+ status = "okay";
+};
+
+/* to bt-wifi module */
+&uart1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart1_pins>, <&uart1_rts_cts_pins>;
+ uart-has-rtscts;
+ status = "okay";
+
+ bluetooth {
+ compatible = "brcm,bcm43438-bt";
+ clocks = <&rtc 1>;
+ clock-names = "lpo";
+ device-wakeup-gpios = <&r_pio 0 4 GPIO_ACTIVE_HIGH>; /* PL4 AP-WAKE-BT */
+ host-wakeup-gpios = <&r_pio 0 6 GPIO_ACTIVE_HIGH>; /* PL6 BT-WAKE-AP */
+ shutdown-gpios = <&r_pio 0 5 GPIO_ACTIVE_HIGH>; /* PL5 BT-RST-N */
+ max-speed = <1500000>;
+ };
+};
+
+&uart2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart2_pins>, <&uart2_rts_cts_pins>; /* , <&uart2_rts_cts_pins> пересекается с spi cs1 */
+ status = "disabled";
+};
+
+&r_uart {
+ pinctrl-names = "default";
+ pinctrl-0 = <&r_uart_pins>;
+ status = "disabled";
+};
+
+&usb_otg {
+ dr_mode = "host";
+ status = "okay";
+};
+
+&usbphy {
+ status = "okay";
+};
+
+
Index: v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5.dtsi
===================================================================
--- v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5.dtsi (nonexistent)
+++ v6.x/create-6.1.53-repka-pi3-patch/linux-6.1.53-new/arch/arm64/boot/dts/allwinner/sun50i-h5.dtsi (revision 385)
@@ -0,0 +1,348 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+// Copyright (C) 2016 ARM Ltd.
+
+#include <arm/sunxi-h3-h5.dtsi>
+
+#include <dt-bindings/thermal/thermal.h>
+
+/ {
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cpu0: cpu@0 {
+ compatible = "arm,cortex-a53";
+ device_type = "cpu";
+ reg = <0>;
+ enable-method = "psci";
+ clocks = <&ccu CLK_CPUX>;
+ clock-latency-ns = <244144>; /* 8 32k periods */
+ #cooling-cells = <2>;
+ };
+
+ cpu1: cpu@1 {
+ compatible = "arm,cortex-a53";
+ device_type = "cpu";
+ reg = <1>;
+ enable-method = "psci";
+ clocks = <&ccu CLK_CPUX>;
+ clock-latency-ns = <244144>; /* 8 32k periods */
+ #cooling-cells = <2>;
+ };
+
+ cpu2: cpu@2 {
+ compatible = "arm,cortex-a53";
+ device_type = "cpu";
+ reg = <2>;
+ enable-method = "psci";
+ clocks = <&ccu CLK_CPUX>;
+ clock-latency-ns = <244144>; /* 8 32k periods */
+ #cooling-cells = <2>;
+ };
+
+ cpu3: cpu@3 {
+ compatible = "arm,cortex-a53";
+ device_type = "cpu";
+ reg = <3>;
+ enable-method = "psci";
+ clocks = <&ccu CLK_CPUX>;
+ clock-latency-ns = <244144>; /* 8 32k periods */
+ #cooling-cells = <2>;
+ };
+ };
+
+ pmu {
+ compatible = "arm,cortex-a53-pmu";
+ interrupts = <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-affinity = <&cpu0>, <&cpu1>, <&cpu2>, <&cpu3>;
+ };
+
+ psci {
+ compatible = "arm,psci-0.2";
+ method = "smc";
+ };
+
+ timer {
+ compatible = "arm,armv8-timer";
+ arm,no-tick-in-suspend;
+ interrupts = <GIC_PPI 13
+ (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+ <GIC_PPI 14
+ (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+ <GIC_PPI 11
+ (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+ <GIC_PPI 10
+ (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>;
+ };
+
+ soc {
+ syscon: system-control@1c00000 {
+ compatible = "allwinner,sun50i-h5-system-control";
+ reg = <0x01c00000 0x1000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ sram_a2: sram@40000 {
+ compatible = "mmio-sram";
+ reg = <0x00040000 0x14000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 0x00040000 0x14000>;
+
+ scpi_sram: scp-shmem@13c00 {
+ compatible = "arm,scp-shmem";
+ reg = <0x13c00 0x200>;
+ };
+ };
+
+ sram_c1: sram@18000 {
+ compatible = "mmio-sram";
+ reg = <0x00018000 0x1c000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 0x00018000 0x1c000>;
+
+ ve_sram: sram-section@0 {
+ compatible = "allwinner,sun50i-h5-sram-c1",
+ "allwinner,sun4i-a10-sram-c1";
+ reg = <0x000000 0x1c000>;
+ };
+ };
+ };
+
+ video-codec@1c0e000 {
+ compatible = "allwinner,sun50i-h5-video-engine";
+ reg = <0x01c0e000 0x1000>;
+ clocks = <&ccu CLK_BUS_VE>, <&ccu CLK_VE>,
+ <&ccu CLK_DRAM_VE>;
+ clock-names = "ahb", "mod", "ram";
+ resets = <&ccu RST_BUS_VE>;
+ interrupts = <GIC_SPI 58 IRQ_TYPE_LEVEL_HIGH>;
+ allwinner,sram = <&ve_sram 1>;
+ };
+
+ crypto: crypto@1c15000 {
+ compatible = "allwinner,sun50i-h5-crypto";
+ reg = <0x01c15000 0x1000>;
+ interrupts = <GIC_SPI 94 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_CE>, <&ccu CLK_CE>;
+ clock-names = "bus", "mod";
+ resets = <&ccu RST_BUS_CE>;
+ };
+
+ deinterlace: deinterlace@1e00000 {
+ compatible = "allwinner,sun8i-h3-deinterlace";
+ reg = <0x01e00000 0x20000>;
+ clocks = <&ccu CLK_BUS_DEINTERLACE>,
+ <&ccu CLK_DEINTERLACE>,
+ <&ccu CLK_DRAM_DEINTERLACE>;
+ clock-names = "bus", "mod", "ram";
+ resets = <&ccu RST_BUS_DEINTERLACE>;
+ interrupts = <GIC_SPI 93 IRQ_TYPE_LEVEL_HIGH>;
+ interconnects = <&mbus 9>;
+ interconnect-names = "dma-mem";
+ };
+
+ mali: gpu@1e80000 {
+ compatible = "allwinner,sun50i-h5-mali", "arm,mali-450";
+ reg = <0x01e80000 0x30000>;
+ /*
+ * While the datasheet lists an interrupt for the
+ * PMU, the actual silicon does not have the PMU
+ * block. Reads all return zero, and writes are
+ * ignored.
+ */
+ interrupts = <GIC_SPI 96 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 97 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 99 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 104 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 106 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 107 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "gp",
+ "gpmmu",
+ "pp",
+ "pp0",
+ "ppmmu0",
+ "pp1",
+ "ppmmu1",
+ "pp2",
+ "ppmmu2",
+ "pp3",
+ "ppmmu3";
+ clocks = <&ccu CLK_BUS_GPU>, <&ccu CLK_GPU>;
+ clock-names = "bus", "core";
+ resets = <&ccu RST_BUS_GPU>;
+
+ assigned-clocks = <&ccu CLK_GPU>;
+ assigned-clock-rates = <384000000>;
+ };
+
+ ths: thermal-sensor@1c25000 {
+ compatible = "allwinner,sun50i-h5-ths";
+ reg = <0x01c25000 0x400>;
+ interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
+ resets = <&ccu RST_BUS_THS>;
+ clocks = <&ccu CLK_BUS_THS>, <&ccu CLK_THS>;
+ clock-names = "bus", "mod";
+ nvmem-cells = <&ths_calibration>;
+ nvmem-cell-names = "calibration";
+ #thermal-sensor-cells = <1>;
+ };
+ };
+
+ thermal-zones {
+ cpu_thermal: cpu-thermal {
+ /* milliseconds */
+ polling-delay-passive = <250>;
+ polling-delay = <1000>;
+ thermal-sensors = <&ths 0>;
+
+ trips {
+ cpu_warm: cpu_warm {
+ temperature = <55000>;
+ hysteresis = <2000>;
+ type = "passive";
+ };
+
+ cpu_hot0: cpu_hot0 {
+ temperature = <60000>;
+ hysteresis = <2000>;
+ type = "passive";
+ };
+
+ cpu_hot1: cpu_hot1 {
+ temperature = <65000>;
+ hysteresis = <2000>;
+ type = "passive";
+ };
+
+ cpu_very_hot0: cpu_very_hot0 {
+ temperature = <70000>;
+ hysteresis = <2000>;
+ type = "passive";
+ };
+
+ cpu_very_hot1: cpu_very_hot1 {
+ temperature = <75000>;
+ hysteresis = <2000>;
+ type = "passive";
+ };
+
+ cpu_very_hot2: cpu_very_hot2 {
+ temperature = <80000>;
+ hysteresis = <2000>;
+ type = "passive";
+ };
+
+ cpu_very_hot3: cpu_very_hot3 {
+ temperature = <85000>;
+ hysteresis = <2000>;
+ type = "passive";
+ };
+
+ cpu_crit: cpu_crit {
+ temperature = <95000>;
+ hysteresis = <2000>;
+ type = "critical";
+ };
+ };
+
+ cooling-maps {
+ cpu_warm_limit_cpu {
+ trip = <&cpu_warm>;
+ cooling-device = <&cpu0 THERMAL_NO_LIMIT 1>;
+ };
+
+ cpu_hot_limit_cpu0 {
+ trip = <&cpu_hot0>;
+ cooling-device = <&cpu0 1 2>;
+ };
+
+ cpu_hot_limit_cpu1 {
+ trip = <&cpu_hot1>;
+ cooling-device = <&cpu0 2 3>;
+ };
+
+ cpu_very_hot_limit_cpu0 {
+ trip = <&cpu_very_hot0>;
+ cooling-device = <&cpu0 3 4>;
+ };
+
+ cpu_very_hot_limit_cpu1 {
+ trip = <&cpu_very_hot1>;
+ cooling-device = <&cpu0 4 5>;
+ };
+
+ cpu_very_hot_limit_cpu2 {
+ trip = <&cpu_very_hot2>;
+ cooling-device = <&cpu0 5 6>;
+ };
+
+ cpu_very_hot_limit_cpu3 {
+ trip = <&cpu_very_hot3>;
+ cooling-device = <&cpu0 7 THERMAL_NO_LIMIT>;
+ };
+
+ };
+ };
+
+ gpu-thermal {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&ths 1>;
+ };
+ };
+};
+
+&ccu {
+ compatible = "allwinner,sun50i-h5-ccu";
+};
+
+&display_clocks {
+ compatible = "allwinner,sun50i-h5-de2-clk";
+};
+
+&mmc0 {
+ compatible = "allwinner,sun50i-h5-mmc",
+ "allwinner,sun50i-a64-mmc";
+ clocks = <&ccu CLK_BUS_MMC0>, <&ccu CLK_MMC0>;
+ clock-names = "ahb", "mmc";
+};
+
+&mmc1 {
+ compatible = "allwinner,sun50i-h5-mmc",
+ "allwinner,sun50i-a64-mmc";
+ clocks = <&ccu CLK_BUS_MMC1>, <&ccu CLK_MMC1>;
+ clock-names = "ahb", "mmc";
+};
+
+&mmc2 {
+ compatible = "allwinner,sun50i-h5-emmc",
+ "allwinner,sun50i-a64-emmc";
+ clocks = <&ccu CLK_BUS_MMC2>, <&ccu CLK_MMC2>;
+ clock-names = "ahb", "mmc";
+};
+
+&pio {
+ interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH>;
+ compatible = "allwinner,sun50i-h5-pinctrl";
+};
+
+&rtc {
+ compatible = "allwinner,sun50i-h5-rtc";
+};
+
+&sid {
+ compatible = "allwinner,sun50i-h5-sid";
+};
Index: v6.x/create-6.1.53-sdhci-reset-patch/create.patch.sh
===================================================================
--- v6.x/create-6.1.53-sdhci-reset-patch/create.patch.sh (nonexistent)
+++ v6.x/create-6.1.53-sdhci-reset-patch/create.patch.sh (revision 385)
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+VERSION=6.1.53
+
+tar --files-from=file.list -xJvf ../linux-$VERSION.tar.xz
+mv linux-$VERSION linux-$VERSION-orig
+
+cp -rf ./linux-$VERSION-new ./linux-$VERSION
+
+diff --unified -Nr linux-$VERSION-orig linux-$VERSION > linux-$VERSION-sdhci-reset.patch
+
+mv linux-$VERSION-sdhci-reset.patch ../patches
+
+rm -rf ./linux-$VERSION
+rm -rf ./linux-$VERSION-orig
Property changes on: v6.x/create-6.1.53-sdhci-reset-patch/create.patch.sh
___________________________________________________________________
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: v6.x/create-6.1.53-sdhci-reset-patch/file.list
===================================================================
--- v6.x/create-6.1.53-sdhci-reset-patch/file.list (nonexistent)
+++ v6.x/create-6.1.53-sdhci-reset-patch/file.list (revision 385)
@@ -0,0 +1 @@
+linux-6.1.53/drivers/mmc/host/sdhci.c
Index: v6.x/create-6.1.53-sdhci-reset-patch/linux-6.1.53-new/drivers/mmc/host/sdhci.c
===================================================================
--- v6.x/create-6.1.53-sdhci-reset-patch/linux-6.1.53-new/drivers/mmc/host/sdhci.c (nonexistent)
+++ v6.x/create-6.1.53-sdhci-reset-patch/linux-6.1.53-new/drivers/mmc/host/sdhci.c (revision 385)
@@ -0,0 +1,5005 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * linux/drivers/mmc/host/sdhci.c - Secure Digital Host Controller Interface driver
+ *
+ * Copyright (C) 2005-2008 Pierre Ossman, All Rights Reserved.
+ *
+ * Thanks to the following companies for their support:
+ *
+ * - JMicron (hardware and technical support)
+ */
+
+#include <linux/bitfield.h>
+#include <linux/delay.h>
+#include <linux/dmaengine.h>
+#include <linux/ktime.h>
+#include <linux/highmem.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <linux/scatterlist.h>
+#include <linux/sizes.h>
+#include <linux/regulator/consumer.h>
+#include <linux/pm_runtime.h>
+#include <linux/of.h>
+
+#include <linux/leds.h>
+
+#include <linux/mmc/mmc.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/sdio.h>
+#include <linux/mmc/slot-gpio.h>
+
+#include "sdhci.h"
+
+#define DRIVER_NAME "sdhci"
+
+#define DBG(f, x...) \
+ pr_debug("%s: " DRIVER_NAME ": " f, mmc_hostname(host->mmc), ## x)
+
+#define SDHCI_DUMP(f, x...) \
+ pr_err("%s: " DRIVER_NAME ": " f, mmc_hostname(host->mmc), ## x)
+
+#define MAX_TUNING_LOOP 40
+
+static unsigned int debug_quirks = 0;
+static unsigned int debug_quirks2;
+
+static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable);
+
+static bool sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd);
+
+void sdhci_dumpregs(struct sdhci_host *host)
+{
+ SDHCI_DUMP("============ SDHCI REGISTER DUMP ===========\n");
+
+ SDHCI_DUMP("Sys addr: 0x%08x | Version: 0x%08x\n",
+ sdhci_readl(host, SDHCI_DMA_ADDRESS),
+ sdhci_readw(host, SDHCI_HOST_VERSION));
+ SDHCI_DUMP("Blk size: 0x%08x | Blk cnt: 0x%08x\n",
+ sdhci_readw(host, SDHCI_BLOCK_SIZE),
+ sdhci_readw(host, SDHCI_BLOCK_COUNT));
+ SDHCI_DUMP("Argument: 0x%08x | Trn mode: 0x%08x\n",
+ sdhci_readl(host, SDHCI_ARGUMENT),
+ sdhci_readw(host, SDHCI_TRANSFER_MODE));
+ SDHCI_DUMP("Present: 0x%08x | Host ctl: 0x%08x\n",
+ sdhci_readl(host, SDHCI_PRESENT_STATE),
+ sdhci_readb(host, SDHCI_HOST_CONTROL));
+ SDHCI_DUMP("Power: 0x%08x | Blk gap: 0x%08x\n",
+ sdhci_readb(host, SDHCI_POWER_CONTROL),
+ sdhci_readb(host, SDHCI_BLOCK_GAP_CONTROL));
+ SDHCI_DUMP("Wake-up: 0x%08x | Clock: 0x%08x\n",
+ sdhci_readb(host, SDHCI_WAKE_UP_CONTROL),
+ sdhci_readw(host, SDHCI_CLOCK_CONTROL));
+ SDHCI_DUMP("Timeout: 0x%08x | Int stat: 0x%08x\n",
+ sdhci_readb(host, SDHCI_TIMEOUT_CONTROL),
+ sdhci_readl(host, SDHCI_INT_STATUS));
+ SDHCI_DUMP("Int enab: 0x%08x | Sig enab: 0x%08x\n",
+ sdhci_readl(host, SDHCI_INT_ENABLE),
+ sdhci_readl(host, SDHCI_SIGNAL_ENABLE));
+ SDHCI_DUMP("ACmd stat: 0x%08x | Slot int: 0x%08x\n",
+ sdhci_readw(host, SDHCI_AUTO_CMD_STATUS),
+ sdhci_readw(host, SDHCI_SLOT_INT_STATUS));
+ SDHCI_DUMP("Caps: 0x%08x | Caps_1: 0x%08x\n",
+ sdhci_readl(host, SDHCI_CAPABILITIES),
+ sdhci_readl(host, SDHCI_CAPABILITIES_1));
+ SDHCI_DUMP("Cmd: 0x%08x | Max curr: 0x%08x\n",
+ sdhci_readw(host, SDHCI_COMMAND),
+ sdhci_readl(host, SDHCI_MAX_CURRENT));
+ SDHCI_DUMP("Resp[0]: 0x%08x | Resp[1]: 0x%08x\n",
+ sdhci_readl(host, SDHCI_RESPONSE),
+ sdhci_readl(host, SDHCI_RESPONSE + 4));
+ SDHCI_DUMP("Resp[2]: 0x%08x | Resp[3]: 0x%08x\n",
+ sdhci_readl(host, SDHCI_RESPONSE + 8),
+ sdhci_readl(host, SDHCI_RESPONSE + 12));
+ SDHCI_DUMP("Host ctl2: 0x%08x\n",
+ sdhci_readw(host, SDHCI_HOST_CONTROL2));
+
+ if (host->flags & SDHCI_USE_ADMA) {
+ if (host->flags & SDHCI_USE_64_BIT_DMA) {
+ SDHCI_DUMP("ADMA Err: 0x%08x | ADMA Ptr: 0x%08x%08x\n",
+ sdhci_readl(host, SDHCI_ADMA_ERROR),
+ sdhci_readl(host, SDHCI_ADMA_ADDRESS_HI),
+ sdhci_readl(host, SDHCI_ADMA_ADDRESS));
+ } else {
+ SDHCI_DUMP("ADMA Err: 0x%08x | ADMA Ptr: 0x%08x\n",
+ sdhci_readl(host, SDHCI_ADMA_ERROR),
+ sdhci_readl(host, SDHCI_ADMA_ADDRESS));
+ }
+ }
+
+ if (host->ops->dump_vendor_regs)
+ host->ops->dump_vendor_regs(host);
+
+ SDHCI_DUMP("============================================\n");
+}
+EXPORT_SYMBOL_GPL(sdhci_dumpregs);
+
+/*****************************************************************************\
+ * *
+ * Low level functions *
+ * *
+\*****************************************************************************/
+
+static void sdhci_do_enable_v4_mode(struct sdhci_host *host)
+{
+ u16 ctrl2;
+
+ ctrl2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+ if (ctrl2 & SDHCI_CTRL_V4_MODE)
+ return;
+
+ ctrl2 |= SDHCI_CTRL_V4_MODE;
+ sdhci_writew(host, ctrl2, SDHCI_HOST_CONTROL2);
+}
+
+/*
+ * This can be called before sdhci_add_host() by Vendor's host controller
+ * driver to enable v4 mode if supported.
+ */
+void sdhci_enable_v4_mode(struct sdhci_host *host)
+{
+ host->v4_mode = true;
+ sdhci_do_enable_v4_mode(host);
+}
+EXPORT_SYMBOL_GPL(sdhci_enable_v4_mode);
+
+static inline bool sdhci_data_line_cmd(struct mmc_command *cmd)
+{
+ return cmd->data || cmd->flags & MMC_RSP_BUSY;
+}
+
+static void sdhci_set_card_detection(struct sdhci_host *host, bool enable)
+{
+ u32 present;
+
+ if ((host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) ||
+ !mmc_card_is_removable(host->mmc) || mmc_can_gpio_cd(host->mmc))
+ return;
+
+ if (enable) {
+ present = sdhci_readl(host, SDHCI_PRESENT_STATE) &
+ SDHCI_CARD_PRESENT;
+
+ host->ier |= present ? SDHCI_INT_CARD_REMOVE :
+ SDHCI_INT_CARD_INSERT;
+ } else {
+ host->ier &= ~(SDHCI_INT_CARD_REMOVE | SDHCI_INT_CARD_INSERT);
+ }
+
+ sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
+ sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
+}
+
+static void sdhci_enable_card_detection(struct sdhci_host *host)
+{
+ sdhci_set_card_detection(host, true);
+}
+
+static void sdhci_disable_card_detection(struct sdhci_host *host)
+{
+ sdhci_set_card_detection(host, false);
+}
+
+static void sdhci_runtime_pm_bus_on(struct sdhci_host *host)
+{
+ if (host->bus_on)
+ return;
+ host->bus_on = true;
+ pm_runtime_get_noresume(mmc_dev(host->mmc));
+}
+
+static void sdhci_runtime_pm_bus_off(struct sdhci_host *host)
+{
+ if (!host->bus_on)
+ return;
+ host->bus_on = false;
+ pm_runtime_put_noidle(mmc_dev(host->mmc));
+}
+
+void sdhci_reset(struct sdhci_host *host, u8 mask)
+{
+ ktime_t timeout;
+
+ sdhci_writeb(host, mask, SDHCI_SOFTWARE_RESET);
+
+ if (mask & SDHCI_RESET_ALL) {
+ host->clock = 0;
+ /* Reset-all turns off SD Bus Power */
+ if (host->quirks2 & SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON)
+ sdhci_runtime_pm_bus_off(host);
+ if (host->ops->voltage_switch)
+ host->ops->voltage_switch(host);
+ }
+
+ /* Wait max 100 ms */
+ timeout = ktime_add_ms(ktime_get(), 100);
+
+ /* hw clears the bit when it's done */
+ while (1) {
+ bool timedout = ktime_after(ktime_get(), timeout);
+
+ if (!(sdhci_readb(host, SDHCI_SOFTWARE_RESET) & mask))
+ break;
+ if (timedout) {
+ pr_err("%s: Reset 0x%x never completed.\n",
+ mmc_hostname(host->mmc), (int)mask);
+ sdhci_err_stats_inc(host, CTRL_TIMEOUT);
+ sdhci_dumpregs(host);
+ return;
+ }
+ udelay(10);
+ }
+}
+EXPORT_SYMBOL_GPL(sdhci_reset);
+
+static bool sdhci_do_reset(struct sdhci_host *host, u8 mask)
+{
+ if (host->quirks & SDHCI_QUIRK_NO_CARD_NO_RESET) {
+ struct mmc_host *mmc = host->mmc;
+
+ if (!mmc->ops->get_cd(mmc))
+ return false;
+ }
+
+ host->ops->reset(host, mask);
+
+ return true;
+}
+
+static void sdhci_reset_for_all(struct sdhci_host *host)
+{
+ if (sdhci_do_reset(host, SDHCI_RESET_ALL)) {
+ if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) {
+ if (host->ops->enable_dma)
+ host->ops->enable_dma(host);
+ }
+ /* Resetting the controller clears many */
+ host->preset_enabled = false;
+ }
+}
+
+enum sdhci_reset_reason {
+ SDHCI_RESET_FOR_INIT,
+ SDHCI_RESET_FOR_REQUEST_ERROR,
+ SDHCI_RESET_FOR_REQUEST_ERROR_DATA_ONLY,
+ SDHCI_RESET_FOR_TUNING_ABORT,
+ SDHCI_RESET_FOR_CARD_REMOVED,
+ SDHCI_RESET_FOR_CQE_RECOVERY,
+};
+
+static void sdhci_reset_for_reason(struct sdhci_host *host, enum sdhci_reset_reason reason)
+{
+ if (host->quirks2 & SDHCI_QUIRK2_ISSUE_CMD_DAT_RESET_TOGETHER) {
+ sdhci_do_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
+ return;
+ }
+
+ switch (reason) {
+ case SDHCI_RESET_FOR_INIT:
+ sdhci_do_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
+ break;
+ case SDHCI_RESET_FOR_REQUEST_ERROR:
+ case SDHCI_RESET_FOR_TUNING_ABORT:
+ case SDHCI_RESET_FOR_CARD_REMOVED:
+ case SDHCI_RESET_FOR_CQE_RECOVERY:
+ sdhci_do_reset(host, SDHCI_RESET_CMD);
+ sdhci_do_reset(host, SDHCI_RESET_DATA);
+ break;
+ case SDHCI_RESET_FOR_REQUEST_ERROR_DATA_ONLY:
+ sdhci_do_reset(host, SDHCI_RESET_DATA);
+ break;
+ }
+}
+
+#define sdhci_reset_for(h, r) sdhci_reset_for_reason((h), SDHCI_RESET_FOR_##r)
+
+static void sdhci_set_default_irqs(struct sdhci_host *host)
+{
+ host->ier = SDHCI_INT_BUS_POWER | SDHCI_INT_DATA_END_BIT |
+ SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_TIMEOUT |
+ SDHCI_INT_INDEX | SDHCI_INT_END_BIT | SDHCI_INT_CRC |
+ SDHCI_INT_TIMEOUT | SDHCI_INT_DATA_END |
+ SDHCI_INT_RESPONSE;
+
+ if (host->tuning_mode == SDHCI_TUNING_MODE_2 ||
+ host->tuning_mode == SDHCI_TUNING_MODE_3)
+ host->ier |= SDHCI_INT_RETUNE;
+
+ sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
+ sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
+}
+
+static void sdhci_config_dma(struct sdhci_host *host)
+{
+ u8 ctrl;
+ u16 ctrl2;
+
+ if (host->version < SDHCI_SPEC_200)
+ return;
+
+ ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
+
+ /*
+ * Always adjust the DMA selection as some controllers
+ * (e.g. JMicron) can't do PIO properly when the selection
+ * is ADMA.
+ */
+ ctrl &= ~SDHCI_CTRL_DMA_MASK;
+ if (!(host->flags & SDHCI_REQ_USE_DMA))
+ goto out;
+
+ /* Note if DMA Select is zero then SDMA is selected */
+ if (host->flags & SDHCI_USE_ADMA)
+ ctrl |= SDHCI_CTRL_ADMA32;
+
+ if (host->flags & SDHCI_USE_64_BIT_DMA) {
+ /*
+ * If v4 mode, all supported DMA can be 64-bit addressing if
+ * controller supports 64-bit system address, otherwise only
+ * ADMA can support 64-bit addressing.
+ */
+ if (host->v4_mode) {
+ ctrl2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+ ctrl2 |= SDHCI_CTRL_64BIT_ADDR;
+ sdhci_writew(host, ctrl2, SDHCI_HOST_CONTROL2);
+ } else if (host->flags & SDHCI_USE_ADMA) {
+ /*
+ * Don't need to undo SDHCI_CTRL_ADMA32 in order to
+ * set SDHCI_CTRL_ADMA64.
+ */
+ ctrl |= SDHCI_CTRL_ADMA64;
+ }
+ }
+
+out:
+ sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
+}
+
+static void sdhci_init(struct sdhci_host *host, int soft)
+{
+ struct mmc_host *mmc = host->mmc;
+ unsigned long flags;
+
+ if (soft)
+ sdhci_reset_for(host, INIT);
+ else
+ sdhci_reset_for_all(host);
+
+ if (host->v4_mode)
+ sdhci_do_enable_v4_mode(host);
+
+ spin_lock_irqsave(&host->lock, flags);
+ sdhci_set_default_irqs(host);
+ spin_unlock_irqrestore(&host->lock, flags);
+
+ host->cqe_on = false;
+
+ if (soft) {
+ /* force clock reconfiguration */
+ host->clock = 0;
+ host->reinit_uhs = true;
+ mmc->ops->set_ios(mmc, &mmc->ios);
+ }
+}
+
+static void sdhci_reinit(struct sdhci_host *host)
+{
+ u32 cd = host->ier & (SDHCI_INT_CARD_REMOVE | SDHCI_INT_CARD_INSERT);
+
+ sdhci_init(host, 0);
+ sdhci_enable_card_detection(host);
+
+ /*
+ * A change to the card detect bits indicates a change in present state,
+ * refer sdhci_set_card_detection(). A card detect interrupt might have
+ * been missed while the host controller was being reset, so trigger a
+ * rescan to check.
+ */
+ if (cd != (host->ier & (SDHCI_INT_CARD_REMOVE | SDHCI_INT_CARD_INSERT)))
+ mmc_detect_change(host->mmc, msecs_to_jiffies(200));
+}
+
+static void __sdhci_led_activate(struct sdhci_host *host)
+{
+ u8 ctrl;
+
+ if (host->quirks & SDHCI_QUIRK_NO_LED)
+ return;
+
+ ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
+ ctrl |= SDHCI_CTRL_LED;
+ sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
+}
+
+static void __sdhci_led_deactivate(struct sdhci_host *host)
+{
+ u8 ctrl;
+
+ if (host->quirks & SDHCI_QUIRK_NO_LED)
+ return;
+
+ ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
+ ctrl &= ~SDHCI_CTRL_LED;
+ sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
+}
+
+#if IS_REACHABLE(CONFIG_LEDS_CLASS)
+static void sdhci_led_control(struct led_classdev *led,
+ enum led_brightness brightness)
+{
+ struct sdhci_host *host = container_of(led, struct sdhci_host, led);
+ unsigned long flags;
+
+ spin_lock_irqsave(&host->lock, flags);
+
+ if (host->runtime_suspended)
+ goto out;
+
+ if (brightness == LED_OFF)
+ __sdhci_led_deactivate(host);
+ else
+ __sdhci_led_activate(host);
+out:
+ spin_unlock_irqrestore(&host->lock, flags);
+}
+
+static int sdhci_led_register(struct sdhci_host *host)
+{
+ struct mmc_host *mmc = host->mmc;
+
+ if (host->quirks & SDHCI_QUIRK_NO_LED)
+ return 0;
+
+ snprintf(host->led_name, sizeof(host->led_name),
+ "%s::", mmc_hostname(mmc));
+
+ host->led.name = host->led_name;
+ host->led.brightness = LED_OFF;
+ host->led.default_trigger = mmc_hostname(mmc);
+ host->led.brightness_set = sdhci_led_control;
+
+ return led_classdev_register(mmc_dev(mmc), &host->led);
+}
+
+static void sdhci_led_unregister(struct sdhci_host *host)
+{
+ if (host->quirks & SDHCI_QUIRK_NO_LED)
+ return;
+
+ led_classdev_unregister(&host->led);
+}
+
+static inline void sdhci_led_activate(struct sdhci_host *host)
+{
+}
+
+static inline void sdhci_led_deactivate(struct sdhci_host *host)
+{
+}
+
+#else
+
+static inline int sdhci_led_register(struct sdhci_host *host)
+{
+ return 0;
+}
+
+static inline void sdhci_led_unregister(struct sdhci_host *host)
+{
+}
+
+static inline void sdhci_led_activate(struct sdhci_host *host)
+{
+ __sdhci_led_activate(host);
+}
+
+static inline void sdhci_led_deactivate(struct sdhci_host *host)
+{
+ __sdhci_led_deactivate(host);
+}
+
+#endif
+
+static void sdhci_mod_timer(struct sdhci_host *host, struct mmc_request *mrq,
+ unsigned long timeout)
+{
+ if (sdhci_data_line_cmd(mrq->cmd))
+ mod_timer(&host->data_timer, timeout);
+ else
+ mod_timer(&host->timer, timeout);
+}
+
+static void sdhci_del_timer(struct sdhci_host *host, struct mmc_request *mrq)
+{
+ if (sdhci_data_line_cmd(mrq->cmd))
+ del_timer(&host->data_timer);
+ else
+ del_timer(&host->timer);
+}
+
+static inline bool sdhci_has_requests(struct sdhci_host *host)
+{
+ return host->cmd || host->data_cmd;
+}
+
+/*****************************************************************************\
+ * *
+ * Core functions *
+ * *
+\*****************************************************************************/
+
+static void sdhci_read_block_pio(struct sdhci_host *host)
+{
+ unsigned long flags;
+ size_t blksize, len, chunk;
+ u32 scratch;
+ u8 *buf;
+
+ DBG("PIO reading\n");
+
+ blksize = host->data->blksz;
+ chunk = 0;
+
+ local_irq_save(flags);
+
+ while (blksize) {
+ BUG_ON(!sg_miter_next(&host->sg_miter));
+
+ len = min(host->sg_miter.length, blksize);
+
+ blksize -= len;
+ host->sg_miter.consumed = len;
+
+ buf = host->sg_miter.addr;
+
+ while (len) {
+ if (chunk == 0) {
+ scratch = sdhci_readl(host, SDHCI_BUFFER);
+ chunk = 4;
+ }
+
+ *buf = scratch & 0xFF;
+
+ buf++;
+ scratch >>= 8;
+ chunk--;
+ len--;
+ }
+ }
+
+ sg_miter_stop(&host->sg_miter);
+
+ local_irq_restore(flags);
+}
+
+static void sdhci_write_block_pio(struct sdhci_host *host)
+{
+ unsigned long flags;
+ size_t blksize, len, chunk;
+ u32 scratch;
+ u8 *buf;
+
+ DBG("PIO writing\n");
+
+ blksize = host->data->blksz;
+ chunk = 0;
+ scratch = 0;
+
+ local_irq_save(flags);
+
+ while (blksize) {
+ BUG_ON(!sg_miter_next(&host->sg_miter));
+
+ len = min(host->sg_miter.length, blksize);
+
+ blksize -= len;
+ host->sg_miter.consumed = len;
+
+ buf = host->sg_miter.addr;
+
+ while (len) {
+ scratch |= (u32)*buf << (chunk * 8);
+
+ buf++;
+ chunk++;
+ len--;
+
+ if ((chunk == 4) || ((len == 0) && (blksize == 0))) {
+ sdhci_writel(host, scratch, SDHCI_BUFFER);
+ chunk = 0;
+ scratch = 0;
+ }
+ }
+ }
+
+ sg_miter_stop(&host->sg_miter);
+
+ local_irq_restore(flags);
+}
+
+static void sdhci_transfer_pio(struct sdhci_host *host)
+{
+ u32 mask;
+
+ if (host->blocks == 0)
+ return;
+
+ if (host->data->flags & MMC_DATA_READ)
+ mask = SDHCI_DATA_AVAILABLE;
+ else
+ mask = SDHCI_SPACE_AVAILABLE;
+
+ /*
+ * Some controllers (JMicron JMB38x) mess up the buffer bits
+ * for transfers < 4 bytes. As long as it is just one block,
+ * we can ignore the bits.
+ */
+ if ((host->quirks & SDHCI_QUIRK_BROKEN_SMALL_PIO) &&
+ (host->data->blocks == 1))
+ mask = ~0;
+
+ while (sdhci_readl(host, SDHCI_PRESENT_STATE) & mask) {
+ if (host->quirks & SDHCI_QUIRK_PIO_NEEDS_DELAY)
+ udelay(100);
+
+ if (host->data->flags & MMC_DATA_READ)
+ sdhci_read_block_pio(host);
+ else
+ sdhci_write_block_pio(host);
+
+ host->blocks--;
+ if (host->blocks == 0)
+ break;
+ }
+
+ DBG("PIO transfer complete.\n");
+}
+
+static int sdhci_pre_dma_transfer(struct sdhci_host *host,
+ struct mmc_data *data, int cookie)
+{
+ int sg_count;
+
+ /*
+ * If the data buffers are already mapped, return the previous
+ * dma_map_sg() result.
+ */
+ if (data->host_cookie == COOKIE_PRE_MAPPED)
+ return data->sg_count;
+
+ /* Bounce write requests to the bounce buffer */
+ if (host->bounce_buffer) {
+ unsigned int length = data->blksz * data->blocks;
+
+ if (length > host->bounce_buffer_size) {
+ pr_err("%s: asked for transfer of %u bytes exceeds bounce buffer %u bytes\n",
+ mmc_hostname(host->mmc), length,
+ host->bounce_buffer_size);
+ return -EIO;
+ }
+ if (mmc_get_dma_dir(data) == DMA_TO_DEVICE) {
+ /* Copy the data to the bounce buffer */
+ if (host->ops->copy_to_bounce_buffer) {
+ host->ops->copy_to_bounce_buffer(host,
+ data, length);
+ } else {
+ sg_copy_to_buffer(data->sg, data->sg_len,
+ host->bounce_buffer, length);
+ }
+ }
+ /* Switch ownership to the DMA */
+ dma_sync_single_for_device(mmc_dev(host->mmc),
+ host->bounce_addr,
+ host->bounce_buffer_size,
+ mmc_get_dma_dir(data));
+ /* Just a dummy value */
+ sg_count = 1;
+ } else {
+ /* Just access the data directly from memory */
+ sg_count = dma_map_sg(mmc_dev(host->mmc),
+ data->sg, data->sg_len,
+ mmc_get_dma_dir(data));
+ }
+
+ if (sg_count == 0)
+ return -ENOSPC;
+
+ data->sg_count = sg_count;
+ data->host_cookie = cookie;
+
+ return sg_count;
+}
+
+static char *sdhci_kmap_atomic(struct scatterlist *sg, unsigned long *flags)
+{
+ local_irq_save(*flags);
+ return kmap_atomic(sg_page(sg)) + sg->offset;
+}
+
+static void sdhci_kunmap_atomic(void *buffer, unsigned long *flags)
+{
+ kunmap_atomic(buffer);
+ local_irq_restore(*flags);
+}
+
+void sdhci_adma_write_desc(struct sdhci_host *host, void **desc,
+ dma_addr_t addr, int len, unsigned int cmd)
+{
+ struct sdhci_adma2_64_desc *dma_desc = *desc;
+
+ /* 32-bit and 64-bit descriptors have these members in same position */
+ dma_desc->cmd = cpu_to_le16(cmd);
+ dma_desc->len = cpu_to_le16(len);
+ dma_desc->addr_lo = cpu_to_le32(lower_32_bits(addr));
+
+ if (host->flags & SDHCI_USE_64_BIT_DMA)
+ dma_desc->addr_hi = cpu_to_le32(upper_32_bits(addr));
+
+ *desc += host->desc_sz;
+}
+EXPORT_SYMBOL_GPL(sdhci_adma_write_desc);
+
+static inline void __sdhci_adma_write_desc(struct sdhci_host *host,
+ void **desc, dma_addr_t addr,
+ int len, unsigned int cmd)
+{
+ if (host->ops->adma_write_desc)
+ host->ops->adma_write_desc(host, desc, addr, len, cmd);
+ else
+ sdhci_adma_write_desc(host, desc, addr, len, cmd);
+}
+
+static void sdhci_adma_mark_end(void *desc)
+{
+ struct sdhci_adma2_64_desc *dma_desc = desc;
+
+ /* 32-bit and 64-bit descriptors have 'cmd' in same position */
+ dma_desc->cmd |= cpu_to_le16(ADMA2_END);
+}
+
+static void sdhci_adma_table_pre(struct sdhci_host *host,
+ struct mmc_data *data, int sg_count)
+{
+ struct scatterlist *sg;
+ unsigned long flags;
+ dma_addr_t addr, align_addr;
+ void *desc, *align;
+ char *buffer;
+ int len, offset, i;
+
+ /*
+ * The spec does not specify endianness of descriptor table.
+ * We currently guess that it is LE.
+ */
+
+ host->sg_count = sg_count;
+
+ desc = host->adma_table;
+ align = host->align_buffer;
+
+ align_addr = host->align_addr;
+
+ for_each_sg(data->sg, sg, host->sg_count, i) {
+ addr = sg_dma_address(sg);
+ len = sg_dma_len(sg);
+
+ /*
+ * The SDHCI specification states that ADMA addresses must
+ * be 32-bit aligned. If they aren't, then we use a bounce
+ * buffer for the (up to three) bytes that screw up the
+ * alignment.
+ */
+ offset = (SDHCI_ADMA2_ALIGN - (addr & SDHCI_ADMA2_MASK)) &
+ SDHCI_ADMA2_MASK;
+ if (offset) {
+ if (data->flags & MMC_DATA_WRITE) {
+ buffer = sdhci_kmap_atomic(sg, &flags);
+ memcpy(align, buffer, offset);
+ sdhci_kunmap_atomic(buffer, &flags);
+ }
+
+ /* tran, valid */
+ __sdhci_adma_write_desc(host, &desc, align_addr,
+ offset, ADMA2_TRAN_VALID);
+
+ BUG_ON(offset > 65536);
+
+ align += SDHCI_ADMA2_ALIGN;
+ align_addr += SDHCI_ADMA2_ALIGN;
+
+ addr += offset;
+ len -= offset;
+ }
+
+ /*
+ * The block layer forces a minimum segment size of PAGE_SIZE,
+ * so 'len' can be too big here if PAGE_SIZE >= 64KiB. Write
+ * multiple descriptors, noting that the ADMA table is sized
+ * for 4KiB chunks anyway, so it will be big enough.
+ */
+ while (len > host->max_adma) {
+ int n = 32 * 1024; /* 32KiB*/
+
+ __sdhci_adma_write_desc(host, &desc, addr, n, ADMA2_TRAN_VALID);
+ addr += n;
+ len -= n;
+ }
+
+ /* tran, valid */
+ if (len)
+ __sdhci_adma_write_desc(host, &desc, addr, len,
+ ADMA2_TRAN_VALID);
+
+ /*
+ * If this triggers then we have a calculation bug
+ * somewhere. :/
+ */
+ WARN_ON((desc - host->adma_table) >= host->adma_table_sz);
+ }
+
+ if (host->quirks & SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC) {
+ /* Mark the last descriptor as the terminating descriptor */
+ if (desc != host->adma_table) {
+ desc -= host->desc_sz;
+ sdhci_adma_mark_end(desc);
+ }
+ } else {
+ /* Add a terminating entry - nop, end, valid */
+ __sdhci_adma_write_desc(host, &desc, 0, 0, ADMA2_NOP_END_VALID);
+ }
+}
+
+static void sdhci_adma_table_post(struct sdhci_host *host,
+ struct mmc_data *data)
+{
+ struct scatterlist *sg;
+ int i, size;
+ void *align;
+ char *buffer;
+ unsigned long flags;
+
+ if (data->flags & MMC_DATA_READ) {
+ bool has_unaligned = false;
+
+ /* Do a quick scan of the SG list for any unaligned mappings */
+ for_each_sg(data->sg, sg, host->sg_count, i)
+ if (sg_dma_address(sg) & SDHCI_ADMA2_MASK) {
+ has_unaligned = true;
+ break;
+ }
+
+ if (has_unaligned) {
+ dma_sync_sg_for_cpu(mmc_dev(host->mmc), data->sg,
+ data->sg_len, DMA_FROM_DEVICE);
+
+ align = host->align_buffer;
+
+ for_each_sg(data->sg, sg, host->sg_count, i) {
+ if (sg_dma_address(sg) & SDHCI_ADMA2_MASK) {
+ size = SDHCI_ADMA2_ALIGN -
+ (sg_dma_address(sg) & SDHCI_ADMA2_MASK);
+
+ buffer = sdhci_kmap_atomic(sg, &flags);
+ memcpy(buffer, align, size);
+ sdhci_kunmap_atomic(buffer, &flags);
+
+ align += SDHCI_ADMA2_ALIGN;
+ }
+ }
+ }
+ }
+}
+
+static void sdhci_set_adma_addr(struct sdhci_host *host, dma_addr_t addr)
+{
+ sdhci_writel(host, lower_32_bits(addr), SDHCI_ADMA_ADDRESS);
+ if (host->flags & SDHCI_USE_64_BIT_DMA)
+ sdhci_writel(host, upper_32_bits(addr), SDHCI_ADMA_ADDRESS_HI);
+}
+
+static dma_addr_t sdhci_sdma_address(struct sdhci_host *host)
+{
+ if (host->bounce_buffer)
+ return host->bounce_addr;
+ else
+ return sg_dma_address(host->data->sg);
+}
+
+static void sdhci_set_sdma_addr(struct sdhci_host *host, dma_addr_t addr)
+{
+ if (host->v4_mode)
+ sdhci_set_adma_addr(host, addr);
+ else
+ sdhci_writel(host, addr, SDHCI_DMA_ADDRESS);
+}
+
+static unsigned int sdhci_target_timeout(struct sdhci_host *host,
+ struct mmc_command *cmd,
+ struct mmc_data *data)
+{
+ unsigned int target_timeout;
+
+ /* timeout in us */
+ if (!data) {
+ target_timeout = cmd->busy_timeout * 1000;
+ } else {
+ target_timeout = DIV_ROUND_UP(data->timeout_ns, 1000);
+ if (host->clock && data->timeout_clks) {
+ unsigned long long val;
+
+ /*
+ * data->timeout_clks is in units of clock cycles.
+ * host->clock is in Hz. target_timeout is in us.
+ * Hence, us = 1000000 * cycles / Hz. Round up.
+ */
+ val = 1000000ULL * data->timeout_clks;
+ if (do_div(val, host->clock))
+ target_timeout++;
+ target_timeout += val;
+ }
+ }
+
+ return target_timeout;
+}
+
+static void sdhci_calc_sw_timeout(struct sdhci_host *host,
+ struct mmc_command *cmd)
+{
+ struct mmc_data *data = cmd->data;
+ struct mmc_host *mmc = host->mmc;
+ struct mmc_ios *ios = &mmc->ios;
+ unsigned char bus_width = 1 << ios->bus_width;
+ unsigned int blksz;
+ unsigned int freq;
+ u64 target_timeout;
+ u64 transfer_time;
+
+ target_timeout = sdhci_target_timeout(host, cmd, data);
+ target_timeout *= NSEC_PER_USEC;
+
+ if (data) {
+ blksz = data->blksz;
+ freq = mmc->actual_clock ? : host->clock;
+ transfer_time = (u64)blksz * NSEC_PER_SEC * (8 / bus_width);
+ do_div(transfer_time, freq);
+ /* multiply by '2' to account for any unknowns */
+ transfer_time = transfer_time * 2;
+ /* calculate timeout for the entire data */
+ host->data_timeout = data->blocks * target_timeout +
+ transfer_time;
+ } else {
+ host->data_timeout = target_timeout;
+ }
+
+ if (host->data_timeout)
+ host->data_timeout += MMC_CMD_TRANSFER_TIME;
+}
+
+static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd,
+ bool *too_big)
+{
+ u8 count;
+ struct mmc_data *data;
+ unsigned target_timeout, current_timeout;
+
+ *too_big = false;
+
+ /*
+ * If the host controller provides us with an incorrect timeout
+ * value, just skip the check and use the maximum. The hardware may take
+ * longer to time out, but that's much better than having a too-short
+ * timeout value.
+ */
+ if (host->quirks & SDHCI_QUIRK_BROKEN_TIMEOUT_VAL)
+ return host->max_timeout_count;
+
+ /* Unspecified command, assume max */
+ if (cmd == NULL)
+ return host->max_timeout_count;
+
+ data = cmd->data;
+ /* Unspecified timeout, assume max */
+ if (!data && !cmd->busy_timeout)
+ return host->max_timeout_count;
+
+ /* timeout in us */
+ target_timeout = sdhci_target_timeout(host, cmd, data);
+
+ /*
+ * Figure out needed cycles.
+ * We do this in steps in order to fit inside a 32 bit int.
+ * The first step is the minimum timeout, which will have a
+ * minimum resolution of 6 bits:
+ * (1) 2^13*1000 > 2^22,
+ * (2) host->timeout_clk < 2^16
+ * =>
+ * (1) / (2) > 2^6
+ */
+ count = 0;
+ current_timeout = (1 << 13) * 1000 / host->timeout_clk;
+ while (current_timeout < target_timeout) {
+ count++;
+ current_timeout <<= 1;
+ if (count > host->max_timeout_count) {
+ if (!(host->quirks2 & SDHCI_QUIRK2_DISABLE_HW_TIMEOUT))
+ DBG("Too large timeout 0x%x requested for CMD%d!\n",
+ count, cmd->opcode);
+ count = host->max_timeout_count;
+ *too_big = true;
+ break;
+ }
+ }
+
+ return count;
+}
+
+static void sdhci_set_transfer_irqs(struct sdhci_host *host)
+{
+ u32 pio_irqs = SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL;
+ u32 dma_irqs = SDHCI_INT_DMA_END | SDHCI_INT_ADMA_ERROR;
+
+ if (host->flags & SDHCI_REQ_USE_DMA)
+ host->ier = (host->ier & ~pio_irqs) | dma_irqs;
+ else
+ host->ier = (host->ier & ~dma_irqs) | pio_irqs;
+
+ if (host->flags & (SDHCI_AUTO_CMD23 | SDHCI_AUTO_CMD12))
+ host->ier |= SDHCI_INT_AUTO_CMD_ERR;
+ else
+ host->ier &= ~SDHCI_INT_AUTO_CMD_ERR;
+
+ sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
+ sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
+}
+
+void sdhci_set_data_timeout_irq(struct sdhci_host *host, bool enable)
+{
+ if (enable)
+ host->ier |= SDHCI_INT_DATA_TIMEOUT;
+ else
+ host->ier &= ~SDHCI_INT_DATA_TIMEOUT;
+ sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
+ sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
+}
+EXPORT_SYMBOL_GPL(sdhci_set_data_timeout_irq);
+
+void __sdhci_set_timeout(struct sdhci_host *host, struct mmc_command *cmd)
+{
+ bool too_big = false;
+ u8 count = sdhci_calc_timeout(host, cmd, &too_big);
+
+ if (too_big &&
+ host->quirks2 & SDHCI_QUIRK2_DISABLE_HW_TIMEOUT) {
+ sdhci_calc_sw_timeout(host, cmd);
+ sdhci_set_data_timeout_irq(host, false);
+ } else if (!(host->ier & SDHCI_INT_DATA_TIMEOUT)) {
+ sdhci_set_data_timeout_irq(host, true);
+ }
+
+ sdhci_writeb(host, count, SDHCI_TIMEOUT_CONTROL);
+}
+EXPORT_SYMBOL_GPL(__sdhci_set_timeout);
+
+static void sdhci_set_timeout(struct sdhci_host *host, struct mmc_command *cmd)
+{
+ if (host->ops->set_timeout)
+ host->ops->set_timeout(host, cmd);
+ else
+ __sdhci_set_timeout(host, cmd);
+}
+
+static void sdhci_initialize_data(struct sdhci_host *host,
+ struct mmc_data *data)
+{
+ WARN_ON(host->data);
+
+ /* Sanity checks */
+ BUG_ON(data->blksz * data->blocks > 524288);
+ BUG_ON(data->blksz > host->mmc->max_blk_size);
+ BUG_ON(data->blocks > 65535);
+
+ host->data = data;
+ host->data_early = 0;
+ host->data->bytes_xfered = 0;
+}
+
+static inline void sdhci_set_block_info(struct sdhci_host *host,
+ struct mmc_data *data)
+{
+ /* Set the DMA boundary value and block size */
+ sdhci_writew(host,
+ SDHCI_MAKE_BLKSZ(host->sdma_boundary, data->blksz),
+ SDHCI_BLOCK_SIZE);
+ /*
+ * For Version 4.10 onwards, if v4 mode is enabled, 32-bit Block Count
+ * can be supported, in that case 16-bit block count register must be 0.
+ */
+ if (host->version >= SDHCI_SPEC_410 && host->v4_mode &&
+ (host->quirks2 & SDHCI_QUIRK2_USE_32BIT_BLK_CNT)) {
+ if (sdhci_readw(host, SDHCI_BLOCK_COUNT))
+ sdhci_writew(host, 0, SDHCI_BLOCK_COUNT);
+ sdhci_writew(host, data->blocks, SDHCI_32BIT_BLK_CNT);
+ } else {
+ sdhci_writew(host, data->blocks, SDHCI_BLOCK_COUNT);
+ }
+}
+
+static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd)
+{
+ struct mmc_data *data = cmd->data;
+
+ sdhci_initialize_data(host, data);
+
+ if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) {
+ struct scatterlist *sg;
+ unsigned int length_mask, offset_mask;
+ int i;
+
+ host->flags |= SDHCI_REQ_USE_DMA;
+
+ /*
+ * FIXME: This doesn't account for merging when mapping the
+ * scatterlist.
+ *
+ * The assumption here being that alignment and lengths are
+ * the same after DMA mapping to device address space.
+ */
+ length_mask = 0;
+ offset_mask = 0;
+ if (host->flags & SDHCI_USE_ADMA) {
+ if (host->quirks & SDHCI_QUIRK_32BIT_ADMA_SIZE) {
+ length_mask = 3;
+ /*
+ * As we use up to 3 byte chunks to work
+ * around alignment problems, we need to
+ * check the offset as well.
+ */
+ offset_mask = 3;
+ }
+ } else {
+ if (host->quirks & SDHCI_QUIRK_32BIT_DMA_SIZE)
+ length_mask = 3;
+ if (host->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR)
+ offset_mask = 3;
+ }
+
+ if (unlikely(length_mask | offset_mask)) {
+ for_each_sg(data->sg, sg, data->sg_len, i) {
+ if (sg->length & length_mask) {
+ DBG("Reverting to PIO because of transfer size (%d)\n",
+ sg->length);
+ host->flags &= ~SDHCI_REQ_USE_DMA;
+ break;
+ }
+ if (sg->offset & offset_mask) {
+ DBG("Reverting to PIO because of bad alignment\n");
+ host->flags &= ~SDHCI_REQ_USE_DMA;
+ break;
+ }
+ }
+ }
+ }
+
+ sdhci_config_dma(host);
+
+ if (host->flags & SDHCI_REQ_USE_DMA) {
+ int sg_cnt = sdhci_pre_dma_transfer(host, data, COOKIE_MAPPED);
+
+ if (sg_cnt <= 0) {
+ /*
+ * This only happens when someone fed
+ * us an invalid request.
+ */
+ WARN_ON(1);
+ host->flags &= ~SDHCI_REQ_USE_DMA;
+ } else if (host->flags & SDHCI_USE_ADMA) {
+ sdhci_adma_table_pre(host, data, sg_cnt);
+ sdhci_set_adma_addr(host, host->adma_addr);
+ } else {
+ WARN_ON(sg_cnt != 1);
+ sdhci_set_sdma_addr(host, sdhci_sdma_address(host));
+ }
+ }
+
+ if (!(host->flags & SDHCI_REQ_USE_DMA)) {
+ int flags;
+
+ flags = SG_MITER_ATOMIC;
+ if (host->data->flags & MMC_DATA_READ)
+ flags |= SG_MITER_TO_SG;
+ else
+ flags |= SG_MITER_FROM_SG;
+ sg_miter_start(&host->sg_miter, data->sg, data->sg_len, flags);
+ host->blocks = data->blocks;
+ }
+
+ sdhci_set_transfer_irqs(host);
+
+ sdhci_set_block_info(host, data);
+}
+
+#if IS_ENABLED(CONFIG_MMC_SDHCI_EXTERNAL_DMA)
+
+static int sdhci_external_dma_init(struct sdhci_host *host)
+{
+ int ret = 0;
+ struct mmc_host *mmc = host->mmc;
+
+ host->tx_chan = dma_request_chan(mmc_dev(mmc), "tx");
+ if (IS_ERR(host->tx_chan)) {
+ ret = PTR_ERR(host->tx_chan);
+ if (ret != -EPROBE_DEFER)
+ pr_warn("Failed to request TX DMA channel.\n");
+ host->tx_chan = NULL;
+ return ret;
+ }
+
+ host->rx_chan = dma_request_chan(mmc_dev(mmc), "rx");
+ if (IS_ERR(host->rx_chan)) {
+ if (host->tx_chan) {
+ dma_release_channel(host->tx_chan);
+ host->tx_chan = NULL;
+ }
+
+ ret = PTR_ERR(host->rx_chan);
+ if (ret != -EPROBE_DEFER)
+ pr_warn("Failed to request RX DMA channel.\n");
+ host->rx_chan = NULL;
+ }
+
+ return ret;
+}
+
+static struct dma_chan *sdhci_external_dma_channel(struct sdhci_host *host,
+ struct mmc_data *data)
+{
+ return data->flags & MMC_DATA_WRITE ? host->tx_chan : host->rx_chan;
+}
+
+static int sdhci_external_dma_setup(struct sdhci_host *host,
+ struct mmc_command *cmd)
+{
+ int ret, i;
+ enum dma_transfer_direction dir;
+ struct dma_async_tx_descriptor *desc;
+ struct mmc_data *data = cmd->data;
+ struct dma_chan *chan;
+ struct dma_slave_config cfg;
+ dma_cookie_t cookie;
+ int sg_cnt;
+
+ if (!host->mapbase)
+ return -EINVAL;
+
+ memset(&cfg, 0, sizeof(cfg));
+ cfg.src_addr = host->mapbase + SDHCI_BUFFER;
+ cfg.dst_addr = host->mapbase + SDHCI_BUFFER;
+ cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+ cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+ cfg.src_maxburst = data->blksz / 4;
+ cfg.dst_maxburst = data->blksz / 4;
+
+ /* Sanity check: all the SG entries must be aligned by block size. */
+ for (i = 0; i < data->sg_len; i++) {
+ if ((data->sg + i)->length % data->blksz)
+ return -EINVAL;
+ }
+
+ chan = sdhci_external_dma_channel(host, data);
+
+ ret = dmaengine_slave_config(chan, &cfg);
+ if (ret)
+ return ret;
+
+ sg_cnt = sdhci_pre_dma_transfer(host, data, COOKIE_MAPPED);
+ if (sg_cnt <= 0)
+ return -EINVAL;
+
+ dir = data->flags & MMC_DATA_WRITE ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM;
+ desc = dmaengine_prep_slave_sg(chan, data->sg, data->sg_len, dir,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ if (!desc)
+ return -EINVAL;
+
+ desc->callback = NULL;
+ desc->callback_param = NULL;
+
+ cookie = dmaengine_submit(desc);
+ if (dma_submit_error(cookie))
+ ret = cookie;
+
+ return ret;
+}
+
+static void sdhci_external_dma_release(struct sdhci_host *host)
+{
+ if (host->tx_chan) {
+ dma_release_channel(host->tx_chan);
+ host->tx_chan = NULL;
+ }
+
+ if (host->rx_chan) {
+ dma_release_channel(host->rx_chan);
+ host->rx_chan = NULL;
+ }
+
+ sdhci_switch_external_dma(host, false);
+}
+
+static void __sdhci_external_dma_prepare_data(struct sdhci_host *host,
+ struct mmc_command *cmd)
+{
+ struct mmc_data *data = cmd->data;
+
+ sdhci_initialize_data(host, data);
+
+ host->flags |= SDHCI_REQ_USE_DMA;
+ sdhci_set_transfer_irqs(host);
+
+ sdhci_set_block_info(host, data);
+}
+
+static void sdhci_external_dma_prepare_data(struct sdhci_host *host,
+ struct mmc_command *cmd)
+{
+ if (!sdhci_external_dma_setup(host, cmd)) {
+ __sdhci_external_dma_prepare_data(host, cmd);
+ } else {
+ sdhci_external_dma_release(host);
+ pr_err("%s: Cannot use external DMA, switch to the DMA/PIO which standard SDHCI provides.\n",
+ mmc_hostname(host->mmc));
+ sdhci_prepare_data(host, cmd);
+ }
+}
+
+static void sdhci_external_dma_pre_transfer(struct sdhci_host *host,
+ struct mmc_command *cmd)
+{
+ struct dma_chan *chan;
+
+ if (!cmd->data)
+ return;
+
+ chan = sdhci_external_dma_channel(host, cmd->data);
+ if (chan)
+ dma_async_issue_pending(chan);
+}
+
+#else
+
+static inline int sdhci_external_dma_init(struct sdhci_host *host)
+{
+ return -EOPNOTSUPP;
+}
+
+static inline void sdhci_external_dma_release(struct sdhci_host *host)
+{
+}
+
+static inline void sdhci_external_dma_prepare_data(struct sdhci_host *host,
+ struct mmc_command *cmd)
+{
+ /* This should never happen */
+ WARN_ON_ONCE(1);
+}
+
+static inline void sdhci_external_dma_pre_transfer(struct sdhci_host *host,
+ struct mmc_command *cmd)
+{
+}
+
+static inline struct dma_chan *sdhci_external_dma_channel(struct sdhci_host *host,
+ struct mmc_data *data)
+{
+ return NULL;
+}
+
+#endif
+
+void sdhci_switch_external_dma(struct sdhci_host *host, bool en)
+{
+ host->use_external_dma = en;
+}
+EXPORT_SYMBOL_GPL(sdhci_switch_external_dma);
+
+static inline bool sdhci_auto_cmd12(struct sdhci_host *host,
+ struct mmc_request *mrq)
+{
+ return !mrq->sbc && (host->flags & SDHCI_AUTO_CMD12) &&
+ !mrq->cap_cmd_during_tfr;
+}
+
+static inline bool sdhci_auto_cmd23(struct sdhci_host *host,
+ struct mmc_request *mrq)
+{
+ return mrq->sbc && (host->flags & SDHCI_AUTO_CMD23);
+}
+
+static inline bool sdhci_manual_cmd23(struct sdhci_host *host,
+ struct mmc_request *mrq)
+{
+ return mrq->sbc && !(host->flags & SDHCI_AUTO_CMD23);
+}
+
+static inline void sdhci_auto_cmd_select(struct sdhci_host *host,
+ struct mmc_command *cmd,
+ u16 *mode)
+{
+ bool use_cmd12 = sdhci_auto_cmd12(host, cmd->mrq) &&
+ (cmd->opcode != SD_IO_RW_EXTENDED);
+ bool use_cmd23 = sdhci_auto_cmd23(host, cmd->mrq);
+ u16 ctrl2;
+
+ /*
+ * In case of Version 4.10 or later, use of 'Auto CMD Auto
+ * Select' is recommended rather than use of 'Auto CMD12
+ * Enable' or 'Auto CMD23 Enable'. We require Version 4 Mode
+ * here because some controllers (e.g sdhci-of-dwmshc) expect it.
+ */
+ if (host->version >= SDHCI_SPEC_410 && host->v4_mode &&
+ (use_cmd12 || use_cmd23)) {
+ *mode |= SDHCI_TRNS_AUTO_SEL;
+
+ ctrl2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+ if (use_cmd23)
+ ctrl2 |= SDHCI_CMD23_ENABLE;
+ else
+ ctrl2 &= ~SDHCI_CMD23_ENABLE;
+ sdhci_writew(host, ctrl2, SDHCI_HOST_CONTROL2);
+
+ return;
+ }
+
+ /*
+ * If we are sending CMD23, CMD12 never gets sent
+ * on successful completion (so no Auto-CMD12).
+ */
+ if (use_cmd12)
+ *mode |= SDHCI_TRNS_AUTO_CMD12;
+ else if (use_cmd23)
+ *mode |= SDHCI_TRNS_AUTO_CMD23;
+}
+
+static void sdhci_set_transfer_mode(struct sdhci_host *host,
+ struct mmc_command *cmd)
+{
+ u16 mode = 0;
+ struct mmc_data *data = cmd->data;
+
+ if (data == NULL) {
+ if (host->quirks2 &
+ SDHCI_QUIRK2_CLEAR_TRANSFERMODE_REG_BEFORE_CMD) {
+ /* must not clear SDHCI_TRANSFER_MODE when tuning */
+ if (cmd->opcode != MMC_SEND_TUNING_BLOCK_HS200)
+ sdhci_writew(host, 0x0, SDHCI_TRANSFER_MODE);
+ } else {
+ /* clear Auto CMD settings for no data CMDs */
+ mode = sdhci_readw(host, SDHCI_TRANSFER_MODE);
+ sdhci_writew(host, mode & ~(SDHCI_TRNS_AUTO_CMD12 |
+ SDHCI_TRNS_AUTO_CMD23), SDHCI_TRANSFER_MODE);
+ }
+ return;
+ }
+
+ WARN_ON(!host->data);
+
+ if (!(host->quirks2 & SDHCI_QUIRK2_SUPPORT_SINGLE))
+ mode = SDHCI_TRNS_BLK_CNT_EN;
+
+ if (mmc_op_multi(cmd->opcode) || data->blocks > 1) {
+ mode = SDHCI_TRNS_BLK_CNT_EN | SDHCI_TRNS_MULTI;
+ sdhci_auto_cmd_select(host, cmd, &mode);
+ if (sdhci_auto_cmd23(host, cmd->mrq))
+ sdhci_writel(host, cmd->mrq->sbc->arg, SDHCI_ARGUMENT2);
+ }
+
+ if (data->flags & MMC_DATA_READ)
+ mode |= SDHCI_TRNS_READ;
+ if (host->flags & SDHCI_REQ_USE_DMA)
+ mode |= SDHCI_TRNS_DMA;
+
+ sdhci_writew(host, mode, SDHCI_TRANSFER_MODE);
+}
+
+static bool sdhci_needs_reset(struct sdhci_host *host, struct mmc_request *mrq)
+{
+ return (!(host->flags & SDHCI_DEVICE_DEAD) &&
+ ((mrq->cmd && mrq->cmd->error) ||
+ (mrq->sbc && mrq->sbc->error) ||
+ (mrq->data && mrq->data->stop && mrq->data->stop->error) ||
+ (host->quirks & SDHCI_QUIRK_RESET_AFTER_REQUEST)));
+}
+
+static void sdhci_set_mrq_done(struct sdhci_host *host, struct mmc_request *mrq)
+{
+ int i;
+
+ for (i = 0; i < SDHCI_MAX_MRQS; i++) {
+ if (host->mrqs_done[i] == mrq) {
+ WARN_ON(1);
+ return;
+ }
+ }
+
+ for (i = 0; i < SDHCI_MAX_MRQS; i++) {
+ if (!host->mrqs_done[i]) {
+ host->mrqs_done[i] = mrq;
+ break;
+ }
+ }
+
+ WARN_ON(i >= SDHCI_MAX_MRQS);
+}
+
+static void __sdhci_finish_mrq(struct sdhci_host *host, struct mmc_request *mrq)
+{
+ if (host->cmd && host->cmd->mrq == mrq)
+ host->cmd = NULL;
+
+ if (host->data_cmd && host->data_cmd->mrq == mrq)
+ host->data_cmd = NULL;
+
+ if (host->deferred_cmd && host->deferred_cmd->mrq == mrq)
+ host->deferred_cmd = NULL;
+
+ if (host->data && host->data->mrq == mrq)
+ host->data = NULL;
+
+ if (sdhci_needs_reset(host, mrq))
+ host->pending_reset = true;
+
+ sdhci_set_mrq_done(host, mrq);
+
+ sdhci_del_timer(host, mrq);
+
+ if (!sdhci_has_requests(host))
+ sdhci_led_deactivate(host);
+}
+
+static void sdhci_finish_mrq(struct sdhci_host *host, struct mmc_request *mrq)
+{
+ __sdhci_finish_mrq(host, mrq);
+
+ queue_work(host->complete_wq, &host->complete_work);
+}
+
+static void __sdhci_finish_data(struct sdhci_host *host, bool sw_data_timeout)
+{
+ struct mmc_command *data_cmd = host->data_cmd;
+ struct mmc_data *data = host->data;
+
+ host->data = NULL;
+ host->data_cmd = NULL;
+
+ /*
+ * The controller needs a reset of internal state machines upon error
+ * conditions.
+ */
+ if (data->error) {
+ if (!host->cmd || host->cmd == data_cmd)
+ sdhci_reset_for(host, REQUEST_ERROR);
+ else
+ sdhci_reset_for(host, REQUEST_ERROR_DATA_ONLY);
+ }
+
+ if ((host->flags & (SDHCI_REQ_USE_DMA | SDHCI_USE_ADMA)) ==
+ (SDHCI_REQ_USE_DMA | SDHCI_USE_ADMA))
+ sdhci_adma_table_post(host, data);
+
+ /*
+ * The specification states that the block count register must
+ * be updated, but it does not specify at what point in the
+ * data flow. That makes the register entirely useless to read
+ * back so we have to assume that nothing made it to the card
+ * in the event of an error.
+ */
+ if (data->error)
+ data->bytes_xfered = 0;
+ else
+ data->bytes_xfered = data->blksz * data->blocks;
+
+ /*
+ * Need to send CMD12 if -
+ * a) open-ended multiblock transfer not using auto CMD12 (no CMD23)
+ * b) error in multiblock transfer
+ */
+ if (data->stop &&
+ ((!data->mrq->sbc && !sdhci_auto_cmd12(host, data->mrq)) ||
+ data->error)) {
+ /*
+ * 'cap_cmd_during_tfr' request must not use the command line
+ * after mmc_command_done() has been called. It is upper layer's
+ * responsibility to send the stop command if required.
+ */
+ if (data->mrq->cap_cmd_during_tfr) {
+ __sdhci_finish_mrq(host, data->mrq);
+ } else {
+ /* Avoid triggering warning in sdhci_send_command() */
+ host->cmd = NULL;
+ if (!sdhci_send_command(host, data->stop)) {
+ if (sw_data_timeout) {
+ /*
+ * This is anyway a sw data timeout, so
+ * give up now.
+ */
+ data->stop->error = -EIO;
+ __sdhci_finish_mrq(host, data->mrq);
+ } else {
+ WARN_ON(host->deferred_cmd);
+ host->deferred_cmd = data->stop;
+ }
+ }
+ }
+ } else {
+ __sdhci_finish_mrq(host, data->mrq);
+ }
+}
+
+static void sdhci_finish_data(struct sdhci_host *host)
+{
+ __sdhci_finish_data(host, false);
+}
+
+static bool sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
+{
+ int flags;
+ u32 mask;
+ unsigned long timeout;
+
+ WARN_ON(host->cmd);
+
+ /* Initially, a command has no error */
+ cmd->error = 0;
+
+ if ((host->quirks2 & SDHCI_QUIRK2_STOP_WITH_TC) &&
+ cmd->opcode == MMC_STOP_TRANSMISSION)
+ cmd->flags |= MMC_RSP_BUSY;
+
+ mask = SDHCI_CMD_INHIBIT;
+ if (sdhci_data_line_cmd(cmd))
+ mask |= SDHCI_DATA_INHIBIT;
+
+ /* We shouldn't wait for data inihibit for stop commands, even
+ though they might use busy signaling */
+ if (cmd->mrq->data && (cmd == cmd->mrq->data->stop))
+ mask &= ~SDHCI_DATA_INHIBIT;
+
+ if (sdhci_readl(host, SDHCI_PRESENT_STATE) & mask)
+ return false;
+
+ host->cmd = cmd;
+ host->data_timeout = 0;
+ if (sdhci_data_line_cmd(cmd)) {
+ WARN_ON(host->data_cmd);
+ host->data_cmd = cmd;
+ sdhci_set_timeout(host, cmd);
+ }
+
+ if (cmd->data) {
+ if (host->use_external_dma)
+ sdhci_external_dma_prepare_data(host, cmd);
+ else
+ sdhci_prepare_data(host, cmd);
+ }
+
+ sdhci_writel(host, cmd->arg, SDHCI_ARGUMENT);
+
+ sdhci_set_transfer_mode(host, cmd);
+
+ if ((cmd->flags & MMC_RSP_136) && (cmd->flags & MMC_RSP_BUSY)) {
+ WARN_ONCE(1, "Unsupported response type!\n");
+ /*
+ * This does not happen in practice because 136-bit response
+ * commands never have busy waiting, so rather than complicate
+ * the error path, just remove busy waiting and continue.
+ */
+ cmd->flags &= ~MMC_RSP_BUSY;
+ }
+
+ if (!(cmd->flags & MMC_RSP_PRESENT))
+ flags = SDHCI_CMD_RESP_NONE;
+ else if (cmd->flags & MMC_RSP_136)
+ flags = SDHCI_CMD_RESP_LONG;
+ else if (cmd->flags & MMC_RSP_BUSY)
+ flags = SDHCI_CMD_RESP_SHORT_BUSY;
+ else
+ flags = SDHCI_CMD_RESP_SHORT;
+
+ if (cmd->flags & MMC_RSP_CRC)
+ flags |= SDHCI_CMD_CRC;
+ if (cmd->flags & MMC_RSP_OPCODE)
+ flags |= SDHCI_CMD_INDEX;
+
+ /* CMD19 is special in that the Data Present Select should be set */
+ if (cmd->data || cmd->opcode == MMC_SEND_TUNING_BLOCK ||
+ cmd->opcode == MMC_SEND_TUNING_BLOCK_HS200)
+ flags |= SDHCI_CMD_DATA;
+
+ timeout = jiffies;
+ if (host->data_timeout)
+ timeout += nsecs_to_jiffies(host->data_timeout);
+ else if (!cmd->data && cmd->busy_timeout > 9000)
+ timeout += DIV_ROUND_UP(cmd->busy_timeout, 1000) * HZ + HZ;
+ else
+ timeout += 10 * HZ;
+ sdhci_mod_timer(host, cmd->mrq, timeout);
+
+ if (host->use_external_dma)
+ sdhci_external_dma_pre_transfer(host, cmd);
+
+ sdhci_writew(host, SDHCI_MAKE_CMD(cmd->opcode, flags), SDHCI_COMMAND);
+
+ return true;
+}
+
+static bool sdhci_present_error(struct sdhci_host *host,
+ struct mmc_command *cmd, bool present)
+{
+ if (!present || host->flags & SDHCI_DEVICE_DEAD) {
+ cmd->error = -ENOMEDIUM;
+ return true;
+ }
+
+ return false;
+}
+
+static bool sdhci_send_command_retry(struct sdhci_host *host,
+ struct mmc_command *cmd,
+ unsigned long flags)
+ __releases(host->lock)
+ __acquires(host->lock)
+{
+ struct mmc_command *deferred_cmd = host->deferred_cmd;
+ int timeout = 10; /* Approx. 10 ms */
+ bool present;
+
+ while (!sdhci_send_command(host, cmd)) {
+ if (!timeout--) {
+ pr_err("%s: Controller never released inhibit bit(s).\n",
+ mmc_hostname(host->mmc));
+ sdhci_err_stats_inc(host, CTRL_TIMEOUT);
+ sdhci_dumpregs(host);
+ cmd->error = -EIO;
+ return false;
+ }
+
+ spin_unlock_irqrestore(&host->lock, flags);
+
+ usleep_range(1000, 1250);
+
+ present = host->mmc->ops->get_cd(host->mmc);
+
+ spin_lock_irqsave(&host->lock, flags);
+
+ /* A deferred command might disappear, handle that */
+ if (cmd == deferred_cmd && cmd != host->deferred_cmd)
+ return true;
+
+ if (sdhci_present_error(host, cmd, present))
+ return false;
+ }
+
+ if (cmd == host->deferred_cmd)
+ host->deferred_cmd = NULL;
+
+ return true;
+}
+
+static void sdhci_read_rsp_136(struct sdhci_host *host, struct mmc_command *cmd)
+{
+ int i, reg;
+
+ for (i = 0; i < 4; i++) {
+ reg = SDHCI_RESPONSE + (3 - i) * 4;
+ cmd->resp[i] = sdhci_readl(host, reg);
+ }
+
+ if (host->quirks2 & SDHCI_QUIRK2_RSP_136_HAS_CRC)
+ return;
+
+ /* CRC is stripped so we need to do some shifting */
+ for (i = 0; i < 4; i++) {
+ cmd->resp[i] <<= 8;
+ if (i != 3)
+ cmd->resp[i] |= cmd->resp[i + 1] >> 24;
+ }
+}
+
+static void sdhci_finish_command(struct sdhci_host *host)
+{
+ struct mmc_command *cmd = host->cmd;
+
+ host->cmd = NULL;
+
+ if (cmd->flags & MMC_RSP_PRESENT) {
+ if (cmd->flags & MMC_RSP_136) {
+ sdhci_read_rsp_136(host, cmd);
+ } else {
+ cmd->resp[0] = sdhci_readl(host, SDHCI_RESPONSE);
+ }
+ }
+
+ if (cmd->mrq->cap_cmd_during_tfr && cmd == cmd->mrq->cmd)
+ mmc_command_done(host->mmc, cmd->mrq);
+
+ /*
+ * The host can send and interrupt when the busy state has
+ * ended, allowing us to wait without wasting CPU cycles.
+ * The busy signal uses DAT0 so this is similar to waiting
+ * for data to complete.
+ *
+ * Note: The 1.0 specification is a bit ambiguous about this
+ * feature so there might be some problems with older
+ * controllers.
+ */
+ if (cmd->flags & MMC_RSP_BUSY) {
+ if (cmd->data) {
+ DBG("Cannot wait for busy signal when also doing a data transfer");
+ } else if (!(host->quirks & SDHCI_QUIRK_NO_BUSY_IRQ) &&
+ cmd == host->data_cmd) {
+ /* Command complete before busy is ended */
+ return;
+ }
+ }
+
+ /* Finished CMD23, now send actual command. */
+ if (cmd == cmd->mrq->sbc) {
+ if (!sdhci_send_command(host, cmd->mrq->cmd)) {
+ WARN_ON(host->deferred_cmd);
+ host->deferred_cmd = cmd->mrq->cmd;
+ }
+ } else {
+
+ /* Processed actual command. */
+ if (host->data && host->data_early)
+ sdhci_finish_data(host);
+
+ if (!cmd->data)
+ __sdhci_finish_mrq(host, cmd->mrq);
+ }
+}
+
+static u16 sdhci_get_preset_value(struct sdhci_host *host)
+{
+ u16 preset = 0;
+
+ switch (host->timing) {
+ case MMC_TIMING_MMC_HS:
+ case MMC_TIMING_SD_HS:
+ preset = sdhci_readw(host, SDHCI_PRESET_FOR_HIGH_SPEED);
+ break;
+ case MMC_TIMING_UHS_SDR12:
+ preset = sdhci_readw(host, SDHCI_PRESET_FOR_SDR12);
+ break;
+ case MMC_TIMING_UHS_SDR25:
+ preset = sdhci_readw(host, SDHCI_PRESET_FOR_SDR25);
+ break;
+ case MMC_TIMING_UHS_SDR50:
+ preset = sdhci_readw(host, SDHCI_PRESET_FOR_SDR50);
+ break;
+ case MMC_TIMING_UHS_SDR104:
+ case MMC_TIMING_MMC_HS200:
+ preset = sdhci_readw(host, SDHCI_PRESET_FOR_SDR104);
+ break;
+ case MMC_TIMING_UHS_DDR50:
+ case MMC_TIMING_MMC_DDR52:
+ preset = sdhci_readw(host, SDHCI_PRESET_FOR_DDR50);
+ break;
+ case MMC_TIMING_MMC_HS400:
+ preset = sdhci_readw(host, SDHCI_PRESET_FOR_HS400);
+ break;
+ default:
+ pr_warn("%s: Invalid UHS-I mode selected\n",
+ mmc_hostname(host->mmc));
+ preset = sdhci_readw(host, SDHCI_PRESET_FOR_SDR12);
+ break;
+ }
+ return preset;
+}
+
+u16 sdhci_calc_clk(struct sdhci_host *host, unsigned int clock,
+ unsigned int *actual_clock)
+{
+ int div = 0; /* Initialized for compiler warning */
+ int real_div = div, clk_mul = 1;
+ u16 clk = 0;
+ bool switch_base_clk = false;
+
+ if (host->version >= SDHCI_SPEC_300) {
+ if (host->preset_enabled) {
+ u16 pre_val;
+
+ clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
+ pre_val = sdhci_get_preset_value(host);
+ div = FIELD_GET(SDHCI_PRESET_SDCLK_FREQ_MASK, pre_val);
+ if (host->clk_mul &&
+ (pre_val & SDHCI_PRESET_CLKGEN_SEL)) {
+ clk = SDHCI_PROG_CLOCK_MODE;
+ real_div = div + 1;
+ clk_mul = host->clk_mul;
+ } else {
+ real_div = max_t(int, 1, div << 1);
+ }
+ goto clock_set;
+ }
+
+ /*
+ * Check if the Host Controller supports Programmable Clock
+ * Mode.
+ */
+ if (host->clk_mul) {
+ for (div = 1; div <= 1024; div++) {
+ if ((host->max_clk * host->clk_mul / div)
+ <= clock)
+ break;
+ }
+ if ((host->max_clk * host->clk_mul / div) <= clock) {
+ /*
+ * Set Programmable Clock Mode in the Clock
+ * Control register.
+ */
+ clk = SDHCI_PROG_CLOCK_MODE;
+ real_div = div;
+ clk_mul = host->clk_mul;
+ div--;
+ } else {
+ /*
+ * Divisor can be too small to reach clock
+ * speed requirement. Then use the base clock.
+ */
+ switch_base_clk = true;
+ }
+ }
+
+ if (!host->clk_mul || switch_base_clk) {
+ /* Version 3.00 divisors must be a multiple of 2. */
+ if (host->max_clk <= clock)
+ div = 1;
+ else {
+ for (div = 2; div < SDHCI_MAX_DIV_SPEC_300;
+ div += 2) {
+ if ((host->max_clk / div) <= clock)
+ break;
+ }
+ }
+ real_div = div;
+ div >>= 1;
+ if ((host->quirks2 & SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN)
+ && !div && host->max_clk <= 25000000)
+ div = 1;
+ }
+ } else {
+ /* Version 2.00 divisors must be a power of 2. */
+ for (div = 1; div < SDHCI_MAX_DIV_SPEC_200; div *= 2) {
+ if ((host->max_clk / div) <= clock)
+ break;
+ }
+ real_div = div;
+ div >>= 1;
+ }
+
+clock_set:
+ if (real_div)
+ *actual_clock = (host->max_clk * clk_mul) / real_div;
+ clk |= (div & SDHCI_DIV_MASK) << SDHCI_DIVIDER_SHIFT;
+ clk |= ((div & SDHCI_DIV_HI_MASK) >> SDHCI_DIV_MASK_LEN)
+ << SDHCI_DIVIDER_HI_SHIFT;
+
+ return clk;
+}
+EXPORT_SYMBOL_GPL(sdhci_calc_clk);
+
+void sdhci_enable_clk(struct sdhci_host *host, u16 clk)
+{
+ ktime_t timeout;
+
+ clk |= SDHCI_CLOCK_INT_EN;
+ sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
+
+ /* Wait max 150 ms */
+ timeout = ktime_add_ms(ktime_get(), 150);
+ while (1) {
+ bool timedout = ktime_after(ktime_get(), timeout);
+
+ clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
+ if (clk & SDHCI_CLOCK_INT_STABLE)
+ break;
+ if (timedout) {
+ pr_err("%s: Internal clock never stabilised.\n",
+ mmc_hostname(host->mmc));
+ sdhci_err_stats_inc(host, CTRL_TIMEOUT);
+ sdhci_dumpregs(host);
+ return;
+ }
+ udelay(10);
+ }
+
+ if (host->version >= SDHCI_SPEC_410 && host->v4_mode) {
+ clk |= SDHCI_CLOCK_PLL_EN;
+ clk &= ~SDHCI_CLOCK_INT_STABLE;
+ sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
+
+ /* Wait max 150 ms */
+ timeout = ktime_add_ms(ktime_get(), 150);
+ while (1) {
+ bool timedout = ktime_after(ktime_get(), timeout);
+
+ clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
+ if (clk & SDHCI_CLOCK_INT_STABLE)
+ break;
+ if (timedout) {
+ pr_err("%s: PLL clock never stabilised.\n",
+ mmc_hostname(host->mmc));
+ sdhci_err_stats_inc(host, CTRL_TIMEOUT);
+ sdhci_dumpregs(host);
+ return;
+ }
+ udelay(10);
+ }
+ }
+
+ clk |= SDHCI_CLOCK_CARD_EN;
+ sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
+}
+EXPORT_SYMBOL_GPL(sdhci_enable_clk);
+
+void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
+{
+ u16 clk;
+
+ host->mmc->actual_clock = 0;
+
+ sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
+
+ if (clock == 0)
+ return;
+
+ clk = sdhci_calc_clk(host, clock, &host->mmc->actual_clock);
+ sdhci_enable_clk(host, clk);
+}
+EXPORT_SYMBOL_GPL(sdhci_set_clock);
+
+static void sdhci_set_power_reg(struct sdhci_host *host, unsigned char mode,
+ unsigned short vdd)
+{
+ struct mmc_host *mmc = host->mmc;
+
+ mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, vdd);
+
+ if (mode != MMC_POWER_OFF)
+ sdhci_writeb(host, SDHCI_POWER_ON, SDHCI_POWER_CONTROL);
+ else
+ sdhci_writeb(host, 0, SDHCI_POWER_CONTROL);
+}
+
+void sdhci_set_power_noreg(struct sdhci_host *host, unsigned char mode,
+ unsigned short vdd)
+{
+ u8 pwr = 0;
+
+ if (mode != MMC_POWER_OFF) {
+ switch (1 << vdd) {
+ case MMC_VDD_165_195:
+ /*
+ * Without a regulator, SDHCI does not support 2.0v
+ * so we only get here if the driver deliberately
+ * added the 2.0v range to ocr_avail. Map it to 1.8v
+ * for the purpose of turning on the power.
+ */
+ case MMC_VDD_20_21:
+ pwr = SDHCI_POWER_180;
+ break;
+ case MMC_VDD_29_30:
+ case MMC_VDD_30_31:
+ pwr = SDHCI_POWER_300;
+ break;
+ case MMC_VDD_32_33:
+ case MMC_VDD_33_34:
+ /*
+ * 3.4 ~ 3.6V are valid only for those platforms where it's
+ * known that the voltage range is supported by hardware.
+ */
+ case MMC_VDD_34_35:
+ case MMC_VDD_35_36:
+ pwr = SDHCI_POWER_330;
+ break;
+ default:
+ WARN(1, "%s: Invalid vdd %#x\n",
+ mmc_hostname(host->mmc), vdd);
+ break;
+ }
+ }
+
+ if (host->pwr == pwr)
+ return;
+
+ host->pwr = pwr;
+
+ if (pwr == 0) {
+ sdhci_writeb(host, 0, SDHCI_POWER_CONTROL);
+ if (host->quirks2 & SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON)
+ sdhci_runtime_pm_bus_off(host);
+ } else {
+ /*
+ * Spec says that we should clear the power reg before setting
+ * a new value. Some controllers don't seem to like this though.
+ */
+ if (!(host->quirks & SDHCI_QUIRK_SINGLE_POWER_WRITE))
+ sdhci_writeb(host, 0, SDHCI_POWER_CONTROL);
+
+ /*
+ * At least the Marvell CaFe chip gets confused if we set the
+ * voltage and set turn on power at the same time, so set the
+ * voltage first.
+ */
+ if (host->quirks & SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER)
+ sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL);
+
+ pwr |= SDHCI_POWER_ON;
+
+ sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL);
+
+ if (host->quirks2 & SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON)
+ sdhci_runtime_pm_bus_on(host);
+
+ /*
+ * Some controllers need an extra 10ms delay of 10ms before
+ * they can apply clock after applying power
+ */
+ if (host->quirks & SDHCI_QUIRK_DELAY_AFTER_POWER)
+ mdelay(10);
+ }
+}
+EXPORT_SYMBOL_GPL(sdhci_set_power_noreg);
+
+void sdhci_set_power(struct sdhci_host *host, unsigned char mode,
+ unsigned short vdd)
+{
+ if (IS_ERR(host->mmc->supply.vmmc))
+ sdhci_set_power_noreg(host, mode, vdd);
+ else
+ sdhci_set_power_reg(host, mode, vdd);
+}
+EXPORT_SYMBOL_GPL(sdhci_set_power);
+
+/*
+ * Some controllers need to configure a valid bus voltage on their power
+ * register regardless of whether an external regulator is taking care of power
+ * supply. This helper function takes care of it if set as the controller's
+ * sdhci_ops.set_power callback.
+ */
+void sdhci_set_power_and_bus_voltage(struct sdhci_host *host,
+ unsigned char mode,
+ unsigned short vdd)
+{
+ if (!IS_ERR(host->mmc->supply.vmmc)) {
+ struct mmc_host *mmc = host->mmc;
+
+ mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, vdd);
+ }
+ sdhci_set_power_noreg(host, mode, vdd);
+}
+EXPORT_SYMBOL_GPL(sdhci_set_power_and_bus_voltage);
+
+/*****************************************************************************\
+ * *
+ * MMC callbacks *
+ * *
+\*****************************************************************************/
+
+void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+ struct sdhci_host *host = mmc_priv(mmc);
+ struct mmc_command *cmd;
+ unsigned long flags;
+ bool present;
+
+ /* Firstly check card presence */
+ present = mmc->ops->get_cd(mmc);
+
+ spin_lock_irqsave(&host->lock, flags);
+
+ sdhci_led_activate(host);
+
+ if (sdhci_present_error(host, mrq->cmd, present))
+ goto out_finish;
+
+ cmd = sdhci_manual_cmd23(host, mrq) ? mrq->sbc : mrq->cmd;
+
+ if (!sdhci_send_command_retry(host, cmd, flags))
+ goto out_finish;
+
+ spin_unlock_irqrestore(&host->lock, flags);
+
+ return;
+
+out_finish:
+ sdhci_finish_mrq(host, mrq);
+ spin_unlock_irqrestore(&host->lock, flags);
+}
+EXPORT_SYMBOL_GPL(sdhci_request);
+
+int sdhci_request_atomic(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+ struct sdhci_host *host = mmc_priv(mmc);
+ struct mmc_command *cmd;
+ unsigned long flags;
+ int ret = 0;
+
+ spin_lock_irqsave(&host->lock, flags);
+
+ if (sdhci_present_error(host, mrq->cmd, true)) {
+ sdhci_finish_mrq(host, mrq);
+ goto out_finish;
+ }
+
+ cmd = sdhci_manual_cmd23(host, mrq) ? mrq->sbc : mrq->cmd;
+
+ /*
+ * The HSQ may send a command in interrupt context without polling
+ * the busy signaling, which means we should return BUSY if controller
+ * has not released inhibit bits to allow HSQ trying to send request
+ * again in non-atomic context. So we should not finish this request
+ * here.
+ */
+ if (!sdhci_send_command(host, cmd))
+ ret = -EBUSY;
+ else
+ sdhci_led_activate(host);
+
+out_finish:
+ spin_unlock_irqrestore(&host->lock, flags);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(sdhci_request_atomic);
+
+void sdhci_set_bus_width(struct sdhci_host *host, int width)
+{
+ u8 ctrl;
+
+ ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
+ if (width == MMC_BUS_WIDTH_8) {
+ ctrl &= ~SDHCI_CTRL_4BITBUS;
+ ctrl |= SDHCI_CTRL_8BITBUS;
+ } else {
+ if (host->mmc->caps & MMC_CAP_8_BIT_DATA)
+ ctrl &= ~SDHCI_CTRL_8BITBUS;
+ if (width == MMC_BUS_WIDTH_4)
+ ctrl |= SDHCI_CTRL_4BITBUS;
+ else
+ ctrl &= ~SDHCI_CTRL_4BITBUS;
+ }
+ sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
+}
+EXPORT_SYMBOL_GPL(sdhci_set_bus_width);
+
+void sdhci_set_uhs_signaling(struct sdhci_host *host, unsigned timing)
+{
+ u16 ctrl_2;
+
+ ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+ /* Select Bus Speed Mode for host */
+ ctrl_2 &= ~SDHCI_CTRL_UHS_MASK;
+ if ((timing == MMC_TIMING_MMC_HS200) ||
+ (timing == MMC_TIMING_UHS_SDR104))
+ ctrl_2 |= SDHCI_CTRL_UHS_SDR104;
+ else if (timing == MMC_TIMING_UHS_SDR12)
+ ctrl_2 |= SDHCI_CTRL_UHS_SDR12;
+ else if (timing == MMC_TIMING_UHS_SDR25)
+ ctrl_2 |= SDHCI_CTRL_UHS_SDR25;
+ else if (timing == MMC_TIMING_UHS_SDR50)
+ ctrl_2 |= SDHCI_CTRL_UHS_SDR50;
+ else if ((timing == MMC_TIMING_UHS_DDR50) ||
+ (timing == MMC_TIMING_MMC_DDR52))
+ ctrl_2 |= SDHCI_CTRL_UHS_DDR50;
+ else if (timing == MMC_TIMING_MMC_HS400)
+ ctrl_2 |= SDHCI_CTRL_HS400; /* Non-standard */
+ sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
+}
+EXPORT_SYMBOL_GPL(sdhci_set_uhs_signaling);
+
+static bool sdhci_timing_has_preset(unsigned char timing)
+{
+ switch (timing) {
+ case MMC_TIMING_UHS_SDR12:
+ case MMC_TIMING_UHS_SDR25:
+ case MMC_TIMING_UHS_SDR50:
+ case MMC_TIMING_UHS_SDR104:
+ case MMC_TIMING_UHS_DDR50:
+ case MMC_TIMING_MMC_DDR52:
+ return true;
+ };
+ return false;
+}
+
+static bool sdhci_preset_needed(struct sdhci_host *host, unsigned char timing)
+{
+ return !(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN) &&
+ sdhci_timing_has_preset(timing);
+}
+
+static bool sdhci_presetable_values_change(struct sdhci_host *host, struct mmc_ios *ios)
+{
+ /*
+ * Preset Values are: Driver Strength, Clock Generator and SDCLK/RCLK
+ * Frequency. Check if preset values need to be enabled, or the Driver
+ * Strength needs updating. Note, clock changes are handled separately.
+ */
+ return !host->preset_enabled &&
+ (sdhci_preset_needed(host, ios->timing) || host->drv_type != ios->drv_type);
+}
+
+void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+ struct sdhci_host *host = mmc_priv(mmc);
+ bool reinit_uhs = host->reinit_uhs;
+ bool turning_on_clk = false;
+ u8 ctrl;
+
+ host->reinit_uhs = false;
+
+ if (ios->power_mode == MMC_POWER_UNDEFINED)
+ return;
+
+ if (host->flags & SDHCI_DEVICE_DEAD) {
+ if (!IS_ERR(mmc->supply.vmmc) &&
+ ios->power_mode == MMC_POWER_OFF)
+ mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0);
+ return;
+ }
+
+ /*
+ * Reset the chip on each power off.
+ * Should clear out any weird states.
+ */
+ if (ios->power_mode == MMC_POWER_OFF) {
+ sdhci_writel(host, 0, SDHCI_SIGNAL_ENABLE);
+ sdhci_reinit(host);
+ }
+
+ if (host->version >= SDHCI_SPEC_300 &&
+ (ios->power_mode == MMC_POWER_UP) &&
+ !(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN))
+ sdhci_enable_preset_value(host, false);
+
+ if (!ios->clock || ios->clock != host->clock) {
+ turning_on_clk = ios->clock && !host->clock;
+
+ host->ops->set_clock(host, ios->clock);
+ host->clock = ios->clock;
+
+ if (host->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK &&
+ host->clock) {
+ host->timeout_clk = mmc->actual_clock ?
+ mmc->actual_clock / 1000 :
+ host->clock / 1000;
+ mmc->max_busy_timeout =
+ host->ops->get_max_timeout_count ?
+ host->ops->get_max_timeout_count(host) :
+ 1 << 27;
+ mmc->max_busy_timeout /= host->timeout_clk;
+ }
+ }
+
+ if (host->ops->set_power)
+ host->ops->set_power(host, ios->power_mode, ios->vdd);
+ else
+ sdhci_set_power(host, ios->power_mode, ios->vdd);
+
+ if (host->ops->platform_send_init_74_clocks)
+ host->ops->platform_send_init_74_clocks(host, ios->power_mode);
+
+ host->ops->set_bus_width(host, ios->bus_width);
+
+ /*
+ * Special case to avoid multiple clock changes during voltage
+ * switching.
+ */
+ if (!reinit_uhs &&
+ turning_on_clk &&
+ host->timing == ios->timing &&
+ host->version >= SDHCI_SPEC_300 &&
+ !sdhci_presetable_values_change(host, ios))
+ return;
+
+ ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
+
+ if (!(host->quirks & SDHCI_QUIRK_NO_HISPD_BIT)) {
+ if (ios->timing == MMC_TIMING_SD_HS ||
+ ios->timing == MMC_TIMING_MMC_HS ||
+ ios->timing == MMC_TIMING_MMC_HS400 ||
+ ios->timing == MMC_TIMING_MMC_HS200 ||
+ ios->timing == MMC_TIMING_MMC_DDR52 ||
+ ios->timing == MMC_TIMING_UHS_SDR50 ||
+ ios->timing == MMC_TIMING_UHS_SDR104 ||
+ ios->timing == MMC_TIMING_UHS_DDR50 ||
+ ios->timing == MMC_TIMING_UHS_SDR25)
+ ctrl |= SDHCI_CTRL_HISPD;
+ else
+ ctrl &= ~SDHCI_CTRL_HISPD;
+ }
+
+ if (host->version >= SDHCI_SPEC_300) {
+ u16 clk, ctrl_2;
+
+ if (!host->preset_enabled) {
+ sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
+ /*
+ * We only need to set Driver Strength if the
+ * preset value enable is not set.
+ */
+ ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+ ctrl_2 &= ~SDHCI_CTRL_DRV_TYPE_MASK;
+ if (ios->drv_type == MMC_SET_DRIVER_TYPE_A)
+ ctrl_2 |= SDHCI_CTRL_DRV_TYPE_A;
+ else if (ios->drv_type == MMC_SET_DRIVER_TYPE_B)
+ ctrl_2 |= SDHCI_CTRL_DRV_TYPE_B;
+ else if (ios->drv_type == MMC_SET_DRIVER_TYPE_C)
+ ctrl_2 |= SDHCI_CTRL_DRV_TYPE_C;
+ else if (ios->drv_type == MMC_SET_DRIVER_TYPE_D)
+ ctrl_2 |= SDHCI_CTRL_DRV_TYPE_D;
+ else {
+ pr_warn("%s: invalid driver type, default to driver type B\n",
+ mmc_hostname(mmc));
+ ctrl_2 |= SDHCI_CTRL_DRV_TYPE_B;
+ }
+
+ sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
+ host->drv_type = ios->drv_type;
+ } else {
+ /*
+ * According to SDHC Spec v3.00, if the Preset Value
+ * Enable in the Host Control 2 register is set, we
+ * need to reset SD Clock Enable before changing High
+ * Speed Enable to avoid generating clock gliches.
+ */
+
+ /* Reset SD Clock Enable */
+ clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
+ clk &= ~SDHCI_CLOCK_CARD_EN;
+ sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
+
+ sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
+
+ /* Re-enable SD Clock */
+ host->ops->set_clock(host, host->clock);
+ }
+
+ /* Reset SD Clock Enable */
+ clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
+ clk &= ~SDHCI_CLOCK_CARD_EN;
+ sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
+
+ host->ops->set_uhs_signaling(host, ios->timing);
+ host->timing = ios->timing;
+
+ if (sdhci_preset_needed(host, ios->timing)) {
+ u16 preset;
+
+ sdhci_enable_preset_value(host, true);
+ preset = sdhci_get_preset_value(host);
+ ios->drv_type = FIELD_GET(SDHCI_PRESET_DRV_MASK,
+ preset);
+ host->drv_type = ios->drv_type;
+ }
+
+ /* Re-enable SD Clock */
+ host->ops->set_clock(host, host->clock);
+ } else
+ sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
+}
+EXPORT_SYMBOL_GPL(sdhci_set_ios);
+
+static int sdhci_get_cd(struct mmc_host *mmc)
+{
+ struct sdhci_host *host = mmc_priv(mmc);
+ int gpio_cd = mmc_gpio_get_cd(mmc);
+
+ if (host->flags & SDHCI_DEVICE_DEAD)
+ return 0;
+
+ /* If nonremovable, assume that the card is always present. */
+ if (!mmc_card_is_removable(mmc))
+ return 1;
+
+ /*
+ * Try slot gpio detect, if defined it take precedence
+ * over build in controller functionality
+ */
+ if (gpio_cd >= 0)
+ return !!gpio_cd;
+
+ /* If polling, assume that the card is always present. */
+ if (host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION)
+ return 1;
+
+ /* Host native card detect */
+ return !!(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT);
+}
+
+int sdhci_get_cd_nogpio(struct mmc_host *mmc)
+{
+ struct sdhci_host *host = mmc_priv(mmc);
+ unsigned long flags;
+ int ret = 0;
+
+ spin_lock_irqsave(&host->lock, flags);
+
+ if (host->flags & SDHCI_DEVICE_DEAD)
+ goto out;
+
+ ret = !!(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT);
+out:
+ spin_unlock_irqrestore(&host->lock, flags);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(sdhci_get_cd_nogpio);
+
+static int sdhci_check_ro(struct sdhci_host *host)
+{
+ unsigned long flags;
+ int is_readonly;
+
+ spin_lock_irqsave(&host->lock, flags);
+
+ if (host->flags & SDHCI_DEVICE_DEAD)
+ is_readonly = 0;
+ else if (host->ops->get_ro)
+ is_readonly = host->ops->get_ro(host);
+ else if (mmc_can_gpio_ro(host->mmc))
+ is_readonly = mmc_gpio_get_ro(host->mmc);
+ else
+ is_readonly = !(sdhci_readl(host, SDHCI_PRESENT_STATE)
+ & SDHCI_WRITE_PROTECT);
+
+ spin_unlock_irqrestore(&host->lock, flags);
+
+ /* This quirk needs to be replaced by a callback-function later */
+ return host->quirks & SDHCI_QUIRK_INVERTED_WRITE_PROTECT ?
+ !is_readonly : is_readonly;
+}
+
+#define SAMPLE_COUNT 5
+
+static int sdhci_get_ro(struct mmc_host *mmc)
+{
+ struct sdhci_host *host = mmc_priv(mmc);
+ int i, ro_count;
+
+ if (!(host->quirks & SDHCI_QUIRK_UNSTABLE_RO_DETECT))
+ return sdhci_check_ro(host);
+
+ ro_count = 0;
+ for (i = 0; i < SAMPLE_COUNT; i++) {
+ if (sdhci_check_ro(host)) {
+ if (++ro_count > SAMPLE_COUNT / 2)
+ return 1;
+ }
+ msleep(30);
+ }
+ return 0;
+}
+
+static void sdhci_hw_reset(struct mmc_host *mmc)
+{
+ struct sdhci_host *host = mmc_priv(mmc);
+
+ if (host->ops && host->ops->hw_reset)
+ host->ops->hw_reset(host);
+}
+
+static void sdhci_enable_sdio_irq_nolock(struct sdhci_host *host, int enable)
+{
+ if (!(host->flags & SDHCI_DEVICE_DEAD)) {
+ if (enable)
+ host->ier |= SDHCI_INT_CARD_INT;
+ else
+ host->ier &= ~SDHCI_INT_CARD_INT;
+
+ sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
+ sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
+ }
+}
+
+void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable)
+{
+ struct sdhci_host *host = mmc_priv(mmc);
+ unsigned long flags;
+
+ if (enable)
+ pm_runtime_get_noresume(mmc_dev(mmc));
+
+ spin_lock_irqsave(&host->lock, flags);
+ sdhci_enable_sdio_irq_nolock(host, enable);
+ spin_unlock_irqrestore(&host->lock, flags);
+
+ if (!enable)
+ pm_runtime_put_noidle(mmc_dev(mmc));
+}
+EXPORT_SYMBOL_GPL(sdhci_enable_sdio_irq);
+
+static void sdhci_ack_sdio_irq(struct mmc_host *mmc)
+{
+ struct sdhci_host *host = mmc_priv(mmc);
+ unsigned long flags;
+
+ spin_lock_irqsave(&host->lock, flags);
+ sdhci_enable_sdio_irq_nolock(host, true);
+ spin_unlock_irqrestore(&host->lock, flags);
+}
+
+int sdhci_start_signal_voltage_switch(struct mmc_host *mmc,
+ struct mmc_ios *ios)
+{
+ struct sdhci_host *host = mmc_priv(mmc);
+ u16 ctrl;
+ int ret;
+
+ /*
+ * Signal Voltage Switching is only applicable for Host Controllers
+ * v3.00 and above.
+ */
+ if (host->version < SDHCI_SPEC_300)
+ return 0;
+
+ ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+
+ switch (ios->signal_voltage) {
+ case MMC_SIGNAL_VOLTAGE_330:
+ if (!(host->flags & SDHCI_SIGNALING_330))
+ return -EINVAL;
+ /* Set 1.8V Signal Enable in the Host Control2 register to 0 */
+ ctrl &= ~SDHCI_CTRL_VDD_180;
+ sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
+
+ if (!IS_ERR(mmc->supply.vqmmc)) {
+ ret = mmc_regulator_set_vqmmc(mmc, ios);
+ if (ret < 0) {
+ pr_warn("%s: Switching to 3.3V signalling voltage failed\n",
+ mmc_hostname(mmc));
+ return -EIO;
+ }
+ }
+ /* Wait for 5ms */
+ usleep_range(5000, 5500);
+
+ /* 3.3V regulator output should be stable within 5 ms */
+ ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+ if (!(ctrl & SDHCI_CTRL_VDD_180))
+ return 0;
+
+ pr_warn("%s: 3.3V regulator output did not become stable\n",
+ mmc_hostname(mmc));
+
+ return -EAGAIN;
+ case MMC_SIGNAL_VOLTAGE_180:
+ if (!(host->flags & SDHCI_SIGNALING_180))
+ return -EINVAL;
+ if (!IS_ERR(mmc->supply.vqmmc)) {
+ ret = mmc_regulator_set_vqmmc(mmc, ios);
+ if (ret < 0) {
+ pr_warn("%s: Switching to 1.8V signalling voltage failed\n",
+ mmc_hostname(mmc));
+ return -EIO;
+ }
+ }
+
+ /*
+ * Enable 1.8V Signal Enable in the Host Control2
+ * register
+ */
+ ctrl |= SDHCI_CTRL_VDD_180;
+ sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
+
+ /* Some controller need to do more when switching */
+ if (host->ops->voltage_switch)
+ host->ops->voltage_switch(host);
+
+ /* 1.8V regulator output should be stable within 5 ms */
+ ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+ if (ctrl & SDHCI_CTRL_VDD_180)
+ return 0;
+
+ pr_warn("%s: 1.8V regulator output did not become stable\n",
+ mmc_hostname(mmc));
+
+ return -EAGAIN;
+ case MMC_SIGNAL_VOLTAGE_120:
+ if (!(host->flags & SDHCI_SIGNALING_120))
+ return -EINVAL;
+ if (!IS_ERR(mmc->supply.vqmmc)) {
+ ret = mmc_regulator_set_vqmmc(mmc, ios);
+ if (ret < 0) {
+ pr_warn("%s: Switching to 1.2V signalling voltage failed\n",
+ mmc_hostname(mmc));
+ return -EIO;
+ }
+ }
+ return 0;
+ default:
+ /* No signal voltage switch required */
+ return 0;
+ }
+}
+EXPORT_SYMBOL_GPL(sdhci_start_signal_voltage_switch);
+
+static int sdhci_card_busy(struct mmc_host *mmc)
+{
+ struct sdhci_host *host = mmc_priv(mmc);
+ u32 present_state;
+
+ /* Check whether DAT[0] is 0 */
+ present_state = sdhci_readl(host, SDHCI_PRESENT_STATE);
+
+ return !(present_state & SDHCI_DATA_0_LVL_MASK);
+}
+
+static int sdhci_prepare_hs400_tuning(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+ struct sdhci_host *host = mmc_priv(mmc);
+ unsigned long flags;
+
+ spin_lock_irqsave(&host->lock, flags);
+ host->flags |= SDHCI_HS400_TUNING;
+ spin_unlock_irqrestore(&host->lock, flags);
+
+ return 0;
+}
+
+void sdhci_start_tuning(struct sdhci_host *host)
+{
+ u16 ctrl;
+
+ ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+ ctrl |= SDHCI_CTRL_EXEC_TUNING;
+ if (host->quirks2 & SDHCI_QUIRK2_TUNING_WORK_AROUND)
+ ctrl |= SDHCI_CTRL_TUNED_CLK;
+ sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
+
+ /*
+ * As per the Host Controller spec v3.00, tuning command
+ * generates Buffer Read Ready interrupt, so enable that.
+ *
+ * Note: The spec clearly says that when tuning sequence
+ * is being performed, the controller does not generate
+ * interrupts other than Buffer Read Ready interrupt. But
+ * to make sure we don't hit a controller bug, we _only_
+ * enable Buffer Read Ready interrupt here.
+ */
+ sdhci_writel(host, SDHCI_INT_DATA_AVAIL, SDHCI_INT_ENABLE);
+ sdhci_writel(host, SDHCI_INT_DATA_AVAIL, SDHCI_SIGNAL_ENABLE);
+}
+EXPORT_SYMBOL_GPL(sdhci_start_tuning);
+
+void sdhci_end_tuning(struct sdhci_host *host)
+{
+ sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
+ sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
+}
+EXPORT_SYMBOL_GPL(sdhci_end_tuning);
+
+void sdhci_reset_tuning(struct sdhci_host *host)
+{
+ u16 ctrl;
+
+ ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+ ctrl &= ~SDHCI_CTRL_TUNED_CLK;
+ ctrl &= ~SDHCI_CTRL_EXEC_TUNING;
+ sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
+}
+EXPORT_SYMBOL_GPL(sdhci_reset_tuning);
+
+void sdhci_abort_tuning(struct sdhci_host *host, u32 opcode)
+{
+ sdhci_reset_tuning(host);
+
+ sdhci_reset_for(host, TUNING_ABORT);
+
+ sdhci_end_tuning(host);
+
+ mmc_send_abort_tuning(host->mmc, opcode);
+}
+EXPORT_SYMBOL_GPL(sdhci_abort_tuning);
+
+/*
+ * We use sdhci_send_tuning() because mmc_send_tuning() is not a good fit. SDHCI
+ * tuning command does not have a data payload (or rather the hardware does it
+ * automatically) so mmc_send_tuning() will return -EIO. Also the tuning command
+ * interrupt setup is different to other commands and there is no timeout
+ * interrupt so special handling is needed.
+ */
+void sdhci_send_tuning(struct sdhci_host *host, u32 opcode)
+{
+ struct mmc_host *mmc = host->mmc;
+ struct mmc_command cmd = {};
+ struct mmc_request mrq = {};
+ unsigned long flags;
+ u32 b = host->sdma_boundary;
+
+ spin_lock_irqsave(&host->lock, flags);
+
+ cmd.opcode = opcode;
+ cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
+ cmd.mrq = &mrq;
+
+ mrq.cmd = &cmd;
+ /*
+ * In response to CMD19, the card sends 64 bytes of tuning
+ * block to the Host Controller. So we set the block size
+ * to 64 here.
+ */
+ if (cmd.opcode == MMC_SEND_TUNING_BLOCK_HS200 &&
+ mmc->ios.bus_width == MMC_BUS_WIDTH_8)
+ sdhci_writew(host, SDHCI_MAKE_BLKSZ(b, 128), SDHCI_BLOCK_SIZE);
+ else
+ sdhci_writew(host, SDHCI_MAKE_BLKSZ(b, 64), SDHCI_BLOCK_SIZE);
+
+ /*
+ * The tuning block is sent by the card to the host controller.
+ * So we set the TRNS_READ bit in the Transfer Mode register.
+ * This also takes care of setting DMA Enable and Multi Block
+ * Select in the same register to 0.
+ */
+ sdhci_writew(host, SDHCI_TRNS_READ, SDHCI_TRANSFER_MODE);
+
+ if (!sdhci_send_command_retry(host, &cmd, flags)) {
+ spin_unlock_irqrestore(&host->lock, flags);
+ host->tuning_done = 0;
+ return;
+ }
+
+ host->cmd = NULL;
+
+ sdhci_del_timer(host, &mrq);
+
+ host->tuning_done = 0;
+
+ spin_unlock_irqrestore(&host->lock, flags);
+
+ /* Wait for Buffer Read Ready interrupt */
+ wait_event_timeout(host->buf_ready_int, (host->tuning_done == 1),
+ msecs_to_jiffies(50));
+
+}
+EXPORT_SYMBOL_GPL(sdhci_send_tuning);
+
+static int __sdhci_execute_tuning(struct sdhci_host *host, u32 opcode)
+{
+ int i;
+
+ /*
+ * Issue opcode repeatedly till Execute Tuning is set to 0 or the number
+ * of loops reaches tuning loop count.
+ */
+ for (i = 0; i < host->tuning_loop_count; i++) {
+ u16 ctrl;
+
+ sdhci_send_tuning(host, opcode);
+
+ if (!host->tuning_done) {
+ pr_debug("%s: Tuning timeout, falling back to fixed sampling clock\n",
+ mmc_hostname(host->mmc));
+ sdhci_abort_tuning(host, opcode);
+ return -ETIMEDOUT;
+ }
+
+ /* Spec does not require a delay between tuning cycles */
+ if (host->tuning_delay > 0)
+ mdelay(host->tuning_delay);
+
+ ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+ if (!(ctrl & SDHCI_CTRL_EXEC_TUNING)) {
+ if (ctrl & SDHCI_CTRL_TUNED_CLK)
+ return 0; /* Success! */
+ break;
+ }
+
+ }
+
+ pr_info("%s: Tuning failed, falling back to fixed sampling clock\n",
+ mmc_hostname(host->mmc));
+ sdhci_reset_tuning(host);
+ return -EAGAIN;
+}
+
+int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
+{
+ struct sdhci_host *host = mmc_priv(mmc);
+ int err = 0;
+ unsigned int tuning_count = 0;
+ bool hs400_tuning;
+
+ hs400_tuning = host->flags & SDHCI_HS400_TUNING;
+
+ if (host->tuning_mode == SDHCI_TUNING_MODE_1)
+ tuning_count = host->tuning_count;
+
+ /*
+ * The Host Controller needs tuning in case of SDR104 and DDR50
+ * mode, and for SDR50 mode when Use Tuning for SDR50 is set in
+ * the Capabilities register.
+ * If the Host Controller supports the HS200 mode then the
+ * tuning function has to be executed.
+ */
+ switch (host->timing) {
+ /* HS400 tuning is done in HS200 mode */
+ case MMC_TIMING_MMC_HS400:
+ err = -EINVAL;
+ goto out;
+
+ case MMC_TIMING_MMC_HS200:
+ /*
+ * Periodic re-tuning for HS400 is not expected to be needed, so
+ * disable it here.
+ */
+ if (hs400_tuning)
+ tuning_count = 0;
+ break;
+
+ case MMC_TIMING_UHS_SDR104:
+ case MMC_TIMING_UHS_DDR50:
+ break;
+
+ case MMC_TIMING_UHS_SDR50:
+ if (host->flags & SDHCI_SDR50_NEEDS_TUNING)
+ break;
+ fallthrough;
+
+ default:
+ goto out;
+ }
+
+ if (host->ops->platform_execute_tuning) {
+ err = host->ops->platform_execute_tuning(host, opcode);
+ goto out;
+ }
+
+ mmc->retune_period = tuning_count;
+
+ if (host->tuning_delay < 0)
+ host->tuning_delay = opcode == MMC_SEND_TUNING_BLOCK;
+
+ sdhci_start_tuning(host);
+
+ host->tuning_err = __sdhci_execute_tuning(host, opcode);
+
+ sdhci_end_tuning(host);
+out:
+ host->flags &= ~SDHCI_HS400_TUNING;
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(sdhci_execute_tuning);
+
+static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable)
+{
+ /* Host Controller v3.00 defines preset value registers */
+ if (host->version < SDHCI_SPEC_300)
+ return;
+
+ /*
+ * We only enable or disable Preset Value if they are not already
+ * enabled or disabled respectively. Otherwise, we bail out.
+ */
+ if (host->preset_enabled != enable) {
+ u16 ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+
+ if (enable)
+ ctrl |= SDHCI_CTRL_PRESET_VAL_ENABLE;
+ else
+ ctrl &= ~SDHCI_CTRL_PRESET_VAL_ENABLE;
+
+ sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
+
+ if (enable)
+ host->flags |= SDHCI_PV_ENABLED;
+ else
+ host->flags &= ~SDHCI_PV_ENABLED;
+
+ host->preset_enabled = enable;
+ }
+}
+
+static void sdhci_post_req(struct mmc_host *mmc, struct mmc_request *mrq,
+ int err)
+{
+ struct mmc_data *data = mrq->data;
+
+ if (data->host_cookie != COOKIE_UNMAPPED)
+ dma_unmap_sg(mmc_dev(mmc), data->sg, data->sg_len,
+ mmc_get_dma_dir(data));
+
+ data->host_cookie = COOKIE_UNMAPPED;
+}
+
+static void sdhci_pre_req(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+ struct sdhci_host *host = mmc_priv(mmc);
+
+ mrq->data->host_cookie = COOKIE_UNMAPPED;
+
+ /*
+ * No pre-mapping in the pre hook if we're using the bounce buffer,
+ * for that we would need two bounce buffers since one buffer is
+ * in flight when this is getting called.
+ */
+ if (host->flags & SDHCI_REQ_USE_DMA && !host->bounce_buffer)
+ sdhci_pre_dma_transfer(host, mrq->data, COOKIE_PRE_MAPPED);
+}
+
+static void sdhci_error_out_mrqs(struct sdhci_host *host, int err)
+{
+ if (host->data_cmd) {
+ host->data_cmd->error = err;
+ sdhci_finish_mrq(host, host->data_cmd->mrq);
+ }
+
+ if (host->cmd) {
+ host->cmd->error = err;
+ sdhci_finish_mrq(host, host->cmd->mrq);
+ }
+}
+
+static void sdhci_card_event(struct mmc_host *mmc)
+{
+ struct sdhci_host *host = mmc_priv(mmc);
+ unsigned long flags;
+ int present;
+
+ /* First check if client has provided their own card event */
+ if (host->ops->card_event)
+ host->ops->card_event(host);
+
+ present = mmc->ops->get_cd(mmc);
+
+ spin_lock_irqsave(&host->lock, flags);
+
+ /* Check sdhci_has_requests() first in case we are runtime suspended */
+ if (sdhci_has_requests(host) && !present) {
+ pr_err("%s: Card removed during transfer!\n",
+ mmc_hostname(mmc));
+ pr_err("%s: Resetting controller.\n",
+ mmc_hostname(mmc));
+
+ sdhci_reset_for(host, CARD_REMOVED);
+
+ sdhci_error_out_mrqs(host, -ENOMEDIUM);
+ }
+
+ spin_unlock_irqrestore(&host->lock, flags);
+}
+
+static const struct mmc_host_ops sdhci_ops = {
+ .request = sdhci_request,
+ .post_req = sdhci_post_req,
+ .pre_req = sdhci_pre_req,
+ .set_ios = sdhci_set_ios,
+ .get_cd = sdhci_get_cd,
+ .get_ro = sdhci_get_ro,
+ .card_hw_reset = sdhci_hw_reset,
+ .enable_sdio_irq = sdhci_enable_sdio_irq,
+ .ack_sdio_irq = sdhci_ack_sdio_irq,
+ .start_signal_voltage_switch = sdhci_start_signal_voltage_switch,
+ .prepare_hs400_tuning = sdhci_prepare_hs400_tuning,
+ .execute_tuning = sdhci_execute_tuning,
+ .card_event = sdhci_card_event,
+ .card_busy = sdhci_card_busy,
+};
+
+/*****************************************************************************\
+ * *
+ * Request done *
+ * *
+\*****************************************************************************/
+
+static bool sdhci_request_done(struct sdhci_host *host)
+{
+ unsigned long flags;
+ struct mmc_request *mrq;
+ int i;
+
+ spin_lock_irqsave(&host->lock, flags);
+
+ for (i = 0; i < SDHCI_MAX_MRQS; i++) {
+ mrq = host->mrqs_done[i];
+ if (mrq)
+ break;
+ }
+
+ if (!mrq) {
+ spin_unlock_irqrestore(&host->lock, flags);
+ return true;
+ }
+
+ /*
+ * The controller needs a reset of internal state machines
+ * upon error conditions.
+ */
+ if (sdhci_needs_reset(host, mrq)) {
+ /*
+ * Do not finish until command and data lines are available for
+ * reset. Note there can only be one other mrq, so it cannot
+ * also be in mrqs_done, otherwise host->cmd and host->data_cmd
+ * would both be null.
+ */
+ if (host->cmd || host->data_cmd) {
+ spin_unlock_irqrestore(&host->lock, flags);
+ return true;
+ }
+
+ /* Some controllers need this kick or reset won't work here */
+ if (host->quirks & SDHCI_QUIRK_CLOCK_BEFORE_RESET)
+ /* This is to force an update */
+ host->ops->set_clock(host, host->clock);
+
+ sdhci_reset_for(host, REQUEST_ERROR);
+
+ host->pending_reset = false;
+ }
+
+ /*
+ * Always unmap the data buffers if they were mapped by
+ * sdhci_prepare_data() whenever we finish with a request.
+ * This avoids leaking DMA mappings on error.
+ */
+ if (host->flags & SDHCI_REQ_USE_DMA) {
+ struct mmc_data *data = mrq->data;
+
+ if (host->use_external_dma && data &&
+ (mrq->cmd->error || data->error)) {
+ struct dma_chan *chan = sdhci_external_dma_channel(host, data);
+
+ host->mrqs_done[i] = NULL;
+ spin_unlock_irqrestore(&host->lock, flags);
+ dmaengine_terminate_sync(chan);
+ spin_lock_irqsave(&host->lock, flags);
+ sdhci_set_mrq_done(host, mrq);
+ }
+
+ if (data && data->host_cookie == COOKIE_MAPPED) {
+ if (host->bounce_buffer) {
+ /*
+ * On reads, copy the bounced data into the
+ * sglist
+ */
+ if (mmc_get_dma_dir(data) == DMA_FROM_DEVICE) {
+ unsigned int length = data->bytes_xfered;
+
+ if (length > host->bounce_buffer_size) {
+ pr_err("%s: bounce buffer is %u bytes but DMA claims to have transferred %u bytes\n",
+ mmc_hostname(host->mmc),
+ host->bounce_buffer_size,
+ data->bytes_xfered);
+ /* Cap it down and continue */
+ length = host->bounce_buffer_size;
+ }
+ dma_sync_single_for_cpu(
+ mmc_dev(host->mmc),
+ host->bounce_addr,
+ host->bounce_buffer_size,
+ DMA_FROM_DEVICE);
+ sg_copy_from_buffer(data->sg,
+ data->sg_len,
+ host->bounce_buffer,
+ length);
+ } else {
+ /* No copying, just switch ownership */
+ dma_sync_single_for_cpu(
+ mmc_dev(host->mmc),
+ host->bounce_addr,
+ host->bounce_buffer_size,
+ mmc_get_dma_dir(data));
+ }
+ } else {
+ /* Unmap the raw data */
+ dma_unmap_sg(mmc_dev(host->mmc), data->sg,
+ data->sg_len,
+ mmc_get_dma_dir(data));
+ }
+ data->host_cookie = COOKIE_UNMAPPED;
+ }
+ }
+
+ host->mrqs_done[i] = NULL;
+
+ spin_unlock_irqrestore(&host->lock, flags);
+
+ if (host->ops->request_done)
+ host->ops->request_done(host, mrq);
+ else
+ mmc_request_done(host->mmc, mrq);
+
+ return false;
+}
+
+static void sdhci_complete_work(struct work_struct *work)
+{
+ struct sdhci_host *host = container_of(work, struct sdhci_host,
+ complete_work);
+
+ while (!sdhci_request_done(host))
+ ;
+}
+
+static void sdhci_timeout_timer(struct timer_list *t)
+{
+ struct sdhci_host *host;
+ unsigned long flags;
+
+ host = from_timer(host, t, timer);
+
+ spin_lock_irqsave(&host->lock, flags);
+
+ if (host->cmd && !sdhci_data_line_cmd(host->cmd)) {
+ pr_err("%s: Timeout waiting for hardware cmd interrupt.\n",
+ mmc_hostname(host->mmc));
+ sdhci_err_stats_inc(host, REQ_TIMEOUT);
+ sdhci_dumpregs(host);
+
+ host->cmd->error = -ETIMEDOUT;
+ sdhci_finish_mrq(host, host->cmd->mrq);
+ }
+
+ spin_unlock_irqrestore(&host->lock, flags);
+}
+
+static void sdhci_timeout_data_timer(struct timer_list *t)
+{
+ struct sdhci_host *host;
+ unsigned long flags;
+
+ host = from_timer(host, t, data_timer);
+
+ spin_lock_irqsave(&host->lock, flags);
+
+ if (host->data || host->data_cmd ||
+ (host->cmd && sdhci_data_line_cmd(host->cmd))) {
+ pr_err("%s: Timeout waiting for hardware interrupt.\n",
+ mmc_hostname(host->mmc));
+ sdhci_err_stats_inc(host, REQ_TIMEOUT);
+ sdhci_dumpregs(host);
+
+ if (host->data) {
+ host->data->error = -ETIMEDOUT;
+ __sdhci_finish_data(host, true);
+ queue_work(host->complete_wq, &host->complete_work);
+ } else if (host->data_cmd) {
+ host->data_cmd->error = -ETIMEDOUT;
+ sdhci_finish_mrq(host, host->data_cmd->mrq);
+ } else {
+ host->cmd->error = -ETIMEDOUT;
+ sdhci_finish_mrq(host, host->cmd->mrq);
+ }
+ }
+
+ spin_unlock_irqrestore(&host->lock, flags);
+}
+
+/*****************************************************************************\
+ * *
+ * Interrupt handling *
+ * *
+\*****************************************************************************/
+
+static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask, u32 *intmask_p)
+{
+ /* Handle auto-CMD12 error */
+ if (intmask & SDHCI_INT_AUTO_CMD_ERR && host->data_cmd) {
+ struct mmc_request *mrq = host->data_cmd->mrq;
+ u16 auto_cmd_status = sdhci_readw(host, SDHCI_AUTO_CMD_STATUS);
+ int data_err_bit = (auto_cmd_status & SDHCI_AUTO_CMD_TIMEOUT) ?
+ SDHCI_INT_DATA_TIMEOUT :
+ SDHCI_INT_DATA_CRC;
+
+ /* Treat auto-CMD12 error the same as data error */
+ if (!mrq->sbc && (host->flags & SDHCI_AUTO_CMD12)) {
+ *intmask_p |= data_err_bit;
+ return;
+ }
+ }
+
+ if (!host->cmd) {
+ /*
+ * SDHCI recovers from errors by resetting the cmd and data
+ * circuits. Until that is done, there very well might be more
+ * interrupts, so ignore them in that case.
+ */
+ if (host->pending_reset)
+ return;
+ pr_err("%s: Got command interrupt 0x%08x even though no command operation was in progress.\n",
+ mmc_hostname(host->mmc), (unsigned)intmask);
+ sdhci_err_stats_inc(host, UNEXPECTED_IRQ);
+ sdhci_dumpregs(host);
+ return;
+ }
+
+ if (intmask & (SDHCI_INT_TIMEOUT | SDHCI_INT_CRC |
+ SDHCI_INT_END_BIT | SDHCI_INT_INDEX)) {
+ if (intmask & SDHCI_INT_TIMEOUT) {
+ host->cmd->error = -ETIMEDOUT;
+ sdhci_err_stats_inc(host, CMD_TIMEOUT);
+ } else {
+ host->cmd->error = -EILSEQ;
+ if (!mmc_op_tuning(host->cmd->opcode))
+ sdhci_err_stats_inc(host, CMD_CRC);
+ }
+ /* Treat data command CRC error the same as data CRC error */
+ if (host->cmd->data &&
+ (intmask & (SDHCI_INT_CRC | SDHCI_INT_TIMEOUT)) ==
+ SDHCI_INT_CRC) {
+ host->cmd = NULL;
+ *intmask_p |= SDHCI_INT_DATA_CRC;
+ return;
+ }
+
+ __sdhci_finish_mrq(host, host->cmd->mrq);
+ return;
+ }
+
+ /* Handle auto-CMD23 error */
+ if (intmask & SDHCI_INT_AUTO_CMD_ERR) {
+ struct mmc_request *mrq = host->cmd->mrq;
+ u16 auto_cmd_status = sdhci_readw(host, SDHCI_AUTO_CMD_STATUS);
+ int err = (auto_cmd_status & SDHCI_AUTO_CMD_TIMEOUT) ?
+ -ETIMEDOUT :
+ -EILSEQ;
+
+ sdhci_err_stats_inc(host, AUTO_CMD);
+
+ if (sdhci_auto_cmd23(host, mrq)) {
+ mrq->sbc->error = err;
+ __sdhci_finish_mrq(host, mrq);
+ return;
+ }
+ }
+
+ if (intmask & SDHCI_INT_RESPONSE)
+ sdhci_finish_command(host);
+}
+
+static void sdhci_adma_show_error(struct sdhci_host *host)
+{
+ void *desc = host->adma_table;
+ dma_addr_t dma = host->adma_addr;
+
+ sdhci_dumpregs(host);
+
+ while (true) {
+ struct sdhci_adma2_64_desc *dma_desc = desc;
+
+ if (host->flags & SDHCI_USE_64_BIT_DMA)
+ SDHCI_DUMP("%08llx: DMA 0x%08x%08x, LEN 0x%04x, Attr=0x%02x\n",
+ (unsigned long long)dma,
+ le32_to_cpu(dma_desc->addr_hi),
+ le32_to_cpu(dma_desc->addr_lo),
+ le16_to_cpu(dma_desc->len),
+ le16_to_cpu(dma_desc->cmd));
+ else
+ SDHCI_DUMP("%08llx: DMA 0x%08x, LEN 0x%04x, Attr=0x%02x\n",
+ (unsigned long long)dma,
+ le32_to_cpu(dma_desc->addr_lo),
+ le16_to_cpu(dma_desc->len),
+ le16_to_cpu(dma_desc->cmd));
+
+ desc += host->desc_sz;
+ dma += host->desc_sz;
+
+ if (dma_desc->cmd & cpu_to_le16(ADMA2_END))
+ break;
+ }
+}
+
+static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
+{
+ u32 command;
+
+ /*
+ * CMD19 generates _only_ Buffer Read Ready interrupt if
+ * use sdhci_send_tuning.
+ * Need to exclude this case: PIO mode and use mmc_send_tuning,
+ * If not, sdhci_transfer_pio will never be called, make the
+ * SDHCI_INT_DATA_AVAIL always there, stuck in irq storm.
+ */
+ if (intmask & SDHCI_INT_DATA_AVAIL && !host->data) {
+ command = SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND));
+ if (command == MMC_SEND_TUNING_BLOCK ||
+ command == MMC_SEND_TUNING_BLOCK_HS200) {
+ host->tuning_done = 1;
+ wake_up(&host->buf_ready_int);
+ return;
+ }
+ }
+
+ if (!host->data) {
+ struct mmc_command *data_cmd = host->data_cmd;
+
+ /*
+ * The "data complete" interrupt is also used to
+ * indicate that a busy state has ended. See comment
+ * above in sdhci_cmd_irq().
+ */
+ if (data_cmd && (data_cmd->flags & MMC_RSP_BUSY)) {
+ if (intmask & SDHCI_INT_DATA_TIMEOUT) {
+ host->data_cmd = NULL;
+ data_cmd->error = -ETIMEDOUT;
+ sdhci_err_stats_inc(host, CMD_TIMEOUT);
+ __sdhci_finish_mrq(host, data_cmd->mrq);
+ return;
+ }
+ if (intmask & SDHCI_INT_DATA_END) {
+ host->data_cmd = NULL;
+ /*
+ * Some cards handle busy-end interrupt
+ * before the command completed, so make
+ * sure we do things in the proper order.
+ */
+ if (host->cmd == data_cmd)
+ return;
+
+ __sdhci_finish_mrq(host, data_cmd->mrq);
+ return;
+ }
+ }
+
+ /*
+ * SDHCI recovers from errors by resetting the cmd and data
+ * circuits. Until that is done, there very well might be more
+ * interrupts, so ignore them in that case.
+ */
+ if (host->pending_reset)
+ return;
+
+ pr_err("%s: Got data interrupt 0x%08x even though no data operation was in progress.\n",
+ mmc_hostname(host->mmc), (unsigned)intmask);
+ sdhci_err_stats_inc(host, UNEXPECTED_IRQ);
+ sdhci_dumpregs(host);
+
+ return;
+ }
+
+ if (intmask & SDHCI_INT_DATA_TIMEOUT) {
+ host->data->error = -ETIMEDOUT;
+ sdhci_err_stats_inc(host, DAT_TIMEOUT);
+ } else if (intmask & SDHCI_INT_DATA_END_BIT) {
+ host->data->error = -EILSEQ;
+ if (!mmc_op_tuning(SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND))))
+ sdhci_err_stats_inc(host, DAT_CRC);
+ } else if ((intmask & SDHCI_INT_DATA_CRC) &&
+ SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND))
+ != MMC_BUS_TEST_R) {
+ host->data->error = -EILSEQ;
+ if (!mmc_op_tuning(SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND))))
+ sdhci_err_stats_inc(host, DAT_CRC);
+ } else if (intmask & SDHCI_INT_ADMA_ERROR) {
+ pr_err("%s: ADMA error: 0x%08x\n", mmc_hostname(host->mmc),
+ intmask);
+ sdhci_adma_show_error(host);
+ sdhci_err_stats_inc(host, ADMA);
+ host->data->error = -EIO;
+ if (host->ops->adma_workaround)
+ host->ops->adma_workaround(host, intmask);
+ }
+
+ if (host->data->error)
+ sdhci_finish_data(host);
+ else {
+ if (intmask & (SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL))
+ sdhci_transfer_pio(host);
+
+ /*
+ * We currently don't do anything fancy with DMA
+ * boundaries, but as we can't disable the feature
+ * we need to at least restart the transfer.
+ *
+ * According to the spec sdhci_readl(host, SDHCI_DMA_ADDRESS)
+ * should return a valid address to continue from, but as
+ * some controllers are faulty, don't trust them.
+ */
+ if (intmask & SDHCI_INT_DMA_END) {
+ dma_addr_t dmastart, dmanow;
+
+ dmastart = sdhci_sdma_address(host);
+ dmanow = dmastart + host->data->bytes_xfered;
+ /*
+ * Force update to the next DMA block boundary.
+ */
+ dmanow = (dmanow &
+ ~((dma_addr_t)SDHCI_DEFAULT_BOUNDARY_SIZE - 1)) +
+ SDHCI_DEFAULT_BOUNDARY_SIZE;
+ host->data->bytes_xfered = dmanow - dmastart;
+ DBG("DMA base %pad, transferred 0x%06x bytes, next %pad\n",
+ &dmastart, host->data->bytes_xfered, &dmanow);
+ sdhci_set_sdma_addr(host, dmanow);
+ }
+
+ if (intmask & SDHCI_INT_DATA_END) {
+ if (host->cmd == host->data_cmd) {
+ /*
+ * Data managed to finish before the
+ * command completed. Make sure we do
+ * things in the proper order.
+ */
+ host->data_early = 1;
+ } else {
+ sdhci_finish_data(host);
+ }
+ }
+ }
+}
+
+static inline bool sdhci_defer_done(struct sdhci_host *host,
+ struct mmc_request *mrq)
+{
+ struct mmc_data *data = mrq->data;
+
+ return host->pending_reset || host->always_defer_done ||
+ ((host->flags & SDHCI_REQ_USE_DMA) && data &&
+ data->host_cookie == COOKIE_MAPPED);
+}
+
+static irqreturn_t sdhci_irq(int irq, void *dev_id)
+{
+ struct mmc_request *mrqs_done[SDHCI_MAX_MRQS] = {0};
+ irqreturn_t result = IRQ_NONE;
+ struct sdhci_host *host = dev_id;
+ u32 intmask, mask, unexpected = 0;
+ int max_loops = 16;
+ int i;
+
+ spin_lock(&host->lock);
+
+ if (host->runtime_suspended) {
+ spin_unlock(&host->lock);
+ return IRQ_NONE;
+ }
+
+ intmask = sdhci_readl(host, SDHCI_INT_STATUS);
+ if (!intmask || intmask == 0xffffffff) {
+ result = IRQ_NONE;
+ goto out;
+ }
+
+ do {
+ DBG("IRQ status 0x%08x\n", intmask);
+
+ if (host->ops->irq) {
+ intmask = host->ops->irq(host, intmask);
+ if (!intmask)
+ goto cont;
+ }
+
+ /* Clear selected interrupts. */
+ mask = intmask & (SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK |
+ SDHCI_INT_BUS_POWER);
+ sdhci_writel(host, mask, SDHCI_INT_STATUS);
+
+ if (intmask & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE)) {
+ u32 present = sdhci_readl(host, SDHCI_PRESENT_STATE) &
+ SDHCI_CARD_PRESENT;
+
+ /*
+ * There is a observation on i.mx esdhc. INSERT
+ * bit will be immediately set again when it gets
+ * cleared, if a card is inserted. We have to mask
+ * the irq to prevent interrupt storm which will
+ * freeze the system. And the REMOVE gets the
+ * same situation.
+ *
+ * More testing are needed here to ensure it works
+ * for other platforms though.
+ */
+ host->ier &= ~(SDHCI_INT_CARD_INSERT |
+ SDHCI_INT_CARD_REMOVE);
+ host->ier |= present ? SDHCI_INT_CARD_REMOVE :
+ SDHCI_INT_CARD_INSERT;
+ sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
+ sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
+
+ sdhci_writel(host, intmask & (SDHCI_INT_CARD_INSERT |
+ SDHCI_INT_CARD_REMOVE), SDHCI_INT_STATUS);
+
+ host->thread_isr |= intmask & (SDHCI_INT_CARD_INSERT |
+ SDHCI_INT_CARD_REMOVE);
+ result = IRQ_WAKE_THREAD;
+ }
+
+ if (intmask & SDHCI_INT_CMD_MASK)
+ sdhci_cmd_irq(host, intmask & SDHCI_INT_CMD_MASK, &intmask);
+
+ if (intmask & SDHCI_INT_DATA_MASK)
+ sdhci_data_irq(host, intmask & SDHCI_INT_DATA_MASK);
+
+ if (intmask & SDHCI_INT_BUS_POWER)
+ pr_err("%s: Card is consuming too much power!\n",
+ mmc_hostname(host->mmc));
+
+ if (intmask & SDHCI_INT_RETUNE)
+ mmc_retune_needed(host->mmc);
+
+ if ((intmask & SDHCI_INT_CARD_INT) &&
+ (host->ier & SDHCI_INT_CARD_INT)) {
+ sdhci_enable_sdio_irq_nolock(host, false);
+ sdio_signal_irq(host->mmc);
+ }
+
+ intmask &= ~(SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE |
+ SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK |
+ SDHCI_INT_ERROR | SDHCI_INT_BUS_POWER |
+ SDHCI_INT_RETUNE | SDHCI_INT_CARD_INT);
+
+ if (intmask) {
+ unexpected |= intmask;
+ sdhci_writel(host, intmask, SDHCI_INT_STATUS);
+ }
+cont:
+ if (result == IRQ_NONE)
+ result = IRQ_HANDLED;
+
+ intmask = sdhci_readl(host, SDHCI_INT_STATUS);
+ } while (intmask && --max_loops);
+
+ /* Determine if mrqs can be completed immediately */
+ for (i = 0; i < SDHCI_MAX_MRQS; i++) {
+ struct mmc_request *mrq = host->mrqs_done[i];
+
+ if (!mrq)
+ continue;
+
+ if (sdhci_defer_done(host, mrq)) {
+ result = IRQ_WAKE_THREAD;
+ } else {
+ mrqs_done[i] = mrq;
+ host->mrqs_done[i] = NULL;
+ }
+ }
+out:
+ if (host->deferred_cmd)
+ result = IRQ_WAKE_THREAD;
+
+ spin_unlock(&host->lock);
+
+ /* Process mrqs ready for immediate completion */
+ for (i = 0; i < SDHCI_MAX_MRQS; i++) {
+ if (!mrqs_done[i])
+ continue;
+
+ if (host->ops->request_done)
+ host->ops->request_done(host, mrqs_done[i]);
+ else
+ mmc_request_done(host->mmc, mrqs_done[i]);
+ }
+
+ if (unexpected) {
+ pr_err("%s: Unexpected interrupt 0x%08x.\n",
+ mmc_hostname(host->mmc), unexpected);
+ sdhci_err_stats_inc(host, UNEXPECTED_IRQ);
+ sdhci_dumpregs(host);
+ }
+
+ return result;
+}
+
+static irqreturn_t sdhci_thread_irq(int irq, void *dev_id)
+{
+ struct sdhci_host *host = dev_id;
+ struct mmc_command *cmd;
+ unsigned long flags;
+ u32 isr;
+
+ while (!sdhci_request_done(host))
+ ;
+
+ spin_lock_irqsave(&host->lock, flags);
+
+ isr = host->thread_isr;
+ host->thread_isr = 0;
+
+ cmd = host->deferred_cmd;
+ if (cmd && !sdhci_send_command_retry(host, cmd, flags))
+ sdhci_finish_mrq(host, cmd->mrq);
+
+ spin_unlock_irqrestore(&host->lock, flags);
+
+ if (isr & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE)) {
+ struct mmc_host *mmc = host->mmc;
+
+ mmc->ops->card_event(mmc);
+ mmc_detect_change(mmc, msecs_to_jiffies(200));
+ }
+
+ return IRQ_HANDLED;
+}
+
+/*****************************************************************************\
+ * *
+ * Suspend/resume *
+ * *
+\*****************************************************************************/
+
+#ifdef CONFIG_PM
+
+static bool sdhci_cd_irq_can_wakeup(struct sdhci_host *host)
+{
+ return mmc_card_is_removable(host->mmc) &&
+ !(host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) &&
+ !mmc_can_gpio_cd(host->mmc);
+}
+
+/*
+ * To enable wakeup events, the corresponding events have to be enabled in
+ * the Interrupt Status Enable register too. See 'Table 1-6: Wakeup Signal
+ * Table' in the SD Host Controller Standard Specification.
+ * It is useless to restore SDHCI_INT_ENABLE state in
+ * sdhci_disable_irq_wakeups() since it will be set by
+ * sdhci_enable_card_detection() or sdhci_init().
+ */
+static bool sdhci_enable_irq_wakeups(struct sdhci_host *host)
+{
+ u8 mask = SDHCI_WAKE_ON_INSERT | SDHCI_WAKE_ON_REMOVE |
+ SDHCI_WAKE_ON_INT;
+ u32 irq_val = 0;
+ u8 wake_val = 0;
+ u8 val;
+
+ if (sdhci_cd_irq_can_wakeup(host)) {
+ wake_val |= SDHCI_WAKE_ON_INSERT | SDHCI_WAKE_ON_REMOVE;
+ irq_val |= SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE;
+ }
+
+ if (mmc_card_wake_sdio_irq(host->mmc)) {
+ wake_val |= SDHCI_WAKE_ON_INT;
+ irq_val |= SDHCI_INT_CARD_INT;
+ }
+
+ if (!irq_val)
+ return false;
+
+ val = sdhci_readb(host, SDHCI_WAKE_UP_CONTROL);
+ val &= ~mask;
+ val |= wake_val;
+ sdhci_writeb(host, val, SDHCI_WAKE_UP_CONTROL);
+
+ sdhci_writel(host, irq_val, SDHCI_INT_ENABLE);
+
+ host->irq_wake_enabled = !enable_irq_wake(host->irq);
+
+ return host->irq_wake_enabled;
+}
+
+static void sdhci_disable_irq_wakeups(struct sdhci_host *host)
+{
+ u8 val;
+ u8 mask = SDHCI_WAKE_ON_INSERT | SDHCI_WAKE_ON_REMOVE
+ | SDHCI_WAKE_ON_INT;
+
+ val = sdhci_readb(host, SDHCI_WAKE_UP_CONTROL);
+ val &= ~mask;
+ sdhci_writeb(host, val, SDHCI_WAKE_UP_CONTROL);
+
+ disable_irq_wake(host->irq);
+
+ host->irq_wake_enabled = false;
+}
+
+int sdhci_suspend_host(struct sdhci_host *host)
+{
+ sdhci_disable_card_detection(host);
+
+ mmc_retune_timer_stop(host->mmc);
+
+ if (!device_may_wakeup(mmc_dev(host->mmc)) ||
+ !sdhci_enable_irq_wakeups(host)) {
+ host->ier = 0;
+ sdhci_writel(host, 0, SDHCI_INT_ENABLE);
+ sdhci_writel(host, 0, SDHCI_SIGNAL_ENABLE);
+ free_irq(host->irq, host);
+ }
+
+ return 0;
+}
+
+EXPORT_SYMBOL_GPL(sdhci_suspend_host);
+
+int sdhci_resume_host(struct sdhci_host *host)
+{
+ struct mmc_host *mmc = host->mmc;
+ int ret = 0;
+
+ if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) {
+ if (host->ops->enable_dma)
+ host->ops->enable_dma(host);
+ }
+
+ if ((mmc->pm_flags & MMC_PM_KEEP_POWER) &&
+ (host->quirks2 & SDHCI_QUIRK2_HOST_OFF_CARD_ON)) {
+ /* Card keeps power but host controller does not */
+ sdhci_init(host, 0);
+ host->pwr = 0;
+ host->clock = 0;
+ host->reinit_uhs = true;
+ mmc->ops->set_ios(mmc, &mmc->ios);
+ } else {
+ sdhci_init(host, (mmc->pm_flags & MMC_PM_KEEP_POWER));
+ }
+
+ if (host->irq_wake_enabled) {
+ sdhci_disable_irq_wakeups(host);
+ } else {
+ ret = request_threaded_irq(host->irq, sdhci_irq,
+ sdhci_thread_irq, IRQF_SHARED,
+ mmc_hostname(mmc), host);
+ if (ret)
+ return ret;
+ }
+
+ sdhci_enable_card_detection(host);
+
+ return ret;
+}
+
+EXPORT_SYMBOL_GPL(sdhci_resume_host);
+
+int sdhci_runtime_suspend_host(struct sdhci_host *host)
+{
+ unsigned long flags;
+
+ mmc_retune_timer_stop(host->mmc);
+
+ spin_lock_irqsave(&host->lock, flags);
+ host->ier &= SDHCI_INT_CARD_INT;
+ sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
+ sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
+ spin_unlock_irqrestore(&host->lock, flags);
+
+ synchronize_hardirq(host->irq);
+
+ spin_lock_irqsave(&host->lock, flags);
+ host->runtime_suspended = true;
+ spin_unlock_irqrestore(&host->lock, flags);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(sdhci_runtime_suspend_host);
+
+int sdhci_runtime_resume_host(struct sdhci_host *host, int soft_reset)
+{
+ struct mmc_host *mmc = host->mmc;
+ unsigned long flags;
+ int host_flags = host->flags;
+
+ if (host_flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) {
+ if (host->ops->enable_dma)
+ host->ops->enable_dma(host);
+ }
+
+ sdhci_init(host, soft_reset);
+
+ if (mmc->ios.power_mode != MMC_POWER_UNDEFINED &&
+ mmc->ios.power_mode != MMC_POWER_OFF) {
+ /* Force clock and power re-program */
+ host->pwr = 0;
+ host->clock = 0;
+ host->reinit_uhs = true;
+ mmc->ops->start_signal_voltage_switch(mmc, &mmc->ios);
+ mmc->ops->set_ios(mmc, &mmc->ios);
+
+ if ((host_flags & SDHCI_PV_ENABLED) &&
+ !(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN)) {
+ spin_lock_irqsave(&host->lock, flags);
+ sdhci_enable_preset_value(host, true);
+ spin_unlock_irqrestore(&host->lock, flags);
+ }
+
+ if ((mmc->caps2 & MMC_CAP2_HS400_ES) &&
+ mmc->ops->hs400_enhanced_strobe)
+ mmc->ops->hs400_enhanced_strobe(mmc, &mmc->ios);
+ }
+
+ spin_lock_irqsave(&host->lock, flags);
+
+ host->runtime_suspended = false;
+
+ /* Enable SDIO IRQ */
+ if (sdio_irq_claimed(mmc))
+ sdhci_enable_sdio_irq_nolock(host, true);
+
+ /* Enable Card Detection */
+ sdhci_enable_card_detection(host);
+
+ spin_unlock_irqrestore(&host->lock, flags);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(sdhci_runtime_resume_host);
+
+#endif /* CONFIG_PM */
+
+/*****************************************************************************\
+ * *
+ * Command Queue Engine (CQE) helpers *
+ * *
+\*****************************************************************************/
+
+void sdhci_cqe_enable(struct mmc_host *mmc)
+{
+ struct sdhci_host *host = mmc_priv(mmc);
+ unsigned long flags;
+ u8 ctrl;
+
+ spin_lock_irqsave(&host->lock, flags);
+
+ ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
+ ctrl &= ~SDHCI_CTRL_DMA_MASK;
+ /*
+ * Host from V4.10 supports ADMA3 DMA type.
+ * ADMA3 performs integrated descriptor which is more suitable
+ * for cmd queuing to fetch both command and transfer descriptors.
+ */
+ if (host->v4_mode && (host->caps1 & SDHCI_CAN_DO_ADMA3))
+ ctrl |= SDHCI_CTRL_ADMA3;
+ else if (host->flags & SDHCI_USE_64_BIT_DMA)
+ ctrl |= SDHCI_CTRL_ADMA64;
+ else
+ ctrl |= SDHCI_CTRL_ADMA32;
+ sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
+
+ sdhci_writew(host, SDHCI_MAKE_BLKSZ(host->sdma_boundary, 512),
+ SDHCI_BLOCK_SIZE);
+
+ /* Set maximum timeout */
+ sdhci_set_timeout(host, NULL);
+
+ host->ier = host->cqe_ier;
+
+ sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
+ sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
+
+ host->cqe_on = true;
+
+ pr_debug("%s: sdhci: CQE on, IRQ mask %#x, IRQ status %#x\n",
+ mmc_hostname(mmc), host->ier,
+ sdhci_readl(host, SDHCI_INT_STATUS));
+
+ spin_unlock_irqrestore(&host->lock, flags);
+}
+EXPORT_SYMBOL_GPL(sdhci_cqe_enable);
+
+void sdhci_cqe_disable(struct mmc_host *mmc, bool recovery)
+{
+ struct sdhci_host *host = mmc_priv(mmc);
+ unsigned long flags;
+
+ spin_lock_irqsave(&host->lock, flags);
+
+ sdhci_set_default_irqs(host);
+
+ host->cqe_on = false;
+
+ if (recovery)
+ sdhci_reset_for(host, CQE_RECOVERY);
+
+ pr_debug("%s: sdhci: CQE off, IRQ mask %#x, IRQ status %#x\n",
+ mmc_hostname(mmc), host->ier,
+ sdhci_readl(host, SDHCI_INT_STATUS));
+
+ spin_unlock_irqrestore(&host->lock, flags);
+}
+EXPORT_SYMBOL_GPL(sdhci_cqe_disable);
+
+bool sdhci_cqe_irq(struct sdhci_host *host, u32 intmask, int *cmd_error,
+ int *data_error)
+{
+ u32 mask;
+
+ if (!host->cqe_on)
+ return false;
+
+ if (intmask & (SDHCI_INT_INDEX | SDHCI_INT_END_BIT | SDHCI_INT_CRC)) {
+ *cmd_error = -EILSEQ;
+ if (!mmc_op_tuning(SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND))))
+ sdhci_err_stats_inc(host, CMD_CRC);
+ } else if (intmask & SDHCI_INT_TIMEOUT) {
+ *cmd_error = -ETIMEDOUT;
+ sdhci_err_stats_inc(host, CMD_TIMEOUT);
+ } else
+ *cmd_error = 0;
+
+ if (intmask & (SDHCI_INT_DATA_END_BIT | SDHCI_INT_DATA_CRC)) {
+ *data_error = -EILSEQ;
+ if (!mmc_op_tuning(SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND))))
+ sdhci_err_stats_inc(host, DAT_CRC);
+ } else if (intmask & SDHCI_INT_DATA_TIMEOUT) {
+ *data_error = -ETIMEDOUT;
+ sdhci_err_stats_inc(host, DAT_TIMEOUT);
+ } else if (intmask & SDHCI_INT_ADMA_ERROR) {
+ *data_error = -EIO;
+ sdhci_err_stats_inc(host, ADMA);
+ } else
+ *data_error = 0;
+
+ /* Clear selected interrupts. */
+ mask = intmask & host->cqe_ier;
+ sdhci_writel(host, mask, SDHCI_INT_STATUS);
+
+ if (intmask & SDHCI_INT_BUS_POWER)
+ pr_err("%s: Card is consuming too much power!\n",
+ mmc_hostname(host->mmc));
+
+ intmask &= ~(host->cqe_ier | SDHCI_INT_ERROR);
+ if (intmask) {
+ sdhci_writel(host, intmask, SDHCI_INT_STATUS);
+ pr_err("%s: CQE: Unexpected interrupt 0x%08x.\n",
+ mmc_hostname(host->mmc), intmask);
+ sdhci_err_stats_inc(host, UNEXPECTED_IRQ);
+ sdhci_dumpregs(host);
+ }
+
+ return true;
+}
+EXPORT_SYMBOL_GPL(sdhci_cqe_irq);
+
+/*****************************************************************************\
+ * *
+ * Device allocation/registration *
+ * *
+\*****************************************************************************/
+
+struct sdhci_host *sdhci_alloc_host(struct device *dev,
+ size_t priv_size)
+{
+ struct mmc_host *mmc;
+ struct sdhci_host *host;
+
+ WARN_ON(dev == NULL);
+
+ mmc = mmc_alloc_host(sizeof(struct sdhci_host) + priv_size, dev);
+ if (!mmc)
+ return ERR_PTR(-ENOMEM);
+
+ host = mmc_priv(mmc);
+ host->mmc = mmc;
+ host->mmc_host_ops = sdhci_ops;
+ mmc->ops = &host->mmc_host_ops;
+
+ host->flags = SDHCI_SIGNALING_330;
+
+ host->cqe_ier = SDHCI_CQE_INT_MASK;
+ host->cqe_err_ier = SDHCI_CQE_INT_ERR_MASK;
+
+ host->tuning_delay = -1;
+ host->tuning_loop_count = MAX_TUNING_LOOP;
+
+ host->sdma_boundary = SDHCI_DEFAULT_BOUNDARY_ARG;
+
+ /*
+ * The DMA table descriptor count is calculated as the maximum
+ * number of segments times 2, to allow for an alignment
+ * descriptor for each segment, plus 1 for a nop end descriptor.
+ */
+ host->adma_table_cnt = SDHCI_MAX_SEGS * 2 + 1;
+ host->max_adma = 65536;
+
+ host->max_timeout_count = 0xE;
+
+ return host;
+}
+
+EXPORT_SYMBOL_GPL(sdhci_alloc_host);
+
+static int sdhci_set_dma_mask(struct sdhci_host *host)
+{
+ struct mmc_host *mmc = host->mmc;
+ struct device *dev = mmc_dev(mmc);
+ int ret = -EINVAL;
+
+ if (host->quirks2 & SDHCI_QUIRK2_BROKEN_64_BIT_DMA)
+ host->flags &= ~SDHCI_USE_64_BIT_DMA;
+
+ /* Try 64-bit mask if hardware is capable of it */
+ if (host->flags & SDHCI_USE_64_BIT_DMA) {
+ ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64));
+ if (ret) {
+ pr_warn("%s: Failed to set 64-bit DMA mask.\n",
+ mmc_hostname(mmc));
+ host->flags &= ~SDHCI_USE_64_BIT_DMA;
+ }
+ }
+
+ /* 32-bit mask as default & fallback */
+ if (ret) {
+ ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
+ if (ret)
+ pr_warn("%s: Failed to set 32-bit DMA mask.\n",
+ mmc_hostname(mmc));
+ }
+
+ return ret;
+}
+
+void __sdhci_read_caps(struct sdhci_host *host, const u16 *ver,
+ const u32 *caps, const u32 *caps1)
+{
+ u16 v;
+ u64 dt_caps_mask = 0;
+ u64 dt_caps = 0;
+
+ if (host->read_caps)
+ return;
+
+ host->read_caps = true;
+
+ if (debug_quirks)
+ host->quirks = debug_quirks;
+
+ if (debug_quirks2)
+ host->quirks2 = debug_quirks2;
+
+ sdhci_reset_for_all(host);
+
+ if (host->v4_mode)
+ sdhci_do_enable_v4_mode(host);
+
+ device_property_read_u64(mmc_dev(host->mmc),
+ "sdhci-caps-mask", &dt_caps_mask);
+ device_property_read_u64(mmc_dev(host->mmc),
+ "sdhci-caps", &dt_caps);
+
+ v = ver ? *ver : sdhci_readw(host, SDHCI_HOST_VERSION);
+ host->version = (v & SDHCI_SPEC_VER_MASK) >> SDHCI_SPEC_VER_SHIFT;
+
+ if (host->quirks & SDHCI_QUIRK_MISSING_CAPS)
+ return;
+
+ if (caps) {
+ host->caps = *caps;
+ } else {
+ host->caps = sdhci_readl(host, SDHCI_CAPABILITIES);
+ host->caps &= ~lower_32_bits(dt_caps_mask);
+ host->caps |= lower_32_bits(dt_caps);
+ }
+
+ if (host->version < SDHCI_SPEC_300)
+ return;
+
+ if (caps1) {
+ host->caps1 = *caps1;
+ } else {
+ host->caps1 = sdhci_readl(host, SDHCI_CAPABILITIES_1);
+ host->caps1 &= ~upper_32_bits(dt_caps_mask);
+ host->caps1 |= upper_32_bits(dt_caps);
+ }
+}
+EXPORT_SYMBOL_GPL(__sdhci_read_caps);
+
+static void sdhci_allocate_bounce_buffer(struct sdhci_host *host)
+{
+ struct mmc_host *mmc = host->mmc;
+ unsigned int max_blocks;
+ unsigned int bounce_size;
+ int ret;
+
+ /*
+ * Cap the bounce buffer at 64KB. Using a bigger bounce buffer
+ * has diminishing returns, this is probably because SD/MMC
+ * cards are usually optimized to handle this size of requests.
+ */
+ bounce_size = SZ_64K;
+ /*
+ * Adjust downwards to maximum request size if this is less
+ * than our segment size, else hammer down the maximum
+ * request size to the maximum buffer size.
+ */
+ if (mmc->max_req_size < bounce_size)
+ bounce_size = mmc->max_req_size;
+ max_blocks = bounce_size / 512;
+
+ /*
+ * When we just support one segment, we can get significant
+ * speedups by the help of a bounce buffer to group scattered
+ * reads/writes together.
+ */
+ host->bounce_buffer = devm_kmalloc(mmc_dev(mmc),
+ bounce_size,
+ GFP_KERNEL);
+ if (!host->bounce_buffer) {
+ pr_err("%s: failed to allocate %u bytes for bounce buffer, falling back to single segments\n",
+ mmc_hostname(mmc),
+ bounce_size);
+ /*
+ * Exiting with zero here makes sure we proceed with
+ * mmc->max_segs == 1.
+ */
+ return;
+ }
+
+ host->bounce_addr = dma_map_single(mmc_dev(mmc),
+ host->bounce_buffer,
+ bounce_size,
+ DMA_BIDIRECTIONAL);
+ ret = dma_mapping_error(mmc_dev(mmc), host->bounce_addr);
+ if (ret) {
+ devm_kfree(mmc_dev(mmc), host->bounce_buffer);
+ host->bounce_buffer = NULL;
+ /* Again fall back to max_segs == 1 */
+ return;
+ }
+
+ host->bounce_buffer_size = bounce_size;
+
+ /* Lie about this since we're bouncing */
+ mmc->max_segs = max_blocks;
+ mmc->max_seg_size = bounce_size;
+ mmc->max_req_size = bounce_size;
+
+ pr_info("%s bounce up to %u segments into one, max segment size %u bytes\n",
+ mmc_hostname(mmc), max_blocks, bounce_size);
+}
+
+static inline bool sdhci_can_64bit_dma(struct sdhci_host *host)
+{
+ /*
+ * According to SD Host Controller spec v4.10, bit[27] added from
+ * version 4.10 in Capabilities Register is used as 64-bit System
+ * Address support for V4 mode.
+ */
+ if (host->version >= SDHCI_SPEC_410 && host->v4_mode)
+ return host->caps & SDHCI_CAN_64BIT_V4;
+
+ return host->caps & SDHCI_CAN_64BIT;
+}
+
+int sdhci_setup_host(struct sdhci_host *host)
+{
+ struct mmc_host *mmc;
+ u32 max_current_caps;
+ unsigned int ocr_avail;
+ unsigned int override_timeout_clk;
+ u32 max_clk;
+ int ret = 0;
+ bool enable_vqmmc = false;
+
+ WARN_ON(host == NULL);
+ if (host == NULL)
+ return -EINVAL;
+
+ mmc = host->mmc;
+
+ /*
+ * If there are external regulators, get them. Note this must be done
+ * early before resetting the host and reading the capabilities so that
+ * the host can take the appropriate action if regulators are not
+ * available.
+ */
+ if (!mmc->supply.vqmmc) {
+ ret = mmc_regulator_get_supply(mmc);
+ if (ret)
+ return ret;
+ enable_vqmmc = true;
+ }
+
+ DBG("Version: 0x%08x | Present: 0x%08x\n",
+ sdhci_readw(host, SDHCI_HOST_VERSION),
+ sdhci_readl(host, SDHCI_PRESENT_STATE));
+ DBG("Caps: 0x%08x | Caps_1: 0x%08x\n",
+ sdhci_readl(host, SDHCI_CAPABILITIES),
+ sdhci_readl(host, SDHCI_CAPABILITIES_1));
+
+ sdhci_read_caps(host);
+
+ override_timeout_clk = host->timeout_clk;
+
+ if (host->version > SDHCI_SPEC_420) {
+ pr_err("%s: Unknown controller version (%d). You may experience problems.\n",
+ mmc_hostname(mmc), host->version);
+ }
+
+ if (host->quirks & SDHCI_QUIRK_FORCE_DMA)
+ host->flags |= SDHCI_USE_SDMA;
+ else if (!(host->caps & SDHCI_CAN_DO_SDMA))
+ DBG("Controller doesn't have SDMA capability\n");
+ else
+ host->flags |= SDHCI_USE_SDMA;
+
+ if ((host->quirks & SDHCI_QUIRK_BROKEN_DMA) &&
+ (host->flags & SDHCI_USE_SDMA)) {
+ DBG("Disabling DMA as it is marked broken\n");
+ host->flags &= ~SDHCI_USE_SDMA;
+ }
+
+ if ((host->version >= SDHCI_SPEC_200) &&
+ (host->caps & SDHCI_CAN_DO_ADMA2))
+ host->flags |= SDHCI_USE_ADMA;
+
+ if ((host->quirks & SDHCI_QUIRK_BROKEN_ADMA) &&
+ (host->flags & SDHCI_USE_ADMA)) {
+ DBG("Disabling ADMA as it is marked broken\n");
+ host->flags &= ~SDHCI_USE_ADMA;
+ }
+
+ if (sdhci_can_64bit_dma(host))
+ host->flags |= SDHCI_USE_64_BIT_DMA;
+
+ if (host->use_external_dma) {
+ ret = sdhci_external_dma_init(host);
+ if (ret == -EPROBE_DEFER)
+ goto unreg;
+ /*
+ * Fall back to use the DMA/PIO integrated in standard SDHCI
+ * instead of external DMA devices.
+ */
+ else if (ret)
+ sdhci_switch_external_dma(host, false);
+ /* Disable internal DMA sources */
+ else
+ host->flags &= ~(SDHCI_USE_SDMA | SDHCI_USE_ADMA);
+ }
+
+ if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) {
+ if (host->ops->set_dma_mask)
+ ret = host->ops->set_dma_mask(host);
+ else
+ ret = sdhci_set_dma_mask(host);
+
+ if (!ret && host->ops->enable_dma)
+ ret = host->ops->enable_dma(host);
+
+ if (ret) {
+ pr_warn("%s: No suitable DMA available - falling back to PIO\n",
+ mmc_hostname(mmc));
+ host->flags &= ~(SDHCI_USE_SDMA | SDHCI_USE_ADMA);
+
+ ret = 0;
+ }
+ }
+
+ /* SDMA does not support 64-bit DMA if v4 mode not set */
+ if ((host->flags & SDHCI_USE_64_BIT_DMA) && !host->v4_mode)
+ host->flags &= ~SDHCI_USE_SDMA;
+
+ if (host->flags & SDHCI_USE_ADMA) {
+ dma_addr_t dma;
+ void *buf;
+
+ if (!(host->flags & SDHCI_USE_64_BIT_DMA))
+ host->alloc_desc_sz = SDHCI_ADMA2_32_DESC_SZ;
+ else if (!host->alloc_desc_sz)
+ host->alloc_desc_sz = SDHCI_ADMA2_64_DESC_SZ(host);
+
+ host->desc_sz = host->alloc_desc_sz;
+ host->adma_table_sz = host->adma_table_cnt * host->desc_sz;
+
+ host->align_buffer_sz = SDHCI_MAX_SEGS * SDHCI_ADMA2_ALIGN;
+ /*
+ * Use zalloc to zero the reserved high 32-bits of 128-bit
+ * descriptors so that they never need to be written.
+ */
+ buf = dma_alloc_coherent(mmc_dev(mmc),
+ host->align_buffer_sz + host->adma_table_sz,
+ &dma, GFP_KERNEL);
+ if (!buf) {
+ pr_warn("%s: Unable to allocate ADMA buffers - falling back to standard DMA\n",
+ mmc_hostname(mmc));
+ host->flags &= ~SDHCI_USE_ADMA;
+ } else if ((dma + host->align_buffer_sz) &
+ (SDHCI_ADMA2_DESC_ALIGN - 1)) {
+ pr_warn("%s: unable to allocate aligned ADMA descriptor\n",
+ mmc_hostname(mmc));
+ host->flags &= ~SDHCI_USE_ADMA;
+ dma_free_coherent(mmc_dev(mmc), host->align_buffer_sz +
+ host->adma_table_sz, buf, dma);
+ } else {
+ host->align_buffer = buf;
+ host->align_addr = dma;
+
+ host->adma_table = buf + host->align_buffer_sz;
+ host->adma_addr = dma + host->align_buffer_sz;
+ }
+ }
+
+ /*
+ * If we use DMA, then it's up to the caller to set the DMA
+ * mask, but PIO does not need the hw shim so we set a new
+ * mask here in that case.
+ */
+ if (!(host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA))) {
+ host->dma_mask = DMA_BIT_MASK(64);
+ mmc_dev(mmc)->dma_mask = &host->dma_mask;
+ }
+
+ if (host->version >= SDHCI_SPEC_300)
+ host->max_clk = FIELD_GET(SDHCI_CLOCK_V3_BASE_MASK, host->caps);
+ else
+ host->max_clk = FIELD_GET(SDHCI_CLOCK_BASE_MASK, host->caps);
+
+ host->max_clk *= 1000000;
+ if (host->max_clk == 0 || host->quirks &
+ SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN) {
+ if (!host->ops->get_max_clock) {
+ pr_err("%s: Hardware doesn't specify base clock frequency.\n",
+ mmc_hostname(mmc));
+ ret = -ENODEV;
+ goto undma;
+ }
+ host->max_clk = host->ops->get_max_clock(host);
+ }
+
+ /*
+ * In case of Host Controller v3.00, find out whether clock
+ * multiplier is supported.
+ */
+ host->clk_mul = FIELD_GET(SDHCI_CLOCK_MUL_MASK, host->caps1);
+
+ /*
+ * In case the value in Clock Multiplier is 0, then programmable
+ * clock mode is not supported, otherwise the actual clock
+ * multiplier is one more than the value of Clock Multiplier
+ * in the Capabilities Register.
+ */
+ if (host->clk_mul)
+ host->clk_mul += 1;
+
+ /*
+ * Set host parameters.
+ */
+ max_clk = host->max_clk;
+
+ if (host->ops->get_min_clock)
+ mmc->f_min = host->ops->get_min_clock(host);
+ else if (host->version >= SDHCI_SPEC_300) {
+ if (host->clk_mul)
+ max_clk = host->max_clk * host->clk_mul;
+ /*
+ * Divided Clock Mode minimum clock rate is always less than
+ * Programmable Clock Mode minimum clock rate.
+ */
+ mmc->f_min = host->max_clk / SDHCI_MAX_DIV_SPEC_300;
+ } else
+ mmc->f_min = host->max_clk / SDHCI_MAX_DIV_SPEC_200;
+
+ if (!mmc->f_max || mmc->f_max > max_clk)
+ mmc->f_max = max_clk;
+
+ if (!(host->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK)) {
+ host->timeout_clk = FIELD_GET(SDHCI_TIMEOUT_CLK_MASK, host->caps);
+
+ if (host->caps & SDHCI_TIMEOUT_CLK_UNIT)
+ host->timeout_clk *= 1000;
+
+ if (host->timeout_clk == 0) {
+ if (!host->ops->get_timeout_clock) {
+ pr_err("%s: Hardware doesn't specify timeout clock frequency.\n",
+ mmc_hostname(mmc));
+ ret = -ENODEV;
+ goto undma;
+ }
+
+ host->timeout_clk =
+ DIV_ROUND_UP(host->ops->get_timeout_clock(host),
+ 1000);
+ }
+
+ if (override_timeout_clk)
+ host->timeout_clk = override_timeout_clk;
+
+ mmc->max_busy_timeout = host->ops->get_max_timeout_count ?
+ host->ops->get_max_timeout_count(host) : 1 << 27;
+ mmc->max_busy_timeout /= host->timeout_clk;
+ }
+
+ if (host->quirks2 & SDHCI_QUIRK2_DISABLE_HW_TIMEOUT &&
+ !host->ops->get_max_timeout_count)
+ mmc->max_busy_timeout = 0;
+
+ mmc->caps |= MMC_CAP_SDIO_IRQ | MMC_CAP_CMD23;
+ mmc->caps2 |= MMC_CAP2_SDIO_IRQ_NOTHREAD;
+
+ if (host->quirks & SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12)
+ host->flags |= SDHCI_AUTO_CMD12;
+
+ /*
+ * For v3 mode, Auto-CMD23 stuff only works in ADMA or PIO.
+ * For v4 mode, SDMA may use Auto-CMD23 as well.
+ */
+ if ((host->version >= SDHCI_SPEC_300) &&
+ ((host->flags & SDHCI_USE_ADMA) ||
+ !(host->flags & SDHCI_USE_SDMA) || host->v4_mode) &&
+ !(host->quirks2 & SDHCI_QUIRK2_ACMD23_BROKEN)) {
+ host->flags |= SDHCI_AUTO_CMD23;
+ DBG("Auto-CMD23 available\n");
+ } else {
+ DBG("Auto-CMD23 unavailable\n");
+ }
+
+ /*
+ * A controller may support 8-bit width, but the board itself
+ * might not have the pins brought out. Boards that support
+ * 8-bit width must set "mmc->caps |= MMC_CAP_8_BIT_DATA;" in
+ * their platform code before calling sdhci_add_host(), and we
+ * won't assume 8-bit width for hosts without that CAP.
+ */
+ if (!(host->quirks & SDHCI_QUIRK_FORCE_1_BIT_DATA))
+ mmc->caps |= MMC_CAP_4_BIT_DATA;
+
+ if (host->quirks2 & SDHCI_QUIRK2_HOST_NO_CMD23)
+ mmc->caps &= ~MMC_CAP_CMD23;
+
+ if (host->caps & SDHCI_CAN_DO_HISPD)
+ mmc->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED;
+
+ if ((host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) &&
+ mmc_card_is_removable(mmc) &&
+ mmc_gpio_get_cd(mmc) < 0)
+ mmc->caps |= MMC_CAP_NEEDS_POLL;
+
+ if (!IS_ERR(mmc->supply.vqmmc)) {
+ if (enable_vqmmc) {
+ ret = regulator_enable(mmc->supply.vqmmc);
+ host->sdhci_core_to_disable_vqmmc = !ret;
+ }
+
+ /* If vqmmc provides no 1.8V signalling, then there's no UHS */
+ if (!regulator_is_supported_voltage(mmc->supply.vqmmc, 1700000,
+ 1950000))
+ host->caps1 &= ~(SDHCI_SUPPORT_SDR104 |
+ SDHCI_SUPPORT_SDR50 |
+ SDHCI_SUPPORT_DDR50);
+
+ /* In eMMC case vqmmc might be a fixed 1.8V regulator */
+ if (!regulator_is_supported_voltage(mmc->supply.vqmmc, 2700000,
+ 3600000))
+ host->flags &= ~SDHCI_SIGNALING_330;
+
+ if (ret) {
+ pr_warn("%s: Failed to enable vqmmc regulator: %d\n",
+ mmc_hostname(mmc), ret);
+ mmc->supply.vqmmc = ERR_PTR(-EINVAL);
+ }
+
+ }
+
+ if (host->quirks2 & SDHCI_QUIRK2_NO_1_8_V) {
+ host->caps1 &= ~(SDHCI_SUPPORT_SDR104 | SDHCI_SUPPORT_SDR50 |
+ SDHCI_SUPPORT_DDR50);
+ /*
+ * The SDHCI controller in a SoC might support HS200/HS400
+ * (indicated using mmc-hs200-1_8v/mmc-hs400-1_8v dt property),
+ * but if the board is modeled such that the IO lines are not
+ * connected to 1.8v then HS200/HS400 cannot be supported.
+ * Disable HS200/HS400 if the board does not have 1.8v connected
+ * to the IO lines. (Applicable for other modes in 1.8v)
+ */
+ mmc->caps2 &= ~(MMC_CAP2_HSX00_1_8V | MMC_CAP2_HS400_ES);
+ mmc->caps &= ~(MMC_CAP_1_8V_DDR | MMC_CAP_UHS);
+ }
+
+ /* Any UHS-I mode in caps implies SDR12 and SDR25 support. */
+ if (host->caps1 & (SDHCI_SUPPORT_SDR104 | SDHCI_SUPPORT_SDR50 |
+ SDHCI_SUPPORT_DDR50))
+ mmc->caps |= MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25;
+
+ /* SDR104 supports also implies SDR50 support */
+ if (host->caps1 & SDHCI_SUPPORT_SDR104) {
+ mmc->caps |= MMC_CAP_UHS_SDR104 | MMC_CAP_UHS_SDR50;
+ /* SD3.0: SDR104 is supported so (for eMMC) the caps2
+ * field can be promoted to support HS200.
+ */
+ if (!(host->quirks2 & SDHCI_QUIRK2_BROKEN_HS200))
+ mmc->caps2 |= MMC_CAP2_HS200;
+ } else if (host->caps1 & SDHCI_SUPPORT_SDR50) {
+ mmc->caps |= MMC_CAP_UHS_SDR50;
+ }
+
+ if (host->quirks2 & SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400 &&
+ (host->caps1 & SDHCI_SUPPORT_HS400))
+ mmc->caps2 |= MMC_CAP2_HS400;
+
+ if ((mmc->caps2 & MMC_CAP2_HSX00_1_2V) &&
+ (IS_ERR(mmc->supply.vqmmc) ||
+ !regulator_is_supported_voltage(mmc->supply.vqmmc, 1100000,
+ 1300000)))
+ mmc->caps2 &= ~MMC_CAP2_HSX00_1_2V;
+
+ if ((host->caps1 & SDHCI_SUPPORT_DDR50) &&
+ !(host->quirks2 & SDHCI_QUIRK2_BROKEN_DDR50))
+ mmc->caps |= MMC_CAP_UHS_DDR50;
+
+ /* Does the host need tuning for SDR50? */
+ if (host->caps1 & SDHCI_USE_SDR50_TUNING)
+ host->flags |= SDHCI_SDR50_NEEDS_TUNING;
+
+ /* Driver Type(s) (A, C, D) supported by the host */
+ if (host->caps1 & SDHCI_DRIVER_TYPE_A)
+ mmc->caps |= MMC_CAP_DRIVER_TYPE_A;
+ if (host->caps1 & SDHCI_DRIVER_TYPE_C)
+ mmc->caps |= MMC_CAP_DRIVER_TYPE_C;
+ if (host->caps1 & SDHCI_DRIVER_TYPE_D)
+ mmc->caps |= MMC_CAP_DRIVER_TYPE_D;
+
+ /* Initial value for re-tuning timer count */
+ host->tuning_count = FIELD_GET(SDHCI_RETUNING_TIMER_COUNT_MASK,
+ host->caps1);
+
+ /*
+ * In case Re-tuning Timer is not disabled, the actual value of
+ * re-tuning timer will be 2 ^ (n - 1).
+ */
+ if (host->tuning_count)
+ host->tuning_count = 1 << (host->tuning_count - 1);
+
+ /* Re-tuning mode supported by the Host Controller */
+ host->tuning_mode = FIELD_GET(SDHCI_RETUNING_MODE_MASK, host->caps1);
+
+ ocr_avail = 0;
+
+ /*
+ * According to SD Host Controller spec v3.00, if the Host System
+ * can afford more than 150mA, Host Driver should set XPC to 1. Also
+ * the value is meaningful only if Voltage Support in the Capabilities
+ * register is set. The actual current value is 4 times the register
+ * value.
+ */
+ max_current_caps = sdhci_readl(host, SDHCI_MAX_CURRENT);
+ if (!max_current_caps && !IS_ERR(mmc->supply.vmmc)) {
+ int curr = regulator_get_current_limit(mmc->supply.vmmc);
+ if (curr > 0) {
+
+ /* convert to SDHCI_MAX_CURRENT format */
+ curr = curr/1000; /* convert to mA */
+ curr = curr/SDHCI_MAX_CURRENT_MULTIPLIER;
+
+ curr = min_t(u32, curr, SDHCI_MAX_CURRENT_LIMIT);
+ max_current_caps =
+ FIELD_PREP(SDHCI_MAX_CURRENT_330_MASK, curr) |
+ FIELD_PREP(SDHCI_MAX_CURRENT_300_MASK, curr) |
+ FIELD_PREP(SDHCI_MAX_CURRENT_180_MASK, curr);
+ }
+ }
+
+ if (host->caps & SDHCI_CAN_VDD_330) {
+ ocr_avail |= MMC_VDD_32_33 | MMC_VDD_33_34;
+
+ mmc->max_current_330 = FIELD_GET(SDHCI_MAX_CURRENT_330_MASK,
+ max_current_caps) *
+ SDHCI_MAX_CURRENT_MULTIPLIER;
+ }
+ if (host->caps & SDHCI_CAN_VDD_300) {
+ ocr_avail |= MMC_VDD_29_30 | MMC_VDD_30_31;
+
+ mmc->max_current_300 = FIELD_GET(SDHCI_MAX_CURRENT_300_MASK,
+ max_current_caps) *
+ SDHCI_MAX_CURRENT_MULTIPLIER;
+ }
+ if (host->caps & SDHCI_CAN_VDD_180) {
+ ocr_avail |= MMC_VDD_165_195;
+
+ mmc->max_current_180 = FIELD_GET(SDHCI_MAX_CURRENT_180_MASK,
+ max_current_caps) *
+ SDHCI_MAX_CURRENT_MULTIPLIER;
+ }
+
+ /* If OCR set by host, use it instead. */
+ if (host->ocr_mask)
+ ocr_avail = host->ocr_mask;
+
+ /* If OCR set by external regulators, give it highest prio. */
+ if (mmc->ocr_avail)
+ ocr_avail = mmc->ocr_avail;
+
+ mmc->ocr_avail = ocr_avail;
+ mmc->ocr_avail_sdio = ocr_avail;
+ if (host->ocr_avail_sdio)
+ mmc->ocr_avail_sdio &= host->ocr_avail_sdio;
+ mmc->ocr_avail_sd = ocr_avail;
+ if (host->ocr_avail_sd)
+ mmc->ocr_avail_sd &= host->ocr_avail_sd;
+ else /* normal SD controllers don't support 1.8V */
+ mmc->ocr_avail_sd &= ~MMC_VDD_165_195;
+ mmc->ocr_avail_mmc = ocr_avail;
+ if (host->ocr_avail_mmc)
+ mmc->ocr_avail_mmc &= host->ocr_avail_mmc;
+
+ if (mmc->ocr_avail == 0) {
+ pr_err("%s: Hardware doesn't report any support voltages.\n",
+ mmc_hostname(mmc));
+ ret = -ENODEV;
+ goto unreg;
+ }
+
+ if ((mmc->caps & (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 |
+ MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 |
+ MMC_CAP_UHS_DDR50 | MMC_CAP_1_8V_DDR)) ||
+ (mmc->caps2 & (MMC_CAP2_HS200_1_8V_SDR | MMC_CAP2_HS400_1_8V)))
+ host->flags |= SDHCI_SIGNALING_180;
+
+ if (mmc->caps2 & MMC_CAP2_HSX00_1_2V)
+ host->flags |= SDHCI_SIGNALING_120;
+
+ spin_lock_init(&host->lock);
+
+ /*
+ * Maximum number of sectors in one transfer. Limited by SDMA boundary
+ * size (512KiB). Note some tuning modes impose a 4MiB limit, but this
+ * is less anyway.
+ */
+ mmc->max_req_size = 524288;
+
+ /*
+ * Maximum number of segments. Depends on if the hardware
+ * can do scatter/gather or not.
+ */
+ if (host->flags & SDHCI_USE_ADMA) {
+ mmc->max_segs = SDHCI_MAX_SEGS;
+ } else if (host->flags & SDHCI_USE_SDMA) {
+ mmc->max_segs = 1;
+ mmc->max_req_size = min_t(size_t, mmc->max_req_size,
+ dma_max_mapping_size(mmc_dev(mmc)));
+ } else { /* PIO */
+ mmc->max_segs = SDHCI_MAX_SEGS;
+ }
+
+ /*
+ * Maximum segment size. Could be one segment with the maximum number
+ * of bytes. When doing hardware scatter/gather, each entry cannot
+ * be larger than 64 KiB though.
+ */
+ if (host->flags & SDHCI_USE_ADMA) {
+ if (host->quirks & SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC) {
+ host->max_adma = 65532; /* 32-bit alignment */
+ mmc->max_seg_size = 65535;
+ } else {
+ mmc->max_seg_size = 65536;
+ }
+ } else {
+ mmc->max_seg_size = mmc->max_req_size;
+ }
+
+ /*
+ * Maximum block size. This varies from controller to controller and
+ * is specified in the capabilities register.
+ */
+ if (host->quirks & SDHCI_QUIRK_FORCE_BLK_SZ_2048) {
+ mmc->max_blk_size = 2;
+ } else {
+ mmc->max_blk_size = (host->caps & SDHCI_MAX_BLOCK_MASK) >>
+ SDHCI_MAX_BLOCK_SHIFT;
+ if (mmc->max_blk_size >= 3) {
+ pr_warn("%s: Invalid maximum block size, assuming 512 bytes\n",
+ mmc_hostname(mmc));
+ mmc->max_blk_size = 0;
+ }
+ }
+
+ mmc->max_blk_size = 512 << mmc->max_blk_size;
+
+ /*
+ * Maximum block count.
+ */
+ mmc->max_blk_count = (host->quirks & SDHCI_QUIRK_NO_MULTIBLOCK) ? 1 : 65535;
+
+ if (mmc->max_segs == 1)
+ /* This may alter mmc->*_blk_* parameters */
+ sdhci_allocate_bounce_buffer(host);
+
+ return 0;
+
+unreg:
+ if (host->sdhci_core_to_disable_vqmmc)
+ regulator_disable(mmc->supply.vqmmc);
+undma:
+ if (host->align_buffer)
+ dma_free_coherent(mmc_dev(mmc), host->align_buffer_sz +
+ host->adma_table_sz, host->align_buffer,
+ host->align_addr);
+ host->adma_table = NULL;
+ host->align_buffer = NULL;
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(sdhci_setup_host);
+
+void sdhci_cleanup_host(struct sdhci_host *host)
+{
+ struct mmc_host *mmc = host->mmc;
+
+ if (host->sdhci_core_to_disable_vqmmc)
+ regulator_disable(mmc->supply.vqmmc);
+
+ if (host->align_buffer)
+ dma_free_coherent(mmc_dev(mmc), host->align_buffer_sz +
+ host->adma_table_sz, host->align_buffer,
+ host->align_addr);
+
+ if (host->use_external_dma)
+ sdhci_external_dma_release(host);
+
+ host->adma_table = NULL;
+ host->align_buffer = NULL;
+}
+EXPORT_SYMBOL_GPL(sdhci_cleanup_host);
+
+int __sdhci_add_host(struct sdhci_host *host)
+{
+ unsigned int flags = WQ_UNBOUND | WQ_MEM_RECLAIM | WQ_HIGHPRI;
+ struct mmc_host *mmc = host->mmc;
+ int ret;
+
+ if ((mmc->caps2 & MMC_CAP2_CQE) &&
+ (host->quirks & SDHCI_QUIRK_BROKEN_CQE)) {
+ mmc->caps2 &= ~MMC_CAP2_CQE;
+ mmc->cqe_ops = NULL;
+ }
+
+ host->complete_wq = alloc_workqueue("sdhci", flags, 0);
+ if (!host->complete_wq)
+ return -ENOMEM;
+
+ INIT_WORK(&host->complete_work, sdhci_complete_work);
+
+ timer_setup(&host->timer, sdhci_timeout_timer, 0);
+ timer_setup(&host->data_timer, sdhci_timeout_data_timer, 0);
+
+ init_waitqueue_head(&host->buf_ready_int);
+
+ sdhci_init(host, 0);
+
+ ret = request_threaded_irq(host->irq, sdhci_irq, sdhci_thread_irq,
+ IRQF_SHARED, mmc_hostname(mmc), host);
+ if (ret) {
+ pr_err("%s: Failed to request IRQ %d: %d\n",
+ mmc_hostname(mmc), host->irq, ret);
+ goto unwq;
+ }
+
+ ret = sdhci_led_register(host);
+ if (ret) {
+ pr_err("%s: Failed to register LED device: %d\n",
+ mmc_hostname(mmc), ret);
+ goto unirq;
+ }
+
+ ret = mmc_add_host(mmc);
+ if (ret)
+ goto unled;
+
+ pr_info("%s: SDHCI controller on %s [%s] using %s\n",
+ mmc_hostname(mmc), host->hw_name, dev_name(mmc_dev(mmc)),
+ host->use_external_dma ? "External DMA" :
+ (host->flags & SDHCI_USE_ADMA) ?
+ (host->flags & SDHCI_USE_64_BIT_DMA) ? "ADMA 64-bit" : "ADMA" :
+ (host->flags & SDHCI_USE_SDMA) ? "DMA" : "PIO");
+
+ sdhci_enable_card_detection(host);
+
+ return 0;
+
+unled:
+ sdhci_led_unregister(host);
+unirq:
+ sdhci_reset_for_all(host);
+ sdhci_writel(host, 0, SDHCI_INT_ENABLE);
+ sdhci_writel(host, 0, SDHCI_SIGNAL_ENABLE);
+ free_irq(host->irq, host);
+unwq:
+ destroy_workqueue(host->complete_wq);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(__sdhci_add_host);
+
+int sdhci_add_host(struct sdhci_host *host)
+{
+ int ret;
+
+ ret = sdhci_setup_host(host);
+ if (ret)
+ return ret;
+
+ ret = __sdhci_add_host(host);
+ if (ret)
+ goto cleanup;
+
+ return 0;
+
+cleanup:
+ sdhci_cleanup_host(host);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(sdhci_add_host);
+
+void sdhci_remove_host(struct sdhci_host *host, int dead)
+{
+ struct mmc_host *mmc = host->mmc;
+ unsigned long flags;
+
+ if (dead) {
+ spin_lock_irqsave(&host->lock, flags);
+
+ host->flags |= SDHCI_DEVICE_DEAD;
+
+ if (sdhci_has_requests(host)) {
+ pr_err("%s: Controller removed during "
+ " transfer!\n", mmc_hostname(mmc));
+ sdhci_error_out_mrqs(host, -ENOMEDIUM);
+ }
+
+ spin_unlock_irqrestore(&host->lock, flags);
+ }
+
+ sdhci_disable_card_detection(host);
+
+ mmc_remove_host(mmc);
+
+ sdhci_led_unregister(host);
+
+ if (!dead)
+ sdhci_reset_for_all(host);
+
+ sdhci_writel(host, 0, SDHCI_INT_ENABLE);
+ sdhci_writel(host, 0, SDHCI_SIGNAL_ENABLE);
+ free_irq(host->irq, host);
+
+ del_timer_sync(&host->timer);
+ del_timer_sync(&host->data_timer);
+
+ destroy_workqueue(host->complete_wq);
+
+ if (host->sdhci_core_to_disable_vqmmc)
+ regulator_disable(mmc->supply.vqmmc);
+
+ if (host->align_buffer)
+ dma_free_coherent(mmc_dev(mmc), host->align_buffer_sz +
+ host->adma_table_sz, host->align_buffer,
+ host->align_addr);
+
+ if (host->use_external_dma)
+ sdhci_external_dma_release(host);
+
+ host->adma_table = NULL;
+ host->align_buffer = NULL;
+}
+
+EXPORT_SYMBOL_GPL(sdhci_remove_host);
+
+void sdhci_free_host(struct sdhci_host *host)
+{
+ mmc_free_host(host->mmc);
+}
+
+EXPORT_SYMBOL_GPL(sdhci_free_host);
+
+/*****************************************************************************\
+ * *
+ * Driver init/exit *
+ * *
+\*****************************************************************************/
+
+static int __init sdhci_drv_init(void)
+{
+ pr_info(DRIVER_NAME
+ ": Secure Digital Host Controller Interface driver\n");
+ pr_info(DRIVER_NAME ": Copyright(c) Pierre Ossman\n");
+
+ return 0;
+}
+
+static void __exit sdhci_drv_exit(void)
+{
+}
+
+module_init(sdhci_drv_init);
+module_exit(sdhci_drv_exit);
+
+module_param(debug_quirks, uint, 0444);
+module_param(debug_quirks2, uint, 0444);
+
+MODULE_AUTHOR("Pierre Ossman <pierre@ossman.eu>");
+MODULE_DESCRIPTION("Secure Digital Host Controller Interface core driver");
+MODULE_LICENSE("GPL");
+
+MODULE_PARM_DESC(debug_quirks, "Force certain quirks.");
+MODULE_PARM_DESC(debug_quirks2, "Force certain other quirks.");