generic: drop 3.14

Signed-off-by: Luka Perkov <luka@openwrt.org>

SVN-Revision: 45375
This commit is contained in:
Luka Perkov 2015-04-11 10:28:14 +00:00
parent b66b0ae632
commit 8865505665
208 changed files with 0 additions and 39799 deletions

File diff suppressed because it is too large Load diff

View file

@ -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
@@ -622,6 +622,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();
@@ -629,6 +630,9 @@ int __init init_rootfs(void)
} else {
err = init_ramfs_fs();
}
+#else
+ err = init_ramfs_fs();
+#endif
if (err)
unregister_filesystem(&rootfs_fs_type);

View file

@ -1,42 +0,0 @@
From a7ef1eaddbf4bd50bfee92d9dfbecadc61467bbf Mon Sep 17 00:00:00 2001
From: Kevin Cernekee <cernekee@gmail.com>
Date: Mon, 20 Oct 2014 21:27:57 -0700
Subject: [PATCH] MIPS: Allow MIPS_CPU_SCACHE to be used with different line
sizes
CONFIG_MIPS_CPU_SCACHE determines whether to build sc-mips.c. However,
it is currently hardwired to use an L1_SHIFT of 6 (64 bytes). Move the
L1_SHIFT selection into the CPU or SoC section so that other SoCs can
select different values.
Signed-off-by: Kevin Cernekee <cernekee@gmail.com>
Cc: f.fainelli@gmail.com
Cc: mbizon@freebox.fr
Cc: jogo@openwrt.org
Cc: jfraser@broadcom.com
Cc: linux-mips@linux-mips.org
Cc: devicetree@vger.kernel.org
Patchwork: https://patchwork.linux-mips.org/patch/8162/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
---
arch/mips/Kconfig | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -315,6 +315,7 @@ config MIPS_MALTA
select I8259
select MIPS_BONITO64
select MIPS_CPU_SCACHE
+ select MIPS_L1_CACHE_SHIFT_6
select PCI_GT64XXX_PCI0
select MIPS_MSC
select SWAP_IO_SPACE
@@ -1820,7 +1821,6 @@ config IP22_CPU_SCACHE
config MIPS_CPU_SCACHE
bool
select BOARD_SCACHE
- select MIPS_L1_CACHE_SHIFT_6
config R5000_CPU_SCACHE
bool

View file

