kernel: remove linux 4.3 support

Signed-off-by: Felix Fietkau <nbd@openwrt.org>

SVN-Revision: 48955
master
Felix Fietkau 9 years ago
parent 3abf5ce656
commit 46c7d0d1ab
  1. 2
      package/kernel/linux/modules/crypto.mk
  2. 2
      package/kernel/linux/modules/netsupport.mk
  3. 25
      target/linux/generic/patches-4.3/000-keep_initrafs_the_default.patch
  4. 44
      target/linux/generic/patches-4.3/020-bcma-from-4.4.patch
  5. 686
      target/linux/generic/patches-4.3/020-ssb-backport.patch
  6. 49
      target/linux/generic/patches-4.3/021-bcma-from-4.5.patch
  7. 444
      target/linux/generic/patches-4.3/022-bcma-from-4.6.patch
  8. 505
      target/linux/generic/patches-4.3/050-backport_netfilter_rtcache.patch
  9. 22
      target/linux/generic/patches-4.3/060-mips_decompressor_memmove.patch
  10. 24
      target/linux/generic/patches-4.3/072-13-bgmac-fix-MAC-soft-reset-bit-for-corerev-4.patch
  11. 28
      target/linux/generic/patches-4.3/072-14-bgmac-reset-all-4-GMAC-cores-on-init.patch
  12. 808
      target/linux/generic/patches-4.3/090-m25p80_spi-nor_update_to_4.4rc1.patch
  13. 101
      target/linux/generic/patches-4.3/101-MIPS-fix-cache-flushing-for-highmem-pages.patch
  14. 82
      target/linux/generic/patches-4.3/102-ehci_hcd_ignore_oc.patch
  15. 17
      target/linux/generic/patches-4.3/103-packet_allow_empty_payload.patch
  16. 86
      target/linux/generic/patches-4.3/110-jffs2-use-.rename2-and-add-RENAME_WHITEOUT-support.patch
  17. 58
      target/linux/generic/patches-4.3/111-jffs2-add-RENAME_EXCHANGE-support.patch
  18. 54
      target/linux/generic/patches-4.3/120-bridge_allow_receiption_on_disabled_port.patch
  19. 778
      target/linux/generic/patches-4.3/132-mips_inline_dma_ops.patch
  20. 183
      target/linux/generic/patches-4.3/140-mtd-part-add-generic-parsing-of-linux-part-probe.patch
  21. 35
      target/linux/generic/patches-4.3/141-Revert-mtd-spi-nor-disable-protection-for-Winbond-fl.patch
  22. 38
      target/linux/generic/patches-4.3/142-mtd-spi-nor-include-mtd.h-header-for-struct-mtd_info.patch
  23. 33
      target/linux/generic/patches-4.3/143-mtd-bcm47xxpart-limit-scanned-flash-area-on-BCM47XX-.patch
  24. 92
      target/linux/generic/patches-4.3/144-mtd-bcm47xxpart-don-t-fail-because-of-bit-flips.patch
  25. 96
      target/linux/generic/patches-4.3/193-USB-qmi_wwan-Add-quirk-for-Quectel-EC20-Mini-PCIe-mo.patch
  26. 11
      target/linux/generic/patches-4.3/200-fix_localversion.patch
  27. 14
      target/linux/generic/patches-4.3/201-extra_optimization.patch
  28. 11
      target/linux/generic/patches-4.3/202-reduce_module_size.patch
  29. 108
      target/linux/generic/patches-4.3/203-kallsyms_uncompressed.patch
  30. 194
      target/linux/generic/patches-4.3/204-module_strip.patch
  31. 36
      target/linux/generic/patches-4.3/205-backtrace_module_info.patch
  32. 3088
      target/linux/generic/patches-4.3/210-darwin_scripts_include.patch
  33. 51
      target/linux/generic/patches-4.3/212-byteshift_portability.patch
  34. 11
      target/linux/generic/patches-4.3/214-spidev_h_portability.patch
  35. 536
      target/linux/generic/patches-4.3/220-gc_sections.patch
  36. 88
      target/linux/generic/patches-4.3/221-module_exports.patch
  37. 58
      target/linux/generic/patches-4.3/230-openwrt_lzma_options.patch
  38. 18
      target/linux/generic/patches-4.3/250-netfilter_depends.patch
  39. 18
      target/linux/generic/patches-4.3/251-sound_kconfig.patch
  40. 10
      target/linux/generic/patches-4.3/252-mv_cesa_depends.patch
  41. 29
      target/linux/generic/patches-4.3/253-ssb_b43_default_on.patch
  42. 23
      target/linux/generic/patches-4.3/254-textsearch_kconfig_hacks.patch
  43. 31
      target/linux/generic/patches-4.3/255-lib80211_kconfig_hacks.patch
  44. 47
      target/linux/generic/patches-4.3/256-crypto_add_kconfig_prompts.patch
  45. 22
      target/linux/generic/patches-4.3/257-wireless_ext_kconfig_hack.patch
  46. 11
      target/linux/generic/patches-4.3/258-netfilter_netlink_kconfig_hack.patch
  47. 87
      target/linux/generic/patches-4.3/259-regmap_dynamic.patch
  48. 38
      target/linux/generic/patches-4.3/260-crypto_test_dependencies.patch
  49. 36
      target/linux/generic/patches-4.3/262-compressor_kconfig_hack.patch
  50. 34
      target/linux/generic/patches-4.3/270-uapi-kernel.h-glibc-specific-inclusion-of-sysinfo.h.patch
  51. 81
      target/linux/generic/patches-4.3/271-uapi-libc-compat.h-do-not-rely-on-__GLIBC__.patch
  52. 67
      target/linux/generic/patches-4.3/272-uapi-if_ether.h-prevent-redefinition-of-struct-ethhd.patch
  53. 39
      target/linux/generic/patches-4.3/300-mips_expose_boot_raw.patch
  54. 28
      target/linux/generic/patches-4.3/301-mips_image_cmdline_hack.patch
  55. 11
      target/linux/generic/patches-4.3/302-mips_no_branch_likely.patch
  56. 106
      target/linux/generic/patches-4.3/304-mips_disable_fpu.patch
  57. 352
      target/linux/generic/patches-4.3/305-mips_module_reloc.patch
  58. 83
      target/linux/generic/patches-4.3/306-mips_mem_functions_performance.patch
  59. 17
      target/linux/generic/patches-4.3/307-mips_highmem_offset.patch
  60. 32
      target/linux/generic/patches-4.3/309-mips_fuse_workaround.patch
  61. 13
      target/linux/generic/patches-4.3/310-arm_module_unresolved_weak_sym.patch
  62. 31
      target/linux/generic/patches-4.3/320-ppc4xx_optimization.patch
  63. 10
      target/linux/generic/patches-4.3/321-powerpc_crtsavres_prereq.patch
  64. 298
      target/linux/generic/patches-4.3/330-MIPS-kexec-Accept-command-line-parameters-from-users.patch
  65. 146
      target/linux/generic/patches-4.3/400-mtd-add-rootfs-split-support.patch
  66. 113
      target/linux/generic/patches-4.3/401-mtd-add-support-for-different-partition-parser-types.patch
  67. 72
      target/linux/generic/patches-4.3/402-mtd-use-typed-mtd-parsers-for-rootfs-and-firmware-split.patch
  68. 22
      target/linux/generic/patches-4.3/403-mtd-hook-mtdsplit-to-Kbuild.patch
  69. 101
      target/linux/generic/patches-4.3/404-mtd-add-more-helper-functions.patch
  70. 70
      target/linux/generic/patches-4.3/405-mtd-old-firmware-uimage-splitter.patch
  71. 18
      target/linux/generic/patches-4.3/410-mtd-move-forward-declaration-of-struct-mtd_info.patch
  72. 142
      target/linux/generic/patches-4.3/411-mtd-partial_eraseblock_write.patch
  73. 18
      target/linux/generic/patches-4.3/412-mtd-partial_eraseblock_unlock.patch
  74. 30
      target/linux/generic/patches-4.3/420-mtd-redboot_space.patch
  75. 35
      target/linux/generic/patches-4.3/430-mtd-add-myloader-partition-parser.patch
  76. 34
      target/linux/generic/patches-4.3/431-mtd-bcm47xxpart-support-for-Xiaomi-specific-board_da.patch
  77. 42
      target/linux/generic/patches-4.3/432-mtd-bcm47xxpart-detect-T_Meter-partition.patch
  78. 108
      target/linux/generic/patches-4.3/440-block2mtd_init.patch
  79. 39
      target/linux/generic/patches-4.3/441-block2mtd_probe.patch
  80. 37
      target/linux/generic/patches-4.3/450-mtd-nand-allow-to-use-platform-specific-chip-fixup.patch
  81. 11
      target/linux/generic/patches-4.3/451-mtd-nand-fix-return-code-of-nand_correct_data-function.patch
  82. 11
      target/linux/generic/patches-4.3/460-mtd-cfi_cmdset_0002-no-erase_suspend.patch
  83. 18
      target/linux/generic/patches-4.3/461-mtd-cfi_cmdset_0002-add-buffer-write-cmd-timeout.patch
  84. 14
      target/linux/generic/patches-4.3/465-m25p80-mx-disable-software-protection.patch
  85. 26
      target/linux/generic/patches-4.3/480-mtd-set-rootfs-to-be-root-dev.patch
  86. 76
      target/linux/generic/patches-4.3/490-ubi-auto-attach-mtd-device-named-ubi-or-data-on-boot.patch
  87. 69
      target/linux/generic/patches-4.3/491-ubi-auto-create-ubiblock-device-for-rootfs.patch
  88. 53
      target/linux/generic/patches-4.3/492-try-auto-mounting-ubi0-rootfs-in-init-do_mounts.c.patch
  89. 37
      target/linux/generic/patches-4.3/493-ubi-set-ROOT_DEV-to-ubiblock-rootfs-if-unset.patch
  90. 51
      target/linux/generic/patches-4.3/494-mtd-ubi-add-EOF-marker-support.patch
  91. 18
      target/linux/generic/patches-4.3/500-yaffs-Kbuild-integration.patch
  92. 239
      target/linux/generic/patches-4.3/502-yaffs-fix-compat-tags-handling.patch
  93. 115
      target/linux/generic/patches-4.3/503-yaffs-add-tags-9bytes-mount-option.patch
  94. 29
      target/linux/generic/patches-4.3/504-yaffs-3.16-new-fops.patch
  95. 95
      target/linux/generic/patches-4.3/505-yaffs-3.19-f_dentry-remove.patch
  96. 25
      target/linux/generic/patches-4.3/520-squashfs_update_xz_comp_opts.patch
  97. 5142
      target/linux/generic/patches-4.3/530-jffs2_make_lzma_available.patch
  98. 1024
      target/linux/generic/patches-4.3/531-debloat_lzma.patch
  99. 56
      target/linux/generic/patches-4.3/532-jffs2_eofdetect.patch
  100. 146
      target/linux/generic/patches-4.3/540-crypto-xz-decompression-support.patch
  101. Some files were not shown because too many files have changed in this diff Show More

@ -27,7 +27,7 @@ define KernelPackage/crypto-aead
CONFIG_CRYPTO_AEAD2
FILES:=$(LINUX_DIR)/crypto/aead.ko
AUTOLOAD:=$(call AutoLoad,09,aead,1)
$(call AddDepends/crypto, +LINUX_4_3:kmod-crypto-null +LINUX_4_4:kmod-crypto-null)
$(call AddDepends/crypto, +LINUX_4_4:kmod-crypto-null)
endef
$(eval $(call KernelPackage,crypto-aead))

@ -1005,7 +1005,7 @@ $(eval $(call KernelPackage,rxrpc))
define KernelPackage/mpls
SUBMENU:=$(NETWORK_SUPPORT_MENU)
TITLE:=MPLS support
DEPENDS:=@!(LINUX_3_18||LINUX_4_1||LINUX_4_3)
DEPENDS:=@!(LINUX_3_18||LINUX_4_1)
KCONFIG:= \
CONFIG_MPLS=y \
CONFIG_LWTUNNEL=y \

@ -1,25 +0,0 @@
Upstream changed the default rootfs to tmpfs when none has been passed
to the kernel - this doesn't fit our purposes, so change it back.
Signed-off-by: Imre Kaloz <kaloz@openwrt.org>
--- a/init/do_mounts.c
+++ b/init/do_mounts.c
@@ -633,6 +633,7 @@ int __init init_rootfs(void)
if (err)
return err;
+#if 0
if (IS_ENABLED(CONFIG_TMPFS) && !saved_root_name[0] &&
(!root_fs_names || strstr(root_fs_names, "tmpfs"))) {
err = shmem_init();
@@ -640,6 +641,9 @@ int __init init_rootfs(void)
} else {
err = init_ramfs_fs();
}
+#else
+ err = init_ramfs_fs();
+#endif
if (err)
unregister_filesystem(&rootfs_fs_type);

@ -1,44 +0,0 @@
commit 55acca90da52b85299c033354e51ddaa7b73e019
Author: Hante Meuleman <meuleman@broadcom.com>
Date: Fri Sep 18 22:08:17 2015 +0200
brcmfmac: Add support for the BCM4365 and BCM4366 PCIE devices.
This patch adds support for the BCM4365 and BCM4366 11ac Wave2
PCIE devices.
Reviewed-by: Arend Van Spriel <arend@broadcom.com>
Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
Signed-off-by: Hante Meuleman <meuleman@broadcom.com>
Signed-off-by: Arend van Spriel <arend@broadcom.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
--- a/include/linux/bcma/bcma.h
+++ b/include/linux/bcma/bcma.h
@@ -151,6 +151,8 @@ struct bcma_host_ops {
#define BCMA_CORE_PCIE2 0x83C /* PCI Express Gen2 */
#define BCMA_CORE_USB30_DEV 0x83D
#define BCMA_CORE_ARM_CR4 0x83E
+#define BCMA_CORE_ARM_CA7 0x847
+#define BCMA_CORE_SYS_MEM 0x849
#define BCMA_CORE_DEFAULT 0xFFF
#define BCMA_MAX_NR_CORES 16
--- a/drivers/bcma/main.c
+++ b/drivers/bcma/main.c
@@ -436,13 +436,8 @@ int bcma_bus_register(struct bcma_bus *b
}
dev = bcma_bus_get_host_dev(bus);
- /* TODO: remove check for IS_BUILTIN(CONFIG_BCMA) check when
- * of_default_bus_match_table is exported or in some other way
- * accessible. This is just a temporary workaround.
- */
- if (IS_BUILTIN(CONFIG_BCMA) && dev) {
- of_platform_populate(dev->of_node, of_default_bus_match_table,
- NULL, dev);
+ if (dev) {
+ of_platform_default_populate(dev->of_node, NULL, dev);
}
/* Cores providing flash access go before SPROM init */

@ -1,686 +0,0 @@
--- a/arch/mips/bcm47xx/Kconfig
+++ b/arch/mips/bcm47xx/Kconfig
@@ -4,6 +4,7 @@ config BCM47XX_SSB
bool "SSB Support for Broadcom BCM47XX"
select SYS_HAS_CPU_BMIPS32_3300
select SSB
+ select SSB_HOST_SOC
select SSB_DRIVER_MIPS
select SSB_DRIVER_EXTIF
select SSB_EMBEDDED
--- a/drivers/ssb/Kconfig
+++ b/drivers/ssb/Kconfig
@@ -80,6 +80,15 @@ config SSB_SDIOHOST
If unsure, say N
+config SSB_HOST_SOC
+ bool "Support for SSB bus on SoC"
+ depends on SSB
+ help
+ Host interface for a SSB directly mapped into memory. This is
+ for some Broadcom SoCs from the BCM47xx and BCM53xx lines.
+
+ If unsure, say N
+
config SSB_SILENT
bool "No SSB kernel messages"
depends on SSB && EXPERT
--- a/drivers/ssb/Makefile
+++ b/drivers/ssb/Makefile
@@ -5,8 +5,9 @@ ssb-$(CONFIG_SSB_SPROM) += sprom.o
# host support
ssb-$(CONFIG_SSB_PCIHOST) += pci.o pcihost_wrapper.o
-ssb-$(CONFIG_SSB_PCMCIAHOST) += pcmcia.o
+ssb-$(CONFIG_SSB_PCMCIAHOST) += pcmcia.o bridge_pcmcia_80211.o
ssb-$(CONFIG_SSB_SDIOHOST) += sdio.o
+ssb-$(CONFIG_SSB_HOST_SOC) += host_soc.o
# built-in drivers
ssb-y += driver_chipcommon.o
--- /dev/null
+++ b/drivers/ssb/bridge_pcmcia_80211.c
@@ -0,0 +1,128 @@
+/*
+ * Broadcom 43xx PCMCIA-SSB bridge module
+ *
+ * Copyright (c) 2007 Michael Buesch <m@bues.ch>
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+#include <linux/ssb/ssb.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ciscode.h>
+#include <pcmcia/ds.h>
+#include <pcmcia/cisreg.h>
+
+#include "ssb_private.h"
+
+static const struct pcmcia_device_id ssb_host_pcmcia_tbl[] = {
+ PCMCIA_DEVICE_MANF_CARD(0x2D0, 0x448),
+ PCMCIA_DEVICE_MANF_CARD(0x2D0, 0x476),
+ PCMCIA_DEVICE_NULL,
+};
+
+MODULE_DEVICE_TABLE(pcmcia, ssb_host_pcmcia_tbl);
+
+static int ssb_host_pcmcia_probe(struct pcmcia_device *dev)
+{
+ struct ssb_bus *ssb;
+ int err = -ENOMEM;
+ int res = 0;
+
+ ssb = kzalloc(sizeof(*ssb), GFP_KERNEL);
+ if (!ssb)
+ goto out_error;
+
+ err = -ENODEV;
+
+ dev->config_flags |= CONF_ENABLE_IRQ;
+
+ dev->resource[2]->flags |= WIN_ENABLE | WIN_DATA_WIDTH_16 |
+ WIN_USE_WAIT;
+ dev->resource[2]->start = 0;
+ dev->resource[2]->end = SSB_CORE_SIZE;
+ res = pcmcia_request_window(dev, dev->resource[2], 250);
+ if (res != 0)
+ goto err_kfree_ssb;
+
+ res = pcmcia_map_mem_page(dev, dev->resource[2], 0);
+ if (res != 0)
+ goto err_disable;
+
+ if (!dev->irq)
+ goto err_disable;
+
+ res = pcmcia_enable_device(dev);
+ if (res != 0)
+ goto err_disable;
+
+ err = ssb_bus_pcmciabus_register(ssb, dev, dev->resource[2]->start);
+ if (err)
+ goto err_disable;
+ dev->priv = ssb;
+
+ return 0;
+
+err_disable:
+ pcmcia_disable_device(dev);
+err_kfree_ssb:
+ kfree(ssb);
+out_error:
+ ssb_err("Initialization failed (%d, %d)\n", res, err);
+ return err;
+}
+
+static void ssb_host_pcmcia_remove(struct pcmcia_device *dev)
+{
+ struct ssb_bus *ssb = dev->priv;
+
+ ssb_bus_unregister(ssb);
+ pcmcia_disable_device(dev);
+ kfree(ssb);
+ dev->priv = NULL;
+}
+
+#ifdef CONFIG_PM
+static int ssb_host_pcmcia_suspend(struct pcmcia_device *dev)
+{
+ struct ssb_bus *ssb = dev->priv;
+
+ return ssb_bus_suspend(ssb);
+}
+
+static int ssb_host_pcmcia_resume(struct pcmcia_device *dev)
+{
+ struct ssb_bus *ssb = dev->priv;
+
+ return ssb_bus_resume(ssb);
+}
+#else /* CONFIG_PM */
+# define ssb_host_pcmcia_suspend NULL
+# define ssb_host_pcmcia_resume NULL
+#endif /* CONFIG_PM */
+
+static struct pcmcia_driver ssb_host_pcmcia_driver = {
+ .owner = THIS_MODULE,
+ .name = "ssb-pcmcia",
+ .id_table = ssb_host_pcmcia_tbl,
+ .probe = ssb_host_pcmcia_probe,
+ .remove = ssb_host_pcmcia_remove,
+ .suspend = ssb_host_pcmcia_suspend,
+ .resume = ssb_host_pcmcia_resume,
+};
+
+/*
+ * These are not module init/exit functions!
+ * The module_pcmcia_driver() helper cannot be used here.
+ */
+int ssb_host_pcmcia_init(void)
+{
+ return pcmcia_register_driver(&ssb_host_pcmcia_driver);
+}
+
+void ssb_host_pcmcia_exit(void)
+{
+ pcmcia_unregister_driver(&ssb_host_pcmcia_driver);
+}
--- /dev/null
+++ b/drivers/ssb/host_soc.c
@@ -0,0 +1,173 @@
+/*
+ * Sonics Silicon Backplane SoC host related functions.
+ * Subsystem core
+ *
+ * Copyright 2005, Broadcom Corporation
+ * Copyright 2006, 2007, Michael Buesch <m@bues.ch>
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+#include <linux/ssb/ssb.h>
+
+#include "ssb_private.h"
+
+static u8 ssb_host_soc_read8(struct ssb_device *dev, u16 offset)
+{
+ struct ssb_bus *bus = dev->bus;
+
+ offset += dev->core_index * SSB_CORE_SIZE;
+ return readb(bus->mmio + offset);
+}
+
+static u16 ssb_host_soc_read16(struct ssb_device *dev, u16 offset)
+{
+ struct ssb_bus *bus = dev->bus;
+
+ offset += dev->core_index * SSB_CORE_SIZE;
+ return readw(bus->mmio + offset);
+}
+
+static u32 ssb_host_soc_read32(struct ssb_device *dev, u16 offset)
+{
+ struct ssb_bus *bus = dev->bus;
+
+ offset += dev->core_index * SSB_CORE_SIZE;
+ return readl(bus->mmio + offset);
+}
+
+#ifdef CONFIG_SSB_BLOCKIO
+static void ssb_host_soc_block_read(struct ssb_device *dev, void *buffer,
+ size_t count, u16 offset, u8 reg_width)
+{
+ struct ssb_bus *bus = dev->bus;
+ void __iomem *addr;
+
+ offset += dev->core_index * SSB_CORE_SIZE;
+ addr = bus->mmio + offset;
+
+ switch (reg_width) {
+ case sizeof(u8): {
+ u8 *buf = buffer;
+
+ while (count) {
+ *buf = __raw_readb(addr);
+ buf++;
+ count--;
+ }
+ break;
+ }
+ case sizeof(u16): {
+ __le16 *buf = buffer;
+
+ SSB_WARN_ON(count & 1);
+ while (count) {
+ *buf = (__force __le16)__raw_readw(addr);
+ buf++;
+ count -= 2;
+ }
+ break;
+ }
+ case sizeof(u32): {
+ __le32 *buf = buffer;
+
+ SSB_WARN_ON(count & 3);
+ while (count) {
+ *buf = (__force __le32)__raw_readl(addr);
+ buf++;
+ count -= 4;
+ }
+ break;
+ }
+ default:
+ SSB_WARN_ON(1);
+ }
+}
+#endif /* CONFIG_SSB_BLOCKIO */
+
+static void ssb_host_soc_write8(struct ssb_device *dev, u16 offset, u8 value)
+{
+ struct ssb_bus *bus = dev->bus;
+
+ offset += dev->core_index * SSB_CORE_SIZE;
+ writeb(value, bus->mmio + offset);
+}
+
+static void ssb_host_soc_write16(struct ssb_device *dev, u16 offset, u16 value)
+{
+ struct ssb_bus *bus = dev->bus;
+
+ offset += dev->core_index * SSB_CORE_SIZE;
+ writew(value, bus->mmio + offset);
+}
+
+static void ssb_host_soc_write32(struct ssb_device *dev, u16 offset, u32 value)
+{
+ struct ssb_bus *bus = dev->bus;
+
+ offset += dev->core_index * SSB_CORE_SIZE;
+ writel(value, bus->mmio + offset);
+}
+
+#ifdef CONFIG_SSB_BLOCKIO
+static void ssb_host_soc_block_write(struct ssb_device *dev, const void *buffer,
+ size_t count, u16 offset, u8 reg_width)
+{
+ struct ssb_bus *bus = dev->bus;
+ void __iomem *addr;
+
+ offset += dev->core_index * SSB_CORE_SIZE;
+ addr = bus->mmio + offset;
+
+ switch (reg_width) {
+ case sizeof(u8): {
+ const u8 *buf = buffer;
+
+ while (count) {
+ __raw_writeb(*buf, addr);
+ buf++;
+ count--;
+ }
+ break;
+ }
+ case sizeof(u16): {
+ const __le16 *buf = buffer;
+
+ SSB_WARN_ON(count & 1);
+ while (count) {
+ __raw_writew((__force u16)(*buf), addr);
+ buf++;
+ count -= 2;
+ }
+ break;
+ }
+ case sizeof(u32): {
+ const __le32 *buf = buffer;
+
+ SSB_WARN_ON(count & 3);
+ while (count) {
+ __raw_writel((__force u32)(*buf), addr);
+ buf++;
+ count -= 4;
+ }
+ break;
+ }
+ default:
+ SSB_WARN_ON(1);
+ }
+}
+#endif /* CONFIG_SSB_BLOCKIO */
+
+/* Ops for the plain SSB bus without a host-device (no PCI or PCMCIA). */
+const struct ssb_bus_ops ssb_host_soc_ops = {
+ .read8 = ssb_host_soc_read8,
+ .read16 = ssb_host_soc_read16,
+ .read32 = ssb_host_soc_read32,
+ .write8 = ssb_host_soc_write8,
+ .write16 = ssb_host_soc_write16,
+ .write32 = ssb_host_soc_write32,
+#ifdef CONFIG_SSB_BLOCKIO
+ .block_read = ssb_host_soc_block_read,
+ .block_write = ssb_host_soc_block_write,
+#endif
+};
--- a/drivers/ssb/main.c
+++ b/drivers/ssb/main.c
@@ -596,166 +596,6 @@ error:
return err;
}
-static u8 ssb_ssb_read8(struct ssb_device *dev, u16 offset)
-{
- struct ssb_bus *bus = dev->bus;
-
- offset += dev->core_index * SSB_CORE_SIZE;
- return readb(bus->mmio + offset);
-}
-
-static u16 ssb_ssb_read16(struct ssb_device *dev, u16 offset)
-{
- struct ssb_bus *bus = dev->bus;
-
- offset += dev->core_index * SSB_CORE_SIZE;
- return readw(bus->mmio + offset);
-}
-
-static u32 ssb_ssb_read32(struct ssb_device *dev, u16 offset)
-{
- struct ssb_bus *bus = dev->bus;
-
- offset += dev->core_index * SSB_CORE_SIZE;
- return readl(bus->mmio + offset);
-}
-
-#ifdef CONFIG_SSB_BLOCKIO
-static void ssb_ssb_block_read(struct ssb_device *dev, void *buffer,
- size_t count, u16 offset, u8 reg_width)
-{
- struct ssb_bus *bus = dev->bus;
- void __iomem *addr;
-
- offset += dev->core_index * SSB_CORE_SIZE;
- addr = bus->mmio + offset;
-
- switch (reg_width) {
- case sizeof(u8): {
- u8 *buf = buffer;
-
- while (count) {
- *buf = __raw_readb(addr);
- buf++;
- count--;
- }
- break;
- }
- case sizeof(u16): {
- __le16 *buf = buffer;
-
- SSB_WARN_ON(count & 1);
- while (count) {
- *buf = (__force __le16)__raw_readw(addr);
- buf++;
- count -= 2;
- }
- break;
- }
- case sizeof(u32): {
- __le32 *buf = buffer;
-
- SSB_WARN_ON(count & 3);
- while (count) {
- *buf = (__force __le32)__raw_readl(addr);
- buf++;
- count -= 4;
- }
- break;
- }
- default:
- SSB_WARN_ON(1);
- }
-}
-#endif /* CONFIG_SSB_BLOCKIO */
-
-static void ssb_ssb_write8(struct ssb_device *dev, u16 offset, u8 value)
-{
- struct ssb_bus *bus = dev->bus;
-
- offset += dev->core_index * SSB_CORE_SIZE;
- writeb(value, bus->mmio + offset);
-}
-
-static void ssb_ssb_write16(struct ssb_device *dev, u16 offset, u16 value)
-{
- struct ssb_bus *bus = dev->bus;
-
- offset += dev->core_index * SSB_CORE_SIZE;
- writew(value, bus->mmio + offset);
-}
-
-static void ssb_ssb_write32(struct ssb_device *dev, u16 offset, u32 value)
-{
- struct ssb_bus *bus = dev->bus;
-
- offset += dev->core_index * SSB_CORE_SIZE;
- writel(value, bus->mmio + offset);
-}
-
-#ifdef CONFIG_SSB_BLOCKIO
-static void ssb_ssb_block_write(struct ssb_device *dev, const void *buffer,
- size_t count, u16 offset, u8 reg_width)
-{
- struct ssb_bus *bus = dev->bus;
- void __iomem *addr;
-
- offset += dev->core_index * SSB_CORE_SIZE;
- addr = bus->mmio + offset;
-
- switch (reg_width) {
- case sizeof(u8): {
- const u8 *buf = buffer;
-
- while (count) {
- __raw_writeb(*buf, addr);
- buf++;
- count--;
- }
- break;
- }
- case sizeof(u16): {
- const __le16 *buf = buffer;
-
- SSB_WARN_ON(count & 1);
- while (count) {
- __raw_writew((__force u16)(*buf), addr);
- buf++;
- count -= 2;
- }
- break;
- }
- case sizeof(u32): {
- const __le32 *buf = buffer;
-
- SSB_WARN_ON(count & 3);
- while (count) {
- __raw_writel((__force u32)(*buf), addr);
- buf++;
- count -= 4;
- }
- break;
- }
- default:
- SSB_WARN_ON(1);
- }
-}
-#endif /* CONFIG_SSB_BLOCKIO */
-
-/* Ops for the plain SSB bus without a host-device (no PCI or PCMCIA). */
-static const struct ssb_bus_ops ssb_ssb_ops = {
- .read8 = ssb_ssb_read8,
- .read16 = ssb_ssb_read16,
- .read32 = ssb_ssb_read32,
- .write8 = ssb_ssb_write8,
- .write16 = ssb_ssb_write16,
- .write32 = ssb_ssb_write32,
-#ifdef CONFIG_SSB_BLOCKIO
- .block_read = ssb_ssb_block_read,
- .block_write = ssb_ssb_block_write,
-#endif
-};
-
static int ssb_fetch_invariants(struct ssb_bus *bus,
ssb_invariants_func_t get_invariants)
{
@@ -876,7 +716,6 @@ int ssb_bus_pcibus_register(struct ssb_b
return err;
}
-EXPORT_SYMBOL(ssb_bus_pcibus_register);
#endif /* CONFIG_SSB_PCIHOST */
#ifdef CONFIG_SSB_PCMCIAHOST
@@ -898,7 +737,6 @@ int ssb_bus_pcmciabus_register(struct ss
return err;
}
-EXPORT_SYMBOL(ssb_bus_pcmciabus_register);
#endif /* CONFIG_SSB_PCMCIAHOST */
#ifdef CONFIG_SSB_SDIOHOST
@@ -923,13 +761,14 @@ int ssb_bus_sdiobus_register(struct ssb_
EXPORT_SYMBOL(ssb_bus_sdiobus_register);
#endif /* CONFIG_SSB_PCMCIAHOST */
+#ifdef CONFIG_SSB_HOST_SOC
int ssb_bus_ssbbus_register(struct ssb_bus *bus, unsigned long baseaddr,
ssb_invariants_func_t get_invariants)
{
int err;
bus->bustype = SSB_BUSTYPE_SSB;
- bus->ops = &ssb_ssb_ops;
+ bus->ops = &ssb_host_soc_ops;
err = ssb_bus_register(bus, get_invariants, baseaddr);
if (!err) {
@@ -939,6 +778,7 @@ int ssb_bus_ssbbus_register(struct ssb_b
return err;
}
+#endif
int __ssb_driver_register(struct ssb_driver *drv, struct module *owner)
{
@@ -1465,6 +1305,12 @@ static int __init ssb_modinit(void)
/* don't fail SSB init because of this */
err = 0;
}
+ err = ssb_host_pcmcia_init();
+ if (err) {
+ ssb_err("PCMCIA host initialization failed\n");
+ /* don't fail SSB init because of this */
+ err = 0;
+ }
err = ssb_gige_init();
if (err) {
ssb_err("SSB Broadcom Gigabit Ethernet driver initialization failed\n");
@@ -1482,6 +1328,7 @@ fs_initcall(ssb_modinit);
static void __exit ssb_modexit(void)
{
ssb_gige_exit();
+ ssb_host_pcmcia_exit();
b43_pci_ssb_bridge_exit();
bus_unregister(&ssb_bustype);
}
--- a/drivers/ssb/pcmcia.c
+++ b/drivers/ssb/pcmcia.c
@@ -147,8 +147,7 @@ error:
return err;
}
-int ssb_pcmcia_switch_core(struct ssb_bus *bus,
- struct ssb_device *dev)
+static int ssb_pcmcia_switch_core(struct ssb_bus *bus, struct ssb_device *dev)
{
int err;
--- a/drivers/ssb/sdio.c
+++ b/drivers/ssb/sdio.c
@@ -200,7 +200,7 @@ out:
}
/* host must be already claimed */
-int ssb_sdio_switch_core(struct ssb_bus *bus, struct ssb_device *dev)
+static int ssb_sdio_switch_core(struct ssb_bus *bus, struct ssb_device *dev)
{
u8 coreidx = dev->core_index;
u32 sbaddr;
--- a/drivers/ssb/ssb_private.h
+++ b/drivers/ssb/ssb_private.h
@@ -85,8 +85,6 @@ static inline int ssb_pci_init(struct ss
/* pcmcia.c */
#ifdef CONFIG_SSB_PCMCIAHOST
-extern int ssb_pcmcia_switch_core(struct ssb_bus *bus,
- struct ssb_device *dev);
extern int ssb_pcmcia_switch_coreidx(struct ssb_bus *bus,
u8 coreidx);
extern int ssb_pcmcia_switch_segment(struct ssb_bus *bus,
@@ -96,13 +94,10 @@ extern int ssb_pcmcia_get_invariants(str
extern int ssb_pcmcia_hardware_setup(struct ssb_bus *bus);
extern void ssb_pcmcia_exit(struct ssb_bus *bus);
extern int ssb_pcmcia_init(struct ssb_bus *bus);
+extern int ssb_host_pcmcia_init(void);
+extern void ssb_host_pcmcia_exit(void);
extern const struct ssb_bus_ops ssb_pcmcia_ops;
#else /* CONFIG_SSB_PCMCIAHOST */
-static inline int ssb_pcmcia_switch_core(struct ssb_bus *bus,
- struct ssb_device *dev)
-{
- return 0;
-}
static inline int ssb_pcmcia_switch_coreidx(struct ssb_bus *bus,
u8 coreidx)
{
@@ -124,6 +119,13 @@ static inline int ssb_pcmcia_init(struct
{
return 0;
}
+static inline int ssb_host_pcmcia_init(void)
+{
+ return 0;
+}
+static inline void ssb_host_pcmcia_exit(void)
+{
+}
#endif /* CONFIG_SSB_PCMCIAHOST */
/* sdio.c */
@@ -132,9 +134,7 @@ extern int ssb_sdio_get_invariants(struc
struct ssb_init_invariants *iv);
extern u32 ssb_sdio_scan_read32(struct ssb_bus *bus, u16 offset);
-extern int ssb_sdio_switch_core(struct ssb_bus *bus, struct ssb_device *dev);
extern int ssb_sdio_scan_switch_coreidx(struct ssb_bus *bus, u8 coreidx);
-extern int ssb_sdio_hardware_setup(struct ssb_bus *bus);
extern void ssb_sdio_exit(struct ssb_bus *bus);
extern int ssb_sdio_init(struct ssb_bus *bus);
@@ -144,19 +144,10 @@ static inline u32 ssb_sdio_scan_read32(s
{
return 0;
}
-static inline int ssb_sdio_switch_core(struct ssb_bus *bus,
- struct ssb_device *dev)
-{
- return 0;
-}
static inline int ssb_sdio_scan_switch_coreidx(struct ssb_bus *bus, u8 coreidx)
{
return 0;
}
-static inline int ssb_sdio_hardware_setup(struct ssb_bus *bus)
-{
- return 0;
-}
static inline void ssb_sdio_exit(struct ssb_bus *bus)
{
}
@@ -166,6 +157,13 @@ static inline int ssb_sdio_init(struct s
}
#endif /* CONFIG_SSB_SDIOHOST */
+/**************************************************
+ * host_soc.c
+ **************************************************/
+
+#ifdef CONFIG_SSB_HOST_SOC
+extern const struct ssb_bus_ops ssb_host_soc_ops;
+#endif
/* scan.c */
extern const char *ssb_core_name(u16 coreid);

@ -1,49 +0,0 @@
--- a/drivers/bcma/main.c
+++ b/drivers/bcma/main.c
@@ -668,11 +668,36 @@ static int bcma_device_uevent(struct dev
core->id.rev, core->id.class);
}
-static int __init bcma_modinit(void)
+static unsigned int bcma_bus_registered;
+
+/*
+ * If built-in, bus has to be registered early, before any driver calls
+ * bcma_driver_register.
+ * Otherwise registering driver would trigger BUG in driver_register.
+ */
+static int __init bcma_init_bus_register(void)
{
int err;
+ if (bcma_bus_registered)
+ return 0;
+
err = bus_register(&bcma_bus_type);
+ if (!err)
+ bcma_bus_registered = 1;
+
+ return err;
+}
+#ifndef MODULE
+fs_initcall(bcma_init_bus_register);
+#endif
+
+/* Main initialization has to be done with SPI/mtd/NAND/SPROM available */
+static int __init bcma_modinit(void)
+{
+ int err;
+
+ err = bcma_init_bus_register();
if (err)
return err;
@@ -691,7 +716,7 @@ static int __init bcma_modinit(void)
return err;
}
-fs_initcall(bcma_modinit);
+module_init(bcma_modinit);
static void __exit bcma_modexit(void)
{

@ -1,444 +0,0 @@
--- a/drivers/bcma/driver_chipcommon.c
+++ b/drivers/bcma/driver_chipcommon.c
@@ -15,6 +15,8 @@
#include <linux/platform_device.h>
#include <linux/bcma/bcma.h>
+static void bcma_chipco_serial_init(struct bcma_drv_cc *cc);
+
static inline u32 bcma_cc_write32_masked(struct bcma_drv_cc *cc, u16 offset,
u32 mask, u32 value)
{
@@ -115,6 +117,8 @@ int bcma_chipco_watchdog_register(struct
void bcma_core_chipcommon_early_init(struct bcma_drv_cc *cc)
{
+ struct bcma_bus *bus = cc->core->bus;
+
if (cc->early_setup_done)
return;
@@ -129,6 +133,9 @@ void bcma_core_chipcommon_early_init(str
if (cc->capabilities & BCMA_CC_CAP_PMU)
bcma_pmu_early_init(cc);
+ if (IS_BUILTIN(CONFIG_BCM47XX) && bus->hosttype == BCMA_HOSTTYPE_SOC)
+ bcma_chipco_serial_init(cc);
+
cc->early_setup_done = true;
}
@@ -185,11 +192,12 @@ u32 bcma_chipco_watchdog_timer_set(struc
ticks = 2;
else if (ticks > maxt)
ticks = maxt;
- bcma_cc_write32(cc, BCMA_CC_PMU_WATCHDOG, ticks);
+ bcma_pmu_write32(cc, BCMA_CC_PMU_WATCHDOG, ticks);
} else {
struct bcma_bus *bus = cc->core->bus;
if (bus->chipinfo.id != BCMA_CHIP_ID_BCM4707 &&
+ bus->chipinfo.id != BCMA_CHIP_ID_BCM47094 &&
bus->chipinfo.id != BCMA_CHIP_ID_BCM53018)
bcma_core_set_clockmode(cc->core,
ticks ? BCMA_CLKMODE_FAST : BCMA_CLKMODE_DYNAMIC);
@@ -314,9 +322,9 @@ u32 bcma_chipco_gpio_pulldown(struct bcm
return res;
}
-#ifdef CONFIG_BCMA_DRIVER_MIPS
-void bcma_chipco_serial_init(struct bcma_drv_cc *cc)
+static void bcma_chipco_serial_init(struct bcma_drv_cc *cc)
{
+#if IS_BUILTIN(CONFIG_BCM47XX)
unsigned int irq;
u32 baud_base;
u32 i;
@@ -358,5 +366,5 @@ void bcma_chipco_serial_init(struct bcma
ports[i].baud_base = baud_base;
ports[i].reg_shift = 0;
}
+#endif /* CONFIG_BCM47XX */
}
-#endif /* CONFIG_BCMA_DRIVER_MIPS */
--- a/drivers/bcma/driver_chipcommon_pmu.c
+++ b/drivers/bcma/driver_chipcommon_pmu.c
@@ -15,44 +15,44 @@
u32 bcma_chipco_pll_read(struct bcma_drv_cc *cc, u32 offset)
{
- bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset);
- bcma_cc_read32(cc, BCMA_CC_PLLCTL_ADDR);
- return bcma_cc_read32(cc, BCMA_CC_PLLCTL_DATA);
+ bcma_pmu_write32(cc, BCMA_CC_PMU_PLLCTL_ADDR, offset);
+ bcma_pmu_read32(cc, BCMA_CC_PMU_PLLCTL_ADDR);
+ return bcma_pmu_read32(cc, BCMA_CC_PMU_PLLCTL_DATA);
}
EXPORT_SYMBOL_GPL(bcma_chipco_pll_read);
void bcma_chipco_pll_write(struct bcma_drv_cc *cc, u32 offset, u32 value)
{
- bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset);
- bcma_cc_read32(cc, BCMA_CC_PLLCTL_ADDR);
- bcma_cc_write32(cc, BCMA_CC_PLLCTL_DATA, value);
+ bcma_pmu_write32(cc, BCMA_CC_PMU_PLLCTL_ADDR, offset);
+ bcma_pmu_read32(cc, BCMA_CC_PMU_PLLCTL_ADDR);
+ bcma_pmu_write32(cc, BCMA_CC_PMU_PLLCTL_DATA, value);
}
EXPORT_SYMBOL_GPL(bcma_chipco_pll_write);
void bcma_chipco_pll_maskset(struct bcma_drv_cc *cc, u32 offset, u32 mask,
u32 set)
{
- bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset);
- bcma_cc_read32(cc, BCMA_CC_PLLCTL_ADDR);
- bcma_cc_maskset32(cc, BCMA_CC_PLLCTL_DATA, mask, set);
+ bcma_pmu_write32(cc, BCMA_CC_PMU_PLLCTL_ADDR, offset);
+ bcma_pmu_read32(cc, BCMA_CC_PMU_PLLCTL_ADDR);
+ bcma_pmu_maskset32(cc, BCMA_CC_PMU_PLLCTL_DATA, mask, set);
}
EXPORT_SYMBOL_GPL(bcma_chipco_pll_maskset);
void bcma_chipco_chipctl_maskset(struct bcma_drv_cc *cc,
u32 offset, u32 mask, u32 set)
{
- bcma_cc_write32(cc, BCMA_CC_CHIPCTL_ADDR, offset);
- bcma_cc_read32(cc, BCMA_CC_CHIPCTL_ADDR);
- bcma_cc_maskset32(cc, BCMA_CC_CHIPCTL_DATA, mask, set);
+ bcma_pmu_write32(cc, BCMA_CC_PMU_CHIPCTL_ADDR, offset);
+ bcma_pmu_read32(cc, BCMA_CC_PMU_CHIPCTL_ADDR);
+ bcma_pmu_maskset32(cc, BCMA_CC_PMU_CHIPCTL_DATA, mask, set);
}
EXPORT_SYMBOL_GPL(bcma_chipco_chipctl_maskset);
void bcma_chipco_regctl_maskset(struct bcma_drv_cc *cc, u32 offset, u32 mask,
u32 set)
{
- bcma_cc_write32(cc, BCMA_CC_REGCTL_ADDR, offset);
- bcma_cc_read32(cc, BCMA_CC_REGCTL_ADDR);
- bcma_cc_maskset32(cc, BCMA_CC_REGCTL_DATA, mask, set);
+ bcma_pmu_write32(cc, BCMA_CC_PMU_REGCTL_ADDR, offset);
+ bcma_pmu_read32(cc, BCMA_CC_PMU_REGCTL_ADDR);
+ bcma_pmu_maskset32(cc, BCMA_CC_PMU_REGCTL_DATA, mask, set);
}
EXPORT_SYMBOL_GPL(bcma_chipco_regctl_maskset);
@@ -60,18 +60,18 @@ static u32 bcma_pmu_xtalfreq(struct bcma
{
u32 ilp_ctl, alp_hz;
- if (!(bcma_cc_read32(cc, BCMA_CC_PMU_STAT) &
+ if (!(bcma_pmu_read32(cc, BCMA_CC_PMU_STAT) &
BCMA_CC_PMU_STAT_EXT_LPO_AVAIL))
return 0;
- bcma_cc_write32(cc, BCMA_CC_PMU_XTAL_FREQ,
- BIT(BCMA_CC_PMU_XTAL_FREQ_MEASURE_SHIFT));
+ bcma_pmu_write32(cc, BCMA_CC_PMU_XTAL_FREQ,
+ BIT(BCMA_CC_PMU_XTAL_FREQ_MEASURE_SHIFT));
usleep_range(1000, 2000);
- ilp_ctl = bcma_cc_read32(cc, BCMA_CC_PMU_XTAL_FREQ);
+ ilp_ctl = bcma_pmu_read32(cc, BCMA_CC_PMU_XTAL_FREQ);
ilp_ctl &= BCMA_CC_PMU_XTAL_FREQ_ILPCTL_MASK;
- bcma_cc_write32(cc, BCMA_CC_PMU_XTAL_FREQ, 0);
+ bcma_pmu_write32(cc, BCMA_CC_PMU_XTAL_FREQ, 0);
alp_hz = ilp_ctl * 32768 / 4;
return (alp_hz + 50000) / 100000 * 100;
@@ -127,8 +127,8 @@ static void bcma_pmu2_pll_init0(struct b
mask = (u32)~(BCMA_RES_4314_HT_AVAIL |
BCMA_RES_4314_MACPHY_CLK_AVAIL);
- bcma_cc_mask32(cc, BCMA_CC_PMU_MINRES_MSK, mask);
- bcma_cc_mask32(cc, BCMA_CC_PMU_MAXRES_MSK, mask);
+ bcma_pmu_mask32(cc, BCMA_CC_PMU_MINRES_MSK, mask);
+ bcma_pmu_mask32(cc, BCMA_CC_PMU_MAXRES_MSK, mask);
bcma_wait_value(cc->core, BCMA_CLKCTLST,
BCMA_CLKCTLST_HAVEHT, 0, 20000);
break;
@@ -140,7 +140,7 @@ static void bcma_pmu2_pll_init0(struct b
/* Flush */
if (cc->pmu.rev >= 2)
- bcma_cc_set32(cc, BCMA_CC_PMU_CTL, BCMA_CC_PMU_CTL_PLL_UPD);
+ bcma_pmu_set32(cc, BCMA_CC_PMU_CTL, BCMA_CC_PMU_CTL_PLL_UPD);
/* TODO: Do we need to update OTP? */
}
@@ -195,9 +195,9 @@ static void bcma_pmu_resources_init(stru
/* Set the resource masks. */
if (min_msk)
- bcma_cc_write32(cc, BCMA_CC_PMU_MINRES_MSK, min_msk);
+ bcma_pmu_write32(cc, BCMA_CC_PMU_MINRES_MSK, min_msk);
if (max_msk)
- bcma_cc_write32(cc, BCMA_CC_PMU_MAXRES_MSK, max_msk);
+ bcma_pmu_write32(cc, BCMA_CC_PMU_MAXRES_MSK, max_msk);
/*
* Add some delay; allow resources to come up and settle.
@@ -269,23 +269,33 @@ static void bcma_pmu_workarounds(struct
void bcma_pmu_early_init(struct bcma_drv_cc *cc)
{
+ struct bcma_bus *bus = cc->core->bus;
u32 pmucap;
- pmucap = bcma_cc_read32(cc, BCMA_CC_PMU_CAP);
+ if (cc->core->id.rev >= 35 &&
+ cc->capabilities_ext & BCMA_CC_CAP_EXT_AOB_PRESENT) {
+ cc->pmu.core = bcma_find_core(bus, BCMA_CORE_PMU);
+ if (!cc->pmu.core)
+ bcma_warn(bus, "Couldn't find expected PMU core");
+ }
+ if (!cc->pmu.core)
+ cc->pmu.core = cc->core;
+
+ pmucap = bcma_pmu_read32(cc, BCMA_CC_PMU_CAP);
cc->pmu.rev = (pmucap & BCMA_CC_PMU_CAP_REVISION);
- bcma_debug(cc->core->bus, "Found rev %u PMU (capabilities 0x%08X)\n",
- cc->pmu.rev, pmucap);
+ bcma_debug(bus, "Found rev %u PMU (capabilities 0x%08X)\n", cc->pmu.rev,
+ pmucap);
}
void bcma_pmu_init(struct bcma_drv_cc *cc)
{
if (cc->pmu.rev == 1)
- bcma_cc_mask32(cc, BCMA_CC_PMU_CTL,
- ~BCMA_CC_PMU_CTL_NOILPONW);
+ bcma_pmu_mask32(cc, BCMA_CC_PMU_CTL,
+ ~BCMA_CC_PMU_CTL_NOILPONW);
else
- bcma_cc_set32(cc, BCMA_CC_PMU_CTL,
- BCMA_CC_PMU_CTL_NOILPONW);
+ bcma_pmu_set32(cc, BCMA_CC_PMU_CTL,
+ BCMA_CC_PMU_CTL_NOILPONW);
bcma_pmu_pll_init(cc);
bcma_pmu_resources_init(cc);
@@ -472,8 +482,8 @@ u32 bcma_pmu_get_cpu_clock(struct bcma_d
static void bcma_pmu_spuravoid_pll_write(struct bcma_drv_cc *cc, u32 offset,
u32 value)
{
- bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset);
- bcma_cc_write32(cc, BCMA_CC_PLLCTL_DATA, value);
+ bcma_pmu_write32(cc, BCMA_CC_PMU_PLLCTL_ADDR, offset);
+ bcma_pmu_write32(cc, BCMA_CC_PMU_PLLCTL_DATA, value);
}
void bcma_pmu_spuravoid_pllupdate(struct bcma_drv_cc *cc, int spuravoid)
@@ -497,20 +507,20 @@ void bcma_pmu_spuravoid_pllupdate(struct
bus->chipinfo.id == BCMA_CHIP_ID_BCM53572) ? 6 : 0;
/* RMW only the P1 divider */
- bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR,
+ bcma_pmu_write32(cc, BCMA_CC_PMU_PLLCTL_ADDR,
BCMA_CC_PMU_PLL_CTL0 + phypll_offset);
- tmp = bcma_cc_read32(cc, BCMA_CC_PLLCTL_DATA);
+ tmp = bcma_pmu_read32(cc, BCMA_CC_PMU_PLLCTL_DATA);
tmp &= (~(BCMA_CC_PMU1_PLL0_PC0_P1DIV_MASK));
tmp |= (bcm5357_bcm43236_p1div[spuravoid] << BCMA_CC_PMU1_PLL0_PC0_P1DIV_SHIFT);
- bcma_cc_write32(cc, BCMA_CC_PLLCTL_DATA, tmp);
+ bcma_pmu_write32(cc, BCMA_CC_PMU_PLLCTL_DATA, tmp);
/* RMW only the int feedback divider */
- bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR,
+ bcma_pmu_write32(cc, BCMA_CC_PMU_PLLCTL_ADDR,
BCMA_CC_PMU_PLL_CTL2 + phypll_offset);
- tmp = bcma_cc_read32(cc, BCMA_CC_PLLCTL_DATA);
+ tmp = bcma_pmu_read32(cc, BCMA_CC_PMU_PLLCTL_DATA);
tmp &= ~(BCMA_CC_PMU1_PLL0_PC2_NDIV_INT_MASK);
tmp |= (bcm5357_bcm43236_ndiv[spuravoid]) << BCMA_CC_PMU1_PLL0_PC2_NDIV_INT_SHIFT;
- bcma_cc_write32(cc, BCMA_CC_PLLCTL_DATA, tmp);
+ bcma_pmu_write32(cc, BCMA_CC_PMU_PLLCTL_DATA, tmp);
tmp = BCMA_CC_PMU_CTL_PLL_UPD;
break;
@@ -646,7 +656,7 @@ void bcma_pmu_spuravoid_pllupdate(struct
break;
}
- tmp |= bcma_cc_read32(cc, BCMA_CC_PMU_CTL);
- bcma_cc_write32(cc, BCMA_CC_PMU_CTL, tmp);
+ tmp |= bcma_pmu_read32(cc, BCMA_CC_PMU_CTL);
+ bcma_pmu_write32(cc, BCMA_CC_PMU_CTL, tmp);
}
EXPORT_SYMBOL_GPL(bcma_pmu_spuravoid_pllupdate);
--- a/drivers/bcma/driver_chipcommon_sflash.c
+++ b/drivers/bcma/driver_chipcommon_sflash.c
@@ -38,6 +38,7 @@ static const struct bcma_sflash_tbl_e bc
{ "M25P32", 0x15, 0x10000, 64, },
{ "M25P64", 0x16, 0x10000, 128, },
{ "M25FL128", 0x17, 0x10000, 256, },
+ { "MX25L25635F", 0x18, 0x10000, 512, },
{ NULL },
};
--- a/drivers/bcma/scan.c
+++ b/drivers/bcma/scan.c
@@ -98,6 +98,9 @@ static const struct bcma_device_id_name
{ BCMA_CORE_SHIM, "SHIM" },
{ BCMA_CORE_PCIE2, "PCIe Gen2" },
{ BCMA_CORE_ARM_CR4, "ARM CR4" },
+ { BCMA_CORE_GCI, "GCI" },
+ { BCMA_CORE_CMEM, "CNDS DDR2/3 memory controller" },
+ { BCMA_CORE_ARM_CA7, "ARM CA7" },
{ BCMA_CORE_DEFAULT, "Default" },
};
@@ -315,6 +318,8 @@ static int bcma_get_next_core(struct bcm
switch (core->id.id) {
case BCMA_CORE_4706_MAC_GBIT_COMMON:
case BCMA_CORE_NS_CHIPCOMMON_B:
+ case BCMA_CORE_PMU:
+ case BCMA_CORE_GCI:
/* Not used yet: case BCMA_CORE_OOB_ROUTER: */
break;
default:
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
@@ -1216,10 +1216,10 @@ void b43_wireless_core_phy_pll_reset(str
case B43_BUS_BCMA:
bcma_cc = &dev->dev->bdev->bus->drv_cc;
- bcma_cc_write32(bcma_cc, BCMA_CC_CHIPCTL_ADDR, 0);
- bcma_cc_mask32(bcma_cc, BCMA_CC_CHIPCTL_DATA, ~0x4);
- bcma_cc_set32(bcma_cc, BCMA_CC_CHIPCTL_DATA, 0x4);
- bcma_cc_mask32(bcma_cc, BCMA_CC_CHIPCTL_DATA, ~0x4);
+ bcma_cc_write32(bcma_cc, BCMA_CC_PMU_CHIPCTL_ADDR, 0);
+ bcma_cc_mask32(bcma_cc, BCMA_CC_PMU_CHIPCTL_DATA, ~0x4);
+ bcma_cc_set32(bcma_cc, BCMA_CC_PMU_CHIPCTL_DATA, 0x4);
+ bcma_cc_mask32(bcma_cc, BCMA_CC_PMU_CHIPCTL_DATA, ~0x4);
break;
#endif
#ifdef CONFIG_B43_SSB
--- a/include/linux/bcma/bcma.h
+++ b/include/linux/bcma/bcma.h
@@ -151,6 +151,8 @@ struct bcma_host_ops {
#define BCMA_CORE_PCIE2 0x83C /* PCI Express Gen2 */
#define BCMA_CORE_USB30_DEV 0x83D
#define BCMA_CORE_ARM_CR4 0x83E
+#define BCMA_CORE_GCI 0x840
+#define BCMA_CORE_CMEM 0x846 /* CNDS DDR2/3 memory controller */
#define BCMA_CORE_ARM_CA7 0x847
#define BCMA_CORE_SYS_MEM 0x849
#define BCMA_CORE_DEFAULT 0xFFF
@@ -199,6 +201,7 @@ struct bcma_host_ops {
#define BCMA_PKG_ID_BCM4707 1
#define BCMA_PKG_ID_BCM4708 2
#define BCMA_PKG_ID_BCM4709 0
+#define BCMA_CHIP_ID_BCM47094 53030
#define BCMA_CHIP_ID_BCM53018 53018
/* Board types (on PCI usually equals to the subsystem dev id) */
--- a/include/linux/bcma/bcma_driver_chipcommon.h
+++ b/include/linux/bcma/bcma_driver_chipcommon.h
@@ -217,6 +217,11 @@
#define BCMA_CC_CLKDIV_JTAG_SHIFT 8
#define BCMA_CC_CLKDIV_UART 0x000000FF
#define BCMA_CC_CAP_EXT 0x00AC /* Capabilities */
+#define BCMA_CC_CAP_EXT_SECI_PRESENT 0x00000001
+#define BCMA_CC_CAP_EXT_GSIO_PRESENT 0x00000002
+#define BCMA_CC_CAP_EXT_GCI_PRESENT 0x00000004
+#define BCMA_CC_CAP_EXT_SECI_PUART_PRESENT 0x00000008 /* UART present */
+#define BCMA_CC_CAP_EXT_AOB_PRESENT 0x00000040
#define BCMA_CC_PLLONDELAY 0x00B0 /* Rev >= 4 only */
#define BCMA_CC_FREFSELDELAY 0x00B4 /* Rev >= 4 only */
#define BCMA_CC_SLOWCLKCTL 0x00B8 /* 6 <= Rev <= 9 only */
@@ -351,12 +356,12 @@
#define BCMA_CC_PMU_RES_REQTS 0x0640 /* PMU res req timer sel */
#define BCMA_CC_PMU_RES_REQT 0x0644 /* PMU res req timer */
#define BCMA_CC_PMU_RES_REQM 0x0648 /* PMU res req mask */
-#define BCMA_CC_CHIPCTL_ADDR 0x0650
-#define BCMA_CC_CHIPCTL_DATA 0x0654
-#define BCMA_CC_REGCTL_ADDR 0x0658
-#define BCMA_CC_REGCTL_DATA 0x065C
-#define BCMA_CC_PLLCTL_ADDR 0x0660
-#define BCMA_CC_PLLCTL_DATA 0x0664
+#define BCMA_CC_PMU_CHIPCTL_ADDR 0x0650
+#define BCMA_CC_PMU_CHIPCTL_DATA 0x0654
+#define BCMA_CC_PMU_REGCTL_ADDR 0x0658
+#define BCMA_CC_PMU_REGCTL_DATA 0x065C
+#define BCMA_CC_PMU_PLLCTL_ADDR 0x0660
+#define BCMA_CC_PMU_PLLCTL_DATA 0x0664
#define BCMA_CC_PMU_STRAPOPT 0x0668 /* (corerev >= 28) */
#define BCMA_CC_PMU_XTAL_FREQ 0x066C /* (pmurev >= 10) */
#define BCMA_CC_PMU_XTAL_FREQ_ILPCTL_MASK 0x00001FFF
@@ -566,6 +571,7 @@
* Check availability with ((struct bcma_chipcommon)->capabilities & BCMA_CC_CAP_PMU)
*/
struct bcma_chipcommon_pmu {
+ struct bcma_device *core; /* Can be separated core or just ChipCommon one */
u8 rev; /* PMU revision */
u32 crystalfreq; /* The active crystal frequency (in kHz) */
};
@@ -662,6 +668,19 @@ struct bcma_drv_cc_b {
#define bcma_cc_maskset32(cc, offset, mask, set) \
bcma_cc_write32(cc, offset, (bcma_cc_read32(cc, offset) & (mask)) | (set))
+/* PMU registers access */
+#define bcma_pmu_read32(cc, offset) \
+ bcma_read32((cc)->pmu.core, offset)
+#define bcma_pmu_write32(cc, offset, val) \
+ bcma_write32((cc)->pmu.core, offset, val)
+
+#define bcma_pmu_mask32(cc, offset, mask) \
+ bcma_pmu_write32(cc, offset, bcma_pmu_read32(cc, offset) & (mask))
+#define bcma_pmu_set32(cc, offset, set) \
+ bcma_pmu_write32(cc, offset, bcma_pmu_read32(cc, offset) | (set))
+#define bcma_pmu_maskset32(cc, offset, mask, set) \
+ bcma_pmu_write32(cc, offset, (bcma_pmu_read32(cc, offset) & (mask)) | (set))
+
extern u32 bcma_chipco_watchdog_timer_set(struct bcma_drv_cc *cc, u32 ticks);
extern u32 bcma_chipco_get_alp_clock(struct bcma_drv_cc *cc);
--- a/drivers/bcma/bcma_private.h
+++ b/drivers/bcma/bcma_private.h
@@ -48,7 +48,6 @@ void bcma_core_chipcommon_early_init(str
void bcma_core_chipcommon_init(struct bcma_drv_cc *cc);
void bcma_chipco_bcm4331_ext_pa_lines_ctl(struct bcma_drv_cc *cc, bool enable);
#ifdef CONFIG_BCMA_DRIVER_MIPS
-void bcma_chipco_serial_init(struct bcma_drv_cc *cc);
extern struct platform_device bcma_pflash_dev;
#endif /* CONFIG_BCMA_DRIVER_MIPS */
--- a/drivers/bcma/driver_gpio.c
+++ b/drivers/bcma/driver_gpio.c
@@ -197,6 +197,7 @@ int bcma_gpio_init(struct bcma_drv_cc *c
case BCMA_CHIP_ID_BCM4707:
case BCMA_CHIP_ID_BCM5357:
case BCMA_CHIP_ID_BCM53572:
+ case BCMA_CHIP_ID_BCM47094:
chip->ngpio = 32;
break;
default:
--- a/drivers/bcma/driver_mips.c
+++ b/drivers/bcma/driver_mips.c
@@ -337,12 +337,9 @@ static void bcma_core_mips_flash_detect(
void bcma_core_mips_early_init(struct bcma_drv_mips *mcore)
{
- struct bcma_bus *bus = mcore->core->bus;
-
if (mcore->early_setup_done)
return;
- bcma_chipco_serial_init(&bus->drv_cc);
bcma_core_mips_flash_detect(mcore);
mcore->early_setup_done = true;
--- a/drivers/bcma/host_pci.c
+++ b/drivers/bcma/host_pci.c
@@ -294,7 +294,7 @@ static const struct pci_device_id bcma_p
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4358) },
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4359) },
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4360) },
- { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4365) },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_BROADCOM, 0x4365, PCI_VENDOR_ID_DELL, 0x0016) },
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x43a0) },
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x43a9) },
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x43aa) },

@ -1,505 +0,0 @@
Subject: netfilter: conntrack: cache route for forwarded connections
... to avoid per-packet FIB lookup if possible.
The cached dst is re-used provided the input interface
is the same as that of the previous packet in the same direction.
If not, the cached dst is invalidated.
For ipv6 we also need to store sernum, else dst_check doesn't work,
pointed out by Eric Dumazet.
This should speed up forwarding when conntrack is already in use
anyway, especially when using reverse path filtering -- active RPF
enforces two FIB lookups for each packet.
Before the routing cache removal this didn't matter since RPF was performed
only when route cache didn't yield a result; but without route cache it
comes at higher price.
Julian Anastasov suggested to add NETDEV_UNREGISTER handler to
avoid holding on to dsts of 'frozen' conntracks.
Signed-off-by: Florian Westphal <fw@strlen.de>
--- a/include/net/netfilter/nf_conntrack_extend.h
+++ b/include/net/netfilter/nf_conntrack_extend.h
@@ -30,6 +30,9 @@ enum nf_ct_ext_id {
#if IS_ENABLED(CONFIG_NETFILTER_SYNPROXY)
NF_CT_EXT_SYNPROXY,
#endif
+#if IS_ENABLED(CONFIG_NF_CONNTRACK_RTCACHE)
+ NF_CT_EXT_RTCACHE,
+#endif
NF_CT_EXT_NUM,
};
@@ -43,6 +46,7 @@ enum nf_ct_ext_id {
#define NF_CT_EXT_TIMEOUT_TYPE struct nf_conn_timeout
#define NF_CT_EXT_LABELS_TYPE struct nf_conn_labels
#define NF_CT_EXT_SYNPROXY_TYPE struct nf_conn_synproxy
+#define NF_CT_EXT_RTCACHE_TYPE struct nf_conn_rtcache
/* Extensions: optional stuff which isn't permanently in struct. */
struct nf_ct_ext {
--- /dev/null
+++ b/include/net/netfilter/nf_conntrack_rtcache.h
@@ -0,0 +1,34 @@
+#include <linux/gfp.h>
+#include <net/netfilter/nf_conntrack.h>
+#include <net/netfilter/nf_conntrack_extend.h>
+
+struct dst_entry;
+
+struct nf_conn_dst_cache {
+ struct dst_entry *dst;
+ int iif;
+#if IS_ENABLED(CONFIG_NF_CONNTRACK_IPV6)
+ u32 cookie;
+#endif
+
+};
+
+struct nf_conn_rtcache {
+ struct nf_conn_dst_cache cached_dst[IP_CT_DIR_MAX];
+};
+
+static inline
+struct nf_conn_rtcache *nf_ct_rtcache_find(const struct nf_conn *ct)
+{
+#if IS_ENABLED(CONFIG_NF_CONNTRACK_RTCACHE)
+ return nf_ct_ext_find(ct, NF_CT_EXT_RTCACHE);
+#else
+ return NULL;
+#endif
+}
+
+static inline int nf_conn_rtcache_iif_get(const struct nf_conn_rtcache *rtc,
+ enum ip_conntrack_dir dir)
+{
+ return rtc->cached_dst[dir].iif;
+}
--- a/net/netfilter/Kconfig
+++ b/net/netfilter/Kconfig
@@ -114,6 +114,18 @@ config NF_CONNTRACK_EVENTS
If unsure, say `N'.
+config NF_CONNTRACK_RTCACHE
+ tristate "Cache route entries in conntrack objects"
+ depends on NETFILTER_ADVANCED
+ depends on NF_CONNTRACK
+ help
+ If this option is enabled, the connection tracking code will
+ cache routing information for each connection that is being
+ forwarded, at a cost of 32 bytes per conntrack object.
+
+ To compile it as a module, choose M here. If unsure, say N.
+ The module will be called nf_conntrack_rtcache.
+
config NF_CONNTRACK_TIMEOUT
bool 'Connection tracking timeout'
depends on NETFILTER_ADVANCED
--- a/net/netfilter/Makefile
+++ b/net/netfilter/Makefile
@@ -18,6 +18,9 @@ obj-$(CONFIG_NETFILTER_NETLINK_LOG) += n
# connection tracking
obj-$(CONFIG_NF_CONNTRACK) += nf_conntrack.o
+# optional conntrack route cache extension
+obj-$(CONFIG_NF_CONNTRACK_RTCACHE) += nf_conntrack_rtcache.o
+
# SCTP protocol connection tracking
obj-$(CONFIG_NF_CT_PROTO_DCCP) += nf_conntrack_proto_dccp.o
obj-$(CONFIG_NF_CT_PROTO_GRE) += nf_conntrack_proto_gre.o
--- /dev/null
+++ b/net/netfilter/nf_conntrack_rtcache.c
@@ -0,0 +1,387 @@
+/* route cache for netfilter.
+ *
+ * (C) 2014 Red Hat GmbH
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/types.h>
+#include <linux/netfilter.h>
+#include <linux/skbuff.h>
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/export.h>
+#include <linux/module.h>
+
+#include <net/dst.h>
+
+#include <net/netfilter/nf_conntrack.h>
+#include <net/netfilter/nf_conntrack_core.h>
+#include <net/netfilter/nf_conntrack_extend.h>
+#include <net/netfilter/nf_conntrack_rtcache.h>
+
+#if IS_ENABLED(CONFIG_NF_CONNTRACK_IPV6)
+#include <net/ip6_fib.h>
+#endif
+
+static void __nf_conn_rtcache_destroy(struct nf_conn_rtcache *rtc,
+ enum ip_conntrack_dir dir)
+{
+ struct dst_entry *dst = rtc->cached_dst[dir].dst;
+
+ dst_release(dst);
+}
+
+static void nf_conn_rtcache_destroy(struct nf_conn *ct)
+{
+ struct nf_conn_rtcache *rtc = nf_ct_rtcache_find(ct);
+
+ if (!rtc)
+ return;
+
+ __nf_conn_rtcache_destroy(rtc, IP_CT_DIR_ORIGINAL);
+ __nf_conn_rtcache_destroy(rtc, IP_CT_DIR_REPLY);
+}
+
+static void nf_ct_rtcache_ext_add(struct nf_conn *ct)
+{
+ struct nf_conn_rtcache *rtc;
+
+ rtc = nf_ct_ext_add(ct, NF_CT_EXT_RTCACHE, GFP_ATOMIC);
+ if (rtc) {
+ rtc->cached_dst[IP_CT_DIR_ORIGINAL].iif = -1;
+ rtc->cached_dst[IP_CT_DIR_ORIGINAL].dst = NULL;
+ rtc->cached_dst[IP_CT_DIR_REPLY].iif = -1;
+ rtc->cached_dst[IP_CT_DIR_REPLY].dst = NULL;
+ }
+}
+
+static struct nf_conn_rtcache *nf_ct_rtcache_find_usable(struct nf_conn *ct)
+{
+ if (nf_ct_is_untracked(ct))
+ return NULL;
+ return nf_ct_rtcache_find(ct);
+}
+
+static struct dst_entry *
+nf_conn_rtcache_dst_get(const struct nf_conn_rtcache *rtc,
+ enum ip_conntrack_dir dir)
+{
+ return rtc->cached_dst[dir].dst;
+}
+
+static u32 nf_rtcache_get_cookie(int pf, const struct dst_entry *dst)
+{
+#if IS_ENABLED(CONFIG_NF_CONNTRACK_IPV6)
+ if (pf == NFPROTO_IPV6) {
+ const struct rt6_info *rt = (const struct rt6_info *)dst;
+
+ if (rt->rt6i_node)
+ return (u32)rt->rt6i_node->fn_sernum;
+ }
+#endif
+ return 0;
+}
+
+static void nf_conn_rtcache_dst_set(int pf,
+ struct nf_conn_rtcache *rtc,
+ struct dst_entry *dst,
+ enum ip_conntrack_dir dir, int iif)
+{
+ if (rtc->cached_dst[dir].iif != iif)
+ rtc->cached_dst[dir].iif = iif;
+
+ if (rtc->cached_dst[dir].dst != dst) {
+ struct dst_entry *old;
+
+ dst_hold(dst);
+
+ old = xchg(&rtc->cached_dst[dir].dst, dst);
+ dst_release(old);
+
+#if IS_ENABLED(CONFIG_NF_CONNTRACK_IPV6)
+ if (pf == NFPROTO_IPV6)
+ rtc->cached_dst[dir].cookie =
+ nf_rtcache_get_cookie(pf, dst);
+#endif
+ }
+}
+
+static void nf_conn_rtcache_dst_obsolete(struct nf_conn_rtcache *rtc,
+ enum ip_conntrack_dir dir)
+{
+ struct dst_entry *old;
+
+ pr_debug("Invalidate iif %d for dir %d on cache %p\n",
+ rtc->cached_dst[dir].iif, dir, rtc);
+
+ old = xchg(&rtc->cached_dst[dir].dst, NULL);
+ dst_release(old);
+ rtc->cached_dst[dir].iif = -1;
+}
+
+static unsigned int nf_rtcache_in(const struct nf_hook_ops *ops,
+ struct sk_buff *skb,
+ const struct nf_hook_state *state)
+{
+ struct nf_conn_rtcache *rtc;
+ enum ip_conntrack_info ctinfo;
+ enum ip_conntrack_dir dir;
+ struct dst_entry *dst;
+ struct nf_conn *ct;
+ int iif;
+ u32 cookie;
+
+ if (skb_dst(skb) || skb->sk)
+ return NF_ACCEPT;
+
+ ct = nf_ct_get(skb, &ctinfo);
+ if (!ct)
+ return NF_ACCEPT;
+
+ rtc = nf_ct_rtcache_find_usable(ct);
+ if (!rtc)
+ return NF_ACCEPT;
+
+ /* if iif changes, don't use cache and let ip stack
+ * do route lookup.
+ *
+ * If rp_filter is enabled it might toss skb, so
+ * we don't want to avoid these checks.
+ */
+ dir = CTINFO2DIR(ctinfo);
+ iif = nf_conn_rtcache_iif_get(rtc, dir);
+ if (state->in->ifindex != iif) {
+ pr_debug("ct %p, iif %d, cached iif %d, skip cached entry\n",
+ ct, iif, state->in->ifindex);
+ return NF_ACCEPT;
+ }
+ dst = nf_conn_rtcache_dst_get(rtc, dir);
+ if (dst == NULL)
+ return NF_ACCEPT;
+
+ cookie = nf_rtcache_get_cookie(ops->pf, dst);
+
+ dst = dst_check(dst, cookie);
+ pr_debug("obtained dst %p for skb %p, cookie %d\n", dst, skb, cookie);
+ if (likely(dst))
+ skb_dst_set_noref(skb, dst);
+ else
+ nf_conn_rtcache_dst_obsolete(rtc, dir);
+
+ return NF_ACCEPT;
+}
+
+static unsigned int nf_rtcache_forward(const struct nf_hook_ops *ops,
+ struct sk_buff *skb,
+ const struct nf_hook_state *state)
+{
+ struct nf_conn_rtcache *rtc;
+ enum ip_conntrack_info ctinfo;
+ enum ip_conntrack_dir dir;
+ struct nf_conn *ct;
+ struct dst_entry *dst = skb_dst(skb);
+ int iif;
+
+ ct = nf_ct_get(skb, &ctinfo);
+ if (!ct)
+ return NF_ACCEPT;
+
+ if (dst && dst_xfrm(dst))
+ return NF_ACCEPT;
+
+ if (!nf_ct_is_confirmed(ct)) {
+ if (WARN_ON(nf_ct_rtcache_find(ct)))
+ return NF_ACCEPT;
+ nf_ct_rtcache_ext_add(ct);
+ return NF_ACCEPT;
+ }
+
+ rtc = nf_ct_rtcache_find_usable(ct);
+ if (!rtc)
+ return NF_ACCEPT;
+
+ dir = CTINFO2DIR(ctinfo);
+ iif = nf_conn_rtcache_iif_get(rtc, dir);
+ pr_debug("ct %p, skb %p, dir %d, iif %d, cached iif %d\n",
+ ct, skb, dir, iif, state->in->ifindex);
+ if (likely(state->in->ifindex == iif))
+ return NF_ACCEPT;
+
+ nf_conn_rtcache_dst_set(ops->pf, rtc, skb_dst(skb), dir, state->in->ifindex);
+ return NF_ACCEPT;
+}
+
+static int nf_rtcache_dst_remove(struct nf_conn *ct, void *data)
+{
+ struct nf_conn_rtcache *rtc = nf_ct_rtcache_find(ct);
+ struct net_device *dev = data;
+
+ if (!rtc)
+ return 0;
+
+ if (dev->ifindex == rtc->cached_dst[IP_CT_DIR_ORIGINAL].iif ||
+ dev->ifindex == rtc->cached_dst[IP_CT_DIR_REPLY].iif) {
+ nf_conn_rtcache_dst_obsolete(rtc, IP_CT_DIR_ORIGINAL);
+ nf_conn_rtcache_dst_obsolete(rtc, IP_CT_DIR_REPLY);
+ }
+
+ return 0;
+}
+
+static int nf_rtcache_netdev_event(struct notifier_block *this,
+ unsigned long event, void *ptr)
+{
+ struct net_device *dev = netdev_notifier_info_to_dev(ptr);
+ struct net *net = dev_net(dev);
+
+ if (event == NETDEV_DOWN)
+ nf_ct_iterate_cleanup(net, nf_rtcache_dst_remove, dev, 0, 0);
+
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block nf_rtcache_notifier = {
+ .notifier_call = nf_rtcache_netdev_event,
+};
+
+static struct nf_hook_ops rtcache_ops[] = {
+ {
+ .hook = nf_rtcache_in,
+ .owner = THIS_MODULE,
+ .pf = NFPROTO_IPV4,
+ .hooknum = NF_INET_PRE_ROUTING,
+ .priority = NF_IP_PRI_LAST,
+ },
+ {
+ .hook = nf_rtcache_forward,
+ .owner = THIS_MODULE,
+ .pf = NFPROTO_IPV4,
+ .hooknum = NF_INET_FORWARD,
+ .priority = NF_IP_PRI_LAST,
+ },
+#if IS_ENABLED(CONFIG_NF_CONNTRACK_IPV6)
+ {
+ .hook = nf_rtcache_in,
+ .owner = THIS_MODULE,
+ .pf = NFPROTO_IPV6,
+ .hooknum = NF_INET_PRE_ROUTING,
+ .priority = NF_IP_PRI_LAST,
+ },
+ {
+ .hook = nf_rtcache_forward,
+ .owner = THIS_MODULE,
+ .pf = NFPROTO_IPV6,
+ .hooknum = NF_INET_FORWARD,
+ .priority = NF_IP_PRI_LAST,
+ },
+#endif
+};
+
+static struct nf_ct_ext_type rtcache_extend __read_mostly = {
+ .len = sizeof(struct nf_conn_rtcache),
+ .align = __alignof__(struct nf_conn_rtcache),
+ .id = NF_CT_EXT_RTCACHE,
+ .destroy = nf_conn_rtcache_destroy,
+};
+
+static int __init nf_conntrack_rtcache_init(void)
+{
+ int ret = nf_ct_extend_register(&rtcache_extend);
+
+ if (ret < 0) {
+ pr_err("nf_conntrack_rtcache: Unable to register extension\n");
+ return ret;
+ }
+
+ ret = nf_register_hooks(rtcache_ops, ARRAY_SIZE(rtcache_ops));
+ if (ret < 0) {
+ nf_ct_extend_unregister(&rtcache_extend);
+ return ret;
+ }
+
+ ret = register_netdevice_notifier(&nf_rtcache_notifier);
+ if (ret) {
+ nf_unregister_hooks(rtcache_ops, ARRAY_SIZE(rtcache_ops));
+ nf_ct_extend_unregister(&rtcache_extend);
+ }
+
+ return ret;
+}
+
+static int nf_rtcache_ext_remove(struct nf_conn *ct, void *data)
+{
+ struct nf_conn_rtcache *rtc = nf_ct_rtcache_find(ct);
+
+ return rtc != NULL;
+}
+
+static bool __exit nf_conntrack_rtcache_wait_for_dying(struct net *net)
+{
+ bool wait = false;
+ int cpu;
+
+ for_each_possible_cpu(cpu) {
+ struct nf_conntrack_tuple_hash *h;
+ struct hlist_nulls_node *n;
+ struct nf_conn *ct;
+ struct ct_pcpu *pcpu = per_cpu_ptr(net->ct.pcpu_lists, cpu);
+
+ rcu_read_lock();
+ spin_lock_bh(&pcpu->lock);
+
+ hlist_nulls_for_each_entry(h, n, &pcpu->dying, hnnode) {
+ ct = nf_ct_tuplehash_to_ctrack(h);
+ if (nf_ct_rtcache_find(ct) != NULL) {
+ wait = true;
+ break;
+ }
+ }
+ spin_unlock_bh(&pcpu->lock);
+ rcu_read_unlock();
+ }
+
+ return wait;
+}
+
+static void __exit nf_conntrack_rtcache_fini(void)
+{
+ struct net *net;
+ int count = 0;
+
+ /* remove hooks so no new connections get rtcache extension */
+ nf_unregister_hooks(rtcache_ops, ARRAY_SIZE(rtcache_ops));
+
+ synchronize_net();
+
+ unregister_netdevice_notifier(&nf_rtcache_notifier);
+
+ rtnl_lock();
+
+ /* zap all conntracks with rtcache extension */
+ for_each_net(net)
+ nf_ct_iterate_cleanup(net, nf_rtcache_ext_remove, NULL, 0, 0);
+
+ for_each_net(net) {
+ /* .. and make sure they're gone from dying list, too */
+ while (nf_conntrack_rtcache_wait_for_dying(net)) {
+ msleep(200);
+ WARN_ONCE(++count > 25, "Waiting for all rtcache conntracks to go away\n");
+ }
+ }
+
+ rtnl_unlock();
+ synchronize_net();
+ nf_ct_extend_unregister(&rtcache_extend);
+}
+module_init(nf_conntrack_rtcache_init);
+module_exit(nf_conntrack_rtcache_fini);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Florian Westphal <fw@strlen.de>");
+MODULE_DESCRIPTION("Conntrack route cache extension");

@ -1,22 +0,0 @@
--- a/arch/mips/boot/compressed/string.c
+++ b/arch/mips/boot/compressed/string.c
@@ -26,3 +26,19 @@ void *memset(void *s, int c, size_t n)
ss[i] = c;
return s;
}
+
+void *memmove(void *__dest, __const void *__src, size_t count)
+{
+ unsigned char *d = __dest;
+ const unsigned char *s = __src;
+
+ if (__dest == __src)
+ return __dest;
+
+ if (__dest < __src)
+ return memcpy(__dest, __src, count);
+
+ while (count--)
+ d[count] = s[count];
+ return __dest;
+}

@ -1,24 +0,0 @@
From: Felix Fietkau <nbd@openwrt.org>
Date: Mon, 13 Apr 2015 15:54:04 +0200
Subject: [PATCH] bgmac: fix MAC soft-reset bit for corerev > 4
Only core revisions older than 4 use BGMAC_CMDCFG_SR_REV0
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
---
--- a/drivers/net/ethernet/broadcom/bgmac.h
+++ b/drivers/net/ethernet/broadcom/bgmac.h
@@ -199,9 +199,9 @@
#define BGMAC_CMDCFG_TAI 0x00000200
#define BGMAC_CMDCFG_HD 0x00000400 /* Set if in half duplex mode */
#define BGMAC_CMDCFG_HD_SHIFT 10
-#define BGMAC_CMDCFG_SR_REV0 0x00000800 /* Set to reset mode, for other revs */
-#define BGMAC_CMDCFG_SR_REV4 0x00002000 /* Set to reset mode, only for core rev 4 */
-#define BGMAC_CMDCFG_SR(rev) ((rev == 4) ? BGMAC_CMDCFG_SR_REV4 : BGMAC_CMDCFG_SR_REV0)
+#define BGMAC_CMDCFG_SR_REV0 0x00000800 /* Set to reset mode, for core rev 0-3 */
+#define BGMAC_CMDCFG_SR_REV4 0x00002000 /* Set to reset mode, for core rev >= 4 */
+#define BGMAC_CMDCFG_SR(rev) ((rev >= 4) ? BGMAC_CMDCFG_SR_REV4 : BGMAC_CMDCFG_SR_REV0)
#define BGMAC_CMDCFG_ML 0x00008000 /* Set to activate mac loopback mode */
#define BGMAC_CMDCFG_AE 0x00400000
#define BGMAC_CMDCFG_CFE 0x00800000

@ -1,28 +0,0 @@
From: Felix Fietkau <nbd@openwrt.org>
Date: Mon, 13 Apr 2015 15:56:26 +0200
Subject: [PATCH] bgmac: reset all 4 GMAC cores on init
On a BCM4709 based device, I found that GMAC cores may be enabled at
probe time, but only become usable after a full reset.
Disable cores before re-enabling them to ensure that they are properly
reset.
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
---
--- a/drivers/net/ethernet/broadcom/bgmac.c
+++ b/drivers/net/ethernet/broadcom/bgmac.c
@@ -1641,8 +1641,11 @@ static int bgmac_probe(struct bcma_devic
ns_core = bcma_find_core_unit(core->bus,
BCMA_CORE_MAC_GBIT,
ns_gmac);
- if (ns_core && !bcma_core_is_enabled(ns_core))
- bcma_core_enable(ns_core, 0);
+ if (!ns_core)
+ continue;
+
+ bcma_core_disable(ns_core, 0);
+ bcma_core_enable(ns_core, 0);
}
}

@ -1,808 +0,0 @@
--- a/drivers/mtd/devices/m25p80.c
+++ b/drivers/mtd/devices/m25p80.c
@@ -31,7 +31,6 @@
struct m25p {
struct spi_device *spi;
struct spi_nor spi_nor;
- struct mtd_info mtd;
u8 command[MAX_CMD_SIZE];
};
@@ -62,8 +61,7 @@ static int m25p_cmdsz(struct spi_nor *no
return 1 + nor->addr_width;
}
-static int m25p80_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len,
- int wr_en)
+static int m25p80_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
{
struct m25p *flash = nor->priv;
struct spi_device *spi = flash->spi;
@@ -159,7 +157,7 @@ static int m25p80_erase(struct spi_nor *
struct m25p *flash = nor->priv;
dev_dbg(nor->dev, "%dKiB at 0x%08x\n",
- flash->mtd.erasesize / 1024, (u32)offset);
+ flash->spi_nor.mtd.erasesize / 1024, (u32)offset);
/* Set up command buffer. */
flash->command[0] = nor->erase_opcode;
@@ -201,11 +199,10 @@ static int m25p_probe(struct spi_device
nor->read_reg = m25p80_read_reg;
nor->dev = &spi->dev;
- nor->mtd = &flash->mtd;
+ nor->flash_node = spi->dev.of_node;
nor->priv = flash;
spi_set_drvdata(spi, flash);
- flash->mtd.priv = nor;
flash->spi = spi;
if (spi->mode & SPI_RX_QUAD)
@@ -214,7 +211,7 @@ static int m25p_probe(struct spi_device
mode = SPI_NOR_DUAL;
if (data && data->name)
- flash->mtd.name = data->name;
+ nor->mtd.name = data->name;
/* For some (historical?) reason many platforms provide two different
* names in flash_platform_data: "name" and "type". Quite often name is
@@ -232,7 +229,7 @@ static int m25p_probe(struct spi_device
ppdata.of_node = spi->dev.of_node;
- return mtd_device_parse_register(&flash->mtd, NULL, &ppdata,
+ return mtd_device_parse_register(&nor->mtd, NULL, &ppdata,
data ? data->parts : NULL,
data ? data->nr_parts : 0);
}
@@ -243,7 +240,7 @@ static int m25p_remove(struct spi_device
struct m25p *flash = spi_get_drvdata(spi);
/* Clean up MTD stuff. */
- return mtd_device_unregister(&flash->mtd);
+ return mtd_device_unregister(&flash->spi_nor.mtd);
}
/*
@@ -304,7 +301,6 @@ MODULE_DEVICE_TABLE(of, m25p_of_table);
static struct spi_driver m25p80_driver = {
.driver = {
.name = "m25p80",
- .owner = THIS_MODULE,
.of_match_table = m25p_of_table,
},
.id_table = m25p_ids,
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -16,15 +16,26 @@
#include <linux/device.h>
#include <linux/mutex.h>
#include <linux/math64.h>
+#include <linux/sizes.h>
-#include <linux/mtd/cfi.h>
#include <linux/mtd/mtd.h>
#include <linux/of_platform.h>
#include <linux/spi/flash.h>
#include <linux/mtd/spi-nor.h>
/* Define max times to check status register before we give up. */
-#define MAX_READY_WAIT_JIFFIES (40 * HZ) /* M25P16 specs 40s max chip erase */
+
+/*
+ * For everything but full-chip erase; probably could be much smaller, but kept
+ * around for safety for now
+ */
+#define DEFAULT_READY_WAIT_JIFFIES (40UL * HZ)
+
+/*
+ * For full-chip erase, calibrated to a 2MB flash (M25P16); should be scaled up
+ * for larger flash
+ */
+#define CHIP_ERASE_2MB_READY_WAIT_JIFFIES (40UL * HZ)
#define SPI_NOR_MAX_ID_LEN 6
@@ -145,7 +156,7 @@ static inline int spi_nor_read_dummy_cyc
static inline int write_sr(struct spi_nor *nor, u8 val)
{
nor->cmd_buf[0] = val;
- return nor->write_reg(nor, SPINOR_OP_WRSR, nor->cmd_buf, 1, 0);
+ return nor->write_reg(nor, SPINOR_OP_WRSR, nor->cmd_buf, 1);
}
/*
@@ -154,7 +165,7 @@ static inline int write_sr(struct spi_no
*/
static inline int write_enable(struct spi_nor *nor)
{
- return nor->write_reg(nor, SPINOR_OP_WREN, NULL, 0, 0);
+ return nor->write_reg(nor, SPINOR_OP_WREN, NULL, 0);
}
/*
@@ -162,7 +173,7 @@ static inline int write_enable(struct sp
*/
static inline int write_disable(struct spi_nor *nor)
{
- return nor->write_reg(nor, SPINOR_OP_WRDI, NULL, 0, 0);
+ return nor->write_reg(nor, SPINOR_OP_WRDI, NULL, 0);
}
static inline struct spi_nor *mtd_to_spi_nor(struct mtd_info *mtd)
@@ -179,16 +190,16 @@ static inline int set_4byte(struct spi_n
u8 cmd;
switch (JEDEC_MFR(info)) {
- case CFI_MFR_ST: /* Micron, actually */
+ case SNOR_MFR_MICRON:
/* Some Micron need WREN command; all will accept it */
need_wren = true;
- case CFI_MFR_MACRONIX:
- case 0xEF /* winbond */:
+ case SNOR_MFR_MACRONIX:
+ case SNOR_MFR_WINBOND:
if (need_wren)
write_enable(nor);
cmd = enable ? SPINOR_OP_EN4B : SPINOR_OP_EX4B;
- status = nor->write_reg(nor, cmd, NULL, 0, 0);
+ status = nor->write_reg(nor, cmd, NULL, 0);
if (need_wren)
write_disable(nor);
@@ -196,7 +207,7 @@ static inline int set_4byte(struct spi_n
default:
/* Spansion style */
nor->cmd_buf[0] = enable << 7;
- return nor->write_reg(nor, SPINOR_OP_BRWR, nor->cmd_buf, 1, 0);
+ return nor->write_reg(nor, SPINOR_OP_BRWR, nor->cmd_buf, 1);
}
}
static inline int spi_nor_sr_ready(struct spi_nor *nor)
@@ -233,12 +244,13 @@ static int spi_nor_ready(struct spi_nor
* Service routine to read status register until ready, or timeout occurs.
* Returns non-zero if error.
*/
-static int spi_nor_wait_till_ready(struct spi_nor *nor)
+static int spi_nor_wait_till_ready_with_timeout(struct spi_nor *nor,
+ unsigned long timeout_jiffies)
{
unsigned long deadline;
int timeout = 0, ret;
- deadline = jiffies + MAX_READY_WAIT_JIFFIES;
+ deadline = jiffies + timeout_jiffies;
while (!timeout) {
if (time_after_eq(jiffies, deadline))
@@ -258,6 +270,12 @@ static int spi_nor_wait_till_ready(struc
return -ETIMEDOUT;
}
+static int spi_nor_wait_till_ready(struct spi_nor *nor)
+{
+ return spi_nor_wait_till_ready_with_timeout(nor,
+ DEFAULT_READY_WAIT_JIFFIES);
+}
+
/*
* Erase the whole flash memory
*
@@ -265,9 +283,9 @@ static int spi_nor_wait_till_ready(struc
*/
static int erase_chip(struct spi_nor *nor)
{
- dev_dbg(nor->dev, " %lldKiB\n", (long long)(nor->mtd->size >> 10));
+ dev_dbg(nor->dev, " %lldKiB\n", (long long)(nor->mtd.size >> 10));
- return nor->write_reg(nor, SPINOR_OP_CHIP_ERASE, NULL, 0, 0);
+ return nor->write_reg(nor, SPINOR_OP_CHIP_ERASE, NULL, 0);
}
static int spi_nor_lock_and_prep(struct spi_nor *nor, enum spi_nor_ops ops)
@@ -321,6 +339,8 @@ static int spi_nor_erase(struct mtd_info
/* whole-chip erase? */
if (len == mtd->size) {
+ unsigned long timeout;
+
write_enable(nor);
if (erase_chip(nor)) {
@@ -328,7 +348,16 @@ static int spi_nor_erase(struct mtd_info
goto erase_err;
}
- ret = spi_nor_wait_till_ready(nor);
+ /*
+ * Scale the timeout linearly with the size of the flash, with
+ * a minimum calibrated to an old 2MB flash. We could try to
+ * pull these from CFI/SFDP, but these values should be good
+ * enough for now.
+ */
+ timeout = max(CHIP_ERASE_2MB_READY_WAIT_JIFFIES,
+ CHIP_ERASE_2MB_READY_WAIT_JIFFIES *
+ (unsigned long)(mtd->size / SZ_2M));
+ ret = spi_nor_wait_till_ready_with_timeout(nor, timeout);
if (ret)
goto erase_err;
@@ -371,72 +400,171 @@ erase_err:
return ret;
}
+static void stm_get_locked_range(struct spi_nor *nor, u8 sr, loff_t *ofs,
+ uint64_t *len)
+{
+ struct mtd_info *mtd = &nor->mtd;
+ u8 mask = SR_BP2 | SR_BP1 | SR_BP0;
+ int shift = ffs(mask) - 1;
+ int pow;
+
+ if (!(sr & mask)) {
+ /* No protection */
+ *ofs = 0;
+ *len = 0;
+ } else {
+ pow = ((sr & mask) ^ mask) >> shift;
+ *len = mtd->size >> pow;
+ *ofs = mtd->size - *len;
+ }
+}
+
+/*
+ * Return 1 if the entire region is locked, 0 otherwise
+ */
+static int stm_is_locked_sr(struct spi_nor *nor, loff_t ofs, uint64_t len,
+ u8 sr)
+{
+ loff_t lock_offs;
+ uint64_t lock_len;
+
+ stm_get_locked_range(nor, sr, &lock_offs, &lock_len);
+
+ return (ofs + len <= lock_offs + lock_len) && (ofs >= lock_offs);
+}
+
+/*
+ * Lock a region of the flash. Compatible with ST Micro and similar flash.
+ * Supports only the block protection bits BP{0,1,2} in the status register
+ * (SR). Does not support these features found in newer SR bitfields:
+ * - TB: top/bottom protect - only handle TB=0 (top protect)
+ * - SEC: sector/block protect - only handle SEC=0 (block protect)
+ * - CMP: complement protect - only support CMP=0 (range is not complemented)
+ *
+ * Sample table portion for 8MB flash (Winbond w25q64fw):
+ *
+ * SEC | TB | BP2 | BP1 | BP0 | Prot Length | Protected Portion
+ * --------------------------------------------------------------------------
+ * X | X | 0 | 0 | 0 | NONE | NONE
+ * 0 | 0 | 0 | 0 | 1 | 128 KB | Upper 1/64
+ * 0 | 0 | 0 | 1 | 0 | 256 KB | Upper 1/32
+ * 0 | 0 | 0 | 1 | 1 | 512 KB | Upper 1/16
+ * 0 | 0 | 1 | 0 | 0 | 1 MB | Upper 1/8
+ * 0 | 0 | 1 | 0 | 1 | 2 MB | Upper 1/4
+ * 0 | 0 | 1 | 1 | 0 | 4 MB | Upper 1/2
+ * X | X | 1 | 1 | 1 | 8 MB | ALL
+ *
+ * Returns negative on errors, 0 on success.
+ */
static int stm_lock(struct spi_nor *nor, loff_t ofs, uint64_t len)
{
- struct mtd_info *mtd = nor->mtd;
- uint32_t offset = ofs;
- uint8_t status_old, status_new;
- int ret = 0;
+ struct mtd_info *mtd = &nor->mtd;
+ u8 status_old, status_new;
+ u8 mask = SR_BP2 | SR_BP1 | SR_BP0;
+ u8 shift = ffs(mask) - 1, pow, val;
status_old = read_sr(nor);
- if (offset < mtd->size - (mtd->size / 2))
- status_new = status_old | SR_BP2 | SR_BP1 | SR_BP0;
- else if (offset < mtd->size - (mtd->size / 4))
- status_new = (status_old & ~SR_BP0) | SR_BP2 | SR_BP1;
- else if (offset < mtd->size - (mtd->size / 8))
- status_new = (status_old & ~SR_BP1) | SR_BP2 | SR_BP0;
- else if (offset < mtd->size - (mtd->size / 16))
- status_new = (status_old & ~(SR_BP0 | SR_BP1)) | SR_BP2;
- else if (offset < mtd->size - (mtd->size / 32))
- status_new = (status_old & ~SR_BP2) | SR_BP1 | SR_BP0;
- else if (offset < mtd->size - (mtd->size / 64))
- status_new = (status_old & ~(SR_BP2 | SR_BP0)) | SR_BP1;
- else
- status_new = (status_old & ~(SR_BP2 | SR_BP1)) | SR_BP0;
+ /* SPI NOR always locks to the end */
+ if (ofs + len != mtd->size) {
+ /* Does combined region extend to end? */
+ if (!stm_is_locked_sr(nor, ofs + len, mtd->size - ofs - len,
+ status_old))
+ return -EINVAL;
+ len = mtd->size - ofs;
+ }
+
+ /*
+ * Need smallest pow such that:
+ *
+ * 1 / (2^pow) <= (len / size)
+ *
+ * so (assuming power-of-2 size) we do:
+ *
+ * pow = ceil(log2(size / len)) = log2(size) - floor(log2(len))
+ */
+ pow = ilog2(mtd->size) - ilog2(len);
+ val = mask - (pow << shift);
+ if (val & ~mask)
+ return -EINVAL;
+ /* Don't "lock" with no region! */
+ if (!(val & mask))
+ return -EINVAL;
+
+ status_new = (status_old & ~mask) | val;
/* Only modify protection if it will not unlock other areas */
- if ((status_new & (SR_BP2 | SR_BP1 | SR_BP0)) >
- (status_old & (SR_BP2 | SR_BP1 | SR_BP0))) {
- write_enable(nor);
- ret = write_sr(nor, status_new);
- }
+ if ((status_new & mask) <= (status_old & mask))
+ return -EINVAL;
- return ret;
+ write_enable(nor);
+ return write_sr(nor, status_new);
}
+/*
+ * Unlock a region of the flash. See stm_lock() for more info
+ *
+ * Returns negative on errors, 0 on success.
+ */
static int stm_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len)
{
- struct mtd_info *mtd = nor->mtd;
- uint32_t offset = ofs;
+ struct mtd_info *mtd = &nor->mtd;
uint8_t status_old, status_new;
- int ret = 0;
+ u8 mask = SR_BP2 | SR_BP1 | SR_BP0;
+ u8 shift = ffs(mask) - 1, pow, val;
status_old = read_sr(nor);
- if (offset+len > mtd->size - (mtd->size / 64))
- status_new = status_old & ~(SR_BP2 | SR_BP1 | SR_BP0);
- else if (offset+len > mtd->size - (mtd->size / 32))
- status_new = (status_old & ~(SR_BP2 | SR_BP1)) | SR_BP0;
- else if (offset+len > mtd->size - (mtd->size / 16))
- status_new = (status_old & ~(SR_BP2 | SR_BP0)) | SR_BP1;
- else if (offset+len > mtd->size - (mtd->size / 8))
- status_new = (status_old & ~SR_BP2) | SR_BP1 | SR_BP0;
- else if (offset+len > mtd->size - (mtd->size / 4))
- status_new = (status_old & ~(SR_BP0 | SR_BP1)) | SR_BP2;
- else if (offset+len > mtd->size - (mtd->size / 2))
- status_new = (status_old & ~SR_BP1) | SR_BP2 | SR_BP0;
- else
- status_new = (status_old & ~SR_BP0) | SR_BP2 | SR_BP1;
+ /* Cannot unlock; would unlock larger region than requested */
+ if (stm_is_locked_sr(nor, status_old, ofs - mtd->erasesize,
+ mtd->erasesize))
+ return -EINVAL;
- /* Only modify protection if it will not lock other areas */
- if ((status_new & (SR_BP2 | SR_BP1 | SR_BP0)) <
- (status_old & (SR_BP2 | SR_BP1 | SR_BP0))) {
- write_enable(nor);
- ret = write_sr(nor, status_new);
+ /*
+ * Need largest pow such that:
+ *
+ * 1 / (2^pow) >= (len / size)
+ *
+ * so (assuming power-of-2 size) we do:
+ *
+ * pow = floor(log2(size / len)) = log2(size) - ceil(log2(len))
+ */
+ pow = ilog2(mtd->size) - order_base_2(mtd->size - (ofs + len));
+ if (ofs + len == mtd->size) {
+ val = 0; /* fully unlocked */
+ } else {
+ val = mask - (pow << shift);
+ /* Some power-of-two sizes are not supported */
+ if (val & ~mask)
+ return -EINVAL;
}
- return ret;
+ status_new = (status_old & ~mask) | val;
+
+ /* Only modify protection if it will not lock other areas */
+ if ((status_new & mask) >= (status_old & mask))
+ return -EINVAL;
+
+ write_enable(nor);
+ return write_sr(nor, status_new);
+}
+
+/*
+ * Check if a region of the flash is (completely) locked. See stm_lock() for
+ * more info.
+ *
+ * Returns 1 if entire region is locked, 0 if any portion is unlocked, and
+ * negative on errors.
+ */
+static int stm_is_locked(struct spi_nor *nor, loff_t ofs, uint64_t len)
+{
+ int status;
+
+ status = read_sr(nor);
+ if (status < 0)
+ return status;
+
+ return stm_is_locked_sr(nor, ofs, len, status);
}
static int spi_nor_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
@@ -469,6 +597,21 @@ static int spi_nor_unlock(struct mtd_inf
return ret;
}
+static int spi_nor_is_locked(struct mtd_info *mtd, loff_t ofs, uint64_t len)
+{
+ struct spi_nor *nor = mtd_to_spi_nor(mtd);
+ int ret;
+
+ ret = spi_nor_lock_and_prep(nor, SPI_NOR_OPS_UNLOCK);
+ if (ret)
+ return ret;
+
+ ret = nor->flash_is_locked(nor, ofs, len);
+
+ spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_LOCK);
+ return ret;
+}
+
/* Used when the "_ext_id" is two bytes at most */
#define INFO(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags) \
.id = { \
@@ -585,6 +728,7 @@ static const struct flash_info spi_nor_i
/* Micron */
{ "n25q032", INFO(0x20ba16, 0, 64 * 1024, 64, SPI_NOR_QUAD_READ) },
+ { "n25q032a", INFO(0x20bb16, 0, 64 * 1024, 64, SPI_NOR_QUAD_READ) },
{ "n25q064", INFO(0x20ba17, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_QUAD_READ) },
{ "n25q064a", INFO(0x20bb17, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_QUAD_READ) },
{ "n25q128a11", INFO(0x20bb18, 0, 64 * 1024, 256, SPI_NOR_QUAD_READ) },
@@ -618,12 +762,13 @@ static const struct flash_info spi_nor_i
{ "s25sl016a", INFO(0x010214, 0, 64 * 1024, 32, 0) },
{ "s25sl032a", INFO(0x010215, 0, 64 * 1024, 64, 0) },
{ "s25sl064a", INFO(0x010216, 0, 64 * 1024, 128, 0) },
- { "s25fl008k", INFO(0xef4014, 0, 64 * 1024, 16, SECT_4K) },
- { "s25fl016k", INFO(0xef4015, 0, 64 * 1024, 32, SECT_4K) },
+ { "s25fl004k", INFO(0xef4013, 0, 64 * 1024, 8, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+ { "s25fl008k", INFO(0xef4014, 0, 64 * 1024, 16, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+ { "s25fl016k", INFO(0xef4015, 0, 64 * 1024, 32, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ "s25fl064k", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) },
{ "s25fl132k", INFO(0x014016, 0, 64 * 1024, 64, SECT_4K) },
{ "s25fl164k", INFO(0x014017, 0, 64 * 1024, 128, SECT_4K) },
- { "s25fl204k", INFO(0x014013, 0, 64 * 1024, 8, SECT_4K) },
+ { "s25fl204k", INFO(0x014013, 0, 64 * 1024, 8, SECT_4K | SPI_NOR_DUAL_READ) },
/* SST -- large erase sizes are "overlays", "sectors" are 4K */
{ "sst25vf040b", INFO(0xbf258d, 0, 64 * 1024, 8, SECT_4K | SST_WRITE) },
@@ -635,6 +780,7 @@ static const struct flash_info spi_nor_i
{ "sst25wf010", INFO(0xbf2502, 0, 64 * 1024, 2, SECT_4K | SST_WRITE) },
{ "sst25wf020", INFO(0xbf2503, 0, 64 * 1024, 4, SECT_4K | SST_WRITE) },
{ "sst25wf020a", INFO(0x621612, 0, 64 * 1024, 4, SECT_4K) },
+ { "sst25wf040b", INFO(0x621613, 0, 64 * 1024, 8, SECT_4K) },
{ "sst25wf040", INFO(0xbf2504, 0, 64 * 1024, 8, SECT_4K | SST_WRITE) },
{ "sst25wf080", INFO(0xbf2505, 0, 64 * 1024, 16, SECT_4K | SST_WRITE) },
@@ -683,10 +829,11 @@ static const struct flash_info spi_nor_i
{ "w25x16", INFO(0xef3015, 0, 64 * 1024, 32, SECT_4K) },
{ "w25x32", INFO(0xef3016, 0, 64 * 1024, 64, SECT_4K) },
{ "w25q32", INFO(0xef4016, 0, 64 * 1024, 64, SECT_4K) },
- { "w25q32dw", INFO(0xef6016, 0, 64 * 1024, 64, SECT_4K) },
+ { "w25q32dw", INFO(0xef6016, 0, 64 * 1024, 64, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ "w25x64", INFO(0xef3017, 0, 64 * 1024, 128, SECT_4K) },
{ "w25q64", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) },
- { "w25q64dw", INFO(0xef6017, 0, 64 * 1024, 128, SECT_4K) },
+ { "w25q64dw", INFO(0xef6017, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+ { "w25q128fw", INFO(0xef6018, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ "w25q80", INFO(0xef5014, 0, 64 * 1024, 16, SECT_4K) },
{ "w25q80bl", INFO(0xef4014, 0, 64 * 1024, 16, SECT_4K) },
{ "w25q128", INFO(0xef4018, 0, 64 * 1024, 256, SECT_4K) },
@@ -868,8 +1015,7 @@ static int macronix_quad_enable(struct s
val = read_sr(nor);
write_enable(nor);
- nor->cmd_buf[0] = val | SR_QUAD_EN_MX;
- nor->write_reg(nor, SPINOR_OP_WRSR, nor->cmd_buf, 1, 0);
+ write_sr(nor, val | SR_QUAD_EN_MX);
if (spi_nor_wait_till_ready(nor))
return 1;
@@ -894,7 +1040,7 @@ static int write_sr_cr(struct spi_nor *n
nor->cmd_buf[0] = val & 0xff;
nor->cmd_buf[1] = (val >> 8);
- return nor->write_reg(nor, SPINOR_OP_WRSR, nor->cmd_buf, 2, 0);
+ return nor->write_reg(nor, SPINOR_OP_WRSR, nor->cmd_buf, 2);
}
static int spansion_quad_enable(struct spi_nor *nor)
@@ -936,7 +1082,7 @@ static int micron_quad_enable(struct spi
/* set EVCR, enable quad I/O */
nor->cmd_buf[0] = val & ~EVCR_QUAD_EN_MICRON;
- ret = nor->write_reg(nor, SPINOR_OP_WD_EVCR, nor->cmd_buf, 1, 0);
+ ret = nor->write_reg(nor, SPINOR_OP_WD_EVCR, nor->cmd_buf, 1);
if (ret < 0) {
dev_err(nor->dev, "error while writing EVCR register\n");
return ret;
@@ -965,14 +1111,14 @@ static int set_quad_mode(struct spi_nor
int status;
switch (JEDEC_MFR(info)) {
- case CFI_MFR_MACRONIX:
+ case SNOR_MFR_MACRONIX:
status = macronix_quad_enable(nor);
if (status) {
dev_err(nor->dev, "Macronix quad-read not enabled\n");
return -EINVAL;
}
return status;
- case CFI_MFR_ST:
+ case SNOR_MFR_MICRON:
status = micron_quad_enable(nor);
if (status) {
dev_err(nor->dev, "Micron quad-read not enabled\n");
@@ -1004,8 +1150,8 @@ int spi_nor_scan(struct spi_nor *nor, co
{
const struct flash_info *info = NULL;
struct device *dev = nor->dev;
- struct mtd_info *mtd = nor->mtd;
- struct device_node *np = dev->of_node;
+ struct mtd_info *mtd = &nor->mtd;
+ struct device_node *np = nor->flash_node;
int ret;
int i;
@@ -1048,19 +1194,21 @@ int spi_nor_scan(struct spi_nor *nor, co
mutex_init(&nor->lock);
/*
- * Atmel, SST and Intel/Numonyx serial nor tend to power
- * up with the software protection bits set
+ * Atmel, SST, Intel/Numonyx, and others serial NOR tend to power up
+ * with the software protection bits set
*/
- if (JEDEC_MFR(info) == CFI_MFR_ATMEL ||
- JEDEC_MFR(info) == CFI_MFR_INTEL ||
- JEDEC_MFR(info) == CFI_MFR_SST) {
+ if (JEDEC_MFR(info) == SNOR_MFR_ATMEL ||
+ JEDEC_MFR(info) == SNOR_MFR_INTEL ||
+ JEDEC_MFR(info) == SNOR_MFR_SST ||
+ JEDEC_MFR(info) == SNOR_MFR_WINBOND) {
write_enable(nor);
write_sr(nor, 0);
}
if (!mtd->name)
mtd->name = dev_name(dev);
+ mtd->priv = nor;
mtd->type = MTD_NORFLASH;
mtd->writesize = 1;
mtd->flags = MTD_CAP_NORFLASH;
@@ -1068,15 +1216,18 @@ int spi_nor_scan(struct spi_nor *nor, co
mtd->_erase = spi_nor_erase;
mtd->_read = spi_nor_read;
- /* nor protection support for STmicro chips */
- if (JEDEC_MFR(info) == CFI_MFR_ST) {
+ /* NOR protection support for STmicro/Micron chips and similar */
+ if (JEDEC_MFR(info) == SNOR_MFR_MICRON ||
+ JEDEC_MFR(info) == SNOR_MFR_WINBOND) {
nor->flash_lock = stm_lock;
nor->flash_unlock = stm_unlock;
+ nor->flash_is_locked = stm_is_locked;
}
- if (nor->flash_lock && nor->flash_unlock) {
+ if (nor->flash_lock && nor->flash_unlock && nor->flash_is_locked) {
mtd->_lock = spi_nor_lock;
mtd->_unlock = spi_nor_unlock;
+ mtd->_is_locked = spi_nor_is_locked;
}
/* sst nor chips use AAI word program */
@@ -1163,7 +1314,7 @@ int spi_nor_scan(struct spi_nor *nor, co
else if (mtd->size > 0x1000000) {
/* enable 4-byte addressing if the device exceeds 16MiB */
nor->addr_width = 4;
- if (JEDEC_MFR(info) == CFI_MFR_AMD) {
+ if (JEDEC_MFR(info) == SNOR_MFR_SPANSION) {
/* Dedicated 4-byte command set */
switch (nor->flash_read) {
case SPI_NOR_QUAD:
--- a/include/linux/mtd/spi-nor.h
+++ b/include/linux/mtd/spi-nor.h
@@ -10,6 +10,23 @@
#ifndef __LINUX_MTD_SPI_NOR_H
#define __LINUX_MTD_SPI_NOR_H
+#include <linux/bitops.h>
+#include <linux/mtd/cfi.h>
+
+/*
+ * Manufacturer IDs
+ *
+ * The first byte returned from the flash after sending opcode SPINOR_OP_RDID.
+ * Sometimes these are the same as CFI IDs, but sometimes they aren't.
+ */
+#define SNOR_MFR_ATMEL CFI_MFR_ATMEL
+#define SNOR_MFR_INTEL CFI_MFR_INTEL
+#define SNOR_MFR_MICRON CFI_MFR_ST /* ST Micro <--> Micron */
+#define SNOR_MFR_MACRONIX CFI_MFR_MACRONIX
+#define SNOR_MFR_SPANSION CFI_MFR_AMD
+#define SNOR_MFR_SST CFI_MFR_SST
+#define SNOR_MFR_WINBOND 0xef
+
/*
* Note on opcode nomenclature: some opcodes have a format like
* SPINOR_OP_FUNCTION{4,}_x_y_z. The numbers x, y, and z stand for the number
@@ -61,24 +78,24 @@
#define SPINOR_OP_WD_EVCR 0x61 /* Write EVCR register */
/* Status Register bits. */
-#define SR_WIP 1 /* Write in progress */
-#define SR_WEL 2 /* Write enable latch */
+#define SR_WIP BIT(0) /* Write in progress */
+#define SR_WEL BIT(1) /* Write enable latch */
/* meaning of other SR_* bits may differ between vendors */
-#define SR_BP0 4 /* Block protect 0 */
-#define SR_BP1 8 /* Block protect 1 */
-#define SR_BP2 0x10 /* Block protect 2 */
-#define SR_SRWD 0x80 /* SR write protect */
+#define SR_BP0 BIT(2) /* Block protect 0 */
+#define SR_BP1 BIT(3) /* Block protect 1 */
+#define SR_BP2 BIT(4) /* Block protect 2 */
+#define SR_SRWD BIT(7) /* SR write protect */
-#define SR_QUAD_EN_MX 0x40 /* Macronix Quad I/O */
+#define SR_QUAD_EN_MX BIT(6) /* Macronix Quad I/O */
/* Enhanced Volatile Configuration Register bits */
-#define EVCR_QUAD_EN_MICRON 0x80 /* Micron Quad I/O */
+#define EVCR_QUAD_EN_MICRON BIT(7) /* Micron Quad I/O */
/* Flag Status Register bits */
-#define FSR_READY 0x80
+#define FSR_READY BIT(7)
/* Configuration Register bits. */
-#define CR_QUAD_EN_SPAN 0x2 /* Spansion Quad I/O */
+#define CR_QUAD_EN_SPAN BIT(1) /* Spansion Quad I/O */
enum read_mode {
SPI_NOR_NORMAL = 0,
@@ -87,33 +104,6 @@ enum read_mode {
SPI_NOR_QUAD,
};
-/**
- * struct spi_nor_xfer_cfg - Structure for defining a Serial Flash transfer
- * @wren: command for "Write Enable", or 0x00 for not required
- * @cmd: command for operation
- * @cmd_pins: number of pins to send @cmd (1, 2, 4)
- * @addr: address for operation
- * @addr_pins: number of pins to send @addr (1, 2, 4)
- * @addr_width: number of address bytes
- * (3,4, or 0 for address not required)
- * @mode: mode data
- * @mode_pins: number of pins to send @mode (1, 2, 4)
- * @mode_cycles: number of mode cycles (0 for mode not required)
- * @dummy_cycles: number of dummy cycles (0 for dummy not required)
- */
-struct spi_nor_xfer_cfg {
- u8 wren;
- u8 cmd;
- u8 cmd_pins;
- u32 addr;
- u8 addr_pins;
- u8 addr_width;
- u8 mode;
- u8 mode_pins;
- u8 mode_cycles;
- u8 dummy_cycles;
-};
-
#define SPI_NOR_MAX_CMD_SIZE 8
enum spi_nor_ops {
SPI_NOR_OPS_READ = 0,
@@ -127,11 +117,14 @@ enum spi_nor_option_flags {
SNOR_F_USE_FSR = BIT(0),
};
+struct mtd_info;
+
/**
* struct spi_nor - Structure for defining a the SPI NOR layer
* @mtd: point to a mtd_info structure
* @lock: the lock for the read/write/erase/lock/unlock operations
* @dev: point to a spi device, or a spi nor controller device.
+ * @flash_node: point to a device node describing this flash instance.
* @page_size: the page size of the SPI NOR
* @addr_width: number of address bytes
* @erase_opcode: the opcode for erasing a sector
@@ -141,28 +134,28 @@ enum spi_nor_option_flags {
* @flash_read: the mode of the read
* @sst_write_second: used by the SST write operation
* @flags: flag options for the current SPI-NOR (SNOR_F_*)
- * @cfg: used by the read_xfer/write_xfer
* @cmd_buf: used by the write_reg
* @prepare: [OPTIONAL] do some preparations for the
* read/write/erase/lock/unlock operations
* @unprepare: [OPTIONAL] do some post work after the
* read/write/erase/lock/unlock operations
- * @read_xfer: [OPTIONAL] the read fundamental primitive
- * @write_xfer: [OPTIONAL] the writefundamental primitive
* @read_reg: [DRIVER-SPECIFIC] read out the register
* @write_reg: [DRIVER-SPECIFIC] write data to the register
* @read: [DRIVER-SPECIFIC] read data from the SPI NOR
* @write: [DRIVER-SPECIFIC] write data to the SPI NOR
* @erase: [DRIVER-SPECIFIC] erase a sector of the SPI NOR
* at the offset @offs
- * @lock: [FLASH-SPECIFIC] lock a region of the SPI NOR
- * @unlock: [FLASH-SPECIFIC] unlock a region of the SPI NOR
+ * @flash_lock: [FLASH-SPECIFIC] lock a region of the SPI NOR
+ * @flash_unlock: [FLASH-SPECIFIC] unlock a region of the SPI NOR
+ * @flash_is_locked: [FLASH-SPECIFIC] check if a region of the SPI NOR is
+ * completely locked
* @priv: the private data
*/
struct spi_nor {
- struct mtd_info *mtd;
+ struct mtd_info mtd;
struct mutex lock;
struct device *dev;
+ struct device_node *flash_node;
u32 page_size;
u8 addr_width;
u8 erase_opcode;
@@ -172,18 +165,12 @@ struct spi_nor {
enum read_mode flash_read;
bool sst_write_second;
u32 flags;
- struct spi_nor_xfer_cfg cfg;
u8 cmd_buf[SPI_NOR_MAX_CMD_SIZE];
int (*prepare)(struct spi_nor *nor, enum spi_nor_ops ops);
void (*unprepare)(struct spi_nor *nor, enum spi_nor_ops ops);
- int (*read_xfer)(struct spi_nor *nor, struct spi_nor_xfer_cfg *cfg,
- u8 *buf, size_t len);
- int (*write_xfer)(struct spi_nor *nor, struct spi_nor_xfer_cfg *cfg,
- u8 *buf, size_t len);
int (*read_reg)(struct spi_nor *nor, u8 opcode, u8 *buf, int len);
- int (*write_reg)(struct spi_nor *nor, u8 opcode, u8 *buf, int len,
- int write_enable);
+ int (*write_reg)(struct spi_nor *nor, u8 opcode, u8 *buf, int len);
int (*read)(struct spi_nor *nor, loff_t from,
size_t len, size_t *retlen, u_char *read_buf);
@@ -193,6 +180,7 @@ struct spi_nor {
int (*flash_lock)(struct spi_nor *nor, loff_t ofs, uint64_t len);
int (*flash_unlock)(struct spi_nor *nor, loff_t ofs, uint64_t len);
+ int (*flash_is_locked)(struct spi_nor *nor, loff_t ofs, uint64_t len);
void *priv;
};

@ -1,101 +0,0 @@
From: Felix Fietkau <nbd@openwrt.org>
Date: Sun, 24 Jan 2016 01:03:51 +0100
Subject: [PATCH] MIPS: fix cache flushing for highmem pages
Most cache flush ops were no-op for highmem pages. This led to nasty
segfaults and (in the case of page_address(page) == NULL) kernel
crashes.
Fix this by always flushing highmem pages using kmap/kunmap_atomic
around the actual cache flush. This might be a bit inefficient, but at
least it's stable.
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
---
--- a/arch/mips/mm/cache.c
+++ b/arch/mips/mm/cache.c
@@ -14,6 +14,7 @@
#include <linux/sched.h>
#include <linux/syscalls.h>
#include <linux/mm.h>
+#include <linux/highmem.h>
#include <asm/cacheflush.h>
#include <asm/processor.h>
@@ -78,18 +79,29 @@ SYSCALL_DEFINE3(cacheflush, unsigned lon
return 0;
}
+static void
+flush_highmem_page(struct page *page)
+{
+ void *addr = kmap_atomic(page);
+ flush_data_cache_page((unsigned long)addr);
+ kunmap_atomic(addr);
+}
+
void __flush_dcache_page(struct page *page)
{
struct address_space *mapping = page_mapping(page);
unsigned long addr;
- if (PageHighMem(page))
- return;
if (mapping && !mapping_mapped(mapping)) {
SetPageDcacheDirty(page);
return;
}
+ if (PageHighMem(page)) {
+ flush_highmem_page(page);
+ return;
+ }
+
/*
* We could delay the flush for the !page_mapping case too. But that
* case is for exec env/arg pages and those are %99 certainly going to
@@ -105,6 +117,11 @@ void __flush_anon_page(struct page *page
{
unsigned long addr = (unsigned long) page_address(page);
+ if (PageHighMem(page)) {
+ flush_highmem_page(page);
+ return;
+ }
+
if (pages_do_alias(addr, vmaddr)) {
if (page_mapped(page) && !Page_dcache_dirty(page)) {
void *kaddr;
@@ -123,8 +140,10 @@ void __flush_icache_page(struct vm_area_
{
unsigned long addr;
- if (PageHighMem(page))
+ if (PageHighMem(page)) {
+ flush_highmem_page(page);
return;
+ }
addr = (unsigned long) page_address(page);
flush_data_cache_page(addr);
@@ -142,12 +161,17 @@ void __update_cache(struct vm_area_struc
if (unlikely(!pfn_valid(pfn)))
return;
page = pfn_to_page(pfn);
- if (page_mapping(page) && Page_dcache_dirty(page)) {
+ if (!Page_dcache_dirty(page) || !page_mapping(page))
+ return;
+
+ if (PageHighMem(page)) {
+ flush_highmem_page(page);
+ } else {
addr = (unsigned long) page_address(page);
if (exec || pages_do_alias(addr, address & PAGE_MASK))
flush_data_cache_page(addr);
- ClearPageDcacheDirty(page);
}
+ ClearPageDcacheDirty(page);
}
unsigned long _page_cachable_default;

@ -1,82 +0,0 @@
From 1e311820ec3055e3f08e687de6564692a7cec675 Mon Sep 17 00:00:00 2001
From: Florian Fainelli <florian@openwrt.org>
Date: Mon, 28 Jan 2013 20:06:29 +0100
Subject: [PATCH 11/12] USB: EHCI: add ignore_oc flag to disable overcurrent
checking
This patch adds an ignore_oc flag which can be set by EHCI controller
not supporting or wanting to disable overcurrent checking. The EHCI
platform data in include/linux/usb/ehci_pdriver.h is also augmented to
take advantage of this new flag.
Signed-off-by: Florian Fainelli <florian@openwrt.org>
---
drivers/usb/host/ehci-hcd.c | 2 +-
drivers/usb/host/ehci-hub.c | 4 ++--
drivers/usb/host/ehci-platform.c | 1 +
drivers/usb/host/ehci.h | 1 +
include/linux/usb/ehci_pdriver.h | 1 +
5 files changed, 6 insertions(+), 3 deletions(-)
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -639,7 +639,7 @@ static int ehci_run (struct usb_hcd *hcd
"USB %x.%x started, EHCI %x.%02x%s\n",
((ehci->sbrn & 0xf0)>>4), (ehci->sbrn & 0x0f),
temp >> 8, temp & 0xff,
- ignore_oc ? ", overcurrent ignored" : "");
+ (ignore_oc || ehci->ignore_oc) ? ", overcurrent ignored" : "");
ehci_writel(ehci, INTR_MASK,
&ehci->regs->intr_enable); /* Turn On Interrupts */
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -634,7 +634,7 @@ ehci_hub_status_data (struct usb_hcd *hc
* always set, seem to clear PORT_OCC and PORT_CSC when writing to
* PORT_POWER; that's surprising, but maybe within-spec.
*/
- if (!ignore_oc)
+ if (!ignore_oc && !ehci->ignore_oc)
mask = PORT_CSC | PORT_PEC | PORT_OCC;
else
mask = PORT_CSC | PORT_PEC;
@@ -996,7 +996,7 @@ int ehci_hub_control(
if (temp & PORT_PEC)
status |= USB_PORT_STAT_C_ENABLE << 16;
- if ((temp & PORT_OCC) && !ignore_oc){
+ if ((temp & PORT_OCC) && (!ignore_oc && !ehci->ignore_oc)){
status |= USB_PORT_STAT_C_OVERCURRENT << 16;
/*
--- a/drivers/usb/host/ehci-platform.c
+++ b/drivers/usb/host/ehci-platform.c
@@ -251,6 +251,8 @@ static int ehci_platform_probe(struct pl
hcd->has_tt = 1;
if (pdata->reset_on_resume)
priv->reset_on_resume = true;
+ if (pdata->ignore_oc)
+ ehci->ignore_oc = 1;
#ifndef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO
if (ehci->big_endian_mmio) {
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -227,6 +227,7 @@ struct ehci_hcd { /* one per controlle
unsigned frame_index_bug:1; /* MosChip (AKA NetMos) */
unsigned need_oc_pp_cycle:1; /* MPC834X port power */
unsigned imx28_write_fix:1; /* For Freescale i.MX28 */
+ unsigned ignore_oc:1;
/* required for usb32 quirk */
#define OHCI_CTRL_HCFS (3 << 6)
--- a/include/linux/usb/ehci_pdriver.h
+++ b/include/linux/usb/ehci_pdriver.h
@@ -49,6 +49,7 @@ struct usb_ehci_pdata {
unsigned no_io_watchdog:1;
unsigned reset_on_resume:1;
unsigned dma_mask_64:1;
+ unsigned ignore_oc:1;
/* Turn on all power and clocks */
int (*power_on)(struct platform_device *pdev);

@ -1,17 +0,0 @@
Fix a regression in the af_packet code that was breaking PPPoE
pppd sends packets with only a header and no payload.
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -2329,7 +2329,7 @@ static void tpacket_destruct_skb(struct
static bool ll_header_truncated(const struct net_device *dev, int len)
{
/* net device doesn't like empty head */
- if (unlikely(len <= dev->hard_header_len)) {
+ if (unlikely(len < dev->hard_header_len)) {
net_warn_ratelimited("%s: packet size is too short (%d <= %d)\n",
current->comm, len, dev->hard_header_len);
return true;

@ -1,86 +0,0 @@
From: Felix Fietkau <nbd@openwrt.org>
Date: Fri, 10 Apr 2015 13:35:29 +0200
Subject: [PATCH] jffs2: use .rename2 and add RENAME_WHITEOUT support
It is required for renames on overlayfs
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
---
--- a/fs/jffs2/dir.c
+++ b/fs/jffs2/dir.c
@@ -35,7 +35,7 @@ static int jffs2_mkdir (struct inode *,s
static int jffs2_rmdir (struct inode *,struct dentry *);
static int jffs2_mknod (struct inode *,struct dentry *,umode_t,dev_t);
static int jffs2_rename (struct inode *, struct dentry *,
- struct inode *, struct dentry *);
+ struct inode *, struct dentry *, unsigned int);
const struct file_operations jffs2_dir_operations =
{
@@ -57,7 +57,7 @@ const struct inode_operations jffs2_dir_
.mkdir = jffs2_mkdir,
.rmdir = jffs2_rmdir,
.mknod = jffs2_mknod,
- .rename = jffs2_rename,
+ .rename2 = jffs2_rename,
.get_acl = jffs2_get_acl,
.set_acl = jffs2_set_acl,
.setattr = jffs2_setattr,
@@ -757,8 +757,27 @@ static int jffs2_mknod (struct inode *di
return ret;
}
+static int jffs2_whiteout(struct inode *old_dir, struct dentry *old_dentry)
+{
+ struct dentry *wh;
+ int err;
+
+ wh = d_alloc(old_dentry->d_parent, &old_dentry->d_name);
+ if (!wh)
+ return -ENOMEM;
+
+ err = jffs2_mknod(old_dir, wh, S_IFCHR | WHITEOUT_MODE,
+ WHITEOUT_DEV);
+ if (err)
+ return err;
+
+ d_rehash(wh);
+ return 0;
+}
+
static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry,
- struct inode *new_dir_i, struct dentry *new_dentry)
+ struct inode *new_dir_i, struct dentry *new_dentry,
+ unsigned int flags)
{
int ret;
struct jffs2_sb_info *c = JFFS2_SB_INFO(old_dir_i->i_sb);
@@ -766,6 +785,9 @@ static int jffs2_rename (struct inode *o
uint8_t type;
uint32_t now;
+ if (flags & ~RENAME_WHITEOUT)
+ return -EINVAL;
+
/* The VFS will check for us and prevent trying to rename a
* file over a directory and vice versa, but if it's a directory,
* the VFS can't check whether the victim is empty. The filesystem
@@ -829,9 +851,14 @@ static int jffs2_rename (struct inode *o
if (d_is_dir(old_dentry) && !victim_f)
inc_nlink(new_dir_i);
- /* Unlink the original */
- ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i),
- old_dentry->d_name.name, old_dentry->d_name.len, NULL, now);
+ if (flags & RENAME_WHITEOUT)
+ /* Replace with whiteout */
+ ret = jffs2_whiteout(old_dir_i, old_dentry);
+ else
+ /* Unlink the original */
+ ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i),
+ old_dentry->d_name.name,
+ old_dentry->d_name.len, NULL, now);
/* We don't touch inode->i_nlink */

@ -1,58 +0,0 @@
From: Felix Fietkau <nbd@openwrt.org>
Date: Sat, 25 Apr 2015 12:41:32 +0200
Subject: [PATCH] jffs2: add RENAME_EXCHANGE support
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
---
--- a/fs/jffs2/dir.c
+++ b/fs/jffs2/dir.c
@@ -785,7 +785,7 @@ static int jffs2_rename (struct inode *o
uint8_t type;
uint32_t now;
- if (flags & ~RENAME_WHITEOUT)
+ if (flags & ~(RENAME_WHITEOUT | RENAME_EXCHANGE))
return -EINVAL;
/* The VFS will check for us and prevent trying to rename a
@@ -793,7 +793,7 @@ static int jffs2_rename (struct inode *o
* the VFS can't check whether the victim is empty. The filesystem
* needs to do that for itself.
*/
- if (d_really_is_positive(new_dentry)) {
+ if (d_really_is_positive(new_dentry) && !(flags & RENAME_EXCHANGE)) {
victim_f = JFFS2_INODE_INFO(d_inode(new_dentry));
if (d_is_dir(new_dentry)) {
struct jffs2_full_dirent *fd;
@@ -828,7 +828,7 @@ static int jffs2_rename (struct inode *o
if (ret)
return ret;
- if (victim_f) {
+ if (victim_f && !(flags & RENAME_EXCHANGE)) {
/* There was a victim. Kill it off nicely */
if (d_is_dir(new_dentry))
clear_nlink(d_inode(new_dentry));
@@ -854,6 +854,12 @@ static int jffs2_rename (struct inode *o
if (flags & RENAME_WHITEOUT)
/* Replace with whiteout */
ret = jffs2_whiteout(old_dir_i, old_dentry);
+ else if (flags & RENAME_EXCHANGE)
+ /* Replace the original */
+ ret = jffs2_do_link(c, JFFS2_INODE_INFO(old_dir_i),
+ d_inode(new_dentry)->i_ino, type,
+ old_dentry->d_name.name, old_dentry->d_name.len,
+ now);
else
/* Unlink the original */
ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i),
@@ -880,7 +886,7 @@ static int jffs2_rename (struct inode *o
return ret;
}
- if (d_is_dir(old_dentry))
+ if (d_is_dir(old_dentry) && !(flags & RENAME_EXCHANGE))
drop_nlink(old_dir_i);
new_dir_i->i_mtime = new_dir_i->i_ctime = old_dir_i->i_mtime = old_dir_i->i_ctime = ITIME(now);

@ -1,54 +0,0 @@
From: Stephen Hemminger <stephen@networkplumber.org>
Subject: bridge: allow receiption on disabled port
When an ethernet device is enslaved to a bridge, and the bridge STP
detects loss of carrier (or operational state down), then normally
packet receiption is blocked.
This breaks control applications like WPA which maybe expecting to
receive packets to negotiate to bring link up. The bridge needs to
block forwarding packets from these disabled ports, but there is no
hard requirement to not allow local packet delivery.
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
--- a/net/bridge/br_input.c
+++ b/net/bridge/br_input.c
@@ -211,11 +211,13 @@ EXPORT_SYMBOL_GPL(br_handle_frame_finish
static int br_handle_local_finish(struct sock *sk, struct sk_buff *skb)
{
struct net_bridge_port *p = br_port_get_rcu(skb->dev);
- u16 vid = 0;
+ if (p->state != BR_STATE_DISABLED) {
+ u16 vid = 0;
- /* check if vlan is allowed, to avoid spoofing */
- if (p->flags & BR_LEARNING && br_should_learn(p, skb, &vid))
- br_fdb_update(p->br, p, eth_hdr(skb)->h_source, vid, false);
+ /* check if vlan is allowed, to avoid spoofing */
+ if (p->flags & BR_LEARNING && br_should_learn(p, skb, &vid))
+ br_fdb_update(p->br, p, eth_hdr(skb)->h_source, vid, false);
+ }
return 0; /* process further */
}
@@ -289,6 +291,18 @@ rx_handler_result_t br_handle_frame(stru
forward:
switch (p->state) {
+ case BR_STATE_DISABLED:
+ if (ether_addr_equal(p->br->dev->dev_addr, dest))
+ skb->pkt_type = PACKET_HOST;
+
+ if (NF_HOOK(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING, NULL, skb, skb->dev, NULL,
+ br_handle_local_finish))
+ break;
+
+ BR_INPUT_SKB_CB(skb)->brdev = p->br->dev;
+ br_pass_frame_up(skb);
+ break;
+
case BR_STATE_FORWARDING:
rhook = rcu_dereference(br_should_route_hook);
if (rhook) {

@ -1,778 +0,0 @@
From 2c58080407554e1bac8fd50d23cb02420524caed Mon Sep 17 00:00:00 2001
From: Felix Fietkau <nbd@openwrt.org>
Date: Mon, 12 Aug 2013 12:50:22 +0200
Subject: [PATCH] MIPS: partially inline dma ops
Several DMA ops are no-op on many platforms, and the indirection through
the mips_dma_map_ops function table is causing the compiler to emit
unnecessary code.
Inlining visibly improves network performance in my tests (on a 24Kc
based system), and also slightly reduces code size of a few drivers.
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
---
arch/mips/Kconfig | 4 +
arch/mips/include/asm/dma-mapping.h | 360 +++++++++++++++++++++++++++++++++++-
arch/mips/mm/dma-default.c | 163 ++--------------
3 files changed, 373 insertions(+), 154 deletions(-)
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -1586,6 +1586,7 @@ config CPU_CAVIUM_OCTEON
select USB_EHCI_BIG_ENDIAN_MMIO if CPU_BIG_ENDIAN
select USB_OHCI_BIG_ENDIAN_MMIO if CPU_BIG_ENDIAN
select MIPS_L1_CACHE_SHIFT_7
+ select SYS_HAS_DMA_OPS
help
The Cavium Octeon processor is a highly integrated chip containing
many ethernet hardware widgets for networking tasks. The processor
@@ -1881,6 +1882,9 @@ config MIPS_MALTA_PM
bool
default y
+config SYS_HAS_DMA_OPS
+ bool
+
#
# CPU may reorder R->R, R->W, W->R, W->W
# Reordering beyond LL and SC is handled in WEAK_REORDERING_BEYOND_LLSC
--- a/arch/mips/include/asm/dma-mapping.h
+++ b/arch/mips/include/asm/dma-mapping.h
@@ -1,9 +1,16 @@
#ifndef _ASM_DMA_MAPPING_H
#define _ASM_DMA_MAPPING_H
+#include <linux/kmemcheck.h>
+#include <linux/bug.h>
#include <linux/scatterlist.h>
+#include <linux/dma-debug.h>
+#include <linux/dma-attrs.h>
+
#include <asm/dma-coherence.h>
#include <asm/cache.h>
+#include <asm/cpu-type.h>
+#include <asm-generic/dma-coherent.h>
#ifndef CONFIG_SGI_IP27 /* Kludge to fix 2.6.39 build for IP27 */
#include <dma-coherence.h>
@@ -11,12 +18,53 @@
extern struct dma_map_ops *mips_dma_map_ops;
+void __dma_sync(struct page *page, unsigned long offset, size_t size,
+ enum dma_data_direction direction);
+void *mips_dma_alloc_coherent(struct device *dev, size_t size,
+ dma_addr_t *dma_handle, gfp_t gfp,
+ struct dma_attrs *attrs);
+void mips_dma_free_coherent(struct device *dev, size_t size, void *vaddr,
+ dma_addr_t dma_handle, struct dma_attrs *attrs);
+
static inline struct dma_map_ops *get_dma_ops(struct device *dev)
{
+#ifdef CONFIG_SYS_HAS_DMA_OPS
if (dev && dev->archdata.dma_ops)
return dev->archdata.dma_ops;
else
return mips_dma_map_ops;
+#else
+ return NULL;
+#endif
+}
+
+/*
+ * The affected CPUs below in 'cpu_needs_post_dma_flush()' can
+ * speculatively fill random cachelines with stale data at any time,
+ * requiring an extra flush post-DMA.
+ *
+ * Warning on the terminology - Linux calls an uncached area coherent;
+ * MIPS terminology calls memory areas with hardware maintained coherency
+ * coherent.
+ *
+ * Note that the R14000 and R16000 should also be checked for in this
+ * condition. However this function is only called on non-I/O-coherent
+ * systems and only the R10000 and R12000 are used in such systems, the
+ * SGI IP28 Indigo² rsp. SGI IP32 aka O2.
+ */
+static inline int cpu_needs_post_dma_flush(struct device *dev)
+{
+ return !plat_device_is_coherent(dev) &&
+ (boot_cpu_type() == CPU_R10000 ||
+ boot_cpu_type() == CPU_R12000 ||
+ boot_cpu_type() == CPU_BMIPS5000);
+}
+
+static inline struct page *dma_addr_to_page(struct device *dev,
+ dma_addr_t dma_addr)
+{
+ return pfn_to_page(
+ plat_dma_addr_to_phys(dev, dma_addr) >> PAGE_SHIFT);
}
static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size)
@@ -29,9 +77,399 @@ static inline bool dma_capable(struct de
static inline void dma_mark_clean(void *addr, size_t size) {}
-#include <asm-generic/dma-mapping-common.h>
+static inline dma_addr_t dma_map_single_attrs(struct device *dev, void *ptr,
+ size_t size,
+ enum dma_data_direction dir,
+ struct dma_attrs *attrs)
+{
+ struct dma_map_ops *ops = get_dma_ops(dev);
+ unsigned long offset = (unsigned long)ptr & ~PAGE_MASK;
+ struct page *page = virt_to_page(ptr);
+ dma_addr_t addr;
+
+ kmemcheck_mark_initialized(ptr, size);
+ BUG_ON(!valid_dma_direction(dir));
+ if (ops) {
+ addr = ops->map_page(dev, page, offset, size, dir, attrs);
+ } else {
+ if (!plat_device_is_coherent(dev))
+ __dma_sync(page, offset, size, dir);
+
+ addr = plat_map_dma_mem_page(dev, page) + offset;
+ }
+ debug_dma_map_page(dev, page, offset, size, dir, addr, true);
+ return addr;
+}
+
+static inline void dma_unmap_single_attrs(struct device *dev, dma_addr_t addr,
+ size_t size,
+ enum dma_data_direction dir,
+ struct dma_attrs *attrs)
+{
+ struct dma_map_ops *ops = get_dma_ops(dev);
+
+ BUG_ON(!valid_dma_direction(dir));
+ if (ops) {
+ ops->unmap_page(dev, addr, size, dir, attrs);
+ } else {
+ if (cpu_needs_post_dma_flush(dev))
+ __dma_sync(dma_addr_to_page(dev, addr),
+ addr & ~PAGE_MASK, size, dir);
+ plat_post_dma_flush(dev);
+ plat_unmap_dma_mem(dev, addr, size, dir);
+ }
+ debug_dma_unmap_page(dev, addr, size, dir, true);
+}
+
+/*
+ * dma_maps_sg_attrs returns 0 on error and > 0 on success.
+ * It should never return a value < 0.
+ */
+static inline int dma_map_sg_attrs(struct device *dev, struct scatterlist *sg,
+ int nents, enum dma_data_direction dir,
+ struct dma_attrs *attrs)
+{
+ struct dma_map_ops *ops = get_dma_ops(dev);
+ int i, ents;
+ struct scatterlist *s;
+
+ for_each_sg(sg, s, nents, i)
+ kmemcheck_mark_initialized(sg_virt(s), s->length);
+ BUG_ON(!valid_dma_direction(dir));
+ if (ops) {
+ ents = ops->map_sg(dev, sg, nents, dir, attrs);
+ } else {
+ for_each_sg(sg, s, nents, i) {
+ struct page *page = sg_page(s);
+
+ if (!plat_device_is_coherent(dev))
+ __dma_sync(page, s->offset, s->length, dir);
+#ifdef CONFIG_NEED_SG_DMA_LENGTH
+ s->dma_length = s->length;
+#endif
+ s->dma_address =
+ plat_map_dma_mem_page(dev, page) + s->offset;
+ }
+ ents = nents;
+ }
+ BUG_ON(ents < 0);
+ debug_dma_map_sg(dev, sg, nents, ents, dir);
+
+ return ents;
+}
+
+static inline void dma_unmap_sg_attrs(struct device *dev, struct scatterlist *sg,
+ int nents, enum dma_data_direction dir,
+ struct dma_attrs *attrs)
+{
+ struct dma_map_ops *ops = get_dma_ops(dev);
+ struct scatterlist *s;
+ int i;
+
+ BUG_ON(!valid_dma_direction(dir));
+ debug_dma_unmap_sg(dev, sg, nents, dir);
+ if (ops) {
+ ops->unmap_sg(dev, sg, nents, dir, attrs);
+ return;
+ }
+ for_each_sg(sg, s, nents, i) {
+ if (!plat_device_is_coherent(dev) && dir != DMA_TO_DEVICE)
+ __dma_sync(sg_page(s), s->offset, s->length, dir);
+ plat_unmap_dma_mem(dev, s->dma_address, s->length, dir);
+ }
+}
+
+static inline dma_addr_t dma_map_page(struct device *dev, struct page *page,
+ size_t offset, size_t size,
+ enum dma_data_direction dir)
+{
+ struct dma_map_ops *ops = get_dma_ops(dev);
+ dma_addr_t addr;
+
+ kmemcheck_mark_initialized(page_address(page) + offset, size);
+ BUG_ON(!valid_dma_direction(dir));
+ if (ops) {
+ addr = ops->map_page(dev, page, offset, size, dir, NULL);
+ } else {
+ if (!plat_device_is_coherent(dev))
+ __dma_sync(page, offset, size, dir);
+
+ addr = plat_map_dma_mem_page(dev, page) + offset;
+ }
+ debug_dma_map_page(dev, page, offset, size, dir, addr, false);
+
+ return addr;
+}
+
+static inline void dma_unmap_page(struct device *dev, dma_addr_t addr,
+ size_t size, enum dma_data_direction dir)
+{
+ struct dma_map_ops *ops = get_dma_ops(dev);
+
+ BUG_ON(!valid_dma_direction(dir));
+ if (ops) {
+ ops->unmap_page(dev, addr, size, dir, NULL);
+ } else {
+ if (cpu_needs_post_dma_flush(dev))
+ __dma_sync(dma_addr_to_page(dev, addr),
+ addr & ~PAGE_MASK, size, dir);
+ plat_post_dma_flush(dev);
+ plat_unmap_dma_mem(dev, addr, size, dir);
+ }
+ debug_dma_unmap_page(dev, addr, size, dir, false);
+}
+
+static inline void dma_sync_single_for_cpu(struct device *dev, dma_addr_t addr,
+ size_t size,
+ enum dma_data_direction dir)
+{
+ struct dma_map_ops *ops = get_dma_ops(dev);
+
+ BUG_ON(!valid_dma_direction(dir));
+ if (ops) {
+ ops->sync_single_for_cpu(dev, addr, size, dir);
+ } else {
+ if (cpu_needs_post_dma_flush(dev))
+ __dma_sync(dma_addr_to_page(dev, addr),
+ addr & ~PAGE_MASK, size, dir);
+ plat_post_dma_flush(dev);
+ }
+ debug_dma_sync_single_for_cpu(dev, addr, size, dir);
+}
+
+static inline void dma_sync_single_for_device(struct device *dev,
+ dma_addr_t addr, size_t size,
+ enum dma_data_direction dir)
+{
+ struct dma_map_ops *ops = get_dma_ops(dev);
+
+ BUG_ON(!valid_dma_direction(dir));
+ if (ops)
+ ops->sync_single_for_device(dev, addr, size, dir);
+ else if (!plat_device_is_coherent(dev))
+ __dma_sync(dma_addr_to_page(dev, addr),
+ addr & ~PAGE_MASK, size, dir);
+ debug_dma_sync_single_for_device(dev, addr, size, dir);
+}
+
+static inline void dma_sync_single_range_for_cpu(struct device *dev,
+ dma_addr_t addr,
+ unsigned long offset,
+ size_t size,
+ enum dma_data_direction dir)
+{
+ const struct dma_map_ops *ops = get_dma_ops(dev);
+
+ BUG_ON(!valid_dma_direction(dir));
+ if (ops) {
+ ops->sync_single_for_cpu(dev, addr + offset, size, dir);
+ } else {
+ if (cpu_needs_post_dma_flush(dev))
+ __dma_sync(dma_addr_to_page(dev, addr + offset),
+ (addr + offset) & ~PAGE_MASK, size, dir);
+ plat_post_dma_flush(dev);
+ }
+
+ debug_dma_sync_single_range_for_cpu(dev, addr, offset, size, dir);
+}
+
+static inline void dma_sync_single_range_for_device(struct device *dev,
+ dma_addr_t addr,
+ unsigned long offset,
+ size_t size,
+ enum dma_data_direction dir)
+{
+ const struct dma_map_ops *ops = get_dma_ops(dev);
+
+ BUG_ON(!valid_dma_direction(dir));
+ if (ops)
+ ops->sync_single_for_device(dev, addr + offset, size, dir);
+ else if (!plat_device_is_coherent(dev))
+ __dma_sync(dma_addr_to_page(dev, addr + offset),
+ (addr + offset) & ~PAGE_MASK, size, dir);
+ debug_dma_sync_single_range_for_device(dev, addr, offset, size, dir);
+}
+
+static inline void
+dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg,
+ int nelems, enum dma_data_direction dir)
+{
+ struct dma_map_ops *ops = get_dma_ops(dev);
+ struct scatterlist *s;
+ int i;
+
+ BUG_ON(!valid_dma_direction(dir));
+ if (ops) {
+ ops->sync_sg_for_cpu(dev, sg, nelems, dir);
+ } else if (cpu_needs_post_dma_flush(dev)) {
+ for_each_sg(sg, s, nelems, i)
+ __dma_sync(sg_page(s), s->offset, s->length, dir);
+ }
+ plat_post_dma_flush(dev);
+ debug_dma_sync_sg_for_cpu(dev, sg, nelems, dir);
+}
+
+static inline void
+dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg,
+ int nelems, enum dma_data_direction dir)
+{
+ struct dma_map_ops *ops = get_dma_ops(dev);
+ struct scatterlist *s;
+ int i;
+
+ BUG_ON(!valid_dma_direction(dir));
+ if (ops) {
+ ops->sync_sg_for_device(dev, sg, nelems, dir);
+ } else if (!plat_device_is_coherent(dev)) {
+ for_each_sg(sg, s, nelems, i)
+ __dma_sync(sg_page(s), s->offset, s->length, dir);
+ }
+ debug_dma_sync_sg_for_device(dev, sg, nelems, dir);
+
+}
+
+#define dma_map_single(d, a, s, r) dma_map_single_attrs(d, a, s, r, NULL)
+#define dma_unmap_single(d, a, s, r) dma_unmap_single_attrs(d, a, s, r, NULL)
+#define dma_map_sg(d, s, n, r) dma_map_sg_attrs(d, s, n, r, NULL)
+#define dma_unmap_sg(d, s, n, r) dma_unmap_sg_attrs(d, s, n, r, NULL)
+
+extern int dma_common_mmap(struct device *dev, struct vm_area_struct *vma,
+ void *cpu_addr, dma_addr_t dma_addr, size_t size);
+
+/**
+ * dma_mmap_attrs - map a coherent DMA allocation into user space
+ * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
+ * @vma: vm_area_struct describing requested user mapping
+ * @cpu_addr: kernel CPU-view address returned from dma_alloc_attrs
+ * @handle: device-view address returned from dma_alloc_attrs
+ * @size: size of memory originally requested in dma_alloc_attrs
+ * @attrs: attributes of mapping properties requested in dma_alloc_attrs
+ *
+ * Map a coherent DMA buffer previously allocated by dma_alloc_attrs
+ * into user space. The coherent DMA buffer must not be freed by the
+ * driver until the user space mapping has been released.
+ */
+static inline int
+dma_mmap_attrs(struct device *dev, struct vm_area_struct *vma, void *cpu_addr,
+ dma_addr_t dma_addr, size_t size, struct dma_attrs *attrs)
+{
+ struct dma_map_ops *ops = get_dma_ops(dev);
+ BUG_ON(!ops);
+ if (ops && ops->mmap)
+ return ops->mmap(dev, vma, cpu_addr, dma_addr, size, attrs);
+ return dma_common_mmap(dev, vma, cpu_addr, dma_addr, size);
+}
+
+#define dma_mmap_coherent(d, v, c, h, s) dma_mmap_attrs(d, v, c, h, s, NULL)
+
+int
+dma_common_get_sgtable(struct device *dev, struct sg_table *sgt,
+ void *cpu_addr, dma_addr_t dma_addr, size_t size);
+
+static inline int
+dma_get_sgtable_attrs(struct device *dev, struct sg_table *sgt, void *cpu_addr,
+ dma_addr_t dma_addr, size_t size, struct dma_attrs *attrs)
+{
+ struct dma_map_ops *ops = get_dma_ops(dev);
+ BUG_ON(!ops);
+ if (ops && ops->get_sgtable)
+ return ops->get_sgtable(dev, sgt, cpu_addr, dma_addr, size,
+ attrs);
+ return dma_common_get_sgtable(dev, sgt, cpu_addr, dma_addr, size);
+}
+
+#define dma_get_sgtable(d, t, v, h, s) dma_get_sgtable_attrs(d, t, v, h, s, NULL)
+
+static inline int dma_supported(struct device *dev, u64 mask)
+{
+ struct dma_map_ops *ops = get_dma_ops(dev);
+ if (ops)
+ return ops->dma_supported(dev, mask);
+ return plat_dma_supported(dev, mask);
+}
+
+static inline int dma_mapping_error(struct device *dev, u64 mask)
+{
+ struct dma_map_ops *ops = get_dma_ops(dev);
+
+ debug_dma_mapping_error(dev, mask);
+ if (ops)
+ return ops->mapping_error(dev, mask);
+ return 0;
+}
+
+static inline int
+dma_set_mask(struct device *dev, u64 mask)
+{
+ struct dma_map_ops *ops = get_dma_ops(dev);
+
+ if(!dev->dma_mask || !dma_supported(dev, mask))
+ return -EIO;
+
+ if (ops && ops->set_dma_mask)
+ return ops->set_dma_mask(dev, mask);
+
+ *dev->dma_mask = mask;
+
+ return 0;
+}
extern void dma_cache_sync(struct device *dev, void *vaddr, size_t size,
enum dma_data_direction direction);
+#define dma_alloc_coherent(d,s,h,f) dma_alloc_attrs(d,s,h,f,NULL)
+
+static inline void *dma_alloc_attrs(struct device *dev, size_t size,
+ dma_addr_t *dma_handle, gfp_t gfp,
+ struct dma_attrs *attrs)
+{
+ void *ret;
+ struct dma_map_ops *ops = get_dma_ops(dev);
+
+ if (ops)
+ ret = ops->alloc(dev, size, dma_handle, gfp, attrs);
+ else
+ ret = mips_dma_alloc_coherent(dev, size, dma_handle, gfp,
+ attrs);
+
+ debug_dma_alloc_coherent(dev, size, *dma_handle, ret);
+
+ return ret;
+}
+
+#define dma_free_coherent(d,s,c,h) dma_free_attrs(d,s,c,h,NULL)
+
+static inline void dma_free_attrs(struct device *dev, size_t size,
+ void *vaddr, dma_addr_t dma_handle,
+ struct dma_attrs *attrs)
+{
+ struct dma_map_ops *ops = get_dma_ops(dev);
+
+ if (ops)
+ ops->free(dev, size, vaddr, dma_handle, attrs);
+ else
+ mips_dma_free_coherent(dev, size, vaddr, dma_handle, attrs);
+
+ debug_dma_free_coherent(dev, size, vaddr, dma_handle);
+}
+
+static inline void *dma_alloc_noncoherent(struct device *dev, size_t size,
+ dma_addr_t *dma_handle, gfp_t gfp)
+{
+ DEFINE_DMA_ATTRS(attrs);
+
+ dma_set_attr(DMA_ATTR_NON_CONSISTENT, &attrs);
+ return dma_alloc_attrs(dev, size, dma_handle, gfp, &attrs);
+}
+
+static inline void dma_free_noncoherent(struct device *dev, size_t size,
+ void *cpu_addr, dma_addr_t dma_handle)
+{
+ DEFINE_DMA_ATTRS(attrs);
+
+ dma_set_attr(DMA_ATTR_NON_CONSISTENT, &attrs);
+ dma_free_attrs(dev, size, cpu_addr, dma_handle, &attrs);
+}
+
+
#endif /* _ASM_DMA_MAPPING_H */
--- a/arch/mips/mm/dma-default.c
+++ b/arch/mips/mm/dma-default.c
@@ -46,35 +46,6 @@ static int __init setnocoherentio(char *
early_param("nocoherentio", setnocoherentio);
#endif
-static inline struct page *dma_addr_to_page(struct device *dev,
- dma_addr_t dma_addr)
-{
- return pfn_to_page(
- plat_dma_addr_to_phys(dev, dma_addr) >> PAGE_SHIFT);
-}
-
-/*
- * The affected CPUs below in 'cpu_needs_post_dma_flush()' can
- * speculatively fill random cachelines with stale data at any time,
- * requiring an extra flush post-DMA.
- *
- * Warning on the terminology - Linux calls an uncached area coherent;
- * MIPS terminology calls memory areas with hardware maintained coherency
- * coherent.
- *
- * Note that the R14000 and R16000 should also be checked for in this
- * condition. However this function is only called on non-I/O-coherent
- * systems and only the R10000 and R12000 are used in such systems, the
- * SGI IP28 Indigo² rsp. SGI IP32 aka O2.
- */
-static inline int cpu_needs_post_dma_flush(struct device *dev)
-{
- return !plat_device_is_coherent(dev) &&
- (boot_cpu_type() == CPU_R10000 ||
- boot_cpu_type() == CPU_R12000 ||
- boot_cpu_type() == CPU_BMIPS5000);
-}
-
static gfp_t massage_gfp_flags(const struct device *dev, gfp_t gfp)
{
gfp_t dma_flag;
@@ -129,7 +100,7 @@ static void *mips_dma_alloc_noncoherent(
return ret;
}
-static void *mips_dma_alloc_coherent(struct device *dev, size_t size,
+void *mips_dma_alloc_coherent(struct device *dev, size_t size,
dma_addr_t * dma_handle, gfp_t gfp, struct dma_attrs *attrs)
{
void *ret;
@@ -165,6 +136,7 @@ static void *mips_dma_alloc_coherent(str
return ret;
}
+EXPORT_SYMBOL(mips_dma_alloc_coherent);
static void mips_dma_free_noncoherent(struct device *dev, size_t size,
@@ -174,7 +146,7 @@ static void mips_dma_free_noncoherent(st
free_pages((unsigned long) vaddr, get_order(size));
}
-static void mips_dma_free_coherent(struct device *dev, size_t size, void *vaddr,
+void mips_dma_free_coherent(struct device *dev, size_t size, void *vaddr,
dma_addr_t dma_handle, struct dma_attrs *attrs)
{
unsigned long addr = (unsigned long) vaddr;
@@ -196,40 +168,7 @@ static void mips_dma_free_coherent(struc
if (!dma_release_from_contiguous(dev, page, count))
__free_pages(page, get_order(size));
}
-
-static int mips_dma_mmap(struct device *dev, struct vm_area_struct *vma,
- void *cpu_addr, dma_addr_t dma_addr, size_t size,
- struct dma_attrs *attrs)
-{
- unsigned long user_count = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
- unsigned long count = PAGE_ALIGN(size) >> PAGE_SHIFT;
- unsigned long addr = (unsigned long)cpu_addr;
- unsigned long off = vma->vm_pgoff;
- unsigned long pfn;
- int ret = -ENXIO;
-
- if (!plat_device_is_coherent(dev) && !hw_coherentio)
- addr = CAC_ADDR(addr);
-
- pfn = page_to_pfn(virt_to_page((void *)addr));
-
- if (dma_get_attr(DMA_ATTR_WRITE_COMBINE, attrs))
- vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
- else
- vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
-
- if (dma_mmap_from_coherent(dev, vma, cpu_addr, size, &ret))
- return ret;
-
- if (off < count && user_count <= (count - off)) {
- ret = remap_pfn_range(vma, vma->vm_start,
- pfn + off,
- user_count << PAGE_SHIFT,
- vma->vm_page_prot);
- }
-
- return ret;
-}
+EXPORT_SYMBOL(mips_dma_free_coherent);
static inline void __dma_sync_virtual(void *addr, size_t size,
enum dma_data_direction direction)
@@ -258,7 +197,7 @@ static inline void __dma_sync_virtual(vo
* If highmem is not configured then the bulk of this loop gets
* optimized out.
*/
-static inline void __dma_sync(struct page *page,
+void __dma_sync(struct page *page,
unsigned long offset, size_t size, enum dma_data_direction direction)
{
size_t left = size;
@@ -288,120 +227,7 @@ static inline void __dma_sync(struct pag
left -= len;
} while (left);
}
-
-static void mips_dma_unmap_page(struct device *dev, dma_addr_t dma_addr,
- size_t size, enum dma_data_direction direction, struct dma_attrs *attrs)
-{
- if (cpu_needs_post_dma_flush(dev))
- __dma_sync(dma_addr_to_page(dev, dma_addr),
- dma_addr & ~PAGE_MASK, size, direction);
- plat_post_dma_flush(dev);
- plat_unmap_dma_mem(dev, dma_addr, size, direction);
-}
-
-static int mips_dma_map_sg(struct device *dev, struct scatterlist *sglist,
- int nents, enum dma_data_direction direction, struct dma_attrs *attrs)
-{
- int i;
- struct scatterlist *sg;
-
- for_each_sg(sglist, sg, nents, i) {
- if (!plat_device_is_coherent(dev))
- __dma_sync(sg_page(sg), sg->offset, sg->length,
- direction);
-#ifdef CONFIG_NEED_SG_DMA_LENGTH
- sg->dma_length = sg->length;
-#endif
- sg->dma_address = plat_map_dma_mem_page(dev, sg_page(sg)) +
- sg->offset;
- }
-
- return nents;
-}
-
-static dma_addr_t mips_dma_map_page(struct device *dev, struct page *page,
- unsigned long offset, size_t size, enum dma_data_direction direction,
- struct dma_attrs *attrs)
-{
- if (!plat_device_is_coherent(dev))
- __dma_sync(page, offset, size, direction);
-
- return plat_map_dma_mem_page(dev, page) + offset;
-}
-
-static void mips_dma_unmap_sg(struct device *dev, struct scatterlist *sglist,
- int nhwentries, enum dma_data_direction direction,
- struct dma_attrs *attrs)
-{
- int i;
- struct scatterlist *sg;
-
- for_each_sg(sglist, sg, nhwentries, i) {
- if (!plat_device_is_coherent(dev) &&
- direction != DMA_TO_DEVICE)
- __dma_sync(sg_page(sg), sg->offset, sg->length,
- direction);
- plat_unmap_dma_mem(dev, sg->dma_address, sg->length, direction);
- }
-}
-
-static void mips_dma_sync_single_for_cpu(struct device *dev,
- dma_addr_t dma_handle, size_t size, enum dma_data_direction direction)
-{
- if (cpu_needs_post_dma_flush(dev))
- __dma_sync(dma_addr_to_page(dev, dma_handle),
- dma_handle & ~PAGE_MASK, size, direction);
- plat_post_dma_flush(dev);
-}
-
-static void mips_dma_sync_single_for_device(struct device *dev,
- dma_addr_t dma_handle, size_t size, enum dma_data_direction direction)
-{
- if (!plat_device_is_coherent(dev))
- __dma_sync(dma_addr_to_page(dev, dma_handle),
- dma_handle & ~PAGE_MASK, size, direction);
-}
-
-static void mips_dma_sync_sg_for_cpu(struct device *dev,
- struct scatterlist *sglist, int nelems,
- enum dma_data_direction direction)
-{
- int i;
- struct scatterlist *sg;
-
- if (cpu_needs_post_dma_flush(dev)) {
- for_each_sg(sglist, sg, nelems, i) {
- __dma_sync(sg_page(sg), sg->offset, sg->length,
- direction);
- }
- }
- plat_post_dma_flush(dev);
-}
-
-static void mips_dma_sync_sg_for_device(struct device *dev,
- struct scatterlist *sglist, int nelems,
- enum dma_data_direction direction)
-{
- int i;
- struct scatterlist *sg;
-
- if (!plat_device_is_coherent(dev)) {
- for_each_sg(sglist, sg, nelems, i) {
- __dma_sync(sg_page(sg), sg->offset, sg->length,
- direction);
- }
- }
-}
-
-int mips_dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
-{
- return 0;
-}
-
-int mips_dma_supported(struct device *dev, u64 mask)
-{
- return plat_dma_supported(dev, mask);
-}
+EXPORT_SYMBOL(__dma_sync);
void dma_cache_sync(struct device *dev, void *vaddr, size_t size,
enum dma_data_direction direction)
@@ -414,24 +240,10 @@ void dma_cache_sync(struct device *dev,
EXPORT_SYMBOL(dma_cache_sync);
-static struct dma_map_ops mips_default_dma_map_ops = {
- .alloc = mips_dma_alloc_coherent,
- .free = mips_dma_free_coherent,
- .mmap = mips_dma_mmap,
- .map_page = mips_dma_map_page,
- .unmap_page = mips_dma_unmap_page,
- .map_sg = mips_dma_map_sg,
- .unmap_sg = mips_dma_unmap_sg,
- .sync_single_for_cpu = mips_dma_sync_single_for_cpu,
- .sync_single_for_device = mips_dma_sync_single_for_device,
- .sync_sg_for_cpu = mips_dma_sync_sg_for_cpu,
- .sync_sg_for_device = mips_dma_sync_sg_for_device,
- .mapping_error = mips_dma_mapping_error,
- .dma_supported = mips_dma_supported
-};
-
-struct dma_map_ops *mips_dma_map_ops = &mips_default_dma_map_ops;
+#ifdef CONFIG_SYS_HAS_DMA_OPS
+struct dma_map_ops *mips_dma_map_ops = NULL;
EXPORT_SYMBOL(mips_dma_map_ops);
+#endif
#define PREALLOC_DMA_DEBUG_ENTRIES (1 << 16)

@ -1,183 +0,0 @@
From 3e7056c3a369e9ef9ca804bc626b60ef6b62ee27 Mon Sep 17 00:00:00 2001
From: Hauke Mehrtens <hauke@hauke-m.de>
Date: Sun, 17 May 2015 18:48:38 +0200
Subject: [PATCH 2/3] mtd: part: add generic parsing of linux,part-probe
This moves the linux,part-probe device tree parsing code from
physmap_of.c to mtdpart.c. Now all drivers can use this feature by just
providing a reference to their device tree node in struct
mtd_part_parser_data.
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
---
Documentation/devicetree/bindings/mtd/nand.txt | 16 +++++++++
drivers/mtd/maps/physmap_of.c | 46 +-------------------------
drivers/mtd/mtdpart.c | 45 +++++++++++++++++++++++++
3 files changed, 62 insertions(+), 45 deletions(-)
--- a/Documentation/devicetree/bindings/mtd/nand.txt
+++ b/Documentation/devicetree/bindings/mtd/nand.txt
@@ -12,6 +12,22 @@
- nand-ecc-step-size: integer representing the number of data bytes
that are covered by a single ECC step.
+- linux,part-probe: list of name as strings of the partition parser
+ which should be used to parse the partition table.
+ They will be tried in the specified ordering and
+ the next one will be used if the previous one
+ failed.
+
+ Example: linux,part-probe = "cmdlinepart", "ofpart";
+
+ This is also the default value, which will be used
+ if this attribute is not specified. It could be
+ that the flash driver in use overwrote the default
+ value and uses some other default.
+
+ Possible values are: bcm47xxpart, afs, ar7part,
+ ofoldpart, ofpart, bcm63xxpart, RedBoot, cmdlinepart
+
The ECC strength and ECC step size properties define the correction capability
of a controller. Together, they say a controller can correct "{strength} bit
errors per {size} bytes".
--- a/drivers/mtd/maps/physmap_of.c
+++ b/drivers/mtd/maps/physmap_of.c
@@ -112,47 +112,9 @@ static struct mtd_info *obsolete_probe(s
static const char * const part_probe_types_def[] = {
"cmdlinepart", "RedBoot", "ofpart", "ofoldpart", NULL };
-static const char * const *of_get_probes(struct device_node *dp)
-{
- const char *cp;
- int cplen;
- unsigned int l;
- unsigned int count;
- const char **res;
-
- cp = of_get_property(dp, "linux,part-probe", &cplen);
- if (cp == NULL)
- return part_probe_types_def;
-
- count = 0;
- for (l = 0; l != cplen; l++)
- if (cp[l] == 0)
- count++;
-
- res = kzalloc((count + 1)*sizeof(*res), GFP_KERNEL);
- if (!res)
- return NULL;
- count = 0;
- while (cplen > 0) {
- res[count] = cp;
- l = strlen(cp) + 1;
- cp += l;
- cplen -= l;
- count++;
- }
- return res;
-}
-
-static void of_free_probes(const char * const *probes)
-{
- if (probes != part_probe_types_def)
- kfree(probes);
-}
-
static const struct of_device_id of_flash_match[];
static int of_flash_probe(struct platform_device *dev)
{
- const char * const *part_probe_types;
const struct of_device_id *match;
struct device_node *dp = dev->dev.of_node;
struct resource res;
@@ -312,14 +274,8 @@ static int of_flash_probe(struct platfor
goto err_out;
ppdata.of_node = dp;
- part_probe_types = of_get_probes(dp);
- if (!part_probe_types) {
- err = -ENOMEM;
- goto err_out;
- }
- mtd_device_parse_register(info->cmtd, part_probe_types, &ppdata,
+ mtd_device_parse_register(info->cmtd, part_probe_types_def, &ppdata,
NULL, 0);
- of_free_probes(part_probe_types);
kfree(mtd_list);
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -29,6 +29,7 @@
#include <linux/kmod.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
+#include <linux/of.h>
#include <linux/err.h>
#include <linux/kconfig.h>
@@ -719,6 +720,42 @@ void deregister_mtd_parser(struct mtd_pa
EXPORT_SYMBOL_GPL(deregister_mtd_parser);
/*
+ * Parses the linux,part-probe device tree property.
+ * When a non null value is returned it has to be freed with kfree() by
+ * the caller.
+ */
+static const char * const *of_get_probes(struct device_node *dp)
+{
+ const char *cp;
+ int cplen;
+ unsigned int l;
+ unsigned int count;
+ const char **res;
+
+ cp = of_get_property(dp, "linux,part-probe", &cplen);
+ if (cp == NULL)
+ return NULL;
+
+ count = 0;
+ for (l = 0; l != cplen; l++)
+ if (cp[l] == 0)
+ count++;
+
+ res = kzalloc((count + 1) * sizeof(*res), GFP_KERNEL);
+ if (!res)
+ return NULL;
+ count = 0;
+ while (cplen > 0) {
+ res[count] = cp;
+ l = strlen(cp) + 1;
+ cp += l;
+ cplen -= l;
+ count++;
+ }
+ return res;
+}
+
+/*
* Do not forget to update 'parse_mtd_partitions()' kerneldoc comment if you
* are changing this array!
*/
@@ -754,6 +791,13 @@ int parse_mtd_partitions(struct mtd_info
{
struct mtd_part_parser *parser;
int ret = 0;
+ const char *const *types_of = NULL;
+
+ if (data && data->of_node) {
+ types_of = of_get_probes(data->of_node);
+ if (types_of != NULL)
+ types = types_of;
+ }
if (!types)
types = default_mtd_part_types;
@@ -772,6 +816,7 @@ int parse_mtd_partitions(struct mtd_info
break;
}
}
+ kfree(types_of);
return ret;
}

@ -1,35 +0,0 @@
From: Felix Fietkau <nbd@openwrt.org>
Date: Thu, 26 Nov 2015 17:03:46 +0100
Subject: [PATCH] Revert "mtd: spi-nor: disable protection for Winbond flash at
startup"
This reverts commit c6fc2171b249e73745c497b578b417a2946f1b2f.
This commit is breaking read access on at least s25fl064k, but also
possibly other Spansion flash chips.
Any mtd read seems to succeed, but simply returns a zero-filled buffer.
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
---
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -1194,14 +1194,13 @@ int spi_nor_scan(struct spi_nor *nor, co
mutex_init(&nor->lock);
/*
- * Atmel, SST, Intel/Numonyx, and others serial NOR tend to power up
- * with the software protection bits set
+ * Atmel, SST and Intel/Numonyx serial nor tend to power
+ * up with the software protection bits set
*/
if (JEDEC_MFR(info) == SNOR_MFR_ATMEL ||
JEDEC_MFR(info) == SNOR_MFR_INTEL ||
- JEDEC_MFR(info) == SNOR_MFR_SST ||
- JEDEC_MFR(info) == SNOR_MFR_WINBOND) {
+ JEDEC_MFR(info) == SNOR_MFR_SST) {
write_enable(nor);
write_sr(nor, 0);
}

@ -1,38 +0,0 @@
From 72fc448c4c970bdbba604ab340f16080b4f3bb17 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
Date: Thu, 26 Nov 2015 08:52:09 +0100
Subject: [PATCH] mtd: spi-nor: include mtd.h header for struct mtd_info
definition
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
So far struct spi_nor was using just a pointer to struct mtd_info so it
wasn't needed to have it fully defined there. After recent change we
embed whole struct so we need to include a proper header.
Fixes: 1976367173a4 ("mtd: spi-nor: embed struct mtd_info within struct spi_nor")
Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
---
include/linux/mtd/spi-nor.h | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
--- a/include/linux/mtd/spi-nor.h
+++ b/include/linux/mtd/spi-nor.h
@@ -12,6 +12,7 @@
#include <linux/bitops.h>
#include <linux/mtd/cfi.h>
+#include <linux/mtd/mtd.h>
/*
* Manufacturer IDs
@@ -117,8 +118,6 @@ enum spi_nor_option_flags {
SNOR_F_USE_FSR = BIT(0),
};
-struct mtd_info;
-
/**
* struct spi_nor - Structure for defining a the SPI NOR layer
* @mtd: point to a mtd_info structure

@ -1,33 +0,0 @@
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
Date: Sat, 5 Dec 2015 02:03:32 +0100
Subject: [PATCH] mtd: bcm47xxpart: limit scanned flash area on BCM47XX (MIPS)
only
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
We allowed using bcm47xxpart on BCM5301X arch with commit:
9e3afa5f5c7 ("mtd: bcm47xxpart: allow enabling on ARCH_BCM_5301X")
BCM5301X devices may contain some partitions in higher memory, e.g.
Netgear R8000 has board_data at 0x2600000. To detect them we should
use size limit on MIPS only.
Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
---
drivers/mtd/bcm47xxpart.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
--- a/drivers/mtd/bcm47xxpart.c
+++ b/drivers/mtd/bcm47xxpart.c
@@ -118,8 +118,8 @@ static int bcm47xxpart_parse(struct mtd_
/* Parse block by block looking for magics */
for (offset = 0; offset <= master->size - blocksize;
offset += blocksize) {
- /* Nothing more in higher memory */
- if (offset >= 0x2000000)
+ /* Nothing more in higher memory on BCM47XX (MIPS) */
+ if (config_enabled(CONFIG_BCM47XX) && offset >= 0x2000000)
break;
if (curr_part >= BCM47XXPART_MAX_PARTS) {

@ -1,92 +0,0 @@
From dfe4b4c732365fc1d83c2d2fd9cc18054ae850b7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
Date: Sun, 6 Dec 2015 11:24:05 +0100
Subject: [PATCH] mtd: bcm47xxpart: don't fail because of bit-flips
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Bit-flip errors may occur on NAND flashes and are harmless. Handle them
gracefully as read content is still reliable and can be parsed.
Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
---
drivers/mtd/bcm47xxpart.c | 38 ++++++++++++++++++++++----------------
1 file changed, 22 insertions(+), 16 deletions(-)
--- a/drivers/mtd/bcm47xxpart.c
+++ b/drivers/mtd/bcm47xxpart.c
@@ -66,11 +66,13 @@ static const char *bcm47xxpart_trx_data_
{
uint32_t buf;
size_t bytes_read;
+ int err;
- if (mtd_read(master, offset, sizeof(buf), &bytes_read,
- (uint8_t *)&buf) < 0) {
- pr_err("mtd_read error while parsing (offset: 0x%X)!\n",
- offset);
+ err = mtd_read(master, offset, sizeof(buf), &bytes_read,
+ (uint8_t *)&buf);
+ if (err && !mtd_is_bitflip(err)) {
+ pr_err("mtd_read error while parsing (offset: 0x%X): %d\n",
+ offset, err);
goto out_default;
}
@@ -95,6 +97,7 @@ static int bcm47xxpart_parse(struct mtd_
int trx_part = -1;
int last_trx_part = -1;
int possible_nvram_sizes[] = { 0x8000, 0xF000, 0x10000, };
+ int err;
/*
* Some really old flashes (like AT45DB*) had smaller erasesize-s, but
@@ -128,10 +131,11 @@ static int bcm47xxpart_parse(struct mtd_
}
/* Read beginning of the block */
- if (mtd_read(master, offset, BCM47XXPART_BYTES_TO_READ,
- &bytes_read, (uint8_t *)buf) < 0) {
- pr_err("mtd_read error while parsing (offset: 0x%X)!\n",
- offset);
+ err = mtd_read(master, offset, BCM47XXPART_BYTES_TO_READ,
+ &bytes_read, (uint8_t *)buf);
+ if (err && !mtd_is_bitflip(err)) {
+ pr_err("mtd_read error while parsing (offset: 0x%X): %d\n",
+ offset, err);
continue;
}
@@ -254,10 +258,11 @@ static int bcm47xxpart_parse(struct mtd_
}
/* Read middle of the block */
- if (mtd_read(master, offset + 0x8000, 0x4,
- &bytes_read, (uint8_t *)buf) < 0) {
- pr_err("mtd_read error while parsing (offset: 0x%X)!\n",
- offset);
+ err = mtd_read(master, offset + 0x8000, 0x4, &bytes_read,
+ (uint8_t *)buf);
+ if (err && !mtd_is_bitflip(err)) {
+ pr_err("mtd_read error while parsing (offset: 0x%X): %d\n",
+ offset, err);
continue;
}
@@ -277,10 +282,11 @@ static int bcm47xxpart_parse(struct mtd_
}
offset = master->size - possible_nvram_sizes[i];
- if (mtd_read(master, offset, 0x4, &bytes_read,
- (uint8_t *)buf) < 0) {
- pr_err("mtd_read error while reading at offset 0x%X!\n",
- offset);
+ err = mtd_read(master, offset, 0x4, &bytes_read,
+ (uint8_t *)buf);
+ if (err && !mtd_is_bitflip(err)) {
+ pr_err("mtd_read error while reading (offset 0x%X): %d\n",
+ offset, err);
continue;
}

@ -1,96 +0,0 @@
From fe29727caa7fe434fcb3166df2a62672bc516b54 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20=C5=A0tetiar?= <ynezz@true.cz>
Date: Wed, 4 Nov 2015 16:23:37 +0100
Subject: [PATCH 2/2] USB: qmi_wwan: Add quirk for Quectel EC20 Mini PCIe
module
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This device has same vendor and product IDs as G2K devices, but it has
different number of interfaces(4 vs 5) and also different interface
layout where EC20 has QMI on interface 4 instead of 0.
lsusb output:
Bus 002 Device 003: ID 05c6:9215 Qualcomm, Inc. Acer Gobi 2000
Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 2.00
bDeviceClass 0 (Defined at Interface level)
bDeviceSubClass 0
bDeviceProtocol 0
bMaxPacketSize0 64
idVendor 0x05c6 Qualcomm, Inc.
idProduct 0x9215 Acer Gobi 2000 Wireless Modem
bcdDevice 2.32
iManufacturer 1 Quectel
iProduct 2 Quectel LTE Module
iSerial 0
bNumConfigurations 1
Configuration Descriptor:
bLength 9
bDescriptorType 2
wTotalLength 209
bNumInterfaces 5
bConfigurationValue 1
iConfiguration 0
bmAttributes 0xa0
(Bus Powered)
Remote Wakeup
MaxPower 500mA
Signed-off-by: Petr Štetiar <ynezz@true.cz>
---
drivers/net/usb/qmi_wwan.c | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)
--- a/drivers/net/usb/qmi_wwan.c
+++ b/drivers/net/usb/qmi_wwan.c
@@ -823,6 +823,7 @@ static const struct usb_device_id produc
{QMI_GOBI_DEVICE(0x05c6, 0x9245)}, /* Samsung Gobi 2000 Modem device (VL176) */
{QMI_GOBI_DEVICE(0x03f0, 0x251d)}, /* HP Gobi 2000 Modem device (VP412) */
{QMI_GOBI_DEVICE(0x05c6, 0x9215)}, /* Acer Gobi 2000 Modem device (VP413) */
+ {QMI_FIXED_INTF(0x05c6, 0x9215, 4)}, /* Quectel EC20 Mini PCIe */
{QMI_GOBI_DEVICE(0x05c6, 0x9265)}, /* Asus Gobi 2000 Modem device (VR305) */
{QMI_GOBI_DEVICE(0x05c6, 0x9235)}, /* Top Global Gobi 2000 Modem device (VR306) */
{QMI_GOBI_DEVICE(0x05c6, 0x9275)}, /* iRex Technologies Gobi 2000 Modem device (VR307) */
@@ -854,10 +855,24 @@ static const struct usb_device_id produc
};
MODULE_DEVICE_TABLE(usb, products);
+static bool quectel_ec20_detected(struct usb_interface *intf)
+{
+ struct usb_device *dev = interface_to_usbdev(intf);
+
+ if (dev->actconfig &&
+ le16_to_cpu(dev->descriptor.idVendor) == 0x05c6 &&
+ le16_to_cpu(dev->descriptor.idProduct) == 0x9215 &&
+ dev->actconfig->desc.bNumInterfaces == 5)
+ return true;
+
+ return false;
+}
+
static int qmi_wwan_probe(struct usb_interface *intf,
const struct usb_device_id *prod)
{
struct usb_device_id *id = (struct usb_device_id *)prod;
+ struct usb_interface_descriptor *desc = &intf->cur_altsetting->desc;
/* Workaround to enable dynamic IDs. This disables usbnet
* blacklisting functionality. Which, if required, can be
@@ -869,6 +884,12 @@ static int qmi_wwan_probe(struct usb_int
id->driver_info = (unsigned long)&qmi_wwan_info;
}
+ /* Quectel EC20 quirk where we've QMI on interface 4 instead of 0 */
+ if (quectel_ec20_detected(intf) && desc->bInterfaceNumber == 0) {
+ dev_dbg(&intf->dev, "Quectel EC20 quirk, skipping interface 0\n");
+ return -ENODEV;
+ }
+
return usbnet_probe(intf, id);
}

@ -1,11 +0,0 @@
--- a/scripts/setlocalversion
+++ b/scripts/setlocalversion
@@ -165,7 +165,7 @@ else
# annotated or signed tagged state (as git describe only
# looks at signed or annotated tags - git tag -a/-s) and
# LOCALVERSION= is not specified
- if test "${LOCALVERSION+set}" != "set"; then
+ if test "${CONFIG_LOCALVERSION+set}" != "set"; then
scm=$(scm_version --short)
res="$res${scm:++}"
fi

@ -1,14 +0,0 @@
--- a/Makefile
+++ b/Makefile
@@ -607,9 +607,9 @@ include arch/$(SRCARCH)/Makefile
KBUILD_CFLAGS += $(call cc-option,-fno-delete-null-pointer-checks,)
ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE
-KBUILD_CFLAGS += -Os $(call cc-disable-warning,maybe-uninitialized,)
+KBUILD_CFLAGS += -Os $(EXTRA_OPTIMIZATION) $(call cc-disable-warning,maybe-uninitialized,)
else
-KBUILD_CFLAGS += -O2
+KBUILD_CFLAGS += -O2 -fno-reorder-blocks -fno-tree-ch $(EXTRA_OPTIMIZATION)
endif
# Tell gcc to never replace conditional load with a non-conditional one

@ -1,11 +0,0 @@
--- a/Makefile
+++ b/Makefile
@@ -398,7 +398,7 @@ KBUILD_CFLAGS_KERNEL :=
KBUILD_AFLAGS := -D__ASSEMBLY__
KBUILD_AFLAGS_MODULE := -DMODULE
KBUILD_CFLAGS_MODULE := -DMODULE
-KBUILD_LDFLAGS_MODULE := -T $(srctree)/scripts/module-common.lds
+KBUILD_LDFLAGS_MODULE = -T $(srctree)/scripts/module-common.lds $(if $(CONFIG_PROFILING),,-s)
# Read KERNELRELEASE from include/config/kernel.release (if it exists)
KERNELRELEASE = $(shell cat include/config/kernel.release 2> /dev/null)

@ -1,108 +0,0 @@
--- a/scripts/kallsyms.c
+++ b/scripts/kallsyms.c
@@ -58,6 +58,7 @@ static struct addr_range percpu_range =
static struct sym_entry *table;
static unsigned int table_size, table_cnt;
static int all_symbols = 0;
+static int uncompressed = 0;
static int absolute_percpu = 0;
static char symbol_prefix_char = '\0';
static unsigned long long kernel_start_addr = 0;
@@ -403,6 +404,9 @@ static void write_src(void)
free(markers);
+ if (uncompressed)
+ return;
+
output_label("kallsyms_token_table");
off = 0;
for (i = 0; i < 256; i++) {
@@ -461,6 +465,9 @@ static void *find_token(unsigned char *s
{
int i;
+ if (uncompressed)
+ return NULL;
+
for (i = 0; i < len - 1; i++) {
if (str[i] == token[0] && str[i+1] == token[1])
return &str[i];
@@ -533,6 +540,9 @@ static void optimize_result(void)
{
int i, best;
+ if (uncompressed)
+ return;
+
/* using the '\0' symbol last allows compress_symbols to use standard
* fast string functions */
for (i = 255; i >= 0; i--) {
@@ -703,7 +713,9 @@ int main(int argc, char **argv)
} else if (strncmp(argv[i], "--page-offset=", 14) == 0) {
const char *p = &argv[i][14];
kernel_start_addr = strtoull(p, NULL, 16);
- } else
+ } else if (strcmp(argv[i], "--uncompressed") == 0)
+ uncompressed = 1;
+ else
usage();
}
} else if (argc != 1)
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -1345,6 +1345,17 @@ config SYSCTL_ARCH_UNALIGN_ALLOW
the unaligned access emulation.
see arch/parisc/kernel/unaligned.c for reference
+config KALLSYMS_UNCOMPRESSED
+ bool "Keep kallsyms uncompressed"
+ depends on KALLSYMS
+ help
+ Normally kallsyms contains compressed symbols (using a token table),
+ reducing the uncompressed kernel image size. Keeping the symbol table
+ uncompressed significantly improves the size of this part in compressed
+ kernel images.
+
+ Say N unless you need compressed kernel images to be small.
+
config HAVE_PCSPKR_PLATFORM
bool
--- a/scripts/link-vmlinux.sh
+++ b/scripts/link-vmlinux.sh
@@ -90,6 +90,10 @@ kallsyms()
kallsymopt="${kallsymopt} --absolute-percpu"
fi
+ if [ -n "${CONFIG_KALLSYMS_UNCOMPRESSED}" ]; then
+ kallsymopt="${kallsymopt} --uncompressed"
+ fi
+
local aflags="${KBUILD_AFLAGS} ${KBUILD_AFLAGS_KERNEL} \
${NOSTDINC_FLAGS} ${LINUXINCLUDE} ${KBUILD_CPPFLAGS}"
--- a/kernel/kallsyms.c
+++ b/kernel/kallsyms.c
@@ -109,6 +109,11 @@ static unsigned int kallsyms_expand_symb
* For every byte on the compressed symbol data, copy the table
* entry for that byte.
*/
+#ifdef CONFIG_KALLSYMS_UNCOMPRESSED
+ memcpy(result, data + 1, len - 1);
+ result += len - 1;
+ len = 0;
+#endif
while (len) {
tptr = &kallsyms_token_table[kallsyms_token_index[*data]];
data++;
@@ -141,6 +146,9 @@ tail:
*/
static char kallsyms_get_symbol_type(unsigned int off)
{
+#ifdef CONFIG_KALLSYMS_UNCOMPRESSED
+ return kallsyms_names[off + 1];
+#endif
/*
* Get just the first code, look it up in the token table,
* and return the first char from this token.

@ -1,194 +0,0 @@
From: Felix Fietkau <nbd@openwrt.org>
Subject: [PATCH] build: add a hack for removing non-essential module info
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
---
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -169,9 +169,10 @@ void trim_init_extable(struct module *m)
/* Generic info of form tag = "info" */
#define MODULE_INFO(tag, info) __MODULE_INFO(tag, tag, info)
+#define MODULE_INFO_STRIP(tag, info) __MODULE_INFO_STRIP(tag, tag, info)
/* For userspace: you can also call me... */
-#define MODULE_ALIAS(_alias) MODULE_INFO(alias, _alias)
+#define MODULE_ALIAS(_alias) MODULE_INFO_STRIP(alias, _alias)
/* Soft module dependencies. See man modprobe.d for details.
* Example: MODULE_SOFTDEP("pre: module-foo module-bar post: module-baz")
@@ -212,12 +213,12 @@ void trim_init_extable(struct module *m)
* Author(s), use "Name <email>" or just "Name", for multiple
* authors use multiple MODULE_AUTHOR() statements/lines.
*/
-#define MODULE_AUTHOR(_author) MODULE_INFO(author, _author)
+#define MODULE_AUTHOR(_author) MODULE_INFO_STRIP(author, _author)
/* What your module does. */
-#define MODULE_DESCRIPTION(_description) MODULE_INFO(description, _description)
+#define MODULE_DESCRIPTION(_description) MODULE_INFO_STRIP(description, _description)
-#ifdef MODULE
+#if defined(MODULE) && !defined(CONFIG_MODULE_STRIPPED)
/* Creates an alias so file2alias.c can find device table. */
#define MODULE_DEVICE_TABLE(type, name) \
extern const typeof(name) __mod_##type##__##name##_device_table \
@@ -244,7 +245,9 @@ extern const typeof(name) __mod_##type##
*/
#if defined(MODULE) || !defined(CONFIG_SYSFS)
-#define MODULE_VERSION(_version) MODULE_INFO(version, _version)
+#define MODULE_VERSION(_version) MODULE_INFO_STRIP(version, _version)
+#elif defined(CONFIG_MODULE_STRIPPED)
+#define MODULE_VERSION(_version) __MODULE_INFO_DISABLED(version)
#else
#define MODULE_VERSION(_version) \
static struct module_version_attribute ___modver_attr = { \
@@ -266,7 +269,7 @@ extern const typeof(name) __mod_##type##
/* Optional firmware file (or files) needed by the module
* format is simply firmware file name. Multiple firmware
* files require multiple MODULE_FIRMWARE() specifiers */
-#define MODULE_FIRMWARE(_firmware) MODULE_INFO(firmware, _firmware)
+#define MODULE_FIRMWARE(_firmware) MODULE_INFO_STRIP(firmware, _firmware)
/* Given an address, look for it in the exception tables */
const struct exception_table_entry *search_exception_tables(unsigned long add);
--- a/include/linux/moduleparam.h
+++ b/include/linux/moduleparam.h
@@ -16,6 +16,16 @@
/* Chosen so that structs with an unsigned long line up. */
#define MAX_PARAM_PREFIX_LEN (64 - sizeof(unsigned long))
+/* This struct is here for syntactic coherency, it is not used */
+#define __MODULE_INFO_DISABLED(name) \
+ struct __UNIQUE_ID(name) {}
+
+#ifdef CONFIG_MODULE_STRIPPED
+#define __MODULE_INFO_STRIP(tag, name, info) __MODULE_INFO_DISABLED(name)
+#else
+#define __MODULE_INFO_STRIP(tag, name, info) __MODULE_INFO(tag, name, info)
+#endif
+
#ifdef MODULE
#define __MODULE_INFO(tag, name, info) \
static const char __UNIQUE_ID(name)[] \
@@ -23,8 +33,7 @@ static const char __UNIQUE_ID(name)[]
= __stringify(tag) "=" info
#else /* !MODULE */
/* This struct is here for syntactic coherency, it is not used */
-#define __MODULE_INFO(tag, name, info) \
- struct __UNIQUE_ID(name) {}
+#define __MODULE_INFO(tag, name, info) __MODULE_INFO_DISABLED(name)
#endif
#define __MODULE_PARM_TYPE(name, _type) \
__MODULE_INFO(parmtype, name##type, #name ":" _type)
@@ -32,7 +41,7 @@ static const char __UNIQUE_ID(name)[]
/* One for each parameter, describing how to use it. Some files do
multiple of these per line, so can't just use MODULE_INFO. */
#define MODULE_PARM_DESC(_parm, desc) \
- __MODULE_INFO(parm, _parm, #_parm ":" desc)
+ __MODULE_INFO_STRIP(parm, _parm, #_parm ":" desc)
struct kernel_param;
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -2026,6 +2026,13 @@ config MODULE_COMPRESS_XZ
endchoice
+config MODULE_STRIPPED
+ bool "Reduce module size"
+ depends on MODULES
+ help
+ Remove module parameter descriptions, author info, version, aliases,
+ device tables, etc.
+
endif # MODULES
config MODULES_TREE_LOOKUP
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -2840,6 +2840,7 @@ static struct module *setup_load_info(st
static int check_modinfo(struct module *mod, struct load_info *info, int flags)
{
+#ifndef CONFIG_MODULE_STRIPPED
const char *modmagic = get_modinfo(info, "vermagic");
int err;
@@ -2865,6 +2866,7 @@ static int check_modinfo(struct module *
pr_warn("%s: module is from the staging directory, the quality "
"is unknown, you have been warned.\n", mod->name);
}
+#endif
/* Set up license info based on the info section */
set_license(mod, get_modinfo(info, "license"));
--- a/scripts/mod/modpost.c
+++ b/scripts/mod/modpost.c
@@ -1960,7 +1960,9 @@ static void read_symbols(char *modname)
symname = remove_dot(info.strtab + sym->st_name);
handle_modversions(mod, &info, sym, symname);
+#ifndef CONFIG_MODULE_STRIPPED
handle_moddevtable(mod, &info, sym, symname);
+#endif
}
if (!is_vmlinux(modname) ||
(is_vmlinux(modname) && vmlinux_section_warnings))
@@ -2104,7 +2106,9 @@ static void add_header(struct buffer *b,
buf_printf(b, "#include <linux/vermagic.h>\n");
buf_printf(b, "#include <linux/compiler.h>\n");
buf_printf(b, "\n");
+#ifndef CONFIG_MODULE_STRIPPED
buf_printf(b, "MODULE_INFO(vermagic, VERMAGIC_STRING);\n");
+#endif
buf_printf(b, "\n");
buf_printf(b, "__visible struct module __this_module\n");
buf_printf(b, "__attribute__((section(\".gnu.linkonce.this_module\"))) = {\n");
@@ -2121,16 +2125,20 @@ static void add_header(struct buffer *b,
static void add_intree_flag(struct buffer *b, int is_intree)
{
+#ifndef CONFIG_MODULE_STRIPPED
if (is_intree)
buf_printf(b, "\nMODULE_INFO(intree, \"Y\");\n");
+#endif
}
static void add_staging_flag(struct buffer *b, const char *name)
{
+#ifndef CONFIG_MODULE_STRIPPED
static const char *staging_dir = "drivers/staging";
if (strncmp(staging_dir, name, strlen(staging_dir)) == 0)
buf_printf(b, "\nMODULE_INFO(staging, \"Y\");\n");
+#endif
}
/**
@@ -2223,11 +2231,13 @@ static void add_depends(struct buffer *b
static void add_srcversion(struct buffer *b, struct module *mod)
{
+#ifndef CONFIG_MODULE_STRIPPED
if (mod->srcversion[0]) {
buf_printf(b, "\n");
buf_printf(b, "MODULE_INFO(srcversion, \"%s\");\n",
mod->srcversion);
}
+#endif
}
static void write_if_changed(struct buffer *b, const char *fname)
@@ -2458,7 +2468,9 @@ int main(int argc, char **argv)
add_staging_flag(&buf, mod->name);
err |= add_versions(&buf, mod);
add_depends(&buf, mod, modules);
+#ifndef CONFIG_MODULE_STRIPPED
add_moddevtable(&buf, mod);
+#endif
add_srcversion(&buf, mod);
sprintf(fname, "%s.mod.c", mod->name);

@ -1,36 +0,0 @@
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -618,8 +618,10 @@ char *symbol_string(char *buf, char *end
struct printf_spec spec, const char *fmt)
{
unsigned long value;
-#ifdef CONFIG_KALLSYMS
char sym[KSYM_SYMBOL_LEN];
+#ifndef CONFIG_KALLSYMS
+ struct module *mod;
+ int len;
#endif
if (fmt[1] == 'R')
@@ -633,15 +635,15 @@ char *symbol_string(char *buf, char *end
sprint_symbol(sym, value);
else
sprint_symbol_no_offset(sym, value);
-
- return string(buf, end, sym, spec);
#else
- spec.field_width = 2 * sizeof(void *);
- spec.flags |= SPECIAL | SMALL | ZEROPAD;
- spec.base = 16;
+ len = snprintf(sym, sizeof(sym), "0x%lx", value);
- return number(buf, end, value, spec);
+ mod = __module_address(value);
+ if (mod)
+ snprintf(sym + len, sizeof(sym) - len, " [%s@%p+0x%x]",
+ mod->name, mod->module_core, mod->core_size);
#endif
+ return string(buf, end, sym, spec);
}
static noinline_for_stack

@ -1,51 +0,0 @@
--- a/tools/include/tools/be_byteshift.h
+++ b/tools/include/tools/be_byteshift.h
@@ -1,6 +1,10 @@
#ifndef _TOOLS_BE_BYTESHIFT_H
#define _TOOLS_BE_BYTESHIFT_H
+#ifndef __linux__
+#include "linux_types.h"
+#endif
+
#include <stdint.h>
static inline uint16_t __get_unaligned_be16(const uint8_t *p)
--- a/tools/include/tools/le_byteshift.h
+++ b/tools/include/tools/le_byteshift.h
@@ -1,6 +1,10 @@
#ifndef _TOOLS_LE_BYTESHIFT_H
#define _TOOLS_LE_BYTESHIFT_H
+#ifndef __linux__
+#include "linux_types.h"
+#endif
+
#include <stdint.h>
static inline uint16_t __get_unaligned_le16(const uint8_t *p)
--- /dev/null
+++ b/tools/include/tools/linux_types.h
@@ -0,0 +1,22 @@
+#ifndef __LINUX_TYPES_H
+#define __LINUX_TYPES_H
+
+#include <stdint.h>
+
+typedef uint8_t __u8;
+typedef uint8_t __be8;
+typedef uint8_t __le8;
+
+typedef uint16_t __u16;
+typedef uint16_t __be16;
+typedef uint16_t __le16;
+
+typedef uint32_t __u32;
+typedef uint32_t __be32;
+typedef uint32_t __le32;
+
+typedef uint64_t __u64;
+typedef uint64_t __be64;
+typedef uint64_t __le64;
+
+#endif

@ -1,11 +0,0 @@
--- a/include/uapi/linux/spi/spidev.h
+++ b/include/uapi/linux/spi/spidev.h
@@ -111,7 +111,7 @@ struct spi_ioc_transfer {
/* not all platforms use <asm-generic/ioctl.h> or _IOC_TYPECHECK() ... */
#define SPI_MSGSIZE(N) \
- ((((N)*(sizeof (struct spi_ioc_transfer))) < (1 << _IOC_SIZEBITS)) \
+ ((((N)*(sizeof (struct spi_ioc_transfer))) < (1 << 13)) \
? ((N)*(sizeof (struct spi_ioc_transfer))) : 0)
#define SPI_IOC_MESSAGE(N) _IOW(SPI_IOC_MAGIC, 0, char[SPI_MSGSIZE(N)])

@ -1,536 +0,0 @@
From: Felix Fietkau <nbd@openwrt.org>
use -ffunction-sections, -fdata-sections and --gc-sections
In combination with kernel symbol export stripping this significantly reduces
the kernel image size. Used on both ARM and MIPS architectures.
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
Signed-off-by: Jonas Gorski <jogo@openwrt.org>
Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
---
--- a/arch/mips/Makefile
+++ b/arch/mips/Makefile
@@ -89,10 +89,14 @@ all-$(CONFIG_SYS_SUPPORTS_ZBOOT)+= vmlin
#
cflags-y += -G 0 -mno-abicalls -fno-pic -pipe
cflags-y += -msoft-float
-LDFLAGS_vmlinux += -G 0 -static -n -nostdlib
+LDFLAGS_vmlinux += -G 0 -static -n -nostdlib --gc-sections
KBUILD_AFLAGS_MODULE += -mlong-calls
KBUILD_CFLAGS_MODULE += -mlong-calls
+ifndef CONFIG_FUNCTION_TRACER
+KBUILD_CFLAGS_KERNEL += -ffunction-sections -fdata-sections
+endif
+
#
# pass -msoft-float to GAS if it supports it. However on newer binutils
# (specifically newer than 2.24.51.20140728) we then also need to explicitly
--- a/arch/mips/kernel/vmlinux.lds.S
+++ b/arch/mips/kernel/vmlinux.lds.S
@@ -67,7 +67,7 @@ SECTIONS
/* Exception table for data bus errors */
__dbe_table : {
__start___dbe_table = .;
- *(__dbe_table)
+ KEEP(*(__dbe_table))
__stop___dbe_table = .;
}
@@ -112,7 +112,7 @@ SECTIONS
. = ALIGN(4);
.mips.machines.init : AT(ADDR(.mips.machines.init) - LOAD_OFFSET) {
__mips_machines_start = .;
- *(.mips.machines.init)
+ KEEP(*(.mips.machines.init))
__mips_machines_end = .;
}
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -89,7 +89,7 @@
#ifdef CONFIG_FTRACE_MCOUNT_RECORD
#define MCOUNT_REC() . = ALIGN(8); \
VMLINUX_SYMBOL(__start_mcount_loc) = .; \
- *(__mcount_loc) \
+ KEEP(*(__mcount_loc)) \
VMLINUX_SYMBOL(__stop_mcount_loc) = .;
#else
#define MCOUNT_REC()
@@ -97,7 +97,7 @@
#ifdef CONFIG_TRACE_BRANCH_PROFILING
#define LIKELY_PROFILE() VMLINUX_SYMBOL(__start_annotated_branch_profile) = .; \
- *(_ftrace_annotated_branch) \
+ KEEP(*(_ftrace_annotated_branch)) \
VMLINUX_SYMBOL(__stop_annotated_branch_profile) = .;
#else
#define LIKELY_PROFILE()
@@ -105,7 +105,7 @@
#ifdef CONFIG_PROFILE_ALL_BRANCHES
#define BRANCH_PROFILE() VMLINUX_SYMBOL(__start_branch_profile) = .; \
- *(_ftrace_branch) \
+ KEEP(*(_ftrace_branch)) \
VMLINUX_SYMBOL(__stop_branch_profile) = .;
#else
#define BRANCH_PROFILE()
@@ -114,7 +114,7 @@
#ifdef CONFIG_KPROBES
#define KPROBE_BLACKLIST() . = ALIGN(8); \
VMLINUX_SYMBOL(__start_kprobe_blacklist) = .; \
- *(_kprobe_blacklist) \
+ KEEP(*(_kprobe_blacklist)) \
VMLINUX_SYMBOL(__stop_kprobe_blacklist) = .;
#else
#define KPROBE_BLACKLIST()
@@ -123,10 +123,10 @@
#ifdef CONFIG_EVENT_TRACING
#define FTRACE_EVENTS() . = ALIGN(8); \
VMLINUX_SYMBOL(__start_ftrace_events) = .; \
- *(_ftrace_events) \
+ KEEP(*(_ftrace_events)) \
VMLINUX_SYMBOL(__stop_ftrace_events) = .; \
VMLINUX_SYMBOL(__start_ftrace_enum_maps) = .; \
- *(_ftrace_enum_map) \
+ KEEP(*(_ftrace_enum_map)) \
VMLINUX_SYMBOL(__stop_ftrace_enum_maps) = .;
#else
#define FTRACE_EVENTS()
@@ -134,7 +134,7 @@
#ifdef CONFIG_TRACING
#define TRACE_PRINTKS() VMLINUX_SYMBOL(__start___trace_bprintk_fmt) = .; \
- *(__trace_printk_fmt) /* Trace_printk fmt' pointer */ \
+ KEEP(*(__trace_printk_fmt)) /* Trace_printk fmt' pointer */ \
VMLINUX_SYMBOL(__stop___trace_bprintk_fmt) = .;
#define TRACEPOINT_STR() VMLINUX_SYMBOL(__start___tracepoint_str) = .; \
*(__tracepoint_str) /* Trace_printk fmt' pointer */ \
@@ -147,7 +147,7 @@
#ifdef CONFIG_FTRACE_SYSCALLS
#define TRACE_SYSCALLS() . = ALIGN(8); \
VMLINUX_SYMBOL(__start_syscalls_metadata) = .; \
- *(__syscalls_metadata) \
+ KEEP(*(__syscalls_metadata)) \
VMLINUX_SYMBOL(__stop_syscalls_metadata) = .;
#else
#define TRACE_SYSCALLS()
@@ -169,8 +169,8 @@
#define _OF_TABLE_1(name) \
. = ALIGN(8); \
VMLINUX_SYMBOL(__##name##_of_table) = .; \
- *(__##name##_of_table) \
- *(__##name##_of_table_end)
+ KEEP(*(__##name##_of_table)) \
+ KEEP(*(__##name##_of_table_end))
#define CLKSRC_OF_TABLES() OF_TABLE(CONFIG_CLKSRC_OF, clksrc)
#define IRQCHIP_OF_MATCH_TABLE() OF_TABLE(CONFIG_IRQCHIP, irqchip)
@@ -184,7 +184,7 @@
#define KERNEL_DTB() \
STRUCT_ALIGN(); \
VMLINUX_SYMBOL(__dtb_start) = .; \
- *(.dtb.init.rodata) \
+ KEEP(*(.dtb.init.rodata)) \
VMLINUX_SYMBOL(__dtb_end) = .;
/* .data section */
@@ -200,16 +200,17 @@
/* implement dynamic printk debug */ \
. = ALIGN(8); \
VMLINUX_SYMBOL(__start___jump_table) = .; \
- *(__jump_table) \
+ KEEP(*(__jump_table)) \
VMLINUX_SYMBOL(__stop___jump_table) = .; \
. = ALIGN(8); \
VMLINUX_SYMBOL(__start___verbose) = .; \
- *(__verbose) \
+ KEEP(*(__verbose)) \
VMLINUX_SYMBOL(__stop___verbose) = .; \
LIKELY_PROFILE() \
BRANCH_PROFILE() \
TRACE_PRINTKS() \
- TRACEPOINT_STR()
+ TRACEPOINT_STR() \
+ *(.data.[a-zA-Z_]*)
/*
* Data section helpers
@@ -263,35 +264,35 @@
/* PCI quirks */ \
.pci_fixup : AT(ADDR(.pci_fixup) - LOAD_OFFSET) { \
VMLINUX_SYMBOL(__start_pci_fixups_early) = .; \
- *(.pci_fixup_early) \
+ KEEP(*(.pci_fixup_early)) \
VMLINUX_SYMBOL(__end_pci_fixups_early) = .; \
VMLINUX_SYMBOL(__start_pci_fixups_header) = .; \
- *(.pci_fixup_header) \
+ KEEP(*(.pci_fixup_header)) \
VMLINUX_SYMBOL(__end_pci_fixups_header) = .; \
VMLINUX_SYMBOL(__start_pci_fixups_final) = .; \
- *(.pci_fixup_final) \
+ KEEP(*(.pci_fixup_final)) \
VMLINUX_SYMBOL(__end_pci_fixups_final) = .; \
VMLINUX_SYMBOL(__start_pci_fixups_enable) = .; \
- *(.pci_fixup_enable) \
+ KEEP(*(.pci_fixup_enable)) \
VMLINUX_SYMBOL(__end_pci_fixups_enable) = .; \
VMLINUX_SYMBOL(__start_pci_fixups_resume) = .; \
- *(.pci_fixup_resume) \
+ KEEP(*(.pci_fixup_resume)) \
VMLINUX_SYMBOL(__end_pci_fixups_resume) = .; \
VMLINUX_SYMBOL(__start_pci_fixups_resume_early) = .; \
- *(.pci_fixup_resume_early) \
+ KEEP(*(.pci_fixup_resume_early)) \
VMLINUX_SYMBOL(__end_pci_fixups_resume_early) = .; \
VMLINUX_SYMBOL(__start_pci_fixups_suspend) = .; \
- *(.pci_fixup_suspend) \
+ KEEP(*(.pci_fixup_suspend)) \
VMLINUX_SYMBOL(__end_pci_fixups_suspend) = .; \
VMLINUX_SYMBOL(__start_pci_fixups_suspend_late) = .; \
- *(.pci_fixup_suspend_late) \
+ KEEP(*(.pci_fixup_suspend_late)) \
VMLINUX_SYMBOL(__end_pci_fixups_suspend_late) = .; \
} \
\
/* Built-in firmware blobs */ \
.builtin_fw : AT(ADDR(.builtin_fw) - LOAD_OFFSET) { \
VMLINUX_SYMBOL(__start_builtin_fw) = .; \
- *(.builtin_fw) \
+ KEEP(*(.builtin_fw)) \
VMLINUX_SYMBOL(__end_builtin_fw) = .; \
} \
\
@@ -300,49 +301,49 @@
/* Kernel symbol table: Normal symbols */ \
__ksymtab : AT(ADDR(__ksymtab) - LOAD_OFFSET) { \
VMLINUX_SYMBOL(__start___ksymtab) = .; \
- *(SORT(___ksymtab+*)) \
+ KEEP(*(SORT(___ksymtab+*))) \
VMLINUX_SYMBOL(__stop___ksymtab) = .; \
} \
\
/* Kernel symbol table: GPL-only symbols */ \
__ksymtab_gpl : AT(ADDR(__ksymtab_gpl) - LOAD_OFFSET) { \
VMLINUX_SYMBOL(__start___ksymtab_gpl) = .; \
- *(SORT(___ksymtab_gpl+*)) \
+ KEEP(*(SORT(___ksymtab_gpl+*))) \
VMLINUX_SYMBOL(__stop___ksymtab_gpl) = .; \
} \
\
/* Kernel symbol table: Normal unused symbols */ \
__ksymtab_unused : AT(ADDR(__ksymtab_unused) - LOAD_OFFSET) { \
VMLINUX_SYMBOL(__start___ksymtab_unused) = .; \
- *(SORT(___ksymtab_unused+*)) \
+ KEEP(*(SORT(___ksymtab_unused+*))) \
VMLINUX_SYMBOL(__stop___ksymtab_unused) = .; \
} \
\
/* Kernel symbol table: GPL-only unused symbols */ \
__ksymtab_unused_gpl : AT(ADDR(__ksymtab_unused_gpl) - LOAD_OFFSET) { \
VMLINUX_SYMBOL(__start___ksymtab_unused_gpl) = .; \
- *(SORT(___ksymtab_unused_gpl+*)) \
+ KEEP(*(SORT(___ksymtab_unused_gpl+*))) \
VMLINUX_SYMBOL(__stop___ksymtab_unused_gpl) = .; \
} \
\
/* Kernel symbol table: GPL-future-only symbols */ \
__ksymtab_gpl_future : AT(ADDR(__ksymtab_gpl_future) - LOAD_OFFSET) { \
VMLINUX_SYMBOL(__start___ksymtab_gpl_future) = .; \
- *(SORT(___ksymtab_gpl_future+*)) \
+ KEEP(*(SORT(___ksymtab_gpl_future+*))) \
VMLINUX_SYMBOL(__stop___ksymtab_gpl_future) = .; \
} \
\
/* Kernel symbol table: Normal symbols */ \
__kcrctab : AT(ADDR(__kcrctab) - LOAD_OFFSET) { \
VMLINUX_SYMBOL(__start___kcrctab) = .; \
- *(SORT(___kcrctab+*)) \
+ KEEP(*(SORT(___kcrctab+*))) \
VMLINUX_SYMBOL(__stop___kcrctab) = .; \
} \
\
/* Kernel symbol table: GPL-only symbols */ \
__kcrctab_gpl : AT(ADDR(__kcrctab_gpl) - LOAD_OFFSET) { \
VMLINUX_SYMBOL(__start___kcrctab_gpl) = .; \
- *(SORT(___kcrctab_gpl+*)) \
+ KEEP(*(SORT(___kcrctab_gpl+*))) \
VMLINUX_SYMBOL(__stop___kcrctab_gpl) = .; \
} \
\
@@ -356,14 +357,14 @@
/* Kernel symbol table: GPL-only unused symbols */ \
__kcrctab_unused_gpl : AT(ADDR(__kcrctab_unused_gpl) - LOAD_OFFSET) { \
VMLINUX_SYMBOL(__start___kcrctab_unused_gpl) = .; \
- *(SORT(___kcrctab_unused_gpl+*)) \
+ KEEP(*(SORT(___kcrctab_unused_gpl+*))) \
VMLINUX_SYMBOL(__stop___kcrctab_unused_gpl) = .; \
} \
\
/* Kernel symbol table: GPL-future-only symbols */ \
__kcrctab_gpl_future : AT(ADDR(__kcrctab_gpl_future) - LOAD_OFFSET) { \
VMLINUX_SYMBOL(__start___kcrctab_gpl_future) = .; \
- *(SORT(___kcrctab_gpl_future+*)) \
+ KEEP(*(SORT(___kcrctab_gpl_future+*))) \
VMLINUX_SYMBOL(__stop___kcrctab_gpl_future) = .; \
} \
\
@@ -382,14 +383,14 @@
/* Built-in module parameters. */ \
__param : AT(ADDR(__param) - LOAD_OFFSET) { \
VMLINUX_SYMBOL(__start___param) = .; \
- *(__param) \
+ KEEP(*(__param)) \
VMLINUX_SYMBOL(__stop___param) = .; \
} \
\
/* Built-in module versions. */ \
__modver : AT(ADDR(__modver) - LOAD_OFFSET) { \
VMLINUX_SYMBOL(__start___modver) = .; \
- *(__modver) \
+ KEEP(*(__modver)) \
VMLINUX_SYMBOL(__stop___modver) = .; \
. = ALIGN((align)); \
VMLINUX_SYMBOL(__end_rodata) = .; \
@@ -443,7 +444,7 @@
#define ENTRY_TEXT \
ALIGN_FUNCTION(); \
VMLINUX_SYMBOL(__entry_text_start) = .; \
- *(.entry.text) \
+ KEEP(*(.entry.text)) \
VMLINUX_SYMBOL(__entry_text_end) = .;
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
@@ -471,7 +472,7 @@
. = ALIGN(align); \
__ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) { \
VMLINUX_SYMBOL(__start___ex_table) = .; \
- *(__ex_table) \
+ KEEP(*(__ex_table)) \
VMLINUX_SYMBOL(__stop___ex_table) = .; \
}
@@ -487,9 +488,9 @@
#ifdef CONFIG_CONSTRUCTORS
#define KERNEL_CTORS() . = ALIGN(8); \
VMLINUX_SYMBOL(__ctors_start) = .; \
- *(.ctors) \
+ KEEP(*(.ctors)) \
*(SORT(.init_array.*)) \
- *(.init_array) \
+ KEEP(*(.init_array)) \
VMLINUX_SYMBOL(__ctors_end) = .;
#else
#define KERNEL_CTORS()
@@ -540,7 +541,7 @@
#define SBSS(sbss_align) \
. = ALIGN(sbss_align); \
.sbss : AT(ADDR(.sbss) - LOAD_OFFSET) { \
- *(.sbss) \
+ *(.sbss .sbss.*) \
*(.scommon) \
}
@@ -558,7 +559,7 @@
BSS_FIRST_SECTIONS \
*(.bss..page_aligned) \
*(.dynbss) \
- *(.bss) \
+ *(.bss .bss.*) \
*(COMMON) \
}
@@ -607,7 +608,7 @@
. = ALIGN(8); \
__bug_table : AT(ADDR(__bug_table) - LOAD_OFFSET) { \
VMLINUX_SYMBOL(__start___bug_table) = .; \
- *(__bug_table) \
+ KEEP(*(__bug_table)) \
VMLINUX_SYMBOL(__stop___bug_table) = .; \
}
#else
@@ -619,7 +620,7 @@
. = ALIGN(4); \
.tracedata : AT(ADDR(.tracedata) - LOAD_OFFSET) { \
VMLINUX_SYMBOL(__tracedata_start) = .; \
- *(.tracedata) \
+ KEEP(*(.tracedata)) \
VMLINUX_SYMBOL(__tracedata_end) = .; \
}
#else
@@ -636,17 +637,17 @@
#define INIT_SETUP(initsetup_align) \
. = ALIGN(initsetup_align); \
VMLINUX_SYMBOL(__setup_start) = .; \
- *(.init.setup) \
+ KEEP(*(.init.setup)) \
VMLINUX_SYMBOL(__setup_end) = .;
#define INIT_CALLS_LEVEL(level) \
VMLINUX_SYMBOL(__initcall##level##_start) = .; \
- *(.initcall##level##.init) \
- *(.initcall##level##s.init) \
+ KEEP(*(.initcall##level##.init)) \
+ KEEP(*(.initcall##level##s.init)) \
#define INIT_CALLS \
VMLINUX_SYMBOL(__initcall_start) = .; \
- *(.initcallearly.init) \
+ KEEP(*(.initcallearly.init)) \
INIT_CALLS_LEVEL(0) \
INIT_CALLS_LEVEL(1) \
INIT_CALLS_LEVEL(2) \
@@ -660,21 +661,21 @@
#define CON_INITCALL \
VMLINUX_SYMBOL(__con_initcall_start) = .; \
- *(.con_initcall.init) \
+ KEEP(*(.con_initcall.init)) \
VMLINUX_SYMBOL(__con_initcall_end) = .;
#define SECURITY_INITCALL \
VMLINUX_SYMBOL(__security_initcall_start) = .; \
- *(.security_initcall.init) \
+ KEEP(*(.security_initcall.init)) \
VMLINUX_SYMBOL(__security_initcall_end) = .;
#ifdef CONFIG_BLK_DEV_INITRD
#define INIT_RAM_FS \
. = ALIGN(4); \
VMLINUX_SYMBOL(__initramfs_start) = .; \
- *(.init.ramfs) \
+ KEEP(*(.init.ramfs)) \
. = ALIGN(8); \
- *(.init.ramfs.info)
+ KEEP(*(.init.ramfs.info))
#else
#define INIT_RAM_FS
#endif
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -22,11 +22,16 @@ endif
ifeq ($(CONFIG_ARM_MODULE_PLTS),y)
LDFLAGS_MODULE += -T $(srctree)/arch/arm/kernel/module.lds
endif
+LDFLAGS_vmlinux += --gc-sections
OBJCOPYFLAGS :=-O binary -R .comment -S
GZFLAGS :=-9
#KBUILD_CFLAGS +=-pipe
+ifndef CONFIG_FUNCTION_TRACER
+KBUILD_CFLAGS_KERNEL += -ffunction-sections -fdata-sections
+endif
+
# Never generate .eh_frame
KBUILD_CFLAGS += $(call cc-option,-fno-dwarf2-cfi-asm)
--- a/arch/arm/kernel/vmlinux.lds.S
+++ b/arch/arm/kernel/vmlinux.lds.S
@@ -15,13 +15,13 @@
#define PROC_INFO \
. = ALIGN(4); \
VMLINUX_SYMBOL(__proc_info_begin) = .; \
- *(.proc.info.init) \
+ KEEP(*(.proc.info.init)) \
VMLINUX_SYMBOL(__proc_info_end) = .;
#define IDMAP_TEXT \
ALIGN_FUNCTION(); \
VMLINUX_SYMBOL(__idmap_text_start) = .; \
- *(.idmap.text) \
+ KEEP(*(.idmap.text)) \
VMLINUX_SYMBOL(__idmap_text_end) = .; \
. = ALIGN(PAGE_SIZE); \
VMLINUX_SYMBOL(__hyp_idmap_text_start) = .; \
@@ -102,7 +102,7 @@ SECTIONS
_stext = .; /* Text and read-only data */
IDMAP_TEXT
__exception_text_start = .;
- *(.exception.text)
+ KEEP(*(.exception.text))
__exception_text_end = .;
IRQENTRY_TEXT
TEXT_TEXT
@@ -126,7 +126,7 @@ SECTIONS
__ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) {
__start___ex_table = .;
#ifdef CONFIG_MMU
- *(__ex_table)
+ KEEP(*(__ex_table))
#endif
__stop___ex_table = .;
}
@@ -138,12 +138,12 @@ SECTIONS
. = ALIGN(8);
.ARM.unwind_idx : {
__start_unwind_idx = .;
- *(.ARM.exidx*)
+ KEEP(*(.ARM.exidx*))
__stop_unwind_idx = .;
}
.ARM.unwind_tab : {
__start_unwind_tab = .;
- *(.ARM.extab*)
+ KEEP(*(.ARM.extab*))
__stop_unwind_tab = .;
}
#endif
@@ -166,14 +166,14 @@ SECTIONS
*/
__vectors_start = .;
.vectors 0 : AT(__vectors_start) {
- *(.vectors)
+ KEEP(*(.vectors))
}
. = __vectors_start + SIZEOF(.vectors);
__vectors_end = .;
__stubs_start = .;
.stubs 0x1000 : AT(__stubs_start) {
- *(.stubs)
+ KEEP(*(.stubs))
}
. = __stubs_start + SIZEOF(.stubs);
__stubs_end = .;
@@ -187,24 +187,24 @@ SECTIONS
}
.init.arch.info : {
__arch_info_begin = .;
- *(.arch.info.init)
+ KEEP(*(.arch.info.init))
__arch_info_end = .;
}
.init.tagtable : {
__tagtable_begin = .;
- *(.taglist.init)
+ KEEP(*(.taglist.init))
__tagtable_end = .;
}
#ifdef CONFIG_SMP_ON_UP
.init.smpalt : {
__smpalt_begin = .;
- *(.alt.smp.init)
+ KEEP(*(.alt.smp.init))
__smpalt_end = .;
}
#endif
.init.pv_table : {
__pv_table_begin = .;
- *(.pv_table)
+ KEEP(*(.pv_table))
__pv_table_end = .;
}
.init.data : {
--- a/arch/arm/boot/compressed/Makefile
+++ b/arch/arm/boot/compressed/Makefile
@@ -105,6 +105,7 @@ ifeq ($(CONFIG_FUNCTION_TRACER),y)
ORIG_CFLAGS := $(KBUILD_CFLAGS)
KBUILD_CFLAGS = $(subst -pg, , $(ORIG_CFLAGS))
endif
+KBUILD_CFLAGS_KERNEL := $(patsubst -f%-sections,,$(KBUILD_CFLAGS_KERNEL))
ccflags-y := -fpic -mno-single-pic-base -fno-builtin -I$(obj)
asflags-y := -DZIMAGE

@ -1,88 +0,0 @@
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -54,6 +54,16 @@
#define LOAD_OFFSET 0
#endif
+#ifndef SYMTAB_KEEP
+#define SYMTAB_KEEP KEEP(*(SORT(___ksymtab+*)))
+#define SYMTAB_KEEP_GPL KEEP(*(SORT(___ksymtab_gpl+*)))
+#endif
+
+#ifndef SYMTAB_DISCARD
+#define SYMTAB_DISCARD
+#define SYMTAB_DISCARD_GPL
+#endif
+
#include <linux/export.h>
/* Align . to a 8 byte boundary equals to maximum function alignment. */
@@ -301,14 +311,14 @@
/* Kernel symbol table: Normal symbols */ \
__ksymtab : AT(ADDR(__ksymtab) - LOAD_OFFSET) { \
VMLINUX_SYMBOL(__start___ksymtab) = .; \
- KEEP(*(SORT(___ksymtab+*))) \
+ SYMTAB_KEEP \
VMLINUX_SYMBOL(__stop___ksymtab) = .; \
} \
\
/* Kernel symbol table: GPL-only symbols */ \
__ksymtab_gpl : AT(ADDR(__ksymtab_gpl) - LOAD_OFFSET) { \
VMLINUX_SYMBOL(__start___ksymtab_gpl) = .; \
- KEEP(*(SORT(___ksymtab_gpl+*))) \
+ SYMTAB_KEEP_GPL \
VMLINUX_SYMBOL(__stop___ksymtab_gpl) = .; \
} \
\
@@ -370,7 +380,7 @@
\
/* Kernel symbol table: strings */ \
__ksymtab_strings : AT(ADDR(__ksymtab_strings) - LOAD_OFFSET) { \
- *(__ksymtab_strings) \
+ *(__ksymtab_strings+*) \
} \
\
/* __*init sections */ \
@@ -694,6 +704,8 @@
EXIT_TEXT \
EXIT_DATA \
EXIT_CALL \
+ SYMTAB_DISCARD \
+ SYMTAB_DISCARD_GPL \
*(.discard) \
*(.discard.*) \
}
--- a/scripts/Makefile.build
+++ b/scripts/Makefile.build
@@ -299,7 +299,7 @@ targets += $(extra-y) $(MAKECMDGOALS) $(
# Linker scripts preprocessor (.lds.S -> .lds)
# ---------------------------------------------------------------------------
quiet_cmd_cpp_lds_S = LDS $@
- cmd_cpp_lds_S = $(CPP) $(cpp_flags) -P -C -U$(ARCH) \
+ cmd_cpp_lds_S = $(CPP) $(EXTRA_LDSFLAGS) $(cpp_flags) -P -C -U$(ARCH) \
-D__ASSEMBLY__ -DLINKER_SCRIPT -o $@ $<
$(obj)/%.lds: $(src)/%.lds.S FORCE
--- a/include/linux/export.h
+++ b/include/linux/export.h
@@ -52,12 +52,19 @@ extern struct module __this_module;
#define __CRC_SYMBOL(sym, sec)
#endif
+#ifdef MODULE
+#define __EXPORT_SUFFIX(sym)
+#else
+#define __EXPORT_SUFFIX(sym) "+" #sym
+#endif
+
/* For every exported symbol, place a struct in the __ksymtab section */
#define __EXPORT_SYMBOL(sym, sec) \
extern typeof(sym) sym; \
__CRC_SYMBOL(sym, sec) \
static const char __kstrtab_##sym[] \
- __attribute__((section("__ksymtab_strings"), aligned(1))) \
+ __attribute__((section("__ksymtab_strings" \
+ __EXPORT_SUFFIX(sym)), aligned(1))) \
= VMLINUX_SYMBOL_STR(sym); \
extern const struct kernel_symbol __ksymtab_##sym; \
__visible const struct kernel_symbol __ksymtab_##sym \

@ -1,58 +0,0 @@
--- a/scripts/Makefile.lib
+++ b/scripts/Makefile.lib
@@ -324,7 +324,7 @@ cmd_bzip2 = (cat $(filter-out FORCE,$^)
quiet_cmd_lzma = LZMA $@
cmd_lzma = (cat $(filter-out FORCE,$^) | \
- lzma -9 && $(call size_append, $(filter-out FORCE,$^))) > $@ || \
+ lzma e -d20 -lc1 -lp2 -pb2 -eos -si -so && $(call size_append, $(filter-out FORCE,$^))) > $@ || \
(rm -f $@ ; false)
quiet_cmd_lzo = LZO $@
--- a/scripts/gen_initramfs_list.sh
+++ b/scripts/gen_initramfs_list.sh
@@ -226,7 +226,7 @@ cpio_list=
output="/dev/stdout"
output_file=""
is_cpio_compressed=
-compr="gzip -n -9 -f"
+compr="gzip -n -9 -f -"
arg="$1"
case "$arg" in
@@ -242,13 +242,13 @@ case "$arg" in
output=${cpio_list}
echo "$output_file" | grep -q "\.gz$" \
&& [ -x "`which gzip 2> /dev/null`" ] \
- && compr="gzip -n -9 -f"
+ && compr="gzip -n -9 -f -"
echo "$output_file" | grep -q "\.bz2$" \
&& [ -x "`which bzip2 2> /dev/null`" ] \
- && compr="bzip2 -9 -f"
+ && compr="bzip2 -9 -f -"
echo "$output_file" | grep -q "\.lzma$" \
&& [ -x "`which lzma 2> /dev/null`" ] \
- && compr="lzma -9 -f"
+ && compr="lzma e -d20 -lc1 -lp2 -pb2 -eos -si -so"
echo "$output_file" | grep -q "\.xz$" \
&& [ -x "`which xz 2> /dev/null`" ] \
&& compr="xz --check=crc32 --lzma2=dict=1MiB"
@@ -315,7 +315,7 @@ if [ ! -z ${output_file} ]; then
if [ "${is_cpio_compressed}" = "compressed" ]; then
cat ${cpio_tfile} > ${output_file}
else
- (cat ${cpio_tfile} | ${compr} - > ${output_file}) \
+ (cat ${cpio_tfile} | ${compr} > ${output_file}) \
|| (rm -f ${output_file} ; false)
fi
[ -z ${cpio_file} ] && rm ${cpio_tfile}
--- a/lib/decompress.c
+++ b/lib/decompress.c
@@ -48,6 +48,7 @@ static const struct compress_format comp
{ {0x1f, 0x9e}, "gzip", gunzip },
{ {0x42, 0x5a}, "bzip2", bunzip2 },
{ {0x5d, 0x00}, "lzma", unlzma },
+ { {0x6d, 0x00}, "lzma-openwrt", unlzma },
{ {0xfd, 0x37}, "xz", unxz },
{ {0x89, 0x4c}, "lzo", unlzo },
{ {0x02, 0x21}, "lz4", unlz4 },

@ -1,18 +0,0 @@
--- a/net/netfilter/Kconfig
+++ b/net/netfilter/Kconfig
@@ -218,7 +218,6 @@ config NF_CONNTRACK_FTP
config NF_CONNTRACK_H323
tristate "H.323 protocol support"
- depends on IPV6 || IPV6=n
depends on NETFILTER_ADVANCED
help
H.323 is a VoIP signalling protocol from ITU-T. As one of the most
@@ -929,7 +928,6 @@ config NETFILTER_XT_TARGET_SECMARK
config NETFILTER_XT_TARGET_TCPMSS
tristate '"TCPMSS" target support'
- depends on IPV6 || IPV6=n
default m if NETFILTER_ADVANCED=n
---help---
This option adds a `TCPMSS' target, which allows you to alter the

@ -1,18 +0,0 @@
--- a/sound/core/Kconfig
+++ b/sound/core/Kconfig
@@ -16,13 +16,13 @@ config SND_DMAENGINE_PCM
tristate
config SND_HWDEP
- tristate
+ tristate "Sound hardware support"
config SND_RAWMIDI
tristate
config SND_COMPRESS_OFFLOAD
- tristate
+ tristate "Compression offloading support"
# To be effective this also requires INPUT - users should say:
# select SND_JACK if INPUT=y || INPUT=SND

@ -1,10 +0,0 @@
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -163,6 +163,7 @@ config CRYPTO_DEV_MV_CESA
tristate "Marvell's Cryptographic Engine"
depends on PLAT_ORION
select CRYPTO_AES
+ select CRYPTO_HASH2
select CRYPTO_BLKCIPHER
select CRYPTO_HASH
select SRAM

@ -1,29 +0,0 @@
--- a/drivers/ssb/Kconfig
+++ b/drivers/ssb/Kconfig
@@ -29,6 +29,7 @@ config SSB_SPROM
config SSB_BLOCKIO
bool
depends on SSB
+ default y
config SSB_PCIHOST_POSSIBLE
bool
@@ -49,7 +50,7 @@ config SSB_PCIHOST
config SSB_B43_PCI_BRIDGE
bool
depends on SSB_PCIHOST
- default n
+ default y
config SSB_PCMCIAHOST_POSSIBLE
bool
--- a/drivers/bcma/Kconfig
+++ b/drivers/bcma/Kconfig
@@ -17,6 +17,7 @@ config BCMA
config BCMA_BLOCKIO
bool
depends on BCMA
+ default y
config BCMA_HOST_PCI_POSSIBLE
bool

@ -1,23 +0,0 @@
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -332,16 +332,16 @@ config BCH_CONST_T
# Textsearch support is select'ed if needed
#
config TEXTSEARCH
- bool
+ boolean "Textsearch support"
config TEXTSEARCH_KMP
- tristate
+ tristate "Textsearch KMP"
config TEXTSEARCH_BM
- tristate
+ tristate "Textsearch BM"
config TEXTSEARCH_FSM
- tristate
+ tristate "Textsearch FSM"
config BTREE
bool

@ -1,31 +0,0 @@
--- a/net/wireless/Kconfig
+++ b/net/wireless/Kconfig
@@ -191,7 +191,7 @@ config CFG80211_WEXT_EXPORT
wext compatibility symbols to be exported.
config LIB80211
- tristate
+ tristate "LIB80211"
default n
help
This options enables a library of common routines used
@@ -200,13 +200,16 @@ config LIB80211
Drivers should select this themselves if needed.
config LIB80211_CRYPT_WEP
- tristate
+ tristate "LIB80211_CRYPT_WEP"
+ select LIB80211
config LIB80211_CRYPT_CCMP
- tristate
+ tristate "LIB80211_CRYPT_CCMP"
+ select LIB80211
config LIB80211_CRYPT_TKIP
- tristate
+ tristate "LIB80211_CRYPT_TKIP"
+ select LIB80211
config LIB80211_DEBUG
bool "lib80211 debugging messages"

@ -1,47 +0,0 @@
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -32,7 +32,7 @@ config CRYPTO_FIPS
this is.
config CRYPTO_ALGAPI
- tristate
+ tristate "ALGAPI"
select CRYPTO_ALGAPI2
help
This option provides the API for cryptographic algorithms.
@@ -41,7 +41,7 @@ config CRYPTO_ALGAPI2
tristate
config CRYPTO_AEAD
- tristate
+ tristate "AEAD"
select CRYPTO_AEAD2
select CRYPTO_ALGAPI
@@ -52,7 +52,7 @@ config CRYPTO_AEAD2
select CRYPTO_RNG2
config CRYPTO_BLKCIPHER
- tristate
+ tristate "BLKCIPHER"
select CRYPTO_BLKCIPHER2
select CRYPTO_ALGAPI
@@ -63,7 +63,7 @@ config CRYPTO_BLKCIPHER2
select CRYPTO_WORKQUEUE
config CRYPTO_HASH
- tristate
+ tristate "HASH"
select CRYPTO_HASH2
select CRYPTO_ALGAPI
@@ -72,7 +72,7 @@ config CRYPTO_HASH2
select CRYPTO_ALGAPI2
config CRYPTO_RNG
- tristate
+ tristate "RNG"
select CRYPTO_RNG2
select CRYPTO_ALGAPI

@ -1,22 +0,0 @@
--- a/net/wireless/Kconfig
+++ b/net/wireless/Kconfig
@@ -1,5 +1,5 @@
config WIRELESS_EXT
- bool
+ bool "Wireless extensions"
config WEXT_CORE
def_bool y
@@ -11,10 +11,10 @@ config WEXT_PROC
depends on WEXT_CORE
config WEXT_SPY
- bool
+ bool "WEXT_SPY"
config WEXT_PRIV
- bool
+ bool "WEXT_PRIV"
config CFG80211
tristate "cfg80211 - wireless configuration API"

@ -1,11 +0,0 @@
--- a/net/netfilter/Kconfig
+++ b/net/netfilter/Kconfig
@@ -10,7 +10,7 @@ config NETFILTER_INGRESS
infrastructure.
config NETFILTER_NETLINK
- tristate
+ tristate "Netfilter NFNETLINK interface"
config NETFILTER_NETLINK_ACCT
tristate "Netfilter NFACCT over NFNETLINK interface"

@ -1,87 +0,0 @@
--- a/drivers/base/regmap/Kconfig
+++ b/drivers/base/regmap/Kconfig
@@ -3,29 +3,35 @@
# subsystems should select the appropriate symbols.
config REGMAP
- default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_AC97 || REGMAP_MMIO || REGMAP_IRQ)
select LZO_COMPRESS
select LZO_DECOMPRESS
select IRQ_DOMAIN if REGMAP_IRQ
- bool
+ tristate "Regmap"
config REGMAP_AC97
+ select REGMAP
tristate
config REGMAP_I2C
- tristate
+ tristate "Regmap I2C"
+ select REGMAP
depends on I2C
config REGMAP_SPI
- tristate
+ tristate "Regmap SPI"
+ select REGMAP
+ depends on SPI_MASTER
depends on SPI
config REGMAP_SPMI
+ select REGMAP
tristate
depends on SPMI
config REGMAP_MMIO
- tristate
+ tristate "Regmap MMIO"
+ select REGMAP
config REGMAP_IRQ
+ select REGMAP
bool
--- a/include/linux/regmap.h
+++ b/include/linux/regmap.h
@@ -65,7 +65,7 @@ struct reg_sequence {
unsigned int delay_us;
};
-#ifdef CONFIG_REGMAP
+#if IS_ENABLED(CONFIG_REGMAP)
enum regmap_endian {
/* Unspecified -> 0 -> Backwards compatible default */
--- a/drivers/base/regmap/Makefile
+++ b/drivers/base/regmap/Makefile
@@ -1,9 +1,11 @@
# For include/trace/define_trace.h to include trace.h
CFLAGS_regmap.o := -I$(src)
-obj-$(CONFIG_REGMAP) += regmap.o regcache.o
-obj-$(CONFIG_REGMAP) += regcache-rbtree.o regcache-lzo.o regcache-flat.o
-obj-$(CONFIG_DEBUG_FS) += regmap-debugfs.o
+regmap-core-objs = regmap.o regcache.o regcache-rbtree.o regcache-lzo.o regcache-flat.o
+ifdef CONFIG_DEBUG_FS
+regmap-core-objs += regmap-debugfs.o
+endif
+obj-$(CONFIG_REGMAP) += regmap-core.o
obj-$(CONFIG_REGMAP_AC97) += regmap-ac97.o
obj-$(CONFIG_REGMAP_I2C) += regmap-i2c.o
obj-$(CONFIG_REGMAP_SPI) += regmap-spi.o
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -13,6 +13,7 @@
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/export.h>
+#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/err.h>
#include <linux/of.h>
@@ -2852,3 +2853,5 @@ static int __init regmap_initcall(void)
return 0;
}
postcore_initcall(regmap_initcall);
+
+MODULE_LICENSE("GPL");

@ -1,38 +0,0 @@
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -119,11 +119,11 @@ config CRYPTO_MANAGER
config CRYPTO_MANAGER2
def_tristate CRYPTO_MANAGER || (CRYPTO_MANAGER!=n && CRYPTO_ALGAPI=y)
- select CRYPTO_AEAD2
- select CRYPTO_HASH2
- select CRYPTO_BLKCIPHER2
- select CRYPTO_PCOMP2
- select CRYPTO_AKCIPHER2
+ select CRYPTO_AEAD2 if !CRYPTO_MANAGER_DISABLE_TESTS
+ select CRYPTO_HASH2 if !CRYPTO_MANAGER_DISABLE_TESTS
+ select CRYPTO_BLKCIPHER2 if !CRYPTO_MANAGER_DISABLE_TESTS
+ select CRYPTO_PCOMP2 if !CRYPTO_MANAGER_DISABLE_TESTS
+ select CRYPTO_AKCIPHER2 if !CRYPTO_MANAGER_DISABLE_TESTS
config CRYPTO_USER
tristate "Userspace cryptographic algorithm configuration"
--- a/crypto/algboss.c
+++ b/crypto/algboss.c
@@ -248,12 +248,16 @@ static int cryptomgr_schedule_test(struc
type = alg->cra_flags;
/* This piece of crap needs to disappear into per-type test hooks. */
+#ifdef CONFIG_CRYPTO_MANAGER_DISABLE_TESTS
+ type |= CRYPTO_ALG_TESTED;
+#else
if (!((type ^ CRYPTO_ALG_TYPE_BLKCIPHER) &
CRYPTO_ALG_TYPE_BLKCIPHER_MASK) && !(type & CRYPTO_ALG_GENIV) &&
((alg->cra_flags & CRYPTO_ALG_TYPE_MASK) ==
CRYPTO_ALG_TYPE_BLKCIPHER ? alg->cra_blkcipher.ivsize :
alg->cra_ablkcipher.ivsize))
type |= CRYPTO_ALG_TESTED;
+#endif
param->type = type;

@ -1,36 +0,0 @@
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -216,26 +216,26 @@ config 842_DECOMPRESS
tristate
config ZLIB_INFLATE
- tristate
+ tristate "ZLIB inflate support"
config ZLIB_DEFLATE
- tristate
+ tristate "ZLIB deflate support"
select BITREVERSE
config LZO_COMPRESS
- tristate
+ tristate "LZO compress support"
config LZO_DECOMPRESS
- tristate
+ tristate "LZO decompress support"
config LZ4_COMPRESS
- tristate
+ tristate "LZ4 compress support"
config LZ4HC_COMPRESS
- tristate
+ tristate "LZ4HC compress support"
config LZ4_DECOMPRESS
- tristate
+ tristate "LZ4 decompress support"
source "lib/xz/Kconfig"

@ -1,34 +0,0 @@
From 8b05e325824d3b38e52a7748b3b5dc34dc1c0f6d Mon Sep 17 00:00:00 2001
From: David Heidelberger <david.heidelberger@ixit.cz>
Date: Mon, 29 Jun 2015 14:37:54 +0200
Subject: [PATCH 1/3] uapi/kernel.h: glibc specific inclusion of sysinfo.h
including sysinfo.h from kernel.h makes no sense whatsoever,
but removing it breaks glibc's userspace header,
which includes kernel.h instead of sysinfo.h from their sys/sysinfo.h.
this seems to be a historical mistake.
on musl, including any header that uses kernel.h directly or indirectly
plus sys/sysinfo.h will produce a compile error due to redefinition of
struct sysinfo from sys/sysinfo.h.
so for now, only include it on glibc or when including from kernel
in order not to break their headers.
Signed-off-by: John Spencer <maillist-linux@barfooze.de>
Signed-off-by: David Heidelberger <david.heidelberger@ixit.cz>
Signed-off-by: Jonas Gorski <jogo@openwrt.org>
---
include/uapi/linux/kernel.h | 2 ++
1 file changed, 2 insertions(+)
--- a/include/uapi/linux/kernel.h
+++ b/include/uapi/linux/kernel.h
@@ -1,7 +1,9 @@
#ifndef _UAPI_LINUX_KERNEL_H
#define _UAPI_LINUX_KERNEL_H
+#if defined(__KERNEL__) || defined( __GLIBC__)
#include <linux/sysinfo.h>
+#endif
/*
* 'kernel.h' contains some often-used function prototypes etc

@ -1,81 +0,0 @@
From f972afc2509eebcb00d370256c55b112a3b5ffca Mon Sep 17 00:00:00 2001
From: David Heidelberger <david.heidelberger@ixit.cz>
Date: Mon, 29 Jun 2015 16:50:40 +0200
Subject: [PATCH 2/3] uapi/libc-compat.h: do not rely on __GLIBC__
Musl provides the same structs as glibc, but does not provide a define to
allow its detection. Since the absence of __GLIBC__ also can mean that it
is included from the kernel, change the __GLIBC__ detection to
!__KERNEL__, which should always be true when included from userspace.
Signed-off-by: John Spencer <maillist-linux@barfooze.de>
Tested-by: David Heidelberger <david.heidelberger@ixit.cz>
Signed-off-by: Jonas Gorski <jogo@openwrt.org>
---
include/uapi/linux/libc-compat.h | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
--- a/include/uapi/linux/libc-compat.h
+++ b/include/uapi/linux/libc-compat.h
@@ -48,13 +48,13 @@
#ifndef _UAPI_LIBC_COMPAT_H
#define _UAPI_LIBC_COMPAT_H
-/* We have included glibc headers... */
-#if defined(__GLIBC__)
+/* We have included libc headers... */
+#if !defined(__KERNEL__)
-/* Coordinate with glibc netinet/in.h header. */
+/* Coordinate with libc netinet/in.h header. */
#if defined(_NETINET_IN_H)
-/* GLIBC headers included first so don't define anything
+/* LIBC headers included first so don't define anything
* that would already be defined. */
#define __UAPI_DEF_IN_ADDR 0
#define __UAPI_DEF_IN_IPPROTO 0
@@ -68,7 +68,7 @@
* if the glibc code didn't define them. This guard matches
* the guard in glibc/inet/netinet/in.h which defines the
* additional in6_addr macros e.g. s6_addr16, and s6_addr32. */
-#if defined(__USE_MISC) || defined (__USE_GNU)
+#if !defined(__GLIBC__) || defined(__USE_MISC) || defined (__USE_GNU)
#define __UAPI_DEF_IN6_ADDR_ALT 0
#else
#define __UAPI_DEF_IN6_ADDR_ALT 1
@@ -83,7 +83,7 @@
#else
/* Linux headers included first, and we must define everything
- * we need. The expectation is that glibc will check the
+ * we need. The expectation is that the libc will check the
* __UAPI_DEF_* defines and adjust appropriately. */
#define __UAPI_DEF_IN_ADDR 1
#define __UAPI_DEF_IN_IPPROTO 1
@@ -93,7 +93,7 @@
#define __UAPI_DEF_IN_CLASS 1
#define __UAPI_DEF_IN6_ADDR 1
-/* We unconditionally define the in6_addr macros and glibc must
+/* We unconditionally define the in6_addr macros and the libc must
* coordinate. */
#define __UAPI_DEF_IN6_ADDR_ALT 1
#define __UAPI_DEF_SOCKADDR_IN6 1
@@ -115,7 +115,7 @@
/* If we did not see any headers from any supported C libraries,
* or we are being included in the kernel, then define everything
* that we need. */
-#else /* !defined(__GLIBC__) */
+#else /* defined(__KERNEL__) */
/* Definitions for in.h */
#define __UAPI_DEF_IN_ADDR 1
@@ -138,6 +138,6 @@
/* Definitions for xattr.h */
#define __UAPI_DEF_XATTR 1
-#endif /* __GLIBC__ */
+#endif /* __KERNEL__ */
#endif /* _UAPI_LIBC_COMPAT_H */

@ -1,67 +0,0 @@
From fcbb6fed85ea9ff4feb4f1ebd4f0f235fdaf06b6 Mon Sep 17 00:00:00 2001
From: David Heidelberger <david.heidelberger@ixit.cz>
Date: Mon, 29 Jun 2015 16:53:03 +0200
Subject: [PATCH 3/3] uapi/if_ether.h: prevent redefinition of struct ethhdr
Musl provides its own ethhdr struct definition. Add a guard to prevent
its definition of the appropriate musl header has already been included.
Signed-off-by: John Spencer <maillist-linux@barfooze.de>
Tested-by: David Heidelberger <david.heidelberger@ixit.cz>
Signed-off-by: Jonas Gorski <jogo@openwrt.org>
---
include/uapi/linux/if_ether.h | 3 +++
include/uapi/linux/libc-compat.h | 11 +++++++++++
2 files changed, 14 insertions(+)
--- a/include/uapi/linux/if_ether.h
+++ b/include/uapi/linux/if_ether.h
@@ -22,6 +22,7 @@
#define _UAPI_LINUX_IF_ETHER_H
#include <linux/types.h>
+#include <linux/libc-compat.h>
/*
* IEEE 802.3 Ethernet magic constants. The frame sizes omit the preamble
@@ -135,11 +136,13 @@
* This is an Ethernet frame header.
*/
+#if __UAPI_DEF_ETHHDR
struct ethhdr {
unsigned char h_dest[ETH_ALEN]; /* destination eth addr */
unsigned char h_source[ETH_ALEN]; /* source ether addr */
__be16 h_proto; /* packet type ID field */
} __attribute__((packed));
+#endif
#endif /* _UAPI_LINUX_IF_ETHER_H */
--- a/include/uapi/linux/libc-compat.h
+++ b/include/uapi/linux/libc-compat.h
@@ -51,6 +51,14 @@
/* We have included libc headers... */
#if !defined(__KERNEL__)
+/* musl defines the ethhdr struct itself in its netinet/if_ether.h.
+ * Glibc just includes the kernel header and uses a different guard. */
+#if defined(_NETINET_IF_ETHER_H)
+#define __UAPI_DEF_ETHHDR 0
+#else
+#define __UAPI_DEF_ETHHDR 1
+#endif
+
/* Coordinate with libc netinet/in.h header. */
#if defined(_NETINET_IN_H)
@@ -117,6 +125,9 @@
* that we need. */
#else /* defined(__KERNEL__) */
+/* Definitions for if_ether.h */
+#define __UAPI_DEF_ETHHDR 1
+
/* Definitions for in.h */
#define __UAPI_DEF_IN_ADDR 1
#define __UAPI_DEF_IN_IPPROTO 1

@ -1,39 +0,0 @@
From: Mark Miller <mark@mirell.org>
This exposes the CONFIG_BOOT_RAW symbol in Kconfig. This is needed on
certain Broadcom chipsets running CFE in order to load the kernel.
Signed-off-by: Mark Miller <mark@mirell.org>
Acked-by: Rob Landley <rob@landley.net>
---
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -1003,9 +1003,6 @@ config FW_ARC
config ARCH_MAY_HAVE_PC_FDC
bool
-config BOOT_RAW
- bool
-
config CEVT_BCM1480
bool
@@ -2733,6 +2730,18 @@ choice
if you don't intend to always append a DTB.
endchoice
+config BOOT_RAW
+ bool "Enable the kernel to be executed from the load address"
+ default n
+ help
+ Allow the kernel to be executed from the load address for
+ bootloaders which cannot read the ELF format. This places
+ a jump to start_kernel at the load address.
+
+ If unsure, say N.
+
+
+
endmenu
config LOCKDEP_SUPPORT

@ -1,28 +0,0 @@
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -1091,6 +1091,10 @@ config SYNC_R4K
config MIPS_MACHINE
def_bool n
+config IMAGE_CMDLINE_HACK
+ bool "OpenWrt specific image command line hack"
+ default n
+
config NO_IOPORT_MAP
def_bool n
--- a/arch/mips/kernel/head.S
+++ b/arch/mips/kernel/head.S
@@ -80,6 +80,12 @@ FEXPORT(__kernel_entry)
j kernel_entry
#endif
+#ifdef CONFIG_IMAGE_CMDLINE_HACK
+ .ascii "CMDLINE:"
+EXPORT(__image_cmdline)
+ .fill 0x400
+#endif /* CONFIG_IMAGE_CMDLINE_HACK */
+
__REF
NESTED(kernel_entry, 16, sp) # kernel entry point

@ -1,11 +0,0 @@
--- a/arch/mips/Makefile
+++ b/arch/mips/Makefile
@@ -87,7 +87,7 @@ all-$(CONFIG_SYS_SUPPORTS_ZBOOT)+= vmlin
# machines may also. Since BFD is incredibly buggy with respect to
# crossformat linking we rely on the elf2ecoff tool for format conversion.
#
-cflags-y += -G 0 -mno-abicalls -fno-pic -pipe
+cflags-y += -G 0 -mno-abicalls -fno-pic -pipe -mno-branch-likely
cflags-y += -msoft-float
LDFLAGS_vmlinux += -G 0 -static -n -nostdlib --gc-sections
KBUILD_AFLAGS_MODULE += -mlong-calls

@ -1,106 +0,0 @@
From: Manuel Lauss <manuel.lauss@gmail.com>
Subject: [RFC PATCH v4 2/2] MIPS: make FPU emulator optional
Date: Mon, 7 Apr 2014 12:57:04 +0200
Message-Id: <1396868224-252888-2-git-send-email-manuel.lauss@gmail.com>
This small patch makes the MIPS FPU emulator optional. The kernel
kills float-users on systems without a hardware FPU by sending a SIGILL.
Disabling the emulator shrinks vmlinux by about 54kBytes (32bit,
optimizing for size).
Signed-off-by: Manuel Lauss <manuel.lauss@gmail.com>
---
v4: rediffed because of patch 1/2, should now work with micromips as well
v3: updated patch description with size savings.
v2: incorporated changes suggested by Jonas Gorski
force the fpu emulator on for micromips: relocating the parts
of the mmips code in the emulator to other areas would be a
much larger change; I went the cheap route instead with this.
arch/mips/Kbuild | 2 +-
arch/mips/Kconfig | 14 ++++++++++++++
arch/mips/include/asm/fpu.h | 5 +++--
arch/mips/include/asm/fpu_emulator.h | 15 +++++++++++++++
4 files changed, 33 insertions(+), 3 deletions(-)
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -2680,6 +2680,20 @@ config MIPS_O32_FP64_SUPPORT
If unsure, say N.
+config MIPS_FPU_EMULATOR
+ bool "MIPS FPU Emulator"
+ default y
+ help
+ This option lets you disable the built-in MIPS FPU (Coprocessor 1)
+ emulator, which handles floating-point instructions on processors
+ without a hardware FPU. It is generally a good idea to keep the
+ emulator built-in, unless you are perfectly sure you have a
+ complete soft-float environment. With the emulator disabled, all
+ users of float operations will be killed with an illegal instr-
+ uction exception.
+
+ Say Y, please.
+
config USE_OF
bool
select OF
--- a/arch/mips/Makefile
+++ b/arch/mips/Makefile
@@ -285,7 +285,7 @@ OBJCOPYFLAGS += --remove-section=.regin
head-y := arch/mips/kernel/head.o
libs-y += arch/mips/lib/
-libs-y += arch/mips/math-emu/
+libs-$(CONFIG_MIPS_FPU_EMULATOR) += arch/mips/math-emu/
# See arch/mips/Kbuild for content of core part of the kernel
core-y += arch/mips/
--- a/arch/mips/include/asm/fpu.h
+++ b/arch/mips/include/asm/fpu.h
@@ -223,8 +223,10 @@ static inline int init_fpu(void)
/* Restore FRE */
write_c0_config5(config5);
enable_fpu_hazard();
- } else
+ } else if (IS_ENABLED(CONFIG_MIPS_FPU_EMULATOR))
fpu_emulator_init_fpu();
+ else
+ ret = SIGILL;
return ret;
}
--- a/arch/mips/include/asm/fpu_emulator.h
+++ b/arch/mips/include/asm/fpu_emulator.h
@@ -30,6 +30,7 @@
#include <asm/local.h>
#include <asm/processor.h>
+#ifdef CONFIG_MIPS_FPU_EMULATOR
#ifdef CONFIG_DEBUG_FS
struct mips_fpu_emulator_stats {
@@ -66,6 +67,21 @@ extern int do_dsemulret(struct pt_regs *
extern int fpu_emulator_cop1Handler(struct pt_regs *xcp,
struct mips_fpu_struct *ctx, int has_fpu,
void *__user *fault_addr);
+#else /* no CONFIG_MIPS_FPU_EMULATOR */
+static inline int do_dsemulret(struct pt_regs *xcp)
+{
+ return 0; /* 0 means error, should never get here anyway */
+}
+
+static inline int fpu_emulator_cop1Handler(struct pt_regs *xcp,
+ struct mips_fpu_struct *ctx, int has_fpu,
+ void *__user *fault_addr)
+{
+ *fault_addr = NULL;
+ return SIGILL; /* we don't speak MIPS FPU */
+}
+#endif /* CONFIG_MIPS_FPU_EMULATOR */
+
int process_fpemu_return(int sig, void __user *fault_addr,
unsigned long fcr31);
int mm_isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,

@ -1,352 +0,0 @@
--- a/arch/mips/Makefile
+++ b/arch/mips/Makefile
@@ -90,8 +90,13 @@ all-$(CONFIG_SYS_SUPPORTS_ZBOOT)+= vmlin
cflags-y += -G 0 -mno-abicalls -fno-pic -pipe -mno-branch-likely
cflags-y += -msoft-float
LDFLAGS_vmlinux += -G 0 -static -n -nostdlib --gc-sections
+ifdef CONFIG_64BIT
KBUILD_AFLAGS_MODULE += -mlong-calls
KBUILD_CFLAGS_MODULE += -mlong-calls
+else
+KBUILD_AFLAGS_MODULE += -mno-long-calls
+KBUILD_CFLAGS_MODULE += -mno-long-calls
+endif
ifndef CONFIG_FUNCTION_TRACER
KBUILD_CFLAGS_KERNEL += -ffunction-sections -fdata-sections
--- a/arch/mips/include/asm/module.h
+++ b/arch/mips/include/asm/module.h
@@ -11,6 +11,11 @@ struct mod_arch_specific {
const struct exception_table_entry *dbe_start;
const struct exception_table_entry *dbe_end;
struct mips_hi16 *r_mips_hi16_list;
+
+ void *phys_plt_tbl;
+ void *virt_plt_tbl;
+ unsigned int phys_plt_offset;
+ unsigned int virt_plt_offset;
};
typedef uint8_t Elf64_Byte; /* Type for a 8-bit quantity. */
--- a/arch/mips/kernel/module.c
+++ b/arch/mips/kernel/module.c
@@ -43,14 +43,221 @@ struct mips_hi16 {
static LIST_HEAD(dbe_list);
static DEFINE_SPINLOCK(dbe_lock);
-#ifdef MODULE_START
+/*
+ * Get the potential max trampolines size required of the init and
+ * non-init sections. Only used if we cannot find enough contiguous
+ * physically mapped memory to put the module into.
+ */
+static unsigned int
+get_plt_size(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs,
+ const char *secstrings, unsigned int symindex, bool is_init)
+{
+ unsigned long ret = 0;
+ unsigned int i, j;
+ Elf_Sym *syms;
+
+ /* Everything marked ALLOC (this includes the exported symbols) */
+ for (i = 1; i < hdr->e_shnum; ++i) {
+ unsigned int info = sechdrs[i].sh_info;
+
+ if (sechdrs[i].sh_type != SHT_REL
+ && sechdrs[i].sh_type != SHT_RELA)
+ continue;
+
+ /* Not a valid relocation section? */
+ if (info >= hdr->e_shnum)
+ continue;
+
+ /* Don't bother with non-allocated sections */
+ if (!(sechdrs[info].sh_flags & SHF_ALLOC))
+ continue;
+
+ /* If it's called *.init*, and we're not init, we're
+ not interested */
+ if ((strstr(secstrings + sechdrs[i].sh_name, ".init") != 0)
+ != is_init)
+ continue;
+
+ syms = (Elf_Sym *) sechdrs[symindex].sh_addr;
+ if (sechdrs[i].sh_type == SHT_REL) {
+ Elf_Mips_Rel *rel = (void *) sechdrs[i].sh_addr;
+ unsigned int size = sechdrs[i].sh_size / sizeof(*rel);
+
+ for (j = 0; j < size; ++j) {
+ Elf_Sym *sym;
+
+ if (ELF_MIPS_R_TYPE(rel[j]) != R_MIPS_26)
+ continue;
+
+ sym = syms + ELF_MIPS_R_SYM(rel[j]);
+ if (!is_init && sym->st_shndx != SHN_UNDEF)
+ continue;
+
+ ret += 4 * sizeof(int);
+ }
+ } else {
+ Elf_Mips_Rela *rela = (void *) sechdrs[i].sh_addr;
+ unsigned int size = sechdrs[i].sh_size / sizeof(*rela);
+
+ for (j = 0; j < size; ++j) {
+ Elf_Sym *sym;
+
+ if (ELF_MIPS_R_TYPE(rela[j]) != R_MIPS_26)
+ continue;
+
+ sym = syms + ELF_MIPS_R_SYM(rela[j]);
+ if (!is_init && sym->st_shndx != SHN_UNDEF)
+ continue;
+
+ ret += 4 * sizeof(int);
+ }
+ }
+ }
+
+ return ret;
+}
+
+#ifndef MODULE_START
+static void *alloc_phys(unsigned long size)
+{
+ unsigned order;
+ struct page *page;
+ struct page *p;
+
+ size = PAGE_ALIGN(size);
+ order = get_order(size);
+
+ page = alloc_pages(GFP_KERNEL | __GFP_NORETRY | __GFP_NOWARN |
+ __GFP_THISNODE, order);
+ if (!page)
+ return NULL;
+
+ split_page(page, order);
+
+ /* mark all pages except for the last one */
+ for (p = page; p + 1 < page + (size >> PAGE_SHIFT); ++p)
+ set_bit(PG_owner_priv_1, &p->flags);
+
+ for (p = page + (size >> PAGE_SHIFT); p < page + (1 << order); ++p)
+ __free_page(p);
+
+ return page_address(page);
+}
+#endif
+
+static void free_phys(void *ptr)
+{
+ struct page *page;
+ bool free;
+
+ page = virt_to_page(ptr);
+ do {
+ free = test_and_clear_bit(PG_owner_priv_1, &page->flags);
+ __free_page(page);
+ page++;
+ } while (free);
+}
+
+
void *module_alloc(unsigned long size)
{
+#ifdef MODULE_START
return __vmalloc_node_range(size, 1, MODULE_START, MODULE_END,
GFP_KERNEL, PAGE_KERNEL, 0, NUMA_NO_NODE,
__builtin_return_address(0));
+#else
+ void *ptr;
+
+ if (size == 0)
+ return NULL;
+
+ ptr = alloc_phys(size);
+
+ /* If we failed to allocate physically contiguous memory,
+ * fall back to regular vmalloc. The module loader code will
+ * create jump tables to handle long jumps */
+ if (!ptr)
+ return vmalloc(size);
+
+ return ptr;
+#endif
}
+
+static inline bool is_phys_addr(void *ptr)
+{
+#ifdef CONFIG_64BIT
+ return (KSEGX((unsigned long)ptr) == CKSEG0);
+#else
+ return (KSEGX(ptr) == KSEG0);
#endif
+}
+
+/* Free memory returned from module_alloc */
+void module_memfree(void *module_region)
+{
+ if (is_phys_addr(module_region))
+ free_phys(module_region);
+ else
+ vfree(module_region);
+}
+
+static void *__module_alloc(int size, bool phys)
+{
+ void *ptr;
+
+ if (phys)
+ ptr = kmalloc(size, GFP_KERNEL);
+ else
+ ptr = vmalloc(size);
+ return ptr;
+}
+
+static void __module_free(void *ptr)
+{
+ if (is_phys_addr(ptr))
+ kfree(ptr);
+ else
+ vfree(ptr);
+}
+
+int module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs,
+ char *secstrings, struct module *mod)
+{
+ unsigned int symindex = 0;
+ unsigned int core_size, init_size;
+ int i;
+
+ mod->arch.phys_plt_offset = 0;
+ mod->arch.virt_plt_offset = 0;
+ mod->arch.phys_plt_tbl = NULL;
+ mod->arch.virt_plt_tbl = NULL;
+
+ if (IS_ENABLED(CONFIG_64BIT))
+ return 0;
+
+ for (i = 1; i < hdr->e_shnum; i++)
+ if (sechdrs[i].sh_type == SHT_SYMTAB)
+ symindex = i;
+
+ core_size = get_plt_size(hdr, sechdrs, secstrings, symindex, false);
+ init_size = get_plt_size(hdr, sechdrs, secstrings, symindex, true);
+
+ if ((core_size + init_size) == 0)
+ return 0;
+
+ mod->arch.phys_plt_tbl = __module_alloc(core_size + init_size, 1);
+ if (!mod->arch.phys_plt_tbl)
+ return -ENOMEM;
+
+ mod->arch.virt_plt_tbl = __module_alloc(core_size + init_size, 0);
+ if (!mod->arch.virt_plt_tbl) {
+ __module_free(mod->arch.phys_plt_tbl);
+ mod->arch.phys_plt_tbl = NULL;
+ return -ENOMEM;
+ }
+
+ return 0;
+}
int apply_r_mips_none(struct module *me, u32 *location, Elf_Addr v)
{
@@ -64,8 +271,39 @@ static int apply_r_mips_32_rel(struct mo
return 0;
}
+static Elf_Addr add_plt_entry_to(unsigned *plt_offset,
+ void *start, Elf_Addr v)
+{
+ unsigned *tramp = start + *plt_offset;
+ *plt_offset += 4 * sizeof(int);
+
+ /* adjust carry for addiu */
+ if (v & 0x00008000)
+ v += 0x10000;
+
+ tramp[0] = 0x3c190000 | (v >> 16); /* lui t9, hi16 */
+ tramp[1] = 0x27390000 | (v & 0xffff); /* addiu t9, t9, lo16 */
+ tramp[2] = 0x03200008; /* jr t9 */
+ tramp[3] = 0x00000000; /* nop */
+
+ return (Elf_Addr) tramp;
+}
+
+static Elf_Addr add_plt_entry(struct module *me, void *location, Elf_Addr v)
+{
+ if (is_phys_addr(location))
+ return add_plt_entry_to(&me->arch.phys_plt_offset,
+ me->arch.phys_plt_tbl, v);
+ else
+ return add_plt_entry_to(&me->arch.virt_plt_offset,
+ me->arch.virt_plt_tbl, v);
+
+}
+
static int apply_r_mips_26_rel(struct module *me, u32 *location, Elf_Addr v)
{
+ u32 ofs = *location & 0x03ffffff;
+
if (v % 4) {
pr_err("module %s: dangerous R_MIPS_26 REL relocation\n",
me->name);
@@ -73,14 +311,17 @@ static int apply_r_mips_26_rel(struct mo
}
if ((v & 0xf0000000) != (((unsigned long)location + 4) & 0xf0000000)) {
- printk(KERN_ERR
- "module %s: relocation overflow\n",
- me->name);
- return -ENOEXEC;
+ v = add_plt_entry(me, location, v + (ofs << 2));
+ if (!v) {
+ printk(KERN_ERR
+ "module %s: relocation overflow\n", me->name);
+ return -ENOEXEC;
+ }
+ ofs = 0;
}
*location = (*location & ~0x03ffffff) |
- ((*location + (v >> 2)) & 0x03ffffff);
+ ((ofs + (v >> 2)) & 0x03ffffff);
return 0;
}
@@ -287,9 +528,33 @@ int module_finalize(const Elf_Ehdr *hdr,
list_add(&me->arch.dbe_list, &dbe_list);
spin_unlock_irq(&dbe_lock);
}
+
+ /* Get rid of the fixup trampoline if we're running the module
+ * from physically mapped address space */
+ if (me->arch.phys_plt_offset == 0) {
+ __module_free(me->arch.phys_plt_tbl);
+ me->arch.phys_plt_tbl = NULL;
+ }
+ if (me->arch.virt_plt_offset == 0) {
+ __module_free(me->arch.virt_plt_tbl);
+ me->arch.virt_plt_tbl = NULL;
+ }
+
return 0;
}
+void module_arch_freeing_init(struct module *mod)
+{
+ if (mod->arch.phys_plt_tbl) {
+ __module_free(mod->arch.phys_plt_tbl);
+ mod->arch.phys_plt_tbl = NULL;
+ }
+ if (mod->arch.virt_plt_tbl) {
+ __module_free(mod->arch.virt_plt_tbl);
+ mod->arch.virt_plt_tbl = NULL;
+ }
+}
+
void module_arch_cleanup(struct module *mod)
{
spin_lock_irq(&dbe_lock);

@ -1,83 +0,0 @@
--- a/arch/mips/include/asm/string.h
+++ b/arch/mips/include/asm/string.h
@@ -133,11 +133,44 @@ strncmp(__const__ char *__cs, __const__
#define __HAVE_ARCH_MEMSET
extern void *memset(void *__s, int __c, size_t __count);
+#define memset(__s, __c, len) \
+({ \
+ size_t __len = (len); \
+ void *__ret; \
+ if (__builtin_constant_p(len) && __len >= 64) \
+ __ret = memset((__s), (__c), __len); \
+ else \
+ __ret = __builtin_memset((__s), (__c), __len); \
+ __ret; \
+})
#define __HAVE_ARCH_MEMCPY
extern void *memcpy(void *__to, __const__ void *__from, size_t __n);
+#define memcpy(dst, src, len) \
+({ \
+ size_t __len = (len); \
+ void *__ret; \
+ if (__builtin_constant_p(len) && __len >= 64) \
+ __ret = memcpy((dst), (src), __len); \
+ else \
+ __ret = __builtin_memcpy((dst), (src), __len); \
+ __ret; \
+})
#define __HAVE_ARCH_MEMMOVE
extern void *memmove(void *__dest, __const__ void *__src, size_t __n);
+#define memmove(dst, src, len) \
+({ \
+ size_t __len = (len); \
+ void *__ret; \
+ if (__builtin_constant_p(len) && __len >= 64) \
+ __ret = memmove((dst), (src), __len); \
+ else \
+ __ret = __builtin_memmove((dst), (src), __len); \
+ __ret; \
+})
+
+#define __HAVE_ARCH_MEMCMP
+#define memcmp(src1, src2, len) __builtin_memcmp((src1), (src2), (len))
#endif /* _ASM_STRING_H */
--- a/arch/mips/lib/Makefile
+++ b/arch/mips/lib/Makefile
@@ -4,7 +4,7 @@
lib-y += bitops.o csum_partial.o delay.o memcpy.o memset.o \
mips-atomic.o strlen_user.o strncpy_user.o \
- strnlen_user.o uncached.o
+ strnlen_user.o uncached.o memcmp.o
obj-y += iomap.o
obj-$(CONFIG_PCI) += iomap-pci.o
--- /dev/null
+++ b/arch/mips/lib/memcmp.c
@@ -0,0 +1,22 @@
+/*
+ * copied from linux/lib/string.c
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ */
+
+#include <linux/module.h>
+#include <linux/string.h>
+
+#undef memcmp
+int memcmp(const void *cs, const void *ct, size_t count)
+{
+ const unsigned char *su1, *su2;
+ int res = 0;
+
+ for (su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--)
+ if ((res = *su1 - *su2) != 0)
+ break;
+ return res;
+}
+EXPORT_SYMBOL(memcmp);
+

@ -1,17 +0,0 @@
Adjust highmem offset to 0x10000000 to ensure that all kmalloc allocations
stay within the same 256M boundary. This ensures that -mlong-calls is not
needed on systems with more than 256M RAM.
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
---
--- a/arch/mips/include/asm/mach-generic/spaces.h
+++ b/arch/mips/include/asm/mach-generic/spaces.h
@@ -44,7 +44,7 @@
* Memory above this physical address will be considered highmem.
*/
#ifndef HIGHMEM_START
-#define HIGHMEM_START _AC(0x20000000, UL)
+#define HIGHMEM_START _AC(0x10000000, UL)
#endif
#endif /* CONFIG_32BIT */

@ -1,32 +0,0 @@
--- a/arch/mips/mm/cache.c
+++ b/arch/mips/mm/cache.c
@@ -39,6 +39,7 @@ void (*__flush_cache_vunmap)(void);
void (*__flush_kernel_vmap_range)(unsigned long vaddr, int size);
EXPORT_SYMBOL_GPL(__flush_kernel_vmap_range);
+EXPORT_SYMBOL(__flush_cache_all);
void (*__invalidate_kernel_vmap_range)(unsigned long vaddr, int size);
/* MIPS specific cache operations */
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -19,6 +19,9 @@
#include <linux/pipe_fs_i.h>
#include <linux/swap.h>
#include <linux/splice.h>
+#ifdef CONFIG_MIPS
+#include <asm/cacheflush.h>
+#endif
MODULE_ALIAS_MISCDEV(FUSE_MINOR);
MODULE_ALIAS("devname:fuse");
@@ -802,6 +805,9 @@ static int fuse_copy_fill(struct fuse_co
static int fuse_copy_do(struct fuse_copy_state *cs, void **val, unsigned *size)
{
unsigned ncpy = min(*size, cs->len);
+#ifdef CONFIG_MIPS
+ __flush_cache_all();
+#endif
if (val) {
void *pgaddr = kmap_atomic(cs->pg);
void *buf = pgaddr + cs->offset;

@ -1,13 +0,0 @@
--- a/arch/arm/kernel/module.c
+++ b/arch/arm/kernel/module.c
@@ -88,6 +88,10 @@ apply_relocate(Elf32_Shdr *sechdrs, cons
return -ENOEXEC;
}
+ if ((IS_ERR_VALUE(sym->st_value) || !sym->st_value) &&
+ ELF_ST_BIND(sym->st_info) == STB_WEAK)
+ continue;
+
loc = dstsec->sh_addr + rel->r_offset;
switch (ELF32_R_TYPE(rel->r_info)) {

@ -1,31 +0,0 @@
Upstream doesn't optimize the kernel and bootwrappers for ppc44x because
they still want to support gcc 3.3 -- well, we don't.
--- a/arch/powerpc/Makefile
+++ b/arch/powerpc/Makefile
@@ -207,7 +207,8 @@ ifeq ($(CONFIG_FUNCTION_TRACER),y)
KBUILD_CFLAGS += -mno-sched-epilog
endif
-cpu-as-$(CONFIG_4xx) += -Wa,-m405
+cpu-as-$(CONFIG_40x) += -Wa,-m405
+cpu-as-$(CONFIG_44x) += -Wa,-m440
cpu-as-$(CONFIG_ALTIVEC) += -Wa,-maltivec
cpu-as-$(CONFIG_E200) += -Wa,-me200
--- a/arch/powerpc/boot/Makefile
+++ b/arch/powerpc/boot/Makefile
@@ -48,10 +48,10 @@ BOOTCFLAGS += -I$(obj) -I$(srctree)/$(ob
DTC_FLAGS ?= -p 1024
$(obj)/4xx.o: BOOTCFLAGS += -mcpu=405
-$(obj)/ebony.o: BOOTCFLAGS += -mcpu=405
+$(obj)/ebony.o: BOOTCFLAGS += -mcpu=440
$(obj)/cuboot-hotfoot.o: BOOTCFLAGS += -mcpu=405
-$(obj)/cuboot-taishan.o: BOOTCFLAGS += -mcpu=405
-$(obj)/cuboot-katmai.o: BOOTCFLAGS += -mcpu=405
+$(obj)/cuboot-taishan.o: BOOTCFLAGS += -mcpu=440
+$(obj)/cuboot-katmai.o: BOOTCFLAGS += -mcpu=440
$(obj)/cuboot-acadia.o: BOOTCFLAGS += -mcpu=405
$(obj)/treeboot-walnut.o: BOOTCFLAGS += -mcpu=405
$(obj)/treeboot-iss4xx.o: BOOTCFLAGS += -mcpu=405

@ -1,10 +0,0 @@
--- a/arch/powerpc/Makefile
+++ b/arch/powerpc/Makefile
@@ -169,7 +169,6 @@ CPP = $(CC) -E $(KBUILD_CFLAGS)
CHECKFLAGS += -m$(CONFIG_WORD_SIZE) -D__powerpc__ -D__powerpc$(CONFIG_WORD_SIZE)__
-KBUILD_LDFLAGS_MODULE += arch/powerpc/lib/crtsavres.o
ifeq ($(CONFIG_476FPE_ERR46),y)
KBUILD_LDFLAGS_MODULE += --ppc476-workaround \

@ -1,298 +0,0 @@
From d8582dcf1ed66eee88a11e4760f42c0d6c8822be Mon Sep 17 00:00:00 2001
From: Yousong Zhou <yszhou4tech@gmail.com>
Date: Sat, 31 Jan 2015 22:26:03 +0800
Subject: [PATCH 331/331] MIPS: kexec: Accept command line parameters from
userspace.
Signed-off-by: Yousong Zhou <yszhou4tech@gmail.com>
---
arch/mips/kernel/machine_kexec.c | 153 +++++++++++++++++++++++++++++++-----
arch/mips/kernel/machine_kexec.h | 20 +++++
arch/mips/kernel/relocate_kernel.S | 21 +++--
3 files changed, 167 insertions(+), 27 deletions(-)
create mode 100644 arch/mips/kernel/machine_kexec.h
--- a/arch/mips/kernel/machine_kexec.c
+++ b/arch/mips/kernel/machine_kexec.c
@@ -10,45 +10,145 @@
#include <linux/mm.h>
#include <linux/delay.h>
+#include <asm/bootinfo.h>
#include <asm/cacheflush.h>
#include <asm/page.h>
-
-extern const unsigned char relocate_new_kernel[];
-extern const size_t relocate_new_kernel_size;
-
-extern unsigned long kexec_start_address;
-extern unsigned long kexec_indirection_page;
+#include <asm/uaccess.h>
+#include "machine_kexec.h"
int (*_machine_kexec_prepare)(struct kimage *) = NULL;
void (*_machine_kexec_shutdown)(void) = NULL;
void (*_machine_crash_shutdown)(struct pt_regs *regs) = NULL;
+
#ifdef CONFIG_SMP
void (*relocated_kexec_smp_wait) (void *);
atomic_t kexec_ready_to_reboot = ATOMIC_INIT(0);
#endif
-int
-machine_kexec_prepare(struct kimage *kimage)
+static void machine_kexec_print_args(void)
{
+ unsigned long argc = (int)kexec_args[0];
+ int i;
+
+ pr_info("kexec_args[0] (argc): %lu\n", argc);
+ pr_info("kexec_args[1] (argv): %p\n", (void *)kexec_args[1]);
+ pr_info("kexec_args[2] (env ): %p\n", (void *)kexec_args[2]);
+ pr_info("kexec_args[3] (desc): %p\n", (void *)kexec_args[3]);
+
+ for (i = 0; i < argc; i++) {
+ pr_info("kexec_argv[%d] = %p, %s\n",
+ i, kexec_argv[i], kexec_argv[i]);
+ }
+}
+
+static void machine_kexec_init_argv(struct kimage *image)
+{
+ void __user *buf = NULL;
+ size_t bufsz;
+ size_t size;
+ int i;
+
+ bufsz = 0;
+ for (i = 0; i < image->nr_segments; i++) {
+ struct kexec_segment *seg;
+
+ seg = &image->segment[i];
+ if (seg->bufsz < 6)
+ continue;
+
+ if (strncmp((char *) seg->buf, "kexec ", 6))
+ continue;
+
+ buf = seg->buf;
+ bufsz = seg->bufsz;
+ break;
+ }
+
+ if (!buf)
+ return;
+
+ size = KEXEC_COMMAND_LINE_SIZE;
+ size = min(size, bufsz);
+ if (size < bufsz)
+ pr_warn("kexec command line truncated to %zd bytes\n", size);
+
+ /* Copy to kernel space */
+ copy_from_user(kexec_argv_buf, buf, size);
+ kexec_argv_buf[size - 1] = 0;
+}
+
+static void machine_kexec_parse_argv(struct kimage *image)
+{
+ char *reboot_code_buffer;
+ int reloc_delta;
+ char *ptr;
+ int argc;
+ int i;
+
+ ptr = kexec_argv_buf;
+ argc = 0;
+
+ /*
+ * convert command line string to array of parameters
+ * (as bootloader does).
+ */
+ while (ptr && *ptr && (KEXEC_MAX_ARGC > argc)) {
+ if (*ptr == ' ') {
+ *ptr++ = '\0';
+ continue;
+ }
+
+ kexec_argv[argc++] = ptr;
+ ptr = strchr(ptr, ' ');
+ }
+
+ if (!argc)
+ return;
+
+ kexec_args[0] = argc;
+ kexec_args[1] = (unsigned long)kexec_argv;
+ kexec_args[2] = 0;
+ kexec_args[3] = 0;
+
+ reboot_code_buffer = page_address(image->control_code_page);
+ reloc_delta = reboot_code_buffer - (char *)kexec_relocate_new_kernel;
+
+ kexec_args[1] += reloc_delta;
+ for (i = 0; i < argc; i++)
+ kexec_argv[i] += reloc_delta;
+}
+
+int machine_kexec_prepare(struct kimage *kimage)
+{
+ /*
+ * Whenever arguments passed from kexec-tools, Init the arguments as
+ * the original ones to try avoiding booting failure.
+ */
+
+ kexec_args[0] = fw_arg0;
+ kexec_args[1] = fw_arg1;
+ kexec_args[2] = fw_arg2;
+ kexec_args[3] = fw_arg3;
+
+ machine_kexec_init_argv(kimage);
+ machine_kexec_parse_argv(kimage);
+
if (_machine_kexec_prepare)
return _machine_kexec_prepare(kimage);
return 0;
}
-void
-machine_kexec_cleanup(struct kimage *kimage)
+void machine_kexec_cleanup(struct kimage *kimage)
{
}
-void
-machine_shutdown(void)
+void machine_shutdown(void)
{
if (_machine_kexec_shutdown)
_machine_kexec_shutdown();
}
-void
-machine_crash_shutdown(struct pt_regs *regs)
+void machine_crash_shutdown(struct pt_regs *regs)
{
if (_machine_crash_shutdown)
_machine_crash_shutdown(regs);
@@ -66,10 +166,12 @@ machine_kexec(struct kimage *image)
unsigned long *ptr;
reboot_code_buffer =
- (unsigned long)page_address(image->control_code_page);
+ (unsigned long)page_address(image->control_code_page);
+ pr_info("reboot_code_buffer = %p\n", (void *)reboot_code_buffer);
kexec_start_address =
(unsigned long) phys_to_virt(image->start);
+ pr_info("kexec_start_address = %p\n", (void *)kexec_start_address);
if (image->type == KEXEC_TYPE_DEFAULT) {
kexec_indirection_page =
@@ -77,9 +179,19 @@ machine_kexec(struct kimage *image)
} else {
kexec_indirection_page = (unsigned long)&image->head;
}
+ pr_info("kexec_indirection_page = %p\n", (void *)kexec_indirection_page);
- memcpy((void*)reboot_code_buffer, relocate_new_kernel,
- relocate_new_kernel_size);
+ pr_info("Where is memcpy: %p\n", memcpy);
+ pr_info("kexec_relocate_new_kernel = %p, kexec_relocate_new_kernel_end = %p\n",
+ (void *)kexec_relocate_new_kernel, &kexec_relocate_new_kernel_end);
+ pr_info("Copy %lu bytes from %p to %p\n", KEXEC_RELOCATE_NEW_KERNEL_SIZE,
+ (void *)kexec_relocate_new_kernel, (void *)reboot_code_buffer);
+ memcpy((void*)reboot_code_buffer, kexec_relocate_new_kernel,
+ KEXEC_RELOCATE_NEW_KERNEL_SIZE);
+
+ pr_info("Before _print_args().\n");
+ machine_kexec_print_args();
+ pr_info("Before eval loop.\n");
/*
* The generic kexec code builds a page list with physical
@@ -98,15 +210,16 @@ machine_kexec(struct kimage *image)
/*
* we do not want to be bothered.
*/
+ pr_info("Before irq_disable.\n");
local_irq_disable();
- printk("Will call new kernel at %08lx\n", image->start);
- printk("Bye ...\n");
+ pr_info("Will call new kernel at %08lx\n", image->start);
+ pr_info("Bye ...\n");
__flush_cache_all();
#ifdef CONFIG_SMP
/* All secondary cpus now may jump to kexec_wait cycle */
relocated_kexec_smp_wait = reboot_code_buffer +
- (void *)(kexec_smp_wait - relocate_new_kernel);
+ (void *)(kexec_smp_wait - kexec_relocate_new_kernel);
smp_wmb();
atomic_set(&kexec_ready_to_reboot, 1);
#endif
--- /dev/null
+++ b/arch/mips/kernel/machine_kexec.h
@@ -0,0 +1,20 @@
+#ifndef _MACHINE_KEXEC_H
+#define _MACHINE_KEXEC_H
+
+#ifndef __ASSEMBLY__
+extern const unsigned char kexec_relocate_new_kernel[];
+extern unsigned long kexec_relocate_new_kernel_end;
+extern unsigned long kexec_start_address;
+extern unsigned long kexec_indirection_page;
+
+extern char kexec_argv_buf[];
+extern char *kexec_argv[];
+
+#define KEXEC_RELOCATE_NEW_KERNEL_SIZE ((unsigned long)&kexec_relocate_new_kernel_end - (unsigned long)kexec_relocate_new_kernel)
+#endif /* !__ASSEMBLY__ */
+
+#define KEXEC_COMMAND_LINE_SIZE 256
+#define KEXEC_ARGV_SIZE (KEXEC_COMMAND_LINE_SIZE / 16)
+#define KEXEC_MAX_ARGC (KEXEC_ARGV_SIZE / sizeof(long))
+
+#endif
--- a/arch/mips/kernel/relocate_kernel.S
+++ b/arch/mips/kernel/relocate_kernel.S
@@ -12,8 +12,9 @@
#include <asm/mipsregs.h>
#include <asm/stackframe.h>
#include <asm/addrspace.h>
+#include "machine_kexec.h"
-LEAF(relocate_new_kernel)
+LEAF(kexec_relocate_new_kernel)
PTR_L a0, arg0
PTR_L a1, arg1
PTR_L a2, arg2
@@ -98,7 +99,7 @@ done:
#endif
/* jump to kexec_start_address */
j s1
- END(relocate_new_kernel)
+ END(kexec_relocate_new_kernel)
#ifdef CONFIG_SMP
/*
@@ -184,9 +185,15 @@ kexec_indirection_page:
PTR 0
.size kexec_indirection_page, PTRSIZE
-relocate_new_kernel_end:
+kexec_argv_buf:
+ EXPORT(kexec_argv_buf)
+ .skip KEXEC_COMMAND_LINE_SIZE
+ .size kexec_argv_buf, KEXEC_COMMAND_LINE_SIZE
+
+kexec_argv:
+ EXPORT(kexec_argv)
+ .skip KEXEC_ARGV_SIZE
+ .size kexec_argv, KEXEC_ARGV_SIZE
-relocate_new_kernel_size:
- EXPORT(relocate_new_kernel_size)
- PTR relocate_new_kernel_end - relocate_new_kernel
- .size relocate_new_kernel_size, PTRSIZE
+kexec_relocate_new_kernel_end:
+ EXPORT(kexec_relocate_new_kernel_end)

@ -1,146 +0,0 @@
--- a/drivers/mtd/Kconfig
+++ b/drivers/mtd/Kconfig
@@ -12,6 +12,23 @@ menuconfig MTD
if MTD
+menu "OpenWrt specific MTD options"
+
+config MTD_ROOTFS_ROOT_DEV
+ bool "Automatically set 'rootfs' partition to be root filesystem"
+ default y
+
+config MTD_SPLIT_FIRMWARE
+ bool "Automatically split firmware partition for kernel+rootfs"
+ default y
+
+config MTD_SPLIT_FIRMWARE_NAME
+ string "Firmware partition name"
+ depends on MTD_SPLIT_FIRMWARE
+ default "firmware"
+
+endmenu
+
config MTD_TESTS
tristate "MTD tests support (DANGEROUS)"
depends on m
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -29,11 +29,13 @@
#include <linux/kmod.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
+#include <linux/magic.h>
#include <linux/of.h>
#include <linux/err.h>
#include <linux/kconfig.h>
#include "mtdcore.h"
+#include "mtdsplit/mtdsplit.h"
/* Our partition linked list */
static LIST_HEAD(mtd_partitions);
@@ -47,13 +49,14 @@ struct mtd_part {
struct list_head list;
};
+static void mtd_partition_split(struct mtd_info *master, struct mtd_part *part);
+
/*
* Given a pointer to the MTD object in the mtd_part structure, we can retrieve
* the pointer to that structure with this macro.
*/
#define PART(x) ((struct mtd_part *)(x))
-
/*
* MTD methods which simply translate the effective address and pass through
* to the _real_ device.
@@ -579,8 +582,10 @@ static int mtd_add_partition_attrs(struc
return ret;
}
-int mtd_add_partition(struct mtd_info *master, const char *name,
- long long offset, long long length)
+
+static int
+__mtd_add_partition(struct mtd_info *master, const char *name,
+ long long offset, long long length, bool dup_check)
{
struct mtd_partition part;
struct mtd_part *new;
@@ -612,6 +617,7 @@ int mtd_add_partition(struct mtd_info *m
mutex_unlock(&mtd_partitions_mutex);
add_mtd_device(&new->mtd);
+ mtd_partition_split(master, new);
mtd_add_partition_attrs(new);
@@ -619,6 +625,12 @@ int mtd_add_partition(struct mtd_info *m
}
EXPORT_SYMBOL_GPL(mtd_add_partition);
+int mtd_add_partition(struct mtd_info *master, const char *name,
+ long long offset, long long length)
+{
+ return __mtd_add_partition(master, name, offset, length, true);
+}
+
int mtd_del_partition(struct mtd_info *master, int partno)
{
struct mtd_part *slave, *next;
@@ -644,6 +656,35 @@ int mtd_del_partition(struct mtd_info *m
}
EXPORT_SYMBOL_GPL(mtd_del_partition);
+#ifdef CONFIG_MTD_SPLIT_FIRMWARE_NAME
+#define SPLIT_FIRMWARE_NAME CONFIG_MTD_SPLIT_FIRMWARE_NAME
+#else
+#define SPLIT_FIRMWARE_NAME "unused"
+#endif
+
+static void split_firmware(struct mtd_info *master, struct mtd_part *part)
+{
+}
+
+void __weak arch_split_mtd_part(struct mtd_info *master, const char *name,
+ int offset, int size)
+{
+}
+
+static void mtd_partition_split(struct mtd_info *master, struct mtd_part *part)
+{
+ static int rootfs_found = 0;
+
+ if (rootfs_found)
+ return;
+
+ if (!strcmp(part->mtd.name, SPLIT_FIRMWARE_NAME) &&
+ config_enabled(CONFIG_MTD_SPLIT_FIRMWARE))
+ split_firmware(master, part);
+
+ arch_split_mtd_part(master, part->mtd.name, part->offset,
+ part->mtd.size);
+}
/*
* This function, given a master MTD object and a partition table, creates
* and registers slave MTD objects which are bound to the master according to
@@ -673,6 +714,7 @@ int add_mtd_partitions(struct mtd_info *
mutex_unlock(&mtd_partitions_mutex);
add_mtd_device(&slave->mtd);
+ mtd_partition_split(master, slave);
mtd_add_partition_attrs(slave);
cur_offset = slave->offset + slave->mtd.size;
--- a/include/linux/mtd/partitions.h
+++ b/include/linux/mtd/partitions.h
@@ -84,5 +84,7 @@ int mtd_add_partition(struct mtd_info *m
long long offset, long long length);
int mtd_del_partition(struct mtd_info *master, int partno);
uint64_t mtd_get_device_size(const struct mtd_info *mtd);
+extern void __weak arch_split_mtd_part(struct mtd_info *master,
+ const char *name, int offset, int size);
#endif

@ -1,113 +0,0 @@
From 02cff0ccaa6d364f5c1eeea83f47ac80ccc967d4 Mon Sep 17 00:00:00 2001
From: Gabor Juhos <juhosg@openwrt.org>
Date: Tue, 3 Sep 2013 18:11:50 +0200
Subject: [PATCH] mtd: add support for different partition parser types
Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
---
drivers/mtd/mtdpart.c | 56 ++++++++++++++++++++++++++++++++++++++++
include/linux/mtd/partitions.h | 11 ++++++++
2 files changed, 67 insertions(+)
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -745,6 +745,30 @@ static struct mtd_part_parser *get_parti
#define put_partition_parser(p) do { module_put((p)->owner); } while (0)
+static struct mtd_part_parser *
+get_partition_parser_by_type(enum mtd_parser_type type,
+ struct mtd_part_parser *start)
+{
+ struct mtd_part_parser *p, *ret = NULL;
+
+ spin_lock(&part_parser_lock);
+
+ p = list_prepare_entry(start, &part_parsers, list);
+ if (start)
+ put_partition_parser(start);
+
+ list_for_each_entry_continue(p, &part_parsers, list) {
+ if (p->type == type && try_module_get(p->owner)) {
+ ret = p;
+ break;
+ }
+ }
+
+ spin_unlock(&part_parser_lock);
+
+ return ret;
+}
+
void register_mtd_parser(struct mtd_part_parser *p)
{
spin_lock(&part_parser_lock);
@@ -862,6 +886,38 @@ int parse_mtd_partitions(struct mtd_info
return ret;
}
+int parse_mtd_partitions_by_type(struct mtd_info *master,
+ enum mtd_parser_type type,
+ struct mtd_partition **pparts,
+ struct mtd_part_parser_data *data)
+{
+ struct mtd_part_parser *prev = NULL;
+ int ret = 0;
+
+ while (1) {
+ struct mtd_part_parser *parser;
+
+ parser = get_partition_parser_by_type(type, prev);
+ if (!parser)
+ break;
+
+ ret = (*parser->parse_fn)(master, pparts, data);
+
+ if (ret > 0) {
+ put_partition_parser(parser);
+ printk(KERN_NOTICE
+ "%d %s partitions found on MTD device %s\n",
+ ret, parser->name, master->name);
+ break;
+ }
+
+ prev = parser;
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(parse_mtd_partitions_by_type);
+
int mtd_is_partition(const struct mtd_info *mtd)
{
struct mtd_part *part;
--- a/include/linux/mtd/partitions.h
+++ b/include/linux/mtd/partitions.h
@@ -68,12 +68,17 @@ struct mtd_part_parser_data {
* Functions dealing with the various ways of partitioning the space
*/
+enum mtd_parser_type {
+ MTD_PARSER_TYPE_DEVICE = 0,
+};
+
struct mtd_part_parser {
struct list_head list;
struct module *owner;
const char *name;
int (*parse_fn)(struct mtd_info *, struct mtd_partition **,
struct mtd_part_parser_data *);
+ enum mtd_parser_type type;
};
extern void register_mtd_parser(struct mtd_part_parser *parser);
@@ -87,4 +92,9 @@ uint64_t mtd_get_device_size(const struc
extern void __weak arch_split_mtd_part(struct mtd_info *master,
const char *name, int offset, int size);
+int parse_mtd_partitions_by_type(struct mtd_info *master,
+ enum mtd_parser_type type,
+ struct mtd_partition **pparts,
+ struct mtd_part_parser_data *data);
+
#endif

@ -1,72 +0,0 @@
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -656,6 +656,37 @@ int mtd_del_partition(struct mtd_info *m
}
EXPORT_SYMBOL_GPL(mtd_del_partition);
+static int
+run_parsers_by_type(struct mtd_part *slave, enum mtd_parser_type type)
+{
+ struct mtd_partition *parts;
+ int nr_parts;
+ int i;
+
+ nr_parts = parse_mtd_partitions_by_type(&slave->mtd, type, &parts,
+ NULL);
+ if (nr_parts <= 0)
+ return nr_parts;
+
+ if (WARN_ON(!parts))
+ return 0;
+
+ for (i = 0; i < nr_parts; i++) {
+ /* adjust partition offsets */
+ parts[i].offset += slave->offset;
+
+ __mtd_add_partition(slave->master,
+ parts[i].name,
+ parts[i].offset,
+ parts[i].size,
+ false);
+ }
+
+ kfree(parts);
+
+ return nr_parts;
+}
+
#ifdef CONFIG_MTD_SPLIT_FIRMWARE_NAME
#define SPLIT_FIRMWARE_NAME CONFIG_MTD_SPLIT_FIRMWARE_NAME
#else
@@ -664,6 +695,7 @@ EXPORT_SYMBOL_GPL(mtd_del_partition);
static void split_firmware(struct mtd_info *master, struct mtd_part *part)
{
+ run_parsers_by_type(part, MTD_PARSER_TYPE_FIRMWARE);
}
void __weak arch_split_mtd_part(struct mtd_info *master, const char *name,
@@ -678,6 +710,12 @@ static void mtd_partition_split(struct m
if (rootfs_found)
return;
+ if (!strcmp(part->mtd.name, "rootfs")) {
+ run_parsers_by_type(part, MTD_PARSER_TYPE_ROOTFS);
+
+ rootfs_found = 1;
+ }
+
if (!strcmp(part->mtd.name, SPLIT_FIRMWARE_NAME) &&
config_enabled(CONFIG_MTD_SPLIT_FIRMWARE))
split_firmware(master, part);
--- a/include/linux/mtd/partitions.h
+++ b/include/linux/mtd/partitions.h
@@ -70,6 +70,8 @@ struct mtd_part_parser_data {
enum mtd_parser_type {
MTD_PARSER_TYPE_DEVICE = 0,
+ MTD_PARSER_TYPE_ROOTFS,
+ MTD_PARSER_TYPE_FIRMWARE,
};
struct mtd_part_parser {

@ -1,22 +0,0 @@
--- a/drivers/mtd/Kconfig
+++ b/drivers/mtd/Kconfig
@@ -27,6 +27,8 @@ config MTD_SPLIT_FIRMWARE_NAME
depends on MTD_SPLIT_FIRMWARE
default "firmware"
+source "drivers/mtd/mtdsplit/Kconfig"
+
endmenu
config MTD_TESTS
--- a/drivers/mtd/Makefile
+++ b/drivers/mtd/Makefile
@@ -6,6 +6,8 @@
obj-$(CONFIG_MTD) += mtd.o
mtd-y := mtdcore.o mtdsuper.o mtdconcat.o mtdpart.o mtdchar.o
+obj-$(CONFIG_MTD_SPLIT) += mtdsplit/
+
obj-$(CONFIG_MTD_OF_PARTS) += ofpart.o
obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o
obj-$(CONFIG_MTD_CMDLINE_PARTS) += cmdlinepart.o

@ -1,101 +0,0 @@
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -453,14 +453,12 @@ static struct mtd_part *allocate_partiti
if (slave->offset == MTDPART_OFS_APPEND)
slave->offset = cur_offset;
if (slave->offset == MTDPART_OFS_NXTBLK) {
- slave->offset = cur_offset;
- if (mtd_mod_by_eb(cur_offset, master) != 0) {
- /* Round up to next erasesize */
- slave->offset = (mtd_div_by_eb(cur_offset, master) + 1) * master->erasesize;
+ /* Round up to next erasesize */
+ slave->offset = mtd_roundup_to_eb(cur_offset, master);
+ if (slave->offset != cur_offset)
printk(KERN_NOTICE "Moving partition %d: "
"0x%012llx -> 0x%012llx\n", partno,
(unsigned long long)cur_offset, (unsigned long long)slave->offset);
- }
}
if (slave->offset == MTDPART_OFS_RETAIN) {
slave->offset = cur_offset;
@@ -687,6 +685,17 @@ run_parsers_by_type(struct mtd_part *sla
return nr_parts;
}
+static inline unsigned long
+mtd_pad_erasesize(struct mtd_info *mtd, int offset, int len)
+{
+ unsigned long mask = mtd->erasesize - 1;
+
+ len += offset & mask;
+ len = (len + mask) & ~mask;
+ len -= offset & mask;
+ return len;
+}
+
#ifdef CONFIG_MTD_SPLIT_FIRMWARE_NAME
#define SPLIT_FIRMWARE_NAME CONFIG_MTD_SPLIT_FIRMWARE_NAME
#else
@@ -973,6 +982,24 @@ int mtd_is_partition(const struct mtd_in
}
EXPORT_SYMBOL_GPL(mtd_is_partition);
+struct mtd_info *mtdpart_get_master(const struct mtd_info *mtd)
+{
+ if (!mtd_is_partition(mtd))
+ return (struct mtd_info *)mtd;
+
+ return PART(mtd)->master;
+}
+EXPORT_SYMBOL_GPL(mtdpart_get_master);
+
+uint64_t mtdpart_get_offset(const struct mtd_info *mtd)
+{
+ if (!mtd_is_partition(mtd))
+ return 0;
+
+ return PART(mtd)->offset;
+}
+EXPORT_SYMBOL_GPL(mtdpart_get_offset);
+
/* Returns the size of the entire flash chip */
uint64_t mtd_get_device_size(const struct mtd_info *mtd)
{
--- a/include/linux/mtd/partitions.h
+++ b/include/linux/mtd/partitions.h
@@ -90,6 +90,8 @@ int mtd_is_partition(const struct mtd_in
int mtd_add_partition(struct mtd_info *master, const char *name,
long long offset, long long length);
int mtd_del_partition(struct mtd_info *master, int partno);
+struct mtd_info *mtdpart_get_master(const struct mtd_info *mtd);
+uint64_t mtdpart_get_offset(const struct mtd_info *mtd);
uint64_t mtd_get_device_size(const struct mtd_info *mtd);
extern void __weak arch_split_mtd_part(struct mtd_info *master,
const char *name, int offset, int size);
--- a/include/linux/mtd/mtd.h
+++ b/include/linux/mtd/mtd.h
@@ -334,6 +334,24 @@ static inline uint32_t mtd_mod_by_eb(uin
return do_div(sz, mtd->erasesize);
}
+static inline uint64_t mtd_roundup_to_eb(uint64_t sz, struct mtd_info *mtd)
+{
+ if (mtd_mod_by_eb(sz, mtd) == 0)
+ return sz;
+
+ /* Round up to next erase block */
+ return (mtd_div_by_eb(sz, mtd) + 1) * mtd->erasesize;
+}
+
+static inline uint64_t mtd_rounddown_to_eb(uint64_t sz, struct mtd_info *mtd)
+{
+ if (mtd_mod_by_eb(sz, mtd) == 0)
+ return sz;
+
+ /* Round down to the start of the current erase block */
+ return (mtd_div_by_eb(sz, mtd)) * mtd->erasesize;
+}
+
static inline uint32_t mtd_div_by_ws(uint64_t sz, struct mtd_info *mtd)
{
if (mtd->writesize_shift)

@ -1,70 +0,0 @@
--- a/drivers/mtd/Kconfig
+++ b/drivers/mtd/Kconfig
@@ -27,6 +27,11 @@ config MTD_SPLIT_FIRMWARE_NAME
depends on MTD_SPLIT_FIRMWARE
default "firmware"
+config MTD_UIMAGE_SPLIT
+ bool "Enable split support for firmware partitions containing a uImage"
+ depends on MTD_SPLIT_FIRMWARE
+ default y
+
source "drivers/mtd/mtdsplit/Kconfig"
endmenu
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -696,6 +696,37 @@ mtd_pad_erasesize(struct mtd_info *mtd,
return len;
}
+#define UBOOT_MAGIC 0x27051956
+
+static void split_uimage(struct mtd_info *master, struct mtd_part *part)
+{
+ struct {
+ __be32 magic;
+ __be32 pad[2];
+ __be32 size;
+ } hdr;
+ size_t len;
+
+ if (mtd_read(master, part->offset, sizeof(hdr), &len, (void *) &hdr))
+ return;
+
+ if (len != sizeof(hdr) || hdr.magic != cpu_to_be32(UBOOT_MAGIC))
+ return;
+
+ len = be32_to_cpu(hdr.size) + 0x40;
+ len = mtd_pad_erasesize(master, part->offset, len);
+ if (len + master->erasesize > part->mtd.size)
+ return;
+
+ if (config_enabled(CONFIG_MTD_SPLIT_UIMAGE_FW))
+ pr_err("Dedicated partitioner didn't split firmware partition, please fill a bug report!\n");
+ else
+ pr_warn("Support for built-in firmware splitter will be removed, please use CONFIG_MTD_SPLIT_UIMAGE_FW\n");
+
+ __mtd_add_partition(master, "rootfs", part->offset + len,
+ part->mtd.size - len, false);
+}
+
#ifdef CONFIG_MTD_SPLIT_FIRMWARE_NAME
#define SPLIT_FIRMWARE_NAME CONFIG_MTD_SPLIT_FIRMWARE_NAME
#else
@@ -704,7 +735,14 @@ mtd_pad_erasesize(struct mtd_info *mtd,
static void split_firmware(struct mtd_info *master, struct mtd_part *part)
{
- run_parsers_by_type(part, MTD_PARSER_TYPE_FIRMWARE);
+ int ret;
+
+ ret = run_parsers_by_type(part, MTD_PARSER_TYPE_FIRMWARE);
+ if (ret > 0)
+ return;
+
+ if (config_enabled(CONFIG_MTD_UIMAGE_SPLIT))
+ split_uimage(master, part);
}
void __weak arch_split_mtd_part(struct mtd_info *master, const char *name,

@ -1,18 +0,0 @@
--- a/include/linux/mtd/partitions.h
+++ b/include/linux/mtd/partitions.h
@@ -35,6 +35,7 @@
* Note: writeable partitions require their size and offset be
* erasesize aligned (e.g. use MTDPART_OFS_NEXTBLK).
*/
+struct mtd_info;
struct mtd_partition {
const char *name; /* identifier string */
@@ -50,7 +51,6 @@ struct mtd_partition {
#define MTDPART_SIZ_FULL (0)
-struct mtd_info;
struct device_node;
/**

@ -1,142 +0,0 @@
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -37,6 +37,8 @@
#include "mtdcore.h"
#include "mtdsplit/mtdsplit.h"
+#define MTD_ERASE_PARTIAL 0x8000 /* partition only covers parts of an erase block */
+
/* Our partition linked list */
static LIST_HEAD(mtd_partitions);
static DEFINE_MUTEX(mtd_partitions_mutex);
@@ -235,13 +237,61 @@ static int part_erase(struct mtd_info *m
struct mtd_part *part = PART(mtd);
int ret;
+
+ instr->partial_start = false;
+ if (mtd->flags & MTD_ERASE_PARTIAL) {
+ size_t readlen = 0;
+ u64 mtd_ofs;
+
+ instr->erase_buf = kmalloc(part->master->erasesize, GFP_ATOMIC);
+ if (!instr->erase_buf)
+ return -ENOMEM;
+
+ mtd_ofs = part->offset + instr->addr;
+ instr->erase_buf_ofs = do_div(mtd_ofs, part->master->erasesize);
+
+ if (instr->erase_buf_ofs > 0) {
+ instr->addr -= instr->erase_buf_ofs;
+ ret = mtd_read(part->master,
+ instr->addr + part->offset,
+ part->master->erasesize,
+ &readlen, instr->erase_buf);
+
+ instr->len += instr->erase_buf_ofs;
+ instr->partial_start = true;
+ } else {
+ mtd_ofs = part->offset + part->mtd.size;
+ instr->erase_buf_ofs = part->master->erasesize -
+ do_div(mtd_ofs, part->master->erasesize);
+
+ if (instr->erase_buf_ofs > 0) {
+ instr->len += instr->erase_buf_ofs;
+ ret = mtd_read(part->master,
+ part->offset + instr->addr +
+ instr->len - part->master->erasesize,
+ part->master->erasesize, &readlen,
+ instr->erase_buf);
+ } else {
+ ret = 0;
+ }
+ }
+ if (ret < 0) {
+ kfree(instr->erase_buf);
+ return ret;
+ }
+
+ }
+
instr->addr += part->offset;
ret = part->master->_erase(part->master, instr);
if (ret) {
if (instr->fail_addr != MTD_FAIL_ADDR_UNKNOWN)
instr->fail_addr -= part->offset;
instr->addr -= part->offset;
+ if (mtd->flags & MTD_ERASE_PARTIAL)
+ kfree(instr->erase_buf);
}
+
return ret;
}
@@ -249,7 +299,25 @@ void mtd_erase_callback(struct erase_inf
{
if (instr->mtd->_erase == part_erase) {
struct mtd_part *part = PART(instr->mtd);
+ size_t wrlen = 0;
+ if (instr->mtd->flags & MTD_ERASE_PARTIAL) {
+ if (instr->partial_start) {
+ part->master->_write(part->master,
+ instr->addr, instr->erase_buf_ofs,
+ &wrlen, instr->erase_buf);
+ instr->addr += instr->erase_buf_ofs;
+ } else {
+ instr->len -= instr->erase_buf_ofs;
+ part->master->_write(part->master,
+ instr->addr + instr->len,
+ instr->erase_buf_ofs, &wrlen,
+ instr->erase_buf +
+ part->master->erasesize -
+ instr->erase_buf_ofs);
+ }
+ kfree(instr->erase_buf);
+ }
if (instr->fail_addr != MTD_FAIL_ADDR_UNKNOWN)
instr->fail_addr -= part->offset;
instr->addr -= part->offset;
@@ -522,17 +590,20 @@ static struct mtd_part *allocate_partiti
if ((slave->mtd.flags & MTD_WRITEABLE) &&
mtd_mod_by_eb(slave->offset, &slave->mtd)) {
/* Doesn't start on a boundary of major erase size */
- /* FIXME: Let it be writable if it is on a boundary of
- * _minor_ erase size though */
- slave->mtd.flags &= ~MTD_WRITEABLE;
- printk(KERN_WARNING"mtd: partition \"%s\" doesn't start on an erase block boundary -- force read-only\n",
- part->name);
+ slave->mtd.flags |= MTD_ERASE_PARTIAL;
+ if (((u32) slave->mtd.size) > master->erasesize)
+ slave->mtd.flags &= ~MTD_WRITEABLE;
+ else
+ slave->mtd.erasesize = slave->mtd.size;
}
if ((slave->mtd.flags & MTD_WRITEABLE) &&
- mtd_mod_by_eb(slave->mtd.size, &slave->mtd)) {
- slave->mtd.flags &= ~MTD_WRITEABLE;
- printk(KERN_WARNING"mtd: partition \"%s\" doesn't end on an erase block -- force read-only\n",
- part->name);
+ mtd_mod_by_eb(slave->offset + slave->mtd.size, &slave->mtd)) {
+ slave->mtd.flags |= MTD_ERASE_PARTIAL;
+
+ if ((u32) slave->mtd.size > master->erasesize)
+ slave->mtd.flags &= ~MTD_WRITEABLE;
+ else
+ slave->mtd.erasesize = slave->mtd.size;
}
slave->mtd.ecclayout = master->ecclayout;
--- a/include/linux/mtd/mtd.h
+++ b/include/linux/mtd/mtd.h
@@ -55,6 +55,10 @@ struct erase_info {
u_long priv;
u_char state;
struct erase_info *next;
+
+ u8 *erase_buf;
+ u32 erase_buf_ofs;
+ bool partial_start;
};
struct mtd_erase_region_info {

@ -1,18 +0,0 @@
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -336,7 +336,14 @@ static int part_lock(struct mtd_info *mt
static int part_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
{
struct mtd_part *part = PART(mtd);
- return part->master->_unlock(part->master, ofs + part->offset, len);
+
+ ofs += part->offset;
+ if (mtd->flags & MTD_ERASE_PARTIAL) {
+ /* round up len to next erasesize and round down offset to prev block */
+ len = (mtd_div_by_eb(len, part->master) + 1) * part->master->erasesize;
+ ofs &= ~(part->master->erasesize - 1);
+ }
+ return part->master->_unlock(part->master, ofs, len);
}
static int part_is_locked(struct mtd_info *mtd, loff_t ofs, uint64_t len)

@ -1,30 +0,0 @@
--- a/drivers/mtd/redboot.c
+++ b/drivers/mtd/redboot.c
@@ -265,14 +265,21 @@ static int parse_redboot_partitions(stru
#endif
names += strlen(names)+1;
-#ifdef CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED
if(fl->next && fl->img->flash_base + fl->img->size + master->erasesize <= fl->next->img->flash_base) {
- i++;
- parts[i].offset = parts[i-1].size + parts[i-1].offset;
- parts[i].size = fl->next->img->flash_base - parts[i].offset;
- parts[i].name = nullname;
- }
+ if (!strcmp(parts[i].name, "rootfs")) {
+ parts[i].size = fl->next->img->flash_base;
+ parts[i].size &= ~(master->erasesize - 1);
+ parts[i].size -= parts[i].offset;
+#ifdef CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED
+ nrparts--;
+ } else {
+ i++;
+ parts[i].offset = parts[i-1].size + parts[i-1].offset;
+ parts[i].size = fl->next->img->flash_base - parts[i].offset;
+ parts[i].name = nullname;
#endif
+ }
+ }
tmp_fl = fl;
fl = fl->next;
kfree(tmp_fl);

@ -1,35 +0,0 @@
--- a/drivers/mtd/Kconfig
+++ b/drivers/mtd/Kconfig
@@ -179,6 +179,22 @@ config MTD_BCM47XX_PARTS
This provides partitions parser for devices based on BCM47xx
boards.
+config MTD_MYLOADER_PARTS
+ tristate "MyLoader partition parsing"
+ depends on ADM5120 || ATH25 || ATH79
+ ---help---
+ MyLoader is a bootloader which allows the user to define partitions
+ in flash devices, by putting a table in the second erase block
+ on the device, similar to a partition table. This table gives the
+ offsets and lengths of the user defined partitions.
+
+ If you need code which can detect and parse these tables, and
+ register MTD 'partitions' corresponding to each image detected,
+ enable this option.
+
+ You will still need the parsing functions to be called by the driver
+ for your particular device. It won't happen automatically.
+
comment "User Modules And Translation Layers"
#
--- a/drivers/mtd/Makefile
+++ b/drivers/mtd/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_MTD_AFS_PARTS) += afs.o
obj-$(CONFIG_MTD_AR7_PARTS) += ar7part.o
obj-$(CONFIG_MTD_BCM63XX_PARTS) += bcm63xxpart.o
obj-$(CONFIG_MTD_BCM47XX_PARTS) += bcm47xxpart.o
+obj-$(CONFIG_MTD_MYLOADER_PARTS) += myloader.o
# 'Users' - code which presents functionality to userspace.
obj-$(CONFIG_MTD_BLKDEVS) += mtd_blkdevs.o

@ -1,34 +0,0 @@
From 841e59ba3e496d86ca5f069204d5e5c1ad43c01d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
Date: Tue, 27 Jan 2015 22:29:21 +0100
Subject: [PATCH] mtd: bcm47xxpart: support for Xiaomi specific board_data
partition
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
---
drivers/mtd/bcm47xxpart.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
--- a/drivers/mtd/bcm47xxpart.c
+++ b/drivers/mtd/bcm47xxpart.c
@@ -33,6 +33,7 @@
/* Magics */
#define BOARD_DATA_MAGIC 0x5246504D /* MPFR */
#define BOARD_DATA_MAGIC2 0xBD0D0BBD
+#define BOARD_DATA_XIAOMI_MAGIC 0x474D4442 /* GMDB */
#define CFE_MAGIC 0x43464531 /* 1EFC */
#define FACTORY_MAGIC 0x59544346 /* FCTY */
#define NVRAM_HEADER 0x48534C46 /* FLSH */
@@ -267,7 +268,8 @@ static int bcm47xxpart_parse(struct mtd_
}
/* Some devices (ex. WNDR3700v3) don't have a standard 'MPFR' */
- if (buf[0x000 / 4] == BOARD_DATA_MAGIC2) {
+ if (buf[0x000 / 4] == BOARD_DATA_MAGIC2 ||
+ le32_to_cpu(buf[0x000 / 4]) == BOARD_DATA_XIAOMI_MAGIC) {
bcm47xxpart_add_part(&parts[curr_part++], "board_data",
offset, MTD_WRITEABLE);
continue;

@ -1,42 +0,0 @@
From fd54aa583296f9adfb1f519affbc10ba521eb809 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
Date: Wed, 28 Jan 2015 22:14:41 +0100
Subject: [PATCH] mtd: bcm47xxpart: detect T_Meter partition
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
It can be found on many Netgear devices. It consists of many 0x30 blocks
starting with 4D 54.
Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
---
drivers/mtd/bcm47xxpart.c | 10 ++++++++++
1 file changed, 10 insertions(+)
--- a/drivers/mtd/bcm47xxpart.c
+++ b/drivers/mtd/bcm47xxpart.c
@@ -39,6 +39,7 @@
#define NVRAM_HEADER 0x48534C46 /* FLSH */
#define POT_MAGIC1 0x54544f50 /* POTT */
#define POT_MAGIC2 0x504f /* OP */
+#define T_METER_MAGIC 0x4D540000 /* MT */
#define ML_MAGIC1 0x39685a42
#define ML_MAGIC2 0x26594131
#define TRX_MAGIC 0x30524448
@@ -180,6 +181,15 @@ static int bcm47xxpart_parse(struct mtd_
MTD_WRITEABLE);
continue;
}
+
+ /* T_Meter */
+ if ((le32_to_cpu(buf[0x000 / 4]) & 0xFFFF0000) == T_METER_MAGIC &&
+ (le32_to_cpu(buf[0x030 / 4]) & 0xFFFF0000) == T_METER_MAGIC &&
+ (le32_to_cpu(buf[0x060 / 4]) & 0xFFFF0000) == T_METER_MAGIC) {
+ bcm47xxpart_add_part(&parts[curr_part++], "T_Meter", offset,
+ MTD_WRITEABLE);
+ continue;
+ }
/* TRX */
if (buf[0x000 / 4] == TRX_MAGIC) {

@ -1,108 +0,0 @@
--- a/drivers/mtd/devices/block2mtd.c
+++ b/drivers/mtd/devices/block2mtd.c
@@ -26,6 +26,7 @@
#include <linux/list.h>
#include <linux/init.h>
#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
#include <linux/mutex.h>
#include <linux/mount.h>
#include <linux/slab.h>
@@ -219,7 +220,7 @@ static void block2mtd_free_device(struct
static struct block2mtd_dev *add_device(char *devname, int erase_size,
- int timeout)
+ const char *mtdname, int timeout)
{
#ifndef MODULE
int i;
@@ -227,6 +228,7 @@ static struct block2mtd_dev *add_device(
const fmode_t mode = FMODE_READ | FMODE_WRITE | FMODE_EXCL;
struct block_device *bdev = ERR_PTR(-ENODEV);
struct block2mtd_dev *dev;
+ struct mtd_partition *part;
char *name;
if (!devname)
@@ -283,13 +285,16 @@ static struct block2mtd_dev *add_device(
/* Setup the MTD structure */
/* make the name contain the block device in */
- name = kasprintf(GFP_KERNEL, "block2mtd: %s", devname);
+ if (!mtdname)
+ mtdname = devname;
+ name = kmalloc(strlen(mtdname) + 1, GFP_KERNEL);
if (!name)
goto err_destroy_mutex;
+ strcpy(name, mtdname);
dev->mtd.name = name;
- dev->mtd.size = dev->blkdev->bd_inode->i_size & PAGE_MASK;
+ dev->mtd.size = dev->blkdev->bd_inode->i_size & PAGE_MASK & ~(erase_size - 1);
dev->mtd.erasesize = erase_size;
dev->mtd.writesize = 1;
dev->mtd.writebufsize = PAGE_SIZE;
@@ -302,7 +307,11 @@ static struct block2mtd_dev *add_device(
dev->mtd.priv = dev;
dev->mtd.owner = THIS_MODULE;
- if (mtd_device_register(&dev->mtd, NULL, 0)) {
+ part = kzalloc(sizeof(struct mtd_partition), GFP_KERNEL);
+ part->name = name;
+ part->offset = 0;
+ part->size = dev->mtd.size;
+ if (mtd_device_register(&dev->mtd, part, 1)) {
/* Device didn't get added, so free the entry */
goto err_destroy_mutex;
}
@@ -310,8 +319,7 @@ static struct block2mtd_dev *add_device(
list_add(&dev->list, &blkmtd_device_list);
pr_info("mtd%d: [%s] erase_size = %dKiB [%d]\n",
dev->mtd.index,
- dev->mtd.name + strlen("block2mtd: "),
- dev->mtd.erasesize >> 10, dev->mtd.erasesize);
+ mtdname, dev->mtd.erasesize >> 10, dev->mtd.erasesize);
return dev;
err_destroy_mutex:
@@ -384,7 +392,7 @@ static int block2mtd_setup2(const char *
/* 80 for device, 12 for erase size, 80 for name, 8 for timeout */
char buf[80 + 12 + 80 + 8];
char *str = buf;
- char *token[2];
+ char *token[3];
char *name;
size_t erase_size = PAGE_SIZE;
unsigned long timeout = MTD_DEFAULT_TIMEOUT;
@@ -398,7 +406,7 @@ static int block2mtd_setup2(const char *
strcpy(str, val);
kill_final_newline(str);
- for (i = 0; i < 2; i++)
+ for (i = 0; i < 3; i++)
token[i] = strsep(&str, ",");
if (str) {
@@ -424,8 +432,10 @@ static int block2mtd_setup2(const char *
return 0;
}
}
+ if (token[2] && (strlen(token[2]) + 1 > 80))
+ pr_err("mtd device name too long\n");
- add_device(name, erase_size, timeout);
+ add_device(name, erase_size, token[2], timeout);
return 0;
}
@@ -459,7 +469,7 @@ static int block2mtd_setup(const char *v
module_param_call(block2mtd, block2mtd_setup, NULL, NULL, 0200);
-MODULE_PARM_DESC(block2mtd, "Device to use. \"block2mtd=<dev>[,<erasesize>]\"");
+MODULE_PARM_DESC(block2mtd, "Device to use. \"block2mtd=<dev>[,<erasesize>[,<name>]]\"");
static int __init block2mtd_init(void)
{

@ -1,39 +0,0 @@
--- a/drivers/mtd/devices/block2mtd.c
+++ b/drivers/mtd/devices/block2mtd.c
@@ -392,7 +392,7 @@ static int block2mtd_setup2(const char *
/* 80 for device, 12 for erase size, 80 for name, 8 for timeout */
char buf[80 + 12 + 80 + 8];
char *str = buf;
- char *token[3];
+ char *token[4];
char *name;
size_t erase_size = PAGE_SIZE;
unsigned long timeout = MTD_DEFAULT_TIMEOUT;
@@ -406,7 +406,7 @@ static int block2mtd_setup2(const char *
strcpy(str, val);
kill_final_newline(str);
- for (i = 0; i < 3; i++)
+ for (i = 0; i < 4; i++)
token[i] = strsep(&str, ",");
if (str) {
@@ -435,6 +435,9 @@ static int block2mtd_setup2(const char *
if (token[2] && (strlen(token[2]) + 1 > 80))
pr_err("mtd device name too long\n");
+ if (token[3] && kstrtoul(token[3], 0, &timeout))
+ pr_err("invalid timeout\n");
+
add_device(name, erase_size, token[2], timeout);
return 0;
@@ -469,7 +472,7 @@ static int block2mtd_setup(const char *v
module_param_call(block2mtd, block2mtd_setup, NULL, NULL, 0200);
-MODULE_PARM_DESC(block2mtd, "Device to use. \"block2mtd=<dev>[,<erasesize>[,<name>]]\"");
+MODULE_PARM_DESC(block2mtd, "Device to use. \"block2mtd=<dev>[,<erasesize>[,<name>[,<timeout>]]]\"");
static int __init block2mtd_init(void)
{

@ -1,37 +0,0 @@
---
drivers/mtd/nand/plat_nand.c | 13 ++++++++++++-
include/linux/mtd/nand.h | 1 +
2 files changed, 13 insertions(+), 1 deletion(-)
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -869,6 +869,7 @@ struct platform_nand_chip {
unsigned int options;
unsigned int bbt_options;
const char **part_probe_types;
+ int (*chip_fixup)(struct mtd_info *mtd);
};
/* Keep gcc happy */
--- a/drivers/mtd/nand/plat_nand.c
+++ b/drivers/mtd/nand/plat_nand.c
@@ -88,7 +88,18 @@ static int plat_nand_probe(struct platfo
}
/* Scan to find existence of the device */
- if (nand_scan(&data->mtd, pdata->chip.nr_chips)) {
+ if (nand_scan_ident(&data->mtd, pdata->chip.nr_chips, NULL)) {
+ err = -ENXIO;
+ goto out;
+ }
+
+ if (pdata->chip.chip_fixup) {
+ err = pdata->chip.chip_fixup(&data->mtd);
+ if (err)
+ goto out;
+ }
+
+ if (nand_scan_tail(&data->mtd)) {
err = -ENXIO;
goto out;
}

@ -1,11 +0,0 @@
--- a/drivers/mtd/nand/nand_ecc.c
+++ b/drivers/mtd/nand/nand_ecc.c
@@ -507,7 +507,7 @@ int __nand_correct_data(unsigned char *b
return 1; /* error in ECC data; no action needed */
pr_err("%s: uncorrectable ECC error\n", __func__);
- return -1;
+ return -EBADMSG;
}
EXPORT_SYMBOL(__nand_correct_data);

@ -1,11 +0,0 @@
--- a/drivers/mtd/chips/cfi_cmdset_0002.c
+++ b/drivers/mtd/chips/cfi_cmdset_0002.c
@@ -809,7 +809,7 @@ static int get_chip(struct map_info *map
return 0;
case FL_ERASING:
- if (!cfip || !(cfip->EraseSuspend & (0x1|0x2)) ||
+ if (1 /* no suspend */ || !cfip || !(cfip->EraseSuspend & (0x1|0x2)) ||
!(mode == FL_READY || mode == FL_POINT ||
(mode == FL_WRITING && (cfip->EraseSuspend & 0x2))))
goto sleep;

@ -1,18 +0,0 @@
From: George Kashperko <george@znau.edu.ua>
Issue map read after Write Buffer Load command to ensure chip is ready
to receive data.
Signed-off-by: George Kashperko <george@znau.edu.ua>
---
drivers/mtd/chips/cfi_cmdset_0002.c | 1 +
1 file changed, 1 insertion(+)
--- a/drivers/mtd/chips/cfi_cmdset_0002.c
+++ b/drivers/mtd/chips/cfi_cmdset_0002.c
@@ -1830,6 +1830,7 @@ static int __xipram do_write_buffer(stru
/* Write Buffer Load */
map_write(map, CMD(0x25), cmd_adr);
+ (void) map_read(map, cmd_adr);
chip->state = FL_WRITING_TO_BUFFER;

@ -1,14 +0,0 @@
Disable software protection bits for Macronix flashes.
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -1200,6 +1200,7 @@ int spi_nor_scan(struct spi_nor *nor, co
if (JEDEC_MFR(info) == SNOR_MFR_ATMEL ||
JEDEC_MFR(info) == SNOR_MFR_INTEL ||
+ JEDEC_MFR(info) == SNOR_MFR_MACRONIX ||
JEDEC_MFR(info) == SNOR_MFR_SST) {
write_enable(nor);
write_sr(nor, 0);

@ -1,26 +0,0 @@
--- a/drivers/mtd/mtdcore.c
+++ b/drivers/mtd/mtdcore.c
@@ -39,6 +39,7 @@
#include <linux/slab.h>
#include <linux/reboot.h>
#include <linux/kconfig.h>
+#include <linux/root_dev.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
@@ -456,6 +457,15 @@ int add_mtd_device(struct mtd_info *mtd)
of this try_ nonsense, and no bitching about it
either. :) */
__module_get(THIS_MODULE);
+
+ if (!strcmp(mtd->name, "rootfs") &&
+ config_enabled(CONFIG_MTD_ROOTFS_ROOT_DEV) &&
+ ROOT_DEV == 0) {
+ pr_notice("mtd: device %d (%s) set to be root filesystem\n",
+ mtd->index, mtd->name);
+ ROOT_DEV = MKDEV(MTD_BLOCK_MAJOR, mtd->index);
+ }
+
return 0;
fail_added:

@ -1,76 +0,0 @@
From 8a52e4100d7c3a4a1dfddfa02b8864a9b0068c13 Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org>
Date: Sat, 17 May 2014 03:36:18 +0200
Subject: [PATCH 1/5] ubi: auto-attach mtd device named "ubi" or "data" on boot
To: openwrt-devel@lists.openwrt.org
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
drivers/mtd/ubi/build.c | 36 ++++++++++++++++++++++++++++++++++++
1 file changed, 36 insertions(+)
--- a/drivers/mtd/ubi/build.c
+++ b/drivers/mtd/ubi/build.c
@@ -1200,6 +1200,49 @@ static struct mtd_info * __init open_mtd
return mtd;
}
+/*
+ * This function tries attaching mtd partitions named either "ubi" or "data"
+ * during boot.
+ */
+static void __init ubi_auto_attach(void)
+{
+ int err;
+ struct mtd_info *mtd;
+
+ /* try attaching mtd device named "ubi" or "data" */
+ mtd = open_mtd_device("ubi");
+ if (IS_ERR(mtd))
+ mtd = open_mtd_device("data");
+
+ if (!IS_ERR(mtd)) {
+ size_t len;
+ char magic[4];
+
+ /* check for a valid ubi magic */
+ err = mtd_read(mtd, 0, 4, &len, (void *) magic);
+ if (!err && len == 4 && strncmp(magic, "UBI#", 4)) {
+ pr_err("UBI error: no valid UBI magic found inside mtd%d", mtd->index);
+ put_mtd_device(mtd);
+ return;
+ }
+
+ /* auto-add only media types where UBI makes sense */
+ if (mtd->type == MTD_NANDFLASH ||
+ mtd->type == MTD_NORFLASH ||
+ mtd->type == MTD_DATAFLASH ||
+ mtd->type == MTD_MLCNANDFLASH) {
+ mutex_lock(&ubi_devices_mutex);
+ pr_notice("UBI: auto-attach mtd%d", mtd->index);
+ err = ubi_attach_mtd_dev(mtd, UBI_DEV_NUM_AUTO, 0, 0);
+ mutex_unlock(&ubi_devices_mutex);
+ if (err < 0) {
+ pr_err("UBI error: cannot attach mtd%d", mtd->index);
+ put_mtd_device(mtd);
+ }
+ }
+ }
+}
+
static int __init ubi_init(void)
{
int err, i, k;
@@ -1283,6 +1326,12 @@ static int __init ubi_init(void)
}
}
+ /* auto-attach mtd devices only if built-in to the kernel and no ubi.mtd
+ * parameter was given */
+ if (config_enabled(CONFIG_MTD_ROOTFS_ROOT_DEV) &&
+ !ubi_is_module() && !mtd_devs)
+ ubi_auto_attach();
+
err = ubiblock_init();
if (err) {
pr_err("UBI error: block: cannot initialize, error %d", err);

@ -1,69 +0,0 @@
From 0f3966579815f889bb2fcb4846152c35f65e79c4 Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org>
Date: Thu, 15 May 2014 21:06:33 +0200
Subject: [PATCH 2/5] ubi: auto-create ubiblock device for rootfs
To: openwrt-devel@lists.openwrt.org
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
drivers/mtd/ubi/block.c | 42 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 42 insertions(+)
--- a/drivers/mtd/ubi/block.c
+++ b/drivers/mtd/ubi/block.c
@@ -628,6 +628,44 @@ static void __init ubiblock_create_from_
}
}
+#define UBIFS_NODE_MAGIC 0x06101831
+static inline int ubi_vol_is_ubifs(struct ubi_volume_desc *desc)
+{
+ int ret;
+ uint32_t magic_of, magic;
+ ret = ubi_read(desc, 0, (char *)&magic_of, 0, 4);
+ if (ret)
+ return 0;
+ magic = le32_to_cpu(magic_of);
+ return magic == UBIFS_NODE_MAGIC;
+}
+
+static void __init ubiblock_create_auto_rootfs(void)
+{
+ int ubi_num, ret, is_ubifs;
+ struct ubi_volume_desc *desc;
+ struct ubi_volume_info vi;
+
+ for (ubi_num = 0; ubi_num < UBI_MAX_DEVICES; ubi_num++) {
+ desc = ubi_open_volume_nm(ubi_num, "rootfs", UBI_READONLY);
+ if (IS_ERR(desc))
+ continue;
+
+ ubi_get_volume_info(desc, &vi);
+ is_ubifs = ubi_vol_is_ubifs(desc);
+ ubi_close_volume(desc);
+ if (is_ubifs)
+ break;
+
+ ret = ubiblock_create(&vi);
+ if (ret)
+ pr_err("UBI error: block: can't add '%s' volume, err=%d\n",
+ vi.name, ret);
+ /* always break if we get here */
+ break;
+ }
+}
+
static void ubiblock_remove_all(void)
{
struct ubiblock *next;
@@ -658,6 +696,10 @@ int __init ubiblock_init(void)
*/
ubiblock_create_from_param();
+ /* auto-attach "rootfs" volume if existing and non-ubifs */
+ if (config_enabled(CONFIG_MTD_ROOTFS_ROOT_DEV))
+ ubiblock_create_auto_rootfs();
+
/*
* Block devices are only created upon user requests, so we ignore
* existing volumes.

@ -1,53 +0,0 @@
From eea9e1785e4c05c2a3444506aabafa0ae958538f Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org>
Date: Sat, 17 May 2014 03:35:02 +0200
Subject: [PATCH 4/5] try auto-mounting ubi0:rootfs in init/do_mounts.c
To: openwrt-devel@lists.openwrt.org
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
init/do_mounts.c | 26 +++++++++++++++++++++++++-
1 file changed, 25 insertions(+), 1 deletion(-)
--- a/init/do_mounts.c
+++ b/init/do_mounts.c
@@ -438,7 +438,27 @@ retry:
out:
put_page(page);
}
-
+
+static int __init mount_ubi_rootfs(void)
+{
+ int flags = MS_SILENT;
+ int err, tried = 0;
+
+ while (tried < 2) {
+ err = do_mount_root("ubi0:rootfs", "ubifs", flags, \
+ root_mount_data);
+ switch (err) {
+ case -EACCES:
+ flags |= MS_RDONLY;
+ tried++;
+ default:
+ return err;
+ }
+ }
+
+ return -EINVAL;
+}
+
#ifdef CONFIG_ROOT_NFS
#define NFSROOT_TIMEOUT_MIN 5
@@ -532,6 +552,10 @@ void __init mount_root(void)
change_floppy("root floppy");
}
#endif
+#ifdef CONFIG_MTD_ROOTFS_ROOT_DEV
+ if (!mount_ubi_rootfs())
+ return;
+#endif
#ifdef CONFIG_BLOCK
{
int err = create_dev("/dev/root", ROOT_DEV);

@ -1,37 +0,0 @@
From cd68d1b12b5ea4c01a664c064179ada42bf55d3d Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org>
Date: Thu, 15 May 2014 20:55:42 +0200
Subject: [PATCH 5/5] ubi: set ROOT_DEV to ubiblock "rootfs" if unset
To: openwrt-devel@lists.openwrt.org
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
drivers/mtd/ubi/block.c | 10 ++++++++++
1 file changed, 10 insertions(+)
--- a/drivers/mtd/ubi/block.c
+++ b/drivers/mtd/ubi/block.c
@@ -50,6 +50,7 @@
#include <linux/scatterlist.h>
#include <linux/idr.h>
#include <asm/div64.h>
+#include <linux/root_dev.h>
#include "ubi-media.h"
#include "ubi.h"
@@ -448,6 +449,15 @@ int ubiblock_create(struct ubi_volume_in
add_disk(dev->gd);
dev_info(disk_to_dev(dev->gd), "created from ubi%d:%d(%s)",
dev->ubi_num, dev->vol_id, vi->name);
+
+ if (!strcmp(vi->name, "rootfs") &&
+ config_enabled(CONFIG_MTD_ROOTFS_ROOT_DEV) &&
+ ROOT_DEV == 0) {
+ pr_notice("ubiblock: device ubiblock%d_%d (%s) set to be root filesystem\n",
+ dev->ubi_num, dev->vol_id, vi->name);
+ ROOT_DEV = MKDEV(gd->major, gd->first_minor);
+ }
+
return 0;
out_free_queue:

@ -1,51 +0,0 @@
--- a/drivers/mtd/ubi/attach.c
+++ b/drivers/mtd/ubi/attach.c
@@ -803,6 +803,13 @@ out_unlock:
return err;
}
+static bool ec_hdr_has_eof(struct ubi_ec_hdr *ech)
+{
+ return ech->padding1[0] == 'E' &&
+ ech->padding1[1] == 'O' &&
+ ech->padding1[2] == 'F';
+}
+
/**
* scan_peb - scan and process UBI headers of a PEB.
* @ubi: UBI device description object
@@ -833,9 +840,21 @@ static int scan_peb(struct ubi_device *u
return 0;
}
- err = ubi_io_read_ec_hdr(ubi, pnum, ech, 0);
- if (err < 0)
- return err;
+ if (!ai->eof_found) {
+ err = ubi_io_read_ec_hdr(ubi, pnum, ech, 0);
+ if (err < 0)
+ return err;
+
+ if (ec_hdr_has_eof(ech)) {
+ pr_notice("UBI: EOF marker found, PEBs from %d will be erased",
+ pnum);
+ ai->eof_found = true;
+ }
+ }
+
+ if (ai->eof_found)
+ err = UBI_IO_FF_BITFLIPS;
+
switch (err) {
case 0:
break;
--- a/drivers/mtd/ubi/ubi.h
+++ b/drivers/mtd/ubi/ubi.h
@@ -739,6 +739,7 @@ struct ubi_attach_info {
int mean_ec;
uint64_t ec_sum;
int ec_count;
+ bool eof_found;
struct kmem_cache *aeb_slab_cache;
};

@ -1,18 +0,0 @@
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -30,6 +30,7 @@ source "fs/ocfs2/Kconfig"
source "fs/btrfs/Kconfig"
source "fs/nilfs2/Kconfig"
source "fs/f2fs/Kconfig"
+source "fs/yaffs2/Kconfig"
config FS_DAX
bool "Direct Access (DAX) support"
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -125,3 +125,5 @@ obj-y += exofs/ # Multiple modules
obj-$(CONFIG_CEPH_FS) += ceph/
obj-$(CONFIG_PSTORE) += pstore/
obj-$(CONFIG_EFIVAR_FS) += efivarfs/
+obj-$(CONFIG_YAFFS_FS) += yaffs2/
+

@ -1,239 +0,0 @@
Subject: yaffs: fix compat tags handling
Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
---
--- a/fs/yaffs2/yaffs_tagscompat.c
+++ b/fs/yaffs2/yaffs_tagscompat.c
@@ -17,7 +17,9 @@
#include "yaffs_getblockinfo.h"
#include "yaffs_trace.h"
+#if 0
static void yaffs_handle_rd_data_error(struct yaffs_dev *dev, int nand_chunk);
+#endif
/********** Tags ECC calculations *********/
@@ -71,6 +73,7 @@ int yaffs_check_tags_ecc(struct yaffs_ta
return 0;
}
+#if 0
/********** Tags **********/
static void yaffs_load_tags_to_spare(struct yaffs_spare *spare_ptr,
@@ -379,3 +382,214 @@ void yaffs_tags_compat_install(struct ya
if(!dev->tagger.mark_bad_fn)
dev->tagger.mark_bad_fn = yaffs_tags_compat_mark_bad;
}
+#else
+
+#include "yaffs_packedtags1.h"
+
+static int yaffs_tags_compat_write(struct yaffs_dev *dev,
+ int nand_chunk,
+ const u8 *data,
+ const struct yaffs_ext_tags *tags)
+{
+ struct yaffs_packed_tags1 pt1;
+ u8 tag_buf[9];
+ int retval;
+
+ /* we assume that yaffs_packed_tags1 and yaffs_tags are compatible */
+ compile_time_assertion(sizeof(struct yaffs_packed_tags1) == 12);
+ compile_time_assertion(sizeof(struct yaffs_tags) == 8);
+
+ yaffs_pack_tags1(&pt1, tags);
+ yaffs_calc_tags_ecc((struct yaffs_tags *)&pt1);
+
+ /* When deleting a chunk, the upper layer provides only skeletal
+ * tags, one with is_deleted set. However, we need to update the
+ * tags, not erase them completely. So we use the NAND write property
+ * that only zeroed-bits stick and set tag bytes to all-ones and
+ * zero just the (not) deleted bit.
+ */
+ if (!dev->param.tags_9bytes) {
+ if (tags->is_deleted) {
+ memset(&pt1, 0xff, 8);
+ /* clear delete status bit to indicate deleted */
+ pt1.deleted = 0;
+ }
+ memcpy(tag_buf, &pt1, 8);
+ } else {
+ if (tags->is_deleted) {
+ memset(tag_buf, 0xff, 8);
+ tag_buf[8] = 0;
+ } else {
+ memcpy(tag_buf, &pt1, 8);
+ tag_buf[8] = 0xff;
+ }
+ }
+
+ retval = dev->drv.drv_write_chunk_fn(dev, nand_chunk,
+ data,
+ (data) ? dev->data_bytes_per_chunk : 0,
+ tag_buf,
+ (dev->param.tags_9bytes) ? 9 : 8);
+
+ return retval;
+}
+
+/* Return with empty extended tags but add ecc_result.
+ */
+static int return_empty_tags(struct yaffs_ext_tags *tags,
+ enum yaffs_ecc_result ecc_result,
+ int retval)
+{
+ if (tags) {
+ memset(tags, 0, sizeof(*tags));
+ tags->ecc_result = ecc_result;
+ }
+
+ return retval;
+}
+
+static int yaffs_tags_compat_read(struct yaffs_dev *dev,
+ int nand_chunk,
+ u8 *data,
+ struct yaffs_ext_tags *tags)
+{
+ struct yaffs_packed_tags1 pt1;
+ enum yaffs_ecc_result ecc_result;
+ int retval;
+ int deleted;
+ u8 tag_buf[9];
+
+ retval = dev->drv.drv_read_chunk_fn(dev, nand_chunk,
+ data, dev->param.total_bytes_per_chunk,
+ tag_buf,
+ (dev->param.tags_9bytes) ? 9 : 8,
+ &ecc_result);
+
+ switch (ecc_result) {
+ case YAFFS_ECC_RESULT_NO_ERROR:
+ case YAFFS_ECC_RESULT_FIXED:
+ break;
+
+ case YAFFS_ECC_RESULT_UNFIXED:
+ default:
+ return_empty_tags(tags, YAFFS_ECC_RESULT_UNFIXED, 0);
+ tags->block_bad = dev->drv.drv_check_bad_fn(dev, nand_chunk);
+ return YAFFS_FAIL;
+ }
+
+ /* Check for a blank/erased chunk. */
+ if (yaffs_check_ff(tag_buf, 8)) {
+ /* when blank, upper layers want ecc_result to be <= NO_ERROR */
+ return return_empty_tags(tags, YAFFS_ECC_RESULT_NO_ERROR,
+ YAFFS_OK);
+ }
+
+ memcpy(&pt1, tag_buf, 8);
+
+ if (!dev->param.tags_9bytes) {
+ /* Read deleted status (bit) then return it to it's non-deleted
+ * state before performing tags mini-ECC check. pt1.deleted is
+ * inverted.
+ */
+ deleted = !pt1.deleted;
+ pt1.deleted = 1;
+ } else {
+ deleted = (hweight8(tag_buf[8]) < 7) ? 1 : 0;
+ }
+
+ /* Check the packed tags mini-ECC and correct if necessary/possible. */
+ retval = yaffs_check_tags_ecc((struct yaffs_tags *)&pt1);
+ switch (retval) {
+ case 0:
+ /* no tags error, use MTD result */
+ break;
+ case 1:
+ /* recovered tags-ECC error */
+ dev->n_tags_ecc_fixed++;
+ if (ecc_result == YAFFS_ECC_RESULT_NO_ERROR)
+ ecc_result = YAFFS_ECC_RESULT_FIXED;
+ break;
+ default:
+ /* unrecovered tags-ECC error */
+ dev->n_tags_ecc_unfixed++;
+ return return_empty_tags(tags, YAFFS_ECC_RESULT_UNFIXED,
+ YAFFS_FAIL);
+ }
+
+ /* Unpack the tags to extended form and set ECC result.
+ * [set should_be_ff just to keep yaffs_unpack_tags1 happy]
+ */
+ pt1.should_be_ff = 0xffffffff;
+ yaffs_unpack_tags1(tags, &pt1);
+ tags->ecc_result = ecc_result;
+
+ /* Set deleted state */
+ tags->is_deleted = deleted;
+ return YAFFS_OK;
+}
+
+static int yaffs_tags_compat_mark_bad(struct yaffs_dev *dev, int block_no)
+{
+ return dev->drv.drv_mark_bad_fn(dev, block_no);
+}
+
+static int yaffs_tags_compat_query_block(struct yaffs_dev *dev,
+ int block_no,
+ enum yaffs_block_state *state,
+ u32 *seq_number)
+{
+ struct yaffs_ext_tags tags;
+ int retval;
+
+ yaffs_trace(YAFFS_TRACE_MTD, "%s %d", __func__, block_no);
+
+ *seq_number = 0;
+
+ retval = dev->drv.drv_check_bad_fn(dev, block_no);
+ if (retval == YAFFS_FAIL) {
+ *state = YAFFS_BLOCK_STATE_DEAD;
+ goto out;
+ }
+
+ yaffs_tags_compat_read(dev, block_no * dev->param.chunks_per_block,
+ NULL, &tags);
+
+ if (tags.ecc_result != YAFFS_ECC_RESULT_NO_ERROR) {
+ yaffs_trace(YAFFS_TRACE_MTD, "block %d is marked bad",
+ block_no);
+ *state = YAFFS_BLOCK_STATE_NEEDS_SCAN;
+ } else if (tags.chunk_used) {
+ *seq_number = tags.seq_number;
+ *state = YAFFS_BLOCK_STATE_NEEDS_SCAN;
+ } else {
+ *state = YAFFS_BLOCK_STATE_EMPTY;
+ }
+
+ retval = YAFFS_OK;
+
+out:
+ yaffs_trace(YAFFS_TRACE_MTD,
+ "block query returns seq %u state %d",
+ *seq_number, *state);
+
+ return retval;
+}
+
+void yaffs_tags_compat_install(struct yaffs_dev *dev)
+{
+ if (dev->param.is_yaffs2)
+ return;
+
+ if (!dev->tagger.write_chunk_tags_fn)
+ dev->tagger.write_chunk_tags_fn = yaffs_tags_compat_write;
+
+ if (!dev->tagger.read_chunk_tags_fn)
+ dev->tagger.read_chunk_tags_fn = yaffs_tags_compat_read;
+
+ if (!dev->tagger.query_block_fn)
+ dev->tagger.query_block_fn = yaffs_tags_compat_query_block;
+
+ if (!dev->tagger.mark_bad_fn)
+ dev->tagger.mark_bad_fn = yaffs_tags_compat_mark_bad;
+}
+#endif

@ -1,115 +0,0 @@
Subject: yaffs: add support for tags-9bytes mount option
Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
---
--- a/fs/yaffs2/yaffs_vfs.c
+++ b/fs/yaffs2/yaffs_vfs.c
@@ -2644,6 +2644,7 @@ static const struct super_operations yaf
struct yaffs_options {
int inband_tags;
+ int tags_9bytes;
int skip_checkpoint_read;
int skip_checkpoint_write;
int no_cache;
@@ -2683,6 +2684,8 @@ static int yaffs_parse_options(struct ya
if (!strcmp(cur_opt, "inband-tags")) {
options->inband_tags = 1;
+ } else if (!strcmp(cur_opt, "tags-9bytes")) {
+ options->tags_9bytes = 1;
} else if (!strcmp(cur_opt, "tags-ecc-off")) {
options->tags_ecc_on = 0;
options->tags_ecc_overridden = 1;
@@ -2756,7 +2759,6 @@ static struct super_block *yaffs_interna
struct yaffs_param *param;
int read_only = 0;
- int inband_tags = 0;
struct yaffs_options options;
@@ -2796,6 +2798,9 @@ static struct super_block *yaffs_interna
memset(&options, 0, sizeof(options));
+ if (IS_ENABLED(CONFIG_YAFFS_9BYTE_TAGS))
+ options.tags_9bytes = 1;
+
if (yaffs_parse_options(&options, data_str)) {
/* Option parsing failed */
return NULL;
@@ -2829,17 +2834,22 @@ static struct super_block *yaffs_interna
}
/* Added NCB 26/5/2006 for completeness */
- if (yaffs_version == 2 && !options.inband_tags
- && WRITE_SIZE(mtd) == 512) {
+ if (yaffs_version == 2 &&
+ (!options.inband_tags || options.tags_9bytes) &&
+ WRITE_SIZE(mtd) == 512) {
yaffs_trace(YAFFS_TRACE_ALWAYS, "auto selecting yaffs1");
yaffs_version = 1;
}
- if (mtd->oobavail < sizeof(struct yaffs_packed_tags2) ||
- options.inband_tags)
- inband_tags = 1;
+ if (yaffs_version == 2 &&
+ mtd->oobavail < sizeof(struct yaffs_packed_tags2)) {
+ yaffs_trace(YAFFS_TRACE_ALWAYS, "auto selecting inband tags");
+ options.inband_tags = 1;
+ }
- if(yaffs_verify_mtd(mtd, yaffs_version, inband_tags) < 0)
+ err = yaffs_verify_mtd(mtd, yaffs_version, options.inband_tags,
+ options.tags_9bytes);
+ if (err < 0)
return NULL;
/* OK, so if we got here, we have an MTD that's NAND and looks
@@ -2896,7 +2906,8 @@ static struct super_block *yaffs_interna
param->n_reserved_blocks = 5;
param->n_caches = (options.no_cache) ? 0 : 10;
- param->inband_tags = inband_tags;
+ param->inband_tags = options.inband_tags;
+ param->tags_9bytes = options.tags_9bytes;
param->enable_xattr = 1;
if (options.lazy_loading_overridden)
--- a/fs/yaffs2/yaffs_mtdif.c
+++ b/fs/yaffs2/yaffs_mtdif.c
@@ -278,7 +278,8 @@ struct mtd_info * yaffs_get_mtd_device(d
return mtd;
}
-int yaffs_verify_mtd(struct mtd_info *mtd, int yaffs_version, int inband_tags)
+int yaffs_verify_mtd(struct mtd_info *mtd, int yaffs_version, int inband_tags,
+ int tags_9bytes)
{
if (yaffs_version == 2) {
if ((WRITE_SIZE(mtd) < YAFFS_MIN_YAFFS2_CHUNK_SIZE ||
@@ -297,6 +298,12 @@ int yaffs_verify_mtd(struct mtd_info *mt
);
return -1;
}
+
+ if (tags_9bytes && mtd->oobavail < 9) {
+ yaffs_trace(YAFFS_TRACE_ALWAYS,
+ "MTD device does not support 9-byte tags");
+ return -1;
+ }
}
return 0;
--- a/fs/yaffs2/yaffs_mtdif.h
+++ b/fs/yaffs2/yaffs_mtdif.h
@@ -21,5 +21,6 @@
void yaffs_mtd_drv_install(struct yaffs_dev *dev);
struct mtd_info * yaffs_get_mtd_device(dev_t sdev);
void yaffs_put_mtd_device(struct mtd_info *mtd);
-int yaffs_verify_mtd(struct mtd_info *mtd, int yaffs_version, int inband_tags);
+int yaffs_verify_mtd(struct mtd_info *mtd, int yaffs_version, int inband_tags,
+ int tags_9bytes);
#endif

@ -1,29 +0,0 @@
--- a/fs/yaffs2/yaffs_vfs.c
+++ b/fs/yaffs2/yaffs_vfs.c
@@ -774,7 +774,25 @@ static int yaffs_sync_object(struct file
}
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22))
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
+static const struct file_operations yaffs_file_operations = {
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 1, 0))
+ .read = new_sync_read,
+#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 1, 0) */
+ .read_iter = generic_file_read_iter,
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 1, 0))
+ .write = new_sync_write,
+#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 1, 0) */
+ .write_iter = generic_file_write_iter,
+ .mmap = generic_file_mmap,
+ .flush = yaffs_file_flush,
+ .fsync = yaffs_sync_object,
+ .splice_read = generic_file_splice_read,
+ .splice_write = iter_file_splice_write,
+ .llseek = generic_file_llseek,
+};
+
+#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22))
static const struct file_operations yaffs_file_operations = {
.read = do_sync_read,
.write = do_sync_write,

@ -1,95 +0,0 @@
--- a/fs/yaffs2/yaffs_vfs.c
+++ b/fs/yaffs2/yaffs_vfs.c
@@ -283,7 +283,7 @@ static int yaffs_readpage_nolock(struct
(long long)pos,
(unsigned)PAGE_CACHE_SIZE);
- obj = yaffs_dentry_to_obj(f->f_dentry);
+ obj = yaffs_dentry_to_obj(f->f_path.dentry);
dev = obj->my_dev;
@@ -481,7 +481,7 @@ static ssize_t yaffs_hold_space(struct f
int n_free_chunks;
- obj = yaffs_dentry_to_obj(f->f_dentry);
+ obj = yaffs_dentry_to_obj(f->f_path.dentry);
dev = obj->my_dev;
@@ -499,7 +499,7 @@ static void yaffs_release_space(struct f
struct yaffs_obj *obj;
struct yaffs_dev *dev;
- obj = yaffs_dentry_to_obj(f->f_dentry);
+ obj = yaffs_dentry_to_obj(f->f_path.dentry);
dev = obj->my_dev;
@@ -591,7 +591,7 @@ static ssize_t yaffs_file_write(struct f
struct inode *inode;
struct yaffs_dev *dev;
- obj = yaffs_dentry_to_obj(f->f_dentry);
+ obj = yaffs_dentry_to_obj(f->f_path.dentry);
if (!obj) {
yaffs_trace(YAFFS_TRACE_OS,
@@ -603,7 +603,7 @@ static ssize_t yaffs_file_write(struct f
yaffs_gross_lock(dev);
- inode = f->f_dentry->d_inode;
+ inode = f->f_path.dentry->d_inode;
if (!S_ISBLK(inode->i_mode) && f->f_flags & O_APPEND)
ipos = inode->i_size;
@@ -727,7 +727,7 @@ static int yaffs_file_flush(struct file
static int yaffs_file_flush(struct file *file)
#endif
{
- struct yaffs_obj *obj = yaffs_dentry_to_obj(file->f_dentry);
+ struct yaffs_obj *obj = yaffs_dentry_to_obj(file->f_path.dentry);
struct yaffs_dev *dev = obj->my_dev;
@@ -1734,7 +1734,7 @@ static int yaffs_iterate(struct file *f,
char name[YAFFS_MAX_NAME_LENGTH + 1];
- obj = yaffs_dentry_to_obj(f->f_dentry);
+ obj = yaffs_dentry_to_obj(f->f_path.dentry);
dev = obj->my_dev;
yaffs_gross_lock(dev);
@@ -1798,14 +1798,14 @@ static int yaffs_readdir(struct file *f,
struct yaffs_obj *obj;
struct yaffs_dev *dev;
struct yaffs_search_context *sc;
- struct inode *inode = f->f_dentry->d_inode;
+ struct inode *inode = f->f_path.dentry->d_inode;
unsigned long offset, curoffs;
struct yaffs_obj *l;
int ret_val = 0;
char name[YAFFS_MAX_NAME_LENGTH + 1];
- obj = yaffs_dentry_to_obj(f->f_dentry);
+ obj = yaffs_dentry_to_obj(f->f_path.dentry);
dev = obj->my_dev;
yaffs_gross_lock(dev);
@@ -1839,10 +1839,10 @@ static int yaffs_readdir(struct file *f,
if (offset == 1) {
yaffs_trace(YAFFS_TRACE_OS,
"yaffs_readdir: entry .. ino %d",
- (int)f->f_dentry->d_parent->d_inode->i_ino);
+ (int)f->f_path.dentry->d_parent->d_inode->i_ino);
yaffs_gross_unlock(dev);
if (filldir(dirent, "..", 2, offset,
- f->f_dentry->d_parent->d_inode->i_ino,
+ f->f_path.dentry->d_parent->d_inode->i_ino,
DT_DIR) < 0) {
yaffs_gross_lock(dev);
goto out;

@ -1,25 +0,0 @@
From f31b7c0efa255dd17a5f584022a319387f09b0d8 Mon Sep 17 00:00:00 2001
From: Jonas Gorski <jonas.gorski@gmail.com>
Date: Tue, 12 Apr 2011 19:55:41 +0200
Subject: [PATCH] squashfs: update xz compressor options struct.
Update the xz compressor options struct to match the squashfs userspace
one.
---
fs/squashfs/xz_wrapper.c | 4 +++-
1 files changed, 3 insertions(+), 1 deletions(-)
--- a/fs/squashfs/xz_wrapper.c
+++ b/fs/squashfs/xz_wrapper.c
@@ -40,8 +40,10 @@ struct squashfs_xz {
};
struct disk_comp_opts {
- __le32 dictionary_size;
__le32 flags;
+ __le16 bit_opts;
+ __le16 fb;
+ __le32 dictionary_size;
};
struct comp_opts {

File diff suppressed because it is too large Load Diff

@ -1,56 +0,0 @@
--- a/fs/jffs2/build.c
+++ b/fs/jffs2/build.c
@@ -114,6 +114,16 @@ static int jffs2_build_filesystem(struct
dbg_fsbuild("scanned flash completely\n");
jffs2_dbg_dump_block_lists_nolock(c);
+ if (c->flags & (1 << 7)) {
+ printk("%s(): unlocking the mtd device... ", __func__);
+ mtd_unlock(c->mtd, 0, c->mtd->size);
+ printk("done.\n");
+
+ printk("%s(): erasing all blocks after the end marker... ", __func__);
+ jffs2_erase_pending_blocks(c, -1);
+ printk("done.\n");
+ }
+
dbg_fsbuild("pass 1 starting\n");
c->flags |= JFFS2_SB_FLAG_BUILDING;
/* Now scan the directory tree, increasing nlink according to every dirent found. */
--- a/fs/jffs2/scan.c
+++ b/fs/jffs2/scan.c
@@ -148,8 +148,14 @@ int jffs2_scan_medium(struct jffs2_sb_in
/* reset summary info for next eraseblock scan */
jffs2_sum_reset_collected(s);
- ret = jffs2_scan_eraseblock(c, jeb, buf_size?flashbuf:(flashbuf+jeb->offset),
- buf_size, s);
+ if (c->flags & (1 << 7)) {
+ if (mtd_block_isbad(c->mtd, jeb->offset))
+ ret = BLK_STATE_BADBLOCK;
+ else
+ ret = BLK_STATE_ALLFF;
+ } else
+ ret = jffs2_scan_eraseblock(c, jeb, buf_size?flashbuf:(flashbuf+jeb->offset),
+ buf_size, s);
if (ret < 0)
goto out;
@@ -561,6 +567,17 @@ full_scan:
return err;
}
+ if ((buf[0] == 0xde) &&
+ (buf[1] == 0xad) &&
+ (buf[2] == 0xc0) &&
+ (buf[3] == 0xde)) {
+ /* end of filesystem. erase everything after this point */
+ printk("%s(): End of filesystem marker found at 0x%x\n", __func__, jeb->offset);
+ c->flags |= (1 << 7);
+
+ return BLK_STATE_ALLFF;
+ }
+
/* We temporarily use 'ofs' as a pointer into the buffer/jeb */
ofs = 0;
max_ofs = EMPTY_SCAN_SIZE(c->sector_size);

@ -1,146 +0,0 @@
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -1536,6 +1536,13 @@ config CRYPTO_LZ4HC
help
This is the LZ4 high compression mode algorithm.
+config CRYPTO_XZ
+ tristate "XZ compression algorithm"
+ select CRYPTO_ALGAPI
+ select XZ_DEC
+ help
+ This is the XZ algorithm. Only decompression is supported for now.
+
comment "Random Number Generation"
config CRYPTO_ANSI_CPRNG
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -103,6 +103,7 @@ obj-$(CONFIG_CRYPTO_AUTHENC) += authenc.
obj-$(CONFIG_CRYPTO_LZO) += lzo.o
obj-$(CONFIG_CRYPTO_LZ4) += lz4.o
obj-$(CONFIG_CRYPTO_LZ4HC) += lz4hc.o
+obj-$(CONFIG_CRYPTO_XZ) += xz.o
obj-$(CONFIG_CRYPTO_842) += 842.o
obj-$(CONFIG_CRYPTO_RNG2) += rng.o
obj-$(CONFIG_CRYPTO_ANSI_CPRNG) += ansi_cprng.o
--- /dev/null
+++ b/crypto/xz.c
@@ -0,0 +1,117 @@
+/*
+ * Cryptographic API.
+ *
+ * XZ decompression support.
+ *
+ * Copyright (c) 2012 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/crypto.h>
+#include <linux/xz.h>
+#include <linux/interrupt.h>
+#include <linux/mm.h>
+#include <linux/net.h>
+
+struct xz_comp_ctx {
+ struct xz_dec *decomp_state;
+ struct xz_buf decomp_buf;
+};
+
+static int crypto_xz_decomp_init(struct xz_comp_ctx *ctx)
+{
+ ctx->decomp_state = xz_dec_init(XZ_SINGLE, 0);
+ if (!ctx->decomp_state)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static void crypto_xz_decomp_exit(struct xz_comp_ctx *ctx)
+{
+ xz_dec_end(ctx->decomp_state);
+}
+
+static int crypto_xz_init(struct crypto_tfm *tfm)
+{
+ struct xz_comp_ctx *ctx = crypto_tfm_ctx(tfm);
+
+ return crypto_xz_decomp_init(ctx);
+}
+
+static void crypto_xz_exit(struct crypto_tfm *tfm)
+{
+ struct xz_comp_ctx *ctx = crypto_tfm_ctx(tfm);
+
+ crypto_xz_decomp_exit(ctx);
+}
+
+static int crypto_xz_compress(struct crypto_tfm *tfm, const u8 *src,
+ unsigned int slen, u8 *dst, unsigned int *dlen)
+{
+ return -EOPNOTSUPP;
+}
+
+static int crypto_xz_decompress(struct crypto_tfm *tfm, const u8 *src,
+ unsigned int slen, u8 *dst, unsigned int *dlen)
+{
+ struct xz_comp_ctx *dctx = crypto_tfm_ctx(tfm);
+ struct xz_buf *xz_buf = &dctx->decomp_buf;
+ int ret;
+
+ memset(xz_buf, '\0', sizeof(struct xz_buf));
+
+ xz_buf->in = (u8 *) src;
+ xz_buf->in_pos = 0;
+ xz_buf->in_size = slen;
+ xz_buf->out = (u8 *) dst;
+ xz_buf->out_pos = 0;
+ xz_buf->out_size = *dlen;
+
+ ret = xz_dec_run(dctx->decomp_state, xz_buf);
+ if (ret != XZ_STREAM_END) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ *dlen = xz_buf->out_pos;
+ ret = 0;
+
+out:
+ return ret;
+}
+
+static struct crypto_alg crypto_xz_alg = {
+ .cra_name = "xz",
+ .cra_flags = CRYPTO_ALG_TYPE_COMPRESS,
+ .cra_ctxsize = sizeof(struct xz_comp_ctx),
+ .cra_module = THIS_MODULE,
+ .cra_list = LIST_HEAD_INIT(crypto_xz_alg.cra_list),
+ .cra_init = crypto_xz_init,
+ .cra_exit = crypto_xz_exit,
+ .cra_u = { .compress = {
+ .coa_compress = crypto_xz_compress,
+ .coa_decompress = crypto_xz_decompress } }
+};
+
+static int __init crypto_xz_mod_init(void)
+{
+ return crypto_register_alg(&crypto_xz_alg);
+}
+
+static void __exit crypto_xz_mod_exit(void)
+{
+ crypto_unregister_alg(&crypto_xz_alg);
+}
+
+module_init(crypto_xz_mod_init);
+module_exit(crypto_xz_mod_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Crypto XZ decompression support");
+MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");

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

Loading…
Cancel
Save