kernel: remove linux 4.3 support
Signed-off-by: Felix Fietkau <nbd@openwrt.org> SVN-Revision: 48955
This commit is contained in:
		| @@ -27,7 +27,7 @@ define KernelPackage/crypto-aead | |||||||
| 	CONFIG_CRYPTO_AEAD2 | 	CONFIG_CRYPTO_AEAD2 | ||||||
|   FILES:=$(LINUX_DIR)/crypto/aead.ko |   FILES:=$(LINUX_DIR)/crypto/aead.ko | ||||||
|   AUTOLOAD:=$(call AutoLoad,09,aead,1) |   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 | endef | ||||||
|  |  | ||||||
| $(eval $(call KernelPackage,crypto-aead)) | $(eval $(call KernelPackage,crypto-aead)) | ||||||
|   | |||||||
| @@ -1005,7 +1005,7 @@ $(eval $(call KernelPackage,rxrpc)) | |||||||
| define KernelPackage/mpls | define KernelPackage/mpls | ||||||
|   SUBMENU:=$(NETWORK_SUPPORT_MENU) |   SUBMENU:=$(NETWORK_SUPPORT_MENU) | ||||||
|   TITLE:=MPLS support |   TITLE:=MPLS support | ||||||
|   DEPENDS:=@!(LINUX_3_18||LINUX_4_1||LINUX_4_3) |   DEPENDS:=@!(LINUX_3_18||LINUX_4_1) | ||||||
|   KCONFIG:= \ |   KCONFIG:= \ | ||||||
| 	CONFIG_MPLS=y \ | 	CONFIG_MPLS=y \ | ||||||
| 	CONFIG_LWTUNNEL=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 |  | ||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -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
											
										
									
								
							
										
											
												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
		Reference in New Issue
	
	Block a user
	 Felix Fietkau
					Felix Fietkau