@ -1,321 +0,0 @@
--- a/drivers/ssb/b43_pci_bridge.c
+++ b/drivers/ssb/b43_pci_bridge.c
@@ -38,6 +38,7 @@ static const struct pci_device_id b43_pc
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x432b) },
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x432c) },
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4350) },
+ { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4351) },
{ 0, },
};
MODULE_DEVICE_TABLE(pci, b43_pci_bridge_tbl);
--- a/drivers/ssb/driver_gpio.c
+++ b/drivers/ssb/driver_gpio.c
@@ -475,7 +475,8 @@ int ssb_gpio_unregister(struct ssb_bus *
{
if (ssb_chipco_available(&bus->chipco) ||
ssb_extif_available(&bus->extif)) {
- return gpiochip_remove(&bus->gpio);
+ gpiochip_remove(&bus->gpio);
+ return 0;
} else {
SSB_WARN_ON(1);
}
--- a/drivers/ssb/pci.c
+++ b/drivers/ssb/pci.c
@@ -326,13 +326,13 @@ err_ctlreg:
return err;
}
-static s8 r123_extract_antgain(u8 sprom_revision, const u16 *in,
- u16 mask, u16 shift)
+static s8 sprom_extract_antgain(u8 sprom_revision, const u16 *in, u16 offset,
+ u16 mask, u16 shift)
{
u16 v;
u8 gain;
- v = in[SPOFF(SSB_SPROM1_AGAIN)];
+ v = in[SPOFF(offset)];
gain = (v & mask) >> shift;
if (gain == 0xFF)
gain = 2; /* If unset use 2dBm */
@@ -416,12 +416,14 @@ static void sprom_extract_r123(struct ss
SPEX(alpha2[1], SSB_SPROM1_CCODE, 0x00ff, 0);
/* Extract the antenna gain values. */
- out->antenna_gain.a0 = r123_extract_antgain(out->revision, in,
- SSB_SPROM1_AGAIN_BG,
- SSB_SPROM1_AGAIN_BG_SHIFT);
- out->antenna_gain.a1 = r123_extract_antgain(out->revision, in,
- SSB_SPROM1_AGAIN_A,
- SSB_SPROM1_AGAIN_A_SHIFT);
+ out->antenna_gain.a0 = sprom_extract_antgain(out->revision, in,
+ SSB_SPROM1_AGAIN,
+ SSB_SPROM1_AGAIN_BG,
+ SSB_SPROM1_AGAIN_BG_SHIFT);
+ out->antenna_gain.a1 = sprom_extract_antgain(out->revision, in,
+ SSB_SPROM1_AGAIN,
+ SSB_SPROM1_AGAIN_A,
+ SSB_SPROM1_AGAIN_A_SHIFT);
if (out->revision >= 2)
sprom_extract_r23(out, in);
}
@@ -468,7 +470,15 @@ static void sprom_extract_r458(struct ss
static void sprom_extract_r45(struct ssb_sprom *out, const u16 *in)
{
+ static const u16 pwr_info_offset[] = {
+ SSB_SPROM4_PWR_INFO_CORE0, SSB_SPROM4_PWR_INFO_CORE1,
+ SSB_SPROM4_PWR_INFO_CORE2, SSB_SPROM4_PWR_INFO_CORE3
+ };
u16 il0mac_offset;
+ int i;
+
+ BUILD_BUG_ON(ARRAY_SIZE(pwr_info_offset) !=
+ ARRAY_SIZE(out->core_pwr_info));
if (out->revision == 4)
il0mac_offset = SSB_SPROM4_IL0MAC;
@@ -524,14 +534,59 @@ static void sprom_extract_r45(struct ssb
}
/* Extract the antenna gain values. */
- SPEX(antenna_gain.a0, SSB_SPROM4_AGAIN01,
- SSB_SPROM4_AGAIN0, SSB_SPROM4_AGAIN0_SHIFT);
- SPEX(antenna_gain.a1, SSB_SPROM4_AGAIN01,
- SSB_SPROM4_AGAIN1, SSB_SPROM4_AGAIN1_SHIFT);
- SPEX(antenna_gain.a2, SSB_SPROM4_AGAIN23,
- SSB_SPROM4_AGAIN2, SSB_SPROM4_AGAIN2_SHIFT);
- SPEX(antenna_gain.a3, SSB_SPROM4_AGAIN23,
- SSB_SPROM4_AGAIN3, SSB_SPROM4_AGAIN3_SHIFT);
+ out->antenna_gain.a0 = sprom_extract_antgain(out->revision, in,
+ SSB_SPROM4_AGAIN01,
+ SSB_SPROM4_AGAIN0,
+ SSB_SPROM4_AGAIN0_SHIFT);
+ out->antenna_gain.a1 = sprom_extract_antgain(out->revision, in,
+ SSB_SPROM4_AGAIN01,
+ SSB_SPROM4_AGAIN1,
+ SSB_SPROM4_AGAIN1_SHIFT);
+ out->antenna_gain.a2 = sprom_extract_antgain(out->revision, in,
+ SSB_SPROM4_AGAIN23,
+ SSB_SPROM4_AGAIN2,
+ SSB_SPROM4_AGAIN2_SHIFT);
+ out->antenna_gain.a3 = sprom_extract_antgain(out->revision, in,
+ SSB_SPROM4_AGAIN23,
+ SSB_SPROM4_AGAIN3,
+ SSB_SPROM4_AGAIN3_SHIFT);
+
+ /* Extract cores power info info */
+ for (i = 0; i < ARRAY_SIZE(pwr_info_offset); i++) {
+ u16 o = pwr_info_offset[i];
+
+ SPEX(core_pwr_info[i].itssi_2g, o + SSB_SPROM4_2G_MAXP_ITSSI,
+ SSB_SPROM4_2G_ITSSI, SSB_SPROM4_2G_ITSSI_SHIFT);
+ SPEX(core_pwr_info[i].maxpwr_2g, o + SSB_SPROM4_2G_MAXP_ITSSI,
+ SSB_SPROM4_2G_MAXP, 0);
+
+ SPEX(core_pwr_info[i].pa_2g[0], o + SSB_SPROM4_2G_PA_0, ~0, 0);
+ SPEX(core_pwr_info[i].pa_2g[1], o + SSB_SPROM4_2G_PA_1, ~0, 0);
+ SPEX(core_pwr_info[i].pa_2g[2], o + SSB_SPROM4_2G_PA_2, ~0, 0);
+ SPEX(core_pwr_info[i].pa_2g[3], o + SSB_SPROM4_2G_PA_3, ~0, 0);
+
+ SPEX(core_pwr_info[i].itssi_5g, o + SSB_SPROM4_5G_MAXP_ITSSI,
+ SSB_SPROM4_5G_ITSSI, SSB_SPROM4_5G_ITSSI_SHIFT);
+ SPEX(core_pwr_info[i].maxpwr_5g, o + SSB_SPROM4_5G_MAXP_ITSSI,
+ SSB_SPROM4_5G_MAXP, 0);
+ SPEX(core_pwr_info[i].maxpwr_5gh, o + SSB_SPROM4_5GHL_MAXP,
+ SSB_SPROM4_5GH_MAXP, 0);
+ SPEX(core_pwr_info[i].maxpwr_5gl, o + SSB_SPROM4_5GHL_MAXP,
+ SSB_SPROM4_5GL_MAXP, SSB_SPROM4_5GL_MAXP_SHIFT);
+
+ SPEX(core_pwr_info[i].pa_5gl[0], o + SSB_SPROM4_5GL_PA_0, ~0, 0);
+ SPEX(core_pwr_info[i].pa_5gl[1], o + SSB_SPROM4_5GL_PA_1, ~0, 0);
+ SPEX(core_pwr_info[i].pa_5gl[2], o + SSB_SPROM4_5GL_PA_2, ~0, 0);
+ SPEX(core_pwr_info[i].pa_5gl[3], o + SSB_SPROM4_5GL_PA_3, ~0, 0);
+ SPEX(core_pwr_info[i].pa_5g[0], o + SSB_SPROM4_5G_PA_0, ~0, 0);
+ SPEX(core_pwr_info[i].pa_5g[1], o + SSB_SPROM4_5G_PA_1, ~0, 0);
+ SPEX(core_pwr_info[i].pa_5g[2], o + SSB_SPROM4_5G_PA_2, ~0, 0);
+ SPEX(core_pwr_info[i].pa_5g[3], o + SSB_SPROM4_5G_PA_3, ~0, 0);
+ SPEX(core_pwr_info[i].pa_5gh[0], o + SSB_SPROM4_5GH_PA_0, ~0, 0);
+ SPEX(core_pwr_info[i].pa_5gh[1], o + SSB_SPROM4_5GH_PA_1, ~0, 0);
+ SPEX(core_pwr_info[i].pa_5gh[2], o + SSB_SPROM4_5GH_PA_2, ~0, 0);
+ SPEX(core_pwr_info[i].pa_5gh[3], o + SSB_SPROM4_5GH_PA_3, ~0, 0);
+ }
sprom_extract_r458(out, in);
@@ -621,14 +676,22 @@ static void sprom_extract_r8(struct ssb_
SPEX32(ofdm5ghpo, SSB_SPROM8_OFDM5GHPO, 0xFFFFFFFF, 0);
/* Extract the antenna gain values. */
- SPEX(antenna_gain.a0, SSB_SPROM8_AGAIN01,
- SSB_SPROM8_AGAIN0, SSB_SPROM8_AGAIN0_SHIFT);
- SPEX(antenna_gain.a1, SSB_SPROM8_AGAIN01,
- SSB_SPROM8_AGAIN1, SSB_SPROM8_AGAIN1_SHIFT);
- SPEX(antenna_gain.a2, SSB_SPROM8_AGAIN23,
- SSB_SPROM8_AGAIN2, SSB_SPROM8_AGAIN2_SHIFT);
- SPEX(antenna_gain.a3, SSB_SPROM8_AGAIN23,
- SSB_SPROM8_AGAIN3, SSB_SPROM8_AGAIN3_SHIFT);
+ out->antenna_gain.a0 = sprom_extract_antgain(out->revision, in,
+ SSB_SPROM8_AGAIN01,
+ SSB_SPROM8_AGAIN0,
+ SSB_SPROM8_AGAIN0_SHIFT);
+ out->antenna_gain.a1 = sprom_extract_antgain(out->revision, in,
+ SSB_SPROM8_AGAIN01,
+ SSB_SPROM8_AGAIN1,
+ SSB_SPROM8_AGAIN1_SHIFT);
+ out->antenna_gain.a2 = sprom_extract_antgain(out->revision, in,
+ SSB_SPROM8_AGAIN23,
+ SSB_SPROM8_AGAIN2,
+ SSB_SPROM8_AGAIN2_SHIFT);
+ out->antenna_gain.a3 = sprom_extract_antgain(out->revision, in,
+ SSB_SPROM8_AGAIN23,
+ SSB_SPROM8_AGAIN3,
+ SSB_SPROM8_AGAIN3_SHIFT);
/* Extract cores power info info */
for (i = 0; i < ARRAY_SIZE(pwr_info_offset); i++) {
--- a/drivers/ssb/pcihost_wrapper.c
+++ b/drivers/ssb/pcihost_wrapper.c
@@ -11,15 +11,17 @@
* Licensed under the GNU/GPL. See COPYING for details.
*/
+#include <linux/pm.h>
#include <linux/pci.h>
#include <linux/export.h>
#include <linux/slab.h>
#include <linux/ssb/ssb.h>
-#ifdef CONFIG_PM
-static int ssb_pcihost_suspend(struct pci_dev *dev, pm_message_t state)
+#ifdef CONFIG_PM_SLEEP
+static int ssb_pcihost_suspend(struct device *d)
{
+ struct pci_dev *dev = to_pci_dev(d);
struct ssb_bus *ssb = pci_get_drvdata(dev);
int err;
@@ -28,17 +30,23 @@ static int ssb_pcihost_suspend(struct pc
return err;
pci_save_state(dev);
pci_disable_device(dev);
- pci_set_power_state(dev, pci_choose_state(dev, state));
+
+ /* if there is a wakeup enabled child device on ssb bus,
+ enable pci wakeup posibility. */
+ device_set_wakeup_enable(d, d->power.wakeup_path);
+
+ pci_prepare_to_sleep(dev);
return 0;
}
-static int ssb_pcihost_resume(struct pci_dev *dev)
+static int ssb_pcihost_resume(struct device *d)
{
+ struct pci_dev *dev = to_pci_dev(d);
struct ssb_bus *ssb = pci_get_drvdata(dev);
int err;
- pci_set_power_state(dev, PCI_D0);
+ pci_back_from_sleep(dev);
err = pci_enable_device(dev);
if (err)
return err;
@@ -49,10 +57,12 @@ static int ssb_pcihost_resume(struct pci
return 0;
}
-#else /* CONFIG_PM */
-# define ssb_pcihost_suspend NULL
-# define ssb_pcihost_resume NULL
-#endif /* CONFIG_PM */
+
+static const struct dev_pm_ops ssb_pcihost_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(ssb_pcihost_suspend, ssb_pcihost_resume)
+};
+
+#endif /* CONFIG_PM_SLEEP */
static int ssb_pcihost_probe(struct pci_dev *dev,
const struct pci_device_id *id)
@@ -115,8 +125,9 @@ int ssb_pcihost_register(struct pci_driv
{
driver->probe = ssb_pcihost_probe;
driver->remove = ssb_pcihost_remove;
- driver->suspend = ssb_pcihost_suspend;
- driver->resume = ssb_pcihost_resume;
+#ifdef CONFIG_PM_SLEEP
+ driver->driver.pm = &ssb_pcihost_pm_ops;
+#endif
return pci_register_driver(driver);
}
--- a/include/linux/ssb/ssb.h
+++ b/include/linux/ssb/ssb.h
@@ -33,6 +33,7 @@ struct ssb_sprom {
u8 et1phyaddr; /* MII address for enet1 */
u8 et0mdcport; /* MDIO for enet0 */
u8 et1mdcport; /* MDIO for enet1 */
+ u16 dev_id; /* Device ID overriding e.g. PCI ID */
u16 board_rev; /* Board revision number from SPROM. */
u16 board_num; /* Board number from SPROM. */
u16 board_type; /* Board type from SPROM. */
--- a/include/linux/ssb/ssb_regs.h
+++ b/include/linux/ssb/ssb_regs.h
@@ -345,6 +345,43 @@
#define SSB_SPROM4_TXPID5GH2_SHIFT 0
#define SSB_SPROM4_TXPID5GH3 0xFF00
#define SSB_SPROM4_TXPID5GH3_SHIFT 8
+
+/* There are 4 blocks with power info sharing the same layout */
+#define SSB_SPROM4_PWR_INFO_CORE0 0x0080
+#define SSB_SPROM4_PWR_INFO_CORE1 0x00AE
+#define SSB_SPROM4_PWR_INFO_CORE2 0x00DC
+#define SSB_SPROM4_PWR_INFO_CORE3 0x010A
+
+#define SSB_SPROM4_2G_MAXP_ITSSI 0x00 /* 2 GHz ITSSI and 2 GHz Max Power */
+#define SSB_SPROM4_2G_MAXP 0x00FF
+#define SSB_SPROM4_2G_ITSSI 0xFF00
+#define SSB_SPROM4_2G_ITSSI_SHIFT 8
+#define SSB_SPROM4_2G_PA_0 0x02 /* 2 GHz power amp */
+#define SSB_SPROM4_2G_PA_1 0x04
+#define SSB_SPROM4_2G_PA_2 0x06
+#define SSB_SPROM4_2G_PA_3 0x08
+#define SSB_SPROM4_5G_MAXP_ITSSI 0x0A /* 5 GHz ITSSI and 5.3 GHz Max Power */
+#define SSB_SPROM4_5G_MAXP 0x00FF
+#define SSB_SPROM4_5G_ITSSI 0xFF00
+#define SSB_SPROM4_5G_ITSSI_SHIFT 8
+#define SSB_SPROM4_5GHL_MAXP 0x0C /* 5.2 GHz and 5.8 GHz Max Power */
+#define SSB_SPROM4_5GH_MAXP 0x00FF
+#define SSB_SPROM4_5GL_MAXP 0xFF00
+#define SSB_SPROM4_5GL_MAXP_SHIFT 8
+#define SSB_SPROM4_5G_PA_0 0x0E /* 5.3 GHz power amp */
+#define SSB_SPROM4_5G_PA_1 0x10
+#define SSB_SPROM4_5G_PA_2 0x12
+#define SSB_SPROM4_5G_PA_3 0x14
+#define SSB_SPROM4_5GL_PA_0 0x16 /* 5.2 GHz power amp */
+#define SSB_SPROM4_5GL_PA_1 0x18
+#define SSB_SPROM4_5GL_PA_2 0x1A
+#define SSB_SPROM4_5GL_PA_3 0x1C
+#define SSB_SPROM4_5GH_PA_0 0x1E /* 5.8 GHz power amp */
+#define SSB_SPROM4_5GH_PA_1 0x20
+#define SSB_SPROM4_5GH_PA_2 0x22
+#define SSB_SPROM4_5GH_PA_3 0x24
+
+/* TODO: Make it deprecated */
#define SSB_SPROM4_MAXP_BG 0x0080 /* Max Power BG in path 1 */
#define SSB_SPROM4_MAXP_BG_MASK 0x00FF /* Mask for Max Power BG */
#define SSB_SPROM4_ITSSI_BG 0xFF00 /* Mask for path 1 itssi_bg */
--- a/arch/mips/bcm47xx/sprom.c
+++ b/arch/mips/bcm47xx/sprom.c
@@ -168,6 +168,7 @@ static void nvram_read_alpha2(const char
static void bcm47xx_fill_sprom_r1234589(struct ssb_sprom *sprom,
const char *prefix, bool fallback)
{
+ nvram_read_u16(prefix, NULL, "devid", &sprom->dev_id, 0, fallback);
nvram_read_u8(prefix, NULL, "ledbh0", &sprom->gpio0, 0xff, fallback);
nvram_read_u8(prefix, NULL, "ledbh1", &sprom->gpio1, 0xff, fallback);
nvram_read_u8(prefix, NULL, "ledbh2", &sprom->gpio2, 0xff, fallback);

File diff suppressed because it is too large Load diff

View file

@ -1,527 +0,0 @@
--- a/drivers/bcma/bcma_private.h
+++ b/drivers/bcma/bcma_private.h
@@ -25,22 +25,18 @@ struct bcma_bus;
bool bcma_wait_value(struct bcma_device *core, u16 reg, u32 mask, u32 value,
int timeout);
void bcma_prepare_core(struct bcma_bus *bus, struct bcma_device *core);
+void bcma_init_bus(struct bcma_bus *bus);
int bcma_bus_register(struct bcma_bus *bus);
void bcma_bus_unregister(struct bcma_bus *bus);
-int __init bcma_bus_early_register(struct bcma_bus *bus,
- struct bcma_device *core_cc,
- struct bcma_device *core_mips);
+int __init bcma_bus_early_register(struct bcma_bus *bus);
#ifdef CONFIG_PM
int bcma_bus_suspend(struct bcma_bus *bus);
int bcma_bus_resume(struct bcma_bus *bus);
#endif
/* scan.c */
+void bcma_detect_chip(struct bcma_bus *bus);
int bcma_bus_scan(struct bcma_bus *bus);
-int __init bcma_bus_scan_early(struct bcma_bus *bus,
- struct bcma_device_id *match,
- struct bcma_device *core);
-void bcma_init_bus(struct bcma_bus *bus);
/* sprom.c */
int bcma_sprom_get(struct bcma_bus *bus);
@@ -111,6 +107,14 @@ extern int bcma_chipco_watchdog_register
#ifdef CONFIG_BCMA_DRIVER_PCI_HOSTMODE
bool bcma_core_pci_is_in_hostmode(struct bcma_drv_pci *pc);
void bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc);
+#else
+static inline bool bcma_core_pci_is_in_hostmode(struct bcma_drv_pci *pc)
+{
+ return false;
+}
+static inline void bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc)
+{
+}
#endif /* CONFIG_BCMA_DRIVER_PCI_HOSTMODE */
#ifdef CONFIG_BCMA_DRIVER_GPIO
--- a/drivers/bcma/driver_chipcommon.c
+++ b/drivers/bcma/driver_chipcommon.c
@@ -79,7 +79,9 @@ static int bcma_chipco_watchdog_ticks_pe
if (cc->capabilities & BCMA_CC_CAP_PMU) {
if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4706)
- /* 4706 CC and PMU watchdogs are clocked at 1/4 of ALP clock */
+ /* 4706 CC and PMU watchdogs are clocked at 1/4 of ALP
+ * clock
+ */
return bcma_chipco_get_alp_clock(cc) / 4000;
else
/* based on 32KHz ILP clock */
@@ -97,7 +99,8 @@ int bcma_chipco_watchdog_register(struct
wdt.driver_data = cc;
wdt.timer_set = bcma_chipco_watchdog_timer_set_wdt;
wdt.timer_set_ms = bcma_chipco_watchdog_timer_set_ms_wdt;
- wdt.max_timer_ms = bcma_chipco_watchdog_get_max_timer(cc) / cc->ticks_per_ms;
+ wdt.max_timer_ms =
+ bcma_chipco_watchdog_get_max_timer(cc) / cc->ticks_per_ms;
pdev = platform_device_register_data(NULL, "bcm47xx-wdt",
cc->core->bus->num, &wdt,
@@ -175,7 +178,6 @@ void bcma_core_chipcommon_init(struct bc
u32 bcma_chipco_watchdog_timer_set(struct bcma_drv_cc *cc, u32 ticks)
{
u32 maxt;
- enum bcma_clkmode clkmode;
maxt = bcma_chipco_watchdog_get_max_timer(cc);
if (cc->capabilities & BCMA_CC_CAP_PMU) {
@@ -185,8 +187,13 @@ u32 bcma_chipco_watchdog_timer_set(struc
ticks = maxt;
bcma_cc_write32(cc, BCMA_CC_PMU_WATCHDOG, ticks);
} else {
- clkmode = ticks ? BCMA_CLKMODE_FAST : BCMA_CLKMODE_DYNAMIC;
- bcma_core_set_clockmode(cc->core, clkmode);
+ struct bcma_bus *bus = cc->core->bus;
+
+ if (bus->chipinfo.id != BCMA_CHIP_ID_BCM4707 &&
+ bus->chipinfo.id != BCMA_CHIP_ID_BCM53018)
+ bcma_core_set_clockmode(cc->core,
+ ticks ? BCMA_CLKMODE_FAST : BCMA_CLKMODE_DYNAMIC);
+
if (ticks > maxt)
ticks = maxt;
/* instant NMI */
@@ -335,7 +342,8 @@ void bcma_chipco_serial_init(struct bcma
| BCMA_CC_CORECTL_UARTCLKEN);
}
} else {
- bcma_err(cc->core->bus, "serial not supported on this device ccrev: 0x%x\n", ccrev);
+ bcma_err(cc->core->bus, "serial not supported on this device ccrev: 0x%x\n",
+ ccrev);
return;
}
--- a/drivers/bcma/driver_pci.c
+++ b/drivers/bcma/driver_pci.c
@@ -145,6 +145,47 @@ static u16 bcma_pcie_mdio_writeread(stru
}
/**************************************************
+ * Early init.
+ **************************************************/
+
+static void bcma_core_pci_fixcfg(struct bcma_drv_pci *pc)
+{
+ struct bcma_device *core = pc->core;
+ u16 val16, core_index;
+ uint regoff;
+
+ regoff = BCMA_CORE_PCI_SPROM(BCMA_CORE_PCI_SPROM_PI_OFFSET);
+ core_index = (u16)core->core_index;
+
+ val16 = pcicore_read16(pc, regoff);
+ if (((val16 & BCMA_CORE_PCI_SPROM_PI_MASK) >> BCMA_CORE_PCI_SPROM_PI_SHIFT)
+ != core_index) {
+ val16 = (core_index << BCMA_CORE_PCI_SPROM_PI_SHIFT) |
+ (val16 & ~BCMA_CORE_PCI_SPROM_PI_MASK);
+ pcicore_write16(pc, regoff, val16);
+ }
+}
+
+/*
+ * Apply some early fixes required before accessing SPROM.
+ * See also si_pci_fixcfg.
+ */
+void bcma_core_pci_early_init(struct bcma_drv_pci *pc)
+{
+ if (pc->early_setup_done)
+ return;
+
+ pc->hostmode = bcma_core_pci_is_in_hostmode(pc);
+ if (pc->hostmode)
+ goto out;
+
+ bcma_core_pci_fixcfg(pc);
+
+out:
+ pc->early_setup_done = true;
+}
+
+/**************************************************
* Workarounds.
**************************************************/
@@ -175,24 +216,6 @@ static void bcma_pcicore_serdes_workarou
tmp & ~BCMA_CORE_PCI_PLL_CTRL_FREQDET_EN);
}
-static void bcma_core_pci_fixcfg(struct bcma_drv_pci *pc)
-{
- struct bcma_device *core = pc->core;
- u16 val16, core_index;
- uint regoff;
-
- regoff = BCMA_CORE_PCI_SPROM(BCMA_CORE_PCI_SPROM_PI_OFFSET);
- core_index = (u16)core->core_index;
-
- val16 = pcicore_read16(pc, regoff);
- if (((val16 & BCMA_CORE_PCI_SPROM_PI_MASK) >> BCMA_CORE_PCI_SPROM_PI_SHIFT)
- != core_index) {
- val16 = (core_index << BCMA_CORE_PCI_SPROM_PI_SHIFT) |
- (val16 & ~BCMA_CORE_PCI_SPROM_PI_MASK);
- pcicore_write16(pc, regoff, val16);
- }
-}
-
/* Fix MISC config to allow coming out of L2/L3-Ready state w/o PRST */
/* Needs to happen when coming out of 'standby'/'hibernate' */
static void bcma_core_pci_config_fixup(struct bcma_drv_pci *pc)
@@ -216,7 +239,6 @@ static void bcma_core_pci_config_fixup(s
static void bcma_core_pci_clientmode_init(struct bcma_drv_pci *pc)
{
- bcma_core_pci_fixcfg(pc);
bcma_pcicore_serdes_workaround(pc);
bcma_core_pci_config_fixup(pc);
}
@@ -226,13 +248,11 @@ void bcma_core_pci_init(struct bcma_drv_
if (pc->setup_done)
return;
-#ifdef CONFIG_BCMA_DRIVER_PCI_HOSTMODE
- pc->hostmode = bcma_core_pci_is_in_hostmode(pc);
+ bcma_core_pci_early_init(pc);
+
if (pc->hostmode)
bcma_core_pci_hostmode_init(pc);
-#endif /* CONFIG_BCMA_DRIVER_PCI_HOSTMODE */
-
- if (!pc->hostmode)
+ else
bcma_core_pci_clientmode_init(pc);
}
--- a/drivers/bcma/host_pci.c
+++ b/drivers/bcma/host_pci.c
@@ -13,10 +13,12 @@
static void bcma_host_pci_switch_core(struct bcma_device *core)
{
+ int win2 = core->bus->host_is_pcie2 ?
+ BCMA_PCIE2_BAR0_WIN2 : BCMA_PCI_BAR0_WIN2;
+
pci_write_config_dword(core->bus->host_pci, BCMA_PCI_BAR0_WIN,
core->addr);
- pci_write_config_dword(core->bus->host_pci, BCMA_PCI_BAR0_WIN2,
- core->wrap);
+ pci_write_config_dword(core->bus->host_pci, win2, core->wrap);
core->bus->mapped_core = core;
bcma_debug(core->bus, "Switched to core: 0x%X\n", core->id.id);
}
--- a/drivers/bcma/host_soc.c
+++ b/drivers/bcma/host_soc.c
@@ -193,7 +193,7 @@ int __init bcma_host_soc_init(struct bcm
int err;
/* Scan bus and initialize it */
- err = bcma_bus_early_register(bus, &soc->core_cc, &soc->core_mips);
+ err = bcma_bus_early_register(bus);
if (err)
iounmap(bus->mmio);
--- a/drivers/bcma/main.c
+++ b/drivers/bcma/main.c
@@ -268,6 +268,18 @@ void bcma_prepare_core(struct bcma_bus *
}
}
+void bcma_init_bus(struct bcma_bus *bus)
+{
+ mutex_lock(&bcma_buses_mutex);
+ bus->num = bcma_bus_next_num++;
+ mutex_unlock(&bcma_buses_mutex);
+
+ INIT_LIST_HEAD(&bus->cores);
+ bus->nr_cores = 0;
+
+ bcma_detect_chip(bus);
+}
+
static void bcma_register_core(struct bcma_bus *bus, struct bcma_device *core)
{
int err;
@@ -356,12 +368,19 @@ static void bcma_unregister_cores(struct
struct bcma_device *core, *tmp;
list_for_each_entry_safe(core, tmp, &bus->cores, list) {
+ if (!core->dev_registered)
+ continue;
list_del(&core->list);
- if (core->dev_registered)
- device_unregister(&core->dev);
+ device_unregister(&core->dev);
}
if (bus->hosttype == BCMA_HOSTTYPE_SOC)
platform_device_unregister(bus->drv_cc.watchdog);
+
+ /* Now noone uses internally-handled cores, we can free them */
+ list_for_each_entry_safe(core, tmp, &bus->cores, list) {
+ list_del(&core->list);
+ kfree(core);
+ }
}
int bcma_bus_register(struct bcma_bus *bus)
@@ -369,10 +388,6 @@ int bcma_bus_register(struct bcma_bus *b
int err;
struct bcma_device *core;
- mutex_lock(&bcma_buses_mutex);
- bus->num = bcma_bus_next_num++;
- mutex_unlock(&bcma_buses_mutex);
-
/* Scan for devices (cores) */
err = bcma_bus_scan(bus);
if (err) {
@@ -387,6 +402,13 @@ int bcma_bus_register(struct bcma_bus *b
bcma_core_chipcommon_early_init(&bus->drv_cc);
}
+ /* Early init PCIE core */
+ core = bcma_find_core(bus, BCMA_CORE_PCIE);
+ if (core) {
+ bus->drv_pci[0].core = core;
+ bcma_core_pci_early_init(&bus->drv_pci[0]);
+ }
+
/* Cores providing flash access go before SPROM init */
list_for_each_entry(core, &bus->cores, list) {
if (bcma_is_core_needed_early(core->id.id))
@@ -459,7 +481,6 @@ int bcma_bus_register(struct bcma_bus *b
void bcma_bus_unregister(struct bcma_bus *bus)
{
- struct bcma_device *cores[3];
int err;
err = bcma_gpio_unregister(&bus->drv_cc);
@@ -470,46 +491,23 @@ void bcma_bus_unregister(struct bcma_bus
bcma_core_chipcommon_b_free(&bus->drv_cc_b);
- cores[0] = bcma_find_core(bus, BCMA_CORE_MIPS_74K);
- cores[1] = bcma_find_core(bus, BCMA_CORE_PCIE);
- cores[2] = bcma_find_core(bus, BCMA_CORE_4706_MAC_GBIT_COMMON);
-
bcma_unregister_cores(bus);
-
- kfree(cores[2]);
- kfree(cores[1]);
- kfree(cores[0]);
}
-int __init bcma_bus_early_register(struct bcma_bus *bus,
- struct bcma_device *core_cc,
- struct bcma_device *core_mips)
+/*
+ * This is a special version of bus registration function designed for SoCs.
+ * It scans bus and performs basic initialization of main cores only.
+ * Please note it requires memory allocation, however it won't try to sleep.
+ */
+int __init bcma_bus_early_register(struct bcma_bus *bus)
{
int err;
struct bcma_device *core;
- struct bcma_device_id match;
-
- match.manuf = BCMA_MANUF_BCM;
- match.id = bcma_cc_core_id(bus);
- match.class = BCMA_CL_SIM;
- match.rev = BCMA_ANY_REV;
- /* Scan for chip common core */
- err = bcma_bus_scan_early(bus, &match, core_cc);
- if (err) {
- bcma_err(bus, "Failed to scan for common core: %d\n", err);
- return -1;
- }
-
- match.manuf = BCMA_MANUF_MIPS;
- match.id = BCMA_CORE_MIPS_74K;
- match.class = BCMA_CL_SIM;
- match.rev = BCMA_ANY_REV;
-
- /* Scan for mips core */
- err = bcma_bus_scan_early(bus, &match, core_mips);
+ /* Scan for devices (cores) */
+ err = bcma_bus_scan(bus);
if (err) {
- bcma_err(bus, "Failed to scan for mips core: %d\n", err);
+ bcma_err(bus, "Failed to scan bus: %d\n", err);
return -1;
}
--- a/drivers/bcma/scan.c
+++ b/drivers/bcma/scan.c
@@ -435,15 +435,12 @@ static int bcma_get_next_core(struct bcm
return 0;
}
-void bcma_init_bus(struct bcma_bus *bus)
+void bcma_detect_chip(struct bcma_bus *bus)
{
s32 tmp;
struct bcma_chipinfo *chipinfo = &(bus->chipinfo);
char chip_id[8];
- INIT_LIST_HEAD(&bus->cores);
- bus->nr_cores = 0;
-
bcma_scan_switch_core(bus, BCMA_ADDR_BASE);
tmp = bcma_scan_read32(bus, 0, BCMA_CC_ID);
@@ -464,6 +461,10 @@ int bcma_bus_scan(struct bcma_bus *bus)
int err, core_num = 0;
+ /* Skip if bus was already scanned (e.g. during early register) */
+ if (bus->nr_cores)
+ return 0;
+
erombase = bcma_scan_read32(bus, 0, BCMA_CC_EROM);
if (bus->hosttype == BCMA_HOSTTYPE_SOC) {
eromptr = ioremap_nocache(erombase, BCMA_CORE_SIZE);
@@ -519,64 +520,6 @@ int bcma_bus_scan(struct bcma_bus *bus)
out:
if (bus->hosttype == BCMA_HOSTTYPE_SOC)
iounmap(eromptr);
-
- return err;
-}
-
-int __init bcma_bus_scan_early(struct bcma_bus *bus,
- struct bcma_device_id *match,
- struct bcma_device *core)
-{
- u32 erombase;
- u32 __iomem *eromptr, *eromend;
-
- int err = -ENODEV;
- int core_num = 0;
-
- erombase = bcma_scan_read32(bus, 0, BCMA_CC_EROM);
- if (bus->hosttype == BCMA_HOSTTYPE_SOC) {
- eromptr = ioremap_nocache(erombase, BCMA_CORE_SIZE);
- if (!eromptr)
- return -ENOMEM;
- } else {
- eromptr = bus->mmio;
- }
-
- eromend = eromptr + BCMA_CORE_SIZE / sizeof(u32);
-
- bcma_scan_switch_core(bus, erombase);
-
- while (eromptr < eromend) {
- memset(core, 0, sizeof(*core));
- INIT_LIST_HEAD(&core->list);
- core->bus = bus;
-
- err = bcma_get_next_core(bus, &eromptr, match, core_num, core);
- if (err == -ENODEV) {
- core_num++;
- continue;
- } else if (err == -ENXIO)
- continue;
- else if (err == -ESPIPE)
- break;
- else if (err < 0)
- goto out;
-
- core->core_index = core_num++;
- bus->nr_cores++;
- bcma_info(bus, "Core %d found: %s (manuf 0x%03X, id 0x%03X, rev 0x%02X, class 0x%X)\n",
- core->core_index, bcma_device_name(&core->id),
- core->id.manuf, core->id.id, core->id.rev,
- core->id.class);
-
- list_add_tail(&core->list, &bus->cores);
- err = 0;
- break;
- }
-
-out:
- if (bus->hosttype == BCMA_HOSTTYPE_SOC)
- iounmap(eromptr);
return err;
}
--- a/drivers/bcma/sprom.c
+++ b/drivers/bcma/sprom.c
@@ -579,7 +579,8 @@ int bcma_sprom_get(struct bcma_bus *bus)
u16 offset = BCMA_CC_SPROM;
u16 *sprom;
size_t sprom_sizes[] = { SSB_SPROMSIZE_WORDS_R4,
- SSB_SPROMSIZE_WORDS_R10, };
+ SSB_SPROMSIZE_WORDS_R10,
+ SSB_SPROMSIZE_WORDS_R11, };
int i, err = 0;
if (!bus->drv_cc.core)
--- a/include/linux/bcma/bcma.h
+++ b/include/linux/bcma/bcma.h
@@ -318,6 +318,7 @@ struct bcma_bus {
const struct bcma_host_ops *ops;
enum bcma_hosttype hosttype;
+ bool host_is_pcie2; /* Used for BCMA_HOSTTYPE_PCI only */
union {
/* Pointer to the PCI bus (only for BCMA_HOSTTYPE_PCI) */
struct pci_dev *host_pci;
--- a/include/linux/bcma/bcma_driver_pci.h
+++ b/include/linux/bcma/bcma_driver_pci.h
@@ -223,6 +223,7 @@ struct bcma_drv_pci_host {
struct bcma_drv_pci {
struct bcma_device *core;
+ u8 early_setup_done:1;
u8 setup_done:1;
u8 hostmode:1;
@@ -237,6 +238,7 @@ struct bcma_drv_pci {
#define pcicore_write16(pc, offset, val) bcma_write16((pc)->core, offset, val)
#define pcicore_write32(pc, offset, val) bcma_write32((pc)->core, offset, val)
+extern void bcma_core_pci_early_init(struct bcma_drv_pci *pc);
extern void bcma_core_pci_init(struct bcma_drv_pci *pc);
extern int bcma_core_pci_irq_ctl(struct bcma_drv_pci *pc,
struct bcma_device *core, bool enable);
--- a/include/linux/bcma/bcma_regs.h
+++ b/include/linux/bcma/bcma_regs.h
@@ -64,6 +64,8 @@
#define BCMA_PCI_GPIO_XTAL 0x40 /* PCI config space GPIO 14 for Xtal powerup */
#define BCMA_PCI_GPIO_PLL 0x80 /* PCI config space GPIO 15 for PLL powerdown */
+#define BCMA_PCIE2_BAR0_WIN2 0x70
+
/* SiliconBackplane Address Map.
* All regions may not exist on all chips.
*/
--- a/include/linux/bcma/bcma_soc.h
+++ b/include/linux/bcma/bcma_soc.h
@@ -5,8 +5,6 @@
struct bcma_soc {
struct bcma_bus bus;
- struct bcma_device core_cc;
- struct bcma_device core_mips;
};
int __init bcma_host_soc_register(struct bcma_soc *soc);
--- a/include/linux/ssb/ssb_regs.h
+++ b/include/linux/ssb/ssb_regs.h
@@ -173,6 +173,7 @@
#define SSB_SPROMSIZE_BYTES_R123 (SSB_SPROMSIZE_WORDS_R123 * sizeof(u16))
#define SSB_SPROMSIZE_BYTES_R4 (SSB_SPROMSIZE_WORDS_R4 * sizeof(u16))
#define SSB_SPROMSIZE_WORDS_R10 230
+#define SSB_SPROMSIZE_WORDS_R11 234
#define SSB_SPROM_BASE1 0x1000
#define SSB_SPROM_BASE31 0x0800
#define SSB_SPROM_REVISION 0x007E

View file

@ -1,355 +0,0 @@
--- a/drivers/bcma/bcma_private.h
+++ b/drivers/bcma/bcma_private.h
@@ -26,6 +26,7 @@ bool bcma_wait_value(struct bcma_device
int timeout);
void bcma_prepare_core(struct bcma_bus *bus, struct bcma_device *core);
void bcma_init_bus(struct bcma_bus *bus);
+void bcma_unregister_cores(struct bcma_bus *bus);
int bcma_bus_register(struct bcma_bus *bus);
void bcma_bus_unregister(struct bcma_bus *bus);
int __init bcma_bus_early_register(struct bcma_bus *bus);
@@ -101,6 +102,11 @@ static inline void __exit bcma_host_soc_
/* driver_pci.c */
u32 bcma_pcie_read(struct bcma_drv_pci *pc, u32 address);
+void bcma_core_pci_up(struct bcma_drv_pci *pc);
+void bcma_core_pci_down(struct bcma_drv_pci *pc);
+
+/* driver_pcie2.c */
+void bcma_core_pcie2_up(struct bcma_drv_pcie2 *pcie2);
extern int bcma_chipco_watchdog_register(struct bcma_drv_cc *cc);
--- a/drivers/bcma/driver_gpio.c
+++ b/drivers/bcma/driver_gpio.c
@@ -76,7 +76,7 @@ static void bcma_gpio_free(struct gpio_c
bcma_chipco_gpio_pullup(cc, 1 << gpio, 0);
}
-#if IS_BUILTIN(CONFIG_BCM47XX)
+#if IS_BUILTIN(CONFIG_BCM47XX) || IS_BUILTIN(CONFIG_ARCH_BCM_5301X)
static int bcma_gpio_to_irq(struct gpio_chip *chip, unsigned gpio)
{
struct bcma_drv_cc *cc = bcma_gpio_get_cc(chip);
@@ -215,7 +215,7 @@ int bcma_gpio_init(struct bcma_drv_cc *c
chip->set = bcma_gpio_set_value;
chip->direction_input = bcma_gpio_direction_input;
chip->direction_output = bcma_gpio_direction_output;
-#if IS_BUILTIN(CONFIG_BCM47XX)
+#if IS_BUILTIN(CONFIG_BCM47XX) || IS_BUILTIN(CONFIG_ARCH_BCM_5301X)
chip->to_irq = bcma_gpio_to_irq;
#endif
#if IS_BUILTIN(CONFIG_OF)
--- a/drivers/bcma/driver_pci.c
+++ b/drivers/bcma/driver_pci.c
@@ -282,21 +282,21 @@ void bcma_core_pci_power_save(struct bcm
}
EXPORT_SYMBOL_GPL(bcma_core_pci_power_save);
-int bcma_core_pci_irq_ctl(struct bcma_drv_pci *pc, struct bcma_device *core,
+int bcma_core_pci_irq_ctl(struct bcma_bus *bus, struct bcma_device *core,
bool enable)
{
struct pci_dev *pdev;
u32 coremask, tmp;
int err = 0;
- if (!pc || core->bus->hosttype != BCMA_HOSTTYPE_PCI) {
+ if (bus->hosttype != BCMA_HOSTTYPE_PCI) {
/* This bcma device is not on a PCI host-bus. So the IRQs are
* not routed through the PCI core.
* So we must not enable routing through the PCI core. */
goto out;
}
- pdev = pc->core->bus->host_pci;
+ pdev = bus->host_pci;
err = pci_read_config_dword(pdev, BCMA_PCI_IRQMASK, &tmp);
if (err)
@@ -328,28 +328,12 @@ static void bcma_core_pci_extend_L1timer
bcma_pcie_read(pc, BCMA_CORE_PCI_DLLP_PMTHRESHREG);
}
-void bcma_core_pci_up(struct bcma_bus *bus)
+void bcma_core_pci_up(struct bcma_drv_pci *pc)
{
- struct bcma_drv_pci *pc;
-
- if (bus->hosttype != BCMA_HOSTTYPE_PCI)
- return;
-
- pc = &bus->drv_pci[0];
-
bcma_core_pci_extend_L1timer(pc, true);
}
-EXPORT_SYMBOL_GPL(bcma_core_pci_up);
-void bcma_core_pci_down(struct bcma_bus *bus)
+void bcma_core_pci_down(struct bcma_drv_pci *pc)
{
- struct bcma_drv_pci *pc;
-
- if (bus->hosttype != BCMA_HOSTTYPE_PCI)
- return;
-
- pc = &bus->drv_pci[0];
-
bcma_core_pci_extend_L1timer(pc, false);
}
-EXPORT_SYMBOL_GPL(bcma_core_pci_down);
--- a/drivers/bcma/driver_pci_host.c
+++ b/drivers/bcma/driver_pci_host.c
@@ -11,6 +11,7 @@
#include "bcma_private.h"
#include <linux/pci.h>
+#include <linux/slab.h>
#include <linux/export.h>
#include <linux/bcma/bcma.h>
#include <asm/paccess.h>
--- a/drivers/bcma/driver_pcie2.c
+++ b/drivers/bcma/driver_pcie2.c
@@ -10,6 +10,7 @@
#include "bcma_private.h"
#include <linux/bcma/bcma.h>
+#include <linux/pci.h>
/**************************************************
* R/W ops.
@@ -156,14 +157,23 @@ static void pciedev_reg_pm_clk_period(st
void bcma_core_pcie2_init(struct bcma_drv_pcie2 *pcie2)
{
- struct bcma_chipinfo *ci = &pcie2->core->bus->chipinfo;
+ struct bcma_bus *bus = pcie2->core->bus;
+ struct bcma_chipinfo *ci = &bus->chipinfo;
u32 tmp;
tmp = pcie2_read32(pcie2, BCMA_CORE_PCIE2_SPROM(54));
if ((tmp & 0xe) >> 1 == 2)
bcma_core_pcie2_cfg_write(pcie2, 0x4e0, 0x17);
- /* TODO: Do we need pcie_reqsize? */
+ switch (bus->chipinfo.id) {
+ case BCMA_CHIP_ID_BCM4360:
+ case BCMA_CHIP_ID_BCM4352:
+ pcie2->reqsize = 1024;
+ break;
+ default:
+ pcie2->reqsize = 128;
+ break;
+ }
if (ci->id == BCMA_CHIP_ID_BCM4360 && ci->rev > 3)
bcma_core_pcie2_war_delay_perst_enab(pcie2, true);
@@ -173,3 +183,18 @@ void bcma_core_pcie2_init(struct bcma_dr
pciedev_crwlpciegen2_180(pcie2);
pciedev_crwlpciegen2_182(pcie2);
}
+
+/**************************************************
+ * Runtime ops.
+ **************************************************/
+
+void bcma_core_pcie2_up(struct bcma_drv_pcie2 *pcie2)
+{
+ struct bcma_bus *bus = pcie2->core->bus;
+ struct pci_dev *dev = bus->host_pci;
+ int err;
+
+ err = pcie_set_readrq(dev, pcie2->reqsize);
+ if (err)
+ bcma_err(bus, "Error setting PCI_EXP_DEVCTL_READRQ: %d\n", err);
+}
--- a/drivers/bcma/host_pci.c
+++ b/drivers/bcma/host_pci.c
@@ -213,16 +213,26 @@ static int bcma_host_pci_probe(struct pc
/* Initialize struct, detect chip */
bcma_init_bus(bus);
+ /* Scan bus to find out generation of PCIe core */
+ err = bcma_bus_scan(bus);
+ if (err)
+ goto err_pci_unmap_mmio;
+
+ if (bcma_find_core(bus, BCMA_CORE_PCIE2))
+ bus->host_is_pcie2 = true;
+
/* Register */
err = bcma_bus_register(bus);
if (err)
- goto err_pci_unmap_mmio;
+ goto err_unregister_cores;
pci_set_drvdata(dev, bus);
out:
return err;
+err_unregister_cores:
+ bcma_unregister_cores(bus);
err_pci_unmap_mmio:
pci_iounmap(dev, bus->mmio);
err_pci_release_regions:
@@ -283,9 +293,12 @@ static const struct pci_device_id bcma_p
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4357) },
{ 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(PCI_VENDOR_ID_BROADCOM, 0x43a0) },
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x43a9) },
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x43aa) },
+ { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x43b1) },
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4727) },
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 43227) }, /* 0xa8db, BCM43217 (sic!) */
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 43228) }, /* 0xa8dc */
@@ -310,3 +323,31 @@ void __exit bcma_host_pci_exit(void)
{
pci_unregister_driver(&bcma_pci_bridge_driver);
}
+
+/**************************************************
+ * Runtime ops for drivers.
+ **************************************************/
+
+/* See also pcicore_up */
+void bcma_host_pci_up(struct bcma_bus *bus)
+{
+ if (bus->hosttype != BCMA_HOSTTYPE_PCI)
+ return;
+
+ if (bus->host_is_pcie2)
+ bcma_core_pcie2_up(&bus->drv_pcie2);
+ else
+ bcma_core_pci_up(&bus->drv_pci[0]);
+}
+EXPORT_SYMBOL_GPL(bcma_host_pci_up);
+
+/* See also pcicore_down */
+void bcma_host_pci_down(struct bcma_bus *bus)
+{
+ if (bus->hosttype != BCMA_HOSTTYPE_PCI)
+ return;
+
+ if (!bus->host_is_pcie2)
+ bcma_core_pci_down(&bus->drv_pci[0]);
+}
+EXPORT_SYMBOL_GPL(bcma_host_pci_down);
--- a/drivers/bcma/main.c
+++ b/drivers/bcma/main.c
@@ -363,7 +363,7 @@ static int bcma_register_devices(struct
return 0;
}
-static void bcma_unregister_cores(struct bcma_bus *bus)
+void bcma_unregister_cores(struct bcma_bus *bus)
{
struct bcma_device *core, *tmp;
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
@@ -4650,7 +4650,7 @@ static void b43_wireless_core_exit(struc
switch (dev->dev->bus_type) {
#ifdef CONFIG_B43_BCMA
case B43_BUS_BCMA:
- bcma_core_pci_down(dev->dev->bdev->bus);
+ bcma_host_pci_down(dev->dev->bdev->bus);
break;
#endif
#ifdef CONFIG_B43_SSB
@@ -4697,9 +4697,9 @@ static int b43_wireless_core_init(struct
switch (dev->dev->bus_type) {
#ifdef CONFIG_B43_BCMA
case B43_BUS_BCMA:
- bcma_core_pci_irq_ctl(&dev->dev->bdev->bus->drv_pci[0],
+ bcma_core_pci_irq_ctl(dev->dev->bdev->bus,
dev->dev->bdev, true);
- bcma_core_pci_up(dev->dev->bdev->bus);
+ bcma_host_pci_up(dev->dev->bdev->bus);
break;
#endif
#ifdef CONFIG_B43_SSB
--- a/drivers/net/wireless/brcm80211/brcmsmac/main.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/main.c
@@ -4669,7 +4669,7 @@ static int brcms_b_attach(struct brcms_c
brcms_c_coredisable(wlc_hw);
/* Match driver "down" state */
- bcma_core_pci_down(wlc_hw->d11core->bus);
+ bcma_host_pci_down(wlc_hw->d11core->bus);
/* turn off pll and xtal to match driver "down" state */
brcms_b_xtal(wlc_hw, OFF);
@@ -5002,7 +5002,7 @@ static int brcms_b_up_prep(struct brcms_
* Configure pci/pcmcia here instead of in brcms_c_attach()
* to allow mfg hotswap: down, hotswap (chip power cycle), up.
*/
- bcma_core_pci_irq_ctl(&wlc_hw->d11core->bus->drv_pci[0], wlc_hw->d11core,
+ bcma_core_pci_irq_ctl(wlc_hw->d11core->bus, wlc_hw->d11core,
true);
/*
@@ -5012,12 +5012,12 @@ static int brcms_b_up_prep(struct brcms_
*/
if (brcms_b_radio_read_hwdisabled(wlc_hw)) {
/* put SB PCI in down state again */
- bcma_core_pci_down(wlc_hw->d11core->bus);
+ bcma_host_pci_down(wlc_hw->d11core->bus);
brcms_b_xtal(wlc_hw, OFF);
return -ENOMEDIUM;
}
- bcma_core_pci_up(wlc_hw->d11core->bus);
+ bcma_host_pci_up(wlc_hw->d11core->bus);
/* reset the d11 core */
brcms_b_corereset(wlc_hw, BRCMS_USE_COREFLAGS);
@@ -5214,7 +5214,7 @@ static int brcms_b_down_finish(struct br
/* turn off primary xtal and pll */
if (!wlc_hw->noreset) {
- bcma_core_pci_down(wlc_hw->d11core->bus);
+ bcma_host_pci_down(wlc_hw->d11core->bus);
brcms_b_xtal(wlc_hw, OFF);
}
}
--- a/include/linux/bcma/bcma.h
+++ b/include/linux/bcma/bcma.h
@@ -434,6 +434,9 @@ static inline struct bcma_device *bcma_f
return bcma_find_core_unit(bus, coreid, 0);
}
+extern void bcma_host_pci_up(struct bcma_bus *bus);
+extern void bcma_host_pci_down(struct bcma_bus *bus);
+
extern bool bcma_core_is_enabled(struct bcma_device *core);
extern void bcma_core_disable(struct bcma_device *core, u32 flags);
extern int bcma_core_enable(struct bcma_device *core, u32 flags);
--- a/include/linux/bcma/bcma_driver_pci.h
+++ b/include/linux/bcma/bcma_driver_pci.h
@@ -240,10 +240,8 @@ struct bcma_drv_pci {
extern void bcma_core_pci_early_init(struct bcma_drv_pci *pc);
extern void bcma_core_pci_init(struct bcma_drv_pci *pc);
-extern int bcma_core_pci_irq_ctl(struct bcma_drv_pci *pc,
+extern int bcma_core_pci_irq_ctl(struct bcma_bus *bus,
struct bcma_device *core, bool enable);
-extern void bcma_core_pci_up(struct bcma_bus *bus);
-extern void bcma_core_pci_down(struct bcma_bus *bus);
extern void bcma_core_pci_power_save(struct bcma_bus *bus, bool up);
extern int bcma_core_pci_pcibios_map_irq(const struct pci_dev *dev);
--- a/include/linux/bcma/bcma_driver_pcie2.h
+++ b/include/linux/bcma/bcma_driver_pcie2.h
@@ -143,6 +143,8 @@
struct bcma_drv_pcie2 {
struct bcma_device *core;
+
+ u16 reqsize;
};
#define pcie2_read16(pcie2, offset) bcma_read16((pcie2)->core, offset)

View file

@ -1,21 +0,0 @@
From: Vadim Kochan <vadim4j@gmail.com>
Date: Mon, 12 Jan 2015 16:34:05 +0200
Subject: [PATCH] nl80211: Allow set network namespace by fd
Added new NL80211_ATTR_NETNS_FD which allows to
set namespace via nl80211 by fd.
Signed-off-by: Vadim Kochan <vadim4j@gmail.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
--- a/net/core/net_namespace.c
+++ b/net/core/net_namespace.c
@@ -361,6 +361,7 @@ struct net *get_net_ns_by_fd(int fd)
return ERR_PTR(-EINVAL);
}
#endif
+EXPORT_SYMBOL_GPL(get_net_ns_by_fd);
struct net *get_net_ns_by_pid(pid_t pid)
{

View file

@ -1,829 +0,0 @@
From 9d54c8a33eec78289b1b3f6e10874719c27ce0a7 Mon Sep 17 00:00:00 2001
From: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
Date: Tue, 25 Feb 2014 13:25:22 -0300
Subject: [PATCH] UBI: R/O block driver on top of UBI volumes
This commit introduces read-only block device emulation on top of UBI volumes.
Given UBI takes care of wear leveling and bad block management it's possible
to add a thin layer to enable block device access to UBI volumes.
This allows to use a block-oriented filesystem on a flash device.
The UBI block devices are meant to be used in conjunction with any
regular, block-oriented file system (e.g. ext4), although it's primarily
targeted at read-only file systems, such as squashfs.
Block devices are created upon user request through new ioctls:
UBI_IOCVOLATTBLK to attach and UBI_IOCVOLDETBLK to detach.
Also, a new UBI module parameter is added 'ubi.block'. This parameter is
needed in order to attach a block device on boot-up time, allowing to
mount the rootfs on a ubiblock device.
For instance, you could have these kernel parameters:
ubi.mtd=5 ubi.block=0,0 root=/dev/ubiblock0_0
Or, if you compile ubi as a module:
$ modprobe ubi mtd=/dev/mtd5 block=/dev/ubi0_0
Artem: amend commentaries and massage the patch a little bit.
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
Signed-off-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
---
drivers/mtd/ubi/Kconfig | 15 +
drivers/mtd/ubi/Makefile | 1 +
drivers/mtd/ubi/block.c | 646 ++++++++++++++++++++++++++++++++++++++++++++
drivers/mtd/ubi/build.c | 11 +
drivers/mtd/ubi/cdev.c | 20 ++
drivers/mtd/ubi/ubi.h | 14 +
include/uapi/mtd/ubi-user.h | 11 +
7 files changed, 718 insertions(+)
create mode 100644 drivers/mtd/ubi/block.c
--- a/drivers/mtd/ubi/Kconfig
+++ b/drivers/mtd/ubi/Kconfig
@@ -87,4 +87,19 @@ config MTD_UBI_GLUEBI
work on top of UBI. Do not enable this unless you use legacy
software.
+config MTD_UBI_BLOCK
+ bool "Read-only block devices on top of UBI volumes"
+ default n
+ help
+ This option enables read-only UBI block devices support. UBI block
+ devices will be layered on top of UBI volumes, which means that the
+ UBI driver will transparently handle things like bad eraseblocks and
+ bit-flips. You can put any block-oriented file system on top of UBI
+ volumes in read-only mode (e.g., ext4), but it is probably most
+ practical for read-only file systems, like squashfs.
+
+ When selected, this feature will be built in the UBI driver.
+
+ If in doubt, say "N".
+
endif # MTD_UBI
--- a/drivers/mtd/ubi/Makefile
+++ b/drivers/mtd/ubi/Makefile
@@ -3,5 +3,6 @@ obj-$(CONFIG_MTD_UBI) += ubi.o
ubi-y += vtbl.o vmt.o upd.o build.o cdev.o kapi.o eba.o io.o wl.o attach.o
ubi-y += misc.o debug.o
ubi-$(CONFIG_MTD_UBI_FASTMAP) += fastmap.o
+ubi-$(CONFIG_MTD_UBI_BLOCK) += block.o
obj-$(CONFIG_MTD_UBI_GLUEBI) += gluebi.o
--- /dev/null
+++ b/drivers/mtd/ubi/block.c
@@ -0,0 +1,646 @@
+/*
+ * Copyright (c) 2014 Ezequiel Garcia
+ * Copyright (c) 2011 Free Electrons
+ *
+ * Driver parameter handling strongly based on drivers/mtd/ubi/build.c
+ * Copyright (c) International Business Machines Corp., 2006
+ * Copyright (c) Nokia Corporation, 2007
+ * Authors: Artem Bityutskiy, Frank Haverkamp
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ */
+
+/*
+ * Read-only block devices on top of UBI volumes
+ *
+ * A simple implementation to allow a block device to be layered on top of a
+ * UBI volume. The implementation is provided by creating a static 1-to-1
+ * mapping between the block device and the UBI volume.
+ *
+ * The addressed byte is obtained from the addressed block sector, which is
+ * mapped linearly into the corresponding LEB:
+ *
+ * LEB number = addressed byte / LEB size
+ *
+ * This feature is compiled in the UBI core, and adds a new 'block' parameter
+ * to allow early block device attaching. Runtime block attach/detach for UBI
+ * volumes is provided through two new UBI ioctls: UBI_IOCVOLATTBLK and
+ * UBI_IOCVOLDETBLK.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/mtd/ubi.h>
+#include <linux/workqueue.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <asm/div64.h>
+
+#include "ubi-media.h"
+#include "ubi.h"
+
+/* Maximum number of supported devices */
+#define UBIBLOCK_MAX_DEVICES 32
+
+/* Maximum length of the 'block=' parameter */
+#define UBIBLOCK_PARAM_LEN 63
+
+/* Maximum number of comma-separated items in the 'block=' parameter */
+#define UBIBLOCK_PARAM_COUNT 2
+
+struct ubiblock_param {
+ int ubi_num;
+ int vol_id;
+ char name[UBIBLOCK_PARAM_LEN+1];
+};
+
+/* Numbers of elements set in the @ubiblock_param array */
+static int ubiblock_devs __initdata;
+
+/* MTD devices specification parameters */
+static struct ubiblock_param ubiblock_param[UBIBLOCK_MAX_DEVICES] __initdata;
+
+struct ubiblock {
+ struct ubi_volume_desc *desc;
+ int ubi_num;
+ int vol_id;
+ int refcnt;
+ int leb_size;
+
+ struct gendisk *gd;
+ struct request_queue *rq;
+
+ struct workqueue_struct *wq;
+ struct work_struct work;
+
+ struct mutex dev_mutex;
+ spinlock_t queue_lock;
+ struct list_head list;
+};
+
+/* Linked list of all ubiblock instances */
+static LIST_HEAD(ubiblock_devices);
+static DEFINE_MUTEX(devices_mutex);
+static int ubiblock_major;
+
+static int __init ubiblock_set_param(const char *val,
+ const struct kernel_param *kp)
+{
+ int i, ret;
+ size_t len;
+ struct ubiblock_param *param;
+ char buf[UBIBLOCK_PARAM_LEN];
+ char *pbuf = &buf[0];
+ char *tokens[UBIBLOCK_PARAM_COUNT];
+
+ if (!val)
+ return -EINVAL;
+
+ len = strnlen(val, UBIBLOCK_PARAM_LEN);
+ if (len == 0) {
+ ubi_warn("block: empty 'block=' parameter - ignored\n");
+ return 0;
+ }
+
+ if (len == UBIBLOCK_PARAM_LEN) {
+ ubi_err("block: parameter \"%s\" is too long, max. is %d\n",
+ val, UBIBLOCK_PARAM_LEN);
+ return -EINVAL;
+ }
+
+ strcpy(buf, val);
+
+ /* Get rid of the final newline */
+ if (buf[len - 1] == '\n')
+ buf[len - 1] = '\0';
+
+ for (i = 0; i < UBIBLOCK_PARAM_COUNT; i++)
+ tokens[i] = strsep(&pbuf, ",");
+
+ param = &ubiblock_param[ubiblock_devs];
+ if (tokens[1]) {
+ /* Two parameters: can be 'ubi, vol_id' or 'ubi, vol_name' */
+ ret = kstrtoint(tokens[0], 10, &param->ubi_num);
+ if (ret < 0)
+ return -EINVAL;
+
+ /* Second param can be a number or a name */
+ ret = kstrtoint(tokens[1], 10, &param->vol_id);
+ if (ret < 0) {
+ param->vol_id = -1;
+ strcpy(param->name, tokens[1]);
+ }
+
+ } else {
+ /* One parameter: must be device path */
+ strcpy(param->name, tokens[0]);
+ param->ubi_num = -1;
+ param->vol_id = -1;
+ }
+
+ ubiblock_devs++;
+
+ return 0;
+}
+
+static const struct kernel_param_ops ubiblock_param_ops = {
+ .set = ubiblock_set_param,
+};
+module_param_cb(block, &ubiblock_param_ops, NULL, 0);
+MODULE_PARM_DESC(block, "Attach block devices to UBI volumes. Parameter format: block=<path|dev,num|dev,name>.\n"
+ "Multiple \"block\" parameters may be specified.\n"
+ "UBI volumes may be specified by their number, name, or path to the device node.\n"
+ "Examples\n"
+ "Using the UBI volume path:\n"
+ "ubi.block=/dev/ubi0_0\n"
+ "Using the UBI device, and the volume name:\n"
+ "ubi.block=0,rootfs\n"
+ "Using both UBI device number and UBI volume number:\n"
+ "ubi.block=0,0\n");
+
+static struct ubiblock *find_dev_nolock(int ubi_num, int vol_id)
+{
+ struct ubiblock *dev;
+
+ list_for_each_entry(dev, &ubiblock_devices, list)
+ if (dev->ubi_num == ubi_num && dev->vol_id == vol_id)
+ return dev;
+ return NULL;
+}
+
+static int ubiblock_read_to_buf(struct ubiblock *dev, char *buffer,
+ int leb, int offset, int len)
+{
+ int ret;
+
+ ret = ubi_read(dev->desc, leb, buffer, offset, len);
+ if (ret) {
+ ubi_err("%s ubi_read error %d",
+ dev->gd->disk_name, ret);
+ return ret;
+ }
+ return 0;
+}
+
+static int ubiblock_read(struct ubiblock *dev, char *buffer,
+ sector_t sec, int len)
+{
+ int ret, leb, offset;
+ int bytes_left = len;
+ int to_read = len;
+ loff_t pos = sec << 9;
+
+ /* Get LEB:offset address to read from */
+ offset = do_div(pos, dev->leb_size);
+ leb = pos;
+
+ while (bytes_left) {
+ /*
+ * We can only read one LEB at a time. Therefore if the read
+ * length is larger than one LEB size, we split the operation.
+ */
+ if (offset + to_read > dev->leb_size)
+ to_read = dev->leb_size - offset;
+
+ ret = ubiblock_read_to_buf(dev, buffer, leb, offset, to_read);
+ if (ret)
+ return ret;
+
+ buffer += to_read;
+ bytes_left -= to_read;
+ to_read = bytes_left;
+ leb += 1;
+ offset = 0;
+ }
+ return 0;
+}
+
+static int do_ubiblock_request(struct ubiblock *dev, struct request *req)
+{
+ int len, ret;
+ sector_t sec;
+
+ if (req->cmd_type != REQ_TYPE_FS)
+ return -EIO;
+
+ if (blk_rq_pos(req) + blk_rq_cur_sectors(req) >
+ get_capacity(req->rq_disk))
+ return -EIO;
+
+ if (rq_data_dir(req) != READ)
+ return -ENOSYS; /* Write not implemented */
+
+ sec = blk_rq_pos(req);
+ len = blk_rq_cur_bytes(req);
+
+ /*
+ * Let's prevent the device from being removed while we're doing I/O
+ * work. Notice that this means we serialize all the I/O operations,
+ * but it's probably of no impact given the NAND core serializes
+ * flash access anyway.
+ */
+ mutex_lock(&dev->dev_mutex);
+ ret = ubiblock_read(dev, req->buffer, sec, len);
+ mutex_unlock(&dev->dev_mutex);
+
+ return ret;
+}
+
+static void ubiblock_do_work(struct work_struct *work)
+{
+ struct ubiblock *dev =
+ container_of(work, struct ubiblock, work);
+ struct request_queue *rq = dev->rq;
+ struct request *req;
+ int res;
+
+ spin_lock_irq(rq->queue_lock);
+
+ req = blk_fetch_request(rq);
+ while (req) {
+
+ spin_unlock_irq(rq->queue_lock);
+ res = do_ubiblock_request(dev, req);
+ spin_lock_irq(rq->queue_lock);
+
+ /*
+ * If we're done with this request,
+ * we need to fetch a new one
+ */
+ if (!__blk_end_request_cur(req, res))
+ req = blk_fetch_request(rq);
+ }
+
+ spin_unlock_irq(rq->queue_lock);
+}
+
+static void ubiblock_request(struct request_queue *rq)
+{
+ struct ubiblock *dev;
+ struct request *req;
+
+ dev = rq->queuedata;
+
+ if (!dev)
+ while ((req = blk_fetch_request(rq)) != NULL)
+ __blk_end_request_all(req, -ENODEV);
+ else
+ queue_work(dev->wq, &dev->work);
+}
+
+static int ubiblock_open(struct block_device *bdev, fmode_t mode)
+{
+ struct ubiblock *dev = bdev->bd_disk->private_data;
+ int ret;
+
+ mutex_lock(&dev->dev_mutex);
+ if (dev->refcnt > 0) {
+ /*
+ * The volume is already open, just increase the reference
+ * counter.
+ */
+ goto out_done;
+ }
+
+ /*
+ * We want users to be aware they should only mount us as read-only.
+ * It's just a paranoid check, as write requests will get rejected
+ * in any case.
+ */
+ if (mode & FMODE_WRITE) {
+ ret = -EPERM;
+ goto out_unlock;
+ }
+
+ dev->desc = ubi_open_volume(dev->ubi_num, dev->vol_id, UBI_READONLY);
+ if (IS_ERR(dev->desc)) {
+ ubi_err("%s failed to open ubi volume %d_%d",
+ dev->gd->disk_name, dev->ubi_num, dev->vol_id);
+ ret = PTR_ERR(dev->desc);
+ dev->desc = NULL;
+ goto out_unlock;
+ }
+
+out_done:
+ dev->refcnt++;
+ mutex_unlock(&dev->dev_mutex);
+ return 0;
+
+out_unlock:
+ mutex_unlock(&dev->dev_mutex);
+ return ret;
+}
+
+static void ubiblock_release(struct gendisk *gd, fmode_t mode)
+{
+ struct ubiblock *dev = gd->private_data;
+
+ mutex_lock(&dev->dev_mutex);
+ dev->refcnt--;
+ if (dev->refcnt == 0) {
+ ubi_close_volume(dev->desc);
+ dev->desc = NULL;
+ }
+ mutex_unlock(&dev->dev_mutex);
+}
+
+static int ubiblock_getgeo(struct block_device *bdev, struct hd_geometry *geo)
+{
+ /* Some tools might require this information */
+ geo->heads = 1;
+ geo->cylinders = 1;
+ geo->sectors = get_capacity(bdev->bd_disk);
+ geo->start = 0;
+ return 0;
+}
+
+static const struct block_device_operations ubiblock_ops = {
+ .owner = THIS_MODULE,
+ .open = ubiblock_open,
+ .release = ubiblock_release,
+ .getgeo = ubiblock_getgeo,
+};
+
+int ubiblock_add(struct ubi_volume_info *vi)
+{
+ struct ubiblock *dev;
+ struct gendisk *gd;
+ int disk_capacity;
+ int ret;
+
+ /* Check that the volume isn't already handled */
+ mutex_lock(&devices_mutex);
+ if (find_dev_nolock(vi->ubi_num, vi->vol_id)) {
+ mutex_unlock(&devices_mutex);
+ return -EEXIST;
+ }
+ mutex_unlock(&devices_mutex);
+
+ dev = kzalloc(sizeof(struct ubiblock), GFP_KERNEL);
+ if (!dev)
+ return -ENOMEM;
+
+ mutex_init(&dev->dev_mutex);
+
+ dev->ubi_num = vi->ubi_num;
+ dev->vol_id = vi->vol_id;
+ dev->leb_size = vi->usable_leb_size;
+
+ /* Initialize the gendisk of this ubiblock device */
+ gd = alloc_disk(1);
+ if (!gd) {
+ ubi_err("block: alloc_disk failed");
+ ret = -ENODEV;
+ goto out_free_dev;
+ }
+
+ gd->fops = &ubiblock_ops;
+ gd->major = ubiblock_major;
+ gd->first_minor = dev->ubi_num * UBI_MAX_VOLUMES + dev->vol_id;
+ gd->private_data = dev;
+ sprintf(gd->disk_name, "ubiblock%d_%d", dev->ubi_num, dev->vol_id);
+ disk_capacity = (vi->size * vi->usable_leb_size) >> 9;
+ set_capacity(gd, disk_capacity);
+ dev->gd = gd;
+
+ spin_lock_init(&dev->queue_lock);
+ dev->rq = blk_init_queue(ubiblock_request, &dev->queue_lock);
+ if (!dev->rq) {
+ ubi_err("block: blk_init_queue failed");
+ ret = -ENODEV;
+ goto out_put_disk;
+ }
+
+ dev->rq->queuedata = dev;
+ dev->gd->queue = dev->rq;
+
+ /*
+ * Create one workqueue per volume (per registered block device).
+ * Rembember workqueues are cheap, they're not threads.
+ */
+ dev->wq = alloc_workqueue(gd->disk_name, 0, 0);
+ if (!dev->wq)
+ goto out_free_queue;
+ INIT_WORK(&dev->work, ubiblock_do_work);
+
+ mutex_lock(&devices_mutex);
+ list_add_tail(&dev->list, &ubiblock_devices);
+ mutex_unlock(&devices_mutex);
+
+ /* Must be the last step: anyone can call file ops from now on */
+ add_disk(dev->gd);
+ ubi_msg("%s created from ubi%d:%d(%s)",
+ dev->gd->disk_name, dev->ubi_num, dev->vol_id, vi->name);
+ return 0;
+
+out_free_queue:
+ blk_cleanup_queue(dev->rq);
+out_put_disk:
+ put_disk(dev->gd);
+out_free_dev:
+ kfree(dev);
+
+ return ret;
+}
+
+static void ubiblock_cleanup(struct ubiblock *dev)
+{
+ del_gendisk(dev->gd);
+ blk_cleanup_queue(dev->rq);
+ ubi_msg("%s released", dev->gd->disk_name);
+ put_disk(dev->gd);
+}
+
+int ubiblock_del(struct ubi_volume_info *vi)
+{
+ struct ubiblock *dev;
+
+ mutex_lock(&devices_mutex);
+ dev = find_dev_nolock(vi->ubi_num, vi->vol_id);
+ if (!dev) {
+ mutex_unlock(&devices_mutex);
+ return -ENODEV;
+ }
+
+ /* Found a device, let's lock it so we can check if it's busy */
+ mutex_lock(&dev->dev_mutex);
+ if (dev->refcnt > 0) {
+ mutex_unlock(&dev->dev_mutex);
+ mutex_unlock(&devices_mutex);
+ return -EBUSY;
+ }
+
+ /* Remove from device list */
+ list_del(&dev->list);
+ mutex_unlock(&devices_mutex);
+
+ /* Flush pending work and stop this workqueue */
+ destroy_workqueue(dev->wq);
+
+ ubiblock_cleanup(dev);
+ mutex_unlock(&dev->dev_mutex);
+ kfree(dev);
+ return 0;
+}
+
+static void ubiblock_resize(struct ubi_volume_info *vi)
+{
+ struct ubiblock *dev;
+ int disk_capacity;
+
+ /*
+ * Need to lock the device list until we stop using the device,
+ * otherwise the device struct might get released in 'ubiblock_del()'.
+ */
+ mutex_lock(&devices_mutex);
+ dev = find_dev_nolock(vi->ubi_num, vi->vol_id);
+ if (!dev) {
+ mutex_unlock(&devices_mutex);
+ return;
+ }
+
+ mutex_lock(&dev->dev_mutex);
+ disk_capacity = (vi->size * vi->usable_leb_size) >> 9;
+ set_capacity(dev->gd, disk_capacity);
+ ubi_msg("%s resized to %d LEBs", dev->gd->disk_name, vi->size);
+ mutex_unlock(&dev->dev_mutex);
+ mutex_unlock(&devices_mutex);
+}
+
+static int ubiblock_notify(struct notifier_block *nb,
+ unsigned long notification_type, void *ns_ptr)
+{
+ struct ubi_notification *nt = ns_ptr;
+
+ switch (notification_type) {
+ case UBI_VOLUME_ADDED:
+ /*
+ * We want to enforce explicit block device attaching for
+ * volumes, so when a volume is added we do nothing.
+ */
+ break;
+ case UBI_VOLUME_REMOVED:
+ ubiblock_del(&nt->vi);
+ break;
+ case UBI_VOLUME_RESIZED:
+ ubiblock_resize(&nt->vi);
+ break;
+ default:
+ break;
+ }
+ return NOTIFY_OK;
+}
+
+static struct notifier_block ubiblock_notifier = {
+ .notifier_call = ubiblock_notify,
+};
+
+static struct ubi_volume_desc * __init
+open_volume_desc(const char *name, int ubi_num, int vol_id)
+{
+ if (ubi_num == -1)
+ /* No ubi num, name must be a vol device path */
+ return ubi_open_volume_path(name, UBI_READONLY);
+ else if (vol_id == -1)
+ /* No vol_id, must be vol_name */
+ return ubi_open_volume_nm(ubi_num, name, UBI_READONLY);
+ else
+ return ubi_open_volume(ubi_num, vol_id, UBI_READONLY);
+}
+
+static int __init ubiblock_attach_from_param(void)
+{
+ int i, ret;
+ struct ubiblock_param *p;
+ struct ubi_volume_desc *desc;
+ struct ubi_volume_info vi;
+
+ for (i = 0; i < ubiblock_devs; i++) {
+ p = &ubiblock_param[i];
+
+ desc = open_volume_desc(p->name, p->ubi_num, p->vol_id);
+ if (IS_ERR(desc)) {
+ ubi_err("block: can't open volume, err=%ld\n",
+ PTR_ERR(desc));
+ ret = PTR_ERR(desc);
+ break;
+ }
+
+ ubi_get_volume_info(desc, &vi);
+ ubi_close_volume(desc);
+
+ ret = ubiblock_add(&vi);
+ if (ret) {
+ ubi_err("block: can't add '%s' volume, err=%d\n",
+ vi.name, ret);
+ break;
+ }
+ }
+ return ret;
+}
+
+static void ubiblock_detach_all(void)
+{
+ struct ubiblock *next;
+ struct ubiblock *dev;
+
+ list_for_each_entry_safe(dev, next, &ubiblock_devices, list) {
+ /* Flush pending work and stop workqueue */
+ destroy_workqueue(dev->wq);
+ /* The module is being forcefully removed */
+ WARN_ON(dev->desc);
+ /* Remove from device list */
+ list_del(&dev->list);
+ ubiblock_cleanup(dev);
+ kfree(dev);
+ }
+}
+
+int __init ubiblock_init(void)
+{
+ int ret;
+
+ ubiblock_major = register_blkdev(0, "ubiblock");
+ if (ubiblock_major < 0)
+ return ubiblock_major;
+
+ /* Attach block devices from 'block=' module param */
+ ret = ubiblock_attach_from_param();
+ if (ret)
+ goto err_detach;
+
+ /*
+ * Block devices needs to be attached to volumes explicitly
+ * upon user request. So we ignore existing volumes.
+ */
+ ret = ubi_register_volume_notifier(&ubiblock_notifier, 1);
+ if (ret)
+ goto err_unreg;
+ return 0;
+
+err_unreg:
+ unregister_blkdev(ubiblock_major, "ubiblock");
+err_detach:
+ ubiblock_detach_all();
+ return ret;
+}
+
+void __exit ubiblock_exit(void)
+{
+ ubi_unregister_volume_notifier(&ubiblock_notifier);
+ ubiblock_detach_all();
+ unregister_blkdev(ubiblock_major, "ubiblock");
+}
--- a/drivers/mtd/ubi/build.c
+++ b/drivers/mtd/ubi/build.c
@@ -1298,6 +1298,15 @@ static int __init ubi_init(void)
}
}
+ err = ubiblock_init();
+ if (err) {
+ ubi_err("block: cannot initialize, error %d", err);
+
+ /* See comment above re-ubi_is_module(). */
+ if (ubi_is_module())
+ goto out_detach;
+ }
+
return 0;
out_detach:
@@ -1326,6 +1335,8 @@ static void __exit ubi_exit(void)
{
int i;
+ ubiblock_exit();
+
for (i = 0; i < UBI_MAX_DEVICES; i++)
if (ubi_devices[i]) {
mutex_lock(&ubi_devices_mutex);
--- a/drivers/mtd/ubi/cdev.c
+++ b/drivers/mtd/ubi/cdev.c
@@ -561,6 +561,26 @@ static long vol_cdev_ioctl(struct file *
break;
}
+ /* Attach a block device to an UBI volume */
+ case UBI_IOCVOLATTBLK:
+ {
+ struct ubi_volume_info vi;
+
+ ubi_get_volume_info(desc, &vi);
+ err = ubiblock_add(&vi);
+ break;
+ }
+
+ /* Dettach a block device from an UBI volume */
+ case UBI_IOCVOLDETBLK:
+ {
+ struct ubi_volume_info vi;
+
+ ubi_get_volume_info(desc, &vi);
+ err = ubiblock_del(&vi);
+ break;
+ }
+
default:
err = -ENOTTY;
break;
--- a/drivers/mtd/ubi/ubi.h
+++ b/drivers/mtd/ubi/ubi.h
@@ -864,6 +864,20 @@ int ubi_update_fastmap(struct ubi_device
int ubi_scan_fastmap(struct ubi_device *ubi, struct ubi_attach_info *ai,
int fm_anchor);
+/* block.c */
+#ifdef CONFIG_MTD_UBI_BLOCK
+int ubiblock_init(void);
+void ubiblock_exit(void);
+int ubiblock_add(struct ubi_volume_info *vi);
+int ubiblock_del(struct ubi_volume_info *vi);
+#else
+static inline int ubiblock_init(void) { return 0; }
+static inline void ubiblock_exit(void) {}
+static inline int ubiblock_add(struct ubi_volume_info *vi) { return -ENOTTY; }
+static inline int ubiblock_del(struct ubi_volume_info *vi) { return -ENOTTY; }
+#endif
+
+
/*
* ubi_rb_for_each_entry - walk an RB-tree.
* @rb: a pointer to type 'struct rb_node' to use as a loop counter
--- a/include/uapi/mtd/ubi-user.h
+++ b/include/uapi/mtd/ubi-user.h
@@ -134,6 +134,13 @@
* used. A pointer to a &struct ubi_set_vol_prop_req object is expected to be
* passed. The object describes which property should be set, and to which value
* it should be set.
+ *
+ * Block devices on UBI volumes
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * To attach or detach a block device from an UBI volume the %UBI_IOCVOLATTBLK
+ * and %UBI_IOCVOLDETBLK ioctl commands should be used, respectively.
+ * These commands take no arguments.
*/
/*
@@ -191,6 +198,10 @@
/* Set an UBI volume property */
#define UBI_IOCSETVOLPROP _IOW(UBI_VOL_IOC_MAGIC, 6, \
struct ubi_set_vol_prop_req)
+/* Attach a block device to an UBI volume */
+#define UBI_IOCVOLATTBLK _IO(UBI_VOL_IOC_MAGIC, 7)
+/* Detach a block device from an UBI volume */
+#define UBI_IOCVOLDETBLK _IO(UBI_VOL_IOC_MAGIC, 8)
/* Maximum MTD device name length supported by UBI */
#define MAX_UBI_MTD_NAME_LEN 127

View file

@ -1,185 +0,0 @@
From 4d283ee2517303afa54ad6cbd9342a2f748cf509 Mon Sep 17 00:00:00 2001
From: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
Date: Tue, 4 Mar 2014 12:00:26 +0200
Subject: [PATCH] UBI: block: do not use term "attach"
We already use term attach/detach for UBI->MTD relations, let's not use this
for UBI->ubiblock relations to avoid confusion. Just use 'create' and 'remove'
instead. E.g., "create a R/O block device on top of a UBI volume".
Signed-off-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
---
drivers/mtd/ubi/block.c | 39 ++++++++++++++++++++-------------------
drivers/mtd/ubi/cdev.c | 4 ++--
drivers/mtd/ubi/ubi.h | 14 ++++++++++----
3 files changed, 32 insertions(+), 25 deletions(-)
--- a/drivers/mtd/ubi/block.c
+++ b/drivers/mtd/ubi/block.c
@@ -29,10 +29,10 @@
*
* LEB number = addressed byte / LEB size
*
- * This feature is compiled in the UBI core, and adds a new 'block' parameter
- * to allow early block device attaching. Runtime block attach/detach for UBI
- * volumes is provided through two new UBI ioctls: UBI_IOCVOLATTBLK and
- * UBI_IOCVOLDETBLK.
+ * This feature is compiled in the UBI core, and adds a 'block' parameter
+ * to allow early creation of block devices on top of UBI volumes. Runtime
+ * block creation/removal for UBI volumes is provided through two UBI ioctls:
+ * UBI_IOCVOLATTBLK and UBI_IOCVOLDETBLK.
*/
#include <linux/module.h>
@@ -374,7 +374,7 @@ static const struct block_device_operati
.getgeo = ubiblock_getgeo,
};
-int ubiblock_add(struct ubi_volume_info *vi)
+int ubiblock_create(struct ubi_volume_info *vi)
{
struct ubiblock *dev;
struct gendisk *gd;
@@ -464,7 +464,7 @@ static void ubiblock_cleanup(struct ubib
put_disk(dev->gd);
}
-int ubiblock_del(struct ubi_volume_info *vi)
+int ubiblock_remove(struct ubi_volume_info *vi)
{
struct ubiblock *dev;
@@ -503,7 +503,8 @@ static void ubiblock_resize(struct ubi_v
/*
* Need to lock the device list until we stop using the device,
- * otherwise the device struct might get released in 'ubiblock_del()'.
+ * otherwise the device struct might get released in
+ * 'ubiblock_remove()'.
*/
mutex_lock(&devices_mutex);
dev = find_dev_nolock(vi->ubi_num, vi->vol_id);
@@ -528,12 +529,12 @@ static int ubiblock_notify(struct notifi
switch (notification_type) {
case UBI_VOLUME_ADDED:
/*
- * We want to enforce explicit block device attaching for
+ * We want to enforce explicit block device creation for
* volumes, so when a volume is added we do nothing.
*/
break;
case UBI_VOLUME_REMOVED:
- ubiblock_del(&nt->vi);
+ ubiblock_remove(&nt->vi);
break;
case UBI_VOLUME_RESIZED:
ubiblock_resize(&nt->vi);
@@ -561,7 +562,7 @@ open_volume_desc(const char *name, int u
return ubi_open_volume(ubi_num, vol_id, UBI_READONLY);
}
-static int __init ubiblock_attach_from_param(void)
+static int __init ubiblock_create_from_param(void)
{
int i, ret;
struct ubiblock_param *p;
@@ -582,7 +583,7 @@ static int __init ubiblock_attach_from_p
ubi_get_volume_info(desc, &vi);
ubi_close_volume(desc);
- ret = ubiblock_add(&vi);
+ ret = ubiblock_create(&vi);
if (ret) {
ubi_err("block: can't add '%s' volume, err=%d\n",
vi.name, ret);
@@ -592,7 +593,7 @@ static int __init ubiblock_attach_from_p
return ret;
}
-static void ubiblock_detach_all(void)
+static void ubiblock_remove_all(void)
{
struct ubiblock *next;
struct ubiblock *dev;
@@ -618,13 +619,13 @@ int __init ubiblock_init(void)
return ubiblock_major;
/* Attach block devices from 'block=' module param */
- ret = ubiblock_attach_from_param();
+ ret = ubiblock_create_from_param();
if (ret)
- goto err_detach;
+ goto err_remove;
/*
- * Block devices needs to be attached to volumes explicitly
- * upon user request. So we ignore existing volumes.
+ * Block devices are only created upon user requests, so we ignore
+ * existing volumes.
*/
ret = ubi_register_volume_notifier(&ubiblock_notifier, 1);
if (ret)
@@ -633,14 +634,14 @@ int __init ubiblock_init(void)
err_unreg:
unregister_blkdev(ubiblock_major, "ubiblock");
-err_detach:
- ubiblock_detach_all();
+err_remove:
+ ubiblock_remove_all();
return ret;
}
void __exit ubiblock_exit(void)
{
ubi_unregister_volume_notifier(&ubiblock_notifier);
- ubiblock_detach_all();
+ ubiblock_remove_all();
unregister_blkdev(ubiblock_major, "ubiblock");
}
--- a/drivers/mtd/ubi/cdev.c
+++ b/drivers/mtd/ubi/cdev.c
@@ -567,7 +567,7 @@ static long vol_cdev_ioctl(struct file *
struct ubi_volume_info vi;
ubi_get_volume_info(desc, &vi);
- err = ubiblock_add(&vi);
+ err = ubiblock_create(&vi);
break;
}
@@ -577,7 +577,7 @@ static long vol_cdev_ioctl(struct file *
struct ubi_volume_info vi;
ubi_get_volume_info(desc, &vi);
- err = ubiblock_del(&vi);
+ err = ubiblock_remove(&vi);
break;
}
--- a/drivers/mtd/ubi/ubi.h
+++ b/drivers/mtd/ubi/ubi.h
@@ -868,13 +868,19 @@ int ubi_scan_fastmap(struct ubi_device *
#ifdef CONFIG_MTD_UBI_BLOCK
int ubiblock_init(void);
void ubiblock_exit(void);
-int ubiblock_add(struct ubi_volume_info *vi);
-int ubiblock_del(struct ubi_volume_info *vi);
+int ubiblock_create(struct ubi_volume_info *vi);
+int ubiblock_remove(struct ubi_volume_info *vi);
#else
static inline int ubiblock_init(void) { return 0; }
static inline void ubiblock_exit(void) {}
-static inline int ubiblock_add(struct ubi_volume_info *vi) { return -ENOTTY; }
-static inline int ubiblock_del(struct ubi_volume_info *vi) { return -ENOTTY; }
+static inline int ubiblock_create(struct ubi_volume_info *vi)
+{
+ return -ENOTTY;
+}
+static inline int ubiblock_remove(struct ubi_volume_info *vi)
+{
+ return -ENOTTY;
+}
#endif

View file

@ -1,37 +0,0 @@
From ca2b722d1ab5bc3ffc34b5995248968cd8a7cb6f Mon Sep 17 00:00:00 2001
From: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
Date: Mon, 3 Mar 2014 13:42:38 -0300
Subject: [PATCH] UBI: block: Mark init-only symbol as __initdata
ubiblock_param_ops should be marked as __init as it's only used to set
a driver parameter on insertion time. This commit fixes the following:
WARNING: drivers/mtd/built-in.o(.text+0x653ac): Section mismatch in
reference from the variable ubiblock_param_ops to the function
.init.text:ubiblock_set_param()
The function ubiblock_param_ops() references the function __init
ubiblock_set_param(). This is often because ubiblock_param_ops lacks a
__init annotation or the annotation of ubiblock_set_param is wrong.
Given gcc errors if the struct is marked const __initdata, this commit
drops the const mark from it.
Reported-by: kbuild test robot <fengguang.wu@intel.com>
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
Signed-off-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
---
drivers/mtd/ubi/block.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/drivers/mtd/ubi/block.c
+++ b/drivers/mtd/ubi/block.c
@@ -156,7 +156,7 @@ static int __init ubiblock_set_param(con
return 0;
}
-static const struct kernel_param_ops ubiblock_param_ops = {
+static struct kernel_param_ops ubiblock_param_ops __initdata = {
.set = ubiblock_set_param,
};
module_param_cb(block, &ubiblock_param_ops, NULL, 0);

View file

@ -1,28 +0,0 @@
From 9981e14ab2f7c6a4d2bb45e51a6371964919837d Mon Sep 17 00:00:00 2001
From: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
Date: Mon, 3 Mar 2014 13:42:39 -0300
Subject: [PATCH] UBI: block: Use 'u64' for the 64-bit dividend
Fixes the following warning on ARCH=avr32:
drivers/mtd/ubi/block.c: In function 'ubiblock_read':
drivers/mtd/ubi/block.c:207: warning: comparison of distinct pointer types lacks a cast
Reported-by: kbuild test robot <fengguang.wu@intel.com>
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
Signed-off-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
---
drivers/mtd/ubi/block.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/drivers/mtd/ubi/block.c
+++ b/drivers/mtd/ubi/block.c
@@ -201,7 +201,7 @@ static int ubiblock_read(struct ubiblock
int ret, leb, offset;
int bytes_left = len;
int to_read = len;
- loff_t pos = sec << 9;
+ u64 pos = sec << 9;
/* Get LEB:offset address to read from */
offset = do_div(pos, dev->leb_size);

View file

@ -1,83 +0,0 @@
From 8af871887fcba470ff9265c65cff7d14d9e0e3f9 Mon Sep 17 00:00:00 2001
From: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
Date: Wed, 5 Mar 2014 13:01:56 +0200
Subject: [PATCH] UBI: rename block device ioctls
Rename the UBI_IOCVOLATTBLK and UBI_IOCVOLDETBLK to UBI_IOCVOLCRBLK and
UBI_IOCVOLRMBLK, because we do not use terms "attach" and "detach" for the R/O
block devices on top of UBI volumes. Instead, we use terms "create" and
"remove". This patch also amends the related commentaries.
Signed-off-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
Acked-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
---
drivers/mtd/ubi/block.c | 2 +-
drivers/mtd/ubi/cdev.c | 8 ++++----
include/uapi/mtd/ubi-user.h | 14 +++++++-------
3 files changed, 12 insertions(+), 12 deletions(-)
--- a/drivers/mtd/ubi/block.c
+++ b/drivers/mtd/ubi/block.c
@@ -32,7 +32,7 @@
* This feature is compiled in the UBI core, and adds a 'block' parameter
* to allow early creation of block devices on top of UBI volumes. Runtime
* block creation/removal for UBI volumes is provided through two UBI ioctls:
- * UBI_IOCVOLATTBLK and UBI_IOCVOLDETBLK.
+ * UBI_IOCVOLCRBLK and UBI_IOCVOLRMBLK.
*/
#include <linux/module.h>
--- a/drivers/mtd/ubi/cdev.c
+++ b/drivers/mtd/ubi/cdev.c
@@ -561,8 +561,8 @@ static long vol_cdev_ioctl(struct file *
break;
}
- /* Attach a block device to an UBI volume */
- case UBI_IOCVOLATTBLK:
+ /* Create a R/O block device on top of the UBI volume */
+ case UBI_IOCVOLCRBLK:
{
struct ubi_volume_info vi;
@@ -571,8 +571,8 @@ static long vol_cdev_ioctl(struct file *
break;
}
- /* Dettach a block device from an UBI volume */
- case UBI_IOCVOLDETBLK:
+ /* Remove the R/O block device */
+ case UBI_IOCVOLRMBLK:
{
struct ubi_volume_info vi;
--- a/include/uapi/mtd/ubi-user.h
+++ b/include/uapi/mtd/ubi-user.h
@@ -138,9 +138,9 @@
* Block devices on UBI volumes
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
- * To attach or detach a block device from an UBI volume the %UBI_IOCVOLATTBLK
- * and %UBI_IOCVOLDETBLK ioctl commands should be used, respectively.
- * These commands take no arguments.
+ * To create or remove a R/O block device on top of an UBI volume the
+ * %UBI_IOCVOLCRBLK and %UBI_IOCVOLRMBLK ioctl commands should be used,
+ * respectively. These commands take no arguments.
*/
/*
@@ -198,10 +198,10 @@
/* Set an UBI volume property */
#define UBI_IOCSETVOLPROP _IOW(UBI_VOL_IOC_MAGIC, 6, \
struct ubi_set_vol_prop_req)
-/* Attach a block device to an UBI volume */
-#define UBI_IOCVOLATTBLK _IO(UBI_VOL_IOC_MAGIC, 7)
-/* Detach a block device from an UBI volume */
-#define UBI_IOCVOLDETBLK _IO(UBI_VOL_IOC_MAGIC, 8)
+/* Create a R/O block device on top of an UBI volume */
+#define UBI_IOCVOLCRBLK _IO(UBI_VOL_IOC_MAGIC, 7)
+/* Remove the R/O block device */
+#define UBI_IOCVOLRMBLK _IO(UBI_VOL_IOC_MAGIC, 8)
/* Maximum MTD device name length supported by UBI */
#define MAX_UBI_MTD_NAME_LEN 127

View file

@ -1,30 +0,0 @@
From d56030ac25d383218045c5d87e98e0494d6af3ad Mon Sep 17 00:00:00 2001
From: Richard Weinberger <richard@nod.at>
Date: Wed, 19 Mar 2014 11:43:22 +0100
Subject: [PATCH] UBI: block: Remove __initdata from ubiblock_param_ops
You cannot mark these parameters as __initdata.
Otherwise the data is gone upon module exit.
Fixes:
[ 172.045465] BUG: unable to handle kernel paging request at ffffffffa001db38
[ 172.046020] IP: [<ffffffff81067aa4>] destroy_params+0x24/0x50
Signed-off-by: Richard Weinberger <richard@nod.at>
Acked-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
Signed-off-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
---
drivers/mtd/ubi/block.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/drivers/mtd/ubi/block.c
+++ b/drivers/mtd/ubi/block.c
@@ -156,7 +156,7 @@ static int __init ubiblock_set_param(con
return 0;
}
-static struct kernel_param_ops ubiblock_param_ops __initdata = {
+static struct kernel_param_ops ubiblock_param_ops = {
.set = ubiblock_set_param,
};
module_param_cb(block, &ubiblock_param_ops, NULL, 0);

View file

@ -1,25 +0,0 @@
From bebfef150e0b8fa68704cddacf05b8c26462d565 Mon Sep 17 00:00:00 2001
From: Kees Cook <keescook@chromium.org>
Date: Mon, 7 Apr 2014 21:44:07 -0700
Subject: [PATCH] UBI: avoid workqueue format string leak
When building the name for the workqueue thread, make sure a format
string cannot leak in from the disk name.
Signed-off-by: Kees Cook <keescook@chromium.org>
Signed-off-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
---
drivers/mtd/ubi/block.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/drivers/mtd/ubi/block.c
+++ b/drivers/mtd/ubi/block.c
@@ -431,7 +431,7 @@ int ubiblock_create(struct ubi_volume_in
* Create one workqueue per volume (per registered block device).
* Rembember workqueues are cheap, they're not threads.
*/
- dev->wq = alloc_workqueue(gd->disk_name, 0, 0);
+ dev->wq = alloc_workqueue("%s", 0, 0, gd->disk_name);
if (!dev->wq)
goto out_free_queue;
INIT_WORK(&dev->work, ubiblock_do_work);

View file

@ -1,58 +0,0 @@
From 463c5eedb4a13b9aa91f05498a0f2c20bd03f8c4 Mon Sep 17 00:00:00 2001
From: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
Date: Wed, 5 Mar 2014 11:16:14 -0300
Subject: [PATCH] UBI: make UBI_IOCVOLCRBLK take a parameter for future usage
In order to allow a future ioctl parameter, such as a creation flag,
we change the UBI_IOCVOLCRBLK so it accepts a struct ubi_blkcreate_req.
For the time being the structure is not in use, but fully reserved.
This ABI change is still possible and harmless, because the ioctl has just
been introduced and there's no userspace program which uses it.
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
Signed-off-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
---
include/uapi/mtd/ubi-user.h | 19 +++++++++++++++----
1 file changed, 15 insertions(+), 4 deletions(-)
--- a/include/uapi/mtd/ubi-user.h
+++ b/include/uapi/mtd/ubi-user.h
@@ -138,9 +138,12 @@
* Block devices on UBI volumes
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
- * To create or remove a R/O block device on top of an UBI volume the
- * %UBI_IOCVOLCRBLK and %UBI_IOCVOLRMBLK ioctl commands should be used,
- * respectively. These commands take no arguments.
+ * To create a R/O block device on top of an UBI volume the %UBI_IOCVOLCRBLK
+ * should be used. A pointer to a &struct ubi_blkcreate_req object is expected
+ * to be passed, which is not used and reserved for future usage.
+ *
+ * Conversely, to remove a block device the %UBI_IOCVOLRMBLK should be used,
+ * which takes no arguments.
*/
/*
@@ -199,7 +202,7 @@
#define UBI_IOCSETVOLPROP _IOW(UBI_VOL_IOC_MAGIC, 6, \
struct ubi_set_vol_prop_req)
/* Create a R/O block device on top of an UBI volume */
-#define UBI_IOCVOLCRBLK _IO(UBI_VOL_IOC_MAGIC, 7)
+#define UBI_IOCVOLCRBLK _IOW(UBI_VOL_IOC_MAGIC, 7, struct ubi_blkcreate_req)
/* Remove the R/O block device */
#define UBI_IOCVOLRMBLK _IO(UBI_VOL_IOC_MAGIC, 8)
@@ -431,4 +434,12 @@ struct ubi_set_vol_prop_req {
__u64 value;
} __packed;
+/**
+ * struct ubi_blkcreate_req - a data structure used in block creation requests.
+ * @padding: reserved for future, not used, has to be zeroed
+ */
+struct ubi_blkcreate_req {
+ __s8 padding[128];
+} __packed;
+
#endif /* __UBI_USER_H__ */

View file

@ -1,59 +0,0 @@
--- a/drivers/mtd/Kconfig
+++ b/drivers/mtd/Kconfig
@@ -150,7 +150,7 @@ config MTD_BCM63XX_PARTS
config MTD_BCM47XX_PARTS
tristate "BCM47XX partitioning support"
- depends on BCM47XX
+ depends on BCM47XX || ARCH_BCM_5301X
help
This provides partitions parser for devices based on BCM47xx
boards.
--- a/drivers/mtd/bcm47xxpart.c
+++ b/drivers/mtd/bcm47xxpart.c
@@ -14,7 +14,6 @@
#include <linux/slab.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
-#include <bcm47xx_nvram.h>
/* 10 parts were found on sflash on Netgear WNDR4500 */
#define BCM47XXPART_MAX_PARTS 12
@@ -30,6 +29,7 @@
#define BOARD_DATA_MAGIC2 0xBD0D0BBD
#define CFE_MAGIC 0x43464531 /* 1EFC */
#define FACTORY_MAGIC 0x59544346 /* FCTY */
+#define NVRAM_HEADER 0x48534C46 /* FLSH */
#define POT_MAGIC1 0x54544f50 /* POTT */
#define POT_MAGIC2 0x504f /* OP */
#define ML_MAGIC1 0x39685a42
@@ -91,7 +91,7 @@ static int bcm47xxpart_parse(struct mtd_
if (offset >= 0x2000000)
break;
- if (curr_part > BCM47XXPART_MAX_PARTS) {
+ if (curr_part >= BCM47XXPART_MAX_PARTS) {
pr_warn("Reached maximum number of partitions, scanning stopped!\n");
break;
}
@@ -147,6 +147,11 @@ static int bcm47xxpart_parse(struct mtd_
/* TRX */
if (buf[0x000 / 4] == TRX_MAGIC) {
+ if (BCM47XXPART_MAX_PARTS - curr_part < 4) {
+ pr_warn("Not enough partitions left to register trx, scanning stopped!\n");
+ break;
+ }
+
trx = (struct trx_header *)buf;
trx_part = curr_part;
@@ -212,7 +217,7 @@ static int bcm47xxpart_parse(struct mtd_
/* Look for NVRAM at the end of the last block. */
for (i = 0; i < ARRAY_SIZE(possible_nvram_sizes); i++) {
- if (curr_part > BCM47XXPART_MAX_PARTS) {
+ if (curr_part >= BCM47XXPART_MAX_PARTS) {
pr_warn("Reached maximum number of partitions, scanning stopped!\n");
break;
}

View file

@ -1,19 +0,0 @@
--- a/drivers/mtd/bcm47xxpart.c
+++ b/drivers/mtd/bcm47xxpart.c
@@ -199,6 +199,16 @@ static int bcm47xxpart_parse(struct mtd_
continue;
}
+ /* New (ARM?) devices may have NVRAM in some middle block. Last
+ * block will be checked later, so skip it.
+ */
+ if (offset != master->size - blocksize &&
+ buf[0x000 / 4] == NVRAM_HEADER) {
+ bcm47xxpart_add_part(&parts[curr_part++], "nvram",
+ offset, 0);
+ continue;
+ }
+
/* Read middle of the block */
if (mtd_read(master, offset + 0x8000, 0x4,
&bytes_read, (uint8_t *)buf) < 0) {

View file

@ -1,50 +0,0 @@
--- a/drivers/mtd/bcm47xxpart.c
+++ b/drivers/mtd/bcm47xxpart.c
@@ -15,8 +15,12 @@
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
-/* 10 parts were found on sflash on Netgear WNDR4500 */
-#define BCM47XXPART_MAX_PARTS 12
+/*
+ * NAND flash on Netgear R6250 was verified to contain 15 partitions.
+ * This will result in allocating too big array for some old devices, but the
+ * memory will be freed soon anyway (see mtd_device_parse_register).
+ */
+#define BCM47XXPART_MAX_PARTS 20
/*
* Amount of bytes we read when analyzing each block of flash memory.
@@ -168,18 +172,26 @@ static int bcm47xxpart_parse(struct mtd_
i++;
}
- bcm47xxpart_add_part(&parts[curr_part++], "linux",
- offset + trx->offset[i], 0);
- i++;
+ if (trx->offset[i]) {
+ bcm47xxpart_add_part(&parts[curr_part++],
+ "linux",
+ offset + trx->offset[i],
+ 0);
+ i++;
+ }
/*
* Pure rootfs size is known and can be calculated as:
* trx->length - trx->offset[i]. We don't fill it as
* we want to have jffs2 (overlay) in the same mtd.
*/
- bcm47xxpart_add_part(&parts[curr_part++], "rootfs",
- offset + trx->offset[i], 0);
- i++;
+ if (trx->offset[i]) {
+ bcm47xxpart_add_part(&parts[curr_part++],
+ "rootfs",
+ offset + trx->offset[i],
+ 0);
+ i++;
+ }
last_trx_part = curr_part - 1;

View file

@ -1,95 +0,0 @@
--- a/drivers/mtd/bcm47xxpart.c
+++ b/drivers/mtd/bcm47xxpart.c
@@ -15,6 +15,8 @@
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
+#include <uapi/linux/magic.h>
+
/*
* NAND flash on Netgear R6250 was verified to contain 15 partitions.
* This will result in allocating too big array for some old devices, but the
@@ -39,7 +41,8 @@
#define ML_MAGIC1 0x39685a42
#define ML_MAGIC2 0x26594131
#define TRX_MAGIC 0x30524448
-#define SQSH_MAGIC 0x71736873 /* shsq */
+#define SHSQ_MAGIC 0x71736873 /* shsq (weird ZTE H218N endianness) */
+#define UBI_EC_MAGIC 0x23494255 /* UBI# */
struct trx_header {
uint32_t magic;
@@ -50,7 +53,7 @@ struct trx_header {
uint32_t offset[3];
} __packed;
-static void bcm47xxpart_add_part(struct mtd_partition *part, char *name,
+static void bcm47xxpart_add_part(struct mtd_partition *part, const char *name,
u64 offset, uint32_t mask_flags)
{
part->name = name;
@@ -58,6 +61,26 @@ static void bcm47xxpart_add_part(struct
part->mask_flags = mask_flags;
}
+static const char *bcm47xxpart_trx_data_part_name(struct mtd_info *master,
+ size_t offset)
+{
+ uint32_t buf;
+ size_t bytes_read;
+
+ 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);
+ goto out_default;
+ }
+
+ if (buf == UBI_EC_MAGIC)
+ return "ubi";
+
+out_default:
+ return "rootfs";
+}
+
static int bcm47xxpart_parse(struct mtd_info *master,
struct mtd_partition **pparts,
struct mtd_part_parser_data *data)
@@ -73,8 +96,12 @@ static int bcm47xxpart_parse(struct mtd_
int last_trx_part = -1;
int possible_nvram_sizes[] = { 0x8000, 0xF000, 0x10000, };
- if (blocksize <= 0x10000)
- blocksize = 0x10000;
+ /*
+ * Some really old flashes (like AT45DB*) had smaller erasesize-s, but
+ * partitions were aligned to at least 0x1000 anyway.
+ */
+ if (blocksize < 0x1000)
+ blocksize = 0x1000;
/* Alloc */
parts = kzalloc(sizeof(struct mtd_partition) * BCM47XXPART_MAX_PARTS,
@@ -186,8 +213,11 @@ static int bcm47xxpart_parse(struct mtd_
* we want to have jffs2 (overlay) in the same mtd.
*/
if (trx->offset[i]) {
+ const char *name;
+
+ name = bcm47xxpart_trx_data_part_name(master, offset + trx->offset[i]);
bcm47xxpart_add_part(&parts[curr_part++],
- "rootfs",
+ name,
offset + trx->offset[i],
0);
i++;
@@ -205,7 +235,8 @@ static int bcm47xxpart_parse(struct mtd_
}
/* Squashfs on devices not using TRX */
- if (buf[0x000 / 4] == SQSH_MAGIC) {
+ if (le32_to_cpu(buf[0x000 / 4]) == SQUASHFS_MAGIC ||
+ buf[0x000 / 4] == SHSQ_MAGIC) {
bcm47xxpart_add_part(&parts[curr_part++], "rootfs",
offset, 0);
continue;

View file

@ -1,323 +0,0 @@
From 61ab9efddf51cbc0d57356a4d650785cf5721fbe Mon Sep 17 00:00:00 2001
From: Ricardo Ribalda <ricardo.ribalda@gmail.com>
Date: Mon, 4 Aug 2014 11:11:49 +0200
Subject: [PATCH] net/usb/hso: Add support for Option GTM671WFS
After this patch:
[ 32.985530] hso: drivers/net/usb/hso.c: Option Wireless
[ 33.000452] hso 2-1.4:1.7: Not our interface
[ 33.001849] usbcore: registered new interface driver hso
root@qt5022:~# ls /dev/ttyHS*
/dev/ttyHS0 /dev/ttyHS1 /dev/ttyHS2 /dev/ttyHS3 /dev/ttyHS4
/dev/ttyHS5
root@qt5022:~# lsusb -d 0af0: -vvv
Bus 002 Device 003: ID 0af0:9200 Option
Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 2.00
bDeviceClass 255 Vendor Specific Class
bDeviceSubClass 255 Vendor Specific Subclass
bDeviceProtocol 255 Vendor Specific Protocol
bMaxPacketSize0 64
idVendor 0x0af0 Option
idProduct 0x9200
bcdDevice 0.00
iManufacturer 3 Option N.V.
iProduct 2 Globetrotter HSUPA Modem
iSerial 0
bNumConfigurations 1
Configuration Descriptor:
bLength 9
bDescriptorType 2
wTotalLength 200
bNumInterfaces 8
bConfigurationValue 1
iConfiguration 1 Option Configuration
bmAttributes 0xe0
Self Powered
Remote Wakeup
MaxPower 100mA
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 0
bAlternateSetting 0
bNumEndpoints 2
bInterfaceClass 255 Vendor Specific Class
bInterfaceSubClass 255 Vendor Specific Subclass
bInterfaceProtocol 255 Vendor Specific Protocol
iInterface 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x81 EP 1 IN
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0200 1x 512 bytes
bInterval 32
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x01 EP 1 OUT
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0200 1x 512 bytes
bInterval 32
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 1
bAlternateSetting 0
bNumEndpoints 2
bInterfaceClass 255 Vendor Specific Class
bInterfaceSubClass 255 Vendor Specific Subclass
bInterfaceProtocol 255 Vendor Specific Protocol
iInterface 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x82 EP 2 IN
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0200 1x 512 bytes
bInterval 32
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x02 EP 2 OUT
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0200 1x 512 bytes
bInterval 32
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 2
bAlternateSetting 0
bNumEndpoints 2
bInterfaceClass 255 Vendor Specific Class
bInterfaceSubClass 255 Vendor Specific Subclass
bInterfaceProtocol 255 Vendor Specific Protocol
iInterface 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x83 EP 3 IN
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0200 1x 512 bytes
bInterval 32
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x03 EP 3 OUT
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0200 1x 512 bytes
bInterval 32
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 3
bAlternateSetting 0
bNumEndpoints 2
bInterfaceClass 255 Vendor Specific Class
bInterfaceSubClass 255 Vendor Specific Subclass
bInterfaceProtocol 255 Vendor Specific Protocol
iInterface 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x84 EP 4 IN
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0200 1x 512 bytes
bInterval 32
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x04 EP 4 OUT
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0200 1x 512 bytes
bInterval 32
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 4
bAlternateSetting 0
bNumEndpoints 2
bInterfaceClass 255 Vendor Specific Class
bInterfaceSubClass 255 Vendor Specific Subclass
bInterfaceProtocol 255 Vendor Specific Protocol
iInterface 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x85 EP 5 IN
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0200 1x 512 bytes
bInterval 32
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x05 EP 5 OUT
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0200 1x 512 bytes
bInterval 32
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 5
bAlternateSetting 0
bNumEndpoints 2
bInterfaceClass 255 Vendor Specific Class
bInterfaceSubClass 255 Vendor Specific Subclass
bInterfaceProtocol 255 Vendor Specific Protocol
iInterface 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x06 EP 6 OUT
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0200 1x 512 bytes
bInterval 32
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x86 EP 6 IN
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0200 1x 512 bytes
bInterval 32
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 6
bAlternateSetting 0
bNumEndpoints 3
bInterfaceClass 255 Vendor Specific Class
bInterfaceSubClass 255 Vendor Specific Subclass
bInterfaceProtocol 255 Vendor Specific Protocol
iInterface 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x87 EP 7 IN
bmAttributes 3
Transfer Type Interrupt
Synch Type None
Usage Type Data
wMaxPacketSize 0x0040 1x 64 bytes
bInterval 5
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x88 EP 8 IN
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0200 1x 512 bytes
bInterval 32
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x07 EP 7 OUT
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0200 1x 512 bytes
bInterval 32
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 7
bAlternateSetting 0
bNumEndpoints 2
bInterfaceClass 8 Mass Storage
bInterfaceSubClass 6 SCSI
bInterfaceProtocol 80 Bulk-Only
iInterface 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x08 EP 8 OUT
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0200 1x 512 bytes
bInterval 1
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x89 EP 9 IN
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0200 1x 512 bytes
bInterval 1
Device Qualifier (for other device speed):
bLength 10
bDescriptorType 6
bcdUSB 2.00
bDeviceClass 255 Vendor Specific Class
bDeviceSubClass 255 Vendor Specific Subclass
bDeviceProtocol 255 Vendor Specific Protocol
bMaxPacketSize0 64
bNumConfigurations 1
Device Status: 0x0001
Self Powered
Signed-off-by: Ricardo Ribalda Delgado <ricardo.ribalda@gmail.com>
Acked-by: Dan Williams <dcbw@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
drivers/net/usb/hso.c | 1 +
1 file changed, 1 insertion(+)
--- a/drivers/net/usb/hso.c
+++ b/drivers/net/usb/hso.c
@@ -469,6 +469,7 @@ static const struct usb_device_id hso_id
{USB_DEVICE(0x0af0, 0x8800)},
{USB_DEVICE(0x0af0, 0x8900)},
{USB_DEVICE(0x0af0, 0x9000)},
+ {USB_DEVICE(0x0af0, 0x9200)}, /* Option GTM671WFS */
{USB_DEVICE(0x0af0, 0xd035)},
{USB_DEVICE(0x0af0, 0xd055)},
{USB_DEVICE(0x0af0, 0xd155)},

View file

@ -1,10 +0,0 @@
--- a/arch/arm/boot/compressed/decompress.c
+++ b/arch/arm/boot/compressed/decompress.c
@@ -48,6 +48,7 @@ extern char * strstr(const char * s1, co
#ifdef CONFIG_KERNEL_XZ
#define memmove memmove
#define memcpy memcpy
+extern char * strstr(const char *, const char *);
#include "../../../../lib/decompress_unxz.c"
#endif

View file

@ -1,64 +0,0 @@
From 0db3db45f5bd6df4bdc03bbd5dec672e16164c4e Mon Sep 17 00:00:00 2001
From: Florian Fainelli <florian@openwrt.org>
Date: Mon, 12 Nov 2012 12:31:55 +0100
Subject: [PATCH] MIPS: decompressor: fix build failure on memcpy() in
decompress.c
The decompress.c file includes linux/kernel.h which causes the following
inclusion chain to be pulled:
linux/kernel.h ->
linux/dynamic_debug.h ->
linux/string.h ->
asm/string.h
We end up having a the GCC builtin + architecture specific memcpy() expanding
into this:
void *({ size_t __len = (size_t n); void *__ret; if
(__builtin_constant_p(size_t n) && __len >= 64) __ret = memcpy((void *dest),
(const void *src), __len); else __ret = __builtin_memcpy((void *dest), (const
void *src), __len); __ret; })
{
[memcpy implementation in decompress.c starts here]
int i;
const char *s = src;
char *d = dest;
for (i = 0; i < n; i++)
d[i] = s[i];
return dest;
}
raising the following compilation error:
arch/mips/boot/compressed/decompress.c:46:8: error: expected identifier or '('
before '{' token
There are at least three possibilities to fix this issue:
1) define _LINUX_STRING_H_ at the beginning of decompress.c to prevent
further linux/string.h definitions and declarations from being used, and add
an explicit strstr() declaration for linux/dynamic_debug.h
2) remove the inclusion of linux/kernel.h because we actually use no definition
or declaration from this header file
3) undefine memcpy or re-define memcpy to memcpy thus resulting in picking up
the local memcpy() implementation to this compilation unit
This patch uses the second option which is the less intrusive one.
Signed-off-by: Florian Fainelli <florian@openwrt.org>
---
arch/mips/boot/compressed/decompress.c | 2 --
1 file changed, 2 deletions(-)
--- a/arch/mips/boot/compressed/decompress.c
+++ b/arch/mips/boot/compressed/decompress.c
@@ -12,7 +12,6 @@
*/
#include <linux/types.h>
-#include <linux/kernel.h>
#include <linux/string.h>
#include <asm/addrspace.h>

View file

@ -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;
+}

View file

@ -1,122 +0,0 @@
Backport essential fixes from 3.15
From Linux 3.10 on this driver required platform data to load, which makes it
unusable in OpenWRT. This commit backports the following fixes:
* Move to regulator framework for scaling
* Fix device-removal path
This commit should not be moved to newer kernel versions!
Signed-off-by: Hartmut Knaack <knaack.h@gmx.de>
---
--- a/drivers/staging/iio/adc/ad799x_core.c
+++ b/drivers/staging/iio/adc/ad799x_core.c
@@ -179,7 +179,10 @@ static int ad799x_read_raw(struct iio_de
RES_MASK(chan->scan_type.realbits);
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
- *val = st->int_vref_mv;
+ ret = regulator_get_voltage(st->vref);
+ if (ret < 0)
+ return ret;
+ *val = ret / 1000;
*val2 = chan->scan_type.realbits;
return IIO_VAL_FRACTIONAL_LOG2;
}
@@ -533,7 +536,6 @@ static int ad799x_probe(struct i2c_clien
const struct i2c_device_id *id)
{
int ret;
- struct ad799x_platform_data *pdata = client->dev.platform_data;
struct ad799x_state *st;
struct iio_dev *indio_dev;
@@ -551,17 +553,21 @@ static int ad799x_probe(struct i2c_clien
/* TODO: Add pdata options for filtering and bit delay */
- if (!pdata)
- return -EINVAL;
-
- st->int_vref_mv = pdata->vref_mv;
-
st->reg = devm_regulator_get(&client->dev, "vcc");
- if (!IS_ERR(st->reg)) {
- ret = regulator_enable(st->reg);
- if (ret)
- return ret;
+ if (IS_ERR(st->reg))
+ return PTR_ERR(st->reg);
+ ret = regulator_enable(st->reg);
+ if (ret)
+ return ret;
+ st->vref = devm_regulator_get(&client->dev, "vref");
+ if (IS_ERR(st->vref)) {
+ ret = PTR_ERR(st->vref);
+ goto error_disable_reg;
}
+ ret = regulator_enable(st->vref);
+ if (ret)
+ goto error_disable_reg;
+
st->client = client;
indio_dev->dev.parent = &client->dev;
@@ -574,7 +580,7 @@ static int ad799x_probe(struct i2c_clien
ret = ad799x_register_ring_funcs_and_init(indio_dev);
if (ret)
- goto error_disable_reg;
+ goto error_disable_vref;
if (client->irq > 0) {
ret = request_threaded_irq(client->irq,
@@ -598,9 +604,10 @@ error_free_irq:
free_irq(client->irq, indio_dev);
error_cleanup_ring:
ad799x_ring_cleanup(indio_dev);
+error_disable_vref:
+ regulator_disable(st->vref);
error_disable_reg:
- if (!IS_ERR(st->reg))
- regulator_disable(st->reg);
+ regulator_disable(st->reg);
return ret;
}
@@ -615,8 +622,8 @@ static int ad799x_remove(struct i2c_clie
free_irq(client->irq, indio_dev);
ad799x_ring_cleanup(indio_dev);
- if (!IS_ERR(st->reg))
- regulator_disable(st->reg);
+ regulator_disable(st->vref);
+ regulator_disable(st->reg);
kfree(st->rx_buf);
return 0;
--- a/drivers/staging/iio/adc/ad799x.h
+++ b/drivers/staging/iio/adc/ad799x.h
@@ -95,7 +95,7 @@ struct ad799x_state {
struct i2c_client *client;
const struct ad799x_chip_info *chip_info;
struct regulator *reg;
- u16 int_vref_mv;
+ struct regulator *vref;
unsigned id;
u16 config;
@@ -103,14 +103,6 @@ struct ad799x_state {
unsigned int transfer_size;
};
-/*
- * TODO: struct ad799x_platform_data needs to go into include/linux/iio
- */
-
-struct ad799x_platform_data {
- u16 vref_mv;
-};
-
#ifdef CONFIG_AD799X_RING_BUFFER
int ad799x_register_ring_funcs_and_init(struct iio_dev *indio_dev);
void ad799x_ring_cleanup(struct iio_dev *indio_dev);

View file

@ -1,71 +0,0 @@
commit 797ac07137d9ae8572008e21e6123a9ae17dae50
Author: Florian Fainelli <f.fainelli@gmail.com>
Date: Mon Feb 17 13:34:02 2014 -0800
net: phy: move PHY software reset to genphy_soft_reset
As pointed out by Shaohui, this function is generic for 10/100/1000
PHYs, but 10G PHYs might have a slightly different reset sequence which
prevents most of them from using this function.
Move the BMCR_RESET based software resent sequence to
genphy_soft_reset() in preparation for allowing PHY drivers to implement
a soft_reset() callback.
Reported-by: Shaohui Xie <Shaohui.Xie@freescale.com>
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -539,11 +539,7 @@ int phy_init_hw(struct phy_device *phyde
if (!phydev->drv || !phydev->drv->config_init)
return 0;
- ret = phy_write(phydev, MII_BMCR, BMCR_RESET);
- if (ret < 0)
- return ret;
-
- ret = phy_poll_reset(phydev);
+ ret = genphy_soft_reset(phydev);
if (ret < 0)
return ret;
@@ -1029,6 +1025,27 @@ static int gen10g_read_status(struct phy
return 0;
}
+/**
+ * genphy_soft_reset - software reset the PHY via BMCR_RESET bit
+ * @phydev: target phy_device struct
+ *
+ * Description: Perform a software PHY reset using the standard
+ * BMCR_RESET bit and poll for the reset bit to be cleared.
+ *
+ * Returns: 0 on success, < 0 on failure
+ */
+int genphy_soft_reset(struct phy_device *phydev)
+{
+ int ret;
+
+ ret = phy_write(phydev, MII_BMCR, BMCR_RESET);
+ if (ret < 0)
+ return ret;
+
+ return phy_poll_reset(phydev);
+}
+EXPORT_SYMBOL(genphy_soft_reset);
+
static int genphy_config_init(struct phy_device *phydev)
{
int val;
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -616,6 +616,7 @@ int genphy_update_link(struct phy_device
int genphy_read_status(struct phy_device *phydev);
int genphy_suspend(struct phy_device *phydev);
int genphy_resume(struct phy_device *phydev);
+int genphy_soft_reset(struct phy_device *phydev);
void phy_driver_unregister(struct phy_driver *drv);
void phy_drivers_unregister(struct phy_driver *drv, int n);
int phy_driver_register(struct phy_driver *new_driver);

View file

@ -1,81 +0,0 @@
commit 9df81dd7583d14862d0cfb673a941b261f3b2112
Author: Florian Fainelli <f.fainelli@gmail.com>
Date: Mon Feb 17 13:34:03 2014 -0800
net: phy: allow PHY drivers to implement their own software reset
As pointed out by Shaohui, most 10G PHYs out there have a non-standard
compliant software reset sequence, eventually something much more
complex than just toggling the BMCR_RESET bit. Allow PHY driver to
implement their own soft_reset() callback to deal with that. If no
callback is provided, call into genphy_soft_reset() which makes sure the
existing behavior is kept intact.
Reported-by: Shaohui Xie <Shaohui.Xie@freescale.com>
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -534,12 +534,16 @@ static int phy_poll_reset(struct phy_dev
int phy_init_hw(struct phy_device *phydev)
{
- int ret;
+ int ret = 0;
if (!phydev->drv || !phydev->drv->config_init)
return 0;
- ret = genphy_soft_reset(phydev);
+ if (phydev->drv->soft_reset)
+ ret = phydev->drv->soft_reset(phydev);
+ else
+ ret = genphy_soft_reset(phydev);
+
if (ret < 0)
return ret;
@@ -1092,6 +1096,12 @@ static int genphy_config_init(struct phy
return 0;
}
+static int gen10g_soft_reset(struct phy_device *phydev)
+{
+ /* Do nothing for now */
+ return 0;
+}
+
static int gen10g_config_init(struct phy_device *phydev)
{
/* Temporarily just say we support everything */
@@ -1266,6 +1276,7 @@ static struct phy_driver genphy_driver[]
.phy_id = 0xffffffff,
.phy_id_mask = 0xffffffff,
.name = "Generic PHY",
+ .soft_reset = genphy_soft_reset,
.config_init = genphy_config_init,
.features = 0,
.config_aneg = genphy_config_aneg,
@@ -1277,6 +1288,7 @@ static struct phy_driver genphy_driver[]
.phy_id = 0xffffffff,
.phy_id_mask = 0xffffffff,
.name = "Generic 10G PHY",
+ .soft_reset = gen10g_soft_reset,
.config_init = gen10g_config_init,
.features = 0,
.config_aneg = gen10g_config_aneg,
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -394,6 +394,11 @@ struct phy_driver {
u32 flags;
/*
+ * Called to issue a PHY software reset
+ */
+ int (*soft_reset)(struct phy_device *phydev);
+
+ /*
* Called to initialize the PHY,
* including after a reset
*/

View file

@ -1,35 +0,0 @@
From: Balakumaran Kannan <kumaran.4353@gmail.com>
Date: Thu, 24 Apr 2014 08:22:47 +0530
Subject: [PATCH] net phy: Check for aneg completion before setting state to
PHY_RUNNING
phy_state_machine should check whether auto-negotiatin is completed
before changing phydev->state from PHY_NOLINK to PHY_RUNNING. If
auto-negotiation is not completed phydev->state should be set to
PHY_AN.
Signed-off-by: Balakumaran Kannan <kumaran.4353@gmail.com>
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -744,6 +744,17 @@ void phy_state_machine(struct work_struc
break;
if (phydev->link) {
+ if (AUTONEG_ENABLE == phydev->autoneg) {
+ err = phy_aneg_done(phydev);
+ if (err < 0)
+ break;
+
+ if (!err) {
+ phydev->state = PHY_AN;
+ phydev->link_timeout = PHY_AN_TIMEOUT;
+ break;
+ }
+ }
phydev->state = PHY_RUNNING;
netif_carrier_on(phydev->attached_dev);
phydev->adjust_link(phydev->attached_dev);

View file

@ -1,68 +0,0 @@
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -690,7 +690,7 @@ void phy_state_machine(struct work_struc
struct delayed_work *dwork = to_delayed_work(work);
struct phy_device *phydev =
container_of(dwork, struct phy_device, state_queue);
- int needs_aneg = 0, do_suspend = 0;
+ bool needs_aneg = false, do_suspend = false, do_resume = false;
int err = 0;
mutex_lock(&phydev->lock);
@@ -702,7 +702,7 @@ void phy_state_machine(struct work_struc
case PHY_PENDING:
break;
case PHY_UP:
- needs_aneg = 1;
+ needs_aneg = true;
phydev->link_timeout = PHY_AN_TIMEOUT;
@@ -732,7 +732,7 @@ void phy_state_machine(struct work_struc
phydev->adjust_link(phydev->attached_dev);
} else if (0 == phydev->link_timeout--) {
- needs_aneg = 1;
+ needs_aneg = true;
/* If we have the magic_aneg bit, we try again */
if (phydev->drv->flags & PHY_HAS_MAGICANEG)
break;
@@ -770,7 +770,7 @@ void phy_state_machine(struct work_struc
netif_carrier_on(phydev->attached_dev);
} else {
if (0 == phydev->link_timeout--)
- needs_aneg = 1;
+ needs_aneg = true;
}
phydev->adjust_link(phydev->attached_dev);
@@ -806,7 +806,7 @@ void phy_state_machine(struct work_struc
phydev->link = 0;
netif_carrier_off(phydev->attached_dev);
phydev->adjust_link(phydev->attached_dev);
- do_suspend = 1;
+ do_suspend = true;
}
break;
case PHY_RESUMING:
@@ -855,6 +855,7 @@ void phy_state_machine(struct work_struc
}
phydev->adjust_link(phydev->attached_dev);
}
+ do_resume = true;
break;
}
@@ -862,9 +863,10 @@ void phy_state_machine(struct work_struc
if (needs_aneg)
err = phy_start_aneg(phydev);
-
- if (do_suspend)
+ else if (do_suspend)
phy_suspend(phydev);
+ else if (do_resume)
+ phy_resume(phydev);
if (err < 0)
phy_error(phydev);

View file

@ -1,44 +0,0 @@
From 6216642f200258708e47170ff14ba8ecb486f4f0 Mon Sep 17 00:00:00 2001
From: Hauke Mehrtens <hauke@hauke-m.de>
Date: Sun, 18 Jan 2015 19:49:58 +0100
Subject: [PATCH] bgmac: register napi before the device
napi should get registered before the netdev and not after.
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
drivers/net/ethernet/broadcom/bgmac.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
--- a/drivers/net/ethernet/broadcom/bgmac.c
+++ b/drivers/net/ethernet/broadcom/bgmac.c
@@ -1515,6 +1515,8 @@ static int bgmac_probe(struct bcma_devic
if (core->bus->sprom.boardflags_lo & BGMAC_BFL_ENETADM)
bgmac_warn(bgmac, "Support for ADMtek ethernet switch not implemented\n");
+ netif_napi_add(net_dev, &bgmac->napi, bgmac_poll, BGMAC_WEIGHT);
+
err = bgmac_mii_register(bgmac);
if (err) {
bgmac_err(bgmac, "Cannot register MDIO\n");
@@ -1529,8 +1531,6 @@ static int bgmac_probe(struct bcma_devic
netif_carrier_off(net_dev);
- netif_napi_add(net_dev, &bgmac->napi, bgmac_poll, BGMAC_WEIGHT);
-
return 0;
err_mii_unregister:
@@ -1549,9 +1549,9 @@ static void bgmac_remove(struct bcma_dev
{
struct bgmac *bgmac = bcma_get_drvdata(core);
- netif_napi_del(&bgmac->napi);
unregister_netdev(bgmac->net_dev);
bgmac_mii_unregister(bgmac);
+ netif_napi_del(&bgmac->napi);
bgmac_dma_free(bgmac);
bcma_set_drvdata(core, NULL);
free_netdev(bgmac->net_dev);

View file

@ -1,30 +0,0 @@
From 43f159c60a99318b1ef7d1d7c16c4dfdd06bfd90 Mon Sep 17 00:00:00 2001
From: Hauke Mehrtens <hauke@hauke-m.de>
Date: Sun, 18 Jan 2015 19:49:59 +0100
Subject: [PATCH] bgmac: activate irqs only if there is nothing to poll
IRQs should only get activated when there is nothing to poll in the
queue any more and to after every poll.
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
drivers/net/ethernet/broadcom/bgmac.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
--- a/drivers/net/ethernet/broadcom/bgmac.c
+++ b/drivers/net/ethernet/broadcom/bgmac.c
@@ -1167,10 +1167,10 @@ static int bgmac_poll(struct napi_struct
bgmac->int_status = 0;
}
- if (handled < weight)
+ if (handled < weight) {
napi_complete(napi);
-
- bgmac_chip_intrs_on(bgmac);
+ bgmac_chip_intrs_on(bgmac);
+ }
return handled;
}

View file

@ -1,133 +0,0 @@
commit 5596732fa8c14139018ecda8356eabbfb599d830
Author: Steffen Klassert <steffen.klassert@secunet.com>
Date: Mon Apr 7 08:08:52 2014 +0200
xfrm: Fix crash with ipv6 IPsec tunnel and NAT.
The ipv6 xfrm output path is not aware that packets can be
rerouted by NAT to not use IPsec. We crash in this case
because we expect to have a xfrm state at the dst_entry.
This crash happens if the ipv6 layer does IPsec and NAT
or if we have an interfamily IPsec tunnel with ipv4 NAT.
We fix this by checking for a NAT rerouted packet in each
address family and dst_output() to the new destination
in this case.
Reported-by: Martin Pelikan <martin.pelikan@gmail.com>
Tested-by: Martin Pelikan <martin.pelikan@gmail.com>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
--- a/net/ipv4/xfrm4_output.c
+++ b/net/ipv4/xfrm4_output.c
@@ -62,10 +62,7 @@ int xfrm4_prepare_output(struct xfrm_sta
if (err)
return err;
- memset(IPCB(skb), 0, sizeof(*IPCB(skb)));
- IPCB(skb)->flags |= IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED;
-
- skb->protocol = htons(ETH_P_IP);
+ IPCB(skb)->flags |= IPSKB_XFRM_TUNNEL_SIZE;
return x->outer_mode->output2(x, skb);
}
@@ -73,27 +70,34 @@ EXPORT_SYMBOL(xfrm4_prepare_output);
int xfrm4_output_finish(struct sk_buff *skb)
{
+ memset(IPCB(skb), 0, sizeof(*IPCB(skb)));
+ skb->protocol = htons(ETH_P_IP);
+
+#ifdef CONFIG_NETFILTER
+ IPCB(skb)->flags |= IPSKB_XFRM_TRANSFORMED;
+#endif
+
+ return xfrm_output(skb);
+}
+
+static int __xfrm4_output(struct sk_buff *skb)
+{
+ struct xfrm_state *x = skb_dst(skb)->xfrm;
+
#ifdef CONFIG_NETFILTER
- if (!skb_dst(skb)->xfrm) {
+ if (!x) {
IPCB(skb)->flags |= IPSKB_REROUTED;
return dst_output(skb);
}
-
- IPCB(skb)->flags |= IPSKB_XFRM_TRANSFORMED;
#endif
- skb->protocol = htons(ETH_P_IP);
- return xfrm_output(skb);
+ return x->outer_mode->afinfo->output_finish(skb);
}
int xfrm4_output(struct sk_buff *skb)
{
- struct dst_entry *dst = skb_dst(skb);
- struct xfrm_state *x = dst->xfrm;
-
return NF_HOOK_COND(NFPROTO_IPV4, NF_INET_POST_ROUTING, skb,
- NULL, dst->dev,
- x->outer_mode->afinfo->output_finish,
+ NULL, skb_dst(skb)->dev, __xfrm4_output,
!(IPCB(skb)->flags & IPSKB_REROUTED));
}
--- a/net/ipv6/xfrm6_output.c
+++ b/net/ipv6/xfrm6_output.c
@@ -114,12 +114,6 @@ int xfrm6_prepare_output(struct xfrm_sta
if (err)
return err;
- memset(IP6CB(skb), 0, sizeof(*IP6CB(skb)));
-#ifdef CONFIG_NETFILTER
- IP6CB(skb)->flags |= IP6SKB_XFRM_TRANSFORMED;
-#endif
-
- skb->protocol = htons(ETH_P_IPV6);
skb->local_df = 1;
return x->outer_mode->output2(x, skb);
@@ -128,11 +122,13 @@ EXPORT_SYMBOL(xfrm6_prepare_output);
int xfrm6_output_finish(struct sk_buff *skb)
{
+ memset(IP6CB(skb), 0, sizeof(*IP6CB(skb)));
+ skb->protocol = htons(ETH_P_IPV6);
+
#ifdef CONFIG_NETFILTER
IP6CB(skb)->flags |= IP6SKB_XFRM_TRANSFORMED;
#endif
- skb->protocol = htons(ETH_P_IPV6);
return xfrm_output(skb);
}
@@ -142,6 +138,13 @@ static int __xfrm6_output(struct sk_buff
struct xfrm_state *x = dst->xfrm;
int mtu;
+#ifdef CONFIG_NETFILTER
+ if (!x) {
+ IP6CB(skb)->flags |= IP6SKB_REROUTED;
+ return dst_output(skb);
+ }
+#endif
+
if (skb->protocol == htons(ETH_P_IPV6))
mtu = ip6_skb_dst_mtu(skb);
else
@@ -165,6 +168,7 @@ static int __xfrm6_output(struct sk_buff
int xfrm6_output(struct sk_buff *skb)
{
- return NF_HOOK(NFPROTO_IPV6, NF_INET_POST_ROUTING, skb, NULL,
- skb_dst(skb)->dev, __xfrm6_output);
+ return NF_HOOK_COND(NFPROTO_IPV6, NF_INET_POST_ROUTING, skb,
+ NULL, skb_dst(skb)->dev, __xfrm6_output,
+ !(IP6CB(skb)->flags & IP6SKB_REROUTED));
}

View file

@ -1,508 +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
@@ -103,6 +103,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,390 @@
+/* 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 net_device *in,
+ const struct net_device *out,
+ int (*okfn)(struct sk_buff *))
+{
+ 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 (in->ifindex != iif) {
+ pr_debug("ct %p, iif %d, cached iif %d, skip cached entry\n",
+ ct, iif, 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_force(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 net_device *in,
+ const struct net_device *out,
+ int (*okfn)(struct sk_buff *))
+{
+ 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, in->ifindex);
+ if (likely(in->ifindex == iif))
+ return NF_ACCEPT;
+
+ nf_conn_rtcache_dst_set(ops->pf, rtc, skb_dst(skb), dir, 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;
+
+ rcu_read_lock();
+ spin_lock_bh(&nf_conntrack_lock);
+
+ hlist_nulls_for_each_entry(h, n, &net->ct.dying, hnnode) {
+ ct = nf_ct_tuplehash_to_ctrack(h);
+ if (nf_ct_rtcache_find(ct) != NULL) {
+ wait = true;
+ break;
+ }
+ }
+ spin_unlock_bh(&nf_conntrack_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");

File diff suppressed because it is too large Load diff

View file

@ -1,81 +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
@@ -633,7 +633,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
@@ -641,7 +641,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;
@@ -1001,7 +1001,7 @@ static 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
@@ -47,6 +47,7 @@ static int ehci_platform_reset(struct us
ehci->has_synopsys_hc_bug = pdata->has_synopsys_hc_bug;
ehci->big_endian_desc = pdata->big_endian_desc;
ehci->big_endian_mmio = pdata->big_endian_mmio;
+ ehci->ignore_oc = pdata->ignore_oc;
if (pdata->pre_setup) {
retval = pdata->pre_setup(hcd);
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -226,6 +226,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
@@ -45,6 +45,7 @@ struct usb_ehci_pdata {
unsigned big_endian_desc:1;
unsigned big_endian_mmio:1;
unsigned no_io_watchdog:1;
+ unsigned ignore_oc:1;
/* Turn on all power and clocks */
int (*power_on)(struct platform_device *pdev);

View file

@ -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
@@ -145,11 +145,13 @@ drop:
static int br_handle_local_finish(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 */
}
@@ -219,6 +221,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, 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) {

View file

@ -1,679 +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
@@ -1621,6 +1621,9 @@ config SYS_HAS_CPU_XLR
config SYS_HAS_CPU_XLP
bool
+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/scatterlist.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 */
@@ -12,12 +19,48 @@
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
+}
+
+/*
+ * Warning on the terminology - Linux calls an uncached area coherent;
+ * MIPS terminology calls memory areas with hardware maintained coherency
+ * coherent.
+ */
+
+static inline int cpu_needs_post_dma_flush(struct device *dev)
+{
+#ifndef CONFIG_SYS_HAS_CPU_R10000
+ return 0;
+#endif
+ 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)
@@ -30,12 +73,312 @@ 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_unmap_dma_mem(dev, addr, size, dir);
+ }
+ debug_dma_unmap_page(dev, addr, size, dir, true);
+}
+
+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;
+ }
+ 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_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);
+ 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);
+ 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);
+ }
+ 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)
+
+static inline int dma_mmap_writecombine(struct device *dev, struct vm_area_struct *vma,
+ void *cpu_addr, dma_addr_t dma_addr, size_t size)
+{
+ DEFINE_DMA_ATTRS(attrs);
+ dma_set_attr(DMA_ATTR_WRITE_COMBINE, &attrs);
+ return dma_mmap_attrs(dev, vma, cpu_addr, dma_addr, size, &attrs);
+}
+
+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);
- return ops->dma_supported(dev, mask);
+ 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)
@@ -43,7 +386,9 @@ static inline int dma_mapping_error(stru
struct dma_map_ops *ops = get_dma_ops(dev);
debug_dma_mapping_error(dev, mask);
- return ops->mapping_error(dev, mask);
+ if (ops)
+ return ops->mapping_error(dev, mask);
+ return 0;
}
static inline int
@@ -69,7 +414,11 @@ static inline void *dma_alloc_attrs(stru
void *ret;
struct dma_map_ops *ops = get_dma_ops(dev);
- ret = ops->alloc(dev, size, dma_handle, gfp, attrs);
+ 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);
@@ -84,7 +433,10 @@ static inline void dma_free_attrs(struct
{
struct dma_map_ops *ops = get_dma_ops(dev);
- ops->free(dev, size, vaddr, dma_handle, attrs);
+ 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);
}
--- a/arch/mips/mm/dma-default.c
+++ b/arch/mips/mm/dma-default.c
@@ -25,7 +25,7 @@
#ifdef CONFIG_DMA_MAYBE_COHERENT
int coherentio = 0; /* User defined DMA coherency from command line. */
-EXPORT_SYMBOL_GPL(coherentio);
+EXPORT_SYMBOL(coherentio);
int hw_coherentio = 0; /* Actual hardware supported DMA coherency setting. */
static int __init setcoherentio(char *str)
@@ -45,30 +45,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.
- */
-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;
@@ -124,8 +100,9 @@ void *dma_alloc_noncoherent(struct devic
}
EXPORT_SYMBOL(dma_alloc_noncoherent);
-static 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_alloc_coherent(struct device *dev, size_t size,
+ dma_addr_t *dma_handle, gfp_t gfp,
+ struct dma_attrs *attrs)
{
void *ret;
@@ -149,6 +126,7 @@ static void *mips_dma_alloc_coherent(str
return ret;
}
+EXPORT_SYMBOL(mips_dma_alloc_coherent);
void dma_free_noncoherent(struct device *dev, size_t size, void *vaddr,
@@ -159,8 +137,8 @@ void dma_free_noncoherent(struct device
}
EXPORT_SYMBOL(dma_free_noncoherent);
-static void mips_dma_free_coherent(struct device *dev, size_t size, void *vaddr,
- dma_addr_t dma_handle, 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)
{
unsigned long addr = (unsigned long) vaddr;
int order = get_order(size);
@@ -175,6 +153,7 @@ static void mips_dma_free_coherent(struc
free_pages(addr, get_order(size));
}
+EXPORT_SYMBOL(mips_dma_free_coherent);
static inline void __dma_sync_virtual(void *addr, size_t size,
enum dma_data_direction direction)
@@ -203,8 +182,8 @@ 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,
- unsigned long offset, size_t size, enum dma_data_direction direction)
+void __dma_sync(struct page *page, unsigned long offset, size_t size,
+ enum dma_data_direction direction)
{
size_t left = size;
@@ -233,108 +212,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_unmap_dma_mem(dev, dma_addr, size, direction);
-}
-
-static int mips_dma_map_sg(struct device *dev, struct scatterlist *sg,
- int nents, enum dma_data_direction direction, struct dma_attrs *attrs)
-{
- int i;
-
- for (i = 0; i < nents; i++, sg++) {
- 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 *sg,
- int nhwentries, enum dma_data_direction direction,
- struct dma_attrs *attrs)
-{
- int i;
-
- for (i = 0; i < nhwentries; i++, sg++) {
- 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);
-}
-
-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 *sg, int nelems, enum dma_data_direction direction)
-{
- int i;
-
- if (cpu_needs_post_dma_flush(dev))
- for (i = 0; i < nelems; i++, sg++)
- __dma_sync(sg_page(sg), sg->offset, sg->length,
- direction);
-}
-
-static void mips_dma_sync_sg_for_device(struct device *dev,
- struct scatterlist *sg, int nelems, enum dma_data_direction direction)
-{
- int i;
-
- if (!plat_device_is_coherent(dev))
- for (i = 0; i < nelems; i++, sg++)
- __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)
@@ -347,23 +225,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,
- .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)

View file

@ -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

View file

@ -1,14 +0,0 @@
--- a/Makefile
+++ b/Makefile
@@ -580,9 +580,9 @@ endif # $(dot-config)
all: vmlinux
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
include $(srctree)/arch/$(SRCARCH)/Makefile

View file

@ -1,11 +0,0 @@
--- a/Makefile
+++ b/Makefile
@@ -388,7 +388,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)

View file

@ -1,108 +0,0 @@
--- a/scripts/kallsyms.c
+++ b/scripts/kallsyms.c
@@ -54,6 +54,7 @@ static struct text_range text_ranges[] =
static struct sym_entry *table;
static unsigned int table_size, table_cnt;
static int all_symbols = 0;
+static int uncompressed = 0;
static char symbol_prefix_char = '\0';
static unsigned long long kernel_start_addr = 0;
@@ -373,6 +374,9 @@ static void write_src(void)
free(markers);
+ if (uncompressed)
+ return;
+
output_label("kallsyms_token_table");
off = 0;
for (i = 0; i < 256; i++) {
@@ -431,6 +435,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];
@@ -503,6 +510,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--) {
@@ -662,7 +672,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
@@ -1270,6 +1270,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
@@ -86,6 +86,10 @@ kallsyms()
kallsymopt="${kallsymopt} --page-offset=$CONFIG_PAGE_OFFSET"
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
@@ -108,6 +108,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++;
@@ -140,6 +145,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.

View file

@ -1,200 +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
@@ -82,7 +82,7 @@ void sort_extable(struct exception_table
void sort_main_extable(void);
void trim_init_extable(struct module *m);
-#ifdef MODULE
+#if defined(MODULE) && !defined(CONFIG_MODULE_STRIPPED)
#define MODULE_GENERIC_TABLE(gtype, name) \
extern const struct gtype##_id __mod_##gtype##_table \
__attribute__ ((unused, alias(__stringify(name))))
@@ -93,9 +93,10 @@ extern const struct gtype##_id __mod_##g
/* 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")
@@ -136,10 +137,10 @@ extern const struct gtype##_id __mod_##g
* 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)
#define MODULE_DEVICE_TABLE(type, name) \
MODULE_GENERIC_TABLE(type##_device, name)
@@ -162,7 +163,9 @@ extern const struct gtype##_id __mod_##g
*/
#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 = { \
@@ -184,7 +187,7 @@ extern const struct gtype##_id __mod_##g
/* 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
@@ -1831,6 +1831,13 @@ config MODULE_SIG_HASH
default "sha384" if MODULE_SIG_SHA384
default "sha512" if MODULE_SIG_SHA512
+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 INIT_ALL_POSSIBLE
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -2663,6 +2663,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;
@@ -2688,6 +2689,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
@@ -1734,7 +1734,9 @@ static void read_symbols(char *modname)
symname = 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))
@@ -1878,7 +1880,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");
@@ -1895,16 +1899,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
}
/**
@@ -1997,11 +2005,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)
@@ -2230,7 +2240,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);

View file

@ -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

View file

@ -1,540 +0,0 @@
From: Felix Fietkau <nbd@openwrt.org>
use -ffunction-sections, -fdata-sections and --gc-sections --sort-section=name
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 --sort-section=name
KBUILD_AFLAGS_MODULE += -mlong-calls
KBUILD_CFLAGS_MODULE += -mlong-calls
+ifndef CONFIG_FUNCTION_TRACER
+KBUILD_CFLAGS_KERNEL += -ffunction-sections -fdata-sections
+endif
+
cflags-y += -ffreestanding
#
--- 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
@@ -87,7 +87,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()
@@ -95,7 +95,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()
@@ -103,7 +103,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()
@@ -112,7 +112,7 @@
#ifdef CONFIG_EVENT_TRACING
#define FTRACE_EVENTS() . = ALIGN(8); \
VMLINUX_SYMBOL(__start_ftrace_events) = .; \
- *(_ftrace_events) \
+ KEEP(*(_ftrace_events)) \
VMLINUX_SYMBOL(__stop_ftrace_events) = .;
#else
#define FTRACE_EVENTS()
@@ -120,7 +120,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 */ \
@@ -133,7 +133,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()
@@ -142,8 +142,8 @@
#ifdef CONFIG_CLKSRC_OF
#define CLKSRC_OF_TABLES() . = ALIGN(8); \
VMLINUX_SYMBOL(__clksrc_of_table) = .; \
- *(__clksrc_of_table) \
- *(__clksrc_of_table_end)
+ KEEP(*(__clksrc_of_table)) \
+ KEEP(*(__clksrc_of_table_end))
#else
#define CLKSRC_OF_TABLES()
#endif
@@ -152,8 +152,8 @@
#define IRQCHIP_OF_MATCH_TABLE() \
. = ALIGN(8); \
VMLINUX_SYMBOL(__irqchip_begin) = .; \
- *(__irqchip_of_table) \
- *(__irqchip_of_end)
+ KEEP(*(__irqchip_of_table)) \
+ KEEP(*(__irqchip_of_end))
#else
#define IRQCHIP_OF_MATCH_TABLE()
#endif
@@ -161,8 +161,8 @@
#ifdef CONFIG_COMMON_CLK
#define CLK_OF_TABLES() . = ALIGN(8); \
VMLINUX_SYMBOL(__clk_of_table) = .; \
- *(__clk_of_table) \
- *(__clk_of_table_end)
+ KEEP(*(__clk_of_table)) \
+ KEEP(*(__clk_of_table_end))
#else
#define CLK_OF_TABLES()
#endif
@@ -170,7 +170,7 @@
#define KERNEL_DTB() \
STRUCT_ALIGN(); \
VMLINUX_SYMBOL(__dtb_start) = .; \
- *(.dtb.init.rodata) \
+ KEEP(*(.dtb.init.rodata)) \
VMLINUX_SYMBOL(__dtb_end) = .;
/* .data section */
@@ -186,16 +186,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
@@ -249,32 +250,32 @@
/* 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) = .; \
} \
\
/* 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) = .; \
} \
\
@@ -283,49 +284,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) = .; \
} \
\
@@ -339,14 +340,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) = .; \
} \
\
@@ -365,14 +366,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) = .; \
@@ -428,7 +429,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
@@ -456,7 +457,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) = .; \
}
@@ -472,8 +473,8 @@
#ifdef CONFIG_CONSTRUCTORS
#define KERNEL_CTORS() . = ALIGN(8); \
VMLINUX_SYMBOL(__ctors_start) = .; \
- *(.ctors) \
- *(.init_array) \
+ KEEP(*(.ctors)) \
+ KEEP(*(.init_array)) \
VMLINUX_SYMBOL(__ctors_end) = .;
#else
#define KERNEL_CTORS()
@@ -517,7 +518,7 @@
#define SBSS(sbss_align) \
. = ALIGN(sbss_align); \
.sbss : AT(ADDR(.sbss) - LOAD_OFFSET) { \
- *(.sbss) \
+ *(.sbss .sbss.*) \
*(.scommon) \
}
@@ -535,7 +536,7 @@
BSS_FIRST_SECTIONS \
*(.bss..page_aligned) \
*(.dynbss) \
- *(.bss) \
+ *(.bss .bss.*) \
*(COMMON) \
}
@@ -584,7 +585,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
@@ -596,7 +597,7 @@
. = ALIGN(4); \
.tracedata : AT(ADDR(.tracedata) - LOAD_OFFSET) { \
VMLINUX_SYMBOL(__tracedata_start) = .; \
- *(.tracedata) \
+ KEEP(*(.tracedata)) \
VMLINUX_SYMBOL(__tracedata_end) = .; \
}
#else
@@ -613,17 +614,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) \
@@ -637,21 +638,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
@@ -18,11 +18,16 @@ ifeq ($(CONFIG_CPU_ENDIAN_BE8),y)
LDFLAGS_vmlinux += --be8
LDFLAGS_MODULE += --be8
endif
+LDFLAGS_vmlinux += --gc-sections --sort-section=name
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
@@ -12,13 +12,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(32); \
VMLINUX_SYMBOL(__hyp_idmap_text_start) = .; \
@@ -93,7 +93,7 @@ SECTIONS
.text : { /* Real text segment */
_stext = .; /* Text and read-only data */
__exception_text_start = .;
- *(.exception.text)
+ KEEP(*(.exception.text))
__exception_text_end = .;
IRQENTRY_TEXT
TEXT_TEXT
@@ -118,7 +118,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 = .;
}
@@ -130,12 +130,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
@@ -154,14 +154,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 = .;
@@ -175,24 +175,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
@@ -120,6 +120,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

View file

@ -1,88 +0,0 @@
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -52,6 +52,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. */
@@ -284,14 +294,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) = .; \
} \
\
@@ -353,7 +363,7 @@
\
/* Kernel symbol table: strings */ \
__ksymtab_strings : AT(ADDR(__ksymtab_strings) - LOAD_OFFSET) { \
- *(__ksymtab_strings) \
+ *(__ksymtab_strings+*) \
} \
\
/* __*init sections */ \
@@ -671,6 +681,8 @@
EXIT_TEXT \
EXIT_DATA \
EXIT_CALL \
+ SYMTAB_DISCARD \
+ SYMTAB_DISCARD_GPL \
*(.discard) \
*(.discard.*) \
}
--- a/scripts/Makefile.build
+++ b/scripts/Makefile.build
@@ -349,7 +349,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 \

View file

@ -1,58 +0,0 @@
--- a/scripts/Makefile.lib
+++ b/scripts/Makefile.lib
@@ -304,7 +304,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
@@ -47,6 +47,7 @@ static const struct compress_format comp
{ {037, 0236}, "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 },

View file

@ -1,18 +0,0 @@
--- a/net/netfilter/Kconfig
+++ b/net/netfilter/Kconfig
@@ -207,7 +207,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
@@ -883,7 +882,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

View file

@ -1,18 +0,0 @@
--- a/sound/core/Kconfig
+++ b/sound/core/Kconfig
@@ -10,13 +10,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

View file

@ -1,10 +0,0 @@
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -164,6 +164,7 @@ config CRYPTO_DEV_MV_CESA
depends on PLAT_ORION
select CRYPTO_ALGAPI
select CRYPTO_AES
+ select CRYPTO_HASH2
select CRYPTO_BLKCIPHER2
select CRYPTO_HASH
help

View file

@ -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

View file

@ -1,23 +0,0 @@
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -308,16 +308,16 @@ config BCH_CONST_T
# Textsearch support is select'ed if needed
#
config TEXTSEARCH
- boolean
+ 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
boolean

View file

@ -1,31 +0,0 @@
--- a/net/wireless/Kconfig
+++ b/net/wireless/Kconfig
@@ -140,7 +140,7 @@ config CFG80211_WEXT
extensions with cfg80211-based drivers.
config LIB80211
- tristate
+ tristate "LIB80211"
default n
help
This options enables a library of common routines used
@@ -149,13 +149,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"

View file

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

View file

@ -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"

View file

@ -1,11 +0,0 @@
--- a/net/netfilter/Kconfig
+++ b/net/netfilter/Kconfig
@@ -2,7 +2,7 @@ menu "Core Netfilter Configuration"
depends on NET && INET && NETFILTER
config NETFILTER_NETLINK
- tristate
+ tristate "Netfilter NFNETLINK interface"
config NETFILTER_NETLINK_ACCT
tristate "Netfilter NFACCT over NFNETLINK interface"

View file

@ -1,76 +0,0 @@
--- a/drivers/base/regmap/Kconfig
+++ b/drivers/base/regmap/Kconfig
@@ -3,23 +3,28 @@
# subsystems should select the appropriate symbols.
config REGMAP
- default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_MMIO || REGMAP_IRQ)
select LZO_COMPRESS
select LZO_DECOMPRESS
select IRQ_DOMAIN if REGMAP_IRQ
- bool
+ tristate "Regmap"
config REGMAP_I2C
- tristate
+ select REGMAP
+ tristate "Regmap I2C"
config REGMAP_SPI
- tristate
+ select REGMAP
+ depends on SPI_MASTER
+ tristate "Regmap SPI"
config REGMAP_SPMI
+ select REGMAP
tristate
config REGMAP_MMIO
+ select REGMAP
tristate
config REGMAP_IRQ
+ select REGMAP
bool
--- a/include/linux/regmap.h
+++ b/include/linux/regmap.h
@@ -49,7 +49,7 @@ struct reg_default {
unsigned int def;
};
-#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,6 +1,8 @@
-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_I2C) += regmap-i2c.o
obj-$(CONFIG_REGMAP_SPI) += regmap-spi.o
obj-$(CONFIG_REGMAP_SPMI) += regmap-spmi.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/rbtree.h>
@@ -2252,3 +2253,5 @@ static int __init regmap_initcall(void)
return 0;
}
postcore_initcall(regmap_initcall);
+
+MODULE_LICENSE("GPL");

View file

@ -1,37 +0,0 @@
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -95,10 +95,10 @@ 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_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
config CRYPTO_USER
tristate "Userspace cryptographic algorithm configuration"
--- a/crypto/algboss.c
+++ b/crypto/algboss.c
@@ -248,6 +248,9 @@ 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) ==
@@ -256,6 +259,7 @@ static int cryptomgr_schedule_test(struc
(!((type ^ CRYPTO_ALG_TYPE_AEAD) & CRYPTO_ALG_TYPE_MASK) &&
alg->cra_type == &crypto_nivaead_type && alg->cra_aead.ivsize))
type |= CRYPTO_ALG_TESTED;
+#endif
param->type = type;

View file

@ -1,23 +0,0 @@
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -193,16 +193,16 @@ config RANDOM32_SELFTEST
# compression support is select'ed if needed
#
config ZLIB_INFLATE
- tristate
+ tristate "ZLIB inflate support"
config ZLIB_DEFLATE
- tristate
+ tristate "ZLIB deflate support"
config LZO_COMPRESS
- tristate
+ tristate "LZO compress support"
config LZO_DECOMPRESS
- tristate
+ tristate "LZO decompress support"
config LZ4_COMPRESS
tristate

View file

@ -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
@@ -853,9 +853,6 @@ config FW_ARC
config ARCH_MAY_HAVE_PC_FDC
bool
-config BOOT_RAW
- bool
-
config CEVT_BCM1480
bool
@@ -2384,6 +2381,18 @@ config USE_OF
select OF_EARLY_FLATTREE
select IRQ_DOMAIN
+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

View file

@ -1,28 +0,0 @@
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -947,6 +947,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
def_bool n
--- a/arch/mips/kernel/head.S
+++ b/arch/mips/kernel/head.S
@@ -101,6 +101,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

View file

@ -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 --sort-section=name
KBUILD_AFLAGS_MODULE += -mlong-calls

View file

@ -1,160 +0,0 @@
MIPS: allow disabling the kernel FPU emulator
This patch allows turning off the in-kernel Algorithmics
FPU emulator support, which allows one to save a couple of
precious blocks on an embedded system.
Signed-off-by: Florian Fainelli <florian@openwrt.org>
--
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -935,6 +935,17 @@ config I8259
config MIPS_BONITO64
bool
+config MIPS_FPU_EMU
+ bool "Enable FPU emulation"
+ default y
+ help
+ This option allows building a kernel with or without the Algorithmics
+ FPU emulator enabled. Turning off this option results in a kernel which
+ does not catch floating operations exceptions. Make sure that your toolchain
+ is configured to enable software floating point emulation in that case.
+
+ If unsure say Y here.
+
config MIPS_MSC
bool
--- a/arch/mips/math-emu/Makefile
+++ b/arch/mips/math-emu/Makefile
@@ -2,10 +2,12 @@
# Makefile for the Linux/MIPS kernel FPU emulation.
#
-obj-y := cp1emu.o ieee754m.o ieee754d.o ieee754dp.o ieee754sp.o ieee754.o \
+obj-y := kernel_linkage.o
+
+obj-$(CONFIG_MIPS_FPU_EMU) += ieee754m.o ieee754d.o ieee754dp.o ieee754sp.o ieee754.o \
ieee754xcpt.o dp_frexp.o dp_modf.o dp_div.o dp_mul.o dp_sub.o \
dp_add.o dp_fsp.o dp_cmp.o dp_logb.o dp_scalb.o dp_simple.o \
dp_tint.o dp_fint.o dp_tlong.o dp_flong.o sp_frexp.o sp_modf.o \
sp_div.o sp_mul.o sp_sub.o sp_add.o sp_fdp.o sp_cmp.o sp_logb.o \
sp_scalb.o sp_simple.o sp_tint.o sp_fint.o sp_tlong.o sp_flong.o \
- dp_sqrt.o sp_sqrt.o kernel_linkage.o dsemul.o
+ dp_sqrt.o sp_sqrt.o dsemul.o cp1emu.o
--- a/arch/mips/math-emu/kernel_linkage.c
+++ b/arch/mips/math-emu/kernel_linkage.c
@@ -29,6 +29,7 @@
#define SIGNALLING_NAN 0x7ff800007ff80000LL
+#ifdef CONFIG_MIPS_FPU_EMU
void fpu_emulator_init_fpu(void)
{
static int first = 1;
@@ -115,3 +116,36 @@ int fpu_emulator_restore_context32(struc
return err;
}
#endif
+
+#else
+
+void fpu_emulator_init_fpu(void)
+{
+ printk(KERN_INFO "FPU emulator disabled, make sure your toolchain"
+ "was compiled with software floating point support (soft-float)\n");
+ return;
+}
+
+int fpu_emulator_save_context(struct sigcontext __user *sc)
+{
+ return 0;
+}
+
+int fpu_emulator_restore_context(struct sigcontext __user *sc)
+{
+ return 0;
+}
+
+#ifdef CONFIG_64BIT
+int fpu_emulator_save_context32(struct sigcontext32 __user *sc)
+{
+ return 0;
+}
+
+int fpu_emulator_restore_context32(struct sigcontext32 __user *sc)
+{
+ return 0;
+}
+#endif /* CONFIG_64BIT */
+
+#endif /* CONFIG_MIPS_FPU_EMU */
--- a/arch/mips/include/asm/fpu_emulator.h
+++ b/arch/mips/include/asm/fpu_emulator.h
@@ -27,6 +27,8 @@
#include <asm/inst.h>
#include <asm/local.h>
+#ifdef CONFIG_MIPS_FPU_EMU
+
#ifdef CONFIG_DEBUG_FS
struct mips_fpu_emulator_stats {
@@ -60,6 +62,38 @@ extern int fpu_emulator_cop1Handler(stru
int process_fpemu_return(int sig, void __user *fault_addr);
int mm_isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
unsigned long *contpc);
+#else
+static inline int mips_dsemul(struct pt_regs *regs, mips_instruction ir,
+ unsigned long cpc)
+{
+ return 0;
+}
+
+static inline int do_dsemulret(struct pt_regs *xcp)
+{
+ return 0;
+}
+
+static inline int fpu_emulator_cop1Handler(struct pt_regs *xcp,
+ struct mips_fpu_struct *ctx,
+ int has_fpu,
+ void *__user *fault_addr)
+{
+ return 0;
+}
+
+static inline int process_fpemu_return(int sig, void __user *fault_addr)
+{
+ return -EINVAL;
+}
+
+static inline int mm_isBranchInstr(struct pt_regs *regs,
+ struct mm_decoded_insn dec_insn,
+ unsigned long *contpc)
+{
+ return 0;
+}
+#endif /* CONFIG_MIPS_FPU_EMU */
/*
* Instruction inserted following the badinst to further tag the sequence
--- a/arch/mips/kernel/traps.c
+++ b/arch/mips/kernel/traps.c
@@ -701,6 +701,7 @@ asmlinkage void do_ov(struct pt_regs *re
exception_exit(prev_state);
}
+#ifdef CONFIG_MIPS_FPU_EMU
int process_fpemu_return(int sig, void __user *fault_addr)
{
if (sig == SIGSEGV || sig == SIGBUS) {
@@ -724,6 +725,7 @@ int process_fpemu_return(int sig, void _
return 0;
}
}
+#endif /* CONFIG_MIPS_FPU_EMU */
/*
* XXX Delayed fp exceptions when doing a lazy ctx switch XXX

View file

@ -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 --sort-section=name
+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,222 @@ 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);
+
+ 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, unsigned long size)
+{
+ struct page *page;
+ struct page *end;
+
+ page = virt_to_page(ptr);
+ end = page + (PAGE_ALIGN(size) >> PAGE_SHIFT);
+
+ for (; page < end; ++page)
+ __free_page(page);
+}
+
+
void *module_alloc(unsigned long size)
{
+#ifdef MODULE_START
return __vmalloc_node_range(size, 1, MODULE_START, MODULE_END,
GFP_KERNEL, PAGE_KERNEL, 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_free(struct module *mod, void *module_region)
+{
+ if (is_phys_addr(module_region)) {
+ if (mod->module_init == module_region)
+ free_phys(module_region, mod->init_size);
+ else if (mod->module_core == module_region)
+ free_phys(module_region, mod->core_size);
+ else
+ BUG();
+ } 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 +272,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 +312,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,11 +529,32 @@ 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_cleanup(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;
+ }
+
spin_lock_irq(&dbe_lock);
list_del(&mod->arch.dbe_list);
spin_unlock_irq(&dbe_lock);

View file

@ -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);
+

View file

@ -1,32 +0,0 @@
--- a/arch/mips/mm/cache.c
+++ b/arch/mips/mm/cache.c
@@ -38,6 +38,7 @@ void (*__flush_kernel_vmap_range)(unsign
void (*__invalidate_kernel_vmap_range)(unsigned long vaddr, int size);
EXPORT_SYMBOL_GPL(__flush_kernel_vmap_range);
+EXPORT_SYMBOL(__flush_cache_all);
/* MIPS specific cache operations */
void (*flush_cache_sigtramp)(unsigned long addr);
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -20,6 +20,9 @@
#include <linux/swap.h>
#include <linux/splice.h>
#include <linux/aio.h>
+#ifdef CONFIG_MIPS
+#include <asm/cacheflush.h>
+#endif
MODULE_ALIAS_MISCDEV(FUSE_MINOR);
MODULE_ALIAS("devname:fuse");
@@ -759,6 +762,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) {
if (cs->write)
memcpy(cs->buf, *val, ncpy);

View file

@ -1,13 +0,0 @@
--- a/arch/arm/kernel/module.c
+++ b/arch/arm/kernel/module.c
@@ -83,6 +83,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)) {

View file

@ -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
@@ -191,7 +191,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
@@ -39,10 +39,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

View file

@ -1,10 +0,0 @@
--- a/arch/powerpc/Makefile
+++ b/arch/powerpc/Makefile
@@ -158,7 +158,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
# No AltiVec or VSX instructions when building kernel
KBUILD_CFLAGS += $(call cc-option,-mno-altivec)

View file

@ -1,171 +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,9 +29,11 @@
#include <linux/kmod.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
+#include <linux/magic.h>
#include <linux/err.h>
#include "mtdcore.h"
+#include "mtdsplit/mtdsplit.h"
/* Our partition linked list */
static LIST_HEAD(mtd_partitions);
@@ -45,13 +47,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.
@@ -534,8 +537,10 @@ out_register:
return slave;
}
-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 *p, *new;
@@ -567,21 +572,24 @@ int mtd_add_partition(struct mtd_info *m
end = offset + length;
mutex_lock(&mtd_partitions_mutex);
- list_for_each_entry(p, &mtd_partitions, list)
- if (p->master == master) {
- if ((start >= p->offset) &&
- (start < (p->offset + p->mtd.size)))
- goto err_inv;
-
- if ((end >= p->offset) &&
- (end < (p->offset + p->mtd.size)))
- goto err_inv;
- }
+ if (dup_check) {
+ list_for_each_entry(p, &mtd_partitions, list)
+ if (p->master == master) {
+ if ((start >= p->offset) &&
+ (start < (p->offset + p->mtd.size)))
+ goto err_inv;
+
+ if ((end >= p->offset) &&
+ (end < (p->offset + p->mtd.size)))
+ goto err_inv;
+ }
+ }
list_add(&new->list, &mtd_partitions);
mutex_unlock(&mtd_partitions_mutex);
add_mtd_device(&new->mtd);
+ mtd_partition_split(master, new);
return ret;
err_inv:
@@ -591,6 +599,12 @@ err_inv:
}
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;
@@ -614,6 +628,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
@@ -643,6 +686,7 @@ int add_mtd_partitions(struct mtd_info *
mutex_unlock(&mtd_partitions_mutex);
add_mtd_device(&slave->mtd);
+ mtd_partition_split(master, 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

View file

@ -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
@@ -716,6 +716,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);
@@ -789,6 +813,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

View file

@ -1,72 +0,0 @@
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -628,6 +628,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
@@ -636,6 +667,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,
@@ -650,6 +682,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 {

View file

@ -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

View file

@ -1,101 +0,0 @@
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -434,14 +434,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;
@@ -659,6 +657,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
@@ -900,6 +909,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
@@ -331,6 +331,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)

View file

@ -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
@@ -668,6 +668,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
@@ -676,7 +707,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,

View file

@ -1,76 +0,0 @@
--- a/drivers/mtd/Kconfig
+++ b/drivers/mtd/Kconfig
@@ -18,6 +18,11 @@ config MTD_ROOTFS_ROOT_DEV
bool "Automatically set 'rootfs' partition to be root filesystem"
default y
+config MTD_ROOTFS_SPLIT
+ bool "Automatically split 'rootfs' partition for squashfs"
+ select MTD_SPLIT
+ default y
+
config MTD_SPLIT_FIRMWARE
bool "Automatically split firmware partition for kernel+rootfs"
default y
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -668,6 +668,47 @@ mtd_pad_erasesize(struct mtd_info *mtd,
return len;
}
+static int split_squashfs(struct mtd_info *master, int offset, int *split_offset)
+{
+ size_t squashfs_len;
+ int len, ret;
+
+ ret = mtd_get_squashfs_len(master, offset, &squashfs_len);
+ if (ret)
+ return ret;
+
+ len = mtd_pad_erasesize(master, offset, squashfs_len);
+ *split_offset = offset + len;
+
+ return 0;
+}
+
+static void split_rootfs_data(struct mtd_info *master, struct mtd_part *part)
+{
+ unsigned int split_offset = 0;
+ unsigned int split_size;
+ int ret;
+
+ ret = split_squashfs(master, part->offset, &split_offset);
+ if (ret)
+ return;
+
+ if (split_offset <= 0)
+ return;
+
+ if (config_enabled(CONFIG_MTD_SPLIT_SQUASHFS_ROOT))
+ pr_err("Dedicated partitioner didn't create \"rootfs_data\" partition, please fill a bug report!\n");
+ else
+ pr_warn("Support for built-in \"rootfs_data\" splitter will be removed, please use CONFIG_MTD_SPLIT_SQUASHFS_ROOT\n");
+
+ split_size = part->mtd.size - (split_offset - part->offset);
+ printk(KERN_INFO "mtd: partition \"%s\" created automatically, ofs=0x%x, len=0x%x\n",
+ ROOTFS_SPLIT_NAME, split_offset, split_size);
+
+ __mtd_add_partition(master, ROOTFS_SPLIT_NAME, split_offset,
+ split_size, false);
+}
+
#define UBOOT_MAGIC 0x27051956
static void split_uimage(struct mtd_info *master, struct mtd_part *part)
@@ -730,7 +771,10 @@ static void mtd_partition_split(struct m
return;
if (!strcmp(part->mtd.name, "rootfs")) {
- run_parsers_by_type(part, MTD_PARSER_TYPE_ROOTFS);
+ int num = run_parsers_by_type(part, MTD_PARSER_TYPE_ROOTFS);
+
+ if (num <= 0 && config_enabled(CONFIG_MTD_ROOTFS_SPLIT))
+ split_rootfs_data(master, part);
rootfs_found = 1;
}

View file

@ -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;
/**

View file

@ -1,146 +0,0 @@
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -35,6 +35,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);
@@ -231,13 +233,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;
}
@@ -245,7 +295,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;
@@ -503,18 +571,24 @@ 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;
}
+ if ((slave->mtd.flags & (MTD_ERASE_PARTIAL|MTD_WRITEABLE)) == MTD_ERASE_PARTIAL)
+ printk(KERN_WARNING"mtd: partition \"%s\" must either start or end on erase block boundary or be smaller than an erase block -- forcing read-only\n",
+ part->name);
slave->mtd.ecclayout = master->ecclayout;
slave->mtd.ecc_step_size = master->ecc_step_size;
--- 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 {

View file

@ -1,18 +0,0 @@
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -332,7 +332,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)

View file

@ -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);

View file

@ -1,35 +0,0 @@
--- a/drivers/mtd/Kconfig
+++ b/drivers/mtd/Kconfig
@@ -184,6 +184,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 || 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

View file

@ -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 */
@@ -261,7 +262,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;

View file

@ -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
@@ -176,6 +177,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) {

View file

@ -1,107 +0,0 @@
--- a/drivers/mtd/devices/block2mtd.c
+++ b/drivers/mtd/devices/block2mtd.c
@@ -17,6 +17,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>
@@ -210,11 +211,12 @@ static void block2mtd_free_device(struct
/* FIXME: ensure that mtd->size % erase_size == 0 */
-static struct block2mtd_dev *add_device(char *devname, int erase_size)
+static struct block2mtd_dev *add_device(char *devname, int erase_size, const char *mtdname)
{
const fmode_t mode = FMODE_READ | FMODE_WRITE | FMODE_EXCL;
struct block_device *bdev;
struct block2mtd_dev *dev;
+ struct mtd_partition *part;
char *name;
if (!devname)
@@ -253,13 +255,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 devinit_err;
+ 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;
@@ -272,15 +277,18 @@ 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 devinit_err;
}
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;
devinit_err:
@@ -347,9 +355,9 @@ static char block2mtd_paramline[80 + 12]
static int block2mtd_setup2(const char *val)
{
- char buf[80 + 12]; /* 80 for device, 12 for erase size */
+ char buf[80 + 12 + 80]; /* 80 for device, 12 for erase size, 80 for name */
char *str = buf;
- char *token[2];
+ char *token[3];
char *name;
size_t erase_size = PAGE_SIZE;
int i, ret;
@@ -362,7 +370,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) {
@@ -388,8 +396,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);
+ add_device(name, erase_size, token[2]);
return 0;
}
@@ -423,7 +433,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)
{

View file

@ -1,108 +0,0 @@
--- a/drivers/mtd/devices/block2mtd.c
+++ b/drivers/mtd/devices/block2mtd.c
@@ -10,6 +10,7 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/module.h>
+#include <linux/delay.h>
#include <linux/fs.h>
#include <linux/blkdev.h>
#include <linux/bio.h>
@@ -211,13 +212,14 @@ static void block2mtd_free_device(struct
/* FIXME: ensure that mtd->size % erase_size == 0 */
-static struct block2mtd_dev *add_device(char *devname, int erase_size, const char *mtdname)
+static struct block2mtd_dev *add_device(char *devname, int erase_size, const char *mtdname, int timeout)
{
const fmode_t mode = FMODE_READ | FMODE_WRITE | FMODE_EXCL;
- struct block_device *bdev;
+ struct block_device *bdev = ERR_PTR(-ENODEV);
struct block2mtd_dev *dev;
struct mtd_partition *part;
char *name;
+ int i;
if (!devname)
return NULL;
@@ -228,15 +230,20 @@ static struct block2mtd_dev *add_device(
/* Get a handle on the device */
bdev = blkdev_get_by_path(devname, mode, dev);
+
#ifndef MODULE
- if (IS_ERR(bdev)) {
+ for (i = 0; IS_ERR(bdev) && i <= timeout; i++) {
+ dev_t devt;
- /* We might not have rootfs mounted at this point. Try
- to resolve the device name by other means. */
+ if (i)
+ msleep(1000);
+ wait_for_device_probe();
+
+ devt = name_to_dev_t(devname);
+ if (!devt)
+ continue;
- dev_t devt = name_to_dev_t(devname);
- if (devt)
- bdev = blkdev_get_by_dev(devt, mode, dev);
+ bdev = blkdev_get_by_dev(devt, mode, dev);
}
#endif
@@ -355,11 +362,12 @@ static char block2mtd_paramline[80 + 12]
static int block2mtd_setup2(const char *val)
{
- char buf[80 + 12 + 80]; /* 80 for device, 12 for erase size, 80 for name */
+ char buf[80 + 12 + 80 + 8]; /* 80 for device, 12 for erase size, 80 for name, 8 for timeout */
char *str = buf;
- char *token[3];
+ char *token[4];
char *name;
size_t erase_size = PAGE_SIZE;
+ unsigned long timeout = 0;
int i, ret;
if (strnlen(val, sizeof(buf)) >= sizeof(buf)) {
@@ -370,7 +378,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) {
@@ -399,7 +407,10 @@ static int block2mtd_setup2(const char *
if (token[2] && (strlen(token[2]) + 1 > 80))
pr_err("mtd device name too long\n");
- add_device(name, erase_size, token[2]);
+ if (token[3] && kstrtoul(token[3], 0, &timeout))
+ pr_err("invalid timeout\n");
+
+ add_device(name, erase_size, token[2], timeout);
return 0;
}
@@ -433,7 +444,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)
{
@@ -467,7 +478,7 @@ static void block2mtd_exit(void)
}
-module_init(block2mtd_init);
+late_initcall(block2mtd_init);
module_exit(block2mtd_exit);
MODULE_LICENSE("GPL");

View file

@ -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
@@ -756,6 +756,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
@@ -90,7 +90,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;
}

View file

@ -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", __func__);
- return -1;
+ return -EBADMSG;
}
EXPORT_SYMBOL(__nand_correct_data);

View file

@ -1,11 +0,0 @@
--- a/drivers/mtd/chips/cfi_cmdset_0002.c
+++ b/drivers/mtd/chips/cfi_cmdset_0002.c
@@ -780,7 +780,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;

View file

@ -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
@@ -1498,6 +1498,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;

View file

@ -1,41 +0,0 @@
--- a/drivers/mtd/devices/Kconfig
+++ b/drivers/mtd/devices/Kconfig
@@ -102,6 +102,14 @@ config MTD_SPEAR_SMI
help
This enable SNOR support on SPEAR platforms using SMI controller
+config M25PXX_PREFER_SMALL_SECTOR_ERASE
+ bool "Prefer small sector erase"
+ depends on MTD_M25P80
+ default y
+ help
+ This option enables use of the small erase sectors if that is
+ supported by the flash chip.
+
config MTD_SST25L
tristate "Support SST25L (non JEDEC) SPI Flash chips"
depends on SPI_MASTER
--- a/drivers/mtd/devices/m25p80.c
+++ b/drivers/mtd/devices/m25p80.c
@@ -90,6 +90,12 @@
#define JEDEC_MFR(_jedec_id) ((_jedec_id) >> 16)
+#ifdef CONFIG_M25PXX_PREFER_SMALL_SECTOR_ERASE
+#define PREFER_SMALL_SECTOR_ERASE 1
+#else
+#define PREFER_SMALL_SECTOR_ERASE 0
+#endif
+
/****************************************************************************/
enum read_type {
@@ -1192,7 +1198,7 @@ static int m25p_probe(struct spi_device
flash->mtd._write = m25p80_write;
/* prefer "small sector" erase if possible */
- if (info->flags & SECT_4K) {
+ if (PREFER_SMALL_SECTOR_ERASE && (info->flags & SECT_4K)) {
flash->erase_opcode = OPCODE_BE_4K;
flash->mtd.erasesize = 4096;
} else if (info->flags & SECT_4K_PMC) {

View file

@ -1,20 +0,0 @@
From eef9dfc4e821408af1af13aa0cc707fc496fb7c6 Mon Sep 17 00:00:00 2001
From: Gabor Juhos <juhosg@openwrt.org>
Date: Wed, 11 Dec 2013 19:05:59 +0100
Subject: [PATCH] m25p80: add support for the Winbond W25X05 flash
Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
---
drivers/mtd/devices/m25p80.c | 1 +
1 file changed, 1 insertion(+)
--- a/drivers/mtd/devices/m25p80.c
+++ b/drivers/mtd/devices/m25p80.c
@@ -1022,6 +1022,7 @@ static const struct spi_device_id m25p_i
{ "m25px64", INFO(0x207117, 0, 64 * 1024, 128, 0) },
/* Winbond -- w25x "blocks" are 64K, "sectors" are 4KiB */
+ { "w25x05", INFO(0xef3010, 0, 64 * 1024, 1, SECT_4K) },
{ "w25x10", INFO(0xef3011, 0, 64 * 1024, 2, SECT_4K) },
{ "w25x20", INFO(0xef3012, 0, 64 * 1024, 4, SECT_4K) },
{ "w25x40", INFO(0xef3013, 0, 64 * 1024, 8, SECT_4K) },

View file

@ -1,20 +0,0 @@
From 0233dcb52eefa0b29250a6d8a58b3143790df57d Mon Sep 17 00:00:00 2001
From: Sergey Ryazanov <ryazanov.s.a@gmail.com>
Date: Wed, 11 Jun 2014 02:23:00 +0400
Subject: [PATCH] mtd: m25p80: add support for EON EN25QH128
Signed-off-by: Sergey Ryazanov <ryazanov.s.a@gmail.com>
---
drivers/mtd/devices/m25p80.c | 1 +
1 file changed, 1 insertion(+)
--- a/drivers/mtd/devices/m25p80.c
+++ b/drivers/mtd/devices/m25p80.c
@@ -909,6 +909,7 @@ static const struct spi_device_id m25p_i
{ "en25q32b", INFO(0x1c3016, 0, 64 * 1024, 64, 0) },
{ "en25p64", INFO(0x1c2017, 0, 64 * 1024, 128, 0) },
{ "en25q64", INFO(0x1c3017, 0, 64 * 1024, 128, SECT_4K) },
+ { "en25qh128", INFO(0x1c7018, 0, 64 * 1024, 256, 0) },
{ "en25qh256", INFO(0x1c7019, 0, 64 * 1024, 512, 0) },
/* ESMT */

View file

@ -1,26 +0,0 @@
--- a/drivers/mtd/mtdcore.c
+++ b/drivers/mtd/mtdcore.c
@@ -37,6 +37,7 @@
#include <linux/backing-dev.h>
#include <linux/gfp.h>
#include <linux/slab.h>
+#include <linux/root_dev.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
@@ -414,6 +415,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:

View file

@ -1,51 +0,0 @@
--- a/drivers/mtd/ubi/attach.c
+++ b/drivers/mtd/ubi/attach.c
@@ -800,6 +800,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
@@ -830,9 +837,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)) {
+ ubi_msg("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
@@ -701,6 +701,7 @@ struct ubi_attach_info {
int mean_ec;
uint64_t ec_sum;
int ec_count;
+ bool eof_found;
struct kmem_cache *aeb_slab_cache;
};

View file

@ -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
@@ -1209,6 +1209,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)) {
+ ubi_err("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);
+ ubi_msg("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) {
+ ubi_err("cannot attach mtd%d", mtd->index);
+ put_mtd_device(mtd);
+ }
+ }
+ }
+}
+
static int __init ubi_init(void)
{
int err, i, k;
@@ -1298,6 +1341,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) {
ubi_err("block: cannot initialize, error %d", err);

View file

@ -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
@@ -593,6 +593,44 @@ static int __init ubiblock_create_from_p
return ret;
}
+#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)
+ ubi_err("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;
@@ -623,6 +661,10 @@ int __init ubiblock_init(void)
if (ret)
goto err_remove;
+ /* 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.

View file

@ -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
@@ -432,7 +432,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
@@ -526,6 +546,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
create_dev("/dev/root", ROOT_DEV);
mount_block_root("/dev/root", root_mountflags);

View file

@ -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
@@ -48,6 +48,7 @@
#include <linux/blkdev.h>
#include <linux/hdreg.h>
#include <asm/div64.h>
+#include <linux/root_dev.h>
#include "ubi-media.h"
#include "ubi.h"
@@ -444,6 +445,15 @@ int ubiblock_create(struct ubi_volume_in
add_disk(dev->gd);
ubi_msg("%s created from ubi%d:%d(%s)",
dev->gd->disk_name, 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:

View file

@ -1,18 +0,0 @@
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -39,6 +39,7 @@ source "fs/gfs2/Kconfig"
source "fs/ocfs2/Kconfig"
source "fs/btrfs/Kconfig"
source "fs/nilfs2/Kconfig"
+source "fs/yaffs2/Kconfig"
endif # BLOCK
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -126,3 +126,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/
+

View file

@ -1,38 +0,0 @@
--- a/fs/yaffs2/yaffs_vfs.c
+++ b/fs/yaffs2/yaffs_vfs.c
@@ -738,7 +738,7 @@ static int yaffs_file_flush(struct file
yaffs_gross_lock(dev);
- yaffs_flush_file(obj, 1, 0);
+ yaffs_flush_file(obj, 1, 0, 1);
yaffs_gross_unlock(dev);
@@ -768,7 +768,7 @@ static int yaffs_sync_object(struct file
yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC,
"yaffs_sync_object");
yaffs_gross_lock(dev);
- yaffs_flush_file(obj, 1, datasync);
+ yaffs_flush_file(obj, 1, datasync, 1);
yaffs_gross_unlock(dev);
return 0;
}
@@ -2187,7 +2187,7 @@ static void yaffs_flush_inodes(struct su
yaffs_trace(YAFFS_TRACE_OS,
"flushing obj %d",
obj->obj_id);
- yaffs_flush_file(obj, 1, 0);
+ yaffs_flush_file(obj, 1, 0, 1);
}
}
}
@@ -2200,7 +2200,7 @@ static void yaffs_flush_super(struct sup
yaffs_flush_inodes(sb);
yaffs_update_dirty_dirs(dev);
- yaffs_flush_whole_cache(dev);
+ yaffs_flush_whole_cache(dev, 1);
if (do_checkpoint)
yaffs_checkpoint_save(dev);
}

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